Documentation · Integration Guide
Server Cron Setup
This document explains why a real server cron job is the recommended way to drive imports for the ADP Car Market Hub plugin in production, how it relates to the built-in WP-Cron scheduler, and which operational checks should be in place once it is running.
When to use this document
Use this document if you are:
- Preparing a production deployment and deciding how scheduled imports should be triggered.
- Migrating from WP-Cron to a server-side cron job because imports are unreliable on a low-traffic site.
- Operating a host that recommends or requires
DISABLE_WP_CRONfor performance reasons. - Reviewing why imports start late, run only during peak hours, or do not start at all.
The audience is a WordPress administrator with access to the server's cron facility (for example via cPanel, Plesk, the hosting control panel, or shell access to a Linux crontab).
Overview
WordPress ships with a built-in scheduler called WP-Cron. WP-Cron does not run continuously in the background — it is checked when somebody requests a page on the site. On a busy site this is usually fine, but it has a few well-known limitations:
- On a low-traffic site, scheduled tasks run late or not at all because no visitor triggers WP-Cron.
- WP-Cron runs inside a normal HTTP request, so it shares the request's PHP memory limit and execution time.
- Several visitors arriving at the same time can race to run the same scheduled task, which is wasteful even if the plugin guards against double-runs internally.
For these reasons, the recommended production setup is to disable WP-Cron and trigger it from a real server cron job. The plugin provides a dedicated, token-secured REST endpoint specifically for this purpose, so that the cron job triggers an import directly without depending on a visitor.
The plugin offers two cron modes that you choose on Car Market Hub → Import & Limits (the Automation card):
- WP-Cron mode (default). The plugin's WP-Cron schedule (hourly, every 6 hours, twice daily, daily, or custom with a 15-minute minimum) drives imports. Suitable for development, evaluation and small sites with regular traffic.
- Server cron mode. The WP-Cron schedule is disabled and the import is triggered by a server cron job that calls the plugin's REST endpoint. Recommended for production.
In both modes, the actual import work is performed by the same shared runner inside the plugin — the only difference is what triggers it.
Why server cron is recommended in production
- Reliable timing. A server cron job runs on a fixed schedule, regardless of whether anybody is visiting the website at that moment.
- No request-time penalty. Imports do not slow down a real visitor's page load, because they run in their own PHP process.
- Predictable resource usage. A server cron job runs once per scheduled time, instead of being kicked off opportunistically by each visitor.
- Easier monitoring. Cron runs leave a clear audit trail (in the cron service's logs and in the plugin's logs) and can be paired with external uptime checks.
- Compatible with hosts that throttle or disable WP-Cron. Some managed hosts limit how often
wp-cron.phpruns internally; an external trigger bypasses that.
Server cron also pairs well with the plugin's image queue: a second cron job that calls wp-cron.php at a short interval keeps WordPress's normal task queue (including image processing) running on a predictable cadence.
Prerequisites
Before switching to server cron, confirm:
- The plugin is installed, activated and the API connection works. See API Credentials Setup and Connection Test.
- The hosting environment provides access to the server's cron facility (cPanel cron jobs, Plesk scheduled tasks, hosting-control-panel cron, or a Linux crontab via SSH).
- The site can be reached over HTTPS by the cron job. For most hosts the cron command runs on the same server and can use
curlto call back into the site. - You are able to edit
wp-config.php(this is required to setDISABLE_WP_CRON). - The general hosting and cron / background processing requirements are met.
Step by step instructions
The plugin's Automation card shows the exact REST trigger URL and example commands for the current installation. Use those values rather than copying URLs from documentation.
- Switch the plugin to server cron mode. Open Car Market Hub → Import & Limits. In the cron mode card, select Server cron and save. The plugin will hide the WP-Cron schedule controls and show a Server Cron Setup card with the REST trigger URL, the secret token and example commands.
- Disable the WordPress built-in cron. Add the following line to
wp-config.php, anywhere above the/* That's all, stop editing! */comment:
define( 'DISABLE_WP_CRON', true );
Without this line, both WP-Cron and the server cron job will try to schedule imports, which is wasteful even when the plugin's internal lock prevents double runs.
- Copy the REST trigger URL. The Server Cron Setup card displays the URL in the form
https://<your-site>/wp-json/as24ci/v1/cron-import?token=<secret>. Use the Copy button so the URL is copied verbatim. Treat the token as a secret — anyone who has it can trigger an import. - Add the import cron job. In your server's cron facility, create a job that calls the trigger URL on the cadence you want. The plugin pre-fills an example like:
*/15 * * * * curl -s "https://<your-site>/wp-json/as24ci/v1/cron-import?token=<secret>" > /dev/null
Adjust the schedule expression (*/15 * * * * means every 15 minutes) to fit the dealer's needs. Imports skip unchanged vehicles thanks to change detection, so frequent runs are typically inexpensive.
- Add a second cron job to keep WordPress's task queue running. Because
DISABLE_WP_CRONalso disables the queue used by the plugin's image worker and by other WordPress features, add a second cron job that runswp-cron.phpdirectly on a short interval. The plugin's example uses the absolute path of the WordPress installation:
*/5 * * * * php /path/to/wordpress/wp-cron.php > /dev/null 2>&1
The path is shown in the Automation card based on the current WordPress installation. Replace it with the value displayed there.
- Verify with a manual run. From a workstation, call the REST trigger URL once with
curl(or paste it into a browser). A successful run returns a JSON response describing the import result. A 403 with "Invalid or missing token" means the URL was copied incorrectly. - Verify on the next scheduled run. Wait for the next scheduled cron tick, then open Car Market Hub → System & Help and confirm that Last external cron run shows a recent timestamp.
For an alternative authentication style that keeps the token out of the URL (and therefore out of access logs and process listings), the endpoint also accepts an Authorization: Bearer <token> header. For example:
*/15 * * * * curl -s -H "Authorization: Bearer <secret>" "https://<your-site>/wp-json/as24ci/v1/cron-import" > /dev/null
Both styles are equivalent; the header style is preferred when the cron environment supports custom headers.
Configuration reference
The settings that affect server cron mode are on Car Market Hub → Import & Limits (Automation card).
| Setting | Purpose |
|---|---|
| Cron mode | Switches between WP-Cron and Server cron. In Server cron mode the WP-Cron schedule is disabled and the Server Cron Setup card is shown. |
| REST trigger URL | The full URL the server cron job should call. Includes the secret token as a query parameter. Generated from the current site URL and the stored token. |
| Secret token | A 32-character random token that authenticates the REST trigger. Generated automatically on first use. Use the Regenerate Token button to issue a new one (the existing cron job will then need to be updated with the new URL). |
| Example cron commands | Pre-filled example commands using the current trigger URL and the absolute path to wp-cron.php. Use the Copy buttons to copy them verbatim. |
| Max vehicles per cron run | Limits how many vehicles a single import run will process. 0 means unlimited. Useful as a safety cap on shared hosts. |
| Image queue mode | When enabled, scheduled imports download only the first image per vehicle immediately and queue the rest for asynchronous processing. Recommended in production. |
Operational notes
- One scheduler at a time. Do not run WP-Cron and server cron mode in parallel. Switching to Server cron in the plugin disables the WP-Cron schedule; adding
DISABLE_WP_CRONtowp-config.phpcompletes the picture by stopping WordPress from running its cron queue from front-end requests. - The shared runner. The REST endpoint, the WP-Cron hook and the Trigger now admin button all delegate to the same import runner inside the plugin. There is no separate "server cron import path" with different behaviour.
- Concurrency safety. The runner uses an internal transient-based lock to prevent two imports from running at the same time. Even if a cron job overlaps, the second run is short-circuited.
- Token confidentiality. The cron token grants the right to trigger an import. Treat it as a secret. Avoid pasting full trigger URLs into screenshots or tickets; redact the
token=...portion before sharing. - Token rotation. Use Regenerate Token whenever you suspect the token is exposed, or as part of a periodic rotation. After regeneration, update every cron job that uses the URL — the previous URL will be rejected.
- Endpoint location. The REST endpoint is the standard WordPress REST URL
…/wp-json/as24ci/v1/cron-import. If the WordPress site URL changes (HTTPS migration, domain change, multi-site move), update the cron job accordingly. - External heartbeat. Any request to the site that includes
?as24ci_cron=1records a timestamp the System & Help tab uses to confirm that an external scheduler is alive. This is purely informational and does not by itself trigger an import. - Image queue companion job. When images are queued during scheduled imports, the queue is processed by the WordPress task queue. If you disabled WP-Cron, the second cron job that calls
wp-cron.phpis what keeps that queue moving. - Do not rely on browser-based testing. Pasting the trigger URL into a browser works for verification, but should not be used as the actual trigger — that depends on someone keeping a browser open.
Operational checks after setup
Run through these checks once after switching to server cron mode, and again after any major change (host migration, URL change, token regeneration):
- Cron service is enabled. Confirm that the host's cron facility is active and that the user account running the job has permission to execute the command.
- Scheduled command is correct. The schedule expression matches the desired frequency, the URL matches the value shown on the Automation card, and the second job that calls
wp-cron.phpexists. DISABLE_WP_CRONis defined. The System & Help tab confirms the constant is set when you are in server cron mode.- Last external cron run is recent. The System & Help tab shows a Last external cron run timestamp within the expected interval.
- Last import run is recent. The dashboard widget and System & Help tab show recent activity from the importer.
- Logs do not show repeated authentication failures. A pattern of 403 responses in the logs means the cron job is using a stale or wrong token.
- Image queue is draining. The Import & Limits tab shows that the image queue is being processed (or is empty).
- Optional external monitor. Configure an uptime monitor or hosting-level alert that notifies you if the import job stops running.
Verify these checks against the current plugin version before publishing customer-facing instructions, since UI labels can evolve between releases.
Troubleshooting
| Symptom | Likely cause | What to check |
|---|---|---|
| Cron job runs but the response is 403 with "Invalid or missing token". | The token in the URL is wrong, contains whitespace, or was regenerated after the cron job was created. | Re-copy the URL from the Automation card and update the cron command. |
| Cron job runs but the response is 403 with "Cron token not configured". | The token has not been generated yet. | Open the Automation card to auto-generate a token, then copy the new URL. |
| Cron job runs successfully, but the System & Help tab still shows no recent external run. | The cron service is calling a different host (for example HTTP instead of HTTPS, or www. vs the canonical hostname) and the request is being redirected away from WordPress. | Use the exact URL shown on the Automation card. Confirm the host's cron service can reach the site over HTTPS. |
| Imports are running, but image attachments stop appearing. | DISABLE_WP_CRON is set but no cron job calls wp-cron.php, so the image queue worker never runs. | Add the second cron job for wp-cron.php as described above. |
| Imports run too long or hit a memory limit. | The host's PHP CLI limits are stricter than expected. | Reduce Max vehicles per cron run, keep image queue mode enabled, and review Cron and Background Processing. |
| Imports run twice in quick succession. | Both WP-Cron mode and a server cron job are active. | Switch the plugin to Server cron mode and add DISABLE_WP_CRON to wp-config.php. |
| Cron job runs but always returns "Another import is already running". | A previous run did not finish (long-running batch, host-side timeout). The transient lock has not yet expired. | Wait for the lock to expire, then investigate the previous run via the plugin logs. See Cron Errors. |