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?
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?
1 Answer
Reset to default 1There 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.