Operanse
Sign inSign up

Documentation · Set up

Server setup

Two settings on your server decide whether a visitor's request really costs the plugin about 0.02 ms of PHP with no database query and no network call. The plugin checks both and shows a notice in wp-admin until they are in place. Setting them first means never seeing the notice. Both involve your server, so you may want your developer or host to do them.

1. A private data directory

Every event the plugin records (an order, a payment, a form submission, a sampled request) is appended to a local file and uploaded later by a scheduled task. That file must be private, so it cannot be fetched over the web, and writable by PHP. Name a directory outside your web root in wp-config.php:

// wp-config.php: a directory OUTSIDE your web root that the web server user can write to.
// cPanel-style, next to public_html:
define( 'OPERANSE_DATA_DIR', '/home/youruser/operanse-data' );
// Cloudways:
// define( 'OPERANSE_DATA_DIR', '/home/master/applications/<app>/private_html/operanse-data' );
// A VPS with the site in /var/www/html:
// define( 'OPERANSE_DATA_DIR', '/var/www/operanse-data' );

The plugin creates the directory with permissions that let only the web server user read it, refuses a path that resolves to inside the document root, and re-checks that it can write there once a day. The constant takes effect on the next page load.

Where the buffer goes without it

TierWhereHow privacy is established
1OPERANSE_DATA_DIRBy construction: the path is outside the document root, so no address maps to it.
2wp-content/uploads/operanse-agent/spoolThis directory is inside the web root, so once a day the plugin writes a random token file and fetches its own address. The directory is used only if the server refuses the request.
3A size-limited table in your databaseThe fallback when neither of the above can be proven.

On the database tier the plugin does what it otherwise never does: on the request that produced an order, payment, webhook or form event it runs a SELECT and an INSERT on your database, about 1.8 ms. It also switches request sampling off rather than pay that for page views, so there is no request-timing data. The table is bounded at 20,000 rows and the site keeps working. It is a cost, not a fault, and the one line above removes it.

Managed hosts. On Cloudways the application directory itself is not writable; use the app's private_html/, which exists for this and is outside public_html. On cPanel, a directory next to public_html works.

Several web servers. If more than one web node serves the site, give each node its own local directory (the same path on each is fine), not a shared network mount. The buffer is appended under a file lock, which is slow or unreliable on NFS, and each node's buffer is uploaded by whichever scheduled run lands on it.

2. A system cron

All of the plugin's work (collecting, uploading, checking for read jobs, the inventory) runs from WP-Cron. WordPress's built-in cron trigger only fires when the site receives a visit, runs the work inside that visitor's request, and depends on a loopback request that fails on many hosts. Disable the built-in trigger and run a real cron every minute:

// wp-config.php
define( 'DISABLE_WP_CRON', true );
* * * * * cd /path/to/wordpress && wp cron event run --due-now --quiet

If WP-CLI is not available, fetch the cron endpoint instead:

* * * * * curl -s https://example.com/wp-cron.php?doing_wp_cron > /dev/null

This also makes your store's own background work (renewals, scheduled actions, emails) run on time on a quiet site.

Verify

wp cron test
wp operanse status

wp operanse status prints the buffer tier and location, the last upload, the last heartbeat and the result of the plugin's own cron check. Settings → Operanse shows the same.

What the notices mean

NoticeWhen it showsIt goes away when
Operanse is buffering events in your databaseThe buffer is on the database tierA private directory is in use
WP-Cron is not running reliably on this siteThe site is paired and the cron check failed or a collection ran lateThe next collection runs on time
Operanse runs on WordPress's built-in cron triggerDISABLE_WP_CRON is not setIt is set to true

Notices are shown to administrators on the Dashboard, the Plugins screen and Settings → Operanse, and nowhere else. A dismissed notice stays dismissed for the same condition and returns if the reason changes. The same state reaches the dashboard through the heartbeat, so the site page says the same thing.