Jetpack-like Related Posts without Jetpack in Genesis

Posted on
5/5 - (402 votes)

Jetpack’s Related Posts module has a “large and visually striking layout” option that shows related posts at the bottom of content like this:

This tutorial provides the steps to show a similarly styled three related posts below the comments section on single posts in Genesis based on the code by Nick Croft and improvements by Andrea and Chinmoy and a single function for category query and tag query by Lee Anthony.

We shall use CSS Grid with Flexbox fallback for arranging the related posts in columns.

Step 1

Add the following in child theme’s functions.php:

// Adds custom image size for images in Related Posts section.
add_image_size( 'related', 400, 222, true );

add_action( 'genesis_after_loop', 'sk_related_posts', 12 );
/**
 * Outputs related posts with thumbnail.
 *
 * @author Nick the Geek
 * @url http://designsbynickthegeek.com/tutorials/related-posts-genesis
 * @global object $post
 */
function sk_related_posts() {
    global $do_not_duplicate;

    // If we are not on a single post page, abort.
    if ( ! is_singular( 'post' ) ) {
        return;
    }

    global $count;
    $count = 0;

    $related = '';

    $do_not_duplicate = array();

    // Get the tags for the current post.
    $tags = get_the_terms( get_the_ID(), 'post_tag' );

    // Get the categories for the current post.
    $cats = get_the_terms( get_the_ID(), 'category' );

    // If we have some tags, run the tag query.
    if ( $tags ) {
        $query    = sk_related_tax_query( $tags, $count, 'tag' );
        $related .= $query['related'];
        $count    = $query['count'];
    }

    // If we have some categories and less than 3 posts, run the cat query.
    if ( $cats && $count <= 2 ) {
        $query    = sk_related_tax_query( $cats, $count, 'category' );
        $related .= $query['related'];
        $count    = $query['count'];
    }

    // End here if we don't have any related posts.
    if ( ! $related ) {
        return;
    }

    // Display the related posts section.
    echo '<div class="related">';
        echo '<h3 class="related-title">Related</h3>';
        echo '<div class="related-posts">' . $related . '</div>';
    echo '</div>';
}

/**
 * The taxonomy query.
 *
 * @since  1.0.0
 * 
 * @param  array  $terms Array of the taxonomy's objects.
 * @param  int    $count The number of posts.
 * @param  string $type  The type of taxonomy, e.g: `tag` or `category`.
 *
 * @return string
 */
function sk_related_tax_query( $terms, $count, $type ) {
    global $do_not_duplicate;

    // If the current post does not have any terms of the specified taxonomy, abort.
    if ( ! $terms ) {
        return;
    }

    // Array variable to store the IDs of the posts.
    // Stores the current post ID to begin with.
    $post_ids = array_merge( array( get_the_ID() ), $do_not_duplicate );

    $term_ids = array();

    // Array variable to store the IDs of the specified taxonomy terms.
    foreach ( $terms as $term ) {
        $term_ids[] = $term->term_id;
    }

    $tax_query = array(
        array(
            'taxonomy'  => 'post_format',
            'field'     => 'slug',
            'terms'     => array(
                'post-format-link',
                'post-format-status',
                'post-format-aside',
                'post-format-quote',
            ),
            'operator' => 'NOT IN',
        ),
    );

    $showposts = 3 - $count;

    $args = array(
        $type . '__in'        => $term_ids,
        'post__not_in'        => $post_ids,
        'showposts'           => $showposts,
        'ignore_sticky_posts' => 1,
        'tax_query'           => $tax_query,
    );

    $related  = '';

    $tax_query = new WP_Query($args);

    if ( $tax_query->have_posts() ) {
        while ( $tax_query->have_posts() ) {
            $tax_query->the_post();

            $do_not_duplicate[] = get_the_ID();

            $count++;

            $title = get_the_title();

            $related .= '<div class="related-post">';

            $related .= '<a href="' . get_permalink() . '" rel="bookmark" title="Permanent Link to ' . $title . '">' . genesis_get_image(array( 'size' => 'related', 'attr' => array( 'class' => 'related-post-image' ) )) . '</a>';

            $related .= '<div class="related-post-info"><a class="related-post-title" href="' . get_permalink() . '" rel="bookmark" title="Permanent Link to ' . $title . '">' . $title . '</a>';

            $related .= '<div class="related-post-date">' . do_shortcode( '[post_date]' ) . '</div>';

            $related .= '<div class="related-post-tags">' . do_shortcode( '[post_tags before="Tags: "]' ) . '</div>';

            $related .= '<div class="related-post-categories">' . do_shortcode( '[post_categories before="Categories: "]' ) . '</div></div>';

            $related .= '</div>';
        }
    }

    wp_reset_postdata();

    $output = array(
        'related' => $related,
        'count'   => $count,
    );

    return $output;
}

Regenerate thumbnails.

Step 2

Add the following in child theme’s style.css:

.related {
    background-color: #fff;
    padding: 40px;
    margin-bottom: 40px;
}

.related a {
    text-decoration: none;
}

.related-post-image {
    vertical-align: top;
}

.related-post-info {
    margin-top: 10px;
    font-size: 15px;
}

.related-title {
    font-size: 13px;
    display: inline-block;
    margin-bottom: 12px;
}

.related-title:before {
    content: "";
    display: block;
    width: 100%;
    min-width: 30px;
    border-top: 1px solid rgba(0,0,0,.2);
    margin-bottom: 1em;
}

.related-post-date {
    font-size: 14px;
    color: #858585;
}

.related-post-tags,
.related-post-categories,
.related-post-tags a,
.related-post-categories a {
    color: #858585;
}

.related-post-tags a:hover,
.related-post-categories a:hover {
    color: #333;
}

.related-post-tags,
.related-post-categories {
    font-size: 13px;
    margin-top: 10px;
    font-style: italic;
}

.related-posts {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
}

.related-posts {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -ms-flex-wrap: wrap;
        flex-wrap: wrap;
    -webkit-box-pack: justify;
        -ms-flex-pack: justify;
            justify-content: space-between;

    display: grid;
    grid-gap: 20px;
    grid-template-columns: 1fr 1fr 1fr;
}

.related-post {
    width: 31.4814814815%;
    opacity: 0.8;
}

.related-post:hover {
    opacity: 1;
}

@supports (grid-area: auto) {
    .related-post {
        width: auto;
    }
}

@media only screen and (max-width: 500px) {
    .related-post {
        width: 100%;
    }

    .related-posts {
        grid-gap: 40px;
        grid-template-columns: 1fr;
    }

    @supports (grid-area: auto) {
        .related-post {
            width: auto;
        }
    }
}