How to add links to WordPress image captions

One issue I’ve run into in WordPress is that you can’t add HTML tags, specifically anchors, into your image captions. This tutorial will show you how to insert links into your image captions so you can link back for photo credits, etc.

Written by

Chris Mavricos

Published on

BlogCode · WordPress Tutorials

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!

Chris Mavricos

Hi, I'm Chris. I'm a web developer and founder of SevenSpark located in Boulder, CO. I've been developing websites since 2004, and have extensive experience in WordPress theme, plugin, and custom development over the last 15+ years.