How to bulk edit WordPress content without breaking Gutenberg blocks

You run a search-replace across the site, the front end looks fine — and a week later an editor opens a post and sees "This block contains unexpected or invalid content." Bulk edits and the block editor do not always get along. This guide explains why, which changes are safe, and how to bulk-fix content without leaving broken blocks behind.

How blocks are stored

The block editor saves ordinary HTML in post_content, wrapped in HTML comments that describe each block:

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Opening hours</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Open daily from 9 to 5.</p>
<!-- /wp:paragraph -->

The comment holds the block name and its attributes as JSON. The HTML between the comments is what the block's save function produced. The front end simply displays the HTML; the editor reads both.

Why blocks become "invalid"

When the editor loads a post, it rebuilds each block from its attributes and compares the result with the stored HTML. If they do not match, the block is marked invalid and the editor offers to recover or convert it. Typical causes after a bulk edit:

  • Changed markup: a removed or renamed class (wp-block-heading), a changed tag, an attribute stripped by a regex.
  • Deleted HTML, kept comments: replacing <p></p> with nothing leaves <!-- wp:paragraph --> wrapping nothing.
  • Broken JSON in a comment: replacing text inside block attributes — URLs, alt text, ACF block data — without keeping valid JSON escaping.
  • Attribute and HTML out of sync: for blocks that store the same value in both places, changing one copy and not the other.

Changing plain words inside a paragraph's text, on the other hand, is fine: the editor reads that text back as the block's content.

Which bulk edits are safe

EditRisk
Replacing words in visible text (a product name, a typo)Low — if the word never appears in URLs, classes or attributes
Changing a domain in linksLow with wp search-replace (handles serialized data); check block JSON with escaped slashes
Whitespace changes (double spaces)Medium — also hits code blocks and markup
Removing tags or empty elements with a regexHigh — breaks block validation
Editing anything inside <!-- wp:… --> commentsHigh — invalid JSON or out-of-sync attributes

A checklist before any bulk edit

  1. Back up the database — wp db export or your host's backup — and know how to restore it.
  2. Dry run first: wp search-replace 'old' 'new' wp_posts --include-columns=post_content --dry-run shows how many rows would change.
  3. Narrow it down to the column, post types and statuses you mean; wp_posts also contains revisions, menu items and reusable blocks.
  4. Make the pattern specific enough not to match inside URLs, classes or attributes.
  5. Open a few changed posts in the editor afterwards — the front end will not show invalid blocks; only the editor does.
  6. Remember there is no undo. Direct database edits create no revisions; restoring the backup also reverts everything else changed since.

A safer way to fix content site-wide

For text-level cleanup — spaces, punctuation, dashes, empty paragraphs — Content Polisher was designed around these pitfalls:

  • It parses the content and edits only the text between tags; block comments, attributes, classes and links keep every byte.
  • Text is edited only in blocks whose content is stored as HTML, so edited blocks stay valid. Code blocks, custom HTML and preformatted text are skipped.
  • An empty paragraph block is removed together with its comments, never leaving an empty wrapper.
  • Every issue has a preview; posts are saved the normal way, so WordPress revisions are created.
  • Every change is recorded in History and can be undone — and undo stops to ask if the post was edited in the meantime.

With Content Polisher Pro, Fix all safe issues applies every safe fix across the site in batches, as one operation you can undo in one click. It also handles ACF blocks: only the changed value is rewritten inside the block's JSON, so undo restores the post exactly.