WordPress previous and next post links usually show only the title. This snippet shows the previous and next post under a single post with its title and featured image, as one navigation block you can style.
It replaces the old template code that printed a broken link and PHP warnings on the first and the last post, because there is no previous or next post there. Now a missing side is simply left out, and every title and URL is escaped.
The snippet
<?php
/**
* Previous and next post, each with its title and featured image.
* Scripts Organizer: Trigger location Conditions, Script location Shortcode.
*/
$dpc_image_size = 'thumbnail'; // Any registered image size.
$dpc_image_class = 'dpc-adjacent__thumb'; // Class on the <img>.
$dpc_same_term = false; // true: only posts in the same category.
$dpc_adjacent = array(
'prev' => array( get_previous_post( $dpc_same_term ), __( 'Previous post', 'dpc' ) ),
'next' => array( get_next_post( $dpc_same_term ), __( 'Next post', 'dpc' ) ),
);
$dpc_links = '';
foreach ( $dpc_adjacent as $dpc_rel => $dpc_item ) {
list( $dpc_adjacent_post, $dpc_label ) = $dpc_item;
// null without a current post, '' on the first or last post.
if ( ! $dpc_adjacent_post instanceof WP_Post ) {
continue;
}
$dpc_links .= sprintf(
'<a class="dpc-adjacent__link dpc-adjacent__link--%1$s" href="%2$s" rel="%1$s"><span class="dpc-adjacent__label">%3$s</span>%4$s<h3 class="dpc-adjacent__title">%5$s</h3></a>',
esc_attr( $dpc_rel ),
esc_url( get_permalink( $dpc_adjacent_post ) ),
esc_html( $dpc_label ),
get_the_post_thumbnail( $dpc_adjacent_post, $dpc_image_size, array( 'class' => $dpc_image_class ) ),
esc_html( get_the_title( $dpc_adjacent_post ) )
);
}
if ( '' !== $dpc_links ) {
echo '<nav class="dpc-adjacent" aria-label="' . esc_attr__( 'Post navigation', 'dpc' ) . '">' . $dpc_links . '</nav>';
}
Add it with Scripts Organizer
In Scripts Organizer go to Code Blocks → Add New and give the block a name. Set Trigger location to Conditions, tick Shortcode under Script location (leave PHP unticked), paste the code into the PHP editor, keep Template on All and publish.
The block now shows its shortcode, for example [scorg_shortcode id="123"]. Paste it where the output should appear: a Shortcode block in the post or in a block theme template, or the shortcode element of your page builder’s single or archive template.
This is the Scripts Organizer way for template code like this: no shortcode to register, and the block’s Conditions decide where it prints. Set Template to Post Type → Posts if the same shortcode also sits in a template shared with pages. Scripts Organizer includes this file every time the shortcode renders, inside its own function. That is why the code has no function declarations (a second shortcode on the same page would fatal with “Cannot redeclare”), uses get_the_ID() or get_queried_object_id() instead of a bare $post, and prefixes its variables with dpc_.
How it works
get_previous_post()andget_next_post()look at the current post in the main query. They return a post, an empty string on the first or last post, andnullwhen there is no current post, so theinstanceof WP_Postcheck covers all three.get_the_post_thumbnail()prints the image withsrcset,sizes, lazy loading and the alt text from the media library. A post without a featured image just has no<img>.- Each side is a link with
rel="prev"orrel="next", a small label, the image and anh3title. The whole thing sits in anavwith anaria-label, and nothing is printed when both sides are missing. - Titles go through
esc_html()and URLs throughesc_url(), so a title with&or HTML cannot break the markup.
Customise it
- Bigger images: set
$dpc_image_sizetomediumor your theme’s size. - Only posts from the same category: set
$dpc_same_termtotrue. The older same-category version of this post covers that case in detail. - Different heading level: change both
h3tags in thesprintf()pattern. - Side by side:
.dpc-adjacent{display:flex;justify-content:space-between;gap:1rem}and.dpc-adjacent__link--next{text-align:right;margin-left:auto}.
Gotchas
- Previous and next follow the publish date of the same post type. Sticky posts and custom ordering are ignored.
- In a page builder’s preview or the Site Editor there may be no current post, so the block stays empty there and appears on the real post.
- Block themes already have a Post Navigation Link block without images. Use this when you need the thumbnails.
In the Scripts Organizer library Import it with one click from Scripts Organizer.