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. 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
  • 4
    +1 for this solution as it now supersedes the accepted answer. It would be nice if you could edit your answer and give a small example how to use. The filter parameters are not obvious. Commented Jan 13, 2017 at 13:23
  • 3
    For completeness' sake: developer.wordpress.org/reference/hooks/do_shortcode_tag Commented Feb 3, 2017 at 10:44
  • 1
    More completeness! developer.wordpress.org/reference/hooks/pre_do_shortcode_tag Commented Feb 3, 2017 at 10:48
  • At last, waited years for this kind of implementation. Wp should always apply this kind of filters before render. An example to remove tabbed indents from the sourcecode: function example_shortcode_output($output, $tag, $attr, $m){ if($tag == 'gallery') $output = str_replace("\t", '', $output); return $output; } add_filter('do_shortcode_tag', 'example_shortcode_output', 10, 4); Commented Jun 12, 2018 at 11:55
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.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.