9

Is there a hook in WordPress that I can use to filter the output of a specific shortcode? Something like this:

add_filter('shortcode_output', 'my_filter_function', 2);

function my_filter_function ( $output, $shortcode ) {
    ....
}

Where $shortcode would be something like [my_schortcode] or even better, shortcode and its attributes separated into an array.

5 Answers 5

7

There is no filter that I know of that is meant to target individual shortcodes like you want.

You can filter attributes with shortcode_atts_{$shortcode} though.

You can hijack another shortcode by creating your own callback and registering it with the original shortcode slug. I think that is what you are probably going to need to do.

Proof of concept:

function my_gallery_shortcode($atts) {
  return 'howdy';
}
add_shortcode('gallery','my_gallery_shortcode');

Now try to use a gallery :)

2
  • You're right. There is no filter for what I wanted. So instead of that I am filtering the_content. It works for my use-case.
    – ragulka
    Aug 31, 2013 at 11:01
  • 2
    As of v4.7, there is a filter. See Shawn H's answer below. Jan 12, 2017 at 1:41
27

WordPress 4.7 introduced a new filter, do_shortcode_tag, to do exactly this.

4
1

While there is no hook, there is a small workaround that makes your end-goal possible. You can create a new shortcode that, on a per-instance basis, you always wrap around any other shortcode whose output you want to filter.

Usage in a post, etc:

Here is some post text. Blah blah...
[filter][target_annoying_shortcode size="small" limit="20"][/filter] 
Here is some more text in my post. More blah blah...

In functions.php:

function my_shortcode_output_filter( $attr, $content ) {

    // Express the shortcode into its output
    $content_translated = do_shortcode(trim($content));
    if($shortcode_to_modify == $content || !$content_translated) {
        // Error handling
        return 'There was an error in filtering shortcode: '.$content;  
    }

    // Now modify the output as you like, here...

    $content_translated_and_filtered = $content_translated;

    return $content_translated_and_filtered;
 }
 add_shortcode('filter', 'my_shortcode_output_filter');
0

The only thing that you can filter is the attributes fo the shortcode:

apply_filters( "shortcode_atts_{$shortcode}", $out, $pairs, $atts );

Point is, that $shortcode is the third argument when registering a shortcode. This argument is pretty new and nearly no shortcode uses it, therefore it will fall back to the default - which is a string of ''.

This leads to a funny result:

add_filter( 'shortcode_atts_', 'wpse112294_shortcode_atts_cb' );
function wpse112294_shortcode_atts_cb( $out, $pairs, $atts )
{
    // here we need to find a way to uniquely identify a shortcode
    // for which we ain't got a name

    // something that makes the shortcode unique:
    $found = isset( $pairs['foo_attribute_key'] );
    if ( $found )
    {
        // Instantly remove this filter to save processing time:
        remove_filter( current_filter(), __FUNCTION__ );

        // do something stunning in here!
    }

    return $out;
}

So, yes, with a 90% chance we need to filter the output of every(!) shortcode and try to somehow identify the shortcode by either some default arguments ($pairs) or by input arguments (impossible). Then, finally we're able to process the output. Are we able to process the string itself? No. This has to be done the way @s_ha_dum showed above.

0

While @s_ha_dum gave a decent answer, you can create a new shortcode for the purpose of filtering an existing shortcode. For example,

function filter_function($atts, $content) {
    extract(shortcode_atts(array(
            'att1' => 'val1',
            'att2' => 'val2'
    ), $atts));

    //save shortcode output in $return
    $return = do_shortcode("[existing_shortcode att1='$att1' att2='$att2'".$content."/existing_shortcode]");

    //insert code to modify $return

    echo $return;
}
add_shortcode('new_shortcode','filter_function');

note that for the [embed] shortcode, you have to use

global $wp_embed;
$return = $wp_embed->run_shortcode("[embed ...

instead of do_shortcode

This site is temporarily in read-only mode and not accepting new answers.

Not the answer you're looking for? Browse other questions tagged .