Article No. 65
Platform-Specific Canonical Setup: WordPress, Shopify & Server-Level Configuration
Abstract
Canonical tags are a hint, not a directive, and the mechanics of what a canonical tag does are covered in full elsewhere on this site. This post is the applied...
On this page
- WordPress: What Core Already Does
- Yoast SEO
- Rank Math
- Choosing Between Core, Yoast, and Rank Math
- WooCommerce and Custom Post Types
- WooCommerce Attribute and Variation Pages
- Common WordPress Canonical Bugs
- Shopify
- Shopify Duplicate-Content Scenarios
- Server-Level Implementation for Custom or Other Platforms
- WordPress Plugin Comparison at a Glance
- Testing Per Platform
- Platform Migration Basics
- Checklist
- Conclusion
- Related:
Canonical tags are a hint, not a directive, and the mechanics of what a canonical tag does are covered in full elsewhere on this site. This post is the applied companion: you’re on a specific platform, and you need to know exactly what to click, what already works by default, and what’s likely to break. It covers WordPress (core behavior, Yoast, Rank Math, WooCommerce), Shopify, and server-level configuration for everything else (Apache, Nginx, IIS).
WordPress: What Core Already Does
WordPress has shipped a basic, automatic self-referencing canonical tag since WordPress 2.9, released in December 2009. The function responsible, <a href="https://developer.wordpress.org/reference/functions/relcanonical/”>rel_canonical(), is hooked into wp_head() and outputs a canonical tag for singular content (posts and pages) automatically, with no plugin required. This is worth stating precisely because it’s frequently misdated in SEO content; the self-referencing canonical in WordPress core is not a recent addition, it’s been there for over a decade.
A related function, <a href="https://developer.wordpress.org/reference/functions/wpgetcanonicalurl/”>wp_get_canonical_url(), which returns the canonical URL for a given post so themes and plugins can reference it programmatically, was introduced in WordPress 4.6. That’s a separate, later addition from the core self-referencing tag itself, and the two dates shouldn’t be conflated.
What core’s built-in canonical does not handle well: archive pages, custom post type edge cases, and any scenario where you need the canonical to point somewhere other than the page’s own URL. That’s what SEO plugins are for.
Yoast SEO
Yoast adds a manual override at the post, page, and taxonomy level. In the block editor, open the Yoast SEO sidebar panel, go to the Advanced tab, and there’s a Canonical URL field. Leaving it blank keeps WordPress core’s self-referencing default; entering a full URL (including protocol and domain, not a relative path) overrides it. This applies the same way to categories, tags, and other taxonomy terms through the same panel. Yoast’s own documentation covers the field directly.
Rank Math
Rank Math follows a similar pattern: open the Advanced tab in the Rank Math meta box on a post or page (if the Advanced tab isn’t visible, it needs to be enabled from Rank Math’s dashboard settings first), and there’s a Canonical URL field. Per Rank Math’s knowledge base, the field shows the post’s own URL as a placeholder by default, and even without manually setting anything, Rank Math will canonical the page to itself, consistent with the self-referencing default described in this cluster’s core canonical guide.
Choosing Between Core, Yoast, and Rank Math
Running WordPress core’s default canonical output alongside an active SEO plugin isn’t usually a conflict, since both Yoast and Rank Math are designed to take over and manage the canonical tag once activated, rather than leaving core’s rel_canonical() output in place alongside their own. The practical risk isn’t core versus plugin, it’s two SEO plugins active at once (a leftover Yoast installation still active after switching to Rank Math, for instance), which can genuinely produce duplicate or conflicting canonical tags in the rendered <head>. If a site has switched SEO plugins at any point, that’s worth checking directly with view-source rather than assuming the old plugin was fully deactivated everywhere.
WooCommerce and Custom Post Types
WooCommerce products are a custom post type, and they inherit WordPress’s and the active SEO plugin’s default self-referencing canonical behavior, which mostly works out of the box for a product with one canonical URL. The real complication is when a product is assigned to more than one category. WooCommerce can generate multiple valid paths to the same product (one per category it belongs to), and without intervention, some of those paths can compete for canonical status. In Yoast, this is handled through the primary category setting on the product edit screen: designating one category as primary tells Yoast to use that category’s path when constructing the canonical URL, consolidating the multiple paths into one signal regardless of how many categories the product is actually assigned to. The same underlying problem (filter and sort parameters generating additional URL variants on category and shop pages) is a parameter-handling question, not a WordPress-specific one, and gets fuller treatment in the parameter-strategy post in this cluster.
WooCommerce Attribute and Variation Pages
Beyond multi-category products, WooCommerce stores using product attributes (size, color, material) as filterable taxonomy terms can generate an additional layer of URL variants: attribute archive pages and attribute-filtered product listings. Rank Math’s documentation on this describes handling canonical output automatically across product, category, and attribute pages, consolidating the filtered combinations back toward the base listing rather than leaving each filter combination to compete as its own indexable URL. The general principle carries over directly from the parameter-strategy guidance elsewhere in this cluster: a filter combination with real, independent search demand can be worth leaving indexable on its own; the much larger set of narrow, low-demand combinations should canonical back to the base category or attribute listing instead of each generating a separate canonical target.
Common WordPress Canonical Bugs
- Wrong URL after a migration. Canonical tags cached in a page builder or hardcoded during a domain move can keep pointing at the old domain. Check this directly with view-source after any migration, don’t assume the SEO plugin re-generated it automatically.
- Duplicate canonical tags. If both WordPress core’s default output and a theme or plugin are independently inserting a
<link rel="canonical">, a page can end up with two conflicting tags in the<head>. Search the rendered HTML forrel="canonical"and confirm there’s exactly one. - Canonical pointing to a noindexed or 404 page. Usually the result of a stale manual override left in an SEO plugin’s field after the target page was deleted or restructured.
- Pagination canonicals set to page 1. A common but incorrect pattern on paginated archives; each paginated page should canonical to itself, not to the first page. This is covered in full in the pagination-specific post in this cluster.
Shopify
Shopify includes a canonical tag automatically, generated through the theme’s theme.liquid layout file, with no manual setup required for the default behavior to work. The default behavior: product pages canonical to their clean /products/product-handle URL regardless of which collection a shopper reached them through, and variant URLs (?variant=12345) canonical back to the base product page rather than being treated as separate indexable pages.
The scenario that catches stores off guard is what’s sometimes called the collection-aware URL problem. Shopify can generate two valid paths to the same product: a direct product URL (/products/blue-widget) and a collection-aware URL (/collections/summer-sale/products/blue-widget). If a theme’s product grid or internal linking consistently uses the collection-aware format, and the canonical tag in theme.liquid isn’t correctly pointing to the direct product URL, the two paths can end up competing rather than consolidating.
Theme-safety note: the canonical tag lives inside theme code, accessible through Online Store > Themes > Actions > Edit Code. This is a place where a well-intentioned manual fix can do real damage if it’s not scoped correctly. A change to theme.liquid affects every page rendered by that theme, so a canonical tag edit that works for product pages but wasn’t tested against collection, blog, and static pages can break the automatic behavior sitewide rather than fixing an isolated issue. Test changes on a duplicate/preview theme before publishing to the live theme, and check final output with view-source on a representative sample of page types, not just the one page the fix was intended for.
A specific version of this risk worth flagging directly: a common (and understandable) instinct when a merchant notices the collection-aware URL problem is to manually hardcode the canonical <link> in theme.liquid to always point at /products/{{ product.handle }}. Done carelessly, on a theme where the same snippet of code also renders on collection or search-result pages, that same hardcoded logic can output an incorrect canonical on pages that were never meant to canonical to a product URL at all. The safer pattern is to scope any manual canonical logic explicitly to the template it’s meant for (Shopify’s Liquid templating supports checking the current template type), rather than editing a single shared snippet that renders across multiple page types.
Shopify Duplicate-Content Scenarios
- Filters and sorting. Faceted collection views (
?sort_by=price-ascending, filter combinations) generate additional URLs for what’s substantively the same collection content; these should canonical back to the base, unfiltered collection URL in most cases. - Variants. As noted above, handled automatically by Shopify’s default canonical behavior; the main risk is a theme customization that inadvertently overrides it.
- Multi-channel listings. Products that also sync to other Shopify sales channels are a separate distribution question, not a canonical one; canonical tags only govern what’s indexed from the storefront itself.
Server-Level Implementation for Custom or Other Platforms
For sites not running WordPress or Shopify, or for non-HTML files (PDFs, documents) that can’t carry an HTML <link> tag, canonical signals are set through the HTTP Link response header at the server level.
Apache (.htaccess). The Header directive, combined with mod_headers, adds the Link header to matching responses. A typical PDF-targeting rule scopes the header to files with a .pdf extension using <FilesMatch>, so it applies only to the intended file type rather than every response the server handles:
<FilesMatch ".pdf$">
Header add Link '<https://example.com/whitepaper/>; rel="canonical"'
</FilesMatch>
Nginx. Nginx doesn’t use .htaccess; the equivalent configuration goes directly into the server block using the add_header directive, scoped to the relevant location block for the file type or path in question:
location ~* .pdf$ {
add_header Link '<https://example.com/whitepaper/>; rel="canonical"';
}
IIS (web.config). On Windows/IIS, custom response headers, including a Link header for canonical purposes, are configured through the <customHeaders> section under <httpProtocol> in web.config, similarly scoped to the relevant path or file type:
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Link" value='<https://example.com/whitepaper/>; rel="canonical"' />
</customHeaders>
</httpProtocol>
</system.webServer>
In all three cases, the actual syntax is server-specific, but the underlying header format Google reads (Link: <URL>; rel="canonical") is identical. Scope any of these rules as narrowly as possible; applying a Link header rule too broadly (matching an entire directory instead of a specific file type) can end up sending the same canonical URL on responses it was never meant to apply to.
The implementation syntax differs by server, but the underlying rule from the core canonical guide still applies here without exception: don’t run the HTTP header method and an HTML <link> tag on the same resource pointing at different URLs, and where a resource can carry an HTML tag at all, that’s still the default, recommended path. The HTTP header method exists specifically for the non-HTML cases where an HTML tag isn’t an option.
WordPress Plugin Comparison at a Glance
| WordPress core | Yoast SEO | Rank Math | |
|---|---|---|---|
| Self-referencing canonical by default | Yes, since WP 2.9 (2009) | Yes | Yes |
| Manual override field | No | Advanced tab, per post/page/term | Advanced tab, per post/page (enable Advanced Mode first if hidden) |
| Programmatic access | <!–INLINECODE36–>, since WP 4.6 | Uses core function, extends for plugin-specific logic | Uses core function, extends for plugin-specific logic |
| WooCommerce category consolidation | Not handled | Primary category setting | Automatic canonical handling across product/category/attribute pages |
This isn’t a recommendation to run more than one of these at a time. The comparison is here to make clear what’s already covered by WordPress itself before reaching for a plugin setting, since a lot of “how do I set a canonical tag in WordPress” confusion comes from not realizing core already does the baseline work automatically.
Testing Per Platform
Regardless of platform, the same three checks apply:
- View-source. Confirm exactly one
rel="canonical"tag (or oneLinkheader) is present, pointing at the expected absolute URL, with no duplicates and no relative paths. - Google Search Console URL Inspection. Compare the “user-declared canonical” field against the “Google-selected canonical” field. A mismatch means Google is overriding the stated signal, worth investigating rather than assuming the tag is doing its job just because it’s present.
- Site crawler (Screaming Frog or similar). A full-site crawl surfaces canonical tags at scale, catching template-level bugs (a theme change that broke canonical output across an entire post type or collection) that spot-checking individual pages would miss.
Platform Migration Basics
Moving between WordPress and Shopify (in either direction) means every canonical tag needs to be regenerated against the new platform’s URL structure, not carried over from the old one. The practical sequence: map old URLs to new ones, set up 301 redirects for the permanent URL changes, and only then verify canonical tags are self-referencing correctly on the new platform rather than still pointing at old-domain or old-path URLs left over from an incomplete migration. Skipping the verification step is the most common way a migration quietly breaks canonical signals that looked fine in a pre-launch check.
A specific migration trap worth naming directly: WordPress product URLs typically follow a /product/product-name/ or category-based pattern, while Shopify’s default is /products/product-handle. If the redirect map is built off the old URL structure but the new platform’s canonical tags are still generating output based on assumptions carried over from the old CMS (a common issue when a migration tool partially preserves old metadata), a site can end up with 301 redirects pointing correctly at new URLs while those same new URLs carry canonical tags pointing somewhere else entirely. The two systems, redirects and canonical tags, need to be checked as a pair after any migration, not assumed to be in sync just because one of them was configured correctly.
Checklist
- WordPress: confirm which layer is setting the canonical (core default, Yoast, or Rank Math) and that only one is active
- WordPress: verify
wp_get_canonical_url()output matches expectations for custom post types, not just standard posts/pages - WooCommerce: set a primary category on multi-category products to consolidate canonical paths
- Shopify: confirm
theme.liquidcanonical output resolves to direct product URLs, not collection-aware paths - Shopify: test any theme code edit against product, collection, blog, and static page templates before publishing live
- Server-level (Apache/Nginx/IIS): scope the
Linkheader to the intended file type or path, and confirm it isn’t running alongside a conflicting HTML tag - Any platform: recheck canonical output after a migration, don’t assume it carried over correctly
Conclusion
The mechanics of a canonical tag are the same everywhere; what changes by platform is where the setting lives and what already works by default without you touching anything. WordPress core has handled basic self-referencing canonical since 2009, with Yoast and Rank Math adding manual overrides at the Advanced tab level. Shopify handles the common cases (variants, collection-aware duplicate paths) automatically through theme.liquid, with theme edits being the main place manual changes can go wrong. Everything else routes through server-level HTTP headers, useful both for non-HTML files and for platforms with no built-in canonical handling at all.