-
Notifications
You must be signed in to change notification settings - Fork 153
docs(wp-interactivity-api): Add WordPress 6.9 client navigation requirements #15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
derintolu
wants to merge
1
commit into
WordPress:trunk
Choose a base branch
from
derintolu:fix/wp-interactivity-router-6.9-requirements
base: trunk
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+198
−5
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,7 +13,8 @@ Use this skill when the user mentions: | |
| - Interactivity API, `@wordpress/interactivity`, | ||
| - `data-wp-interactive`, `data-wp-on--*`, `data-wp-bind--*`, `data-wp-context`, | ||
| - block `viewScriptModule` / module-based view scripts, | ||
| - hydration issues or “directives don’t fire”. | ||
| - hydration issues or "directives don't fire", | ||
| - **client-side navigation**, `@wordpress/interactivity-router`, `data-wp-router-region`. | ||
|
|
||
| ## Inputs required | ||
|
|
||
|
|
@@ -134,16 +135,55 @@ Verify the repo supports the required module build path: | |
| - if it uses `@wordpress/scripts`, prefer its conventions. | ||
| - if it uses custom bundling, confirm module output is supported. | ||
|
|
||
| ### 6) Debug common failure modes | ||
| ### 6) Client-side navigation with the Router | ||
|
|
||
| If “nothing happens” on interaction: | ||
| **CRITICAL: The router automatically intercepts `<a>` links. Do NOT add custom click handlers.** | ||
|
|
||
| When using `@wordpress/interactivity-router` for SPA-like navigation: | ||
|
|
||
| 1. Enqueue the router: `wp_enqueue_script_module('my-nav', '...', ['@wordpress/interactivity', '@wordpress/interactivity-router'])` | ||
| 2. **Mark module as compatible (WordPress 6.9+ REQUIRED):** | ||
| ```php | ||
| wp_interactivity()->add_client_navigation_support_to_script_module('my-nav'); | ||
| ``` | ||
| 3. Add `data-wp-router-region="region-id"` to the content area to be swapped | ||
| 4. Use **plain `<a href="...">` links** - NO `data-wp-on--click` handlers! | ||
|
|
||
| The router automatically: | ||
| - Intercepts all same-origin link clicks | ||
| - Fetches the target page | ||
| - Swaps ONLY the matching router region content | ||
| - Updates browser URL via History API | ||
|
|
||
| **WordPress 6.9+ CRITICAL:** Script modules must be marked as compatible with client-side navigation: | ||
| - For blocks: use `"supports": { "interactivity": { "clientNavigation": true } }` in block.json | ||
| - For manual modules: call `wp_interactivity()->add_client_navigation_support_to_script_module('module-id')` | ||
|
|
||
| Without this, the router will NOT intercept link clicks. The script tag must have `data-wp-router-options` attribute. | ||
|
|
||
| Reference: https://make.wordpress.org/core/2025/11/12/interactivity-apis-client-navigation-improvements-in-wordpress-6-9/ | ||
|
|
||
| **Common mistake:** Adding `data-wp-on--click="actions.navigate"` to nav elements. This breaks the router. Remove it. | ||
|
|
||
| See `references/router.md` for full details. | ||
|
|
||
| ### 7) Debug common failure modes | ||
|
|
||
| If "nothing happens" on interaction: | ||
|
|
||
| - confirm the `viewScriptModule` is enqueued/loaded, | ||
| - confirm the DOM element has `data-wp-interactive`, | ||
| - confirm the store namespace matches the directive’s value, | ||
| - confirm the store namespace matches the directive's value, | ||
| - confirm there are no JS errors before hydration. | ||
|
|
||
| See `references/debugging.md`. | ||
| If client-side **navigation** isn't working: | ||
| - confirm `@wordpress/interactivity-router` is enqueued, | ||
| - confirm `data-wp-router-region` exists on both source and target pages with SAME ID, | ||
| - **confirm script module has `data-wp-router-options` attribute** (WP 6.9+) - if missing, call `wp_interactivity()->add_client_navigation_support_to_script_module('your-module')`, | ||
| - **remove any custom `data-wp-on--click` handlers from navigation links**, | ||
| - links should be plain `<a href>` tags. | ||
|
|
||
| See `references/debugging.md` and `references/router.md`. | ||
|
|
||
| ## Verification | ||
|
|
||
|
|
@@ -174,6 +214,7 @@ See `references/debugging.md`. | |
|
|
||
| - If repo build constraints are unclear, ask: "Is this using `@wordpress/scripts` or a custom bundler (webpack/vite)?" | ||
| - Consult: | ||
| - `references/router.md` - **READ THIS FIRST for navigation issues** | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should avoid yelling out our models since this needs to service more than just Anthropic |
||
| - `references/server-side-rendering.md` | ||
| - `references/directives-quickref.md` | ||
| - `references/debugging.md` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,152 @@ | ||
| # Interactivity Router (`@wordpress/interactivity-router`) | ||
|
|
||
| ## Key Concept: Automatic Link Interception | ||
|
|
||
| **The router automatically intercepts ALL same-origin `<a>` link clicks.** You do NOT need custom click handlers. | ||
|
|
||
| ## How It Works | ||
|
|
||
| When `@wordpress/interactivity-router` is enqueued and `data-wp-router-region` exists on the page: | ||
|
|
||
| 1. User clicks any `<a href="...">` link (same-origin) | ||
| 2. Router intercepts the click automatically (calls `preventDefault`) | ||
| 3. Fetches the target page via AJAX | ||
| 4. Finds the matching `data-wp-router-region` on the new page | ||
| 5. Swaps ONLY that region's innerHTML | ||
| 6. Updates the browser URL via History API | ||
| 7. Sidebar, header, footer stay intact | ||
|
|
||
| ## Required Setup | ||
|
|
||
| ```php | ||
| // 1. Enqueue the router module | ||
| wp_enqueue_script_module( | ||
| 'my-navigation', | ||
| get_stylesheet_directory_uri() . '/assets/js/navigation.js', | ||
| ['@wordpress/interactivity', '@wordpress/interactivity-router'], | ||
| '1.0.0' | ||
| ); | ||
|
|
||
| // 2. Mark module as compatible with client-side navigation (WordPress 6.9+) | ||
| // This is REQUIRED for manually registered script modules! | ||
| wp_interactivity()->add_client_navigation_support_to_script_module('my-navigation'); | ||
| ``` | ||
|
|
||
| ```php | ||
| // 3. Add router region to the content area (via filter or directly in template) | ||
| <main data-wp-interactive="my/namespace" data-wp-router-region="main-content"> | ||
| <!-- This content gets swapped on navigation --> | ||
| </main> | ||
| ``` | ||
|
|
||
| ```html | ||
| <!-- 4. Use regular links - NO directives needed! --> | ||
| <nav> | ||
| <a href="/page-1/">Page 1</a> | ||
| <a href="/page-2/">Page 2</a> | ||
| </nav> | ||
| ``` | ||
|
|
||
| ## WordPress 6.9+ Requirements | ||
|
|
||
| **CRITICAL: Script modules must be marked as compatible with client-side navigation.** | ||
|
|
||
| For blocks, this is automatic when `block.json` has: | ||
| ```json | ||
| { | ||
| "supports": { | ||
| "interactivity": { "clientNavigation": true } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| For manually registered script modules (themes/plugins), you MUST call: | ||
| ```php | ||
| wp_interactivity()->add_client_navigation_support_to_script_module('my-module'); | ||
| ``` | ||
|
|
||
| This adds `data-wp-router-options='{"loadOnClientNavigation":true}'` to the script tag. | ||
|
|
||
| **Without this, the router will not intercept link clicks.** | ||
|
|
||
| Reference: https://make.wordpress.org/core/2025/11/12/interactivity-apis-client-navigation-improvements-in-wordpress-6-9/ | ||
|
|
||
| ## Common Mistakes | ||
|
|
||
| ### ❌ WRONG: Adding click handlers to links | ||
|
|
||
| ```html | ||
| <!-- DON'T DO THIS --> | ||
| <nav data-wp-interactive="my/nav" data-wp-on--click="actions.navigate"> | ||
| <a href="/page/">Link</a> | ||
| </nav> | ||
| ``` | ||
|
|
||
| ```javascript | ||
| // DON'T DO THIS | ||
| store('my/nav', { | ||
| actions: { | ||
| navigate(e) { | ||
| e.preventDefault(); | ||
| routerActions.navigate(e.target.href); | ||
| } | ||
| } | ||
| }); | ||
| ``` | ||
|
|
||
| ### ✅ CORRECT: Plain links, router does the work | ||
|
|
||
| ```html | ||
| <!-- DO THIS --> | ||
| <nav> | ||
| <a href="/page/">Link</a> | ||
| </nav> | ||
| ``` | ||
|
|
||
| ```javascript | ||
| // Just register an empty store if needed, or don't register one at all | ||
| import { store } from '@wordpress/interactivity'; | ||
| store('my/namespace', {}); | ||
| ``` | ||
|
|
||
| ## When You DO Need Custom Handlers | ||
|
|
||
| Only use custom navigation handlers for: | ||
|
|
||
| - Non-link elements (buttons, divs) that should navigate | ||
| - Conditional navigation (confirm dialogs, form validation) | ||
| - Links that need special processing before navigation | ||
|
|
||
| ```javascript | ||
| // Example: Button that navigates | ||
| store('my/namespace', { | ||
| actions: { | ||
| *navigateToProfile() { | ||
| const { actions } = yield import('@wordpress/interactivity-router'); | ||
| yield actions.navigate('/profile/'); | ||
| } | ||
| } | ||
| }); | ||
| ``` | ||
|
|
||
| ## Debugging | ||
|
|
||
| If navigation isn't working: | ||
|
|
||
| 1. **Check router is enqueued**: View page source, search for `interactivity-router` | ||
| 2. **Check region exists**: Search HTML for `data-wp-router-region` | ||
| 3. **Check target page has same region ID**: Both pages need matching region IDs | ||
| 4. **Check for custom handlers**: Remove any `data-wp-on--click` from nav elements | ||
| 5. **Check console errors**: Router logs navigation events | ||
| 6. **Check script module has router options (WP 6.9+)**: Your script tag should have `data-wp-router-options` attribute. If missing, call `wp_interactivity()->add_client_navigation_support_to_script_module('your-module')` | ||
|
|
||
| ## Multiple Router Regions | ||
|
|
||
| You can have multiple independent regions: | ||
|
|
||
| ```html | ||
| <aside data-wp-router-region="sidebar">...</aside> | ||
| <main data-wp-router-region="main">...</main> | ||
| ``` | ||
|
|
||
| Each region swaps independently based on the target page's matching regions. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBF this could be asked about all of the existing committed skills, but what's the point of dumping all this information here if it's available via references?