WordPress Shortcodes API Hooks

Filters and actions available in the WordPress Shortcodes API.


Filters

pre_do_shortcode_tag

Short-circuits shortcode processing before the callback is called.

apply_filters( 'pre_do_shortcode_tag', false|string $output, string $tag, array $attr, array $m )

Parameters:

  • $output (false|string) — Return value. false to continue, or string to short-circuit.
  • $tag (string) — Shortcode name
  • $attr (array) — Parsed attributes (always array since 6.5.0)
  • $m (array) — Full regex match array

Returns: false to process normally, or string to replace the shortcode

Since: 4.7.0 (6.5.0: $attr is always array)

Example:

// Cache shortcode output
add_filter( 'pre_do_shortcode_tag', function( $output, $tag, $attr, $m ) {
    if ( 'expensive_shortcode' !== $tag ) {
        return false; // Not our shortcode, continue normally
    }
    
    $cache_key = 'shortcode_' . md5( serialize( $attr ) );
    $cached = wp_cache_get( $cache_key );
    
    if ( false !== $cached ) {
        return $cached; // Return cached output
    }
    
    return false; // Not cached, process normally
}, 10, 4 );

do_shortcode_tag

Filters the output after a shortcode callback executes.

apply_filters( 'do_shortcode_tag', string $output, string $tag, array $attr, array $m )

Parameters:

  • $output (string) — Shortcode output from callback
  • $tag (string) — Shortcode name
  • $attr (array) — Parsed attributes (always array since 6.5.0)
  • $m (array) — Full regex match array

Returns: Modified output string

Since: 4.7.0 (6.5.0: $attr is always array)

Example:

// Wrap all shortcode output in a container
add_filter( 'do_shortcode_tag', function( $output, $tag ) {
    return '<div class="shortcode-wrapper shortcode-' . esc_attr( $tag ) . '">' 
           . $output 
           . '</div>';
}, 10, 2 );
// Cache shortcode output after processing
add_filter( 'do_shortcode_tag', function( $output, $tag, $attr ) {
    if ( 'expensive_shortcode' !== $tag ) {
        return $output;
    }
    
    $cache_key = 'shortcode_' . md5( serialize( $attr ) );
    wp_cache_set( $cache_key, $output, '', HOUR_IN_SECONDS );
    
    return $output;
}, 10, 3 );

shortcode_atts_{$shortcode}

Filters the merged shortcode attributes for a specific shortcode.

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

Parameters:

  • $out (array) — Merged attributes (defaults + user values)
  • $pairs (array) — Original defaults
  • $atts (array) — User-provided attributes
  • $shortcode (string) — Shortcode name

Returns: Modified attributes array

Since: 3.6.0 (4.4.0: added $shortcode parameter)

Dynamic Hook: The hook name includes the shortcode name. For , the hook is shortcode_atts_gallery.

Example:

// Force gallery to always show 4 columns
add_filter( 'shortcode_atts_gallery', function( $out, $pairs, $atts ) {
    $out['columns'] = 4;
    return $out;
}, 10, 3 );
// Add custom attribute support to existing shortcode
add_filter( 'shortcode_atts_audio', function( $out, $pairs, $atts ) {
    // Allow a custom 'theme' attribute
    $out['theme'] = isset( $atts['theme'] ) ? $atts['theme'] : 'default';
    return $out;
}, 10, 3 );

Note: This filter only fires if the shortcode callback passes the third parameter to shortcode_atts():

// This enables the filter:
$atts = shortcode_atts( $defaults, $atts, 'my_shortcode' );

// This does NOT enable the filter:
$atts = shortcode_atts( $defaults, $atts );

strip_shortcodes_tagnames

Filters which shortcode tags are stripped by strip_shortcodes().

apply_filters( 'strip_shortcodes_tagnames', string[] $tags_to_remove, string $content )

Parameters:

  • $tags_to_remove (string[]) — Array of shortcode tag names to strip
  • $content (string) — Content being processed

Returns: Modified array of tag names

Since: 4.7.0

Example:

// Preserve gallery shortcodes when stripping
add_filter( 'strip_shortcodes_tagnames', function( $tags ) {
    $key = array_search( 'gallery', $tags, true );
    if ( false !== $key ) {
        unset( $tags[ $key ] );
    }
    return $tags;
} );
// Only strip specific shortcodes
add_filter( 'strip_shortcodes_tagnames', function( $tags, $content ) {
    // Only strip embed and video shortcodes
    return array_intersect( $tags, [ 'embed', 'video', 'audio' ] );
}, 10, 2 );

wp_get_attachment_image_context

Filters the context when getting attachment images during shortcode processing.

apply_filters( 'wp_get_attachment_image_context', string $context )

Parameters:

  • $context (string) — Current context

Returns: Modified context string

Since: 6.3.0

Shortcode Value: During do_shortcode(), this filter returns 'do_shortcode'.

Purpose: Allows themes and plugins to detect when wp_get_attachment_image() is called from within a shortcode versus template code.

Example:

add_filter( 'wp_get_attachment_image_attributes', function( $attr, $attachment, $size ) {
    // Check if we're in a shortcode context
    if ( 'do_shortcode' === apply_filters( 'wp_get_attachment_image_context', '' ) ) {
        // Add lazy loading only for shortcode images
        $attr['loading'] = 'lazy';
    }
    return $attr;
}, 10, 3 );

Hook Quick Reference

Hook Type Purpose Since
pre_do_shortcode_tag Filter Short-circuit before callback 4.7.0
do_shortcode_tag Filter Modify output after callback 4.7.0
shortcode_atts_{$shortcode} Filter Modify merged attributes 3.6.0
strip_shortcodes_tagnames Filter Control which tags are stripped 4.7.0

Usage Patterns

Caching Pattern

Complete caching implementation using both pre and post filters:

class Shortcode_Cache {
    
    private static $cache_group = 'shortcodes';
    
    public static function init() {
        add_filter( 'pre_do_shortcode_tag', [ __CLASS__, 'get_cache' ], 10, 4 );
        add_filter( 'do_shortcode_tag', [ __CLASS__, 'set_cache' ], 10, 4 );
    }
    
    public static function get_cache( $output, $tag, $attr, $m ) {
        if ( ! self::should_cache( $tag ) ) {
            return false;
        }
        
        $cached = wp_cache_get( self::cache_key( $tag, $attr ), self::$cache_group );
        return ( false !== $cached ) ? $cached : false;
    }
    
    public static function set_cache( $output, $tag, $attr, $m ) {
        if ( self::should_cache( $tag ) ) {
            wp_cache_set( 
                self::cache_key( $tag, $attr ), 
                $output, 
                self::$cache_group, 
                HOUR_IN_SECONDS 
            );
        }
        return $output;
    }
    
    private static function should_cache( $tag ) {
        return in_array( $tag, [ 'gallery', 'playlist', 'embed' ], true );
    }
    
    private static function cache_key( $tag, $attr ) {
        return $tag . '_' . md5( serialize( $attr ) );
    }
}

Shortcode_Cache::init();

Debugging Pattern

Log all shortcode processing for debugging:

add_filter( 'do_shortcode_tag', function( $output, $tag, $attr, $m ) {
    if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
        error_log( sprintf(
            'Shortcode [%s] processed with attributes: %s',
            $tag,
            wp_json_encode( $attr )
        ) );
    }
    return $output;
}, 10, 4 );

Security Pattern

Block specific shortcodes for certain user roles:

add_filter( 'pre_do_shortcode_tag', function( $output, $tag, $attr, $m ) {
    $restricted = [ 'code', 'script', 'include' ];
    
    if ( in_array( $tag, $restricted, true ) && ! current_user_can( 'unfiltered_html' ) ) {
        return '<!-- shortcode restricted -->';
    }
    
    return false;
}, 10, 4 );

Attribute Extension Pattern

Add custom attributes to core shortcodes:

// Add 'lightbox' attribute to gallery
add_filter( 'shortcode_atts_gallery', function( $out, $pairs, $atts ) {
    $out['lightbox'] = isset( $atts['lightbox'] ) ? $atts['lightbox'] : 'true';
    return $out;
}, 10, 3 );

// Then in your gallery output filter:
add_filter( 'post_gallery', function( $output, $attr, $instance ) {
    if ( 'true' === $attr['lightbox'] ) {
        // Add lightbox wrapper
        $output = '<div class="lightbox-gallery">' . $output . '</div>';
    }
    return $output;
}, 10, 3 );