Logged-out Users Run Your WordPress Cron Jobs

💡 Code that works in a plugin might not behave the same in a scheduled wp-cron job.

Things That Don’t Always Work in WordPress Cron Jobs

  1. get_posts() calls that return posts with unpublished statuses
    Workaround: use $wpdb queries to retrieve posts or force admin
  2. tax_input parameter during wp_insert_post() or wp_update_post() calls
    Workaround: use wp_set_object_terms() or force_admin
  3. wp_get_update_data()
  4. Other functions or codes that call current_user_can() or current_user_can_for_blog()

Why do wp-cron jobs behave differently?

WordPress cron jobs are triggered by any visitor to your site on or after the scheduled time. A logged-out visitor could be running your WordPress cron job.

Any code that uses current_user_can() to restrict permissions can behave differently during wp-cron, including get_posts() and wp_update_post() calls.

SOLUTIONS

1. Test Your Code as a Logged-Out Visitor

Testing wp-cron job code with a tool that runs tasks on demand (like the fantastic Advanced Cron Manager) will fool you into believing the code will always run as an Administrator user. It’s not true. Use a short interval during development so it’s easier to trigger jobs as a logged-out visitor.

2. Briefly Force Administrator

Use wp_set_current_user() to explicitly use an Administrator account at the beginning of your job’s code, and restore the original user ID even if zero to avoid leaking Administrator privileges.

$user_id = get_current_user_id(); //could be 0
wp_set_current_user( 1 ); //1 is the user ID of an Administrator

//do the stuff that needs to run as an admin
$drafts = get_posts( array(
	'post_status' => 'draft', //drafts aren't accessible to logged-out users
) );

//don't leak Administrator privileges, restore the previous user even 
wp_set_current_user( $user_id );

2. Use Real Cron

Almost every hosting company on the planet has written an article about triggering wp-cron with a real cron job. Here’s one at Kinsta.