WooCommerce Ürünlerine Product Schema Ekleme
E-ticaret sitelerinde SEO, sadece iyi içerik yazmaktan ibaret değil. Google’ın ürünlerinizi doğru anlaması, fiyat, stok durumu, yorum puanı gibi bilgileri arama sonuçlarında göstermesi için yapısal veri şart. WooCommerce kendi başına bazı schema verileri ekliyor ama çoğu zaman bu yeterli olmuyor. Özellikle rich snippet’ların tam olarak görünmesini istiyorsanız, functions.php üzerinden kendiniz müdahale etmeniz gerekiyor.
Bu yazıda WooCommerce ürün sayfalarına JSON-LD formatında Product schema nasıl eklenir, bunu functions.php içinde nasıl yönetirsiniz, hangi alanları dahil etmeniz gerekir, gerçek dünya senaryolarında ne tür sorunlarla karşılaşırsınız, bunların hepsine bakacağız.
Schema Markup Neden Bu Kadar Önemli
Google’ın arama sonuçlarında bir ürünün fiyatını, yıldız puanını, stok durumunu görmüşsünüzdür. İşte o görünüm “rich snippet” ya da “rich result” olarak adlandırılıyor. Bunların çıkması için Google’ın sayfanızı makine tarafından okunabilir bir şekilde anlaması lazım. Schema.org standartlarına göre işaretlenmiş JSON-LD verisi tam olarak bunu sağlıyor.
WooCommerce’in varsayılan çıktısına bakarsanız bazı meta etiketler ve kısmi schema verileri eklendiğini görürsünüz. Ama bu veri genellikle eksik kalıyor, fiyat alanı bazen yanlış formatta çıkıyor, yorum verileri dahil edilmiyor ya da stok durumu schema.org standardına uygun yazılmıyor. Bunu manuel olarak kontrol altına almak hem SEO açısından hem de Google Search Console’da “Rich Results” hatalarından kurtulmak için kritik.
Başlamadan Önce Dikkat Edilmesi Gerekenler
functions.php dosyasına doğrudan yazmak yerine child theme kullanmanızı şiddetle tavsiye ederim. Ana tema güncellenince yaptığınız değişikliklerin uçup gitmesini istemiyorsanız bu bir zorunluluk. Ayrıca bir custom plugin yaratmak da iyi bir alternatif; wp-content/plugins/ altında küçük bir plugin klasörü açıp oraya yazabilirsiniz.
Bir diğer önemli nokta, eğer zaten Yoast SEO, Rank Math veya Schema Pro gibi bir plugin kullanıyorsanız, bu araçların ekledikleri schema ile çakışma yaşanabilir. Bu durumu yönetmek için mevcut schema çıktısını kaldırmanız ya da kendi eklediğiniz JSON-LD’yi daha spesifik hale getirmeniz gerekir.
Temel JSON-LD Product Schema Yapısı
Önce elle çalışan temel bir yapıya bakalım. WooCommerce’de woocommerce_before_main_content veya wp_head hook’larına bağlanarak JSON-LD çıktısı üretebilirsiniz.
function custom_product_schema() {
if ( ! is_product() ) {
return;
}
global $product;
if ( ! is_a( $product, 'WC_Product' ) ) {
$product = wc_get_product( get_the_ID() );
}
$schema = array(
'@context' => 'https://schema.org/',
'@type' => 'Product',
'name' => get_the_title(),
'description' => wp_strip_all_tags( $product->get_short_description() ),
'url' => get_permalink(),
);
echo '<script type="application/ld+json">' . wp_json_encode( $schema ) . '</script>';
}
add_action( 'wp_head', 'custom_product_schema' );
Bu en basit hali. Tabii ki bu kadarla rich snippet çıkmaz, ama temel yapının doğru çalışıp çalışmadığını test etmek için başlangıç noktası olarak kullanabilirsiniz.
Fiyat ve Teklif (Offer) Bilgisi Ekleme
Google’ın ürün rich snippet’ı göstermesi için offers alanının doğru dolu olması şart. Fiyat, para birimi, stok durumu bu blok içinde yer alıyor.
function custom_product_schema() {
if ( ! is_product() ) {
return;
}
global $product;
if ( ! is_a( $product, 'WC_Product' ) ) {
$product = wc_get_product( get_the_ID() );
}
$currency = get_woocommerce_currency();
$price = $product->get_price();
$regular = $product->get_regular_price();
$sale = $product->get_sale_price();
$stock = $product->is_in_stock() ? 'https://schema.org/InStock' : 'https://schema.org/OutOfStock';
$permalink = get_permalink();
$offer = array(
'@type' => 'Offer',
'url' => $permalink,
'priceCurrency' => $currency,
'price' => $price,
'availability' => $stock,
'itemCondition' => 'https://schema.org/NewCondition',
);
// Indirimli fiyat varsa priceValidUntil ekle
if ( $sale && $product->get_date_on_sale_to() ) {
$offer['priceValidUntil'] = $product->get_date_on_sale_to()->date( 'Y-m-d' );
}
$schema = array(
'@context' => 'https://schema.org/',
'@type' => 'Product',
'name' => get_the_title(),
'url' => $permalink,
'offers' => $offer,
);
echo '<script type="application/ld+json">' . wp_json_encode( $schema ) . '</script>';
}
add_action( 'wp_head', 'custom_product_schema' );
Burada dikkat edilmesi gereken birkaç nokta var. price alanına string değil sayısal değer gitmelidir. wp_json_encode bunu genellikle doğru halleder ama floatval() ile ekstra güvence alabilirsiniz. availability alanı tam URL formatında olmalı, sadece InStock yazmak yeterli değil.
Görsel ve SKU Bilgisi Ekleme
Google, ürün görselini schema içinde görürse bunu arama sonuçlarında da kullanabiliyor. SKU ise ürün takibi ve Google Merchant Center entegrasyonu için önemli.
function custom_product_schema() {
if ( ! is_product() ) {
return;
}
global $product;
if ( ! is_a( $product, 'WC_Product' ) ) {
$product = wc_get_product( get_the_ID() );
}
$currency = get_woocommerce_currency();
$price = floatval( $product->get_price() );
$stock = $product->is_in_stock() ? 'https://schema.org/InStock' : 'https://schema.org/OutOfStock';
$permalink = get_permalink();
$sku = $product->get_sku();
// Urun gorseli
$image_id = $product->get_image_id();
$image_url = $image_id ? wp_get_attachment_image_url( $image_id, 'full' ) : wc_placeholder_img_src();
$schema = array(
'@context' => 'https://schema.org/',
'@type' => 'Product',
'name' => get_the_title(),
'description' => wp_strip_all_tags( $product->get_short_description() ),
'url' => $permalink,
'image' => $image_url,
'offers' => array(
'@type' => 'Offer',
'url' => $permalink,
'priceCurrency' => $currency,
'price' => $price,
'availability' => $stock,
'itemCondition' => 'https://schema.org/NewCondition',
),
);
if ( $sku ) {
$schema['sku'] = $sku;
}
echo '<script type="application/ld+json">' . wp_json_encode( $schema ) . '</script>';
}
add_action( 'wp_head', 'custom_product_schema' );
WooCommerce Yorumlarını AggregateRating Olarak Ekleme
Yıldız puanının arama sonuçlarında çıkması için aggregateRating alanına ihtiyacınız var. Bu alan yorum sayısı ve ortalama puan içeriyor.
function get_product_aggregate_rating( $product ) {
$rating_count = $product->get_rating_count();
$average = $product->get_average_rating();
if ( $rating_count < 1 || ! $average ) {
return false;
}
return array(
'@type' => 'AggregateRating',
'ratingValue' => $average,
'reviewCount' => $rating_count,
'bestRating' => '5',
'worstRating' => '1',
);
}
function custom_product_schema_with_reviews() {
if ( ! is_product() ) {
return;
}
global $product;
if ( ! is_a( $product, 'WC_Product' ) ) {
$product = wc_get_product( get_the_ID() );
}
$currency = get_woocommerce_currency();
$price = floatval( $product->get_price() );
$stock = $product->is_in_stock() ? 'https://schema.org/InStock' : 'https://schema.org/OutOfStock';
$permalink = get_permalink();
$image_id = $product->get_image_id();
$image_url = $image_id ? wp_get_attachment_image_url( $image_id, 'full' ) : wc_placeholder_img_src();
$schema = array(
'@context' => 'https://schema.org/',
'@type' => 'Product',
'name' => get_the_title(),
'description' => wp_strip_all_tags( $product->get_short_description() ),
'url' => $permalink,
'image' => $image_url,
'sku' => $product->get_sku(),
'offers' => array(
'@type' => 'Offer',
'url' => $permalink,
'priceCurrency' => $currency,
'price' => $price,
'availability' => $stock,
'itemCondition' => 'https://schema.org/NewCondition',
),
);
$rating = get_product_aggregate_rating( $product );
if ( $rating ) {
$schema['aggregateRating'] = $rating;
}
echo '<script type="application/ld+json">' . wp_json_encode( $schema ) . '</script>';
}
add_action( 'wp_head', 'custom_product_schema_with_reviews' );
Dikkat edin, reviewCount sıfır olduğunda aggregateRating alanını eklemeyin. Google bu durumda hataya düşebilir ya da schema’yı geçersiz sayabilir. Yukarıdaki get_product_aggregate_rating fonksiyonu bu kontrolü yapıyor.
Variable (Değişken) Ürünler için Schema
WooCommerce’de renk, beden gibi varyasyonlara sahip ürünler için tek bir fiyat yazmak doğru değil. Bu durumda AggregateOffer kullanmak gerekiyor.
function get_variable_product_offers( $product ) {
if ( ! $product->is_type( 'variable' ) ) {
return false;
}
$currency = get_woocommerce_currency();
$min_price = floatval( $product->get_variation_price( 'min', true ) );
$max_price = floatval( $product->get_variation_price( 'max', true ) );
$stock = $product->is_in_stock() ? 'https://schema.org/InStock' : 'https://schema.org/OutOfStock';
$permalink = get_permalink();
return array(
'@type' => 'AggregateOffer',
'url' => $permalink,
'priceCurrency' => $currency,
'lowPrice' => $min_price,
'highPrice' => $max_price,
'availability' => $stock,
'itemCondition' => 'https://schema.org/NewCondition',
);
}
function custom_variable_product_schema() {
if ( ! is_product() ) {
return;
}
global $product;
if ( ! is_a( $product, 'WC_Product' ) ) {
$product = wc_get_product( get_the_ID() );
}
$permalink = get_permalink();
$image_id = $product->get_image_id();
$image_url = $image_id ? wp_get_attachment_image_url( $image_id, 'full' ) : wc_placeholder_img_src();
if ( $product->is_type( 'variable' ) ) {
$offers = get_variable_product_offers( $product );
} else {
$currency = get_woocommerce_currency();
$price = floatval( $product->get_price() );
$stock = $product->is_in_stock() ? 'https://schema.org/InStock' : 'https://schema.org/OutOfStock';
$offers = array(
'@type' => 'Offer',
'url' => $permalink,
'priceCurrency' => $currency,
'price' => $price,
'availability' => $stock,
'itemCondition' => 'https://schema.org/NewCondition',
);
}
$schema = array(
'@context' => 'https://schema.org/',
'@type' => 'Product',
'name' => get_the_title(),
'description' => wp_strip_all_tags( $product->get_short_description() ),
'url' => $permalink,
'image' => $image_url,
'sku' => $product->get_sku(),
'offers' => $offers,
);
$rating = array();
$rating_count = $product->get_rating_count();
$average = $product->get_average_rating();
if ( $rating_count > 0 && $average ) {
$schema['aggregateRating'] = array(
'@type' => 'AggregateRating',
'ratingValue' => $average,
'reviewCount' => $rating_count,
'bestRating' => '5',
'worstRating' => '1',
);
}
echo '<script type="application/ld+json">' . wp_json_encode( $schema ) . '</script>';
}
add_action( 'wp_head', 'custom_variable_product_schema' );
Marka (Brand) ve Kategori Bilgisi Ekleme
Google Merchant Center ile entegrasyon yapmayı ya da daha zengin bir schema üretmeyi hedefliyorsanız marka bilgisi önemli. WooCommerce’de varsayılan olarak “marka” taxonomy’si yok, ama üçüncü parti plugin varsa ya da custom taxonomy oluşturduysanız bunu çekebilirsiniz.
function get_product_brand( $product_id ) {
// Ornegin 'product_brand' isminde bir taxonomy kullaniyorsaniz
$brands = wp_get_post_terms( $product_id, 'product_brand', array( 'fields' => 'names' ) );
if ( ! is_wp_error( $brands ) && ! empty( $brands ) ) {
return $brands[0];
}
// WooCommerce Brands plugin kullaniyorsaniz
$brand_terms = wp_get_post_terms( $product_id, 'pwb-brand', array( 'fields' => 'names' ) );
if ( ! is_wp_error( $brand_terms ) && ! empty( $brand_terms ) ) {
return $brand_terms[0];
}
return get_bloginfo( 'name' );
}
function add_brand_to_schema( $schema, $product ) {
$brand = get_product_brand( $product->get_id() );
if ( $brand ) {
$schema['brand'] = array(
'@type' => 'Brand',
'name' => $brand,
);
}
// Kategori bilgisi
$categories = wp_get_post_terms( $product->get_id(), 'product_cat', array( 'fields' => 'names' ) );
if ( ! is_wp_error( $categories ) && ! empty( $categories ) ) {
$schema['category'] = implode( ', ', $categories );
}
return $schema;
}
Bu yardımcı fonksiyonu ana schema fonksiyonunuza entegre ederek şu şekilde kullanabilirsiniz:
// Ana schema fonksiyonunuzun icinde, echo'dan once:
$schema = add_brand_to_schema( $schema, $product );
echo '<script type="application/ld+json">' . wp_json_encode( $schema ) . '</script>';
Mevcut WooCommerce Schema’yı Kaldırma veya Değiştirme
Eğer Yoast SEO ya da başka bir SEO plugin’i kullanıyorsanız, bu araçlar zaten bazı schema verileri üretiyor. Kendi yazdığınız schema ile çakışmasın diye önce mevcut olanı temizlemeniz mantıklı.
WooCommerce’in kendi ürettiği schema çıktısını kaldırmak için şu kodu kullanabilirsiniz:
// WooCommerce'in varsayilan schema markup'ini devre disi birakma
add_filter( 'woocommerce_structured_data_product', function( $markup, $product ) {
// Kendi schema'nizi eklediyseniz WooCommerce'inkini bos array dondurun
return array();
}, 10, 2 );
// Ya da tamamen kapatmak istiyorsaniz
add_filter( 'woocommerce_structured_data_context', '__return_empty_string' );
Yoast SEO kullanıyorsanız ve sadece ürün sayfası schema’sını kendiniz yönetmek istiyorsanız şunu yapabilirsiniz:
// Yoast SEO'nun urun sema ciktisini urun sayfalarinda devre disi birakma
add_filter( 'wpseo_schema_graph_pieces', function( $pieces, $context ) {
if ( is_product() ) {
foreach ( $pieces as $key => $piece ) {
if ( $piece instanceof YoastWPSEOGeneratorsSchemaProduct ) {
unset( $pieces[ $key ] );
}
}
}
return $pieces;
}, 11, 2 );
Test ve Doğrulama
Kodu yazdıktan sonra mutlaka test edin. Google’ın Rich Results Test aracını kullanabilirsiniz. URL’nizi girince hem hataları hem de doğru parse edilen alanları gösteriyor. Ayrıca Schema Markup Validator (validator.schema.org) da detaylı validasyon için işe yarıyor.
Terminalden hızlı kontrol için şu komutla sayfanın kaynak koduna bakabilirsiniz:
curl -s "https://siteniz.com/urun-sayfasi/" | grep -A 20 'application/ld+json'
Bu komut sayfanın HTML çıktısındaki JSON-LD bloklarını filtreleyerek gösterir. Birden fazla schema bloğu varsa hepsini listeler.
Google Search Console’da “Geliştirmeler” bölümü altında “Ürün zengin sonuçları” kısmını düzenli kontrol edin. Hata sayısı düşüyor mu, uyarılar giderildi mi, geçerli ürün sayısı artıyor mu bunlara bakın.
Gerçek Dünya Senaryosu: Çakışma Sorunu
Bir projede hem Rank Math hem de el yazısı functions.php kodu aktifti. Google Search Console’da “çakışan fiyat değerleri” hatası çıkıyordu. Schema içinde iki farklı Product tipi vardı, biri Rank Math’ten biri bizim koddan.
Çözüm olarak Rank Math’in product schema üretimini kapadık ve tüm kontrolü functions.php üzerinden yaptık. Rank Math’te bu ayar “Rank Math > Titles & Meta > WooCommerce” bölümünden yapılıyor, “Add Product Schema” seçeneğini kapatmak yeterli.
Öte yandan bazen fiyat 0 ya da boş geldiği için schema geçersiz sayılıyor. Bunu önlemek için şu kontrolü ekleyebilirsiniz:
if ( ! $price || $price <= 0 ) {
return; // Fiyat yoksa schema ekleme
}
Sonuç
WooCommerce ürünlerine Product schema eklemek başlangıçta karmaşık görünebilir ama bir kez çalışan bir fonksiyon hazırladıktan sonra bütün ürün sayfalarınıza otomatik uygulanıyor. Temel olarak şunları kapsayan bir schema yapısı Google’ın beklentilerini karşılar:
- name: Ürün adı
- description: Kısa açıklama
- image: Ürün görseli URL’si
- sku: Stok kodu
- offers: Fiyat, para birimi, stok durumu
- aggregateRating: Yorum sayısı ve ortalama puan
- brand: Marka bilgisi
Bunları doğru ve eksiksiz doldurduğunuzda arama sonuçlarında rich snippet olarak görünme ihtimaliniz ciddi ölçüde artıyor. Bu doğrudan tıklama oranına yansıyor. Organik trafik için meta description optimizasyonu kadar, belki ondan daha etkili bir müdahale.
functions.php yerine custom plugin yaklaşımını tercih ederseniz tema değişikliklerinden bağımsız kalırsınız. Uzun vadeli bir proje için bu kesinlikle daha sağlıklı bir yapı. Kodu yazdıktan sonra Google Search Console’u takip etmeyi ihmal etmeyin; validasyon hataları zaman içinde değişebilir ve güncelleme gerektirebilir.
