Skip to content

WP-CLI, Just For Multisite Fun

WP-CLI is full of useful tools, but getting them to do serious work isn’t so straightforward. The docs are all written in terms of one-liners.

Problem One

On a 12,000-site multisite installation I was using two network-activated privacy plugins. Both had lapsed into the unsupported category in the WordPress repository, so I wanted to get rid of them and replace them with new ones. The primary tool, Authenticator, doesn’t have any options. Set-it-and-forget-it — but I wanted the root blog to be public, so network activation wasn’t going to cut it. I needed to activate the new plugin individually across all the sites. Clearly a job for WP-CLI.

[cc lang=”bash”]wp site list –field=url | xargs -n1 -I % wp –url=% plugin activate authenticator[/cc]

Based on a fairly typical one-liner example. This ran for couple of hours, and when it was done I de-activated the old network-activated plugin, and de-activated Authenticator on the root site. I used similar code to activate the Disable Feeds plugin.

Problem Two

So far, training wheels. Some of the tasks I needed to get done on my two installations — 1,400 and 12,000 sites — were a little more complicated. Sure I could use shell scripting — but I don’t know it well enough (make that, at all) to do anything more than the example above. So by cobbling together little bits and pieces of exec(..) commands and loops in a PHP script, I managed to do some complicated things.

On the smaller installation, there were three different obsolete privacy plugins. Two of them were basic to locking out non-authenticated users, the other was there to prevent the feeds from being active. They were each used inconsistently by several hundred of the sites, but not all of them. What I needed to do was find the blogs that were using the old versions, deactivate them, and then activate two new privacy plugins for those sites only. I wrapped these up in a PHP script.

Throughout these examples I’ve added linebreaks for readability.
[cc lang=”PHP”]
that into the WP-CLI command to list the plugins — only active ones, only for that URL, skip theme and plugin files because they cause nothing but heartache and spurious error messages, under the previously set user account — and store them in the [cci lang=”PHP”]$pluginlist[/cci] array. (I’ve taken the precaution of clearing that array first because it had a habit of pushing to new entries onto the existing array.)

Now you’ll cycle through [cci lang=”PHP”]$pluginlist[/cci] one at a time. After splitting the list on whitespace, the first item in the resulting array is going to be the slug of the plugin. If it’s ‘private-wordpress-access-control-manager’ (earlier I did a version that looks for the two others) we’re going to de-activate it. Change this line to suit.

[cc lang=”PHP”]echo exec(“wp –url=$url plugin deactivate ” . $fields[0]);[/cc]

And then we’ll activate the two replacements.

[cc lang=”PHP”]echo exec(“wp –url=$url plugin activate authenticator”);
echo exec(“wp –url=$url plugin activate disable-feeds”);[/cc]
I’m echoing all this out to the command line so I can see what’s going on. If you like to live on the edge you can skip the echo part.

Problem Three

I’ve modified all the blogs that were using the Twenty Ten theme, so the oldest one still in production is Twenty Eleven. Back when it came out there was a handy plugin called Twenty Eleven Theme Extensions, which gave a few new features for headers, widgets, menus, etc. And once upon a time when it was my default for new blogs I had it network-activated; but obviously that’s not necessary anymore. But I would like to have it activated on those blogs that are still using the Twenty Eleven theme.

[cc lang=”PHP”]
You can use this for any theme that has one or more required/recommended plugins. There are a lot of them.

Problem Four

Then it gets hairier. I used a plugin that provides an authentication box in a widget. Simple enough, but then the plugin went out of support. Call me paranoid but why wait for a vulnerability to show up? Might as well replace it.

The thing is, with a wide variety of available themes, each with its own collection of sidebars, going through them all manually to…

  1. See if it’s using the plugin
  2. If so activate the new one
  3. Figure out where the widget is being used
  4. Put the new one in the right place
  5. Drop the old one
  6. Deactivate the old plugin

..times several hundred is not an option. But it turns out all this is available in the various WP-CLI commands. Here we go…

[cc lang=”PHP”]
activating login-sidebar-widget on
Success: Activated 1 of 1 plugins.
working with name,id
sidebar name: name
working with id
working with Sidebar,sidebar-1
sidebar name: Sidebar
working with sidebar-1
widget name,id,position
widget search,search-2,1
widget wp_sidebarlogin,wp_sidebarlogin-3,2
adding login_wid to sidebar-1 in location 2
Success: Added widget to sidebar.
removing wp_sidebarlogin of id wp_sidebarlogin-3 from sidebar-1
Success: Deleted 1 of 1 widgets.

widget recent-posts,recent-posts-2,3
widget categories,categories-2,4
widget recent-comments,recent-comments-2,5
working with “Content Bottom 1”,sidebar-2
sidebar name: “Content Bottom 1”
working with sidebar-2
widget name,id,position
working with “Content Bottom 2”,sidebar-3
sidebar name: “Content Bottom 2”
working with sidebar-3
widget name,id,position
working with “Inactive Widgets”,wp_inactive_widgets
sidebar name: “Inactive Widgets”
working with wp_inactive_widgets
widget name,id,position
widget pages,pages-2,1
widget calendar,calendar-2,2
widget text,text-2,3
widget rss,rss-2,4
widget tag_cloud,tag_cloud-2,5
widget nav_menu,nav_menu-2,6
widget wp_sidebarlogin,wp_sidebarlogin-2,7
adding login_wid to wp_inactive_widgets in location 7
Success: Added widget to sidebar.
removing wp_sidebarlogin of id wp_sidebarlogin-2 from wp_inactive_widgets
Success: Deleted 1 of 1 widgets.
Deactivating sidebar-login on
Success: Deactivated 1 of 1 plugins.


Problem Five

As of version 4.3, comments on pages are automatically disabled. This was a terrific thing because who needs comments on a “contact us” page? But — if you have a big installation with blogs created prior to that, comments are still on.

We’ve been using a network-activated plug-in for that, but it would be nice to disable it. One less thing, right? But I have to go through and turn off comments on every page on every site first.

So, I used this:
[cc lang=”PHP”]

So you can wrap all your WP-CLI commands into [cci lang=”PHP”]exec[/cci] blocks, and treat the results as PHP variables, then feed them right back in to another WP-CLI command. This allows you to do some non-trivial work on large installations, protecting your security and your time.

Please comment if you see anything wrong. I’m confident this code can be refactored and generalized, but you know how it is once you get something working, it’s time to move on to the next thing.


  1. Frankie Frankie

    Sane solutions for wp-cli in a realistic mulitsite context. Thanks for the detailed write-up!

  2. Mike Langone Mike Langone

    Great Tips! Thanks for contributing, there is not alot out there of actual uses for wp-cli, your post is a welcome find.

    Any thoughts on how to change themes from a list of sites in a multisite? maybe create an array of site urls then activate the theme? I have MS installation that has a 40-50 sites each using a different theme, I would like to use wp-cli to accomplish this have you done anything like this before?

  3. Tom Tom

    I haven’t done it directly, but here’s a scrap of code I used to activate a plugin for sites which were using a specific theme.
    [cc lang=”php”]

Leave a Reply

Your email address will not be published. Required fields are marked *

Share This