How to add links to WordPress image captions

The WordPress media manager allows you to add captions to your images, which can be inserted into your post content wrapped in the caption shortcode.

You can see that I’ve placed anchor tags in the photo caption to link to the photo credit:

Photo credit: <a href="http://www.flickr.com/photos/nattu/2735064420">nattu</a></code>

When you click the “Insert into Post” button, you end up with this markup in your editor:

[ caption id="attachment_1133" align="alignleft" width="300" 
caption="Photo credit: <a href=&quot;http://www.flickr.com/photos/nattu/2735064420&quot;&gt;nattu&lt;/a&gt;"]
<a data-rel="prettyPhoto" title="The Entrance" href="http://localhost/agility/wp-content/uploads/2012/03/TheEntrance.jpg">
<img src="http://localhost/agility/wp-content/uploads/2012/03/TheEntrance-300x199.jpg" alt="" title="The Entrance" width="300" height="199" class="scale-with-grid size-medium wp-image-1133" /></a>[/caption]

Skip to the code solution

The Problem

The issue is that all the HTML entities in the caption attribute (specifically, the anchor tags) are encoded. That is, instead of

Photo credit: <a href="http://www.flickr.com/photos/nattu/2735064420">nattu</a>

we have

Photo credit: &lt;a href=&quot;http://www.flickr.com/photos/nattu/2735064420&quot;&gt;nattu&lt;/a&gt;

As a result, instead of getting the desired output in our caption:

Photo credit: <a href="http://www.flickr.com/photos/nattu/2735064420">nattu</a>

We get the encoded HTML markup instead:

Photo credit: &lt;a href=&quot;http://www.flickr.com/photos/nattu/2735064420&quot;&gt;nattu&lt;/a&gt;

The Solution

Now, the HTML entities have to be escaped in order to safely place them in the caption=”” attribute of the caption shortcode (or at least the double quotes do), and in any event it’s very inconvenient to decode the entities manually. What we’ll need to do is decode them programmatically when the shortcode is processed at run time.

Helpfully, WordPress’s img_caption_shortcode function (wp-includes/media.php) includes a filter that allows us to hook in and override the caption. Here’s the original function:

/**
 * The Caption shortcode.
 *
 * Allows a plugin to replace the content that would otherwise be returned. The
 * filter is 'img_caption_shortcode' and passes an empty string, the attr
 * parameter and the content parameter values.
 *
 * The supported attributes for the shortcode are 'id', 'align', 'width', and
 * 'caption'.
 *
 * @since 2.6.0
 *
 * @param array $attr Attributes attributed to the shortcode.
 * @param string $content Optional. Shortcode content.
 * @return string
 */
function img_caption_shortcode($attr, $content = null) {

	// Allow plugins/themes to override the default caption template.
	$output = apply_filters('img_caption_shortcode', '', $attr, $content);
	if ( $output != '' )
		return $output;

	extract(shortcode_atts(array(
		'id'	=> '',
		'align'	=> 'alignnone',
		'width'	=> '',
		'caption' => ''
	), $attr));

	if ( 1 > (int) $width || empty($caption) )
		return $content;

	if ( $id ) $id = 'id="' . esc_attr($id) . '" ';

	return '<div ' . $id . 'class="wp-caption ' . esc_attr($align) . '" style="width: ' . (10 + (int) $width) . 'px">'
	. do_shortcode( $content ) . '<p class="wp-caption-text">' . $caption . '</p></div>';
}

add_shortcode('gallery', 'gallery_shortcode');

We’re just going to hook in and use the same code, but add a line of our own to decode the HTML tags.

$caption = html_entity_decode( $caption );

The Code

So, our final function, which I’ve placed in functions.php, looks like this:

//Our custom caption shortcode function is based on the WordPress Core version with a small change
function custom_img_caption_shortcode( $a , $attr, $content = null) {

	extract(shortcode_atts(array(
		'id'	=> '',
		'align'	=> 'alignnone',
		'width'	=> '',
		'caption' => ''
	), $attr));

	if ( 1 > (int) $width || empty($caption) )
		return $content;

	$caption = html_entity_decode( $caption );  //Here's our new line to decode the html tags

	if ( $id ) $id = 'id="' . esc_attr($id) . '" ';

	return '<div ' . $id . 'class="wp-caption ' . esc_attr($align) . '" style="width: ' . (10 + (int) $width) . 'px">'
	. do_shortcode( $content ) . '<p class="wp-caption-text">' . $caption . '</p></div>';
}
//Add the filter to override the standard shortcode
add_filter( 'img_caption_shortcode', 'custom_img_caption_shortcode', 10, 3 );

And that’s it! Just pop that code into your functions.php and you should be able to add links to your photo captions. If anyone knows a better way of doing this, let me know in the comments. Enjoy!

4 thoughts on “How to add links to WordPress image captions

    • I am kind of stuck on this as well. I need the description only for an image glelary and then use the attachments to the page to actually describe the galleries. Like a short code for a glelary, puts the id’s of each image, and then it grabs the description and title for them.

  1. I put the final code in my functions file, and did a test caption with a link. It looked perfect until I saved the page with them image – and then everything stripped back out. I didn’t get the encoded version, I just ended up with the text only – all the anchor tag information stripped out.

    Do I still need to escape the double quotes in the caption field?

    I’m using iThemes Builder with a child theme, if that affects this solution.

    • Great function. I’m in a siiatuton where I need to add the description to old content where images are already embedded. Anyway to get the image description to show up on the edit image popup? For some reason it’s different than the add image pop up.

Comments are closed.