0

I am having an issue displaying the shortcode in the correct location when using a display child pages query.

Can someone fix this for me? Thank you!

enter image description here

    function show_product_pages() {

global $post;
$child_pages_query_args = array(
    'post_type'   => 'page',
    'post_parent' => $post->ID,

);
$child_pages = new WP_Query( $child_pages_query_args );

if ( $child_pages->have_posts() ) :
?>
<div class="columns product-archives">
<?php 
while ( $child_pages->have_posts() ) : $child_pages->the_post();
    ?>
        <div class="col col-md-4">
            <a href="<?php the_permalink(); ?>">
                <div class="product_thumb"><?php the_post_thumbnail(array(240, 240)); ?></div>
                <h3 class="product_title"><?php the_title(); ?></h3>
            </a>
            <div class="product-desc"><?php the_content($post->ID); ?></div>
            <a class="cta-link" href="<?php the_permalink(); ?>">Learn More </a>
        </div>
<?php endwhile; ?>
</div>
<?php endif;
wp_reset_postdata();
}
add_shortcode('show_product_pages', 'show_product_pages');
  • Did you see the other answer linked in the duplicate? There I fixed a code very similar to yours. Does that help? – fuxia Jun 26 at 1:12
  • Thanks for the link, I tried to fix my code to match and I am not getting it to work. What specifically should I be looking at? Thank you so much! – Jen Brigham Jun 26 at 14:49
1

Shortcode callbacks must return a string or nothing at all. They must not print anything directly, because that will create an immediate output as you have seen in your example. We have a few topics about that already. I took the liberty to reopen your question, because you said the other answers didn't really help you. :)

Almost every function that prints something directly (often called template tag in WordPress) has an equivalent that returns the string instead, or a parameter that changes the return behavior. the_date() is a notable exception.

You can find these functions either by looking at the source code in your local WordPress copy, or you go to the developer manual and search for the function that you want to replace. The string equivalent will be mentioned there.

Now, knowing that, how do you apply that to your own code? It is clear that you cannot use something like this anymore:

<?php 
// some code 
?>
some HTML
<?php
// more code
?>

… because that some HTML will be printed directly, and that's exactly what we don't want.

We have to write instead:

<?php 
// some code 

$output = 'some HTML';

// more code

return $output;
?>

And that means, we need the functions that return strings, insert these strings into the some HTML, and finally return the result as a string.

Here is how I would rewrite your example. Note that I didn't test it. You might run into some errors that you have to fix later. :)

function show_product_pages() {

    $post = get_post();

    // Just in case the shortcode has been used in the wrong context.
    if ( empty( $post ) ) {
        return;
    }

    $child_pages = new WP_Query([
        'post_type'   => 'page',
        'post_parent' => $post->ID,

    ]);

    // Always return as early as possible.
    if ( ! $child_pages->have_posts() ) {
        return;
    }

    $output = '';

    while ( $child_pages->have_posts() ) {
        // Set up post data.
        $child_pages->the_post();

        // Keep the dynamic values and the HTML template a bit separated.
        // Makes both parts easier to read, and we don't have to call a 
        // function twice.
        $url     = apply_filters( 'the_permalink', get_permalink() );
        $thumb   = get_the_post_thumbnail( null, [240, 240]);
        $title   = the_title( '', '', FALSE );
        $content = apply_filters( 'the_content', get_the_content() );

        // Now we add the HTML to $output.
        $output .= '
        <div class="col col-md-4">
            <a href="' . $url . '">
                <div class="product_thumb">' . $thumb . '</div>
                <h3 class="product_title">' . $title . '</h3>
            </a>
            <div class="product-desc">' . $content . '</div>
            <a class="cta-link" href="' . $url . '">Learn More</a>
        </div>
        ';
    }

    // Clean up what we have done to the global context.
    wp_reset_postdata();

    // We add the container and return the whole string.
    return '<div class="columns product-archives">' . $output . '</div>';
}

And that's it. There are ways to separate the dynamic logic and the HTML a bit more, but for such a simple case, it will do.

  • 1
    You're amazing, this works! Thank you for working with me and adding the explanation. This is so helpful! – Jen Brigham Jun 26 at 19:29

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.