Bulk unpublish posts between specific dates (e.g. from April 2017 and earlier)?

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

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"

etc

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 )