SEO PHP Intermediate

Add Canonical URL to Custom Post Type Archives

Last updated: May 6, 2026

A canonical URL tag tells search engines which version of a page is the authoritative one. On standard posts and pages, most SEO plugins output this automatically. However, many of those same plugins have historically missed or inconsistently handled custom post type archive pages, the URLs like /snippets/ or /portfolio/ that list all posts of a given type. Without a canonical on these pages, you may end up with multiple crawlable variations being treated as separate URLs, particularly when pagination, sorting parameters, or UTM tags get appended.

This snippet adds a self-referencing canonical link tag specifically on custom post type archive pages, running at wp_head priority 1 so it appears near the top of the head before most other tags.

The Code

Add this to your functions.php or a site-specific plugin. It only fires on post type archive pages and exits early for everything else.

How It Works

The is_post_type_archive() check ensures this only runs on archive pages registered via register_post_type() with has_archive set to a slug or true. It doesn’t affect standard posts, pages, categories, tags, or single post templates.

get_query_var( 'post_type' ) retrieves the current post type. In rare configurations this can return an array, so the snippet normalises it to a string using reset().

The $obj->has_archive check is important, it confirms the post type was actually registered with an archive before attempting to generate the archive link. Post types registered with has_archive => false have no archive URL to link to and would return an incorrect value from get_post_type_archive_link().

The canonical URL is output using esc_url() for proper sanitisation. The hook priority of 1 ensures it runs before most SEO plugin output, so if your SEO plugin later outputs its own canonical for this page type, it will simply overwrite this one, no conflicts arise.

Do I Need This If I Have an SEO Plugin?

It depends on the plugin. SlimSEO handles canonicals for CPT archives correctly. Yoast and RankMath do as well in most configurations. However, if you’re on a lightweight setup or a custom SEO implementation, it’s worth checking your CPT archive pages using a tool like Ahrefs’s Site Audit or by simply viewing source on your archive URL and searching for rel="canonical". If it’s missing, this snippet fills the gap cleanly and adds no overhead when a canonical is already present.

Paginated Archives

Note that this snippet always outputs the base archive URL as the canonical, regardless of which page of the archive the visitor is on. For example, /snippets/page/2/ would receive a canonical pointing to /snippets/. This is a deliberate choice, paginated archive pages are rarely worth indexing independently, and consolidating their signals to the root archive URL is generally the correct approach for most sites.

functions.php
add_action( 'wp_head', function() {
    if ( ! is_post_type_archive() ) return;

    $post_type = get_query_var( 'post_type' );
    if ( is_array( $post_type ) ) {
        $post_type = reset( $post_type );
    }

    $obj = get_post_type_object( $post_type );
    if ( ! $obj || ! $obj->has_archive ) return;

    $canonical = get_post_type_archive_link( $post_type );
    if ( $canonical ) {
        echo '<link rel="canonical" href="' . esc_url( $canonical ) . '">' . "\n";
    }
}, 1 );

Built by Nahnu Plugins

Need something more powerful than a snippet?

Our commercial plugins go further, built for serious WordPress sites with full support, updates, and documentation included.

Browse All Plugins →

This website uses cookies to enhance your browsing experience and ensure the site functions properly. By continuing to use this site, you acknowledge and accept our use of cookies.

Accept All Accept Required Only