Editor UI Extensions

Adding AI Blocks to the Inserter via Block Variations

⏱ 16 min

The AI Text block from Lesson 2 already has a mode attribute, 'rewrite' by default, that the toolbar and summarize logic already understand. This lesson uses that attribute to register a second, pre-configured entry in the inserter, “AI Summary Block”, without writing a second block from scratch. It’s also the right place to be direct about something developers sometimes go looking for: there is no separate slash-command API in WordPress distinct from block registration and variations.

What you'll learn in this lesson
The variations property in block.json
Registering a pre-configured, separately-named entry point for an existing block.
isActive and scope
How WordPress decides which variation an already-inserted block matches, and where each variation is allowed to appear.
registerBlockVariation() as the JS alternative
Adding a variation to a block from separate plugin code, not just the block's own block.json.
Why there's no separate slash-command API
Inserter search and the "/" shortcut both work off the exact same registration, nothing extra to build.
Prerequisites

Lesson 2’s “AI Text” block (my-plugin/ai-text), specifically its mode attribute, already needs to exist. This lesson adds a variation on top of that registration, it doesn’t build a new block.

Step 1: A variation in block.json

Block variations let one registered block type show up as multiple, differently labeled entries in the inserter, each with its own default attributes. Add a variations array to the AI Text block’s existing block.json:

// File: my-plugin/blocks/ai-text/block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "my-plugin/ai-text",
	"title": "AI Text",
	"category": "text",
	"icon": "editor-spellcheck",
	"attributes": {
		"content": { "type": "string", "source": "html", "selector": "p", "default": "" },
		"mode": { "type": "string", "default": "rewrite" }
	},
	"variations": [
		{
			"name": "ai-summary",
			"title": "AI Summary Block",
			"description": "A block pre-configured to summarize its text with AI instead of rewriting it.",
			"icon": "excerpt-view",
			"attributes": { "mode": "summarize" },
			"isActive": [ "mode" ],
			"scope": [ "inserter" ]
		}
	],
	"textdomain": "my-plugin",
	"editorScript": "file:./index.js"
}

scope: ["inserter"] means this variation only shows up as its own inserter entry, it doesn’t add a variation-picker UI on top of an already-placed block, which is the right choice here since switching a block between “rewrite” and “summarize” is just a mode attribute the block’s own toolbar already lets an author change (Lesson 2’s button label switches based on it). isActive: ["mode"] tells WordPress to treat an existing block instance as matching this variation whenever its mode attribute equals "summarize", which is what determines whether the inserter shows this block as already placed versus available to insert again.

Step 2: The alternative, registerBlockVariation()

If you need to add a variation to a block from separate plugin code, your own plugin adding a variation to a block registered elsewhere, rather than in that block’s own block.json, use registerBlockVariation() imperatively:

// File: my-plugin/src/register-summary-variation.js
import { registerBlockVariation } from '@wordpress/blocks';

registerBlockVariation( 'my-plugin/ai-text', {
	name: 'ai-summary',
	title: 'AI Summary Block',
	description: 'A block pre-configured to summarize its text with AI instead of rewriting it.',
	icon: 'excerpt-view',
	attributes: { mode: 'summarize' },
	isActive: [ 'mode' ],
	scope: [ 'inserter' ],
} );

Both approaches produce the same result, the block.json array is the right choice when you own the block being varied, registerBlockVariation() is the right choice when you’re adding a variation to a block you don’t own, the same relationship Lesson 6 had between owning a block and only being able to filter one.

Step 3: There is no separate slash-command API

It’s a reasonable thing to go looking for: some way to register “when someone types /ai-summary, insert this specific configuration” as its own distinct system. It doesn’t exist as a separate API. The inserter’s search-as-you-type list and the / slash-command shortcut inside the editor’s text areas are both reading from the exact same registered block types and variations, there’s nothing extra to wire up beyond what Steps 1 and 2 already did. Give a variation a clear title and keywords (an optional array of extra search terms) and it becomes reachable both ways for free.

Inserter visibility more broadly comes from two places: whether a block type is registered and allowed at all, controllable server-side with the allowed_block_types_all PHP filter, and which variations of an allowed block type exist, controlled by the registration covered in Steps 1 and 2. The allowed_block_types_all filter operates at the whole-block-type level, it can hide my-plugin/ai-text entirely, but it has no concept of hiding one variation while allowing another, that distinction lives entirely in how you register variations, not in that filter.

A missing or wrong isActive leaves both entries looking identical

If isActive doesn’t correctly reflect the attribute that distinguishes your variation, an already-placed “AI Summary Block” can show up in the block list or block switcher looking indistinguishable from the plain “AI Text” block, since WordPress has no way to tell which registered variation a given instance is supposed to represent. Keep isActive pointed at whichever attribute (or attributes) actually differ between variations, mode in this case.

Test it

Rebuild your block assets, open the post editor, open the inserter, and search for “summary”. You should see “AI Summary Block” appear as its own entry, separate from “AI Text”, with its own icon and description. Insert it and confirm the block’s toolbar button (from Lesson 2) already reads “Summarize with AI” without you touching the mode attribute manually, confirming the variation’s default attributes applied correctly on insert. Then try typing /summary inside an empty paragraph, the same variation should appear in the slash-command list.

Recap

A block variation, registered either inside block.json’s variations array or imperatively with registerBlockVariation(), gives one block type multiple, independently discoverable entries in the inserter, each with its own default attributes, isActive telling WordPress how to recognize an already-placed instance of that variation. There is no separate API for slash commands specifically, the inserter search and the / shortcut both read from the same block and variation registrations, and the allowed_block_types_all PHP filter controls whole block types, not individual variations within one.

Resources & further reading

← Building an AI-Powered Block Toolbar Action Course Recap: AI in the Editor vs. AI on the Backend →