Spruce interactive

Noise

Use WP Cron to Trigger Asynchronous Background Tasks in WordPress on Post Save or Update

Posted: April 12th, 2013

Author: Ben Heller

Tags:

, , , ,

 Details

The Scenario/Overview

Hi there boys and girls, today we’re going to learn how to use wp-cron to handle background processes in WordPress. Traditionally, wp-cron is used for scheduled tasks or scripts that need to be run daily, weekly, or monthly. This power is most frequently leveraged in service of making regular incremental backups (a good practice, and one that all WordPress developers should follow). The use case we’ll be discussing here is a little bit “outside the box” of common practice, but it’s nevertheless a really solid, WordPress-centric way of achieving something that would otherwise involve some more complicated procedures.

In my limited “free” time, I run an itsy bitsy music blog called Ampeater Music (ampeatermusic.com). If you take a look at its right sidebar, you’ll notice a link that says “Download EVERY Ampeater 7-inch (### MB)”. This is a cumulative zip of every single MP3 the site’s posted in its history. There’s a lot that happens when this zip is created, so we’ll only be talking about triggering the basic action. Behind the scenes, any recently changed ID3 tags are written to each MP3 file from custom post fields (thanks to our beloved ACF), zip files are generated for each updated review independently, and then a cumulative uber-zip is put together from the total collection. We want these checks to run each time a post is saved, and if any data’s been altered that would change the contents of the individual or cumulative zips, then we update the necessary files accordingly.

The challenge here is that while individual post zips contain 1-2 MP3s, the cumulative zip will eventually be several gigabytes. And, since we want the zip to potentially re-generate when we save or update a new or existing post, we don’t want to wait 15 minutes for the page to refresh while everything gets zipped up. So, this particular task needs to be done asynchronously in the background, so we can go on with our lives, editing new posts and browsing around the administration.

Our Real-World Example

This is where the fun starts! First, we need a function that will create the zip (or do whatever it is that you need to do asynchronously).

// Make Sitewide Comp
function uber_comp(){
  $dir = new RecursiveDirectoryIterator(ABSPATH."media");
  $files = array();
  foreach (new RecursiveIteratorIterator($dir) as $file) {
    if (preg_match('/.zip$/i', $file->getFilename())){
      $files[] = $file->getPathname();
    }
  }
  sort($files);
  if(extension_loaded('zip')){
    $zip = new ZipArchive();
    $destination = ABSPATH.'media/ampeatermusic_compilation.zip'; 
    if ($zip->open($destination, ZIPARCHIVE::OVERWRITE)===TRUE){
      foreach ($files as $file){  
        if (basename($file) == 'ampeatermusic_compilation.zip') continue;
        $zip->addFile($file,basename($file));
      }
      $zip->close();
    }
  }
}
add_action('exec_uber_comp', 'uber_comp');

We’re leveraging a RecursiveDirectoryIterator in combination with a RecursiveIteratorIterator, plus a quick regular expression to create our zip, but that’s a topic for another tutorial. The most important bit is this:

add_action('exec_uber_comp', 'uber_comp');

We’re assigning our function to a new action, called “exec_uber_comp”. We then call this action using wp_schedule_single_event(), which will fire off “when someone visits your WordPress site, if the scheduled time has passed”, according to the HOLY OF HOLIES, the WordPress codex.

// Schedule Sitewide Comp
function generate_uber_comp(){
  wp_schedule_single_event(time(), 'exec_uber_comp');
}
add_action('save_post', 'generate_uber_comp');

The two parameters in wp_schedule_single_event() are the time we wish to execute (so we could do time()+3600 to schedule in 1 hour), and the action we’re executing. This MUST be an action hook, and cannot be a function. This is why we’ve assigned the function uber_comp() to the exec_uber_comp action, rather than calling it directly. You can also pass arguments to the hook function using a third parameter (see: http://codex.wordpress.org/Function_Reference/wp_schedule_single_event).

This generate_uber_comp() function is in turn added to the save_post action, which triggers when any post or page is created or updated. When this happens, the chain looks like: SAVE POST (hook) -> GENERATE_UBER_COMP (function) -> WP_SCHEDULE_SINGLE_EVENT (wp-cron) -> EXEC_UBER_COMP (action) -> UBER_COMP (function), which then runs your desired code.

tl;dr – Stuff to Copy/Paste

Here’s a generalized version, which might help you implement it in your own theme:

function MY_CRON(){
  wp_schedule_single_event(time(), 'MY_ACTION');
}
add_action('save_post', 'MY_CRON');

function MY_FUNCTION(){
  // YOUR CODE HERE
}
add_action('MY_ACTION', 'MY_FUNCTION');

Then, whatever magic you’ve specified all happens behind the scenes. Pretty nifty, eh?

  • Hinton

    For those don’t want to cause problem using WP Cron System, and don’t have adequate server Cron, try this WordPress plugin http://wordpress.org/plugins/easycron/.

  • Steven Munro

    This is brilliant. I’m using ‘transition_post_status’ rather than ‘save_post’, but after adopting this method, I didn’t know why I hadn’t thought of it earlier.

Talk to Us

Wise men have said, "All good things must come to an end", and so it was with Spruce. We began our first project in 2006, and completed our last in Fall 2013. It's been a wonderful experience, but now it's time to begin the next adventure.

Though...we wouldn't want to leave you hanging, now would we? Here are our top recommendations for world-class branding, design, and web development:

  • Kristina (KJ) Parish and Beam Collective:
    KJ provided the artistic vision that allowed Spruce to succeed, and we still think she's the greatest designer in the entire world. She's started a new collective with some talented developers, and is covering much the same territory as Spruce--design and development all under one roof, with a caliber of service and professionalism seldom seen in this business or any other. If you like what you see on the Spruce site, then definitely get in touch with KJ at kj@beamcollective.com
  • Permanent Art & Design
    Permanent is a nationally recognized design & branding firm out of Minneapolis, MN. They've been a long term collaborator and strategic partner over the past couple years, and we'd recommend them for medium to large sized businesses/organizations who are serious about putting their best foot forward. In addition to design, Permanent offers strategy and marketing services, plus in-house and networked developers. For more information contact Joseph Belk joseph@permanentadg.com
  • Nate Thompson
    A freelancer, Nate reminds us of ourselves back in the day. Smart, communicative, and skilled, Nate is our recommendation for small to medium sized businesses/organizations who have sites built on Wordpress or other open source content management solutions. With a background in both design and development, he's a one-stop shop for most web-related tasks. You can get in touch at nate.a.thompson@gmail.com
  • Kevin DeBernardi
    Designer turned developer, Kevin is embarking on a freelance web career after working as the in-house designer at the Museum of the City of New York. He's adept at translating his design ideas into custom PHP code, and is constantly expanding his technical palette. Kevin's a good choice for projects that don't quite fit into the Wordpress mold, and that would benefit from a consistency of presence and vision from design through execution. Kevin can be reached at kevin@analoglifestyle.com