Search code examples
phpwordpressfunctionshortcode

Wordpress do_shortcode with content and shortcodes inside adds shortcode before the content instead of inline


It seems that do_shortcode() (as well as apply_filters()) adds shortcodes in front of the content instead of inline. How could I go about solving this?

To explain: I'm calling something like this inside my post:

[add_entry_content]
<p>Some text that needs to be displayed *before* the called list.</p>

[add_display_code_list]<!-- the list-content I add -->[/add_display_code_list]

<p>Some text that needs to be displayed *after* the called list.</p>

[/add_entry_content]

My functions.php contains this:

// add_entry_content
function add_entry_content_func( $atts, $content = '' ) { ?>

    <div class="entry-content content">
        <?php echo apply_filters('the_content', $content); ?>
    </div><!-- .entry-content -->

<?php }
add_shortcode( 'add_entry_content', 'add_entry_content_func' );


// add a function to display the code-list
function add_display_code_list_func( $atts, $content = '' ) { ?>

    <ul>
        <li>Dynamically added 1</li>
        <li>Dynamically added 2</li>
    </ul>

<?php }
add_shortcode( 'add_display_code_list', 'add_display_code_list_func' );

I would expect the parser to display this:

Some text that needs to be displayed *before* the called list.

  • Dynamically added 1
  • Dynamically added 2

Some text that needs to be displayed *after* the called list.


But it instead displays this (the list is displayed inside the container, but before the text-content):

  • Dynamically added 1
  • Dynamically added 2

Some text that needs to be displayed *before* the called list.

Some text that needs to be displayed *after* the called list.



Solution

  • This is because you are displaying the HTML directly within your shortcode callback. You need to return the HTML back through the shortcode. Think of this like a WordPress filter. This will render your short code and output it wherever in the content it was placed.

    function add_entry_content_func( $atts, $content = '' ) { 
    
     $html = '<div class="entry-content content">';
     $html .= apply_filters('the_content', $content);
     $html .= '</div>';
    
     return $html;
     }
    

    Or try this with ob_start();

    <?php function add_entry_content_func( $atts, $content = '' ) { 
    
    ob_start(); ?>
    
    <div class="entry-content content">
        <?php echo apply_filters('the_content', $content); ?>
    </div><!-- .entry-content -->
    
    <?php 
    
     return ob_get_clean();
    } ?>