Axle Block Restore guide

How it finds "the same block"

Blocks have no permanent ID between saves. For the selected block, every block of the same type in the revision is a candidate, scored by:

  • 1 if it sits at the same position (the same path of indexes from the top, so nested blocks count)
  • plus its word similarity to the current block (Jaccard similarity of the word sets, from 0 to 1)

The highest score is marked Best match. Candidates identical to the current block are hidden unless you ask for them.

For the whole post, each top-level block in the revision is Same as now when an identical block exists now, Changed since when the block now at that position has the same type, and Not in the post now otherwise.

Site Editor

Both entry points work in the Site Editor: the block menu (Restore from a revision…) and the editor menu (Restore blocks from a revision). Revisions come from the entity being edited:

EditingRevisions fromCapability
A template/wp/v2/templates/<theme>//<slug>/revisionsedit_theme_options
A template part/wp/v2/template-parts/<theme>//<slug>/revisionsedit_theme_options
A synced pattern/wp/v2/blocks/<id>/revisionsedit_posts
A post or page/wp/v2/<type>/<id>/revisionsthe type’s edit_posts

A block inside a template part, opened from a template, restores from the template part’s own revisions, and the change lands in the part, not in the template. In a template, core locks the blocks of a part to content editing, so their block menu has no restore item: use the command palette, or choose Edit original and use the menu there.

A template or template part that still comes from the theme’s files has no revisions until it is saved once. The window says so.

The REST routes check permissions themselves. The plugin only loads its scripts for a user who has the capability, and does not add anything the revisions endpoints would not show.

Restoring part of a block

With one block selected, each older version has up to four actions:

ActionDoes
Replace current blockThe old block, whole
Restore content onlyThe old content attributes and inner blocks. The block keeps its current style attributes, className, layout, colours, typography and spacing
Restore styling onlyThe old style attributes. The block keeps its current content and inner blocks
Insert below itThe old block next to the current one

A partial restore is disabled, with a note, when it would change nothing. Show changes and Preview follow the option picked under "Show changes for": the words that change, the settings that change (fontSize, className, and so on), and the block as it would look.

Each attribute is content, style or keep:

  • lock and metadata are keep. A partial restore never touches them.
  • style, className, align, layout, backgroundColor, textColor, fontSize, fontFamily, gradient and borderColor are style, whatever their block.json says.
  • An attribute with role: content in block.json (core’s own metadata), or a text source (html, rich-text, text, children, node, query), is content.
  • Any other attribute is style: it changes how the block looks or works, not what it says.

Both filters below change this. They are read each time the window opens.

Groups and inner blocks

A block that holds other blocks restores as a whole: Replace current block, Replace current version and Restore it here bring back the block and everything inside it as one change, so one Ctrl+Z undoes all of it. The card says how many inner blocks it holds.

When the block exists now and its inner blocks differ, the card has an expandable line such as "Inside: 1 added, 1 removed, 2 changed". Inner blocks that are identical drop out first. Of the rest, blocks of the same type pair up in order and count as changed, blocks only in the revision count as added, and blocks only in the post count as removed (a block counts with everything inside it). Open the line to see each difference. Restore this Paragraph (the block’s own name) restores one inner block: it replaces its counterpart, or, for an added block, puts it into the group that holds it. The rest of the group stays as it is.

Template parts are not compared, because their blocks belong to the part’s own document.

Command palette

On WordPress 6.3 and later the command palette (Ctrl+K, ⌘K) has four entries, in the post editor and the Site Editor:

CommandDoes
Restore blocks from a revisionOpens the window for the whole post, template, part or pattern
Restore selected block from a revisionOpens it for the selected block. Only listed while one block is selected
Find text in old revisionsOpens the window with the search box focused
Show removed blocksOpens the window on the Removed blocks view

Without wp-commands the script still loads and the menu entries work.

Removed blocks

The window has three views, as tabs: By revision (the list above), Removed blocks and Another post. Removed blocks answers "what did we lose recently". It looks through the newest 20 revisions (axleBlockRestore.removedRevisions) and lists every block, top level or nested, that was in one of them and is not in the post now, newest removal first.

A block counts as removed when no block now has the same markup, no block of the same type now has at least 60% of its words in common (axleBlockRestore.removedSimilarity; that is an edit), and it holds no block that is still in the post. Then:

  • A block that was gone for several revisions, or was edited before it went, is listed once, as its newest version, with "Also in 2 older revisions".
  • A block inside a removed block is not listed on its own: restoring the outer block brings it back.
  • A block of the same type that now sits at its old place is labelled Rewritten since instead of Removed.
  • Empty paragraphs, headings and lists are left out.

Each card shows the block type, an excerpt, who saved the last revision that had it and when, and Preview. The actions:

ActionPuts the block
Put it back where it wasAfter the nearest earlier neighbour that is still in the post, else before the nearest later one, else at its old index limited to the list. A nested block goes back into the counterpart of its old parent (same type at the same path, else the most similar block of that type), and to the top level when that parent is gone
Insert below the selected blockBelow the block that is selected in the editor. Only shown while a block of what you are editing is selected
Insert at the endAt the end of the post, template or template part

Each is one editor change: one Ctrl+Z undoes it. The view says when it is loading, when the revisions could not load (with Try again), and when nothing was removed. It works in the post editor and in the Site Editor.

Copying a block from another post

Another post searches the posts and pages you can edit, by title or text, and leaves out the post you are editing. Pick one, choose Current version or one of its revisions, optionally filter its blocks by text, then Insert below the selected block or Insert at the end on any block, nested ones included. The block is copied, so the other post does not change. It is one editor change, like every restore.

Only posts you can edit are offered, and the server checks it, not just the screen. The search is GET /axle-block-restore/v1/posts?search=&post_type=&exclude_id=&per_page=. It asks current_user_can( 'edit_post' ) for every post it finds and returns titles, types, status and dates only, never content, so it does not list titles of other people’s published posts or drafts that you cannot edit (core’s own search does list published ones). Reading a post’s revisions or its content then goes through core’s endpoints, which check edit_post again.

axle_block_restore_copy_post_types limits the post types, and an empty list turns the view off for everyone: the route then answers 403.

The states of the window

Each revision and block carries a tone and a word. The tones are core’s Badge intents.

LabelToneMeans
Not in the post nowerrorThe block is in the revision and not in the post
Changed sincewarningThe block now at that position has the same type and different content
Same as nowgoodAn identical block exists now
Best matchinfoThe closest version of the selected block
Found by your searchinfoThe block you picked in the search results
Added, Removed, Changedgood, error, warningInside a group, what restoring the whole group would do
RemovederrorIn the Removed blocks view: in a recent revision, not in the post now
Rewritten sincewarningIn the Removed blocks view: a block of the same type is at its old place now

Loading shows a spinner with "Loading revisions…". A revision list that cannot load shows an error with Try again. A post without revisions, and a template that still comes from the theme, show a note that says why the list is empty.