How to wrap div around <p> tag?

I am using WordPress as a CMS system, and I want to wrap every p tag in some HTML I need for styling and positioning in my website.

I have found a piece of code that does this wonderfully for me, but it is overdoing it right now.

Read More

Here it is:

function tekst_wrapper($content) {
    // match any p tags
    $pattern = '~<p.*</p>~';
    preg_match_all($pattern, $content, $matches);

    foreach ($matches[0] as $match) {
        // wrap matched p tag with div
        $wrappedframe = '<div>' . $match . '</div>';

        //replace original p tag with new in content
       $content = preg_replace($pattern, $wrappedframe, $content);
    }

    return $content;    
}
add_filter('the_content', 'tekst_wrapper');

This adds div tags around each p tag. But for every p tag there is in the post, it starts adding more div tags on each p tag. So say I have four p tags, the resulting HTML will be:

<div>
  <div>
    <div>
      <div>
        <p>random text</p>
      </div>
    </div>
  </div>
</div>
<div>
  <div>
    <div>
      <div>
        <p>random text</p>
      </div>
    </div>
  </div>
</div>
<div>
  <div>
    <div>
      <div>
        <p>random text</p>
      </div>
    </div>
  </div>
</div>
<div>
  <div>
    <div>
      <div>
        <p>random text</p>
      </div>
    </div>
  </div>
</div>

Obviously this not what I need, since I just want each p tag to be wrapped in a single div tag (or whatever my replacement HTML is going to be). Now my PHP skills aren’t that great, but I assume the foreach causes it to add div tags for every match it finds in the $matches array? Is there any way to fix this?

Related posts

2 comments

  1. You have several copies of the same <p> tag in your HTML and you are replacing every one of them on each iteration on your foreach loop. Use preg_replace or preg_replace_callback instead of foreaching.

    function tekst_wrapper($content) {
        // match any p tags
        $pattern = '~<p.*?</p>~';
        return preg_replace_callback($pattern, function($matches) {
            return '<div>' . $matches[0] . '</div>';
        }, $content);
    }
    add_filter('the_content', 'tekst_wrapper');
    

    Note that there is a question mark in the pattern, to make it lazy.

  2. This would be expected because preg_match_all is matching all 4 of the p tags, then in the foreach, the preg_replace is replacing all 4 of the tags everytime the loop runs through, in total the loop runs 4 times and all tags are replaced 4 times resulting in the output above.

    To resolve this simply use the preg_replace and abandon the preg_match_all, as preg_replace would replace it for all, so this is what you would end up with:

    function tekst_wrapper($content) {
      return preg_replace_callback('~<p.*</p>~i', function($match) {
        return '<div>' . $match[0] . '</div>';
      }, $content);
    }
    
    add_filter('the_content', 'tekst_wrapper');
    

    Ive update the regex to include ‘i’ at the end of it, which makes it case insensitive. This is because HTML is case insensitive.

    Hope this helps.

Comments are closed.