<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Florin Livada</title>
    <description>The latest articles on DEV Community by Florin Livada (@floliv).</description>
    <link>https://dev.to/floliv</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4090642%2Fcef4067b-c6d8-42d5-abd4-182a8a69f078.png</url>
      <title>DEV Community: Florin Livada</title>
      <link>https://dev.to/floliv</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/floliv"/>
    <language>en</language>
    <item>
      <title>How to Find Which WordPress Plugin Actually Generated a Canonical Tag</title>
      <dc:creator>Florin Livada</dc:creator>
      <pubDate>Sun, 23 Aug 2026 10:08:50 +0000</pubDate>
      <link>https://dev.to/floliv/how-to-find-which-wordpress-plugin-actually-generated-a-canonical-tag-238n</link>
      <guid>https://dev.to/floliv/how-to-find-which-wordpress-plugin-actually-generated-a-canonical-tag-238n</guid>
      <description>&lt;p&gt;Two canonical tags on the same page. WordPress settings look correct. So why is the live HTML different?&lt;/p&gt;

&lt;p&gt;If you manage WordPress sites for clients, you've probably hit this: the SEO plugin settings say one thing, but the actual rendered &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; says another. Multiple plugins, a theme, and a page builder can all end up touching the same tag.&lt;/p&gt;

&lt;p&gt;Here's the debugging approach I use before touching anything in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Check the final rendered &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;, not just the settings screen
&lt;/h2&gt;

&lt;p&gt;View the page source of the live page. The WordPress admin settings show what a plugin &lt;em&gt;wants&lt;/em&gt; to output — not necessarily what actually reaches the browser. Something later in the request can override, duplicate, or strip it.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Identify every component that hooks into &lt;code&gt;wp_head&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nf"&gt;add_action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;'wp_head'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'my_callback'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every plugin, theme, and page builder that touches SEO output does this somewhere. On a stack with 20-30 plugins, more than one usually will.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Trace the callback and its priority
&lt;/h2&gt;

&lt;p&gt;Priority determines execution order, not who "wins" — two callbacks can both print a canonical tag, and the browser just renders both. Query Monitor (free plugin) lists every &lt;code&gt;wp_head&lt;/code&gt; callback with its priority and source file, which turns this from guesswork into a five-minute check.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Find which plugin/theme actually owns the source file
&lt;/h2&gt;

&lt;p&gt;Once you have the file path from Query Monitor, you know the real source — not just the plugin whose settings screen you assumed was responsible.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Test the suspected removal on staging first
&lt;/h2&gt;

&lt;p&gt;Before removing a competing hook in production, verify the change on staging. A tag that looks redundant might be load-bearing for something you haven't checked yet: hreflang, a verification tag, a plugin-specific integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters for migrations
&lt;/h2&gt;

&lt;p&gt;The same method applies when migrating between SEO plugins. "The new plugin imported the settings" and "the live page still outputs everything it used to" are two different questions. Before switching, I'd capture the rendered head of a representative sample of pages — homepage, posts, archives, WooCommerce products, local pages — then diff the same pages after.&lt;/p&gt;

&lt;p&gt;Anything that &lt;em&gt;silently disappears&lt;/em&gt; — canonical, robots directives, OG/Twitter tags, JSON-LD, verification tags, hreflang — is worth investigating. Text changing usually isn't a problem. A tag that vanishes usually is.&lt;/p&gt;

&lt;p&gt;I'm curious how other people managing multi-plugin WordPress stacks handle this today: disable candidates one by one, rely on Query Monitor, inspect hooks manually, or something else entirely?&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I build &lt;a href="https://livada.io/livada-seo/" rel="noopener noreferrer"&gt;Livada SEO&lt;/a&gt;, a WordPress SEO plugin. This exact debugging process is what led us to build tag-level attribution directly into the plugin — happy to go into more detail if useful.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>seo</category>
      <category>php</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
