🇬🇧 English: Read this in English →

Headless ticaret üzerine yaptığım her ilk toplantıda masaya çıkan endişe hep aynı: SEO. Mağaza vitrinin bir JavaScript uygulamasıysa, Google onu düzgün indeksler mi? Kısa cevabı hemen vereyim: evet, SSR/SSG’yi doğru kurarsan. Ama açık konuşayım, uzun cevap işin asıl kısmı — meta etiketleri, structured data, sitemap’ler ve headless’e özgü birkaç sinsi tuzak. Bu yazıda o uzun cevabı, canlı bir mağazayı kurarken gerçekten yapmam gerekenlerle anlatıyorum.

Problem: Client-Side Rendering

Tamamen client-side rendered (CSR) React uygulaması tarayıcıya (ve Googlebot’a) boş bir HTML kabuğu gönderir:



  

Google JavaScript’i render edebilir, ancak daha yavaş, daha az güvenilir ve ayrı bir rendering kuyruğu kullanır. Kritik e-ticaret sayfaların — ürünler, kategoriler, landing sayfaları — indekslenebilir içerik için asla client-side rendering’e bağımlı olmamalı. Gelirini bir tarayıcının “ikinci geçişte belki render ederim” kuyruğuna emanet etmek istemezsin.

Bunu daha önce yaşadım: Flash da görünmezdi

Bu “boş kabuk” hikâyesi bana hiç yabancı değil. Sektörün dinozoruyum ve web’in bütün bir dönemini Flash’la kurmuş bir neslin içinden geliyorum. O günlerde en gösterişli, en akıcı, en zengin siteler Flash’ta yapılırdı — ekranda muhteşem görünürdü. Sonra müşteri gelip “neden Google’da hiç çıkmıyorum” diye sorardı. Cevap acıydı: Googlebot o parlak .swf dosyasının içine bakamıyordu, gördüğü şey boş bir sayfaydı. İçerik oradaydı, insan görüyordu, arama motoru görmüyordu. Tam olarak bugünkü CSR React uygulamasının Googlebot’a boş bir <div id="root"></div> göndermesi gibi.

Yıllar geçti, teknoloji değişti, ama tuzak birebir aynı: kullanıcıya güzel görünen bir arayüz, tarayıcıya görünmez bir içerik. O zaman dersi zor yoldan öğrendik. Bugün SSR ve SSG sayesinde bunu baştan doğru yapmak elimizde — yani bir kere yaşadığımız hatayı ikinci kez yapmak için hiçbir mazeretimiz yok. Ben bu yüzden headless bir projede render stratejisini en son değil, en başta konuşurum.

Çözüm: SSR ve SSG

Next.js ve Nuxt, server-side rendering (SSR) ve static site generation (SSG) sağlar. Bunlarla ürün sayfaların tarayıcıya tamamen render edilmiş HTML olarak teslim edilir:



  Blue Widget - YourStore
  
  


  

Blue Widget

$29.99

Premium blue widget with stainless steel construction...

Next.js: ISR (Incremental Static Regeneration)

WooCommerce ürün sayfaları için ideal yaklaşım:

// app/products/[slug]/page.js

export async function generateStaticParams() {

const products = await fetchAllProductSlugs();

return products.map(p => ({ slug: p.slug }));

}

export async function generateMetadata({ params }) {

const product = await fetchProduct(params.slug);

return {

title: ${product.name} | YourStore,

description: product.short_description,

openGraph: {

title: product.name,

description: product.short_description,

images: [{ url: product.images[0]?.src }],

type: 'website'

}

};

}

export default async function ProductPage({ params }) {

const product = await fetchProduct(params.slug);

return ;

}

// Revalidate every 5 minutes

export const revalidate = 300;

Sayfalar build zamanında önceden render edilir ve eskidiğinde arka planda yeniden oluşturulur. Googlebot her zaman tamamen render edilmiş HTML alır.

Meta Tag Yönetimi

Geleneksel WooCommerce’de Yoast veya RankMath meta etiketlerini yönetir. Headless’te ise bunları frontend framework’ünde sen yönetirsin — yani bu iş artık senin sorumluluğunda.

Dinamik Meta Tagları (Next.js App Router)

// lib/seo.js

export function generateProductMeta(product) {

const title = product.yoast_head_json?.title || ${product.name} | YourStore;

const description = product.yoast_head_json?.og_description ||

stripHtml(product.short_description).substring(0, 160);

return {

title,

description,

openGraph: {

title: product.yoast_head_json?.og_title || product.name,

description,

url: https://yourstore.com/products/${product.slug},

images: product.images.map(img => ({

url: img.src,

width: 800,

height: 800,

alt: img.alt || product.name

})),

type: 'website',

siteName: 'YourStore'

},

twitter: {

card: 'summary_large_image',

title: product.name,

description,

images: [product.images[0]?.src]

},

alternates: {

canonical: https://yourstore.com/products/${product.slug}

}

};

}

Yoast Verilerini Kullanma

WordPress backend’inde Yoast SEO kuruluysa, SEO verilerini REST API aracılığıyla sana sunar; tekerleği yeniden icat etmene gerek yok:

// Fetch product with Yoast SEO data

const product = await fetch(

${WP_URL}/wp-json/wp/v2/product/${id}?_fields=yoast_head_json

);

const yoast = product.yoast_head_json;

// Use Yoast's pre-computed meta

const meta = {

title: yoast.title,

description: yoast.og_description,

canonical: yoast.canonical,

robots: yoast.robots

};

Structured Data (Schema.org)

Arama sonuçlarında rich snippet çıkmak istiyorsan ürün şeması şart. Bunu mutlaka server-side oluştur:

function generateProductSchema(product) {

const schema = {

'@context': 'https://schema.org',

'@type': 'Product',

name: product.name,

description: stripHtml(product.short_description),

image: product.images.map(img => img.src),

sku: product.sku,

brand: {

'@type': 'Brand',

name: product.brands?.[0]?.name || 'YourStore'

},

offers: {

'@type': 'Offer',

url: https://yourstore.com/products/${product.slug},

priceCurrency: 'USD',

price: product.price,

availability: product.stock_status === 'instock'

? 'https://schema.org/InStock'

: 'https://schema.org/OutOfStock',

seller: {

'@type': 'Organization',

name: 'YourStore'

}

}

};

// Add reviews if available

if (product.rating_count > 0) {

schema.aggregateRating = {

'@type': 'AggregateRating',

ratingValue: product.average_rating,

reviewCount: product.rating_count

};

}

return schema;

}

// In your page component

Close Search Window