1

I'm defining a function which can handle shortcodes for users wisiwyg made posts.

Using a function based on preg_replace_callback works great, but the returned replaced values prints before the initial string

This is the handler function

function shortcodify($string){
    return preg_replace_callback('#\[\[(.*?)\]\]#', function($matches){
        $parts = explode(':',$matches[1]);
        $fnName = array_shift($parts);
        if(function_exists($fnName)){
            return call_user_func_array($fnName,$parts);
        } else {
            return $matches[0];
        }
    },$string);
}

This is the function which will replace the shortcode

function slider($tag){
    //search $tag in DB
    echo '<div>...'.$sliderContentFromDB.'...</div>';
}

The usage:

$postContent = "<h1>Super Slider</h1> [[slider:super-slider]] <p>Slider Description</p>";
shortcodify($postContent);

The expected result is:

<h1>Super Slider</h1>
<div>...super slider content...</div>
<p>Slider Description</p>

The actual result is:

<div>...super slider content...</div>
<h1>Super Slider</h1>
<p>Slider Description</p>

What could I be doing wrong?

3
  • 2
    You have to remember content is a collection of shortcodes (think of it as an array) so you don't output the full content until after you loop through the array, so when you echo from the loop (from slider called by the loop) the output comes out first. Commented Jan 11, 2019 at 17:13
  • indeed it has more sense Commented Jan 11, 2019 at 17:16
  • One trick is to use ob_start() and ob_get_clean() then you can echo from the shortcodes but still capture the output in the callback Commented Jan 11, 2019 at 17:16

2 Answers 2

3

You should return the value rather than echoing it. What you're seeing is correct, in that the callback function should evaluate before the preg_replace_callback() result is returned to your variable.

function slider($tag){
    //search $tag in DB
    return '<div>...'.$sliderContentFromDB.'...</div>';
}

Returning will ensure it gets aggregated into the rest the results from preg_replace_callback(), and returned in the correct order. Example.

Sign up to request clarification or add additional context in comments.

6 Comments

Bit of a side note: Adding \n will produce nicely formatted rendered HTML (source), rather than having it all on the one line; just saying.
@FunkFortyNiner you are right, just doing that way for demo purposes
Yes, I know Robbie :)
Do you? Haha! :-D
I figured- made me laugh though
|
1

This is how I would do it:

function shortcodify($string){
    return preg_replace_callback('#\[\[(.*?)\]\]#', function($matches){
        //start output buffering
        ob_start();
        $parts = explode(':',$matches[1]);
        $fnName = array_shift($parts);

        //echo values in case they return instead of echo
        if(function_exists($fnName)){
            echo call_user_func_array($fnName,$parts);
        } else {
            echo $matches[0];
        }
        //return contents of buffer
        return ob_get_clean();
    },$string);
}

Now if you return or echo from the shortcode it makes no difference, because in either case it will get swept up by the buffer.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.