I’ll build this as a strong related-posts.php template part for your RX theme: secure WordPress coding, multiple matching methods, fallbacks, schema-friendly markup, responsive layout hooks, caching, and many filters so you can expand it later.
Below is an advanced related-posts.php file for your RX theme. Put it here:
rx-theme/
└── template-parts/
└── related-posts.php
Then call it inside single.php after post content:
<?php get_template_part( 'template-parts/related-posts' ); ?>
This version uses WordPress-safe escaping, WP_Query, taxonomies, tags, categories, fallback posts, transients cache, thumbnail support, reading time, post views support, comments count, author display, schema-style attributes, accessibility, and many filters so you can expand later. WordPress officially provides functions like wp_get_post_terms() for post terms, and recommends escaping output with functions such as esc_url(), esc_html(), and wp_kses_post().
<?php
/**
* RX Theme Advanced Related Posts Template
*
* File: template-parts/related-posts.php
*
* Features:
* - Related posts by category, tag, and custom taxonomy.
* - Fallback to recent/popular/random posts.
* - Transient caching.
* - Thumbnail, author, date, comments, excerpt, reading time.
* - Accessibility-ready markup.
* - SEO-friendly article structure.
* - Filter hooks for future customization.
* - Safe escaping and theme-friendly class names.
*
* Usage in single.php:
* get_template_part( 'template-parts/related-posts' );
*
* @package RX_Theme
*/
defined( 'ABSPATH' ) || exit;
if ( ! is_singular() ) {
return;
}
global $post;
if ( ! $post instanceof WP_Post ) {
return;
}
$current_post_id = absint( get_the_ID() );
if ( ! $current_post_id ) {
return;
}
/**
* ------------------------------------------------------------
* 1. Basic Settings
* ------------------------------------------------------------
*/
$rx_related_defaults = array(
'enabled' => true,
'title' => __( 'Related Posts', 'rx-theme' ),
'subtitle' => __( 'You may also like these articles', 'rx-theme' ),
'post_types' => array( 'post' ),
'posts_per_page' => 6,
'columns' => 3,
'orderby' => 'date',
'order' => 'DESC',
'match_categories' => true,
'match_tags' => true,
'match_custom_taxonomies' => true,
'custom_taxonomies' => array(),
'exclude_current_post' => true,
'exclude_sticky_posts' => true,
'show_thumbnail' => true,
'show_category' => true,
'show_date' => true,
'show_author' => true,
'show_comments' => true,
'show_excerpt' => true,
'show_reading_time' => true,
'show_post_format' => false,
'show_views' => true,
'excerpt_length' => 18,
'image_size' => 'medium_large',
'cache_enabled' => true,
'cache_time' => HOUR_IN_SECONDS,
'fallback_enabled' => true,
'fallback_orderby' => 'date',
'fallback_order' => 'DESC',
'fallback_days' => 365,
'layout' => 'grid',
'section_id' => 'rx-related-posts',
'container_class' => 'rx-related-posts',
'card_class' => 'rx-related-card',
'more_text' => __( 'Read More', 'rx-theme' ),
'no_posts_text' => '',
);
$rx_related_args = apply_filters( 'rx_related_posts_args', $rx_related_defaults, $current_post_id );
if ( empty( $rx_related_args['enabled'] ) ) {
return;
}
$posts_per_page = isset( $rx_related_args['posts_per_page'] ) ? absint( $rx_related_args['posts_per_page'] ) : 6;
if ( $posts_per_page < 1 ) {
return;
}
/**
* ------------------------------------------------------------
* 2. Helper Functions
* ------------------------------------------------------------
*/
if ( ! function_exists( 'rx_related_posts_get_reading_time' ) ) {
/**
* Get estimated reading time.
*
* @param int $post_id Post ID.
* @return string
*/
function rx_related_posts_get_reading_time( $post_id ) {
$content = get_post_field( 'post_content', $post_id );
$content = wp_strip_all_tags( strip_shortcodes( $content ) );
$word_count = str_word_count( $content );
$minutes = max( 1, ceil( $word_count / 200 ) );
return sprintf(
_n( '%s min read', '%s min read', $minutes, 'rx-theme' ),
number_format_i18n( $minutes )
);
}
}
if ( ! function_exists( 'rx_related_posts_get_excerpt' ) ) {
/**
* Get clean custom excerpt.
*
* @param int $post_id Post ID.
* @param int $length Word length.
* @return string
*/
function rx_related_posts_get_excerpt( $post_id, $length = 18 ) {
$manual_excerpt = get_the_excerpt( $post_id );
if ( ! empty( $manual_excerpt ) ) {
$text = $manual_excerpt;
} else {
$text = get_post_field( 'post_content', $post_id );
}
$text = wp_strip_all_tags( strip_shortcodes( $text ) );
$text = wp_trim_words( $text, absint( $length ), '...' );
return $text;
}
}
if ( ! function_exists( 'rx_related_posts_get_views' ) ) {
/**
* Get post views if your theme/plugin stores views.
*
* Supported meta examples:
* - post_views_count
* - views
* - rx_post_views
*
* @param int $post_id Post ID.
* @return int
*/
function rx_related_posts_get_views( $post_id ) {
$possible_keys = apply_filters(
'rx_related_posts_view_meta_keys',
array(
'post_views_count',
'views',
'rx_post_views',
)
);
foreach ( $possible_keys as $key ) {
$value = get_post_meta( $post_id, $key, true );
if ( '' !== $value && is_numeric( $value ) ) {
return absint( $value );
}
}
return 0;
}
}
if ( ! function_exists( 'rx_related_posts_get_primary_category' ) ) {
/**
* Get primary/first category.
*
* @param int $post_id Post ID.
* @return WP_Term|null
*/
function rx_related_posts_get_primary_category( $post_id ) {
$categories = get_the_category( $post_id );
if ( empty( $categories ) || is_wp_error( $categories ) ) {
return null;
}
return $categories[0];
}
}
if ( ! function_exists( 'rx_related_posts_get_tax_query' ) ) {
/**
* Build related posts tax query.
*
* @param int $post_id Post ID.
* @param array $args Settings.
* @return array
*/
function rx_related_posts_get_tax_query( $post_id, $args ) {
$tax_query = array(
'relation' => 'OR',
);
if ( ! empty( $args['match_categories'] ) ) {
$category_ids = wp_get_post_terms(
$post_id,
'category',
array(
'fields' => 'ids',
)
);
if ( ! is_wp_error( $category_ids ) && ! empty( $category_ids ) ) {
$tax_query[] = array(
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => array_map( 'absint', $category_ids ),
'include_children' => true,
'operator' => 'IN',
);
}
}
if ( ! empty( $args['match_tags'] ) ) {
$tag_ids = wp_get_post_terms(
$post_id,
'post_tag',
array(
'fields' => 'ids',
)
);
if ( ! is_wp_error( $tag_ids ) && ! empty( $tag_ids ) ) {
$tax_query[] = array(
'taxonomy' => 'post_tag',
'field' => 'term_id',
'terms' => array_map( 'absint', $tag_ids ),
'operator' => 'IN',
);
}
}
if ( ! empty( $args['match_custom_taxonomies'] ) ) {
$custom_taxonomies = ! empty( $args['custom_taxonomies'] ) && is_array( $args['custom_taxonomies'] )
? $args['custom_taxonomies']
: get_object_taxonomies( get_post_type( $post_id ), 'names' );
$excluded_taxonomies = array(
'category',
'post_tag',
'post_format',
'nav_menu',
'link_category',
);
foreach ( $custom_taxonomies as $taxonomy ) {
if ( in_array( $taxonomy, $excluded_taxonomies, true ) ) {
continue;
}
if ( ! taxonomy_exists( $taxonomy ) ) {
continue;
}
$term_ids = wp_get_post_terms(
$post_id,
$taxonomy,
array(
'fields' => 'ids',
)
);
if ( ! is_wp_error( $term_ids ) && ! empty( $term_ids ) ) {
$tax_query[] = array(
'taxonomy' => sanitize_key( $taxonomy ),
'field' => 'term_id',
'terms' => array_map( 'absint', $term_ids ),
'operator' => 'IN',
);
}
}
}
if ( count( $tax_query ) <= 1 ) {
return array();
}
return $tax_query;
}
}
/**
* ------------------------------------------------------------
* 3. Cache Key
* ------------------------------------------------------------
*/
$rx_cache_key = 'rx_related_posts_' . md5(
wp_json_encode(
array(
'post_id' => $current_post_id,
'posts_per_page' => $posts_per_page,
'post_type' => get_post_type( $current_post_id ),
'args' => $rx_related_args,
)
)
);
$rx_related_post_ids = false;
if ( ! empty( $rx_related_args['cache_enabled'] ) ) {
$rx_related_post_ids = get_transient( $rx_cache_key );
}
/**
* ------------------------------------------------------------
* 4. Main Related Query
* ------------------------------------------------------------
*/
if ( false === $rx_related_post_ids ) {
$post__not_in = array();
if ( ! empty( $rx_related_args['exclude_current_post'] ) ) {
$post__not_in[] = $current_post_id;
}
$tax_query = rx_related_posts_get_tax_query( $current_post_id, $rx_related_args );
$query_args = array(
'post_type' => ! empty( $rx_related_args['post_types'] ) ? $rx_related_args['post_types'] : array( 'post' ),
'post_status' => 'publish',
'posts_per_page' => $posts_per_page,
'post__not_in' => array_map( 'absint', $post__not_in ),
'ignore_sticky_posts' => ! empty( $rx_related_args['exclude_sticky_posts'] ),
'orderby' => sanitize_key( $rx_related_args['orderby'] ),
'order' => 'ASC' === strtoupper( $rx_related_args['order'] ) ? 'ASC' : 'DESC',
'no_found_rows' => true,
'update_post_meta_cache' => true,
'update_post_term_cache' => true,
);
if ( ! empty( $tax_query ) ) {
$query_args['tax_query'] = $tax_query; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
}
$query_args = apply_filters( 'rx_related_posts_query_args', $query_args, $current_post_id, $rx_related_args );
$rx_related_query = new WP_Query( $query_args );
$rx_related_post_ids = wp_list_pluck( $rx_related_query->posts, 'ID' );
wp_reset_postdata();
/**
* ------------------------------------------------------------
* 5. Fallback Query
* ------------------------------------------------------------
*/
if (
! empty( $rx_related_args['fallback_enabled'] )
&& count( $rx_related_post_ids ) < $posts_per_page
) {
$needed_posts = $posts_per_page - count( $rx_related_post_ids );
$fallback_exclude = array_merge(
array( $current_post_id ),
array_map( 'absint', $rx_related_post_ids )
);
$fallback_date_query = array();
if ( ! empty( $rx_related_args['fallback_days'] ) ) {
$fallback_date_query[] = array(
'after' => absint( $rx_related_args['fallback_days'] ) . ' days ago',
'inclusive' => true,
);
}
$fallback_args = array(
'post_type' => ! empty( $rx_related_args['post_types'] ) ? $rx_related_args['post_types'] : array( 'post' ),
'post_status' => 'publish',
'posts_per_page' => $needed_posts,
'post__not_in' => array_map( 'absint', $fallback_exclude ),
'ignore_sticky_posts' => true,
'orderby' => sanitize_key( $rx_related_args['fallback_orderby'] ),
'order' => 'ASC' === strtoupper( $rx_related_args['fallback_order'] ) ? 'ASC' : 'DESC',
'no_found_rows' => true,
'update_post_meta_cache' => true,
'update_post_term_cache' => true,
);
if ( ! empty( $fallback_date_query ) ) {
$fallback_args['date_query'] = $fallback_date_query;
}
$fallback_args = apply_filters( 'rx_related_posts_fallback_query_args', $fallback_args, $current_post_id, $rx_related_args );
$fallback_query = new WP_Query( $fallback_args );
$fallback_ids = wp_list_pluck( $fallback_query->posts, 'ID' );
wp_reset_postdata();
if ( ! empty( $fallback_ids ) ) {
$rx_related_post_ids = array_merge( $rx_related_post_ids, $fallback_ids );
$rx_related_post_ids = array_slice( array_unique( array_map( 'absint', $rx_related_post_ids ) ), 0, $posts_per_page );
}
}
if ( ! empty( $rx_related_args['cache_enabled'] ) ) {
set_transient(
$rx_cache_key,
$rx_related_post_ids,
! empty( $rx_related_args['cache_time'] ) ? absint( $rx_related_args['cache_time'] ) : HOUR_IN_SECONDS
);
}
}
/**
* ------------------------------------------------------------
* 6. Stop If Empty
* ------------------------------------------------------------
*/
if ( empty( $rx_related_post_ids ) ) {
if ( ! empty( $rx_related_args['no_posts_text'] ) ) {
echo '<p class="rx-related-posts-empty">' . esc_html( $rx_related_args['no_posts_text'] ) . '</p>';
}
return;
}
/**
* ------------------------------------------------------------
* 7. Final Display Query
* ------------------------------------------------------------
*/
$display_query_args = array(
'post_type' => ! empty( $rx_related_args['post_types'] ) ? $rx_related_args['post_types'] : array( 'post' ),
'post_status' => 'publish',
'post__in' => array_map( 'absint', $rx_related_post_ids ),
'orderby' => 'post__in',
'posts_per_page' => count( $rx_related_post_ids ),
'no_found_rows' => true,
'update_post_meta_cache' => true,
'update_post_term_cache' => true,
);
$display_query_args = apply_filters( 'rx_related_posts_display_query_args', $display_query_args, $current_post_id, $rx_related_args );
$rx_display_query = new WP_Query( $display_query_args );
if ( ! $rx_display_query->have_posts() ) {
wp_reset_postdata();
return;
}
/**
* ------------------------------------------------------------
* 8. Classes
* ------------------------------------------------------------
*/
$section_id = ! empty( $rx_related_args['section_id'] ) ? sanitize_html_class( $rx_related_args['section_id'] ) : 'rx-related-posts';
$container_class = ! empty( $rx_related_args['container_class'] ) ? sanitize_html_class( $rx_related_args['container_class'] ) : 'rx-related-posts';
$layout = ! empty( $rx_related_args['layout'] ) ? sanitize_html_class( $rx_related_args['layout'] ) : 'grid';
$columns = ! empty( $rx_related_args['columns'] ) ? absint( $rx_related_args['columns'] ) : 3;
$wrapper_classes = array(
$container_class,
$container_class . '--layout-' . $layout,
$container_class . '--columns-' . $columns,
);
$wrapper_classes = apply_filters( 'rx_related_posts_wrapper_classes', $wrapper_classes, $current_post_id, $rx_related_args );
?>
<section
id="<?php echo esc_attr( $section_id ); ?>"
class="<?php echo esc_attr( implode( ' ', array_map( 'sanitize_html_class', $wrapper_classes ) ) ); ?>"
aria-labelledby="<?php echo esc_attr( $section_id . '-title' ); ?>"
>
<header class="rx-related-posts__header">
<?php if ( ! empty( $rx_related_args['title'] ) ) : ?>
<h2 id="<?php echo esc_attr( $section_id . '-title' ); ?>" class="rx-related-posts__title">
<?php echo esc_html( $rx_related_args['title'] ); ?>
</h2>
<?php endif; ?>
<?php if ( ! empty( $rx_related_args['subtitle'] ) ) : ?>
<p class="rx-related-posts__subtitle">
<?php echo esc_html( $rx_related_args['subtitle'] ); ?>
</p>
<?php endif; ?>
</header>
<div class="rx-related-posts__grid">
<?php
while ( $rx_display_query->have_posts() ) :
$rx_display_query->the_post();
$related_id = get_the_ID();
$related_title = get_the_title();
$related_link = get_permalink();
$related_category = rx_related_posts_get_primary_category( $related_id );
$reading_time = rx_related_posts_get_reading_time( $related_id );
$views = rx_related_posts_get_views( $related_id );
$card_class = ! empty( $rx_related_args['card_class'] ) ? sanitize_html_class( $rx_related_args['card_class'] ) : 'rx-related-card';
$article_classes = array(
$card_class,
$card_class . '--post-' . absint( $related_id ),
has_post_thumbnail() ? $card_class . '--has-thumbnail' : $card_class . '--no-thumbnail',
);
$article_classes = apply_filters( 'rx_related_posts_card_classes', $article_classes, $related_id, $rx_related_args );
?>
<article
id="rx-related-post-<?php echo esc_attr( $related_id ); ?>"
<?php post_class( array_map( 'sanitize_html_class', $article_classes ), $related_id ); ?>
itemscope
itemtype="https://schema.org/BlogPosting"
>
<?php if ( ! empty( $rx_related_args['show_thumbnail'] ) ) : ?>
<div class="rx-related-card__media">
<a class="rx-related-card__image-link" href="<?php echo esc_url( $related_link ); ?>" aria-label="<?php echo esc_attr( $related_title ); ?>">
<?php if ( has_post_thumbnail( $related_id ) ) : ?>
<?php
echo get_the_post_thumbnail(
$related_id,
! empty( $rx_related_args['image_size'] ) ? esc_attr( $rx_related_args['image_size'] ) : 'medium_large',
array(
'class' => 'rx-related-card__image',
'loading' => 'lazy',
'decoding' => 'async',
'alt' => the_title_attribute(
array(
'echo' => false,
'post' => $related_id,
)
),
'itemprop' => 'image',
)
);
?>
<?php else : ?>
<div class="rx-related-card__placeholder" aria-hidden="true">
<span class="rx-related-card__placeholder-icon">📄</span>
</div>
<?php endif; ?>
</a>
<?php if ( ! empty( $rx_related_args['show_category'] ) && $related_category instanceof WP_Term ) : ?>
<a
class="rx-related-card__category"
href="<?php echo esc_url( get_category_link( $related_category->term_id ) ); ?>"
>
<?php echo esc_html( $related_category->name ); ?>
</a>
<?php endif; ?>
</div>
<?php endif; ?>
<div class="rx-related-card__body">
<?php if ( ! empty( $rx_related_args['show_post_format'] ) && get_post_format( $related_id ) ) : ?>
<span class="rx-related-card__format">
<?php echo esc_html( get_post_format_string( get_post_format( $related_id ) ) ); ?>
</span>
<?php endif; ?>
<h3 class="rx-related-card__title" itemprop="headline">
<a href="<?php echo esc_url( $related_link ); ?>" itemprop="url">
<?php echo esc_html( $related_title ); ?>
</a>
</h3>
<div class="rx-related-card__meta">
<?php if ( ! empty( $rx_related_args['show_date'] ) ) : ?>
<span class="rx-related-card__date">
<time datetime="<?php echo esc_attr( get_the_date( DATE_W3C, $related_id ) ); ?>" itemprop="datePublished">
<?php echo esc_html( get_the_date( '', $related_id ) ); ?>
</time>
</span>
<?php endif; ?>
<?php if ( ! empty( $rx_related_args['show_author'] ) ) : ?>
<span class="rx-related-card__author" itemprop="author" itemscope itemtype="https://schema.org/Person">
<?php esc_html_e( 'By', 'rx-theme' ); ?>
<a href="<?php echo esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ); ?>" itemprop="url">
<span itemprop="name"><?php echo esc_html( get_the_author() ); ?></span>
</a>
</span>
<?php endif; ?>
<?php if ( ! empty( $rx_related_args['show_reading_time'] ) ) : ?>
<span class="rx-related-card__reading-time">
<?php echo esc_html( $reading_time ); ?>
</span>
<?php endif; ?>
<?php if ( ! empty( $rx_related_args['show_comments'] ) && comments_open( $related_id ) ) : ?>
<span class="rx-related-card__comments">
<?php
printf(
esc_html(
_n(
'%s comment',
'%s comments',
get_comments_number( $related_id ),
'rx-theme'
)
),
esc_html( number_format_i18n( get_comments_number( $related_id ) ) )
);
?>
</span>
<?php endif; ?>
<?php if ( ! empty( $rx_related_args['show_views'] ) && $views > 0 ) : ?>
<span class="rx-related-card__views">
<?php
printf(
esc_html(
_n(
'%s view',
'%s views',
$views,
'rx-theme'
)
),
esc_html( number_format_i18n( $views ) )
);
?>
</span>
<?php endif; ?>
</div>
<?php if ( ! empty( $rx_related_args['show_excerpt'] ) ) : ?>
<p class="rx-related-card__excerpt" itemprop="description">
<?php
echo esc_html(
rx_related_posts_get_excerpt(
$related_id,
! empty( $rx_related_args['excerpt_length'] ) ? absint( $rx_related_args['excerpt_length'] ) : 18
)
);
?>
</p>
<?php endif; ?>
<a class="rx-related-card__read-more" href="<?php echo esc_url( $related_link ); ?>">
<?php echo esc_html( $rx_related_args['more_text'] ); ?>
<span class="screen-reader-text">
<?php echo esc_html( $related_title ); ?>
</span>
</a>
</div>
</article>
<?php endwhile; ?>
</div>
</section>
<?php
wp_reset_postdata();
Add this CSS to your theme style.css or assets/css/related-posts.css:
.rx-related-posts {
margin-top: 48px;
margin-bottom: 48px;
}
.rx-related-posts__header {
margin-bottom: 24px;
text-align: center;
}
.rx-related-posts__title {
margin: 0 0 8px;
font-size: clamp(24px, 3vw, 36px);
line-height: 1.2;
}
.rx-related-posts__subtitle {
margin: 0;
color: #666;
font-size: 16px;
}
.rx-related-posts__grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 24px;
}
.rx-related-posts--columns-1 .rx-related-posts__grid {
grid-template-columns: repeat(1, minmax(0, 1fr));
}
.rx-related-posts--columns-2 .rx-related-posts__grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.rx-related-posts--columns-3 .rx-related-posts__grid {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.rx-related-posts--columns-4 .rx-related-posts__grid {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.rx-related-card {
position: relative;
overflow: hidden;
border: 1px solid rgba(0, 0, 0, 0.08);
border-radius: 18px;
background: #fff;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.06);
transition: transform 0.25s ease, box-shadow 0.25s ease;
}
.rx-related-card:hover {
transform: translateY(-4px);
box-shadow: 0 18px 45px rgba(0, 0, 0, 0.1);
}
.rx-related-card__media {
position: relative;
overflow: hidden;
aspect-ratio: 16 / 10;
background: #f3f4f6;
}
.rx-related-card__image-link {
display: block;
width: 100%;
height: 100%;
}
.rx-related-card__image {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.35s ease;
}
.rx-related-card:hover .rx-related-card__image {
transform: scale(1.04);
}
.rx-related-card__placeholder {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
font-size: 40px;
color: #777;
}
.rx-related-card__category {
position: absolute;
left: 14px;
top: 14px;
z-index: 2;
display: inline-flex;
align-items: center;
border-radius: 999px;
padding: 6px 12px;
background: rgba(0, 0, 0, 0.72);
color: #fff;
font-size: 12px;
font-weight: 700;
text-decoration: none;
line-height: 1;
}
.rx-related-card__category:hover {
background: rgba(0, 0, 0, 0.88);
color: #fff;
}
.rx-related-card__body {
padding: 20px;
}
.rx-related-card__format {
display: inline-block;
margin-bottom: 8px;
color: #555;
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.04em;
}
.rx-related-card__title {
margin: 0 0 12px;
font-size: 20px;
line-height: 1.35;
}
.rx-related-card__title a {
color: inherit;
text-decoration: none;
}
.rx-related-card__title a:hover {
text-decoration: underline;
}
.rx-related-card__meta {
display: flex;
flex-wrap: wrap;
gap: 8px 12px;
margin-bottom: 12px;
color: #666;
font-size: 13px;
line-height: 1.4;
}
.rx-related-card__meta a {
color: inherit;
text-decoration: none;
}
.rx-related-card__meta a:hover {
text-decoration: underline;
}
.rx-related-card__excerpt {
margin: 0 0 16px;
color: #555;
font-size: 15px;
line-height: 1.65;
}
.rx-related-card__read-more {
display: inline-flex;
align-items: center;
font-weight: 700;
text-decoration: none;
}
.rx-related-card__read-more:hover {
text-decoration: underline;
}
.rx-related-posts-empty {
margin: 32px 0;
text-align: center;
color: #777;
}
@media (max-width: 1024px) {
.rx-related-posts__grid,
.rx-related-posts--columns-3 .rx-related-posts__grid,
.rx-related-posts--columns-4 .rx-related-posts__grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 640px) {
.rx-related-posts__grid,
.rx-related-posts--columns-2 .rx-related-posts__grid,
.rx-related-posts--columns-3 .rx-related-posts__grid,
.rx-related-posts--columns-4 .rx-related-posts__grid {
grid-template-columns: 1fr;
}
.rx-related-card__body {
padding: 16px;
}
}
Optional: add this to functions.php to clear related post cache when posts are updated:
/**
* Clear RX related post transients when posts are saved.
*/
function rx_clear_related_posts_cache_on_save() {
global $wpdb;
if ( ! $wpdb instanceof wpdb ) {
return;
}
$wpdb->query(
$wpdb->prepare(
"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s OR option_name LIKE %s",
'_transient_rx_related_posts_%',
'_transient_timeout_rx_related_posts_%'
)
);
}
add_action( 'save_post', 'rx_clear_related_posts_cache_on_save' );
add_action( 'deleted_post', 'rx_clear_related_posts_cache_on_save' );
add_action( 'edit_term', 'rx_clear_related_posts_cache_on_save' );
add_action( 'delete_term', 'rx_clear_related_posts_cache_on_save' );
You can customize it from functions.php like this:
function rx_custom_related_posts_settings( $args, $post_id ) {
$args['title'] = 'More Helpful Articles';
$args['subtitle'] = 'Selected from similar topics';
$args['posts_per_page'] = 8;
$args['columns'] = 4;
$args['excerpt_length'] = 22;
$args['show_views'] = true;
$args['show_comments'] = true;
$args['show_author'] = true;
$args['fallback_orderby'] = 'rand';
return $args;
}
add_filter( 'rx_related_posts_args', 'rx_custom_related_posts_settings', 10, 2 );
My friend, this is a strong production-style related posts file for your RX theme. It is not just simple related posts; it is expandable like a mini related-posts system inside your theme.