Axle Block Restore developer reference

Hooks

Every default, limit and message has a filter, and every change fires an action.

axle_block_restore_post_typesFilter
( string[] $post_types )

Post types that get Axle Block Restore in the post editor and the abilities. Default every REST-enabled post type with revisions and the editor. Types without revisions are dropped

axle_block_restore_site_editor_post_typesFilter
( string[] $post_types )

Post types that get it in the Site Editor. Default wp_template, wp_template_part and wp_block. Types that do not exist, have no revisions or are not in the REST API are dropped

axle_block_restore_capabilityFilter
( string $capability, string $post_type )

Capability a user needs before the scripts load for a post type. Default the type’s own edit_posts capability: edit_theme_options for templates and parts, edit_posts for patterns and posts. An empty value falls back to the default

axle_block_restore_copy_post_typesFilter
( string[] $post_types )

Post types the Another post view copies from, and the search route allows. Default every post type the user can edit that has Axle Block Restore. Types the user cannot edit are dropped. An empty array turns the view off and makes the route answer 403

axle_block_restore_copy_max_resultsFilter
( int $max )

Most posts one search returns. Default 20

axleBlockRestore.canRestoreFilter
( boolean canRestore, Object block )

Whether a block’s menu and the "Restore selected block" command are offered for a block

axleBlockRestore.revisionsPerPageFilter
( number perPage )

Revisions loaded at a time, 1 to 100. Default 50

axleBlockRestore.removedRevisionsFilter
( number count )

How many of the newest revisions the Removed blocks view looks through, 1 to 100. Default 20

axleBlockRestore.removedSimilarityFilter
( number similarity )

Share of words, 0 to 1, a block of the same type now must have in common with an old block for it to count as edited, not removed. Default 0.6. 1 lists every block that is not identical

axleBlockRestore.removedBlocksFilter
( Object[] entries, { revisionIds } )

The blocks listed as removed, newest removal first. Each has name, title, text, path, block, revisionId, revisionIds and rewritten

axleBlockRestore.copyPostTypesFilter
( string[] postTypes )

Post types the Another post view offers. Can only narrow the PHP list. An empty array hides the view

axleBlockRestore.attributeRoleFilter
( string role, string name, string blockName, Object schema )

Whether an attribute is content, style or keep for a partial restore. Default from block.json role, the attribute’s source and the style list. Any other return value is ignored

axleBlockRestore.styleAttributesFilter
( string[] names, string blockName )

Attribute names that count as style. Default style, className, align, layout, backgroundColor, textColor, fontSize, fontFamily, gradient, borderColor

axleBlockRestore.restoreModesFilter
( string[] modes )

Ways to restore one block: replace, content, style. Default all three. replace is always kept, unknown names are dropped

axleBlockRestore.commandsFilter
( Object[] commands, string|null blockId )

Command palette entries, each { name, label, icon, callback }. Add, change or remove entries

axleBlockRestore.openedAction
( { clientId, postType, postId, focusSearch, view } )

The window opened. view is revisions or removed. clientId is null for the whole post, template, part or pattern. Template and part IDs look like theme//slug

axleBlockRestore.restoredAction
( { mode, block, revisionId, postId, postType } )

A block came back. mode is replace, content, style, insert-after, replace-at, insert-at, inner-replace, inner-insert, removed-place, removed-end, removed-below, other-post-below or other-post-end. For the last two the details also have sourcePostId and sourcePostType, and revisionId is a revision of that post or current

Abilities

What AI agents can do through the WordPress Abilities API and MCP, with the same permissions as the screen.

axle-block-restore/list-revisions

Read-only. Revisions of post_id, newest first, with who saved each

axle-block-restore/find-deleted

Read-only. Blocks whose text is in an old revision but not in the post, with the revision_id and path to restore them

axle-block-restore/find-text

Read-only. Blocks in old revisions containing text, and whether each is still in the post

axle-block-restore/restore-block

Puts the block at path in revision_id back: mode insert at a top-level position (default: where it was), or replace the block at target_path (default: the same path). Saves the post, which makes a new revision, so it can be undone. Refuses while someone else has the post open in the editor, unless force is true

Built from REFERENCE.md for version 3.1.0.

Scripts

There is no build step. The scripts use the wp.* globals WordPress already loads. They load in the post editor for post types with revisions, and in the Site Editor for templates, template parts, synced patterns and anything else that has revisions.

ScriptJob
assets/js/matching.jsBlock text, similarity ranking, classification, word diff, revision search, attribute roles, partial restores, the inner block comparison, and the removed blocks list with the position a block goes back to. No WordPress dependency, so it is unit tested in Node
assets/js/components.jsThe restore window, built on wp.components and wp.blockEditor, and the lookup of which entity a block belongs to
assets/js/index.jsThe two menu entries (BlockSettingsMenuControls and PluginMoreMenuItem) and the command palette entries

The window uses core components only (Modal, Card, PanelBody, Button, Notice, Spinner, Badge). assets/editor.css holds layout and nothing else.

More on hooks

// No restoring for reusable blocks, and log every restore.
wp.hooks.addFilter( 'axleBlockRestore.canRestore', 'my-plugin', ( canRestore, block ) => canRestore && 'core/block' !== block.name );
wp.hooks.addAction( 'axleBlockRestore.restored', 'my-plugin', ( details ) => console.log( 'Restored', details.block.name, 'from revision', details.revisionId ) );

// Treat a custom block's "heading" attribute as content, and a "variant" attribute as style.
wp.hooks.addFilter( 'axleBlockRestore.attributeRole', 'my-plugin', ( role, name, blockName ) => {
	if ( 'my/card' !== blockName ) {
		return role;
	}
	return 'heading' === name ? 'content' : 'variant' === name ? 'style' : role;
} );
// Templates and parts only for people who can manage options, and no support for patterns in the Site Editor.
add_filter( 'axle_block_restore_site_editor_post_types', static fn( array $types ) => array_diff( $types, array( 'wp_block' ) ) );
add_filter( 'axle_block_restore_capability', static fn( string $cap, string $type ) => in_array( $type, array( 'wp_template', 'wp_template_part' ), true ) ? 'manage_options' : $cap, 10, 2 );

Load that script with wp-hooks as a dependency, on enqueue_block_editor_assets.

More on abilities

On WordPress 6.9 and later, Axle Block Restore registers abilities, which AI agents find and run through the MCP adapter and anything else through the REST API under /wp-abilities/v1/. Each one is marked public, which the MCP adapter needs before it lists an ability.

Abilities work with post IDs, so they reach templates, template parts and patterns by the ID of their post. Restoring only the content or only the styling is an editor feature: the saved markup of a block (its classes and inline styles) only comes from the block’s own save() function, which runs in JavaScript.

In the editor the plugin guesses which old block matches which current one. An agent does not need the guess: it finds text that was deleted or changed, then names the exact block to bring back. A path counts blocks from 0, one number per level: [2] is the third top-level block, [2, 0] the first block inside it.

All four need edit_post on the post, in a post type that has Axle Block Restore. The find abilities look through 20 revisions by default, 50 at most (axle_block_restore_max_revisions).

HookTypeUse
axle_block_restore_restoredaction( int $post_id, array $block, int $revision_id, string $mode ). A block was saved back through restore-block
axle_block_restore_max_revisionsfilter( int $max ). Most revisions the find abilities look through. Default 50

REST

Revisions are fetched 50 at a time from /wp/v2/<rest base>/<id>/revisions with context=edit and _fields=id,wp_id,modified,date_gmt,slug,content.raw,axle_block_restore_author, so the server returns raw block markup and never renders the content. The rest base is templates, template-parts or blocks in the Site Editor.

Template and template part revisions come from core’s templates controller, so each one has id set to the template’s ID (theme//slug), its own ID in wp_id, and its time in modified, in the site’s time zone. The window reads those.

The plugin adds one read-only route, /axle-block-restore/v1/posts (see Copying a block from another post), and one read-only field to revision responses:

FieldValue
axle_block_restore_authorDisplay name of the revision’s author. Editors cannot always list users, so the name comes with the revision

Data

Nothing is stored. Restores are normal editor changes, saved when the post is updated.