10

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

8

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
    Commented Aug 31, 2013 at 11:01
  • 2
    As of v4.7, there is a filter. See Shawn H's answer below. Commented Jan 12, 2017 at 1:41
29

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

Your Answer

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

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