Frage

I have made a small plugin which grabs the post from another blog of mine, and I render it using a shortcode:

<div class="blog__grid">
        <?php
            // If there are posts.
            if ( ! empty( $posts ) ) {

                // For each post.
                foreach ( $posts as $post ) {

                    $featured_img = $post->_embedded->{'wp:featuredmedia'}[0]->source_url;
                    $ecerpt = $post->excerpt->rendered;
                    // Format the date.
                    $fordate = date( 'n/j/Y', strtotime( $post->modified ) );


                    // Show a linked title and post date.
                    ?>
                    <?php
                    $allposts .= "<div class='blog__grid__post'>
                    <div class='blog__grid__post__image'>
                        <img class='blog__grid__post__image--img' src='{$featured_img}' />
                        <a class='blog__grid__link' href='/blog/" .$post->slug. "'>"
                        . esc_html( $post->title->rendered ) .
                        '</a>
                    </div>
                        <div class="blog__grid__post__meta">'
                        . esc_html( $fordate ) .
                        '</div>
                        <div class="blog__grid__post__excerpt">'
                            .$ecerpt.
                        "</div>
                    </div>";

                }

            return $allposts;
        } ?>
    </div>

Now when I try to add more content to the page which uses this shortcode, everything I write is encapsulated inside the blog__grid tag, here is a screenshot from the inspector, the highlighted elements should not be inside this div, and I don't know why they are, can someone please help me with that?

enter image description here

War es hilfreich?

Lösung

There are 2 major problems.

The first is that you output the opening div directly in the shortcode. Shortcodes must never echo or output directly, they always return a HTML string.

As a result, before the post content is even displayed, this has already been sent to the browser:

<div class="blog__grid">

You're very lucky you're wrapping your entire post content with this, otherwise you would have noticed that the opening tag is always at the beginning.

Not only that but:

  • AJAX requests that process this post will be broken
  • REST API endpoints will be broken
  • XMLRPC will be broken
  • Sitemaps will be broken
  • If your shortcode supported nested content, that content would appear after the shortcode, not inside it
  • If this shortcode appears inside another shortcode, it too will be broken
  • Parts of this shortcode will always appear at the start of the post content even if it isn't at the start

You'll get invalid XML errors or invalid JSON syntax errors for anything that doesn't output HTML pages, and the order will be broken on those that do

But this leads to problem number 2. You never have a chance to output the closing tag

Look at this code:

            return $allposts;
        } ?>
    </div>

Notice that if posts are found, $allposts is returned, giving no opportunity for the closing </div> to be sent.

So instead:

  • Don't output the opening and closing tags, assign them instead in a variable, lets call it $output;
  • Don't return $allposts, add it to $output with $output .= $allposts;
  • End the function with return $output;

And if you must use code that outputs directly, wrap it in an output buffer.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit wordpress.stackexchange
scroll top