I need to unpublish (i.e., set to draft) a bunch of posts from a site, but within a specific time frame (that is to say, they don't want all the posts unpublished, just within specific dates).

In this case the date is basically any post from April 2017 or earlier, should be set to draft.

Here is the script I'm starting with as my base and the approach I'm taking so far. I'm adding an "add action" option in this file "wp-includes/plugin.php." How do I target any post within a date range?


    function custom_function(){
    $args = array('post_type'=> 'post',
         'post_status' => 'publish',
    $published_posts = get_posts($args);

    foreach($published_posts as $post_to_draft){
       $query = array(
        'ID' => $post_to_draft->ID,
        'post_status' => 'draft',
       wp_update_post( $query, true );
  • There seems to be a typo in your add_action call, admin_ini should be admin_init, but this can be done in bulk without writing code via WP CLI
    – Tom J Nowell
    Oct 24, 2018 at 16:59
  • 1
    I would also note that all your work will be destroyed on the next WP update if you do your work in wp-includes or wp-admin, add hooks and filters in an actual plugin under wp-content/plugins. You should never modify WP Core under any circumstances unless you're working on a new WordPress release with a WP nightly/trunk
    – Tom J Nowell
    Oct 24, 2018 at 17:13

1 Answer 1


You can do this without writing any code using WP CLI by chaining 2 commands together:

  • the command to retrieve all posts from April 2017 or earlier
  • the command to update all posts and set the post_status set to draft

These can be combined by using a basic shell/terminal feature called a subshell with $() e.g.:

echo "a$(echo 'b')c"

Will print out abc, we can use the same trick to run a command and grab all the post IDs we want to delete, then insert them into a second command that does the deletion!

Retrieving All the Posts Before April 2017

We can use wp post list to do this, and we will need them as post IDs to pass to the next command. More details on this command here.

For example we can fetch all posts from 2017 like this:

wp post list --year="2017" --format=ids

And all posts from April like this:

wp post list --year="2017" --month="4" --format=ids

This way we can run this command for each month of 2017, and each year before that, and pass the result into the next command

Setting A Post to Draft

We can do this with wp post update 123 where 123 is the ID of the post to change

wp post update 123 --post_status="draft"

Bringing the Two together

So lets set all posts in 2016 to draft:

wp post update $(wp post list --year="2016" --format=ids) --post_status="draft"

And 2015:

wp post update $(wp post list --year="2015" --format=ids) --post_status="draft"

And 2014:

wp post update $(wp post list --year="2014" --format=ids) --post_status="draft"


General Notes

  • You will want to do this via WP CLI, doing it on every admin_init hook will slow things down, and if it can't finish what it's doing before the time limit is reached, your site will never load WP Admin
  • Queries that ask for everything are bad for your site, and can cripple your database, or trigger out of memory warnings. Always fetch posts in batches of 100 or less. You can always run a second and a third query, just don't fetch them all at once
  • Never, ever, modify files in wp-includes or wp-admin. All your changes will be overwritten when WP updates. It's a recipe for disaster. In 2012 a site got hacked releasing customer data and earning the company a multi-million $$ fine because they'd modified WP Core instead of using themes and plugins, then couldn't update it to get new security fixes and thought it was no big deal
  • Use WP_Query instead of get_posts, it uses cache by default and it's closer to a real post loop
  • Indent properly, and get an editor that will indent for you, it will solve an entire class of bugs and mistakes
  • You asked an XY question, where you came up with a solution to a problem, didn't know how to implement it, and asked how to implement the solution. You should have asked how to solve the problem, if you had, a whole list of possible answers could have been posted which can't now. E.g. using pre_get_posts to hide posts before April 2017 ( it solves your problem but it's not what you asked for )
  • Very helpful Thanks a lot
    – Trect
    Aug 1, 2019 at 17:55
  • --month="4" did not work for me. --monthnum="4" instead of --month="4" currently worked for me.
    – Jake
    Dec 1, 2021 at 15:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.