Fire synthetic WordPress lifecycle events so scripts can initialize in a headless Next.js environment.
WordPress frontend scripts commonly initialize by listening for DOMContentLoaded:
document.addEventListener('DOMContentLoaded', () => { // Find block elements and set up interactivity document.querySelectorAll('.my-block').forEach(initBlock); });
In a traditional WordPress page, this works because scripts load with defer — they execute after the DOM is parsed but before DOMContentLoaded fires.
In a Next.js headless environment, scripts loaded via next/script with afterInteractive (the strategy used for WordPress deferred scripts) execute after React hydration, which is after DOMContentLoaded has already fired. The scripts register their listener but the event never comes — and the blocks never initialize.
NextPress fires synthetic page lifecycle events after hydration so WordPress scripts get the signals they expect:
DOMContentLoaded on documentload on windownextpress:page-change custom event on documentThese fire:
DOMContentLoaded can initializeIf you're using AssetUpdater, page events are fired automatically — you don't need PageEvents or usePageEvents. AssetUpdater fires events on initial mount and after each asset refresh on navigation.
// This is all you need — page events are built in <AssetUpdater fetchAssets={fetchAssetsAction} />
For apps that don't use AssetUpdater (e.g. static sites, or layouts where assets don't change between pages), use the PageEvents client component:
'use client'; import { usePathname } from 'next/navigation'; import { PageEvents } from '@axistaylor/nextpress/client'; export function MyPageEvents() { const pathname = usePathname(); return <PageEvents pathname={pathname} />; }
Then in your layout:
<WPFooter scripts={scripts} pathname={uri} /> <MyPageEvents />
| Prop | Type | Required | Description |
|---|---|---|---|
pathname | string | Yes | Current page pathname — triggers events on change |
For more control, use the usePageEvents hook directly in your own client component:
'use client'; import { usePathname } from 'next/navigation'; import { usePageEvents } from '@axistaylor/nextpress/client'; export function MyComponent() { const pathname = usePathname(); usePageEvents(pathname); // Your component logic... return <div>...</div>; }
The hook fires events:
queueMicrotask so React hydration completes first)pathname changeFor imperative use (e.g. after dynamically loading content):
import { firePageEvents } from '@axistaylor/nextpress/client'; // After inserting new WordPress content into the DOM firePageEvents();
| Event | Target | Purpose |
|---|---|---|
DOMContentLoaded | document | Standard DOM event — most WP scripts listen for this |
load | window | Window load event — some scripts wait for full page load |
nextpress:page-change | document | NextPress-specific event for scripts that want to distinguish real page loads from synthetic re-fires |
If you're authoring WordPress blocks that need to work in both traditional and headless environments, use the readyState pattern:
function initMyBlock() { document.querySelectorAll('.my-block').forEach(/* ... */); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initMyBlock); } else { initMyBlock(); }
This works on traditional WordPress (where defer scripts run before DOMContentLoaded) AND on headless Next.js (where the script may load after DOMContentLoaded but NextPress will also re-fire it).