2

I am writing custom plugin for Woocommerce based bakery. The thing is, that it has stocks based on orders from two days before. Product A is produced in an amount of 500 pieces. Stock is reduced by the number of items ordered 2 days ago ($sum global). I wrote that function, and it works (I guess), BUT still i have to call this function every day at midnight (24:00 / 12 a.m.)

The best solution is cron, I heard that WP has its own crown-like function, that works only if there is traffic.

Do you think that it's good idea to use WP cron over real cron? There are about 100 people visiting page daily.

Could you please help me edit the code below, to archive these points?

1) Fire function everyday at 24:00 2) Update stock with value inside custom_post_meta auto_restock_value minus orders qty from 2 days before (global variable $sum). This should work (?) 3) Save values and repeat everyday.

Thank you in advance!

$post_id = $_GET['post'];

function update_restock_value() {
    global $post_id;
    $val = get_post_meta( $post_id, 'auto_restock_value', true );
    echo '<div class="option_group">';

    woocommerce_wp_text_input( array(
        'id'          => 'auto_restock_value_id',
        'value'       => $val,
        'type'        => 'number',
        'label'       => 'Auto - uzupełniany stan magazynowy',
        'desc_tip'    => true,
        'name'        => 'auto_restock_value',
        'description' => 'Ta wartość, codziennie o 24:00, nadpisze stan magazynowy danego produktu',
    ) );

    echo '</div>';
}


//register_activation_hook( __FILE__, 'my_custom_cron' );
//add_action( 'my_hourly_event', 'do_this_hourly' );

//function my_custom_cron() {
    //wp_schedule_event( time(), 'hourly', 'update_cart_stock' );
//}

function post_order() {
    $args = array(
        'type' => 'shop_order',
        'status' => 'processing',//zmienić//zmienić na completed
        'return' => 'ids',
        'date_created' => ( date("F j, Y", strtotime( '-2 days' ) ) ),//list orders from 2 days before
    );
    global $sum;
    $orders_ids = wc_get_orders( $args );

    foreach ($orders_ids as $order_id) {//get order Id, and show product qty of this product
        $order = new WC_Order( $order_id );
        $items = $order->get_items();
        foreach ( $items as $item ) {
            $product_id = $item->get_product_id();
            if($product_id == $_GET['post']) {//If product if is the same as current product, then update global $sum
                $product_qty = $item->get_quantity();
                $sum += $product_qty;
            }
        }
    }
}

add_action('init', 'post_order'); 

function update_cart_meta() {
    global $post_id;
    global $sum;
    echo '<p id="sum">' . $sum . '</p>';//checking if it works
    update_post_meta($post_id, '_stock', $sum);//update stock with orders qty from 2 das before
}

add_action('init', 'update_cart_meta');

function update_custom_meta() {
    global $post_id;
    $custom_value = $_POST['auto_restock_value'];
    update_post_meta($post_id, 'auto_restock_value', $custom_value);//update custom post meta field
}

add_action('save_post', 'update_custom_meta');

EDIT:

Question number 2 - why this action returns zero?

function update_cart_meta() {
    global $post_id;
    global $sum;
    echo '<p id="sum">' . $sum . '</p>';//checking if it works (it works)
    $custom_value = $_POST['auto_restock_value']; //(it works)
    $custom_output = $custom_value - $sum; // doesn't work, return 0
    update_post_meta($post_id, '_stock', $custom_value);//update stock with orders qty from 2 days before
}

add_action('init', 'update_cart_meta');
2
  • noon is midday, did you mean midnight? Keep in mind that answers won't include a copy paste solution with your code but with fixes. You will need to understand the answer to apply the solution, as such I believe to keep this on topic it should be phrased "How do I run code every 24 hours?"
    – Tom J Nowell
    Apr 5, 2020 at 11:51
  • Ugh, true. I corrected. Thanks :)
    – Slingy
    Apr 5, 2020 at 13:10

1 Answer 1

5

To run something every 24 hours, you can use the WP Cron system. However, keep in mind:

  • wp-cron is ran/checked after every page load by making a second request to wp-cron.php behind the scenes.
    • This means that if nobody visits your site for 2 days no cron jobs can run, it needs visitors to get an opportunity to run
    • It also means that the cron job runs on a new page request so no variables/POST/GET etc carry over from the request. It also means all the conditionals like is_page won't work because the new request is not for the page the user was just on, but a request to wp-cron.php
  • Because it needs visitors to the site for the chance to check, it won't run it at exactly the right time. If it's due at 12:00, but nobody visits until 13:01, then it won't have the opportunity until 13:01
  • Your code relies on $post_id = $_GET['post']; which will not be possible in a cron job, cron jobs are a separate web request, so there are no POST or GET values. You will need to store this value in an option somewhere so it knows what the post ID will be

Now we have the caveats out the way, this is how a daily WP Cron schedule should be set up:

if ( ! wp_next_scheduled( 'your_hook' ) ) { // if it hasn't been scheduled
    wp_schedule_event( time(), 'daily', 'your_hook' ); // schedule it
}


....


add_action( 'your_hook', 'your_function' );
function your_function() : void {
    //
}

I'd recommend doing this on the init hook. To make it happen after a specific time each day, modify the time passed to wp_schedule_event to the next time it should run. E.g. if it's 7pm monday the 5th, and we want it to run at 5pm every day, give it 5pm Monday the 6th. Doing that is a PHP problem not a WP problem though, and luckily stack overflow has a great answer here.

Making It Run At Exact Times Regardless of Visitors

If you have the good fortune of being able to set a system level cron job, you can remove the need for visitors to your site for WP Cron to work:

https://developer.wordpress.org/plugins/cron/hooking-wp-cron-into-the-system-task-scheduler/

  • disable WP Cron in wp-config.php
  • Manually run the cron event in WP from a system cron job ( crontab? )
    • by either pinging the URL directly
    • or using WP CLI to execute the cron job
    • if you're feeling adventurous and know your dev ops/server admin, setup the cavalcade service to run wp cron tasks
  • Note that if you're on a multisite, you will need to do this for every blog, WP Cron won't run for every single site if you don't explicitly run it for each one

Further Reading

For further reading, the official docs plugin handbook has a section on cron jobs:

https://developer.wordpress.org/plugins/cron/

2
  • Wow! I would love to give you a plus, but sadly - i have no power here (heh). So anyway, thank you very much!! You've really exhausted the topic for people starting their adventure with wp cron, I appreciate it.
    – Slingy
    Apr 5, 2020 at 12:55
  • But still, there is one thing, that I would like to ask you. It's directly related to my first question, so i will not write another post.
    – Slingy
    Apr 5, 2020 at 13:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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