Cocoon の Canonical を安全に無効化して“正しい1本だけ”を出す手順(muプラグイン方式)

パソコン

まさか <link rel="canonical"> の原因がテーマ(Cocoon)だったなんて…という方向けの、**再現→原因→安全な直し方(可逆・少変更)**をまとめました。WordPress 標準や GSC(Google Search Console)の挙動にも馴染む形で、“ページに1本だけ、自己参照

の canonical” を安定して出すのがゴールです。

テーマ名:Cocoon バージョン:2.8.8 が今回のテーマ

要約(最短ルート)

  • Cocoon は wp_head自前の canonical を出力します。
  • これが フィード/AMP/404 でも出てしまう・重複して2本以上出るなどで GSC の評価が不安定になることがあります。
  • MU プラグインで Cocoon の canonical を止め、自前の安全版 canonical を 1 本だけ出せば安定します(テーマ更新にも強い・可逆)。

症状の例

  • GSC で「代替ページ(適切な canonical タグあり)」「ページにリダイレクトがあります」が増える
  • フィード (/feed/)、AMP、404 にも canonical が出ている
  • 1ページ内に canonical が 2本以上 出ている
  • curl で見るとカテゴリを指す 誤った canonical が混ざる

原因の概要(Cocoon の canonical 出力)

Cocoon テーマでは lib/seo.php 内で以下のように canonical を出力しています:

// 例:テーマ内(概念図)
add_action( 'wp_head', 'generate_canonical_tag' );

この実装は便利ですが、条件分岐がサイト運用の方針とズレると、

  • フィード/AMP/404にも出てしまう
  • ほかのプラグイン/自作コードと 重複 する
    …などが起きえます。

解決策:MU プラグインで“止めて、出す”

mu-plugins はテーマや通常プラグインより早く読み込まれるため、テーマ更新の影響を受けにくいのが利点です。

スポンサーリンク

1) Cocoon の canonical を無効化(remove_action)

wp-content/mu-plugins/disable-cocoon-canonical.php を作成:

<?php
/*
Plugin Name: Disable Cocoon Canonical (MU)
Description: Cocoon の canonical 出力を安全に停止する。
*/ // テーマが初期化された後に、Cocoon のフックを外す
add_action('after_setup_theme', function(){ // Cocoon が wp_head にぶら下げている関数名 remove_action('wp_head', 'generate_canonical_tag');
}, 100);

ポイント

  • after_setup_theme の**遅め(100)**で実行すると、確実にフックを外せます。
  • テーマ側の関数名が変わると効かないので、アップデート後に再確認を。

2) 安全版 canonical を“1本だけ”出力

wp-content/mu-plugins/safe-canonical.php を作成:

<?php
/*
Plugin Name: Safe Canonical (MU)
Description: 404/プレビュー/フィード/REST/AMP などには出さず、フロントで自己参照 canonical を1本だけ出力。
*/ // AMP 判定(AMPプラグイン未使用なら false)
if (!function_exists('hd0_is_amp')) { function hd0_is_amp(): bool { return function_exists('is_amp_endpoint') && is_amp_endpoint(); }
} // sitemap など“HTML以外”は除外(必要に応じて調整)
if (!function_exists('hd0_is_sitemap_uri')) { function hd0_is_sitemap_uri(string $uri): bool { return (bool) preg_match( '#^/(?:sitemap(?:_index)?\.xml|[A-Za-z0-9_-]+-sitemap(?:\.xml)?|wp-sitemap(?:-.*)?\.xml)$#', $uri ?? '' ); }
} add_action('wp_head', function(){ // 管理/プレビュー/ログインユーザー/404/フィード/AMP/REST は出さない if (is_admin() || is_user_logged_in() || (function_exists('is_preview') && is_preview())) return; if (function_exists('is_404') && is_404()) return; if (function_exists('is_feed') && is_feed()) return; if (hd0_is_amp()) return; $uri = $_SERVER['REQUEST_URI'] ?? ''; if (hd0_is_sitemap_uri($uri)) return; // フロントのみ(必要なら is_singular() などで更に絞る) if (!is_singular() && !is_home() && !is_front_page() && !is_category() && !is_tag() && !is_tax() && !is_author()) { // ここではアーカイブも許容。絞るなら is_singular() に限定。 } // WordPress の正規URLを取得(末尾スラ/URLエンコードは WP に任せる) if (function_exists('wp_get_canonical_url')) { $canonical = wp_get_canonical_url(); } if (empty($canonical)) { // フォールバック:現在URLを自力で $scheme = is_ssl() ? 'https' : 'http'; $host = $_SERVER['HTTP_HOST'] ?? ''; $request = $_SERVER['REQUEST_URI'] ?? '/'; $canonical = $scheme.'://'.$host.$request; } $canonical = esc_url($canonical); if ($canonical) { echo '<link rel="canonical" href="'.$canonical.'" />' . "\n"; }
}, 50);

運用Tips

  • もし「投稿/固定ページだけに限定したい」なら、if (!is_singular()) return; にしてアーカイブで出さない運用もOK。
  • AMP を使っていないなら hd0_is_amp() は常に false で OK。

動作確認(curl だけでOK)

# 1) 記事本体:canonical が “1行だけ & 自分自身”
curl -s 'https://example.com/2025/post-slug/' | grep -i 'rel="canonical"' # 2) フィード/AMP/404:canonical が “出ない”
curl -s 'https://example.com/2025/post-slug/feed/' | grep -i canonical
curl -s 'https://example.com/2022/09/post-xxx/amp/' | grep -i canonical
curl -s 'https://example.com/404/' | grep -i canonical # 3) サイト全体の重複排除(ざっくり)
for u in \ https://example.com/2025/a/ \ https://example.com/2025/b/ \
; do echo -n "$u : "; curl -s "$u" | grep -ci 'rel="canonical"'; done
# → すべて "1" になっていればOK

キャッシュ/HTTPヘッダの注意

  • もし Apache の mod_cache_disk 等で HTMLをキャッシュしている場合、テーマ修正前の HTML が出続けることがあります。
  • MU を入れた直後は サーバ側でキャッシュを無効/削除curl -H 'Cache-Control: no-cache' で確認がおすすめ。

例:mod_cache_disk

# 例: ディスクキャッシュの確認と手動クリーン(環境依存)
sudo htcacheclean -p /var/cache/httpd/mod_cache_disk -l 2G -t -v
# ※ 実運用では適切な -l (容量) 設定が必要

GSC(Google Search Console)での回復手順

  1. サイトマップは 最終URL(https/エンコード済み/200直) のみが載る構成にしておく。
  2. 問題が出ていた URL は、旧URLではなく“最終URL”で
    • URL 検査 → 公開URLをテスト → インデックス登録をリクエスト
  3. 404 や feed/amp の URL は 検証しない(サイトマップにも含めない)。

よくある質問(FAQ)

Q. Cocoon の更新で元に戻りませんか?
A. MU で remove_action() しているため 基本的に維持されます。テーマ側の関数名が変わった場合は MU を再調整。

Q. canonical は投稿だけに出したい
A. 上記 MU の is_singular() 条件にし、アーカイブでは出さない運用にしてください。

Q. rel=”prev”/”next” は要りますか?
A. Google は rel="next/prev" をランキングシグナルとしては使っていません。ページネーションはサイト内導線として適切に(サイトマップ/内部リンクを丁寧に)。

Q. 代替ページ(適切な canonical タグあり)が消えません
A. クロール更新で順次解消されます。旧URLを送らず最終URLのみ を URL 検査してください。


まとめ

  • Cocoon の canonical は便利な反面、条件が合わないと重複/誤出力の原因に。
  • MU プラグインでテーマに手を入れず、
    • 止める(remove_action)
    • 出す(自己参照 canonical を1本だけ)
      を徹底すると、GSC 側の評価が安定しやすくなります。

付録:より厳格なバリアント(任意)

canonical を 投稿/固定ページのみに限定し、アーカイブには出さないバージョン:

add_action('wp_head', function(){ if (!is_singular()) return; // 投稿/固定ページのみ if (is_admin() || is_user_logged_in()) return; if (function_exists('is_preview') && is_preview()) return; if (function_exists('is_404') && is_404()) return; if (function_exists('is_feed') && is_feed()) return; if (function_exists('is_amp_endpoint') && is_amp_endpoint()) return; $canonical = function_exists('wp_get_canonical_url') ? wp_get_canonical_url() : ''; if (!$canonical) { $scheme = is_ssl() ? 'https' : 'http'; $host = $_SERVER['HTTP_HOST'] ?? ''; $request = $_SERVER['REQUEST_URI'] ?? '/'; $canonical = $scheme.'://'.$host.$request; } echo '<link rel="canonical" href="'.esc_url($canonical).'" />' . "\n";
}, 50);

誤出力の温床になりがちな feed/amp/404 には出さない1本だけ自己参照――この2点を守るだけでクローラビリティは劇的に安定します。テーマやプラグインに大手術は不要。MUで“軽くかわす”のがコツです。