# Related Items From the Same Category for Any Post Type

> Shows up to three other items that share a category or tag below single custom post type entries, such as related recipes, services or case studies.

- Type: PHP
- Runs: Frontend only
- Category: [Custom Post Types & Fields](https://wpide.com/library/category/post-types/)
- Tags: related, custom-post-types, internal-links
- Author: WPIDE Team
- Installs: 0
- Updated: 2026-10-28
- Page: https://wpide.com/library/related-items-same-term/

## Code

```php
// Post types that get related items, how many, and the heading.
$wpide_related_types   = array( 'recipe', 'case_study', 'service' );
$wpide_related_count   = 3;
$wpide_related_heading = 'You may also like';

add_filter( 'the_content', function ( $content ) use ( $wpide_related_types, $wpide_related_count, $wpide_related_heading ) {
    if ( ! is_singular( $wpide_related_types ) || ! in_the_loop() || ! is_main_query() ) {
        return $content;
    }

    $post = get_post();
    $key  = 'wpide_related_' . $post->ID . '_' . get_option( 'wpide_related_ver_' . $post->post_type, '1' );
    $ids  = get_transient( $key );

    if ( false === $ids ) {
        $tax_query = array( 'relation' => 'OR' );

        foreach ( get_object_taxonomies( $post->post_type, 'objects' ) as $taxonomy ) {
            if ( ! $taxonomy->public ) {
                continue;
            }

            $terms = wp_get_object_terms( $post->ID, $taxonomy->name, array( 'fields' => 'ids' ) );

            if ( $terms && ! is_wp_error( $terms ) ) {
                $tax_query[] = array( 'taxonomy' => $taxonomy->name, 'terms' => $terms );
            }
        }

        $ids = count( $tax_query ) > 1 ? get_posts( array(
            'post_type'      => $post->post_type,
            'posts_per_page' => $wpide_related_count,
            'post__not_in'   => array( $post->ID ),
            'tax_query'      => $tax_query,
            'fields'         => 'ids',
            'no_found_rows'  => true,
        ) ) : array();

        set_transient( $key, $ids, DAY_IN_SECONDS );
    }

    if ( ! $ids ) {
        return $content;
    }

    $list = '';

    foreach ( $ids as $id ) {
        $list .= '<li><a href="' . esc_url( get_permalink( $id ) ) . '">' . esc_html( get_the_title( $id ) ) . '</a></li>';
    }

    return $content . '<nav class="related-items" aria-label="' . esc_attr( $wpide_related_heading ) . '"><h2>' . esc_html( $wpide_related_heading ) . '</h2><ul>' . $list . '</ul></nav>';
} );

add_action( 'clean_post_cache', function ( $post_id, $post ) use ( $wpide_related_types ) {
    if ( $post && in_array( $post->post_type, $wpide_related_types, true ) ) {
        update_option( 'wpide_related_ver_' . $post->post_type, (string) microtime( true ), false );
    }
}, 10, 2 );
```

## Notes

Set the post types and heading. Each list is cached for a day and refreshed when content of that type changes.

## How to use it

Install the free WPIDE plugin (https://wordpress.org/plugins/wpide/), find "Related Items From the Same Category for Any Post Type" in its snippet library and add it in one click; or create a new PHP snippet in WPIDE (or any code snippets plugin) and paste the code above. More snippets: https://wpide.com/library/
