How to bulk update all WordPress pages or posts

Standalone PHP script to bootstrap Wordpress environment and execute bulk changes

Hello!

Sometimes its necessary to perform mass or automated actions against your WordPress content. Reasons for this can vary, but in our scenario there was a bug in a plugin relating to translated content via WPML where afte a fix / plugin update was applied, resolving the content errors was as simple as re-saving an existing post (with no changes).

Normally this wouldn’t be a problem but what if your site has over 1,000 pages or posts? Doing those one at a time , or even via the “Quick edit” method can be tedious and resource-taxing (both in-person and server resources!).

Alternatively, what if you needed to update a byline in the post content, or standardize a title format for your posts? The reasons can vary again ,but I thought it might be helpful to include an automated process using a method called “bootstrapping” WordPress. What this really means is we are loading the WordPress environment in a standalone PHP file so that we can create a quick interactions with WordPress in order to manipulate content.

This way we can execute the standalone PHP file, which usually would live outside of the WordPress web accessible folder, and run it on the command line. The advantage of running PHP as a command line script is that you are not as limited to the memory and execution time limitations that the web accessible php processes will be bound to. Your script has more leeway and will not be terminated if it exceeds certain amount of time. This is perfect for automation tasks like mass-updating of content and whatnot.

 

How to bootstrap WordPress in a standalone PHP script

First and foremost we want to create a PHP script outside of the web-accessible environment where your WordPress site lives. I should note that you need command line access to your website (or more ideally, have this all happen on a separate development environment). Lets implement some safeguards to ensure that the script is indeed being executed on the command line , as well as some increased verbosity for debugging :

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('memory_limit', '-1');
if( php_sapi_name() !== 'cli' ) {
    die("Meant to be run from command line");
}

You might recognize those first few lines. You usually would put them in your wp-config.php file if you were diagnosing any sort of issues with your site (i.e. White screen of death).

The last few lines, the if-statement, are a check to ensure that the script is indeed being run on the command line. Next we want to have a standardized method through which the script will find your WordPress install. This can of course be modified to suit wherever you intend the script to live, but keep in mind that we are assuming that the script will live in a parent direction above where the WordPress install is located.

function find_wordpress_base_path() {
    $dir = dirname(__FILE__) . '/yoursite.ca';
    do {
        //it is possible to check for other files here
        if( file_exists($dir."/wp-config.php") ) {
            return $dir;
        }
    } while( $dir = realpath("$dir/..") );
    return null;
}

define( 'BASE_PATH', find_wordpress_base_path()."/" );
define('WP_USE_THEMES', false);
global $wp, $wp_query, $wp_the_query, $wp_rewrite, $wp_did_header;
require(BASE_PATH . 'wp-load.php');

The above is relatively straightforward. We are building a function to return the base path of the WordPress install. This means if your script is located in /var/www/script.php and the site is /var/www/yoursite.ca , the above should work.

We then define the base path as the returned value, disable the use of themes for this implementation because its not necessary and then we require the wp-load.php file. This is key as this is how we are bootstrapping the WordPress environment into the script. Once this is done we are free to use built-in core WordPress functions to manipulate content and do pretty much anything we want.

 

How to mass update WordPress pages or posts with PHP

Now that we have the WordPress environment successfully loaded, we want to build an array of pages to edit.

$args = array(
        'post_type' => 'page',
        'posts_per_page' => -1,
    );
$pages_array = get_posts($args);

if (!empty($pages_array)) {
    echo 'doing!';
    // loop trough each Wordpress post
    foreach ($pages_array as $page)
    {
        echo "doing page : " . $page->ID . "\n";
        shift8_update_page($page->ID);
    }

}

This looks familiar to most WordPress developers. You can see we are building an argument array where we are filtering all post_types of pages and using the get_posts function to pull all the results into an array.

You can also see on one of the last lines that within the foreach loop where we iterate across the pages array, we are calling another function called shift8_update_page. I’ll detail what happens in that function but obviously we are using it to update the pages.

function shift8_update_page($post_id) {
    $post_type = get_post_type($post_id);
    if ($post_type == 'page') {
        $post_data = array(
            'ID' => $post_id,
        );
        wp_update_post($post_data);
    }
}

As mentioned earlier in our post, the scenario for us is that we needed to just re-save all existing pages with no changes. In your scenario you may want to make changes to all posts in a standardized way.

Within this function you can do anything you want. You can pull all the existing page details and through regular expressions or conditional logic you could make intelligent changes on a massive scale.

The post_data array is where you would declare these changes. You can see I’m only assigning the ID of the post in the array but this is where you could define a title change, content change or any other field (including custom fields) for each post.

You can read more about the wp_update_post function to understand what you could do. You can use this in other ways too, for example with advanced custom fields to update custom fields or with Woocommerce to update all your products on your site.

It is important to note that it is ideal, especially when testing these types of scripts out, to always backup your site’s database prior to executing any mass or bulk changes for obvious reasons. Furthermore it would be ideal to simply have a segmented development (or local) environment where you can safely test these interactions on your site safely without the risk of loss of data.

Hopefully this helps you and perhaps will open some doors with being able to make bulk changes to your WordPress site in every way possible. These types of scripts can also be used to execute automated tasks across your WordPress site in a variety of scenarios. Find the full script below for reference.

 

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('memory_limit', '-1');
if( php_sapi_name() !== 'cli' ) {
    die("Meant to be run from command line");
}

function find_wordpress_base_path() {
    $dir = dirname(__FILE__) . '/yoursite.ca';
    do {
        //it is possible to check for other files here
        if( file_exists($dir."/wp-config.php") ) {
            return $dir;
        }
    } while( $dir = realpath("$dir/..") );
    return null;
}

define( 'BASE_PATH', find_wordpress_base_path()."/" );
define('WP_USE_THEMES', false);
global $wp, $wp_query, $wp_the_query, $wp_rewrite, $wp_did_header;
require(BASE_PATH . 'wp-load.php');


$args = array(
        'post_type' => 'page',
        'posts_per_page' => -1,
    );
$pages_array = get_posts($args);

if (!empty($pages_array)) {
    echo 'doing!';
    // loop trough each post
    foreach ($pages_array as $page)
    {
        echo "doing page : " . $page->ID . "\n";
        shift8_update_page($page->ID);
    }

}

function shift8_update_page($post_id) {
    $post_type = get_post_type($post_id);
    if ($post_type == 'page') {
        $post_data = array(
            'ID' => $post_id,
        );
        wp_update_post($post_data);
    }
}