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
- Tek biçim URL standardı belirle
– https + (www ya da çıplak alan) + trailing slash politikası net olsun.
– İç linklerde de bu standardı kullan. - 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. - 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. - 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
- Kod dosyasını
wp-content/plugins/ms-canonical-consolidator.php
adıyla kaydet. - WP Yönetim → Eklentiler → Canonical Consolidator → Etkinleştir.
- Tarayıcıda birkaç sayfayı açıp kaynakta
<link rel="canonical" ...>
kontrol et. - 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 aç. - 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ıyorsanlang
’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!