2

Captions in wordpress do not support nested shortcodes at the moment (v3.6). So, If I do write

[caption]<img src=""> I love my [city][/caption]

Where city is suppose to be processed but it does not. How do I fix this?

Ticket: #24990

3 Answers 3

3

There is a hook inside the caption shortcode that will allow you to hijack the whole thing. Most of the following is copied from the Core img_caption_shortcode function.

function nested_img_caption_shortcode($nada, $attr, $content = null) {

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

  $caption = do_shortcode($caption); // process nested shortcodes

  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_filter('img_caption_shortcode', 'nested_img_caption_shortcode', 1, 3);
2
  • This is now overkill because we can use the 'shortcode_atts_caption' filter to directly alter it's attributes during shortcode_atts().
    – jerclarke
    Apr 21, 2015 at 16:55
  • Much better not to use a function that replaces the whole function, since that means your clone doesn't get updated with WP and falls behind (e.g. my old copy made this way didn't have the new filters added in 4.1 that I use in my answer :)
    – jerclarke
    Apr 21, 2015 at 17:07
4

The latest versions of WP have really improved the filterability of caption arguments, so I think this new answer will have the smallest footprint and safest operation.

What we need to do is directly filter $atts['caption'] during shortcode_atts() for the [caption] shortcode. We can do this with the shortcode_atts_caption filter which only affects the caption shortcode.

As a bonus I added a commented-out line that will test the caption for a specific shortcode before running do_shortcode(). This is useful if you only want to enable a particular shortcode in captions (I use it to enable only the Shortcode Shortcode). Careful though: do_shortcode() will process all shortcodes, not just the one you tested for.

/**
 * Filter Caption shortcode attributes to enable the [shortcode] shortcode inside caption text
 * 
 * WP doesn't run do_shortcode on the 'caption' text value parsed out of [caption], which means
 * the [shortcode] shortcode doesn't work. 
 * 
 * @param array $out atts array as determined by WP to be returned after filtering
 * @param array $pairs 
 * @param array $atts
 * @return filtered $out atts
 */
 function wpse_113416_filter_shortcode_atts_caption($out, $pairs, $atts) {
    // OPTIONAL: Look for a specific shortcode before running do_shortcode
    // if (has_shortcode($out['caption'], 'shortcode_to_look_for')) 
        $out['caption'] = do_shortcode($out['caption']);

    return $out;
}
add_filter('shortcode_atts_caption', 'wpse_113416_filter_shortcode_atts_caption', 10, 3);
2

Using latest function has_shortcode() introduced on v3.6

add_filter( 'the_content', 'process_wp_caption_shortcodes' ); // hook it late

    function process_wp_caption_shortcodes( $content ){
        if( !function_exists    ( 'has_shortcode' ) )   // no luck for user using older versions :)
            return $content;

        if( has_shortcode( get_the_content(), 'caption' ) ){ // check with raw content
            // caption exists on the current post
            $content = do_shortcode( $content );
        }

        return $content;
    }

This solution can be used on any third party shotcode that didn't implemented nested shortcode support.

Any better solution welcomed!

1
  • 1
    For previous version has_shortcode function can be defined coping code from v3.6 wrapping it with if (! function_exists('has_shortcode') ) {
    – gmazzap
    Sep 8, 2013 at 19:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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