Canonical Tags in WordPress: How to Fix Duplicate Content the Right Way

Take one article on a WordPress site and count the URLs it answers on. There is the permalink, the same permalink with ?utm_source=newsletter, the ?replytocom= variant after someone replies to a comment, the /index.php/ form some hosts still serve, the http:// version, and often a category archive that lists the same excerpt. Six URLs, one page of content. Google picks one and calls the rest duplicates.

The instinct is to paste rel="canonical" somewhere and consider it handled. That instinct is half right. A canonical tag is the correct tool for part of this problem and the wrong tool for the rest, and Google is explicit that it is a preference rather than an instruction: in its canonicalization documentation, “indicating a canonical preference is a hint, not a rule.”

So the work is not adding a tag. It is deciding, for each duplicate pattern, whether the extra URL should exist at all.

What a Canonical Tag Actually Does

A canonical tag tells Google which URL is the original when several URLs serve substantially the same content:

<link rel="canonical" href="https://example.com/green-dresses/" />

It does three things and only three:

  • Suggests which URL should be treated as primary
  • Consolidates ranking signals toward that URL
  • Reduces crawl waste, because duplicates get crawled less often once clustered

It does not remove the duplicate from the index, does not block anything, and does not guarantee Google will agree. Google’s own guidance says the canonical page gets crawled most regularly and duplicates less frequently — that is the benefit, not deletion.

Three implementation rules come straight from Google’s consolidate duplicate URLs page and get skipped constantly:

  1. The canonical URL must be indexable. If it 404s, redirects, or carries noindex, the hint fails.
  2. Use absolute URLs. Relative paths work, but Google doesn’t recommend them — the documented failure case is a testing site that unintentionally gets crawled and starts pointing canonicals at itself.
  3. Put a self-referencing canonical on the canonical page. The page you point everything at should canonically point at itself. Otherwise you have created an open question.

The Decision That Comes Before the Tag

Every duplicate in WordPress falls into one of three buckets, and each has a different fix. Getting this order wrong is why “I added canonicals and nothing changed” happens.

SituationFixWhy
The second URL should not exist301 redirectRemoves the duplicate instead of describing it
The second URL must existCanonical tagConsolidates while keeping the URL functional
The page should not be in search at allnoindexBlocks indexing entirely, not just consolidation

The rule in one line: redirect when the duplicate is an accident, canonicalise when it is a necessity, noindex when the page has no business ranking.

And the one thing never to do: use robots.txt for this. Blocking a URL in robots.txt stops Google from crawling it, which also stops Google from reading the canonical tag you put on it. You end up with an uncrawled duplicate and no signal.

The Duplicates WordPress Creates on Its Own

WordPress is generous with URLs. These are the ones worth checking on any site, in rough order of how often they cause trouble.

Trailing slash and case variants. WordPress’s redirect_canonical() handles the slash mismatch with a 301, so /post and /post/ usually converge on their own. It does not fix everything, and it can conflict with a server rule that does the opposite.

www versus non-www, and http versus https. These belong at the server level, as 301s, not as canonicals. Two hostnames serving the same site is a configuration problem; a canonical tag merely asks Google to ignore one of them. If you are chasing redirect loops while doing this, our guide to fixing “too many redirects” in WordPress covers the usual culprits.

Query strings. ?utm_*, ?replytocom=, ?cpage=, ?orderby=, ?filter_* — tracking and sorting parameters that produce the same content. These are the legitimate canonical case: the URL must keep working for the visitor, but the content is identical.

?p=123 and /index.php/ forms. Shortlinks and hosts that don’t have pretty permalinks configured cleanly. Redirect these rather than canonicalise them; nobody needs two working addresses for one post.

Attachment pages. Upload an image inside a post and WordPress can generate a standalone attachment page for it — a thin page with the image and little else. Either redirect these to the parent post or the file, or noindex them. They are the classic “hundreds of duplicates appeared overnight” cause on image-heavy blogs.

Search results and author archives. ?s= result pages and thin author archives are near-infinite duplicate generators. noindex them. They are not pages you want ranking.

Paginated archives. Pages 2, 3, and 4 of a category are not duplicates of page 1, and Google no longer uses rel="next"/rel="prev". Give each page a self-referencing canonical, not a canonical pointing back to page 1.

Fix 1: Redirect What Shouldn’t Exist

Start here, because every redirect you add is one fewer canonical Google has to interpret.

In functions.php or a site-specific plugin, the shortlink and attachment cases are a few lines. For attachments, the common pattern is to redirect the attachment page to its parent post:

add_action( 'template_redirect', function () {
    if ( is_attachment() ) {
        $parent = wp_get_post_parent_id( get_queried_object_id() );
        if ( $parent ) {
            wp_safe_redirect( get_permalink( $parent ), 301 );
            exit;
        }
    }
} );

For host-level variants, do it in .htaccess or the Nginx config, not in PHP — the redirect should happen before WordPress loads.

Test with headers rather than by clicking around:

curl -sI https://example.com/post | head -n 3

A 301 with a Location pointing at the canonical URL is what you want. A 200 means nothing redirected.

Fix 2: Canonicalise What Must Stay

For parameter variants, the canonical belongs on the page itself, pointing at the clean URL:

<link rel="canonical" href="https://example.com/green-dresses/" />

Two things make this work in practice. First, the clean URL must return 200 and be indexable — check it, don’t assume. Second, the same canonical must appear on every variant, including the ones you forgot exist: the made-up ?utm_campaign= someone pasted into a newsletter, the ?replytocom= link in your comment emails.

That second point is why hand-managing canonicals for parameters is a losing game. A rule at the template level beats a per-post field, because the per-post field only exists on the post you remembered to edit.

Fix 3: Where the Tag Comes From in WordPress

There are three sources, and they can conflict.

WordPress core. rel_canonical() is hooked to wp_head and outputs a canonical link — but only on singular views. It returns early on archives, the blog index, and search results, which is why a bare WordPress install has no canonical on category pages at all. The function uses get_canonical_url(), which is filterable, and the whole thing is documented in the reference for rel_canonical().

An SEO plugin. Yoast, Rank Math and similar tools output canonicals for every indexable page type, plus a per-post override under an Advanced panel. If you are comparing options, our comparison of top WordPress SEO plugins covers which ones expose the field and how aggressively they rewrite it.

Your theme. Occasionally a theme hardcodes a canonical in header.php. This is the worst case, because it produces a second tag that contradicts the plugin’s.

If you need full control, remove core’s output and take over:

remove_action( 'wp_head', 'rel_canonical' );

Do that only when something else is reliably providing the tag. Removing it and providing nothing is worse than leaving it.

Then verify what actually renders, because this is where duplicate tags surface:

curl -s https://example.com/post/ | grep -o 'rel="canonical"[^>]*'

One line is correct. Two lines mean two systems are writing the tag, and Google will treat the pair as contradictory and fall back to its own judgment.

Fix 4: Read the Three Search Console Statuses Properly

The Page indexing report uses three phrases that sound similar and mean very different things.

StatusWhat it meansWhat to do
Alternate page with proper canonical tagGoogle accepted your canonicalNothing. This is success
Duplicate without user-selected canonicalYou never named a canonicalAdd one, or redirect the duplicate
Duplicate, Google chose different canonical than userGoogle overrode your choiceFind the conflicting signal

The third one is the one people panic about, and it is the most informative. Google does not override a canonical for fun. It does it when the target you named is a weaker candidate: noindexed, redirected, blocked in robots.txt, slower, or thinner than the page you were trying to demote. Fix the target, and the status usually resolves on the next crawl.

That is also why the “Duplicate without user-selected canonical” status is not automatically a problem. If the duplicates are parameter URLs that nobody links to, Google choosing one of them as canonical costs you nothing. Fix what has traffic, ignore the rest.

The Mistakes That Break Canonicals

A sitewide canonical pointing at the homepage. Usually a template bug or a plugin setting applied globally. Every post then declares the homepage as its original, and Google has to ignore all of it. Check three random posts with the curl command above — if they all return the same URL, this is your problem.

Pointing a canonical at a noindex page. The two instructions fight, and noindex wins. Google’s guidance is direct: it does not recommend using noindex to control canonical selection “because it will completely block the page from Search.” Pick one intent per URL.

Canonical chains. A canonicalises to B, B canonicalises to C. Google may follow it, but every hop dilutes the signal. Point A straight at C.

A canonical and a 301 on the same URL. Two instructions for one problem. If the URL redirects, the canonical is never read. Choose one.

Multiple canonical tags. Covered above, but worth repeating: plugin plus theme is the usual cause.

Canonicals on error pages. A 404 or 410 should not carry a canonical. The status code is the instruction.

Canonicalising paginated pages to page 1. It tells Google that pages 2+ are duplicates, which they are not, and it can remove genuinely distinct content from consideration. Self-canonical each page.

A Ten-Minute Canonical Audit

  1. Pick five URLs: the homepage, a post, a category, a tag archive, a paginated archive
  2. For each, run curl -s <url> | grep -o 'rel="canonical"[^>]*'
  3. Confirm exactly one tag per page
  4. Confirm it is absolute (https:// and full host)
  5. Confirm the target returns 200 — curl -sI <canonical> | head -n 1
  6. Confirm the target is not noindexed
  7. Copy the URL into Search Console’s URL Inspection and check the reported canonical
  8. Only then look at the Page indexing report for anything labelled “Duplicate”

That sequence catches the four failures that account for most broken canonical setups — missing, duplicated, relative, or pointing at a dead target.

When a Canonical Won’t Save You

A canonical consolidates URLs, not content quality. If three of your posts genuinely say the same thing, tagging them as one canonical does not make the survivor better; the right move is to merge them into one stronger page and 301 the rest. That is a content decision, and the ranking consequences are covered in our 12-month review of what moves WordPress rankings.

The same applies to syndicated copies on other domains. Cross-domain canonicals are legitimate and Google supports them, but they only work if the other site cooperates. You cannot canonicalise your way to owning a copy someone else publishes.

If the broader picture is still noisy — indexing gaps, thin archives, canonical conflicts — run through the WordPress SEO checklist and the explainer on how Google indexes a WordPress site before adding more tags. Canonicals are a cleanup tool, not a growth tool.

FAQ

Does WordPress add canonical tags by default?

Partly. Core’s rel_canonical() outputs a self-referencing canonical on singular posts and pages. It does nothing on category, tag, author, or search archives, which is why most sites rely on an SEO plugin to cover the rest.

Should every page have a self-referencing canonical?

Yes, for indexable pages. Google recommends it explicitly: the page you designate as canonical should carry a canonical link pointing at itself. Sitemap entries are read as canonical suggestions too, so keep the sitemap and the tags consistent.

Canonical tag or 301 redirect — which should I use?

If the duplicate URL should not exist at all, use a 301. If it must keep working for visitors but has the same content, use a canonical. Canonical tags consolidate signals; redirects remove the duplicate. Using a canonical where a redirect belongs leaves a duplicate live and crawlable.

Do canonical tags fix duplicate content?

They consolidate it. The duplicate URLs still resolve and can still be crawled, but signals collect on the canonical page and duplicates are crawled less often. If you need the duplicate gone from the index, that is a redirect or noindex decision, not a canonical one.

Why does Search Console say Google chose a different canonical?

Because the URL you nominated looked like a weaker candidate — often noindexed, redirected, blocked in robots.txt, or thinner than the page you wanted demoted. Google treats a canonical as a hint. Fix the target’s status and signals, then request a recrawl.

Can I add canonical tags without an SEO plugin?

Yes. WordPress core already does it for singular content, and get_canonical_url() is filterable if you need custom logic. The trade-off is that you also inherit responsibility for archives, parameter variants, and pagination — which is most of the work.

Do canonical tags work across domains?

They can. Google supports cross-domain canonicals for syndicated copies, so a version published elsewhere can point at your original. It only works if the other site adds the tag, and Google may still choose differently.

A WP Life
A WP Life

Hi! We are A WP Life, we develop best WordPress themes and plugins for blog and websites.