WordPress Command Line Script Boilerplate

Recently I had a client who wanted me to import their posts from BlogSpot on to the shiny new self hosted WordPress I’d built for them.

The official importer is OK, but it didn’t do everything we wanted. Specifically not all images had featured images, and those which did often had a copy of the image in the body as well as the featured image. What I needed was a script to go through all the posts, find an image, sideload it so it’s no longer hosted on Blog Spot and set it as the featured image then remove any other images from the post using a Composer package.

I’m not going to share all those tasks here, but below you’ll find a boilerplate script which should give you everything you need to run WordPress admin operations on a selection of posts. Getting access to the Admin functions is a little more complicated than not since it includes all the plugins/admin side things and their baggage.

This is a CLI script designed to be run from the command line, but you could probably adapt it to run through Apache if you had reason to do so.

If you saved this as ‘update_everything.php’ in a ‘scripts’ folder which lived next to your ‘public’ folder (which contains WordPress) you’d run `php scripts/update_everything.php` to use. No output from the script indicates success (unless you modify it to output something).

// DO NOT RUN THIS SCRIPT without a modifying it, backing up and testing it first.

// This script assumes it's saved in a folder called `script`s and you have
// the following directory layout:

// Soil plugin breaks on CLI, so hack these into place for it. You don't need
// these if you only have well written plugins installed.

// Give us all the errors!
if (!defined('WP_DEBUG')) {
 define('WP_DEBUG', true);
// Include these so we can access all the wordpress bits.
// Change this path to point to wp-load.php, after that we can use ABSPATH
include_once __DIR__.'/../public/wp-load.php';

// These specific includes may vary depending on which bits of admin you need
// you could load admin.php to load everything, but then you'll need to work
// around every not-well-written plugin (see below).
// Look up the function you want in the WordPress docs and it will tell you which
// file it's located in - add that file here. If you then get a "fu
require_once(ABSPATH . 'wp-admin/includes/media.php');
require_once(ABSPATH . 'wp-admin/includes/file.php');
require_once(ABSPATH . 'wp-admin/includes/image.php');

// This SEO Recdirect plugin doesn't play well when you're updating but not
// including every field. You may need to add/remove from these remove_action
// calls or disable other bits of plugin if they're causing trouble.
remove_action( 'save_post', 'seo_redirect_save_current_slug' );
remove_action( 'save_post', 'seo_redirect_save_postdata' );

// Find the post types with a regular query, I wanted everything.
$query = new WP_Query([
	'post_type' => 'post',
	'nopaging' => true,

// This sample script will replace all post content with "Hello, World!";
while ($query->have_posts()) {
	// We are now in the famous WordPress loop and can use functions like get_the_ID() to refer
	// to the post in the current iteration

	// Get the content
	$the_content = get_the_content();

	// Do something with it - you want to change this bit, obviously
	$the_content = "Hello, World!";

	// Put together an array with the post details for updating
	$newPost = [
		// Include ID to tell WP to update this post
		'ID' => get_the_ID(),
		// Set any other fields we want to change
		'post_content' => $the_content,
		// One of the plugins I had installed got confused if I didn't include
		// this in the update too
		'post_type' => 'post',

	// Perform the update
	$error = wp_update_post( $newPost, true );

	// Check if we got an error
	if (is_wp_error($error)) {
		// Output any errors to the console
// Output a new line to clear the console in case anything was output above
echo "\n";

Let me know if this boilerplate was useful and what you’ve done with it in the comments below. Any tips for improving it are also welcome!