Under the Hood
Auto-Sync & Caching
How content flows from Notion to your website — triple-layer caching, 15-minute polling, instant manual flush, and the full sync lifecycle.
The Data Flow
Notion Database → Notion API → WordPress Sync CLI → notion_page CPT
notion_page CPT → voyager/notion binding source → Pattern template → Rendered page
Notion edit → 15-min poll detects change → Cache flush → Next visitor sees fresh data
Triple-Layer Caching
Every Notion API call is expensive (100-300ms per request). Three layers ensure pages render fast while data stays fresh:
Layer 1: In-Memory Cache
A PHP array ($_voyager_notion_row_cache) holds resolved properties for the current request. If the same binding resolves twice on one page load, the second call is free. Zero overhead.
Layer 2: Row Transients (1 hour TTL)
Each Notion row’s properties are cached as a WordPress transient with a 1-hour TTL. Individual page bindings resolve from this cache without hitting the Notion API. Key format: vn_row_{md5(db_id + page_id)}.
Layer 3: Archive Transients (1 hour TTL)
PHP-rendered archive patterns (changelog, case studies, events, pricing, team, jobs) cache the entire query result. One Notion API call per database, then all visitors see the cached result. Keys: vn_changelog_feed, vn_casestudies_grid, etc.
Cache Invalidation — 3 Paths
1. Automatic Polling (15 minutes)
A WP-Cron event runs every 15 minutes. For each active database, it queries the 5 most recently edited Notion rows. If any row’s last_edited_time is newer than the last poll, all transients for that database are flushed — including archive transients.
2. Sync CLI
When wp voyager notion sync creates or updates posts, it automatically flushes all Notion transients and fires the voyager_notion_synced action. Other systems can hook into this for downstream updates.
3. Manual Flush
Two buttons in the admin: “Flush Cache” per-database and “Flush All” in Settings > Voyager Blocks > Notion. The admin bar also has quick-access Flush and Re-sync buttons. All paths flush both row-level and archive-level transients.
Client Isolation
The Content DB uses a mandatory client isolation filter. Every sync operation must specify a Client relation filter — without it, the CLI refuses to run. This prevents cross-pollination between clients sharing a Notion workspace. Internal databases (support, changelog, team, etc.) use --no-filter=true since they contain Voyager-owned content only.
Template Auto-Detection
When syncing a database for the first time, the system scores each of the 12 registered templates against the database’s property schema. Required properties are weighted 2x. The highest-scoring template with at least one required property match wins. For example, a database with “Client Name”, “Industry”, “Challenge” automatically maps to the case study template — no manual configuration needed.
Templates are extensible via the voyager_notion_templates filter. Add your own page types without modifying plugin code.
Try It Yourself
Create a page from scratch using the Notion Pipeline Demo, or explore how all 10 databases power this site.