3

In WordPress I want to schedule an Event which will run my function (hook) at a specific time (let's say at 6PM) and then it will run again after 15 minutes (means at 6:15 PM) and keep running after every 15 minutes for 3 hours (till 9 PM) and then it dies.

// I have the following code which run after every 6 hours
function myprefix_custom_cron_schedule( $schedules ) {
    $schedules['every_six_hours'] = array(
        'interval' => 21600, // Every 6 hours
        'display'  => __( 'Every 6 hours' ),
    );
    return $schedules;
}
add_filter( 'cron_schedules', 'myprefix_custom_cron_schedule' );

// Schedule an action if it's not already scheduled
if ( ! wp_next_scheduled( 'myprefix_cron_hook' ) ) {
    wp_schedule_event( time(), 'every_six_hours', 'myprefix_cron_hook' );
}

// Hook into that action that'll fire every six hours
add_action( 'myprefix_cron_hook', 'myprefix_cron_function' );

// create your function, that runs on cron
function myprefix_cron_function() {
    // your function...
}
  • 1
    WordPress Cronjobs are not as precise as server cronjobs. They rely on users visiting the site, unknowingly triggering the actions to set off the cronjob. This could cause the execution time to vary depending on your sites traffic. If you need something precise you're better off using a traditional server cronjob that you know will run at XYZ no matter what. – Howdy_McGee Jul 30 '18 at 16:38
  • Yes i know that but Ipage (my Hosting Provider) didn't have cron job in my plan.. That's why i have no more option to do this with Wordpress Cron Job. – Thomas Jul 30 '18 at 16:42
  • 1
    Use an online cron service like this. – Fayaz Jul 30 '18 at 16:50
  • If you know Google App script, then you can also use a Google Sheet to program the scheduled calls to wp-cron. – Fayaz Jul 30 '18 at 16:52
  • @Fayaz i will use cron-job.org to ping wp-cron.php file. In actual i wanted to Publish a post on different condition in callback function of cron Hook. so i think i must need the interval or code which i asked in the Question. – Thomas Jul 30 '18 at 17:21
4

Setup WordPress Cron Events

Let's say you want to start the cron at 6PM and keep running the cron after every 15 minutes till 9PM (for 3 hours). Then all cron stops.

Note: for the simplicity of implementation, all time entry in the CODE is considered to be GMT/UTC.

For this, you need to schedule two cron events, one will start at 6PM and keep running at every 15 minutes from 6PM. The other one will be one time cron event that'll run at 9PM. This one will stop the other cron.

The plugin CODE will be something like the following:

<?php
/*
Plugin Name:  WPSE Custom Cron
Plugin URI:   https://wordpress.stackexchange.com/a/309973/110572
Description:  Custom Cron Plugin
Version:      1.0.0
Author:       Fayaz Ahmed
Author URI:   https://www.fayazmiraz.com/
*/

add_action( 'wpse_custom_cron_event',        'wpse_custom_cron' );
add_action( 'wpse_custom_cron_event_stop',   'wpse_custom_cron_stop' );

function wpse_custom_cron() {
    // Your Custom Cron CODE HERE
}

function wpse_custom_cron_start() {
    // Calculate the start time: e.g. whenever the next 6:00PM (UTC) is.
    $cron_start_time = strtotime( "today 6:00pm" );
    // If 6PM has already passed today, set it to 6PM next day
    if( $cron_start_time < time() ) {
        $cron_start_time = $cron_start_time + 24 * HOUR_IN_SECONDS;
    }

    if ( ! wp_next_scheduled( 'wpse_custom_cron_event' ) ) {
        wp_schedule_event( $cron_start_time, 'fifteen_minutes', 'wpse_custom_cron_event' );
    }

    if ( ! wp_next_scheduled( 'wpse_custom_cron_event_stop' ) ) {
        // this 1 time cron will stop the original cron 'wpse_custom_cron_event' after 3 hours of starting 
        $cron_stop_time = $cron_start_time + 3 * HOUR_IN_SECONDS;
        wp_schedule_single_event( $cron_stop_time, 'wpse_custom_cron_event_stop' );
    }
}

function wpse_custom_cron_stop() {
    // removing all possible custom cron events named 'wpse_custom_cron_event'
    while( false !== wp_unschedule_event( wp_next_scheduled( 'wpse_custom_cron_event' ), 'wpse_custom_cron_event' ) ) {}
}

// Add a 15 minutes custom cron schedule
add_filter( 'cron_schedules', 'wpse_custom_cron_schedule' );
function wpse_custom_cron_schedule( $schedules ) {
    $schedules['fifteen_minutes'] = array(
        'interval' => 15 * 60,
        'display'  => esc_html__( 'Every Fifteen Minutes' ),
    );
    return $schedules;
}

// schedule the cron event on plugin activation
register_activation_hook( __FILE__, 'wpse_custom_cron_plugin_activation' );
function wpse_custom_cron_plugin_activation() {
    wpse_custom_cron_start();
}
// remove the cron event on plugin deactivation
register_deactivation_hook( __FILE__, 'wpse_custom_cron_plugin_deactivation' );
function wpse_custom_cron_plugin_deactivation() {
    wpse_custom_cron_stop();

    // in case the stop event didn't run yet
    while( false !== wp_unschedule_event( wp_next_scheduled( 'wpse_custom_cron_event_stop' ), 'wpse_custom_cron_event_stop' ) ) {}
}

This sample plugin will start the cron on plugin activation, but if needed, you can edit the CODE to start the cron by other means as well (say using a button click in admin panel) using the wpse_custom_cron_start() function.

Also, if you want to run the same cron everyday 6PM (not just one time after activation), then simply change the wp_schedule_single_event call in wpse_custom_cron_start() function to:

wp_schedule_event( $cron_stop_time, 'daily', 'wpse_custom_cron_event_stop' );

Note: Event/Cron created with arguments

If you create the event/cron with an argument, you must also stop the event with the exact same argument.

For example, if you created the event like this (in wpse_custom_cron_start() function of the above CODE):

....
wp_schedule_event( $cron_start_time, 'fifteen_minutes', 'wpse_custom_cron_event', $args1 );
....
wp_schedule_single_event( $cron_stop_time, 'wpse_custom_cron_event_stop', $args2 );

then when stopping the events, you must also use the exact same argument in wp_next_scheduled() function call. So the stop CODE will become like:

....
while( false !== wp_unschedule_event( wp_next_scheduled( 'wpse_custom_cron_event', $args1 ), 'wpse_custom_cron_event' ) ) {}
....
while( false !== wp_unschedule_event( wp_next_scheduled( 'wpse_custom_cron_event_stop', $args2 ), 'wpse_custom_cron_event_stop' ) ) {} 

Again, remember, it has to be the exact same argument, even different data type will not work. For example, in the following CODE, $args1 and $args2 are NOT the same, but $args1 and $args3 are same:

$args1 = array( 'key' => 1 );
$args2 = array( 'key' => '1' );
$args3 = array( 'key' => 1 );

because '1' is string and 1 is a number.

This is important because, sometimes people save the arguments in database as key value pairs, & when they use it again later, the value from database doesn't work for arguments that were numbers, as the numbers are converted to strings when retrieved from database. So you must convert them back to numbers when passing the argument to the wp_next_scheduled() function.

for more information, check the documentation:

Running the Cron:

The best way to run WordPress cron is to set define('DISABLE_WP_CRON', true); in wp-config.php file and then run the cron from system crontab as described in this post.

Use external cron service:

In case you cannot set crontab, you may use an external cron service like cron-job.org and set the cron accordingly.

For example, for the above cron events, you may set a single cron job there with a setting like:

cron-job.org settings

Here, all the values of Days of Month, Days of Week & Months are selected; and Hours selected to 18, 19, 20 and Minutes selected to 0, 15, 30, 45. Which means: run cron Everyday from 6PM to 9PM (GTM is set as time zone from account setting) on 0th, 15th, 30th and 45th minute (i.e. at 15 minutes interval).

Cron Check + Manual Cron:

You may check if your cron schedules properly using WP Control plugin. This plugin can also be used to set up custom cron events and intervals.

  • Your Code Almost Solve my Problem but the even which will stop the crons is firing but not unscheduling my cronjOB. Please review my code and suggest me (pastebin.com/t5ND5JW5) – Thomas Jul 31 '18 at 13:20
  • That's because when you create event/cron with arguments, you must also use exactly the same argument in wp_next_scheduled function to stop the cron. Check the function documentation. – Fayaz Jul 31 '18 at 15:35
  • for example: while( false !== wp_unschedule_event( wp_next_scheduled( 'gh_post', $args ), 'gh_post' ) ) {} → make sure you pass the $args argument, and this $args must be the same as the one used in: wp_schedule_event( $next_run, 'fifteen_minutes', $hookname, $args ); – Fayaz Jul 31 '18 at 15:38
  • Check the updated Note: Event/Cron created with arguments section in my answer about arguments. – Fayaz Jul 31 '18 at 16:03
0

to do that, it's better to have a cron that is fired every 15 minutes and then you test if it's time to do the treatments or if it's time to wait.

you can try something like that :

const ACTIVE_PERIOD = 3 * HOUR_IN_SECONDS;
const WAITING_PERIOD = 6 * HOUR_IN_SECONDS;

const TRANSIENT_STATE = "TestCron__state";
const TRANSIENT_TIMEOUT = "TestCron__timeout";


add_action("TestCron/cron/execution", function () {


    $state = get_transient(TRANSIENT_STATE);

    if (FALSE === $state) {
        set_transient(TRANSIENT_STATE, "waiting");
        set_transient(TRANSIENT_TIMEOUT, time() + WAITING_PERIOD);
    }


    if (get_transient(TRANSIENT_TIMEOUT) < time()) { // state change

        if ("waiting" === get_transient(TRANSIENT_STATE)) {
            set_transient(TRANSIENT_STATE, "active");
            set_transient(TRANSIENT_TIMEOUT, time() + ACTIVE_PERIOD);
        } else {
            set_transient(TRANSIENT_STATE, "waiting");
            set_transient(TRANSIENT_TIMEOUT, time() + WAITING_PERIOD);
        }

    }


    if ("waiting" === get_transient(TRANSIENT_STATE)) {
        // continue to sleep
        return;
    }


    // here actions to do
    do_action("myprefix_cron_hook");



});


add_action("wp_loaded", function () {

    if (!wp_next_scheduled("TestCron/cron/execution")) {
        wp_schedule_event(1, "15_minutes", "TestCron/cron/execution");
    }

});


add_filter("cron_schedules", function ($cron_schedules) {

    $cron_schedules["15_minutes"] = [
        "display" => "15 minutes",
        "interval" => 15 * MINUTE_IN_SECONDS,
    ];

    return $cron_schedules;

});

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.