Another Look at Rebuilding Image Tags

In a blog post I wrote last month, “Rebuilding Image Tags When Adding Media”, I discussed a technique that builds image tags instead of removing attributes that are undesirable. As it becomes more popular, a lot of web designers are going to want to incorporate Responsive Web Design, and removing an image’s width or height attribute may be essential.

There was a problem with my proposed code. If the image was sent to the editor inside an anchor or had a caption, and if using the visual editor, the caption would disappear on save, or the undesired attributes would not be removed. Unpredictable behavior would also occur when switching between the visual and text tabs. This is really not acceptable for the majority of WordPress users, so I thought I better try to figure out a better way to handle removing the width and height attributes of images.

The Best Solution

The best solution for removing width and height attributes would be if WordPress had this option built in to it’s Insert Media modal. Until then, we are going to have to remove width and height attributes on our own. I’ve got a decent solution, which completes the task and retains all the basic functionality for using captions. WordPress will filter out the unwanted attributes, but you’re going to need to cope with those attributes being in your editor as your writing them.

My New Solution

/**
 * Rebuild the image tag with only the stuff I want
 */
class bwd_img_rebuilder
{
  public $caption_class   = 'wp-caption';
  public $caption_p_class = 'wp-caption-text';
  public $caption_id_attr = FALSE;
  public $caption_padding = 8; // Double of the padding on $caption_class

  public function __construct()
  {
    add_filter( 'img_caption_shortcode', array( $this, 'img_caption_shortcode' ), 1, 3 );
    add_filter( 'get_avatar', array( $this, 'recreate_img_tag' ) );
    add_filter( 'the_content', array( $this, 'the_content') );
  }

  public function recreate_img_tag( $tag )
  {
    // Supress SimpleXML errors
    libxml_use_internal_errors( TRUE );

    try
    {
      $x = new SimpleXMLElement( $tag );

      // We only want to rebuild img tags
      if( $x->getName() == 'img' )
      {
        // Get the attributes I'll use in the new tag
        $alt        = (string) $x->attributes()->alt;
        $src        = (string) $x->attributes()->src;
        $classes    = (string) $x->attributes()->class;
        $class_segs = explode(' ', $classes);

        // All images have a source
        $img = '<img src="' . $src . '"';

        // If alt not empty, add it
        if( ! empty( $alt ) )
        {
          $img .= ' alt="' . $alt . '"';
        }

        // Only alignment classes are allowed
        $allowed_classes = array( 
          'alignleft', 
          'alignright', 
          'alignnone', 
          'aligncenter' 
        );

        if( in_array( $class_segs[0], $allowed_classes ) )
        {
          $img .= ' class="' . $class_segs[0] . '"';
        }

        // Finish up the img tag
        $img .= ' />';

        return $img; 
      }
    }
    catch ( Exception $e ){}

    // Tag not an img, so just return it untouched
    return $tag;
  }

  /**
   * Search post content for images to rebuild
   */
  public function the_content( $html )
  {
    return preg_replace_callback( 
      '|(<img.*/>)|', 
      array( $this, 'the_content_callback' ), 
      $html 
    );
  }

  /**
   * Rebuild an image in post content
   */
  private function the_content_callback( $match )
  {
    return $this->recreate_img_tag( $match[0] );
  }

  /**
   * Customize caption shortcode
   */
  public function img_caption_shortcode( $output, $attr, $content )
  {
    // Not for feed
    if ( is_feed() )
      return $output;

    // Set up shortcode atts
    $attr = shortcode_atts( array(	      
	  'align'   => 'alignnone',	      
	  'caption' => '',
      'width'   => ''
    ), $attr );

    // Add id and classes to caption
    $attributes = '';

    if( $caption_id_attr && ! empty( $attr['id'] ) )
    {
      $attributes .= ' id="' . esc_attr( $attr['id'] ) . '"';
    }

    $attributes .= ' class="' . $this->caption_class . ' ' . esc_attr( $attr['align'] ) . '"';

    // Set the max-width of the caption
    $attributes .= ' style="max-width:' . ( $attr['width'] + $this->caption_padding ) . 'px;"';

    // Create caption HTML
    $output = '
      <div' . $attributes .'>' . 
        do_shortcode( $content ) . 
        '<p class="' . $this->caption_p_class . '">' . $attr['caption'] . '</p>' . 
      '</div>
    ';

    return $output;
  }
}

$bwd_img_rebuilder = new bwd_img_rebuilder;

// -----------------------------------------------------------------------

This code above goes in your theme’s functions.php file. If you use it without modification, it will do some things you might not expect:

  1. Images will only have alt, src and class attributes. A class attribute is only added for alignment. If you use some of the other CSS classes that WordPress adds to the class attribute, you will have to modify my code.
  2. Avatar images will only have a src attribute. I didn’t really see the need to build up avatar img tags with anything else.
  3. Captions do not have an id attribute. I don’t know about you, but I would generally never need to target a caption by id. If you really needthe id attribute, set $caption_id_attr to TRUE at the top of the class.
  4. Captions have a max-width applied that is 8px wider than the image is wide. This coincides with the padding I set in my CSS (shown below). If you change the caption’s padding in the CSS, you’ll also need to change the value of $caption_padding at the top of the class.

CSS For The Caption Width

skunkbad
Yours Truly

Because I wanted all of my captions to look similar to the standard WordPress caption, but I also needed it to be a flexible width for my responsive web design, I had to come up with some custom CSS to handle the styling.

The styles I have applied are probably close to what you can use in your stylesheet, but the padding of the paragraph may need to be adjusted. My stylesheet sets a 1em bottom padding for all paragraphs, and I didn’t want my caption to have that much padding. I also have a dark theme, so you’ll probably have to play around with the text color, background color, and border color. Another thing to notice is that I’ve set the font size of the caption at 80%. Depending on how you’ve styled the rest of your site, this value may not work for you.

.wp-caption{
  padding:4px;
  border-radius:3px;
  text-align:center;
  background-color:#222;
  border:solid 1px #444;
}

.wp-caption img{
  max-width:100%;
}

p.wp-caption-text{
  font-size:80%;
  padding:.3em 0 .1em 0;
  color:#ccc;
}

Give it a shot and let me know if you have any issues.

9 thoughts on “Another Look at Rebuilding Image Tags”

  • On older posts that use image attachment code this doesn’t seem to have any affect. Is there something that can be changed to also cover these?

    When I use this code:

    add_filter( 'post_thumbnail_html', 'remove_thumbnail_dimensions', 10 );
    add_filter( 'image_send_to_editor', 'remove_thumbnail_dimensions', 10 );
    // Genesis framework only
    add_filter( 'genesis_get_image', 'remove_thumbnail_dimensions', 10 );
    // Removes attached image sizes as well
    add_filter( 'the_content', 'remove_thumbnail_dimensions', 10 );
    function remove_thumbnail_dimensions( $html ) {
        $html = preg_replace( '/(width|height)=\\"\\d*\\"\\s/', "", $html );
        return $html;
    }
    

    from here:
    http://wordpress.stackexchange.com/questions/5568/filter-to-remove-image-dimension-attributes

    then it works with attached images.
    However it affects videos so yours is a lot better but it doesn’t work with some of the older posts that have attachment images. Any idea how I can get this to work and also work with attachment images?

    Thanks, John

    • John, I don’t have any old blog posts to check, so I don’t know what the difference is between the old image attachment code and the newer style. If it were me, I think I”d probably edit the old posts using a find/replace on the SQL itself, rather than try to create code that handles both. I’ll email you so you can send me an example of the old image attachment code, and I’ll try to help you with a solution.

  • Ryan Burnette says:

    I normally don’t make comments when I have nothing pertinent to add … but this is sickkk. Thanks!

  • I tried it but it’s hanging on line 37 !? Not even sure if it’s what need, need something that will strip the dimensions out of linked images?

    Parse error: syntax error, unexpected ” . $src . ” (T_CONSTANT_ENCAPSED_STRING) in …

    php ver 5.5.11

  • Is there a way for $src to return a different image size than what the post started with? For example, if the post originally used the “medium” image file, but I want to change that to the “large” image file via this code.

    • Yes, you would simply specify that image when creating your post. If what you are trying to do is alter the post content for a posts widget, or a custom view of some sort, you would probaby want to handle such changes in a different fashion. What I mean is, it would probably be better to use a featured image or custom field(s). You might even consider creating a custom shortcode with attributes that allow you to show the image in different ways, depending on the view.

Comments are closed.