Clean up stray `<p>` tags added by `wpautop()` inside block level tags.

`autop()` can sometimes get confused and not clean up stray `<p>` or `</p>` tags inside block level elements, which produces sub-optimal HTML. While browsers can generally handle it, there's no need to make things harder for them if we don't have to.

Props pento, ayubi, pbearne, jond, azaozz, 1994rstefan, dionysous, MikeHansenMe, jorbin, miqrogroove, niallkennedy.
Fixes #27350.




git-svn-id: https://develop.svn.wordpress.org/trunk@45585 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Gary Pendergast 2019-07-02 01:30:15 +00:00
parent b97899a07f
commit 8298f9dad0
2 changed files with 70 additions and 4 deletions

View File

@ -492,7 +492,8 @@ function wpautop( $pee, $br = true ) {
// Change multiple <br>s into two line breaks, which will turn into paragraphs.
$pee = preg_replace( '|<br\s*/?>\s*<br\s*/?>|', "\n\n", $pee );
$allblocks = '(?:table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|form|map|area|blockquote|address|math|style|p|h[1-6]|hr|fieldset|legend|section|article|aside|hgroup|header|footer|nav|figure|figcaption|details|menu|summary)';
$allblocks = '(?:table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|form|map|area|blockquote|address|math|style|p|h[1-6]|hr|fieldset|legend|section|article|aside|hgroup|header|footer|nav|figure|figcaption|details|menu|summary)\b';
$allblocksexceptp = str_replace( '|p|', '|', $allblocks );
// Add a double line break above block-level opening tags.
$pee = preg_replace( '!(<' . $allblocks . '[\s/>])!', "\n\n$1", $pee );
@ -558,12 +559,12 @@ function wpautop( $pee, $br = true ) {
// Under certain strange conditions it could create a P of entirely whitespace.
$pee = preg_replace( '|<p>\s*</p>|', '', $pee );
// Add a closing <p> inside <div>, <address>, or <form> tag if missing.
$pee = preg_replace( '!<p>([^<]+)</(div|address|form)>!', '<p>$1</p></$2>', $pee );
// If an opening or closing block element tag is wrapped in a <p>, unwrap it.
$pee = preg_replace( '!<p>\s*(</?' . $allblocks . '[^>]*>)\s*</p>!', '$1', $pee );
// Add a closing <p> inside <div>, <address>, or <form> tag if missing.
$pee = preg_replace( '!<p>([^<]+)</(div|address|form)>!', '<p>$1</p></$2>', $pee );
// In some cases <li> may get wrapped in <p>, fix them.
$pee = preg_replace( '|<p>(<li.+?)</p>|', '$1', $pee );
@ -577,6 +578,12 @@ function wpautop( $pee, $br = true ) {
// If an opening or closing block element tag is followed by a closing <p> tag, remove it.
$pee = preg_replace( '!(</?' . $allblocks . '[^>]*>)\s*</p>!', '$1', $pee );
// If a closing <p> tag is inside a block element tag, without a preceding opening <p> tag, remove it.
$pee = preg_replace( '#(<(' . $allblocksexceptp . ')[^>]*>)(((?!<p>|</\2>).)*)</p>#s', '$1$3', $pee );
// If an opening <p> tag is inside a block element tag, without a following closing <p> tag, remove it.
$pee = preg_replace( '#<p>(((?!</p>).)*</' . $allblocksexceptp . '>)#s', '$1', $pee );
// Optionally insert line breaks.
if ( $br ) {
// Replace newlines that shouldn't be touched with a placeholder.

View File

@ -600,4 +600,63 @@ line 2<br/>
$this->assertEquals( $expected, trim( wpautop( $content ) ) );
}
/**
* wpautop() should remove stray <p> and </p> tags inside blocks
*
* @ticket 27350
* @dataProvider data_wpautop_removes_stray_p_tags_in_blocks
*/
function test_wpautop_removes_stray_p_tags_in_blocks( $data, $expected ) {
$this->assertEquals( $expected, wpautop( $data ) );
}
function data_wpautop_removes_stray_p_tags_in_blocks() {
return array(
array(
'<div><p>123</p> </div>',
"<div>\n<p>123</p>\n</div>\n",
),
array(
'<div><p>123</p></div>',
"<div>\n<p>123</p>\n</div>\n",
),
array(
'hello<div>test</div>',
"<p>hello</p>\n<div>test</div>\n",
),
array(
'<div><p>Hello world</p><span>WordPress</span></div>',
"<div>\n<p>Hello world</p>\n<span>WordPress</span></div>\n",
),
array(
"<div>hello\n<pre>test</pre>\nworld</div>",
"<div>hello\n<pre>test</pre>\n<p>world</p></div>\n",
),
array(
'hello<div>test</div>',
"<p>hello</p>\n<div>test</div>\n",
),
array(
'<div><img src="/wp-content/uploads/example.jpg" alt="something" /><div>Something</div></div>',
"<div><img src=\"/wp-content/uploads/example.jpg\" alt=\"something\" />\n<div>Something</div>\n</div>\n",
),
array(
'<div><span></span><div></div></div>',
"<div><span></span>\n<div></div>\n</div>\n",
),
array(
'<div>X<div></div></div>',
"<div>X\n<div></div>\n</div>\n",
),
array(
"<div><div></div>\n </div>",
"<div>\n<div></div>\n</div>\n",
),
array(
"[banner]\n<h1>Test</h1>",
"<p>[banner]</p>\n<h1>Test</h1>\n",
),
);
}
}