Remove all <p> tags inside of <li> tags with HTML Purifier

Viewed 551

As the title says I need to remove all <p> tags inside of <li> tags with HTML Purifier.

My input is like this:

<ul>
    <li>
        <p>111</p>
    </li>
    <li>
        <p>222</p>
    </li>
</ul>
<p>333</p>

and it should be cleaned liked this:

<ul>
    <li>111</li>
    <li>222</li>
</ul>
<p>333</p>

I can't get it to work no matter what I try. I can see a similar thing working in the example. It does work there as inline tag does not allow block children. But <li> is block and does allow <p> by specification. But I still need it out. Please help)

3 Answers

I found Awesome PHP function for skip tags

<?php 
$tags="<ul>
    <li>
        <p>111</p>
    </li>
    <li>
        <p>222</p>
    </li>
</ul>";
echo strip_tags($tags, ["li","ul"]);
?>

strip_tags takes two parameter one is html string and other is acceptable tags. it will automatically remove tags which are not defined in acceptable list.

the output string it generates:

<ul>
    <li>
        111
    </li>
    <li>
        222
    </li>
</ul>

You could also try using PHP's DOMDocument after purifying in with HTML Purifier - https://www.php.net/manual/en/class.domdocument.php

Loop through all paragraph <p> elements and if their direct parent is list item <li>, set li's textContent to p's textContent. Something like that:

$html = '<ul>
    <li>
        <p>111</p>
    </li>
    <li>
        <p>222</p>
    </li>
</ul>
';

$doc = new DOMDocument();
$doc->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); // See https://www.php.net/manual/en/domdocument.savehtml.php#119767
$paragraphs = $doc->getElementsByTagName('p');
$paragraphsLength = $paragraphs->length;

for ($i = 0; $i < $paragraphsLength; $i++) {
    $p = $paragraphs->item(0); // See https://www.php.net/manual/en/domdocument.getelementsbytagname.php#99716
    if ($p->parentNode->tagName === 'li') {
        $p->parentNode->textContent = $p->textContent;
    }
}

echo $doc->saveHTML();

Update:

My example is a bit simplified. In fact, I have <p> tags elsewhere, not only inside <li>

In the case that your HTML is much bigger. Naively looping through all paragraphs might not be the most performant way and you should look into DOMXPath. For example:

/*...*/
$xpath = new DOMXPath($doc);
$paragraphs = $xpath->query('//li/p');
/*...*/
Related