# Platform notes (WordPress-specific)

## Object cache

The connector caches `tenant.snapshot` in a 5-min transient. If you
run an external object cache (Redis, Memcached) the transient lives
there; otherwise it's a `wp_options` row tagged with an expiry. Either
is fine — the connector does not care.

If you run `wp cli cache flush` or similar between deploys, the next
gateway-talking request takes a one-shot 50-100ms hit to repopulate
the snapshot. Expected, not a regression.

## Page caching plugins (WP Rocket, W3 Total Cache, Cloudflare APO)

Search result pages should NOT be cached by a page cache — they're
visitor-personalized via the click beacon's session id and the
auto-promoter's per-request mode read. The connector adds the
`Cache-Control: private, no-store` header on `is_search()` responses
automatically; if your page cache ignores that header you must add
the search URL pattern (`/?s=*`) to the cache's exclude list.

## Multisite

The connector is per-site. Network-activate installs the schema on
every subsite, but each subsite must pair separately (each gets its
own tenant_id / shared_secret). The storefront-host lock is on
`home_url()`, which is per-subsite, so multisite installs with
distinct subsite domains work correctly out of the box.

If you network-activate and your subsites share a single tenant on
admin.seekmodo.com, the domain lock will reject all but one subsite.
Either:

- Create a separate tenant per subsite (recommended), or
- Set `seekmodo_disable_storefront_host_lock` filter to true and rely
  on the gateway's `X-Seekmodo-Storefront-Host` for routing (advanced).

## WP-Cron vs system cron

If you've switched WP-Cron off via `define('DISABLE_WP_CRON', true)`
and run a system cron hitting `wp-cron.php`, the connector's three
events still fire — they use `wp_schedule_event` which is honored by
the system cron path as well.

If you've ALSO disabled the `wp-cron.php` endpoint entirely, set up:

```cron
*/15 * * * * wp --path=/var/www/site cron event run seekmodo_wp_index_tick
*/5  * * * * wp --path=/var/www/site cron event run seekmodo_wp_tenant_snapshot_pull
*    * * * * wp --path=/var/www/site cron event run seekmodo_wp_events_flush
```

## WPML / Polylang

The indexer treats each translated post as a separate document and
indexes its `lang` attribute. The search swap reads the current locale
and posts `lang=<locale>` on the gateway call. Configure language-aware
boosting from admin.seekmodo.com → Tenant → Search settings → Languages.

## REST API security

The plugin's REST routes under `/wp-json/seekmodo/v1/` are:

- `GET /typeahead`: public (rate-limited per IP).
- `POST /click`: public (rate-limited per IP, bot-checked server-side).
- `POST /connect/callback`: nonce-protected, single-use, expires after
  60s. Used only by the Connect-to-Seekmodo round-trip.
- `GET /health`: admin-only (`manage_options` capability).

## Known incompatibilities

- **Relevanssi** and **SearchWP**: also hook `pre_get_posts` /
  `posts_pre_query` and override the search. Seekmodo runs at the
  default priority and will lose to plugins running at later
  priorities. Resolve by deactivating the other search plugin, or set
  `seekmodo_wp_mode=off` and only use Seekmodo's typeahead via the
  REST endpoint.
- **Aggressive query monitor / debug plugins**: if you see "Wrote in
  X queries" go up with Seekmodo enabled, that's the breaker probe; it
  fires one extra `SELECT` on the half-open transition.
