5

I have created a plugin that adds products programatically to WooCommerce. The plugin is working great, but now I need to make a cron job that runs every 5 minutes to update the inventory.

I have the script all written but I need to include calls to get_option() in this php file to get certain plugin values that the user has entered. However, I can't just include get_option() in this file because it is outside of the Wordpress core. So my thought would be to put in require( 'path/to/wp-load.php' ); which I know you aren't really supposed to do. Anyway it fixes the issue if you hit the page via a web browser request. However the cron job fails the moment that this file is included because somewhere with wp-load.php it is sending HTTP_Header requests.

Any thoughts or solutions? I tried to add define('WP_USE_THEMES', false); right above the requiring of wp-load.php but it is still causing the cron job to fail.

Long winded I know, but how do you include get_option() requests inside of a external PHP script that will be accessed via a PHP cron job.

Thanks much.

Gouda Elalfy
  • 6,888
  • 1
  • 26
  • 38
  • You don't want to do it that way. Use the built-in WP Cron system. If you need a reliable 5 minute cron job, then you actually set up a cron job that triggers the built-in WP cron system: [Schedule Events Using WP Cron](http://www.smashingmagazine.com/2013/10/schedule-events-using-wordpress-cron/) – random_user_name Dec 15 '15 at 15:54
  • I suppose for whatever reason it isnt possible to put this file inside the wordpress folder structure? – fully stacked geek Dec 15 '15 at 15:54
  • @Theavonguy - that's not the way to do it. I've been down this road (lots of experience). You CAN "bootstrap" WP without running the front-end, but that is NOT the proper way to hook / trigger cron jobs for WP plugins. – random_user_name Dec 15 '15 at 15:55
  • @cale_b I don't agree, WP cron system is not reliable for this kind of jobs as it is dependant to if someone visit your website every 5min. For this kind of case including _wp-load.php_ to get the WP core is the right way to go. – vard Dec 15 '15 at 16:10
  • @vard - That **used to be** my concern also, however you can set up a true cron job to trigger the wp_cron. Read the article I linked, that is discussed. – random_user_name Dec 15 '15 at 16:11
  • @cale_b Ah, I see what you mean. I guess that's a possible way to go indeed. – vard Dec 15 '15 at 16:12
  • @caleb_b can you look at the comment that I made below on vard's post about the cron job. I think I have it set up correctly but it isn't displaying anything when I hit it in the browser like I thought it would/should? – Patrick Sasser Dec 15 '15 at 19:32

1 Answers1

3

The quick and easy way

The problem is probably that you try to include wp-load.php from a wrong path. In a CLI environment, the path would not be the same as when you do an HTTP request to the file. So with this you should fixed your issue:

require(dirname(__FILE__) . '/../../../wp-config.php');

The proper but longer way

Based on cale_b comments and this article he linked, there is a much proper way to go by doing a Wordpress Cron job.

First in your plugin add a function that will contain the code needed to be executed, let's call it my_cron_job(). You can eventually just include the script you already wrote in this function. Then add the following to schedule the execution of this every 5min:

// Define a new interval (5 minutes)
add_filter('cron_schedules', 'fively_interval');
function fively_interval($interval) {
    $interval['fively'] = array('interval' => 5*60, 'display' => 'Once 5 minutes');
    return $interval;
}

// Register the hook on plugin activation
register_activation_hook(__FILE__, 'my_cron_job_activation');
add_action('my_cron_event', 'my_cron_job');
function my_cron_job_activation() {
    wp_schedule_event(time(), 'fively', 'my_cron_event');
}

// Unregister the hook on plugin deactivation
register_deactivation_hook( __FILE__, 'my_cron_job_deactivation' );
function my_cron_job_deactivation(){
  wp_clear_scheduled_hook( 'my_cron_event' );
}

Then set up your cron to execute wp-cron.php every 5 minutes:

*/5 * * * * php-cli -f [path to your WP]/wp-cron.php

Update

First when choosing the option of executing wp-cron.php with a server cron you should disable the default WP Cron behaviour (execution of cron through web visits):

define('DISABLE_WP_CRON', true);

Secondly, as for your question about WP Cron reliability I see a potential flaw indeed. I'm not 100% sure of that, but I think it is possible that wp_schedule_event get desynchronized with the server cron, as the job get executed only if the interval is past. As it will be re-scheduled depending of the execution time of the script which is slightly different with the server cron time.

For example:

00:00:00:000    Server cron execute wp-cron.php
00:00:00:100    The job can be executed, so let it run
00:00:00:200    Wordpress finished to execute the job - it schedule the event in 5min
00:05:00:000    Server cron execute wp-cron.php
00:05:00:100    The job is planned for 00:05:00:200, no execution !
00:10:00:000    Server cron execute wp-cron.php
00:10:00:100    The job is executed

That's theory of course, maybe this is not accurate. I suggest doing some test and see how it behave. If it indeed behave like I think it did, I suggest as easy workaround to change the wp_schedule_event to a lower interval - 4min for example.

add_filter('cron_schedules', 'fourly_interval');
function fourly_interval($interval) {
    $interval['fourly'] = array('interval' => 4*60, 'display' => 'Once 4 minutes');
    return $interval;
}

So we'll have the following:

00:00:00:000    Server cron execute wp-cron.php
00:00:00:100    The job can be executed, so let it run
00:00:00:200    Wordpress finished to execute the job - it schedule the event in 4min
00:05:00:000    Server cron execute wp-cron.php
00:05:00:100    The job is planned for 00:04:00:200, so let it run!
00:10:00:000    Server cron execute wp-cron.php
00:00:00:200    Wordpress finished to execute the job - it schedule the event in 4min
00:10:00:100    The job is executed (planned for 00:09:00:200)

With the default WP Cron behaviour disabled it should work flawlessly.

vard
  • 4,057
  • 2
  • 26
  • 46
  • I'm now trying to set the cron up through wp_cron. I changed the cron path in my hosting environment to hit wp-cron.php every 5 min. And I added this code http://puu.sh/lWFWm/e757147b17.png. When I hit the wp-cron.php in the browser should it be printing out yes? – Patrick Sasser Dec 15 '15 at 18:35
  • Also I did have `chdir(dirname(__FILE__)); require( '../../../wp-load.php' );` in the top of that cron file. Still investigating why it didn't work. – Patrick Sasser Dec 15 '15 at 18:39
  • Ok I figured out why the original cron job wasn't working in my wp-config.php file I had this code `define('WP_HOME', 'http://' . $_SERVER['HTTP_HOST']); define('WP_SITEURL', 'http://' . $_SERVER['HTTP_HOST']); define('DOMAIN_CURRENT_SITE', $_SERVER['HTTP_HOST']);` when I hardcode those values in there the original cron starts working. The one that was referencing wp-load.php. But I'm still interested in making it work with the wp-cron.php so let me know on my other comments. Thanks much. – Patrick Sasser Dec 15 '15 at 19:14
  • Ok I figured out how to what was wrong with my code above my function had to be called `my_cron_job()` like you said and I for some reason named it `my_cron_event()` So now all I have to do is set my cron job to hit wp-cron.php every 5 minutes? My cron will send me a results email. Will there be any "results" from the cron like text that I have printed in my cron job or anything or is that not returned? – Patrick Sasser Dec 16 '15 at 00:35
  • Well I suggest to encapsulate your code with an [output buffering](http://php.net/manual/en/function.ob-get-clean.php) to capture everything that is being echo during your cron, and send this buffer result by mail. – vard Dec 16 '15 at 08:43
  • At the moment I'm torn with whether or not to use the wp-load method or to use the wp-cron method. Both of them are working, but for some reason wp-cron feels less efficient because there are like 5-6 cron jobs that are running through wp-cron (from WooCommerce). So if I hit wp-cron.php with my cron job wouldn't that cause all of those other jobs to run? Also is it full proof that wp-cron.php will run the script that I put in every 5 min if that's how often I hit that file? – Patrick Sasser Dec 16 '15 at 19:07
  • Well the other jobs are not a problem, as they're probably not planned to run every 5min only your job will run most of the time. As for your other question, it's a very good one. I updated my question to bring some explanations about that. – vard Dec 17 '15 at 16:41