WPX is shell script wrapper for running commands on multiple sites via (WP CLI) (the WordPress Command Line Interface.)
This allows you to streamline repetitive tasks for Core, Plugin or Themes (and more):
- Installations, Reinstallations and Uninstallations
- Updates, Activations and Deactivations
- Combined Install/Activate or Deactivate/Uninstall
So that any action can process multiple resources and sites with a single command line! ðŸ˜€
wpx installactivateplugin site1,site2,site3 plugin-1,plugin-2,plugin-3
If you are involved in managing multiple WordPress installs, your eyes are probably lighting up right now. ðŸ˜Ž
As you can imagine,
WPX takes the existing timesaving coolness of
WP CLI to the next level.
Another main feature of WPX is File Syncing, giving you the ability to easily synchronize (via
a local core, plugin, theme, must-use plugin or dropin source to any site(s) specified.
This allows for much easier version control as well as faster distribution of bugfixes and other updates on a server with independent sites, giving you the ability to have a more unified codebase without needing to use Multisite. It also makes it easy to say, sync a cloned GitHub repo to a multiple Staging sites.
WPX also includes some nifty extra features:
- Language Commmands - to also install, uninstall, activate or update any locale language pack
- Colourful Lists - list core info, plugins and themes in a colourful (and filterable) display table.
- Check Permissions - find and fix rogue file permissions that do not match with the site owner:group.
- Core Locking - to make core files unwriteable to hackers (see Core Lock section for more details.)
Certain commands will not work with Multisite yet (network plugin activation/deactivation, and theme or plugin activation for a specific Blog Site ID.)
WPX works to manage local sites on any single server, with limited YML config support. It is intended that WPX will support running of all WPX commands to remote sites also (via SSH and rsync.) This will include handling of YML configs which may specify the use of a local path, SSH and/or site Aliases.
The next phase of development will focus on these two features (See the Roadmap section.)
- (Install WP CLI if not already installed. Or maybe time to update it!)
- Download the
WPXZIP file and extract it locally.
- then upload
wpxvia FTP to
/usr/local/bin(or other environment path used)
- (if your FTP user is not root, login as root and
chown root:root /usr/local/bin/wpx)
- then upload
- Or simply change to the environment path in shell and download it directly:
cd /usr/local/bin(making sure you are logged in as
chmod +x /usr/local/bin/wpx(or other environment path used)
- Create a
wpx.confconfig file in the same directory (or alternatively in
- (or you can just rename
wpx.confand edit then upload it)
- (or you can just rename
- For the SYNC commands you need
rsyncinstalled (you probably already do):
- [On Red Hat based systems]# yum install rsync
- [On Debian based systems]# apt-get install rsync
cd /usr/local/bin && wget https://raw.githubusercontent.com/majick777/wpx/master/wpx && chmod +x wpx
One line config file install and edit (with nano):
cd /usr/local/bin && wget https://raw.githubusercontent.com/majick777/wpx/master/wpx.sample.conf && mv wpx.sample.conf wpx.conf && nano wpx.conf
You must set WordPress site paths in
wpx.conf so that it knows where your WordPress installs are.
wpx.sample.conf for more complete examples. Set the site configs (one per line) in the format:
site site-slug /full/path/to/wordpress/install/ user:group
- note: all
WP CLIcommands will run prefixed with 'sudo -u user' for the user specified!
- providing :group is optional (it is used with check/fix file owner/group commands)
- site paths prefixed with ! will use immutable core locking (see Core Lock section)
wpx.sample.conf for more complete examples.
You can define source paths for use with file [SYNC] action commands (listed below.) Set the source paths (one per line) in the format:
type source-slug /full/source/path/
typecan be either: plugin, theme, core, muplugin or dropin
source-slugis a reference slug but is also used for the plugin/theme directory
- advanced slug usage note: for plugins and themes,
- (this means you can still sync an alternative development copy to its correct destination)
- advanced slug usage note: for plugins and themes,
- muplugins type note: these are synced directly to the sites
- dropins type note: these are synced relative to the base install directory
- eg. to sync db-error.php to
/wp-content/you would set the source to
- and then place the source file at
- eg. to sync db-error.php to
wpx.sample.conf for more complete examples.
wpx updatecheck will output the current version and check for an updated version of
WPX on Github.
You can run
wpx updatescript to update to the latest version of the script (you will need to confirm.)
Alternatively you can download the latest version manually and overwrite the existing file via FTP.
Also, here is a one-liner to update the script manually from shell (check your script path):
cd /usr/local/bin && wget -Owpx https://raw.githubusercontent.com/majick777/wpx/master/wpx
Note the contents and format of your
wpx.conf configuration can remain unchanged between versions.
None of the other files in the package are required to be updated, just the main script.
Important: Since WPX attempts to run WP CLI commands as the user specified in your wpx.conf (via sudo),
so you will need to be logged in with
root access to use WPX (to be able to
sudo -u user)
wpx COMMAND SITE(S) SLUG(S)
COMMANDis a command from the command action list below
SITE(S)is a site reference slug defined in wpx.conf (may be a comma-separated list)
- (note: if a site value of "all" is specified, the COMMAND will be run on EVERY site in wpx.conf)
SLUG(S)is an optional reference to theme or plugin slugs (may be a comma-separated list)
For example, to install plugin with slug 'forcefield' on sites with slugs 'my-site' and 'my-other-site':
wpx installplugin my-site,my-other-site forcefield
or to install plugin with slugs 'forcefield' and 'wp-simple-firewall' on site with slug 'my-site':
wpx installplugin my-site forcefield,wp-simple-firewall
Careful with Commas
One of the main purposes and advantages of WPX is to be able to apply to multiple sites. But remember, command line comma-separated lists are treated as single arguments and must contain NO SPACES. For example, the space after comma here will break this list and attempt to install plugin 'my-other-site':
wpx installplugin my-site, my-other-site forcefield
Note: [SYNC] commands use sources defined in your
wpx.conf, all others use WordPress repository sources.
| || Check current version with latest updated version of |
| || Update to the latest updated version of |
| ||Table of matching SITES(s) or SOURCE(s) from wpx.conf (default: all)|
| ||Table of matching SITE(S) from wpx.conf (default: all)|
| ||Table of matching SOURCES(S) from wpx.conf (default: all)|
| || Run |
| ||Check installed WP Core version(s) on the SITE(S) specified|
| ||Verify WP Core(s) Checksums on SITE(S) (requires no WP errors)|
| ||Update to latest WP Core(s) on SITE(S) (version argument optional)|
| ||Install WP Core(s) to SITE(S) (version and locale optional)|
| ||Reinstall WP Core(s) on SITE(S) (auto-matches version and locale)|
| ||Add the immutable lock to WP Core(s) files on SITE(S)|
| ||Removes immutable lock from WP Core(s) files on SITE(S)|
| ||Checks immutable switch on all WP Core files on SITE(S)|
| ||Checks all file owner/group match those in wpx.conf on SITE(S)|
| ||Change all file owner/group to those in wpx.conf on SITE(S)|
| ||Check plugin(s) SLUG(S) for SITE(S) - status, version, updates|
| ||Activate plugin(s) SLUG(S) for SITE(S)|
| ||Deactivate plugin(s) SLUG(S) for SITE(S)|
| ||Install plugin(s) SLUG(S) for SITE(S)|
| ||Install and Activate plugin(s) SLUG(S) for SITE(S)|
| ||Reinstall plugin(s) SLUG(S) for SITE(S|
| ||Update plugin(s) SLUG(S) for SITE(S)|
| ||Update ALL plugins for SITE(S)|
| ||Rollback plugin for SITE(S) (specify plugin-slug:version)|
| ||Deletes plugin(s) SLUG(S) for SITE(S)|
| ||Uninstall (deactivate/delete) plugins(s) SLUG(S) for SITES(S)|
| ||List installed themes on SITE(S)|
| ||Check active child and parent themes on SITE(S)|
| ||Activate theme SLUG for SITE(S)|
| ||Install theme SLUG(S) for SITE(S)|
| ||Install and Activate theme SLUG for SITE(S)|
| ||Reinstall theme SLUG(S) for SITE(S)|
| ||Update theme SLUG(S) for SITE(S)|
| ||Rollback theme SLUG:VERSION for SITE(S)|
| ||Sync core SLUG for SITE(S) using wpx.conf|
| ||Sync plugin SLUG(S) for SITE(S) using wpx.conf|
| ||Sync and activate plugin SLUG(S) for SITE(S) using wpx.conf|
| ||Sync theme SLUG for SITE(S) using wpx.conf|
| ||Sync and activate theme SLUG for SITE(S) wpx.conf|
| ||Sync must-use plugin SLUG(S) for SITE(S) wpx.conf|
| ||Sync dropin (relative files) SLUG(S) for SITE(S) using wpx.conf|
| ||Install language locale SLUG(S) on SITE(S)|
| ||Activate language locale SLUG on SITE(S)|
| ||Update language locale SLUG(S) on SITE(S)|
| ||Uninstall language locale SLUG(S) on SITE(S)|
updatetheme commands can take an additional version argument of either:
a specific version (must be an exact version), minor, patch, or major (default.)
listplugins command will take plugin slugs and/or additional filters if specified in the comma-separated plugin list:
(default when no list specified),updates
(A similar ability will be added in future forlistthemes`)
Command Name Variations Okay!
Plural Commands Also For ease of use when typing on the command line (to prevent retyping), most singular plugin and theme action commands will also work in plural form, ie:
updatethemes (but NOT
syncdropins (but NOT
uninstalllanguages (but NOT
Dashed and Underscored Commands Also for ease of use, all command action variations work, whether without a space as listed in the command table above, or with command words separated with a dash or underscore:
updateplugin = update-plugin = update_plugin = updateplugins = update-plugins = update_plugins
This is an optional extra security feature to help prevent hackers from rewriting any core WordPress files, as this is a common place to hide injected code after a hack. Making these files immutable (read-only) means that NO users can write to them (and only the root user can remove the immutable flags.) Be aware this approach has both advantages and disadvantages.
Making your WordPress core files immutable is two steps beyond simple file monitoring or integrity checking, which require action after the fact and are often too late to prevent damage. As your core files simply cannot be changed and thus infected by malware, this gives one less attack vector for hackers to use.
If you decide to make your WordPress core files read-only this way, you cannot run standard updates from the WordPress admin interface or with standard WP CLI or any other standard update method. This will mean you will need to run core updates via WPX also - logged in as root user. (Alternatively, unlock with WPX (as root), then update via whatever process, then relock with WPX.)
To use this feature, simply prefix a sitepath column in
! and run this to lock the files:
wpx lockcore my-site-slug
WPX will know to unlock before and then relock after ANY core commands that it runs.
So for example, to update a site to the latest version, you can do simply:
wpx updatecore my-site-slug
What is Locked?
Specifically, all base files (
wp-config.php etc.), and all files recursively in both
/wp-content/ and any of its subdirectories or files are not locked. So if you
have dropins in
db-error.php), or other static plugin or theme files,
you may want to lock these down manually (eg.
chattr +i db-error.php.)
If for whatever reason you decide not to use this feature, a similar but not quite as effective method
would be to use the
synccore command via a regular cron job to overwrite any core file changes IF they
happen. (This would instead mean keeping a core version source directory up-to-date to sync from.)
Why is the written in Shell and not a PHP Phar package or WP CLI extension?
A few reasons. First, it started as a simple Shell script wrapper to do some simple WP CLI management tasks... I didn't have any intention of making it in any way a larger project. But as I added a few bits and it grew, it became more of an exercise for me to learn more of the (so weird) Shell scripting syntax. I mostly write in PHP, and partly regret not just writing it all in that, but have learnt a lot in the process. So if it's a little clunky in places that's why - it's come from a trial and error learning process of writing easily understandable and well commented code (for myself first!) rather than coding for efficiency.
Couldn't you just use site @aliases for doing these kind of tasks?
To some extent, yes. But I wasn't even aware of site @alias support existed when I first started this project!
Ah silly me. But that aside, there are some advantages to having this available at the root level. Not having
sudo -u user wp ... to run as the correct user is one. Not having to be in the correct WordPress
install directory or provide a
--path= is another. Also saves time not having to look up the WPI CLI command
syntax and switches over and over knowing they are already in place.
But also, the Core Locking security feature requires root access to make files immutable. And having the
user(:group) available allows for file permission checking/fixing, as well as for writing files with the
correct permissions with the Source Syncing feature. As all of this grew out of this rather unique approach
to a different kind of development process, which provided the opportunity to add some cool little features
already - and to add more into the future - so I'm happy with where it went and what it can do. ðŸ™‚
The next phase of development for WPX will focus on supporting remote commands:
Run commands on sites remotely (via installed SSH keys) instead of just for local WordPress paths.
Similarly, allow for file syncing to remote sites from specified local sources via SSH.
Polish the handling of
wp-cli.ymlconfig files for use with
@aliascommand line arguments.
(Limited experimental support for some of these is already in place but requires further development.)
Development for this project will be via GitHub Issues and Projects, and probably remain that way.
If you have any bugfixes, feature suggestions, you can Submit an Issue
Help appreciated and code contributions are welcome, please Submit a Pull Request
= 1.0.4 =
- added updatecheck and updatescript commands for WPX updates
- added rollbackplugin and rollbacktheme commands
- added deletetheme command (with check for active parent/child)
- added single getoption command (with JSON format output)
- added support for syncing from zip and http zip sources
- fix missing installactivatetheme command trigger check
- fix missing showconfig and debuginfo to valid command help
- fix split commands to avoid Too many positional arguments error
- fix for split slugs in syncactivateplugin and syncactivatetheme
- fix to add missing wp-load.php to base file permission list
- fix to reinstall plugin to reactivate if it was active
- improve site config table listing and validate paths
- improve get script path (symlink compatible version)
= 1.0.3 =
- added plugin list filtering capability
- group active plugins/theme at top of lists
- output extra info for core version check
- check for core updates with core version check
- fix to plugin update command string
= 1.0.2 =
- set command string once (for DRY command reattempt usage)
- check commands against array list of possibile combinations
- change directory to site path instead of using wp --path=
- changed updateallplugins to use updateplugins all
- expand source data lines with read instead of ()
- allow splitting of theme/plugin source slugs (for dev versions)
- added show config command (output column formatted wpx.conf)
- added site@alias argument splitting (needs wp-cli.yml config)
- added setting wp-cli.yml path via wpx.conf (prototype)
- added reading of wp-cli.yml with aliases fix (prototype)
- added patch core updates by setting version argument to patch
= 1.0.1 =
- use single wpx.conf config instead of sources.conf and sites.conf
- added code comment lines to all functions and sections
- added column formatting for plugin and theme list output
- added core language commands (install/uninstall/activate/update)
- removed duplicate code for processing multiple/singular sources
- quoted all variables (and other minor fixes) to pass ShellCheck
- use exact array check function for actions instead of quick matching
- use exact slug match for theme column in theme check function
- allow minor core updates by setting version argument to minor
= 1.0.0 =
- added syncmuplugin and syncdropin commands