I was wondering if someone could point me in the right direction for cleaning up this code.

WordPress uses shortcodes in the form [shortcode] to add extended functionality to posts and pages.

What I am trying to do is to return a string with all of the 'stray' brackets, ones not being used by any of shortcodes, as html entities.

What I have to work with are these variables via WordPress:

  • $shortcode_tags: an array of all shortcodes as strings (without brackets)
  • get_shortcode_regex(): combines all registered shortcode tags into a single regular expression. (I am not using this in the code below)

function find_stray_brackets ($content) {
// this code repalces all occurences of every shortcode with special brackets.
// It then replaces remaining 'stray' brackets with the HTML character entitiy.

        global shortcode_tags;
        foreach($shortcode_tags as $k=>$item)





The approach is to replace all of the brackets that surround shortcodes with special characters-> replace stray brackets with html entities -> re-insert original brackets

My end goal is to put all of the text between short codes (including before the first and after the last shortcode) into an array. I couldn't get the regex that Wordpress produces to do what I wanted, so wrote my own regex that relies on brackets - this is why I need to deal with the strays.

Here is the regex that WordPress outputs and some sample text with nested shortcodes.

  • \$\begingroup\$ I found a solution for what I was trying to do. I ended up creating my own regex like before, however using the list of shortcodes that WordPress provides - one that would only select the shortcodes themseleves, then split everything in between the brackets into an array. This dealt with the stray brackets, and cumbersome replacement schemes. \$\endgroup\$
    – gregpress
    Nov 19 '14 at 1:13

You can simplify and improve this part:

$pattern = '/\[('.$k.'.*?(?=\]))\]/';
$content = preg_replace($pattern,'*{*$1*}*',$content);
$pattern = '/\[\/('.$k.'.*?(?=\]))\]/';
$content = preg_replace($pattern,'*{*/$1*}*',$content);

Instead of using two replacements for [k] and [/k], you can add the /? inside the capture group and use a single replacement:

$pattern = '/\[(\/?'.$k.'.*?(?=\]))\]/';
$content = preg_replace($pattern,'*{*$1*}*',$content);

This regex can be still improved. Is the positive look-ahead really necessary? It seems to me that this should do the job just as well:

$pattern = '/\[(\/?'.$k.'.*?)\]/';

On the other hand, this is not very strict. For example, if you have shortcode gallery, then [galleryzzz] will also match and not be treated as "stray brackets". Maybe that's fine with you, but in any case, it's easy to prevent that by adding a zero-width word boundary check:

$pattern = '/\[(\/?'.$k.'\b.*?)\]/';
  • \$\begingroup\$ Thanks! combining the regex with \/? makes a lot of sense. The positive look ahead is important because sometimes shortcodes include attributes - for example 'column' needs to catch [column width=1/2]. You are right that this is not very strict. I am not a huge fan of the replacement scheme, that is relying on a separator character - seems kludgy and as well is not strict. \$\endgroup\$
    – gregpress
    Nov 16 '14 at 19:53
  • \$\begingroup\$ I asked about the look-ahead, because it seems it should work without it, even for shortcodes that include attributes \$\endgroup\$
    – janos
    Nov 16 '14 at 19:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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