Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

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.

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.

share|improve this question
    
See css-tricks.com/snippets/wordpress/… –  bungeshea Apr 3 '13 at 5:10

9 Answers 9

up vote 26 down vote accepted

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', '\1\2\3', $content);
share|improve this answer
    
Without a doubt, this is the proper answer. Thanks James, I tried it and it works awesomely. –  DigitalSea Feb 3 '11 at 3:25
    
Hi @Dwayne - thanks for the feedback. I've added an improved filter that will handle links, we're now using it on our client site. –  jamesc Feb 4 '11 at 17:29
    
You should definitely put this in the Wordpress plugin repository. A quick google search shows a lot of people are having this problem with no good solution. –  Geoffrey Burdett 2 days ago

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.
share|improve this answer
    
I am going to try this approach. I never thought of actually adding the img tag to the allblocks variable, that's a genius idea. I'll see how I go. –  DigitalSea Jan 17 '11 at 10:51
    
Worked really well Rarst. Thank you for your great help. –  DigitalSea Jan 18 '11 at 2:47
    
Worked well at first, then I hit the scenario when an image is within an anchor tag and both are already inside a paragraph (so p > img > a). With img treated as a block wp-autop closes the paragraph tag out before the img tag starts, busting the layout. –  benz001 Jul 19 at 2:53

maybe this will help

remove_filter('the_content', 'wpautop')

But then you are going to add the paragraphs for everything else manually.

share|improve this answer
    
I considered this approach, but because the layout is eccentric as I said it relies heavily on needing p tags. As I am doing a 2 column text thing where p tags are floated left to give the appearance of 2 columns of text. So you can see why a p tag wrapping an image would be a problem because it's floating that too. –  DigitalSea Jan 17 '11 at 10:49

Soska have given one/easy way.

But what I do is, extract image from content and display it separately.

share|improve this answer
    
I did consider this as well and it is still an option. However because it is only one image to save all of the hassle, I might just use featured post thumbnails instead which would let me control how the image displays. –  DigitalSea Jan 17 '11 at 10:52
    
also you can add custom field to the post/page, like thumb image and save the image path in its value... –  Avinash Jan 17 '11 at 11:09

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.

share|improve this answer
1  
Do you really use curly quotes? :) –  toscho Feb 18 '13 at 19:05
    
I did consider this approach first way back when, but the thought of unnecessary DOM manipulation via jQuery was too much of a risk and potential unneeded overhead when you can do this in PHP with tricky regular expressions. –  DigitalSea Feb 19 '13 at 23:29

Depending on the post, another solution could be to use the WP Unformatted plugin to disable the auto-p function on a per post basis.

share|improve this answer
    
That's pretty useful, although the only caveat I can see is that if you want images to not have P tags but also have text within your page, it's going to be one massive mess. This would probably be good for posts that just have images and maybe a few lines of text. Still, useful. –  DigitalSea Feb 23 '11 at 1:59
    
Yup, that’s why I said it depends on the post. –  Synetech Feb 23 '11 at 2:48

This post is a little old, but there is a much simpler solution, barring CSS on your end.

Wrapping the img tag in a div has little negative effect.

share|improve this answer

I developed a plugin that fixed this exact issue: http://wordpress.org/extend/plugins/unwrap-images/

It's better than setting margin, or diving right into the Wordpress code for those who don't want to mess with code because it uses jQuery's native unwrap function to unwrap all images of their p tags.

Hope this helps someone! Cheers, Brian

share|improve this answer

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 />|', "\n\n", $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 . '>)!', "$1\n\n", $pee);
$pee = str_replace(array("\r\n", "\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("/\n\n+/", "\n\n", $pee); // take care of duplicates
// make paragraphs, including one at the end
$pees = preg_split('/\n\s*\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!

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.