Related Posts without Plugin: A Taxonomy and a few Lines of Code

There are quite a few solutions to relate posts in WordPress. Most of them plugins, adding a post2post table, some using taxonomies or post_metadata. Some days ago, I build a website for one of our clients, who wanted to manually relate posts to each other. The existing plugins didn’t properly match the requirements, so I had to implement related posts without plugin.

My approach was quite simple, I implemented two hooks which are mirroring all published pages in a related-posts-taxonomy, adding a new term for each post that gets published and delete a term when the related post gets removed. First the code to add a related_posts taxonomy, by adding this code to our functions.php:

add_action( 'init', 'register_taxonomy_related_posts' );
function register_taxonomy_related_posts() {
    $labels = array( 
        'name' => _x( 'Related posts', 'related_posts' ),
        'singular_name' => _x( 'Related post', 'related_posts' ),
        'search_items' => _x( 'Search Related posts', 'related_posts' ),
        'popular_items' => _x( 'Popular Related posts', 'related_posts' ),
        'all_items' => _x( 'All Related posts', 'related_posts' ),
        'parent_item' => _x( 'Parent Related post', 'related_posts' ),
        'parent_item_colon' => _x( 'Parent Related post:', 'related_posts' ),
        'edit_item' => _x( 'Edit Related post', 'related_posts' ),
        'update_item' => _x( 'Update Related post', 'related_posts' ),
        'add_new_item' => _x( 'Add New Related post', 'related_posts' ),
        'new_item_name' => _x( 'New Related post', 'related_posts' ),
        'separate_items_with_commas' => _x( 'Separate related posts with commas', 'related_posts' ),
        'add_or_remove_items' => _x( 'Add or remove related posts', 'related_posts' ),
        'choose_from_most_used' => _x( 'Choose from the most used related posts', 'related_posts' ),
        'menu_name' => _x( 'Related posts', 'related_posts' ),

    $args = array( 
        'labels' => $labels,
        'public' => true,
        'show_in_nav_menus' => false,
        'show_ui' => true,
        'show_tagcloud' => false,
        'hierarchical' => true,
        'rewrite' => false,
        'query_var' => true
    register_taxonomy( 'related_posts', array('post'), $args );

Now we have to hook into the save-post-action to add a term to our taxonomy, when a post gets published, or to update a term when a posts title gets changed. We use the posts title as name for the term, which is visible to the user in the taxonomy widget. But since the post-title might not be unique, the relation has to be established via the post-id. That’s why we save the post-id as the terms slug. Add the following code to the functions.php.

add_action( 'save_post', 'add_relatable_post' );
function add_relatable_post( $post_id ) {
	if ( get_post($post_id)->post_status == 'publish' ) {
		if (($term = get_term_by('slug', $post_id, 'related_posts'))) {
			wp_update_term($term->term_id, 'related_posts', array(
				'name' => get_the_title( $post_id ),
				'slug' => $post_id
		} else {
			wp_insert_term( get_the_title( $post_id ), 'related_posts', array(
				'slug' => $post_id

Finally we have to remove a term if its related post gets deleted. This can be done by hooking into the delete_post action, which is triggered when a post gets deleted (not moved to trash).

add_action('delete_post', 'remove_relatable_post', 10 );
function remove_relatable_post( $post_id ) {
	wp_delete_term( get_term_by('slug', $post_id, 'related_posts')->term_id, 'related_posts');

The admin interface is now prepared to relate posts to each other. On every post you see a widget, showing the related_posts taxonomy which should contain a list of all existing posts. Remember, that you have to update existing posts to get them to show up in the taxonomy box. To relate a post to another, you just check the checkbox of the post you want to relate to.

The last thing to do, is to retrieve the related posts in your theme. That is done by a simple taxonomy query in your template files.

if (have_posts()) : while (have_posts()): the_post();
	$related_posts = new WP_Query(array(
		'post_type' => 'post',
		'post_status' => 'publish',
		'tax_query' => array(array(
	        'taxonomy' => 'related_posts',
	        'terms' => get_the_ID(),
	        'field' => 'slug'		

	if ($related_posts->have_posts()) : while ($related_posts->have_posts()): $related_posts->the_post();
		// print your related posts
	endwhile; endif;

endwhile; endif; 
Tagged with:

3 thoughts on “Related Posts without Plugin: A Taxonomy and a few Lines of Code

  1. Just wanted to say: Good post!

    I improved this solution just a little bit by removing the ‘related_posts’ taxonomy from the admin menu (users really shouldn’t touch those terms).

Leave a Reply

Your email address will not be published. Required fields are marked *