Stop WordPress Wrapping Images In A “P” Tag

I have searched high and low for a simple solution to this, but to no avail. WordPress keeps on wrapping my images in p tags and because of the eccentric nature of the layout for a site I am working on, this is highly annoying.

I have created a jQuery solution to unwrap images, but it isn’t that great. It lags because of other stuff loading on the page and so the changes are slow to be made. Is there a way to prevent WordPress wrapping just images with p tags? A hook or filter perhaps that can be run.

Read More

This is happening when uploading an image and then inserting it into the WYSIWYG editor. Manually going into the code view and removing the p tags is not an option as the client is not that technically inept.

I understand that images are inline, but the way I have the site coded images are inside of divs and set to block, so they are valid code.

Related posts

Leave a Reply

11 comments

  1. here’s what we did yesterday on a client site that we were having this exact problem with… I created a quick filter as a plugin and activated it.

    <?php
    /*
    Plugin Name: Image P tag remover
    Description: Plugin to remove p tags from around images in content outputting, after WP autop filter has added them. (oh the irony)
    Version: 1.0
    Author: Fublo Ltd
    Author URI: http://fublo.net/
    */
    
    function filter_ptags_on_images($content)
    {
        // do a regular expression replace...
        // find all p tags that have just
        // <p>maybe some white space<img all stuff up to /> then maybe whitespace </p>
        // replace it with just the image tag...
        return preg_replace('/<p>(s*)(<img .* />)(s*)</p>/iU', '2', $content);
    }
    
    // we want it to be run after the autop stuff... 10 is default.
    add_filter('the_content', 'filter_ptags_on_images');
    

    If you drop that into a php file in your /wp-content/plugins folder and then activate it, it should remove the p tags from any para that just contains an image.

    I’m not sure how strong the regexp is in terms of if it will fail with outputs from other editors – for example if the img tag is closed with just > it will fail. If anyone has anything stronger, that would be really helpful.

    Cheers,

    James

    — Improved filter —

    To work with images that are wrapped in links, it keeps the links in the output and removes the p tags.

    return preg_replace('/<p>s*(<a .*>)?s*(<img .* />)s*(</a>)?s*</p>/iU', '123', $content);
    
  2. Basically you need to make WordPress treat img like block-level element for the purpose of formatting. Such elements are hardcoded in wpautop() and list is unfortunately not filtered.

    What I would do is:

    1. Fork wpautop() under different name.
    2. Add img to regexp in $allblocks variable.
    3. Remove wpautop from the_content filter.
    4. Add your forked version to the_content.
    5. You might need to play with priority and possibly remove and re-add other filters if something breaks because of changed processing order.
  3. Accepted answer helped me with just the images but the revised code doesn’t handle linked images well at my site. This blog post has a code that works perfectly.

    Here’s the code:

    function wpautop_forked($pee, $br = 1) {
    
    if ( trim($pee) === '' )
    return '';
    $pee = $pee . "n"; // just to make things a little easier, pad the end
    $pee = preg_replace('|<br />s*<br />|', "nn", $pee);
    // Space things out a little
    $allblocks = '(?:table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li
    |pre|select|option|form|map|area|blockquote|img|address|math|style|input
    |p|h[1-6]|hr|fieldset|legend|section|article|aside|hgroup|header|footer
    |nav|figure|figcaption|details|menu|summary)';
    $pee = preg_replace('!(<' . $allblocks . '[^>]*>)!', "n$1", $pee);
    $pee = preg_replace('!(</' . $allblocks . '>)!', "$1nn", $pee);
    $pee = str_replace(array("rn", "r"), "n", $pee); // cross-platform newlines
    if ( strpos($pee, '<object') !== false ) {
    $pee = preg_replace('|s*<param([^>]*)>s*|', "<param$1>", $pee); // no pee inside object/embed
    $pee = preg_replace('|s*</embed>s*|', '</embed>', $pee);
    }
    $pee = preg_replace("/nn+/", "nn", $pee); // take care of duplicates
    // make paragraphs, including one at the end
    $pees = preg_split('/ns*n/', $pee, -1, PREG_SPLIT_NO_EMPTY);
    $pee = '';
    foreach ( $pees as $tinkle )
    $pee .= '<p>' . trim($tinkle, "n") . "</p>n";
    $pee = preg_replace('|<p>s*</p>|', '', $pee); // under certain strange conditions it could create a P of entirely whitespace
    $pee = preg_replace('!<p>([^<]+)</(div|address|form)>!', "<p>$1</p></$2>", $pee);
    $pee = preg_replace('!<p>s*(</?' . $allblocks . '[^>]*>)s*</p>!', "$1", $pee); // don't pee all over a tag
    $pee = preg_replace("|<p>(<li.+?)</p>|", "$1", $pee); // problem with nested lists
    $pee = preg_replace('|<p><blockquote([^>]*)>|i', "<blockquote$1><p>", $pee);
    $pee = str_replace('</blockquote></p>', '</p></blockquote>', $pee);
    $pee = preg_replace('!<p>s*(</?' . $allblocks . '[^>]*>)!', "$1", $pee);
    $pee = preg_replace('!(</?' . $allblocks . '[^>]*>)s*</p>!', "$1", $pee);
    if ($br) {
    $pee = preg_replace_callback('/<(script|style).*?</\1>/s', create_function('$matches', 'return str_replace("n", "<WPPreserveNewline />", $matches[0]);'), $pee);
    $pee = preg_replace('|(?<!<br />)s*n|', "<br />n", $pee); // optionally make line breaks
    $pee = str_replace('<WPPreserveNewline />', "n", $pee);
    }
    $pee = preg_replace('!(</?' . $allblocks . '[^>]*>)s*<br />!', "$1", $pee);
    $pee = preg_replace('!<br />(s*</?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)!', '$1', $pee);
    if (strpos($pee, '<pre') !== false)
    $pee = preg_replace_callback('!(<pre[^>]*>)(.*?)</pre>!is', 'clean_pre', $pee );
    $pee = preg_replace( "|n</p>$|", '</p>', $pee );
    
    return $pee;
    }
    
    remove_filter('the_content', 'wpautop');
    add_filter('the_content', 'wpautop_forked');
    

    Cheers!

  4. I’m not an expert but just spent the hole afternoon trying to solve de img wraped in p tags and this worked for me.

    I am working on a wordpress based theme and just added this to the functions.js file

    Jquery function unwrap

    > $(document).ready(function (){
    > 
    > // for images wraped in a tags
    > 
    > $(‘.entry a’).unwrap(‘p’);
    > 
    > //for images wraped in just p tags
    > $(‘.entry img’).unwrap(‘p’);
    

    now I can work p and img seperately.

    Also can add a div with a different class arround the img using this:

    $(document).ready(function (){
    
    $('.entry img').wrap('<div class="justImg"></div>');
    

    this last one didn’t solved my problem because I wanted to make p tags with display:none; so I really had to take those img out of there.

  5. In case someone is look for a quick and dirty way to fix this for any tag here’s what I did:

    1. go to wp-content/formatting.php
    2. find wpautop function. (in case you missed it, it’s WP-AUTO-P, get it?)
    3. fins the “all blocks” variable, should be something like $allblocks = '(?:table|thead|tfoot|capti...
    4. at the end add the block you wish to omit – img, a, etc…
      for example if it ends in (...)menu|summary)'; change to (...)menu|summary|a)'; to add the a tag and avoid autopeeing it. Note the pipe | separator – it’s regex syntax!

    That’s it, happy WordPressing!

  6. Put yout image inside a <div> tag, without any whitespace chars between them. So Instead of :

    <div class="your_container">
        <div class="element1">...</div>
        <div class="element2">...</div>
        <img src="image.jpg" />
    </div>
    

    You write this:

    <div class="your_container">
        <div class="element1">...</div>
        <div class="element2">...</div>
        <div><img src="image.jpg" /></div>
    </div>
    

    I’ve had the same problem with <a> elements, and this solved for me.