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:
| Editing | Revisions from | Capability |
|---|---|---|
| A template | /wp/v2/templates/<theme>//<slug>/revisions | edit_theme_options |
| A template part | /wp/v2/template-parts/<theme>//<slug>/revisions | edit_theme_options |
| A synced pattern | /wp/v2/blocks/<id>/revisions | edit_posts |
| A post or page | /wp/v2/<type>/<id>/revisions | the 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:
| Action | Does |
|---|---|
| Replace current block | The old block, whole |
| Restore content only | The old content attributes and inner blocks. The block keeps its current style attributes, className, layout, colours, typography and spacing |
| Restore styling only | The old style attributes. The block keeps its current content and inner blocks |
| Insert below it | The 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:
lockandmetadataare keep. A partial restore never touches them.style,className,align,layout,backgroundColor,textColor,fontSize,fontFamily,gradientandborderColorare style, whatever theirblock.jsonsays.- An attribute with
role: contentinblock.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:
| Command | Does |
|---|---|
| Restore blocks from a revision | Opens the window for the whole post, template, part or pattern |
| Restore selected block from a revision | Opens it for the selected block. Only listed while one block is selected |
| Find text in old revisions | Opens the window with the search box focused |
| Show removed blocks | Opens 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:
| Action | Puts the block |
|---|---|
| Put it back where it was | After 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 block | Below the block that is selected in the editor. Only shown while a block of what you are editing is selected |
| Insert at the end | At 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.
| Label | Tone | Means |
|---|---|---|
| Not in the post now | error | The block is in the revision and not in the post |
| Changed since | warning | The block now at that position has the same type and different content |
| Same as now | good | An identical block exists now |
| Best match | info | The closest version of the selected block |
| Found by your search | info | The block you picked in the search results |
| Added, Removed, Changed | good, error, warning | Inside a group, what restoring the whole group would do |
| Removed | error | In the Removed blocks view: in a recent revision, not in the post now |
| Rewritten since | warning | In 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.