WordPress cron job

I am confused by the wording that the cron job starts “only activates when someone visits your site”. Does that mean every new visitor will trigger the job? i need only one job that runs regardless whether I have 1 or 100 visitors.

WordPress cron jobs are normally initiated by visitors. So, no visitors, no running cron jobs.
This does not mean WordPress will run all cron jobs in each visit. It means on each visit it will check if there are any cron jobs due and if there are, start them.

If you want you can disable this type of cron and run your own cron from the command line instead, using WP CLI.

2 Likes

if first visitor started the cron job already when the second visitor comes there will be nothing due since visitor #1 already started it?

Indeed, that’s it.

So say you have a cron job that needs to run every 15 minutes. The first visitor will trigger it. The next visitor a minute later won’t. The next one after that, say 10 minutes later, also won’t. Then for thirty minutes you get no visitors at all, so no cron job is started. Then a visitor comes and triggers it again.

So, it’s fine for cron jobs where whatever they do isn’t time critical. If you have something that is time critical you’d better look for an alternative way.

does the user need to interact with the page? say page is loaded at 1:15pm and cron is triggered. if user is only looking at the page for next 15 minutes would cron run again at 1:30pm?

They need to browse to different pages. Only server requests trigger the cron.

@Stribor45,

As you’ve noted, the functionality of WordPress cron jobs depends on on-site visits, but perhaps not in the way you imagine. This mechanism doesn’t mean every new visit to your site triggers the execution of all pending cron jobs. Instead, WordPress checks for pending cron jobs every time someone visits your site.

If a cron job is scheduled and its time has come (or passed), that visit will trigger its execution. However, only those cron jobs due will be executed; not every visit results in every job running.

For example, if you’ve set a cron job to run every 15 minutes, it will only be activated by the first visit after that 15-minute interval has passed. Visits within the interval won’t trigger the job again.

If your site has a visitor at 1:00 PM, which triggers a cron job, another visit at 1:01 PM won’t trigger the same job. If there are no visits for a while, say until 1:45 PM, then that 1:45 PM visit will check, see that the job is due again, and trigger it.

This behaviour ensures that WordPress sites without constant traffic can still manage tasks automatically, albeit with the caveat that tasks are only checked and possibly run upon someone visiting the site. For operations that are not time-sensitive, this approach can be efficient.

However, relying upon on-site visits to trigger cron jobs may not be ideal for tasks where timing is crucial. In such cases, you might consider turning off the default WP-Cron behaviour and setting up a real cron job through your hosting environment or using the command line with WP-CLI.

This method lets you precisely control when your cron jobs run, independent of site traffic, ensuring that time-sensitive tasks are handled precisely when needed.

This setup might require more technical know-how, as you’ll need to access your server via SSH or your hosting control panel to create a real cron job. However, for critical tasks, this extra step ensures reliability and consistency in execution, regardless of your site’s visitor traffic.

Regards,
Michael Swan

1 Like

server requests? You mean if some is browsing/reading same page for 20 min or so that wont trigger cron job?

Indeed, if somebody is just looking at a page a cron job won’t be trigger, as there is no communication from the browser to the server in that time frame.

1 Like

ok I am trying to test this in my XAMPP environment and I am having trouble with this code which I placed at the end of my theme functions file.

function my_custom_cron_job() {
    echo "Hello world";
    file_put_contents('C:\xampp\htdocs\testsite\file.txt', 'Cron job ran at ' . date('Y-m-d H:i:s') . "\n", FILE_APPEND);
}

if (!wp_next_scheduled('my_custom_cron_hook')) {
    wp_schedule_event(time(), 'every_fifteen_minutes', 'my_custom_cron_hook');
}

function my_custom_cron_interval($schedules) {
    $schedules['every_fifteen_minutes'] = array(
        'interval' => 15*60, // Number of seconds
        'display'  => 'Every 15 Minutes',
    );
    return $schedules;
}
add_filter('cron_schedules', 'my_custom_cron_interval');

add_action('my_custom_cron_hook', 'my_custom_cron_job');

//my_custom_cron_job();

but when I unblock that last line of code it runs fine?

That is the function call. When it is commented out, I guess the function never gets called anywhere, so never runs.

How did you test it?

To test stuff like this I always try with something I can quickly test first. So don’t start with 15 minutes, start with every 10 seconds, see what happens. Once you know what’s what, increase to 15 minutes.

I know but i was under impression that “add_action” will call it.

add_action('my_custom_cron_hook', 'my_custom_cron_job');

I hope that this explains things better. With each page load, you need to ensure that “add_action,” much like “register_post_type,” is loaded into WordPress’s memory.

Due to this misunderstanding, even though the cron system would trigger your function, the “add_action” directive was effectively ephemeral, only present in WordPress’s understanding for the duration of that request.

It’s an important distinction, especially when working with WordPress’s hooks and cron jobs.

// Ensuring a kick-off action that allows access to all required data, which could be 'template_redirect' or another suitable action
add_action( 'init', 'setup_my_custom_cron_job' );

function setup_my_custom_cron_job() {
    // Normally, you might fetch some data from the database or elsewhere to pass to your scheduled event
    // For simplicity, these are not fetched but could be added dynamically
    $additional_data = 'Some dynamic data here'; // Example of data you might want to use
    $args = array( $additional_data );

    // Check if the custom cron job is not already scheduled with the specific arguments
    if ( ! wp_next_scheduled( 'my_custom_cron_hook', $args ) ) {
        wp_schedule_event( time(), 'every_fifteen_minutes', 'my_custom_cron_hook', $args );
    }
}

// The callback function that will be triggered by the cron event, revised to accept and use arguments
add_action( 'my_custom_cron_hook', 'my_custom_cron_job_callback', 10, 1 );

function my_custom_cron_job_callback( $additional_data ) {
    echo "Hello world with additional data: $additional_data";
    file_put_contents('C:\xampp\htdocs\testsite\file.txt', 'Cron job ran at ' . date('Y-m-d H:i:s') . ' with data: ' . $additional_data . "\n", FILE_APPEND);
}

// Customizing the cron schedule by adding a new interval
function add_my_custom_cron_interval( $schedules ) {
    // Adding a new interval of every fifteen minutes
    $schedules['every_fifteen_minutes'] = array(
        'interval' => 15 * 60, // 15 minutes in seconds
        'display'  => __( 'Every 15 Minutes', 'textdomain' ) // Display name in the admin scheduler
    );
    return $schedules;
}
add_filter( 'cron_schedules', 'add_my_custom_cron_interval' );

I am using the code you provided and explaining it with comments within the code. Let me know if that helps.

Regards,
Michael Swan

thank you. I als0 installed cron mananger and I am curious why it is showing so many jobs

The issue leading to creating multiple cron jobs instead of a singular one lies in how the $args parameter is used in the wp_next_scheduled and wp_schedule_event functions. Specifically, the $args array is populated with dynamic data ($additional_data = ‘Some dynamic data here’;).

Since this data will likely change between requests (even if it’s just considered for demonstration here and not fetched from a database), each check with wp_next_scheduled sees the arguments as unique.

Consequently, WordPress treats each scheduled event as distinct because the arguments differ, leading to multiple cron jobs being scheduled rather than updating or maintaining a singular job.

To avoid scheduling multiple cron jobs, it’s essential to maintain consistency in the arguments used in wp_next_scheduled and wp_schedule_event.

If the dynamic data is necessary for the cron job’s operation, a viable solution is to store it in a location that the cron job callback function can access. This eliminates the need to pass it to the scheduling functions as an argument.

By adopting this approach, you can use static or no arguments in the scheduling check, effectively preventing the unintended scheduling of multiple jobs.

Here is a revised approach without dynamic $args:

// Ensuring a kick-off action that allows access to all required data, which could be 'template_redirect' or another suitable action
add_action( 'init', 'setup_my_custom_cron_job' );

function setup_my_custom_cron_job() {
    // Check if the custom cron job is not already scheduled
    if ( ! wp_next_scheduled( 'my_custom_cron_hook' ) ) {
        wp_schedule_event( time(), 'every_fifteen_minutes', 'my_custom_cron_hook' );
    }
}

// The callback function that the cron event will trigger
add_action( 'my_custom_cron_hook', 'my_custom_cron_job_callback' );

function my_custom_cron_job_callback() {
    // Here, fetch the dynamic data directly within the callback if needed
    $additional_data = 'Some dynamic data here'; // Example of fetching data dynamically
    echo "Hello world with additional data: $additional_data";
    file_put_contents('C:\xampp\htdocs\testsite\file.txt', 'Cron job ran at ' . date('Y-m-d H:i:s') . ' with data: ' . $additional_data . "\n", FILE_APPEND);
}

// Customizing the cron schedule by adding a new interval
function add_my_custom_cron_interval( $schedules ) {
    // Adding a new interval of every fifteen minutes
    $schedules['every_fifteen_minutes'] = array(
        'interval' => 15 * 60, // 15 minutes in seconds
        'display'  => __( 'Every 15 Minutes', 'textdomain' ) // Display name in the admin scheduler
    );
    return $schedules;
}
add_filter( 'cron_schedules', 'add_my_custom_cron_interval' );

This modification ensures that wp_next_scheduled checks for the existence of the scheduled event without considering the variable data, thereby preventing the creation of multiple instances for what should be a singular cron job.

I hope this helps!

Michael Swan

1 Like

This is great thank you!!! I was able to make this work but will have to modify something for my needs. Is this line of code where you adjust the schedule. i will need it to run every minute.

 'interval' => 15 * 60, // 15 minutes in seconds

 'interval' => 1 * 60, // 1 minutes in second

Also i noticed that the cron is executing even thought I have the WP page open but not interacting with it at all. execution’s time is not exactly at 15 minutes intervals but this is not critical just curious why?

Cron job ran at 2024-04-10 15:23:43 with data: 1448583270
Cron job ran at 2024-04-10 15:39:03 with data: 2092495082
Cron job ran at 2024-04-10 15:53:43 with data: 735813304
Cron job ran at 2024-04-10 16:09:31 with data: 485867963
Cron job ran at 2024-04-10 16:23:43 with data: 1292688403
Cron job ran at 2024-04-10 16:38:53 with data: 919076448
Cron job ran at 2024-04-10 16:55:00 with data: 1527921387
Cron job ran at 2024-04-10 17:09:24 with data: 300645582
Cron job ran at 2024-04-10 17:24:16 with data: 361887751
Cron job ran at 2024-04-10 17:43:07 with data: 1023957052
Cron job ran at 2024-04-10 17:53:43 with data: 369318283
Cron job ran at 2024-04-10 18:16:12 with data: 387223755
Cron job ran at 2024-04-10 18:25:36 with data: 1824987122
Cron job ran at 2024-04-10 18:40:28 with data: 1439777833
Cron job ran at 2024-04-10 18:54:10 with data: 177215734
Cron job ran at 2024-04-10 19:10:16 with data: 247360704
Cron job ran at 2024-04-10 19:43:07 with data: 880557555




As another member stated, “Indeed if somebody is just looking at a page, a cron job won’t be triggered, as there is no communication from the browser to the server in that time frame.”.

This could be your test environment causing this or something missing from the code.

I provided a base for you to work from, but you must make the required edits.

Regards,
Michael Swan

If you look at the access logs of your web server, e.g., nginx or apache, you should be able to figure out what requests are being made.

Is there other way the cron job can be done that doesn’t need OS (task scheduler)?