Why WooCommerce Loyalty Points Stop Updating (WP-Cron)
If your WooCommerce loyalty points have stopped updating, expiring, or triggering emails, the most common cause is not a bug in the plugin. It is WP-Cron, WordPress’s built-in task scheduler, not running when nothing is visiting your site. Points that should update in the background sit frozen until a visitor’s page load happens to trigger the check, which on a quiet store can mean hours or days of silence.
What WP-Cron actually is
WordPress has no real background scheduler. wp-cron.php is not a system-level cron job unless a host configures one explicitly; by default, WordPress checks whether any scheduled task is due on every page load, triggered by a visitor’s request. If a task is due, WordPress runs it inline, as part of that visitor’s request, then moves on.
This works fine on a busy store. It falls apart on a quiet one. No visitor, no page load, no check, no task. A loyalty plugin that schedules “expire these points at midnight” or “send this milestone event to Klaviyo in five minutes” is handing WordPress a promise it can only keep if someone happens to load a page at the right time.
The three symptoms this produces
Points that stop accruing or expiring on schedule. A points expiry job scheduled for a specific time doesn’t fire until the next page load after that time, which could be minutes later or could be the next morning.
Emails and events that fire late, in a batch, or not at all. If a plugin relies on WP-Cron to push events to an email platform like Klaviyo, a quiet period means those events queue up and fire all at once on the next page load, or silently expire if the plugin doesn’t retry.
Behavior that looks intermittent and unreproducible. Because the trigger is “the next visitor,” the same action can appear to work instantly during testing (you’re the visitor, you refresh the page) and then apparently stop working in production, when traffic patterns are different from a developer’s test session.
How to check if this is actually happening on your site
- Install a query monitor or cron inspection plugin and check what’s scheduled and when it last ran versus when it was due.
- Compare the delay against your traffic pattern. If points update fine during the day and stall overnight, that’s the signature: no visitors, no cron checks.
- Check whether your host disabled the default trigger. Some managed WordPress hosts turn off the per-page-load check and rely on a real system cron hitting
wp-cron.phpon a fixed interval (often every 5 or 15 minutes) instead. If that real cron job is misconfigured or removed, WP-Cron stops running entirely, with no page-load fallback either.
The fixes that exist, and their limits
A real system cron job, configured by you or your host, that calls wp-cron.php on a fixed schedule (typically via wget or curl in a crontab entry, with WordPress’s own trigger disabled via DISABLE_WP_CRON). This is the standard fix, and it works, but it depends on your hosting plan supporting cron jobs and on someone maintaining that configuration correctly. It also still runs inside your WordPress process, competing for the same PHP workers and database connections as everything else on the request.
A third-party monitoring service that pings your site on a schedule specifically to trigger WP-Cron, simulating the visitor WordPress needs. This solves the “no traffic” problem without touching server configuration, but it’s one more external dependency to keep working, and it still executes inside WordPress when it fires.
Reducing what depends on scheduling at all. Neither fix changes the underlying model: scheduled work still executes inside your WordPress install, competing with page requests, plugin conflicts, and whatever else is running there. Real system cron makes the trigger reliable; it does not make the execution environment any less shared.
Why hosted loyalty infrastructure does not have this problem
kind loyalty is a hosted loyalty and rewards service for WooCommerce. The WooCommerce plugin’s job is to forward completed orders and render the customer widget, nothing else. Points calculation, campaign logic, expiry, and Klaviyo event delivery all run on kind loyalty’s own infrastructure, scheduled and executed there, not inside your WordPress install.
That means the question “did WP-Cron fire recently on this store” stops being relevant to whether a customer’s points expire on time or a Klaviyo flow triggers when it should. A store with zero visitors overnight behaves identically to a store with heavy traffic, because nothing about the schedule depends on a visitor loading a page.
It also means a delivery failure is visible rather than silent: if an event fails to reach Klaviyo, it retries automatically with backoff, and a failure that persists shows up in your dashboard instead of quietly vanishing into a missed cron window. Read more about what runs where in a hosted setup versus a plugin.
The honest caveat
This is specifically a WP-Cron and scheduling problem. If your points are wrong for a different reason (a miscalculated rate, a coupon restriction misconfigured, a plugin conflict on the order-completed hook), a better scheduler won’t fix it. The diagnostic in this article is for the specific symptom of things that update late, inconsistently, or only after a page load, not points that are simply calculated incorrectly every time.

