Creating background processes in WordPress

If a PHP script runs, the page loads typically as long as the script needs to finish (or throws an error). That is fine for many cases, but if the script needs to process complex and/or many tasks, that take a few minutes or even hours, it would be nice to put that tasks in the background. This post shows you how to create background processes in WordPress with a library.

Advantages of running background processes

  • the browser tab does not need to stay open until the task is finished.
  • With the right tools (I show one of them here) it can be prevented that the server runs into a timeout.

Disadvantages of running background processes

  • A »disadvantage« I noticed was that it is not so easy to stop a background process when there are issues with it 🙂

Using background processes with the »WP Background Processing« library

On my search for a solution, I found the article »How to do Background Processing in WordPress Plugins and Themes« by Ashley Rich, and with that his library WP Background Processing, that enables us to create background processes in WordPress. By default, the lib stores the tasks in the database, but Ashley mentions the possibility to use Redis or something similar for task storing in his post.

The library comes with two types of processes: Async Request for one-time tasks, and Background Process, which can handle multiple tasks that are stored in a queue. If the server has more resources, those queues run more items per batch as on a server with fewer resources. And also if the script also processes the queue, you can add more tasks.

Here I will show a short example of Background Process – I did not try the other option. You can install the library via Composer:

composer require a5hleyrich/wp-background-processing

Like described in the readme on GitHub, we need to create a child class of WP_Background_Process, where we will create our task. Our small (and not very useful) example task looks like that:

class BackgroundProcess extends WP_Background_Process {

	protected $action = 'florianbrinkmann_background_process';

	/**
	 * Task
	 *
	 * Override this method to perform any actions required on each
	 * queue item. Return the modified item for further processing
	 * in the next pass through. Or, return false to remove the
	 * item from the queue.
	 *
	 * @param mixed $item Queue item to iterate over
	 *
	 * @return mixed
	 */
	protected function task( $item ) {
		error_log( $item );

		sleep( 5 );

		return false;
	}

	/**
	 * Complete
	 *
	 * Override if applicable, but ensure that the below actions are
	 * performed, or, call parent::complete().
	 */
	protected function complete() {
		parent::complete();
	}
}
  • protected $action should be a unique identifier – with that ID, you also can find the batches of the background process in the database.
  • protected function task( $item ) is the task, which is run for each item of the queue. Here we write the value of the item to the error log and pause the script for five seconds. If task() returns false, the item is removed from the Queue. If the item is returned, it can be used in the next pass (I did not try that yet).
  • protected function complete() can contain actions that should run after the background process is finished, like sending a success email. It is important to call parent::complete() here.

To run this process, we can use the following code (requirement is, of course, that our class is available):

$background_process = new BackgroundProcessExample();

// Add items to the queue.
$counter = 0;
do {
	$counter ++;
	$background_process->push_to_queue( $counter );
} while ( $counter < 10 );

// Start the queue.
$background_process->save()->dispatch();

First, we store an BackgroundProcessExample() object in $background_process and run a loop that increases a counter variable. With $background_process->push_to_queue( $counter ); we push the current value to the queue and start the queue after finishing the loop via $background_process->save()->dispatch();.

If you run this script and take a look at your error log after that (not immediately, because of the five-second-delay per item), you should see the numbers from 1 to 10 at intervals of about five seconds. But loading the page to run the script did not take 50 seconds, hopefully, so the task was processed in the background.

Using the same principle, more meaningful tasks can now be outsourced to the background, for example, the programmatic modifying of a large number of articles or something like that.

Related posts

Leave a Comment

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