There has been much discussion about a recent bug/issue with Wordpress that prevents scheduled posts from working properly. The problem is somewhat unrelated to Wordpress itself, and is primarily a hosting setup issue. Scheduled posts are published via the use of a cron script. Wordpress attempts to call the cron script with an fsockopen() function call. Many popular hosts disable the use of fopen() in their PHP configuration, which also disables the fsockopen() function, preventing your cron from firing which prevents your scheduled posts from being published.
A more robust way of programming this part of the code would be to try other functions like curl on failure of the original fsockopen() call. If curl is unavailable, then the calling script should just execute the code contained within the wp-cron.php file itself, instead of trying to make an http request to execute it.
I’ve put together a simple fix for sites that cannot use the fsockopen() function. It’s a simple addition, and just requires attention when upgrading. Steps for upgrading are detailed below the fix.
Open up your wp-cron.php file and copy the contents following the “if ( $_GET['check'] != wp_hash(’187425′) ) exit;” line.
Now you are going to have to paste these lines at the very end of the spawn_cron() function in wp-includes/cron.php. After pasting them in you are going to have to change the “if ( $argyle )” clause to be an if/else clause. This will cause the else clause to execute when fsockopen() fails.
In Wordpress 2.6.3, the spawn_cron() function within the wp-includes/cron.php file will now look like this:
function spawn_cron() { $crons = _get_cron_array(); if ( !is_array($crons) ) return; $keys = array_keys( $crons ); if ( array_shift( $keys ) > time() ) return; $cron_url = get_option( 'siteurl' ) . '/wp-cron.php'; $parts = parse_url( $cron_url ); if ($parts['scheme'] == 'https') { // support for SSL was added in 4.3.0 if (version_compare(phpversion(), '4.3.0', '>=') && function_exists('openssl_open')) { $port = isset($parts['port']) ? $parts['port'] : 443; $argyle = @fsockopen('ssl://' . $parts['host'], $port, $errno, $errstr, 0.01); } else { return false; } } else { $port = isset($parts['port']) ? $parts['port'] : 80; $argyle = @ fsockopen( $parts['host'], $port, $errno, $errstr, 0.01 ); } if ( $argyle ) { fputs( $argyle, "GET {$parts['path']}?check=" . wp_hash('187425') . " HTTP/1.0\r\n" . "Host: {$_SERVER['HTTP_HOST']}\r\n\r\n" ); } else { //BEGIN COPIED wp-cron.php CONTENTS if ( get_option('doing_cron') > time() ) exit; update_option('doing_cron', time() + 30); $crons = _get_cron_array(); $keys = array_keys($crons); if (!is_array($crons) || $keys[0] > time()) return; foreach ($crons as $timestamp => $cronhooks) { if ($timestamp > time()) break; foreach ($cronhooks as $hook => $keys) { foreach ($keys as $key => $args) { $schedule = $args['schedule']; if ($schedule != false) { $new_args = array($timestamp, $schedule, $hook, $args['args']); call_user_func_array('wp_reschedule_event', $new_args); } wp_unschedule_event($timestamp, $hook, $args['args']); do_action_ref_array($hook, $args['args']); } } } update_option('doing_cron', 0); //END COPIED wp-cron.php CONTENTS } }
Upgrading
It is very important to remember that you’ll have to take special precautions when upgrading. When upgrading, you are going to have to perform the same copy/paste and alter within the wp-includes/cron.php file. Take whatever the contents of the wp-cron.php file are and copy them after the above mentioned hash check line.
