How to render complicated shortcodes

Good to hear that you managed to solve the problem already. Here’s a few examples on how you could also return html from a shortcode.

As you already found out, you can use ob_start() and ob_get_clean() to buffer the html. Inside it you can echo the markup or drop out of PHP and write plain HTML.

function my_shortcode() {
    ob_start();
    echo '<div>some HTML here</div>';
    ?>
    <p>Or outside of the PHP tags</p>
    <?php
    return ob_get_clean();
}

If the shortcode is within a theme, then you could also use get_template_part() with the output buffering. This way you can make the shortcode callback a little cleaner looking as the HTML will find its home in a separate file. You can also pass data to the template part, if needed.

function my_shortcode() {
    $template_part_args = array(
        'key' => 'value',
    );
    
    ob_start();
    get_template_part(
        'path/to/template/part',
        'optional-name', // use null, if not named
        $template_part_args // access with $args in the template part file
    );
    return ob_get_clean();
}

As Rup noted in the comments, one option is to concatenate the html to a string variable and then return that.

function my_shortcode() {
    $output="<div>";
    $output .= 'Some HTML here';
    $output .= '</div>';
    return $output;
}

Personally, I like to use sprintf() for returning in a similar situation. I think it makes the code clean looking and makes adding escaping a breeze.

function my_shortcode() {
    return sprintf(
        '<div>
            <p>%s</p>
            <div>%s</div>
        </div>',
        esc_html('Some HTML here'),
        esc_html('Additional nested HTML')
    );
}

Especially with lists, I tend to build an array of the list items, which are imploded into a string. But you can use the same idea to push various HTML strings into an array, which is turned into one string on output return.

function my_shortcode() {
    $list_items = array();

    foreach ($some_array as $value) {
        $list_items[] = sprintf(
            '<li>%s</li>',
            esc_html($value)
        );
    }

    return '<ul>' . implode('', $list_items) . '</ul>';
}

Leave a Comment