Are shortcodes case-sensitive?

If I write a plugin and register a shortcode using this code:

add_shortcode('footag', 'footag_func');

and a user uses this in their post:

Read More
[FOOTAG]

Is it supposed to work?

Related posts

1 comment

  1. Short Answer

    Yes, shortcodes are case sensitive

    Longer Answer

    It’s really easy to build a test case for this and see.

    <?php
    add_shortcode('sOme_ShOrTcOdE', 'wpse102375_shortcode');
    function wpse102375_shortcode($args, $content=null)
    {
        return 'yep';
    }
    

    Longest Answer

    Read the source.

    The “magic” with shortcodes happens in do_shortcode, so let’s take a look at that.

    <?php
    // wp-includes/shortcode.php
    function do_shortcode($content) {
        global $shortcode_tags;
    
        if (empty($shortcode_tags) || !is_array($shortcode_tags))
            return $content;
    
        $pattern = get_shortcode_regex();
        return preg_replace_callback( "/$pattern/s", 'do_shortcode_tag', $content );
    }
    

    Hmmm, $shortcode_tags — probably get’s set up in add_shortcode:

    <?php
    // wp-includes/shortcodes.php
    function add_shortcode($tag, $func) {
        global $shortcode_tags;
    
        if ( is_callable($func) )
            $shortcode_tags[$tag] = $func;
    }
    

    So that’s just a key value part of $shortcode_name => $a_callablle. Makes sense.

    Looks like most of the magic of do_shortcode takes place in building the regular expression to match shortcodes themselves. All that happens in get_shortcode_regex, so let’s take a look there:

    <?php
    // wp-includes/shortcode.php
    function get_shortcode_regex() {
        global $shortcode_tags;
        $tagnames = array_keys($shortcode_tags);
        $tagregexp = join( '|', array_map('preg_quote', $tagnames) );
    
        // WARNING! Do not change this regex without changing do_shortcode_tag() and strip_shortcode_tag()
        // Also, see shortcode_unautop() and shortcode.js.
        return
              '\['                              // Opening bracket
            . '(\[?)'                           // 1: Optional second opening bracket for escaping shortcodes: [[tag]]
            . "($tagregexp)"                     // 2: Shortcode name
            . '(?![\w-])'                       // Not followed by word character or hyphen
            . '('                                // 3: Unroll the loop: Inside the opening shortcode tag
            .     '[^\]\/]*'                   // Not a closing bracket or forward slash
            .     '(?:'
            .         '\/(?!\])'               // A forward slash not followed by a closing bracket
            .         '[^\]\/]*'               // Not a closing bracket or forward slash
            .     ')*?'
            . ')'
            . '(?:'
            .     '(\/)'                        // 4: Self closing tag ...
            .     '\]'                          // ... and closing bracket
            . '|'
            .     '\]'                          // Closing bracket
            .     '(?:'
            .         '('                        // 5: Unroll the loop: Optionally, anything between the opening and closing shortcode tags
            .             '[^\[]*+'             // Not an opening bracket
            .             '(?:'
            .                 '\[(?!\/\2\])' // An opening bracket not followed by the closing shortcode tag
            .                 '[^\[]*+'         // Not an opening bracket
            .             ')*+'
            .         ')'
            .         '\[\/\2\]'             // Closing shortcode tag
            .     ')?'
            . ')'
            . '(\]?)';                          // 6: Optional second closing brocket for escaping shortcodes: [[tag]]
    }
    

    Very well commented in the core, so not much to explain here. The key part is here:

    global $shortcode_tags;
    $tagnames = array_keys($shortcode_tags);
    $tagregexp = join( '|', array_map('preg_quote', $tagnames) );
    

    Which essentially will get used later to explicitly match any of the registered shortcode names. Notice that no text processing is done other than preg_quote, so WP will only try to match the explicit values passed in to add_shortcode as the shortcode name. It’s looking like shortcodes are case sensitive so far.

    Next we need to take a look at the flags where the regular expression built in get_shortcode_regex is used. The relevant bit of do_shortcode.

    "/$pattern/s"
    

    The slashes delimit the regular expression, letters after the closing slash are PRCE flags or modifiers.

    If we saw an i there it would be case insensitive. We only have an s (meaning a . matches all characters including the newline).

    So, yes, shortcodes are case sensitive.

Comments are closed.