1

I hope you all having a great day. I'm developing a video player plugin with custom shortcodes and stuff but I'm having a problem with the shortcode render. Currently, my shortcode content is rendered with echo which works fine but it doesn't render inside the page content so I have to change it to return method somehow but it has foreach loops and if else statements inside it so I can't just do return '<ul> '.foreach($x as $s){}.' </ul> '; and stuff, do you guys know a workaround for this? I've also tried to place everything inside a function and tried to render it inside return like this: return ' '.renderdata().' '; which works but again it doesn't render inside the content.

Here's my complete shortcode function

function vc_playlist_shortcode( $atts = array() ) {

    // add_action('wp_head', 'deregister_scripts');
    // add_action('wp_enqueue_scripts', 'deregister_scripts');
    // add_action('wp_footer', 'deregister_scripts');
   
    // get the shortcode attribute value
    extract(shortcode_atts(array(
     'id' => ''
    ), $atts));

    $playlistdata = get_post_meta( $id, 'vc_playlist_data', true );
    

    // Filter the urls in playlist data and assign it to an array
    $playlisturls = array_filter($playlistdata, function($val){
        return filter_var($val, FILTER_VALIDATE_URL);  
    });
    // rebase the assigned array
    $counter = 0;
    $rebasedurls = array();

    foreach ($playlisturls as $key => $value) {
        $rebasedurls[$counter] = $value;
        $counter++;
    }
    // trim the 'https://vimeo.com/' from the values and keep the ID only
    //$videoIDs = preg_replace('/[^0-9]/', '', $rebasedurls);

   
    function videostatuschecker($x){
        $unlockedvideos = get_user_meta(wp_get_current_user()->ID, 'vc_unlocked_videos', false);

        if (in_array($x, $unlockedvideos)){
            return 'unlocked';  
        }
        else{
            return 'locked';
        }
    }
    // Serve the first video URL to browser so we can access it in our JS function
    echo '<script type="text/javascript">var vc_firstvideo = "'.$rebasedurls[0].'"</script>';
    
    echo '<div class="vc-video-container">';
    //echo '<div class="vc-plyr" data-plyr-provider="vimeo" data-plyr-embed-id="'.$rebasedurls[0].'"></div>';
    echo '<div id="vc-player"></div>';
    echo '<div class="plyr-playlist-wrapper">';
    echo '<ul class="plyr-playlist">';

    foreach($playlistdata as $data){
        
        if(! filter_var($data, FILTER_VALIDATE_URL)){   
            echo '<span class="plyr-playlist-chapter-title">'.$data.'</span>'; 
        }
        else{
            echo '<li class="">';
            echo '<a class="plyr-playlist-link" href="javascript:void(0);" data-video-url="'. $data .'" data-status="'.videostatuschecker($data).'">';
            echo '<div class="plyr-playlist-thumbnail skeleton"><img class="plyr-miniposter" src="" alt="thumbnail"></div>';
            echo '<span class="plyr-playlist-title skeleton"><span></span></span>';
            echo '</a>';
            echo '</li>';
        }               
    }

    echo '</ul>';
    echo '</div>';
    echo '</div>';
    echo '<div class="vc-meta-container">'; 
        echo '<button class="fav-video-button" data-video-url="'.$rebasedurls[0].'">Zu Favoriten hinzufügen</button>';
        echo '<div class="autoplay-container"><span class="autoplay-title">Auto Play</span> <div class="toggly-container"> <input type="checkbox" id="autoplay-toggle"> <label class="toggly-label" for="autoplay-toggle"><i class="toggly"></i></label> </div></div>';
    echo '</div>';
    

    //return '';
    
}
add_shortcode('vc_playlist', 'vc_playlist_shortcode'); 

Any help is much appreciated, thank you.

EDIT: I was able to handle the problem with PHP Output Buffering, thanks to WordPress Codex.

Solution:

function my_shortcode() {
    ob_start();
    ?> HTML Here, you can also use foreach loops and stuff it works <?php
    return ob_get_clean();
}
0
2

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>';
}
2

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.