Ana Sayfa Wordpress Alternate page with proper canonical tag sorununu nasıl düzeltebilirim

Alternate page with proper canonical tag sorununu nasıl düzeltebilirim

20
0
Alternate page with proper canonical tag sorununu nasıl düzeltebilirim
Alternate page with proper canonical tag sorununu nasıl düzeltebilirim

Toplu ve kalıcı bir çözüm mümkün. “Alternate page with proper canonical tag” uyarısının kökü, aynı içeriğin birden çok URL’den erişilebilir olması (utm/fbclid, /amp/, replytocom, sıralama/filtre parametreleri, sayfalama, www/non-www, http/https, slash farkları, varyasyon URL’leri vb.). Yapılacaklar:

Hızlı plan

  1. Tek biçim URL standardı belirle
    – https + (www ya da çıplak alan) + trailing slash politikası net olsun.
    – İç linklerde de bu standardı kullan.
  2. Canonical’ı site genelinde tutarlı üret
    – Yazı/sayfa: kalıcı bağlantı.
    – Kategori/etiket/mağaza arşivleri: ilgili arşiv linki (+ sayfalama /page/2/).
    – Ürün varyasyonu/parametreli URL’ler: ebeveyn ürüne canonical.
    UTM, fbclid, replytocom, amp, sorting/order gibi parametreleri canonical’dan sil.
  3. Gereksiz alternatifleri azalt
    – Arama sonuçları, feed’ler, 404: noindex (isteğe bağlı).
    – Sadece canonical URL’leri XML sitemap’e koy.
    – AMP varsa canonical’ı non-AMP sürüme yönelt.
  4. Yeniden doğrula
    – Düzeltme sonrası GSC’de “Validate Fix” başlat, örnek URL’lerde “URL denetimi → Canlı URL’yi test et”.

SİZE ÖZEL Mini-Plugin (tek dosya yaptım)

Senin için, site genelinde temiz canonical üreten, UTM/fbclid vb. parametreleri temizleyen, sayfalamada doğru canonical’ı yazan ve HTTP Link: rel=canonical başlığını da ekleyen ufak bir eklenti hazırladım. Ayrıca WooCommerce için temel varyasyon → ebeveyn canonical mantığı da var.

📄 Sağ taraftaki “Canonical Consolidator – WordPress mini-plugin (for motosikletsitesi.com)” dosyasını indirip /wp-content/plugins/ içine tek dosya olarak at, sonra Yönetim panelinden etkinleştir.

Yoast veya Rank Math kullanıyorsan da sorun yok: eklenti, onların canonical çıktısını override eder ve aynı, temiz URL’yi üretir.

Kurulum

  1. Kod dosyasını wp-content/plugins/ms-canonical-consolidator.php adıyla kaydet.
  2. WP Yönetim → Eklentiler → Canonical Consolidator → Etkinleştir.
  3. Tarayıcıda birkaç sayfayı açıp kaynakta <link rel="canonical" ...> kontrol et.
  4. GSC’de bir örnek URL’yi “Canlı URL’yi test et” ile kontrol et, ardından “Validate Fix”.

Notlar ve isteğe göre aç/kapat

  • Arama/404/feed sayfalarına noindex,follow vermek istersen, dosyanın sonunda yorum satırı içindeki meta robots bloğunu .
  • Daha fazla query parametresini canonical’dan çıkarmak istersen, temaya şunu ekleyebilirsin: add_filter('mscc_ignored_query_args', function($args){ $args[] = 'myparam'; return $args; });

SSS / Teşhis İpuçları

  • “Alternate page…” sayısı çoksa genelde sitemap’te parametreli URL’ler, iç linklerde /amp/ uçları veya filtre/sıralama linkleri dolaşımdadır. İçerideki linkleri ve kategori/listelerdeki “Sırala/Filtrele” linklerini nofollow yapmak yerine canonical’ı temiz üretmek daha sağlıklı.
  • www ↔ non-www, http ↔ https karışıklıkları için .htaccess/Nginx 301’lerini koru; bu eklenti, canonical düzeltir; yönlendirmeleri o bozmaz.
  • AMP kullanıyorsan: AMP sayfasında canonical non-AMP olmalı; eklenti /amp/ son ekini canonical’dan temizler.

Ben bunları yapamam diyorsan aşağıdaki basit eklentiyi sayfan için kaydet.

; rel=”canonical” header.
Version: 1.0.1
Author: Cem
License: GPLv2 or later
*/

if (!defined(‘ABSPATH’)) { exit; }

class MS_Canonical_Consolidator {
/** Query params to ignore in canonical (tracking/sorting/etc.). Extend via filter ‘mscc_ignored_query_args’. */
private $ignored_args = [
‘utm_source’,’utm_medium’,’utm_campaign’,’utm_term’,’utm_content’,’gclid’,’fbclid’,
‘msclkid’,’zanpid’,’pk_campaign’,’pk_kwd’,’ref’,’referrer’,’campaign’,’yclid’,’_ga’,
‘replytocom’,’amp’,’share’,’sorting’,’orderby’,’order’,’lang’,’preview’,
];

public function __construct() {
    // Remove WP's default canonical to avoid duplicates
    remove_action('wp_head', 'rel_canonical');
    add_action('wp_head', [$this, 'print_canonical_tag'], 1);
    add_action('template_redirect', [$this, 'send_http_canonical_header']);

    // Yoast / Rank Math compatibility (if active)
    add_filter('wpseo_canonical', [$this, 'override_seo_plugin_canonical'], 20);
    add_filter('rank_math/frontend/canonical', [$this, 'override_seo_plugin_canonical'], 20);

    // Allow extending ignored args
    add_filter('mscc_ignored_query_args', function($args){ return $args; });
}

/** Echo <link rel="canonical"> */
public function print_canonical_tag() {
    if (is_admin() || is_feed() || is_trackback()) return;
    $url = $this->get_canonical_url();
    if (is_string($url) && $url !== '') {
        echo "


“;
}
}

/** Also add HTTP header for canonical (helps some crawlers) */
public function send_http_canonical_header() {
    if (is_admin() || is_feed() || headers_sent()) return;
    if (!is_main_query()) return;
    $url = $this->get_canonical_url();
    if (is_string($url) && $url !== '') {
        // Use raw in header, validated above
        header('Link: <' . esc_url_raw($url) . '>; rel="canonical"', false);
    }
}

/** Central place to compute canonical URL */
public function get_canonical_url() {
    // Front page / blog home
    if (is_front_page() || is_home()) {
        return $this->with_pagination(home_url('/'));
    }

    // Search results: canonicalize to clean search URL without extra params
    if (is_search()) {
        $clean = remove_query_arg(array_keys($_GET), get_search_link());
        return $this->clean_url($clean);
    }

    // WooCommerce contexts — only if WooCommerce is active and helpers exist
    if (function_exists('is_shop')) {
        if (is_shop()) {
            $shop = function_exists('wc_get_page_id') ? get_permalink(wc_get_page_id('shop')) : home_url('/');
            return $this->with_pagination($shop);
        }
        if (function_exists('is_product_category') && is_product_category()) {
            $link = get_term_link(get_queried_object());
            return $this->safe_term_link($link);
        }
        if (function_exists('is_product_tag') && is_product_tag()) {
            $link = get_term_link(get_queried_object());
            return $this->safe_term_link($link);
        }
    }

    // Singular posts/pages/products
    if (is_singular()) {
        $post = get_queried_object();
        if (!$post) return null;

        // WooCommerce variations: canonicalize to parent product
        if (function_exists('wc_get_product') && get_post_type($post) === 'product_variation') {
            $parent_id = wp_get_post_parent_id($post->ID);
            if ($parent_id) return $this->with_pagination(get_permalink($parent_id));
        }

        $url = get_permalink($post);
        return $this->with_pagination($url);
    }

    // Taxonomy archives (category, tag, custom tax)
    if (is_category() || is_tag() || is_tax()) {
        $obj = get_queried_object();
        $link = get_term_link($obj);
        return $this->safe_term_link($link);
    }

    // Post type archives
    if (is_post_type_archive()) {
        $pta = get_query_var('post_type');
        $url = is_string($pta) ? get_post_type_archive_link($pta) : home_url('/');
        return $this->with_pagination($url);
    }

    // Author archives
    if (is_author()) {
        $url = get_author_posts_url(get_queried_object_id());
        return $this->with_pagination($url);
    }

    // Date archives
    if (is_date()) {
        $url = $this->current_url(true);
        return $this->with_pagination($url);
    }

    // Fallback to current URL cleaned
    return $this->clean_url($this->current_url());
}

/** Ensure term links are strings and paginated safely */
private function safe_term_link($link) {
    if (is_wp_error($link)) {
        $link = home_url('/');
    }
    return $this->with_pagination($link);
}

/** Append pagination to canonical if on /page/2+, else return base. */
private function with_pagination($base_url) {
    $base_url = $this->clean_url($base_url);
    if (!is_string($base_url) || $base_url === '') return null;
    $paged = max(1, (int)(get_query_var('paged') ?: get_query_var('page')));
    if ($paged > 1) {
        // Respect WordPress structure (pretty permalinks assumed)
        $base_url = trailingslashit($base_url) . user_trailingslashit('page/' . $paged, 'paged');
    }
    return $base_url;
}

/** Build current URL optionally without query. */
private function current_url($no_query = false) {
    $scheme = is_ssl() ? 'https' : 'http';
    $host = $_SERVER['HTTP_HOST'] ?? parse_url(home_url(), PHP_URL_HOST);
    $uri  = $_SERVER['REQUEST_URI'] ?? '/';
    $url  = $scheme . '://' . $host . $uri;
    if ($no_query) {
        $parts = wp_parse_url($url);
        $path  = isset($parts['path']) ? $parts['path'] : '/';
        return $scheme . '://' . $host . $path;
    }
    return $url;
}

/** Remove ignored args; normalize trailing slash; drop AMP endpoints. */
private function clean_url($url) {
    if (!is_string($url) || $url === '') return '';
    $parts = wp_parse_url($url);
    if (!$parts) return $url;

    $scheme = isset($parts['scheme']) ? $parts['scheme'] : (is_ssl() ? 'https' : 'http');
    $host   = $parts['host'] ?? parse_url(home_url(), PHP_URL_HOST);
    $path   = isset($parts['path']) ? $parts['path'] : '/';

    // Remove /amp/ suffixes from path
    $path = preg_replace('#/amp/?$#i', '/', $path);

    // Force trailing slash on directories (WordPress pretty permalink style)
    if (!preg_match('#\.[a-zA-Z0-9]{2,6}$#', $path)) {
        $path = trailingslashit($path);
    }

    $query = [];
    if (!empty($parts['query'])) {
        parse_str($parts['query'], $query);
    }

    $ignored = apply_filters('mscc_ignored_query_args', $this->ignored_args);
    foreach ((array)$ignored as $arg) {
        unset($query[$arg]);
    }

    // Sort remaining query args for stability
    if (!empty($query)) {
        ksort($query);
        $query_str = http_build_query($query, '', '&', PHP_QUERY_RFC3986);
        $url = $scheme . '://' . $host . $path . '?' . $query_str;
    } else {
        $url = $scheme . '://' . $host . $path;
    }

    // Force site scheme/host to match home_url canonical host
    $home = wp_parse_url(home_url('/'));
    if (!empty($home['host'])) {
        $home_scheme = $home['scheme'] ?? 'https';
        $url = preg_replace('#^https?://[^/]+#', $home_scheme . '://' . $home['host'], $url);
    }

    return $url;
}

/** If an SEO plugin returns something else, override with our clean URL. */
public function override_seo_plugin_canonical($existing) {
    $ours = $this->get_canonical_url();
    return (is_string($ours) && $ours !== '') ? $ours : $existing;
}

}

add_action(‘plugins_loaded’, function(){ new MS_Canonical_Consolidator(); });

/*

  • Optional: mark thin/utility pages as noindex. Uncomment if desired.
  • This reduces alternate pages created by facets/sort/search.
    / /
    add_action(‘wp_head’, function(){
    if (is_search() || is_404() || is_feed()) {
    echo “

    “;
    }
    });
    */

/*

  • Developers: to ignore more query args from canonical, add in theme’s functions.php or a small mu-plugin:
  • add_filter(‘mscc_ignored_query_args’, function($args){ $args[] = ‘myparam’; return $args; });
    */

Şimdi tamam işte işin halloldu.

1) GSC tarafı: doğruya kilitle

  • URL Denetimi → Canlı URL’yi test et (örnek: 1 yazı, 1 kategori, 1 ürün):
    Kullanıcı tarafından belirtilen canonical” = “Google tarafından seçilen canonical” olmalı.
  • Rapor sayfasında Validate Fix başlat (örnek kümelerden). Bu süreçte sayı hemen düşmeyebilir; önemli olan eşleşmenin sağlanması.

2) Sitemap ve iç link temizliği

  • Sitemap’te sadece canonical URL’ler olsun (Yoast/Rank Math ayarlarında: tarih/author arşivlerini kapat, gereksiz taksonomileri kaldır).
  • Tema/menü/widget’lerde utm, fbclid, orderby, filter_* gibi parametreli iç link kalmasın.

3) WooCommerce filtre/sort parametreleri (isteğe göre)

Filtre/sıralama sayfaları “alternates” üretir; biz canonical’ı temizliyoruz. Daha agresif olmak istersen bu parametreleri canonical’dan tamamen dışarıda tutabilirsin (eklenti zaten izin veriyor). Örnek genişletme:

// functions.php veya küçük bir mu-plugin:
add_filter('mscc_ignored_query_args', function($args){
  $extra = [
    'min_price','max_price','rating_filter',
    'filter_color','filter_size','in_stock',
    'onsale','stock_status'
  ];
  return array_values(array_unique(array_merge($args, $extra)));
});

Not: paged parametresini listeye ekleme; sayfalama canonical’ı zaten eklenti doğru kuruyor.

4) Çok dilli siteler (WPML/Polylang) notu

  • Dizin bazlı dil (ör. /tr/) kullanıyorsan sorun yok.
  • Sorgu parametresiyle dil (ör. ?lang=tr) kullanıyorsan lang’i ignore listesinden çıkar:
add_filter('mscc_ignored_query_args', function($args){
  return array_diff($args, ['lang']);
});

5) İsteğe bağlı sertleştirmeler (gerekirse)

  • Arama/404/feed için noindex,follow bloğunu eklentide açabilirsin (dosya sonunda yorum satırı var).
  • Robots.txt ile agresif disallow (örn. /*?orderby=*) mümkündür ama genelde tavsiye etmem; canonical + sitemap temizliği çoğu sitede yeterli ve daha esnektir.

6) Hızlı sağlık kontrolü (kendine test)

  • Parametreli URL (ör. /urunler?utm_source=fb&orderby=price) → kaynakta canonical temiz URL mi?
  • /amp/ son ekli bir sayfa → canonical non-AMP mi?
  • Varyasyon ürünü → canonical ebeveyn ürün mü?

Şimdilik bu kadar geliştirme için not, yorum vs. ekle bana bildir!

CEVAP VER

Lütfen yorumunuzu giriniz!
Lütfen isminizi buraya giriniz