Skip to content
  • FG-51
  • 12 min read
  • Last checked November 7, 2026

How to Fix “Block contains unexpected or invalid content” and Missing Blocks in WordPress

Blocks flagged as invalid or “Your site doesn’t include support” after a theme switch, plugin removal or update. Recover them without losing content.

Run the health check

You open a page in the block editor and a block is replaced by a warning: “Block contains unexpected or invalid content.” with an “Attempt recovery” button (older versions say “This block contains unexpected or invalid content” and “Attempt Block Recovery”). Or a block shows “Your site doesn’t include support for the “PLUGIN-NAMESPACE/BLOCK-NAME” block. You can leave it as-is, convert it to custom HTML, or remove it.” It often appears right after a theme switch, a plugin was removed, or WordPress or a block plugin was updated.

Your content is not gone. The HTML is still saved in the database, and visitors usually still see it. The editor is telling you it cannot safely take control of that markup. This guide explains why, how to recover each block without losing content, and when to restore a revision instead. It is for site owners, editors and designers working in the block editor; if your page builder (Elementor, Breakdance, Divi and so on) broke after an update, see the page builder update guide instead.

What is happening

Blocks are stored as ordinary HTML inside post_content, wrapped in comment delimiters that hold the block name and its settings:

<!-- wp:NAMESPACE/BLOCK-NAME {"ATTRIBUTE":"VALUE"} -->
<div class="wp-block-NAMESPACE-BLOCK-NAME">SAVED MARKUP</div>
<!-- /wp:NAMESPACE/BLOCK-NAME -->

This is what a block looks like in the database and in the editor’s Code editor view; you do not run it. NAMESPACE/BLOCK-NAME is the block’s registered name, such as core/paragraph or PLUGIN-NAMESPACE/accordion. The JSON holds attributes such as colors and alignment.

When the editor loads a post, it parses those comments, then for each block it runs the block’s JavaScript save() function with the stored attributes and compares the result with the saved markup. If they match (ignoring trivial differences such as whitespace and attribute order), the block is valid. If they do not, and none of the block’s registered deprecated versions produces matching markup either, the block is marked invalid. The front end does not run this check; it simply prints the saved HTML (or, for dynamic blocks, runs PHP to render it), which is why visitors are often unaffected.

Message Meaning Usual cause
Block contains unexpected or invalid content. The block type exists, but its current save() output differs from the saved markup Plugin update that changed markup without a deprecation, hand edited HTML, content pasted or imported from elsewhere, a filter that altered saved markup
Your site doesn’t include support for the “X” block. No block with that name is registered The plugin or theme providing it was deactivated or removed, or its script failed to load
It appears you are trying to use the deprecated Classic block. Classic content where the Classic block is unavailable A plugin or setting disabled the Classic block
The editor has encountered an unexpected error. A JavaScript crash, not a validation failure Plugin conflict; see the Console

Before you start

  • Access: an editor or administrator account. SSH with WP-CLI helps for site wide searches.
  • Backup: take a database backup, or at least copy the post content: open the editor’s Options menu (three dots, top right), switch to Code editor, select all and save the text somewhere safe.
  • How to run commands: WP-CLI commands run over SSH in the site folder, the one containing wp-config.php, as wp or wp-cli depending on your host. Browser checks use DevTools (F12).
  • Do not click Update on a post with invalid blocks until you have decided how to handle each one. Saving can make some choices permanent.

Step 1: Check the front end and decide how urgent it is

Open the published page in a private window. If it looks right, nothing is broken for visitors and you can work calmly. If content is missing on the front end too, the cause is more likely a removed plugin whose dynamic block no longer renders (Step 3) or a styling change (Step 5).

Next, check how many posts are affected. If it happened after a plugin update, it may be every post using that block.

wp post list --post_type=page,post --s="wp:NAMESPACE/BLOCK-NAME" --fields=ID,post_title,post_type --format=table

Run over SSH in the site folder. NAMESPACE/BLOCK-NAME is the block name shown in the warning, or visible in the Code editor comment. --post_type lists the post types to search; add others such as wp_block (synced patterns) or wp_template_part if needed. --s runs WordPress’s normal search against the text, which includes post content, and --fields chooses the columns shown. Good output is a table of posts that contain the block, which is your work list. Empty output means the search found no matches; WordPress search splits on spaces and checks titles and excerpts too, so for exact matching use the SQL query in the Advanced section.

Step 2: Fix “Block contains unexpected or invalid content”

Compare before you click

Select the invalid block, open its three dot menu, and choose Resolve. A “Resolve Block” dialog shows two panes: the current saved markup and the markup the block would produce now. Look at what differs. Common findings:

  • A class name or wrapper div changed in a plugin update. Recovery is safe.
  • Extra HTML someone added by hand (an inline style, an extra link attribute). Recovery will remove it.
  • Text that exists only in the saved version. Recovery may drop it, so copy it first.

Attempt recovery

Attempt recovery (labeled “Attempt Block Recovery” in older versions) re-parses the saved HTML, extracts what it can into the block’s current attributes, and rebuilds the block with the current save() output. In the Resolve dialog the same action is offered as “Convert to Blocks”. It works well when the change was structural (new wrapper, renamed class) and attribute values can still be read from the markup. It loses anything the block cannot represent as an attribute, such as hand added inline styles or unknown inner elements.

After recovery, check the block’s content and settings, then preview. If it looks right, update the post. If not, use the editor’s Undo (Ctrl+Z) before saving, which reverts the recovery.

Convert to HTML or Classic

If recovery would lose important markup, use the three dot menu’s Convert to HTML. This replaces the block with a Custom HTML block containing exactly the saved markup, so the front end stays identical, but you lose the block’s visual controls. For blocks that are mostly text and formatting, converting to a Classic block (where available) gives you a familiar editor at the cost of some layout features. Treat both as stopgaps for content you will rebuild later.

When it affects every post

If a plugin update made every instance invalid, do not recover dozens of posts by hand. Check the plugin’s changelog and support forum; well maintained block plugins ship deprecated definitions so old markup still validates, and a missing one is a bug they usually fix quickly. Rolling the plugin back on staging to confirm, and reporting it, is often better than mass recovery. Some block plugins also provide their own “recover all blocks” tool.

Step 3: Fix “Your site doesn’t include support for the X block”

Confirm the provider

The quoted name tells you the provider: the part before the slash is the namespace, often the plugin’s slug or a short form of it. core/ blocks come with WordPress. If a namespace matches a plugin you recently deactivated or deleted, that is the cause. Check your plugin list:

wp plugin list --status=inactive --fields=name,status,version

Run over SSH in the site folder. --status=inactive limits the list to installed but deactivated plugins, and --fields chooses the columns. Good output shows a plugin whose name matches the block namespace; reactivating it (wp plugin activate PLUGIN_SLUG, where PLUGIN_SLUG is the value in the name column) brings the blocks straight back. Empty output means the plugin is deleted, not just inactive; reinstall it from the same source if you still have access.

If the plugin is active but the block is still unsupported, its editor script failed to load. Open DevTools, then the Console, while the editor loads, and look for a 404 on the plugin’s script or a JavaScript error. A security rule, a CDN rewrite or a JavaScript optimization applied to the admin area are common culprits.

Choose what to do with each block

  • Leave it as is: the saved markup stays in the database. For static blocks it keeps displaying; for dynamic blocks (those rendered by PHP, like post lists or forms) nothing displays, because the PHP renderer is gone.
  • Keep as HTML: converts it to a Custom HTML block with the saved markup. Static content keeps working. The plugin’s CSS and JavaScript are gone, so styling and interactivity may not survive.
  • Remove: deletes it from the post when you save.
  • Replace: rebuild the content with core blocks or blocks from your new plugin, then remove the old one.

On sites that allow the block directory, the editor may offer to install a matching block from WordPress.org instead. Only accept if it is the plugin you actually used.

Step 4: Synced patterns, reusable blocks and template parts

Synced patterns (called reusable blocks before WordPress 6.3) are stored as posts of type wp_block. A synced pattern containing an invalid or missing block shows the warning on every page that uses it, but you fix it once by editing the pattern itself under Appearance, then Editor, then Patterns (or Patterns in the block editor’s inserter, Manage patterns). Inside a page, use the pattern’s “Edit original” option so you change the source instead of detaching a copy.

Unsynced patterns are copied into each post when inserted, so they must be fixed in each post. Theme patterns that come from the old theme’s patterns folder disappear when you switch themes, but content already inserted from them stays in your posts.

In block themes, template parts (header, footer) are stored in the theme files and, once customized, as wp_template_part posts. After a theme switch, customized parts tied to the old theme are not used by the new theme. If a header looks wrong after switching, check Appearance, then Editor, then Patterns, then Template Parts.

Step 5: theme.json and style changes after a theme switch

Some “broken block” reports are not validation errors at all. Blocks store color, font size and spacing choices as preset slugs, such as a class like has-PRESET-SLUG-color or a CSS variable like var(--wp--preset--color--PRESET-SLUG). Those presets are defined by the theme’s theme.json. If the new theme does not define a preset with the same slug, the block keeps the reference but nothing provides the value, so text loses its color or a section loses its background.

To confirm, inspect the element in DevTools and look for a has-...-color class or a --wp--preset-- variable with no value in the Computed or Styles panel. Fix it by adding matching preset slugs in a child theme’s theme.json, choosing new colors in each block, or using Appearance, then Editor, then Styles to redefine the palette. Layout differences (content width, block gap) also come from theme.json settings such as layout.contentSize, so wide or full width blocks may look different under a new theme even though they are valid.

Step 6: Restore from revisions

If recovery made things worse, or someone saved over good content, use revisions. In the editor sidebar’s Post tab, click Revisions (shown with a count). The revisions screen compares versions side by side. Find the last revision before the problem, check it, and click Restore This Revision.

wp post list --post_type=revision --post_parent=POST_ID --fields=ID,post_date,post_author --format=table

Run over SSH in the site folder. POST_ID is the number in the editor URL (post.php?post=POST_ID). --post_parent limits the list to that post’s revisions. Good output is a dated list of revision IDs. Empty output means revisions are disabled (check WP_POST_REVISIONS in wp-config.php) or were cleaned up by an optimization plugin, and you need a backup instead. Restoring a revision brings back its markup; if the cause was a plugin change, the restored blocks may still show as invalid until the plugin issue is fixed, but no content is lost.

Advanced: Finding and inspecting blocks across the database

Exact search with SQL

wp db query "SELECT ID, post_type, post_status, post_title FROM $(wp db prefix)posts WHERE post_content LIKE '%wp:NAMESPACE/BLOCK-NAME%' AND post_type NOT IN ('revision') ORDER BY post_type"

Run over SSH in the site folder, in bash. NAMESPACE/BLOCK-NAME is the block name. $(wp db prefix) inserts your table prefix (often wp_ but not always), and LIKE '%...%' finds the block comment anywhere in the content. Excluding revisions keeps the list to live content. Good output is one row per post, page, synced pattern or template part that contains the block. No output means the block is not used anywhere, so removing its plugin is safe.

Parse a post’s blocks the way WordPress does

wp eval 'foreach ( parse_blocks( get_post( POST_ID )->post_content ) as $b ) { echo ( $b["blockName"] ?? "(freeform)" ), PHP_EOL; }'

Run over SSH in the site folder. Replace POST_ID with the post number. wp eval runs PHP inside WordPress. parse_blocks() is the same parser WordPress uses, and this prints each top level block name in order; content outside any block comment shows as (freeform). Good output is a readable list of block names, letting you spot the unsupported namespaces before you open the editor. An error mentioning a parse problem usually means unbalanced block comments, often from hand editing or a broken import; open the Code editor and look for an opening wp: comment without its matching closing comment.

Why hand edits fail validation

The validator compares normalized HTML, so whitespace and attribute order do not matter, but tag names, class lists, inline styles and text do. Adding a rel attribute to a link inside a block that does not output one, or a class through the Code editor instead of the Additional CSS class field, will fail. Use the block’s own settings (Advanced, Additional CSS class, HTML anchor) so the change is stored as an attribute and regenerated by save().

Filters that change saved markup

Plugins that rewrite content on save (some security, link and lazy load plugins) can alter block markup before it is stored, which fails validation the next time you open the editor. If every new post fails validation for a block right after saving, deactivate content filtering plugins one at a time on staging and retest. The Console in the editor logs a “Block validation failed” message with the expected and actual markup, which shows exactly what was altered.

When to contact your host

Block validation is an editor and plugin issue, so a host can rarely fix the markup for you. Open a ticket when:

  • A plugin’s editor scripts return 403 or 404 in the admin area, which points to a server rule or file problem.
  • You need a database backup from before the problem to recover lost content or revisions.
  • WP-CLI is unavailable and you need the queries above run.

Send the post URLs and IDs, the exact warning text and block name, the UTC time the problem started, and what changed just before (theme switch, plugin removal or update, with versions). If the front end is down rather than just the editor, start at the Emergency Room, and use the diagnostic tools to check the site from outside.

Still stuck?

Print a free one-page checklist to keep, or open the Emergency Room if the symptom does not match.

Get the free checklists

Keep reading

All field guides
FG-108 Updates

WordPress 6.9 Broke My Site: Known Issues and Fixes

Problems since WordPress 6.9? See the changes that broke sites (email sender, post navigation loops, classic theme styles), what 6.9.1 to 6.9.4 fixed, and how to roll back.

Read the guide
11 min read

Search the field manual

What is going wrong?

Press / to search from any page, Esc to close