I had 328 posts that I needed to add a meta field value to. Thankfully they all had the same value at the moment, so what I really needed was to tell WP “For all posts in the custom post type of ‘show’ add the post_meta key of ‘tvtype’ with a value of ‘tvshow’.”

That sounded simple. It wasn’t.

Googling “Updating multiple posts” or “Bulk Update Multiple Posts” (with WordPress in there) was frustratingly vague and told me to do things like the bulk edit from the post lists page. Well. Sure. If I added my post meta to the bulk editor (which I do know how to do) and felt like updating them 20 shows at a time, I could do that. Heck, I could make my page list 50 and not 20, and do it in 5 ‘cycles.’

But that wasn’t what I wanted to do. No, I wanted to figure out how to do it faster forever, so that if I had to update 32,800 posts, I could do it in the least CPU intensive way.

PHP

If I was to do this in PHP, it would look like this:

$ids = array(
	'post_type' 	=> 'post_type_shows',
	'numberposts'	=> -1,
	'post_status'	=> array('publish', 'pending', 'draft', 'future'),
);


foreach ($ids as $id){
    add_post_meta( $id, 'tvtype', 'tvshow' );
}

I picked add_post_meta instead of update_ because while the update will add the meta if it’s not found, I didn’t want to update any of the shows I’d manually fiddled with already. And to run this, I’d have to put it in an MU plugin and delete it when I was done.

Which… Yes. That could work. I’d want to wrap it around a user capability check to make sure it didn’t run indefinitely, but it would work.

WP-CLI

Doesn’t a nice command line call sound better, though? Spoiler alert: It’s not.

I knew I could get a list of the IDs with this:

$ wp post list --post_type=post_type_shows --fields=ID --format=ids

That gave me a space-separated list

And I knew I could add the meta like this for each show:

$ wp post meta add 123 tvtype tvshow

But who wants to do that 328 times?

The documentation for wp post meta update said “Update a meta field.” A. Singular. Now it was possible that this could be for multiple posts, since the information on wp post update said “Update one or more posts” and “one or more” means one or more. But the example only had this:

$ wp post update 123 --post_name=something --post_status=draft

Notice how there’s no mention of how one might handle multiple posts? In light of clear documentation, I checked what the code was doing. For the update function, I found this:

	public function update( $args, $assoc_args ) {
		foreach( $args as $key => $arg ) {
			if ( is_numeric( $arg ) ) {
				continue;
			}

The check for if ( is_numeric( $arg ) ) is the magic there. It says “If this is an ID, keep going.” And no spaces. So the answer to “How do I update multiple posts?” is this:

$ wp post update 123 124 125 --post_name=something --post_status=draft

Great! So can I do that with post meta? Would this work?

$ wp post meta add 123 124 125 tvtype tvshow

Answer: No.

So I took that list, used search/replace to turn it into 328 separate commands, and pasted them in (in 50 line chunks) to my terminal to update everything.

Yaaaay.

Reader Interactions

Comments

  1. Since I don’t use WP CLI (I don’t think that my shared hosting environments will support it) I often write standalone scripts that would accommodate your first bit of PHP code.

    The script would start with

    define(‘WP_USE_THEMES’, false);

    /** Loads the WordPress Environment and Template */
    require( dirname( FILE ) . ‘/wp-blog-header.php’ );

    // Add your code here

    Then you access the file via your browser and it runs. You don’t have to worry about deleting the file from mu-plugins. I often sandbox test code this way before adding it to a theme or plugin.

  2. If you’re already on the command line, wouldn’t a loop be able to do it for you?

    Off the top of my head, something like

    wp post list –post_type=type –fields=ID –format=ids | awk -F’ ‘ ‘{ for ( i = 1; i <= NF; i++ ) wp post meta add $i tvtype tvshow }'

    Probably not be 100% copy-and paste-able, but the gist of it is there, granted it’s not the first thing one would think of when working with WordPress, WP-CLI does allow for some fun automations.

  3. It is possible to do on the command line though the syntax is non-intuitive.
    Here’s an example: https://git.pub/snippets/4

  4. I would use the php one and add a check on some arbitrary $_GET param to make sure it would not run multiple times (and would not bother a visiter). And delete it afterwards.

    • For such scripts I do lost of echo/var_export testing before running the script where it makes changes. I also sometimes put the script in a directory where access is limited to my IP.

  5. Or… you could write one SQL statement for the insert / update on exists and follow it up with clearing the object cache 🙂

%d bloggers like this: