How to remove empty paragraphs (<p> </p>) in WordPress
A post looks fine in the editor, but on the site there is an odd extra gap between two paragraphs. Open the code view and you find it: <p> </p> — a paragraph with nothing in it but a non-breaking space. This guide explains where empty paragraphs come from, why the usual CSS trick only half works, and how to remove them from the content itself.
Contents
Where empty paragraphs come from
- Pressing Enter twice in the Classic editor. To keep the empty line, the editor stores it as
<p> </p>. - Empty paragraph blocks. In the block editor, a paragraph block whose text was deleted is saved as an empty block:
<!-- wp:paragraph --> <p></p> <!-- /wp:paragraph --> - Pasting from Word or Google Docs, where empty lines are used for spacing.
- Migrations and imports that wrap every line of the source in
<p>.
The result is uneven vertical spacing that varies from post to post — and sends a slightly unpolished signal, especially on mobile, where every extra gap is a scroll.
The CSS :empty trick — and why it is not enough
A common suggestion is to hide empty paragraphs in your theme's CSS:
.entry-content p:empty {
display: none;
}
This hides <p></p>, but not <p> </p> or <p> </p>: for CSS, a non-breaking space or even a single regular space is content, so the paragraph is not :empty. Those are exactly the paragraphs the Classic editor creates. And the empty markup is still in your content — in RSS feeds, newsletters, the REST API and any future theme.
Find empty paragraphs with SQL
To see how many posts are affected (replace wp_ with your table prefix):
SELECT ID, post_type, post_title
FROM wp_posts
WHERE post_status = 'publish'
AND (
post_content LIKE '%<p></p>%'
OR post_content LIKE '%<p> </p>%'
OR post_content LIKE '%<p> </p>%'
);
Paragraphs with attributes (<p class="...">) or a non-breaking space stored as the UTF-8 character instead of are not caught by these simple patterns.
Do not mass-replace <p></p> with nothing in block content. That leaves the <!-- wp:paragraph --> delimiters around nothing, and the editor reports the block as invalid. An empty paragraph block has to be removed together with its delimiters.
Hide them with a the_content filter
If you only need them gone from the page, a small filter in a site plugin or your child theme's functions.php removes them when the post is displayed:
add_filter( 'the_content', function ( $content ) {
// <p></p>, <p> </p>, <p> </p> and the UTF-8 non-breaking space.
return preg_replace( '#<p>(?:\s| |\x{00A0})*</p>#iu', '', $content );
}, 20 );
Like the CSS fix, this only hides the problem: the stored content does not change, feeds that bypass the_content still contain the empty paragraphs, and it runs on every page view.
Remove them from the content with a plugin
Content Polisher finds empty paragraphs across all your posts and pages and removes them from the content itself:
- It catches
<p></p>,<p> </p>,<p> </p>and empty paragraph blocks. - An empty paragraph block is removed together with its delimiters, so the block editor stays happy.
- A paragraph is empty only if it holds nothing but whitespace. One with an image, a
<br>, an embed or a shortcode is left alone. - Each removal is a safe fix with a preview. Fix one post or all its safe issues at once; every change is backed up and can be undone from History.
The same scan reports runs of <br><br> as a suggestion, since double line breaks are sometimes used on purpose. With Content Polisher Pro you can also find empty headings and empty formatting tags such as <strong></strong>, and clean up the whole site in one undoable operation.