PluginBench
Skill
Official
Review
Audit score 70

wp-interactivity-api

wordpress/agent-skills

Build and debug WordPress Interactivity API features with data-wp-* directives, store management, and hydration.

What is wp-interactivity-api?

This skill helps you implement and troubleshoot WordPress Interactivity API functionality, including data-wp-* directives, @wordpress/interactivity store/state/actions, block viewScriptModule integration, and server-side rendering. Use it when working with interactive blocks, theme-level interactivity, or debugging directive behavior and hydration issues.

  • Detect and triage existing Interactivity API usage patterns (block-based, theme-level, or plugin-side)
  • Set up server-side rendering with wp_interactivity_state() and wp_interactivity_data_wp_context() for correct initial state
  • Implement and validate data-wp-* directives (on, bind, context, interactive) with proper scoping and alignment
  • Debug common failures: inert directives, hydration mismatches, layout shifts, and performance regressions
  • Handle WordPress 6.9+ changes including deprecated data-wp-ignore, unique directive IDs, and client-side navigation state reset

How to install wp-interactivity-api

npx skills add https://github.com/wordpress/agent-skills --skill wp-interactivity-api
Prerequisites
  • WordPress 7.0+ (PHP 7.4.0+)
  • Node.js and bash for filesystem-based workflows
  • WP-CLI for some advanced workflows
  • Familiarity with block.json, viewScriptModule, and @wordpress/interactivity package
Claude Code
Cursor
Windsurf
Cline

How to use wp-interactivity-api

  1. 1.Search your codebase for data-wp-interactive, @wordpress/interactivity, and viewScriptModule to identify existing usage patterns
  2. 2.Locate and review store definitions to confirm state shape, actions, and event handlers
  3. 3.Enable server-side directive processing via supports.interactivity in block.json or wp_interactivity_process_directives() for themes/plugins
  4. 4.Initialize global state with wp_interactivity_state() and local context with wp_interactivity_data_wp_context() in PHP
  5. 5.Implement directives in markup, keeping them minimal and scoped, ensuring server-rendered markup aligns with client hydration
  6. 6.Verify the viewScriptModule is enqueued, the DOM has data-wp-interactive, and the store namespace matches directive values
  7. 7.Test interactions manually and add Playwright E2E tests around the interaction path if tests exist

Use cases

Good for
  • Building a new interactive block with viewScriptModule and client-side state management
  • Debugging why directives aren't firing after a module update or build configuration change
  • Converting static markup to interactive with server-rendered initial state to avoid layout shift
  • Implementing derived state (e.g., hasItems) in both PHP and JavaScript for seamless hydration
  • Troubleshooting hydration mismatches where server-rendered HTML differs from client expectations
Who it's for
  • WordPress block developers building interactive components
  • Theme developers adding interactivity features
  • Plugin authors enhancing existing markup with client-side behavior
  • Full-stack WordPress engineers debugging state and directive issues

wp-interactivity-api FAQ

When should I use server-side rendering with the Interactivity API?

Always pre-render HTML on the server before outputting to ensure correct initial state, prevent layout shift, improve SEO, and enable seamless hydration. Use wp_interactivity_state() for global state and wp_interactivity_data_wp_context() for local context.

What changed in WordPress 6.9 regarding directives?

data-wp-ignore is deprecated and will be removed; avoid it. Multiple directives of the same type can now coexist on one element using the --- separator (e.g., data-wp-on--click---plugin-a). New TypeScript types AsyncAction<ReturnType> and TypeYield<T> help with async action typing. Client-side navigation now resets getServerState() and getServerContext() between page transitions.

Why are my directives not firing?

Check that the viewScriptModule is enqueued and loaded, the DOM element has data-wp-interactive, the store namespace matches the directive's value, and there are no JavaScript errors before hydration. See references/debugging.md for detailed troubleshooting.

How do I handle derived state like hasItems to avoid layout shift?

Define derived state in PHP using wp_interactivity_state() with closures that replicate the client-side logic. This ensures directives like data-wp-bind--hidden="!state.hasItems" render correctly on first load before JavaScript takes over.

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

Yes, if you're creating a new interactive block from scratch, use @wordpress/create-block-interactive-template via @wordpress/create-block. For debugging or modifying existing blocks, follow the procedures in this skill.

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 7.0+ (PHP 7.4.0+). 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