Filter specific shortcode output?

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.

Related posts

5 comments

  1. 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. 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');
    
  3. 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.

  4. 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

Comments are closed.