Extending the IDE
The IDE is built to be extended the same way its own built-in features are. Everything you can register — panels, tabs, status-bar items, view modes, menu actions, preferences — goes through the public API on window.WPGraphQLIDE, the same registry the IDE itself uses internally (src/registry/index.js).
There are three moving parts:
- A PHP shell that enqueues your JavaScript with
wpgraphql-ideas a dependency. - A JS entry that waits for the IDE to be ready, then registers your contributions.
- The registries and hooks on
window.WPGraphQLIDE.
1. Enqueue your script (PHP)
Hook wpgraphql_ide_enqueue_script — it fires right before the IDE’s own render script is enqueued, so depending on wpgraphql-ide guarantees load order.
add_action( 'wpgraphql_ide_enqueue_script', function ( $app_context ) {
wp_enqueue_script(
'my-ide-extension',
plugins_url( 'build/extension.js', __FILE__ ),
[ 'wpgraphql-ide' ], // ensures window.WPGraphQLIDE exists first
'1.0.0',
true
);
} );
See Actions & Filters for the PHP hooks (wpgraphql_ide_enqueue_script, wpgraphql_ide_localized_data, the capability filter, etc.).
2. Wait for the IDE, then register (JS)
The IDE assembles window.WPGraphQLIDE and then dispatches the WPGraphQLIDE_Window_Ready DOM event. Do all your wiring inside that listener — it’s the guarantee that the stores, registries, and hook bus are in place.
window.addEventListener('WPGraphQLIDE_Window_Ready', () => {
const { registerResponseExtensionTab } = window.WPGraphQLIDE;
registerResponseExtensionTab('myExtension', {
title: 'My Extension',
content: ({ data, response }) => <pre>{JSON.stringify(data, null, 2)}</pre>,
}, 50);
});
window.WPGraphQLIDE exposes every register* function plus the shared hooks bus (a @wordpress/hooks instance — the same one wp.hooks delegates to). Anything fired by the IDE’s PHP-side or JS-side hooks travels on that bus.
3. What you can extend
| You want to… | Register with | Guide / reference |
|---|---|---|
Surface your extensions payload in the response pane | registerResponseExtensionTab | Adding a Response Panel |
| Add a live badge by the HTTP status / duration / size | registerStatusBarItem | Adding a Status Bar Item |
| Add a global left-sidebar panel | registerActivityBarPanel | Adding an Activity Bar Panel |
| Add a response viewer mode (next to JSON / Table) | registerResponseViewMode | Access Functions |
| Add a tab beneath the editor (next to Variables / Headers) | registerEditorBottomTab | Access Functions |
| Add a query-editor toolbar button | registerDocumentEditorToolbarButton | Access Functions |
| Add kebab-menu actions (response / editor / document tab) | registerResponseAction / registerEditorAction / registerDocumentTabAction | Access Functions |
| Add a top-bar button + workspace tab | registerTopbarAction / registerWorkspaceTabType | Access Functions |
| Persist a setting (device or user scope) | registerPreference | Access Functions |
| Observe or rewrite every request / response | wpgraphql-ide.executeRequest / executeResponse / afterExecute | Hooking the Execute Lifecycle |
| Publish a toast | wpgraphql-ide.notice | Actions & Filters |
Things to know before you build
- React & JSX — React, ReactDOM, and GraphQL are WordPress script externals. Build your extension with
@wordpress/scripts(or any bundler that externalizesreact/wp.*) so it shares the IDE’s React instance. The bundled extensions underplugins/are working examples. - Surfaces mount conditionally. A panel/tab/item is unmounted when it isn’t on screen. If you need state that accumulates across executions or persists while hidden, don’t keep it in component state — see Tracking State Across Executions.
- Public API & SemVer. The
register*functions, the@wordpress/datastore names, the PHP hooks, and registered preference keys are public. Breaking changes require a major version bump.