Interlinking Posts in WordPress (Previous Posts from Category)

In this article, I want to share another WordPress function whose task includes displaying previous entries from the category of the current article. The function creates circular interlinking.

One of the feature of this function is that it displays previous entries from the category.

An alternative to this function can be found at this link, where you can specify taxonomy and post type for which interlinking should occur.

I have published a similar function in the comments on the website Dimox.name here. Why "similar"? Because this function has several advantages over the one published on Dimox.name, namely:

  1. It is possible to define the output format, making it very easy to integrate into any template;
  2. There is no need to pre-determine the current category for this function (it will determine it itself), meaning less unnecessary code in the template and simpler for beginners.
  3. The function does not use the heavy WordPress function get_posts().
  4. Classes li1 and li2 are added to each link tag to easily style the list in a zebra pattern.
  5. Caching can be enabled. More details below.
  6. The list is sorted by date, not by ID, so if a post was published at a later date, it will be displayed as required.

Using the Function

Here is the code that needs to be placed in your template file functions.php.

GitHub
<?php
/**
 * Previous posts from the category (relative to the current post) + circular linking
 * Parameters passed to the function. Default values are indicated in parentheses.
 *
 * @param int    $post_num  (5)    Number of links.
 * @param string $format    ('')   Output format: `{thumb} {date:j.M.Y} - {a}{title}{/a} ({comments})`.
 * @param string $cache     ('')   Enable cache (default is off). Write 1 to enable.
 * @param string $list_tag  (li)   List tag.
 * @param string $post_type (post) Type of post we are working with.
 * @param bool   $echo      (true) Output to screen or return for processing (false).
 *
 * @version 1.1
 */
function kama_previous_posts_from_cat( $args ){
	global $post, $wpdb;

	$args = (object) wp_parse_args( $args, [
		'post_num' => 5,
		'format'   => '',
		'cache'    => true,
		'list_tag' => 'li',
		'post_type' => 'post',
		'echo'     => true,
	] );

	$cache_key = md5( __FUNCTION__ . $post->ID );
	$cache_flag = __FUNCTION__;

	if( $args->cache && $cache_out = wp_cache_get( $cache_key, $cache_flag ) ){
		if( $args->echo ){
			return print( $cache_out );
		}

		return $cache_out;
	}

	$cat = get_the_category( $post->ID );
	$cat_id = (int) $cat[0]->term_id;

	$sql_SELECT = "SELECT ID, post_title, post_date, comment_count, guid
	FROM $wpdb->posts p
		LEFT JOIN $wpdb->term_relationships rel ON (p.ID = rel.object_id)
		LEFT JOIN $wpdb->term_taxonomy tax ON (rel.term_taxonomy_id = tax.term_taxonomy_id)";

	$same_AND = $wpdb->prepare(
		"AND tax.term_id = %s AND tax.taxonomy = 'category' AND p.post_status = 'publish' AND p.post_type = %s",
		$cat_id, $args->post_type
	);

	// try to get previous posts
	$sql = "$sql_SELECT WHERE p.ID < $post->ID $same_AND ORDER BY p.post_date DESC LIMIT " . (int) $args->post_num;

	$res = $wpdb->get_results( $sql );

	$count_res = count( $res );

	// if the count is less than required, make a 2nd request
	if( ! $res || $count_res < $args->post_num ){
		$exclude = array_merge( [ $post->ID ], wp_list_pluck( $res, 'ID' ) );
		$exclude = implode( ',', array_map( 'intval', $exclude ) );

		$post_num = (int) $args->post_num - $count_res;

		$sql = "$sql_SELECT WHERE p.ID NOT IN ($exclude) AND p.ID != {$post->ID} $same_AND
		ORDER BY p.post_date DESC LIMIT " . (int) $post_num;

		$res2 = $wpdb->get_results( $sql );

		$res = array_merge( $res, $res2 );
	}

	if( ! $res ){
		return false;
	}

	// output

	if( $args->format ){
		preg_match( '!{date:(.*?)}!', $args->format, $date_m );
	}

	$add_thumb = ( false !== strpos( $args->format, '{thumb}' ) );

	$out = $x = '';
	foreach( $res as $pst ){
		$x = ( $x === 'li1' ) ? 'li2' : 'li1';
		$a1 = '<a href="' . get_permalink( $pst->ID ) . '" title="' . esc_attr( $pst->post_title ) . '">';
		$a2 = "</a>";

		if( $args->format ){
			$date = apply_filters( 'the_time', mysql2date( $date_m[1], $pst->post_date ) );
			$com_count = $pst->comment_count ?: '';

			$formatted = strtr( $args->format, [
				$date_m[0] => $date,
				'{title}' => esc_html( $pst->post_title ),
				'{a}' => $a1,
				'{/a}' => $a2,
				'{comments}' => $com_count,
			] );

			// thumbnail exists
			if( isset( $add_thumb ) ){
				$thumb = get_the_post_thumbnail( $pst->ID, 'thumbnail' );
				$formatted = str_replace( '{thumb}', $thumb, $formatted );
			}
		}
		else{
			$formatted = $a1 . esc_html( $pst->post_title ) . $a2;
		}

		$out .= apply_filters( 'kama_previous_posts_from_cat__append_out',
			"\n<$args->list_tag class=\"$x\">$formatted</$args->list_tag>",
			$args, $formatted, $x, $pst
		);
	}

	if( $args->cache ){
		wp_cache_add( $cache_key, $out, $cache_flag );
	}

	if( $args->echo ){
		return print $out;
	}

	return $out;
}

After successfully copying the code into the theme file functions.php, where you want to display the previous entries from the current category, call the function like this:

<ul>
	<?php kama_previous_posts_from_cat('post_num=5');  ?>
</ul>

That's all you need to do for simple use of the function.

Important! This call will work correctly only in the theme file responsible for displaying posts, usually single.php.

Advanced Usage

For setting the output format, use

You can use the following shortcodes in the format parameter:

  • {thumb} - the post's thumbnail (it must be set for the post);
  • {comments} - will show the number of comments for the article;
  • {title} - the article's title;
  • {date:j.M.Y} - date in the format j.M.Y (11.Apr.2010);
  • {a} and {/a} - link tags, opening and closing.

The call would be like this:

<ul>
<?php
kama_previous_posts_from_cat( array(
	'post_num' => 5,
	'format' => '{a}{title}{/a} - {date:j.M.Y} // {comments}',
) );
?>
</ul>

Will display the list in the format:

<li class='li1'>
	<a href='http://link' title='Article title'>Article title</a> - date // number of comments
</li>
Using Cache

Caching is enabled by default, but you can benefit from using it if the function is called multiple times or if an object caching plugin is enabled: WP File Cache, SJ Object Cache and others...

List Tag

You can change the list tag from li to any other, for example, <div>

<?php kama_previous_posts_from_cat('post_num=5&list_tag=div'); ?>

// will output 5 links in the format - <div class='li1'><a href='http://link' title='Article title'>Article title</a></div>.

Changes

Version 1.0.

  • Added the {thumb} shortcode in the format parameter
  • Now all arguments are passed in the first function parameter, as an array or string.