Site icon Cem Kongur

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

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


SSS / Teşhis İpuçları

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(); });

/*

/*

Şimdi tamam işte işin halloldu.

1) GSC tarafı: doğruya kilitle

2) Sitemap ve iç link temizliği

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

add_filter('mscc_ignored_query_args', function($args){
  return array_diff($args, ['lang']);
});

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

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

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

Exit mobile version