PluginBench
Skill
Official
Review
Audit score 70

wp-interactivity-api

wordpress/agent-skills

Build and debug WordPress Interactivity API features with directives, store state, and hydration.

What is wp-interactivity-api?

This skill helps you work with WordPress Interactivity API—the framework for adding interactivity to blocks and themes using data-wp-* directives, @wordpress/interactivity stores, and server-side rendering. Use it when building interactive blocks, debugging directive behavior, or optimizing hydration and performance.

  • Detect and integrate Interactivity API usage across blocks, themes, and plugins
  • Set up server-side rendering with wp_interactivity_state() and wp_interactivity_data_wp_context()
  • Implement and debug data-wp-* directives (data-wp-on--, data-wp-bind--, data-wp-context)
  • Define derived state in PHP to prevent hydration mismatches and layout shifts
  • Troubleshoot common failures: inert directives, hydration flicker, missing initial content, and performance regressions
  • Support WordPress 6.9+ features including unique directive IDs and new TypeScript types

How to install wp-interactivity-api

npx skills add https://github.com/wordpress/agent-skills --skill wp-interactivity-api
Prerequisites
  • WordPress 6.9+ (PHP 7.2.24+)
  • Node.js and bash for filesystem-based workflows
  • WP-CLI for some workflows
  • wp-project-triage output to understand existing integration style
  • @wordpress/scripts or compatible module bundler
Claude Code
Cursor
Windsurf
Cline

How to use wp-interactivity-api

  1. 1.Run wp-project-triage to detect existing Interactivity API usage and integration style (block, theme, or plugin)
  2. 2.Identify the store definitions and confirm state shape, actions, and event handlers
  3. 3.Enable server directive processing by adding supports.interactivity in block.json or calling wp_interactivity_process_directives()
  4. 4.Initialize global state with wp_interactivity_state() and local context with wp_interactivity_data_wp_context() in PHP
  5. 5.Define derived state in PHP using closures to ensure correct initial HTML rendering before JavaScript loads
  6. 6.Implement directives with minimal scope, keeping data attributes stable and aligned between server and client
  7. 7.Verify the viewScriptModule is enqueued and the DOM element has data-wp-interactive with matching store namespace
  8. 8.Test with manual smoke tests and Playwright E2E tests around interaction paths

Use cases

Good for
  • Building a new interactive block with viewScriptModule and client-side state management
  • Debugging why a data-wp-on--click directive isn't firing on a theme component
  • Adding server-side rendering to an existing interactive component to prevent layout shift
  • Migrating from deprecated data-wp-ignore to modern directive patterns in WordPress 6.9
  • Optimizing performance by scoping interactivity to smaller subtrees instead of broad roots
Who it's for
  • Block developers building interactive WordPress blocks
  • Theme developers adding interactivity to theme components
  • Plugin developers enhancing existing markup with client-side behavior
  • WordPress engineers debugging Interactivity API integration issues
  • Full-stack WordPress developers optimizing performance and hydration

wp-interactivity-api FAQ

When should I use the Interactivity API instead of custom JavaScript?

Use the Interactivity API when you need reactive state management, server-side rendering, and seamless hydration in WordPress blocks or themes. It handles directive processing, store management, and client-side navigation automatically. Use custom JavaScript only when the Interactivity API doesn't fit your use case.

How do I prevent layout shift when loading interactive components?

Define derived state (like state.hasItems) in PHP using wp_interactivity_state() with closures, and ensure server-rendered HTML includes the correct initial attributes (e.g., hidden). This way, directives like data-wp-bind--hidden render correctly on first load before JavaScript takes over.

What changed in WordPress 6.9 for the Interactivity API?

data-wp-ignore is now deprecated and will be removed. Use unique directive IDs with the --- separator instead (e.g., data-wp-on--click---plugin-a). New TypeScript types AsyncAction<ReturnType> and TypeYield<T> help with async action typing. getServerState() and getServerContext() now reset between page transitions.

How do I debug why directives aren't firing?

Check: (1) the viewScriptModule is enqueued and loaded, (2) the DOM element has data-wp-interactive, (3) the store namespace in the directive matches the store definition, (4) there are no JavaScript errors before hydration. See references/debugging.md for detailed troubleshooting.

Should I use @wordpress/create-block-interactive-template for new blocks?

Yes, if you're creating a new interactive block from scratch. The official scaffold template provides best-practice setup for viewScriptModule, store integration, and server-side rendering. Use this skill to debug or enhance existing blocks.

Full instructions (SKILL.md)

Source of truth, from wordpress/agent-skills.


name: wp-interactivity-api description: "Use when building or debugging WordPress Interactivity API features (data-wp-* directives, @wordpress/interactivity store/state/actions, block viewScriptModule integration, wp_interactivity_*()) including performance, hydration, and directive behavior." compatibility: "Targets WordPress 6.9+ (PHP 7.2.24+). Filesystem-based agent with bash + node. Some workflows require WP-CLI."

WP Interactivity API

When to use

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”.

Inputs required

  • Repo root + triage output (wp-project-triage).
  • Which block/theme/plugin surfaces are affected (frontend, editor, both).
  • Any constraints: WP version, whether modules are supported in the build.

Procedure

1) Detect existing usage + integration style

Search for:

  • data-wp-interactive
  • @wordpress/interactivity
  • viewScriptModule

Decide:

  • Is this a block providing interactivity via block.json view script module?
  • Is this theme-level interactivity?
  • Is this plugin-side “enhance existing markup” usage?

If you’re creating a new interactive block (not just debugging), prefer the official scaffold template:

  • @wordpress/create-block-interactive-template (via @wordpress/create-block)

2) Identify the store(s)

Locate store definitions and confirm:

  • state shape,
  • actions (mutations),
  • callbacks/event handlers used by data-wp-on--*.

3) Server-side rendering (best practice)

Pre-render HTML on the server before outputting to ensure:

  • Correct initial state in the HTML before JavaScript loads (no layout shift).
  • SEO benefits and faster perceived load time.
  • Seamless hydration when the client-side JavaScript takes over.

Enable server directive processing

For components using block.json, add supports.interactivity:

{
  "supports": {
    "interactivity": true
  }
}

For themes/plugins without block.json, use wp_interactivity_process_directives() to process directives.

Initialize state/context in PHP

Use wp_interactivity_state() to define initial global state:

wp_interactivity_state( 'myPlugin', array(
  'items'    => array( 'Apple', 'Banana', 'Cherry' ),
  'hasItems' => true,
));

For local context, use wp_interactivity_data_wp_context():

<?php
$context = array( 'isOpen' => false );
?>
<div <?php echo wp_interactivity_data_wp_context( $context ); ?>>
  ...
</div>

Define derived state in PHP

When derived state affects initial HTML rendering, replicate the logic in PHP:

wp_interactivity_state( 'myPlugin', array(
  'items'    => array( 'Apple', 'Banana' ),
  'hasItems' => function() {
    $state = wp_interactivity_state();
    return count( $state['items'] ) > 0;
  }
));

This ensures directives like data-wp-bind--hidden="!state.hasItems" render correctly on first load.

For detailed examples and patterns, see references/server-side-rendering.md.

4) Implement or change directives safely

When touching markup directives:

  • keep directive usage minimal and scoped,
  • prefer stable data attributes that map clearly to store state,
  • ensure server-rendered markup + client hydration align.

WordPress 6.9 changes:

  • data-wp-ignore is deprecated and will be removed in future versions. It broke context inheritance and caused issues with client-side navigation. Avoid using it.
  • Unique directive IDs: Multiple directives of the same type can now exist on one element using the --- separator (e.g., data-wp-on--click---plugin-a="..." and data-wp-on--click---plugin-b="...").
  • New TypeScript types: AsyncAction<ReturnType> and TypeYield<T> help with async action typing.

For quick directive reminders, see references/directives-quickref.md.

5) Build/tooling alignment

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

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 there are no JS errors before hydration.

See references/debugging.md.

Verification

  • wp-project-triage indicates signals.usesInteractivityApi: true after your change (if applicable).
  • Manual smoke test: directive triggers and state updates as expected.
  • If tests exist: add/extend Playwright E2E around the interaction path.

Failure modes / debugging

  • Directives present but inert:
    • view script not loading, wrong module entrypoint, or missing data-wp-interactive.
  • Hydration mismatch / flicker:
    • server markup differs from client expectations; simplify or align initial state.
    • derived state not defined in PHP: use wp_interactivity_state() with closures.
  • Initial content missing or wrong:
    • supports.interactivity not set in block.json (for blocks).
    • wp_interactivity_process_directives() not called (for themes/plugins).
    • state/context not initialized in PHP before render.
  • Layout shift on load:
    • derived state like state.hasItems missing on server, causing hidden attribute to be absent.
  • Performance regressions:
    • overly broad interactive roots; scope interactivity to smaller subtrees.
  • Client-side navigation issues (WordPress 6.9):
    • getServerState() and getServerContext() now reset between page transitions—ensure your code doesn't assume stale values persist.
    • Router regions now support attachTo for rendering overlays (modals, pop-ups) dynamically.

Escalation

  • If repo build constraints are unclear, ask: "Is this using @wordpress/scripts or a custom bundler (webpack/vite)?"
  • Consult:
    • references/server-side-rendering.md
    • references/directives-quickref.md
    • references/debugging.md