Search code examples
phppreg-replace-callback

Using preg_replace_callback with shortcodes


I'm trying to implement short codes on my website to make publishing easier. What i got so far look like this:

$text = "[button]Hello[button] [input]holololo[input]";
$shortcodes = Array( 'button' => '<button>{content}</button>', 'input' => '<input type="text" value="{content}" />' );
$text = preg_replace_callback('(\[([a-z]+?)\](.+?)\[\\\1\])', function ($matches){ 
   if ($shortcodes[$matches[1]]){ 
            return str_replace('{content}', $matches[2], $shortcodes[$matches[1]]); 
   }else{
     return $matches[0]; 
   } 
}, $text);
echo $text;

What i want this to echo is: <button>Hello</button> <input type="text" value="holololo" />

But instead it just echo's out: [button]Hello[button] [input]holololo[input]

What am I doing wrong?


Solution

  • Two things. First, your regex is like this:

    '(\[([a-z]+?)\](.+?)\[\\\1\])'
    

    You don't want to escape the slash before the 1, otherwise you are literally searching for "\1" rather than the backreference. So that should be:

    '(\[([a-z]+?)\](.+?)\[\1\])'
    

    Also:

    function ($matches) { 
    

    You try to refer to $shortcodes in your function. However, that is defined outside the function, so it has no access to it. You must explicitly pass any non-global variables to a function. When dealing with an anonymous function like this, use the use instruction, so your function definition should look like this:

    function ($matches) use ($shortcodes) {
    

    Making those two simple changes gave me this output:

    <button>Hello</button>
    <input type="text" value="holololo">