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!


HTML Basics

This post intends to be a very basic introduction to HTML for people who may need to edit some code but don’t need or want to learn the everything required to build a website. If you have a WordPress site and want to make some tweaks in HTML, this is the place for you.


Websites are built with three computer languages: HTML, CSS and JavaScript. Many other languages exist for outputting these but they all run on the server instead of in your browser and are beyond the scope of this post.

HTML is used to define different bits and content of a web page. CSS then defines how the web browser should make the HTML look (colours, layouts, fonts, sizes etc). Many websites use JavaScript to make things more interactive too.

  • HTML stands for Hyper Text Markup Language
  • CSS stands for Cascading Style Sheets
  • JavaScript is not the same as Java.

Anatomy of an HTML Tag

HTML tags are bits of code which wrap the text of the web page, they have different meanings and the CSS causes them to be displayed in different ways. HTML tags look like one of these. Pay attention to spaces and quotation marks.

  1. Self Closing: <tag_name>
  2. Simple: <tag_name>Contents<value>
  3. Regular with Attributes: <tagname attributes=”value”>Contents</tag>

Self Closing HTML Tag

Many tags don’t have any contents, they just tell the browser to do something. A classic example is a line break, if you have a paragraph (see below) and you want to force a new line somehere stick in the br tag:

 <p>The contents of the paragraph goes here<br> this text will be on a new line</p>

Simple HTML Tag

A simple HTML tag is the P tag, it defines a paragraph and you wrap it around the contents.

 <p>The contents of the paragraph goes here</p>

HTML Tag with Attributes

Another tag is the one which creates links, they’re called anchors and the tag name is a, to define where the link should point you must set the “href” attribute. Do this by adding a space after the tag name, putting the attribute name (href) followed by a space and the value for that attribute. You normally want to surround the attribute value with quotes – either single ” or double ‘ are fine.

 <a href="http://www.google.com">Click here to visit Google</a>

Simple HTML tag with CSS Class

CSS works by applying styles to HTML tags which match various types of attribute. A common one is the class. If your web developer has written code to make some links (Anchors) look like buttons you probably just need to add the right class. For example:

 <a class="button" href="http://www.google.com">Click this button to visit Google</a>

Note that you (or someone) will need to have written some CSS to make that class=”button” do anything, check with your designer/developer to find out what your options are for styling things with classes.


Strip Images from All WordPress Posts

After importing a blog from Blogger to self-hosted WordPress recently I discovered that all the inline images remain hosted on Blogger.

There were various hacks for moving them to my local server and updating the posts and suchlike – but in my case all the posts had a single image, and the importer had managed to set that image as the featured image. So all I really wanted to do was to strip the image and leave my theme to display the featured image.

I’ve got a scripts folder in my project root for just such occasions, here’s the script I used to remove all images from all WordPress posts:

$wordpressBasePath = __DIR__.'/../public/wp-load.php';
include_once $wordpressBasePath;

$query = new WP_Query([
	'post_type' => 'post',
	'nopaging' => true,

// I figured I'd also use this opportunity to make sure the post content adheres to the new blog restrictions too
// plus kses is a handy way to strip the image tags.
$allowed_tags = wp_kses_allowed_html( 'post' );

while ($query->have_posts()) {
	// Everyone loves an update, especially big websites
	echo "\r".($query->current_post + 1).' of '.$query->found_posts.'. '.round((($query->current_post + 1) / $query->found_posts) * 100).'%';
	$newPost = [
		'ID' => get_the_ID(),
		'post_content' => wp_kses(get_the_content(), $allowed_tags),
	$error = wp_update_post($newPost, true);
	if (is_wp_error($error)) {
echo "\n";

I’d like to also make this remove any empty anchor tags which get left behind (most of the images were wrapped in one) but without removing other anchors. If you have a reliable method for doing this, let me know in the comments!