# How to add a canonical tag in WordPress and Shopify

> Where WordPress core, Yoast SEO, Rank Math, All in One SEO and Shopify themes print the canonical tag, how to change it for one page or a whole template, and how to fix the duplicates each platform tends to create.

Updated 2026-09-26 · Technical SEO · HTML version: https://getreport.app/guides/canonical-tags-wordpress-shopify

To add a canonical tag in WordPress, you usually don't have to: WordPress core already prints a self-referencing canonical on posts and pages, and an SEO plugin such as Yoast SEO, Rank Math or All in One SEO extends it to every page type and gives each post a Canonical URL field in its Advanced settings. Shopify prints the canonical from the theme's `canonical_url` variable on every page. This guide shows where each platform sets the canonical, how to change it for one page or a whole template, and how to fix the duplicates each platform tends to create. For what the tag does and how Google uses it, read [canonical tags explained](https://getreport.app/guides/canonical-tags-explained).

## Quick answer

- **WordPress core** prints `<link rel="canonical">` on single posts, pages and attachments, but not on the home page blog listing, categories, tags or other archives.
- **Yoast SEO, Rank Math and All in One SEO** replace core's tag, print one on every indexable page type, and add a per-post field: edit the post → SEO box → **Advanced** → **Canonical URL**.
- **Use one SEO plugin.** Two plugins, or a plugin plus a theme that prints its own, give a page two canonicals.
- **Shopify** prints `{{ canonical_url }}` in `theme.liquid`. Variant URLs and products opened inside a collection canonicalise to `/products/handle`. There is no per-page canonical field in the admin.
- **Change the domain in one place:** the WordPress Address and Site Address (Settings → General), or Shopify's primary domain (Settings → Domains).
- **Check the result** with the free [canonical checker](https://getreport.app/tools/canonical-checker), then URL Inspection in Search Console.

## How WordPress sets the canonical tag

### WordPress core, without an SEO plugin

Since WordPress 2.9, core has printed a canonical tag through the `rel_canonical()` function, hooked to `wp_head`. It runs only on singular views (posts, pages, custom post types and attachments) and uses the permalink, adding the comment page number when comments are paginated. Archives, the blog index, search results and the home page when it shows latest posts get no canonical from core.

For a small blog that is often enough. If you want to change the URL core prints, use the `get_canonical_url` filter (available since WordPress 4.6) in a small must-use plugin rather than the theme, so a theme update does not remove it:

```php
<?php
// wp-content/mu-plugins/canonical.php
// Point one post's canonical at another URL, e.g. the original of a syndicated copy.
add_filter('get_canonical_url', function ($url, $post) {
    if ($post->ID === 1234) {
        return 'https://example.com/original-article/';
    }
    return $url;
}, 10, 2);
```

Do not confuse this with WordPress's `redirect_canonical()`, which is a different feature: it redirects visitors from non-standard URLs (such as `?p=123` or a URL without the trailing slash) to the permalink.

### Yoast SEO

Yoast removes core's tag and prints its own on posts, pages, archives, the home page and paginated pages, where each page in a series points to itself.

To set a custom canonical for one post or page:

1. Edit the post or page.
2. Open the **Yoast SEO** box (below the editor or in the sidebar) and choose **Advanced**.
3. Paste the full URL into **Canonical URL**, including `https://`.
4. Update the post.

To change the canonical for a whole template, for example to strip a parameter, use the `wpseo_canonical` filter. Returning `false` removes the tag for that page.

```php
add_filter('wpseo_canonical', function ($canonical) {
    if (is_search()) {
        return false; // no canonical on internal search results
    }
    return $canonical;
});
```

### Rank Math

Rank Math works the same way: it replaces core's tag, prints a canonical on every indexable page, and has a per-post field under **Rank Math** box → **Advanced** tab → **Canonical URL**. For code, the filter is `rank_math/frontend/canonical`:

```php
add_filter('rank_math/frontend/canonical', function ($canonical) {
    return $canonical; // change or return false as needed
});
```

### All in One SEO

All in One SEO has a **Canonical URL** field in the **Advanced** tab of its settings box on each post and page, and a filter, `aioseo_canonical_url`, for template-wide changes.

### Only one plugin, and no theme canonical

Each SEO plugin assumes it is the only one printing head tags. Two active SEO plugins, or a plugin plus a theme or page builder that prints its own canonical, produce two `<link rel="canonical">` tags. When they disagree, Google may ignore both and choose for itself. The fix is to keep one SEO plugin; [running Yoast and Rank Math together](https://getreport.app/guides/duplicate-seo-plugins-yoast-and-rank-math-together) explains how to migrate settings from one to the other.

> **Check: One SEO plugin is active.** Two or more SEO plugins all write titles, descriptions, canonicals and schema. Google gets duplicate or conflicting tags and one of them wins at random.
>
> 1. Keep one SEO plugin and deactivate the other; import its settings first (both Yoast and Rank Math have an import tool).
> 2. Check the page source afterwards for a single title, description and canonical.

To find a theme canonical, search the theme's `header.php` and template parts for `rel="canonical"` or `rel_canonical`. Remove it in a child theme.

### The domain in every WordPress canonical

Every canonical WordPress and its plugins print is built from the **Site Address (URL)** in Settings → General. If that still says `http://` or `www.` after a move, every canonical on the site points at a URL that redirects. Update both addresses to the final `https://` form, then clear any page cache.

## How Shopify sets the canonical tag

### Where it comes from

Every Theme Store theme has this line in `layout/theme.liquid`:

```liquid
<link rel="canonical" href="{{ canonical_url }}">
```

Shopify builds `canonical_url` for every page from the store's primary domain. Two Shopify patterns are handled for you:

| URL a visitor may land on | Canonical Shopify prints |
| --- | --- |
| `/collections/shoes/products/runner-x` | `/products/runner-x` |
| `/products/runner-x?variant=40123` | `/products/runner-x` |

That is correct, and you should not override it. These URLs appear in Search Console as [alternate pages with a proper canonical tag](https://getreport.app/guides/alternate-page-with-proper-canonical-tag), which is expected.

### The primary domain

The canonical uses the domain you set as primary in **Settings → Domains**. Make sure the domain you want indexed, with or without `www`, is primary and that the other domains, including the `.myshopify.com` address, redirect to it.

### Reducing collection-path duplicates

Many themes link from collection pages to `/collections/…/products/…` URLs, using `product.url | within: collection` in the product card snippet. The canonical cleans that up for indexing, but your internal links still point at non-canonical URLs. Replacing `{{ product.url | within: collection }}` with `{{ product.url }}` in the theme's product card makes internal links match the canonical. You lose the collection-aware breadcrumb on the product page in some themes, so check that first.

### Setting a custom canonical on one Shopify page

The Shopify admin has no canonical field. To override it for selected pages, create a metafield and use it in the theme:

1. In **Settings → Custom data → Products** (or Pages, Collections), add a metafield definition, for example `custom.canonical_url`, of type URL.
2. Fill it on the product that needs a different canonical.
3. In `theme.liquid`, replace the canonical line:

```liquid
{%- if product.metafields.custom.canonical_url != blank -%}
  <link rel="canonical" href="{{ product.metafields.custom.canonical_url.value }}">
{%- else -%}
  <link rel="canonical" href="{{ canonical_url }}">
{%- endif -%}
```

Make sure the theme prints only one canonical after the edit, and that apps have not injected another.

## How to check the result

> **Free tool:** [Canonical checker: free canonical tag test](https://getreport.app/tools/canonical-checker): Free canonical checker: see which URL a page declares as canonical, whether it answers 200, and whether redirects, www and the trailing slash agree with it.

The canonical checker reads every canonical tag in the page, so a second one from a theme, plugin or app shows up, and checks that the canonical URL answers 200 without redirecting. It also requests the http and www variants and compares `og:url` with the canonical. It checks one page per run, so test one page per template: the home page, a post or product, a category or collection, and a paginated archive.

> **Check: Canonical tag is present.** Without a canonical URL, search engines may index duplicate versions of this page (with and without trailing slash, with UTM parameters) and split its ranking signals.
>
> 1. Add <link rel="canonical" href="https://your-site.com/page/"> in <head>.
> 2. In WordPress, Yoast or Rank Math add this automatically: check it is not disabled for this page.

> **Check: Canonical tag points to a valid URL.** The canonical tag asks Google to index that URL instead of this one. If it points to another site, appears twice or leads to an error page, your ranking signals are given away or ignored.
>
> 1. Point the canonical at this page's own clean URL (same scheme and host, no tracking parameters), and make sure it returns 200.
> 2. Keep exactly one canonical tag; if a plugin and the theme both add one, disable one of them.

> **Check: og:url matches the canonical URL.** Facebook counts likes and shares per og:url. When it differs from the canonical URL, the counts split between two addresses and the card may link to the wrong version of the page.
>
> 1. Set og:url to exactly the canonical URL of this page, without tracking parameters.
> 2. In WordPress, Yoast and Rank Math derive it from the canonical automatically; check for a hard-coded value in the theme.

Then open URL Inspection in Search Console for a few of the same pages. "User-declared canonical" should show your URL, and after the next crawl "Google-selected canonical" should match it.

## Common mistakes

- **Pasting a relative URL** into the Canonical URL field. Use the full `https://` URL.
- **Setting a custom canonical to "merge" two different pages.** A canonical is for duplicates; for a page that has moved or been merged, use a 301 redirect. See [canonical vs redirect vs noindex](https://getreport.app/guides/canonical-vs-redirect-vs-noindex).
- **Canonical plus `noindex`** on the same page, pointing elsewhere. Pick one.
- **Leaving a custom canonical after the other URL is deleted.** The page then points at a 404 and may drop out of the index.
- **Editing the canonical in the parent theme.** The next update removes it. Use a child theme, an mu-plugin or a theme duplicate in Shopify.
- **Overriding Shopify's product canonical** to include the collection path. It turns one indexable product into many.

## Questions people ask

### Does WordPress add canonical tags automatically?

Yes, on single posts, pages and attachments. WordPress core's `rel_canonical()` prints a self-referencing canonical built from the permalink. It does not add one to the home page blog listing, categories, tags or other archives. An SEO plugin such as Yoast SEO or Rank Math replaces core's tag and adds canonicals to those page types as well.

### How do I change the canonical URL in Yoast SEO?

Edit the post or page, open the Yoast SEO box, choose Advanced and paste the full URL into the Canonical URL field, then update the post. Leave the field empty to keep the default self-referencing canonical. For template-wide changes, such as removing the canonical from search results, use the `wpseo_canonical` filter in a small plugin.

### Can I edit the canonical tag in Shopify?

Not from the admin; Shopify prints it from `canonical_url` in `theme.liquid`, and the default is correct for most stores. To override it for selected pages, add a URL metafield, fill it on those pages, and change the canonical line in the theme to use the metafield when it is set. Keep exactly one canonical tag after the edit.

### Why does my Shopify product have two URLs?

Because many themes link to products through the collection, as `/collections/name/products/handle`, while the product also lives at `/products/handle`. Shopify's canonical on the collection version points to `/products/handle`, so only that one is indexed. To make internal links match, change `product.url | within: collection` to `product.url` in the theme's product card snippet.
