cPanel yıllıkta ücretsiz taşıma + SSLHemen İncele
Buyukweb
Headless E-Ticaret: Next.js ve WooCommerce GraphQL API

Headless E-Ticaret: Next.js ve WooCommerce GraphQL API

Headless e-ticaret mimarisi: Next.js frontend ile WooCommerce GraphQL (WPGraphQL) backend entegrasyonu, SSG ve ISR stratejileri.

Büyükweb Editör EkibiHosting, Sunucu ve Sistem Yönetimi Editörü13 dakika okuma

Headless E-Ticaret: Next.js ve WooCommerce GraphQL API

Headless e-ticaret, frontend ve backend'i ayırarak maksimum esneklik ve performans sağlar. Next.js ile WooCommerce GraphQL API entegrasyonu en popüler headless yaklaşımlardan biridir.

Headless E-Ticaret Neden?

Geleneksel (Monolithic):
WordPress + WooCommerce → Tema → PHP şablon → Tarayıcı

Headless:
WooCommerce (API/GraphQL) → Next.js/React → CDN → Tarayıcı

Headless avantajları:
✓ Çok daha hızlı yükleme (SSG + CDN)
✓ Daha iyi SEO (SSR ile)
✓ Teknoloji esnekliği
✓ Aynı backend → Web + Mobil + Kiosk
✓ Core Web Vitals mükemmel

Dezavantajları:
✗ Kurulum karmaşıklığı
✗ WooCommerce eklentileri çalışmayabilir
✗ Yüksek başlangıç maliyeti

WPGraphQL Kurulumu (Backend)

# WordPress'e WPGraphQL eklentisi kur
# wordpress.org/plugins/wp-graphql
# Ek: wp-graphql-woocommerce (WooCommerce)

# GraphQL endpoint: https://api.magazaniz.com/graphql
# GraphiQL IDE: https://api.magazaniz.com/graphql (geliştirme)
# Örnek GraphQL sorguları

# Ürün listesi
query GetProducts {
  products(first: 20) {
    nodes {
      id
      name
      slug
      ... on SimpleProduct {
        price
        regularPrice
        salePrice
        stockStatus
        image {
          sourceUrl
          altText
        }
      }
      productCategories {
        nodes {
          name
          slug
        }
      }
    }
  }
}

# Tek ürün
query GetProduct($slug: ID!) {
  product(id: $slug, idType: SLUG) {
    name
    description
    ... on SimpleProduct {
      price
      stockQuantity
      galleryImages {
        nodes { sourceUrl altText }
      }
    }
  }
}

# Sepet
mutation AddToCart($productId: Int!, $quantity: Int!) {
  addToCart(input: { productId: $productId, quantity: $quantity }) {
    cart {
      contents {
        nodes {
          product { node { name } }
          quantity
          total
        }
      }
      total
    }
  }
}

Next.js Frontend

// lib/graphql.js
const GRAPHQL_URL = process.env.NEXT_PUBLIC_GRAPHQL_URL;

export async function fetchAPI(query, variables = {}) {
  const res = await fetch(GRAPHQL_URL, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      // WooCommerce oturum
      ...(process.env.WC_SESSION && {
        'woocommerce-session': `Session ${process.env.WC_SESSION}`
      }),
    },
    body: JSON.stringify({ query, variables }),
  });

  const json = await res.json();
  if (json.errors) throw new Error(json.errors[0].message);
  return json.data;
}

// pages/products/[slug].js - Statik ürün sayfası
import { fetchAPI } from '../../lib/graphql';

export async function getStaticProps({ params }) {
  const data = await fetchAPI(`
    query GetProduct($slug: ID!) {
      product(id: "${params.slug}", idType: SLUG) {
        name
        description
        ... on SimpleProduct {
          price
          stockQuantity
        }
      }
    }
  `);

  return {
    props: { product: data.product },
    revalidate: 60, // ISR: 60 saniyede bir yenile
  };
}

export async function getStaticPaths() {
  const data = await fetchAPI(`
    query {
      products(first: 100) {
        nodes { slug }
      }
    }
  `);

  return {
    paths: data.products.nodes.map(p => ({ params: { slug: p.slug } })),
    fallback: 'blocking', // Yeni ürünler için SSR
  };
}

// Ürün bileşeni
export default function ProductPage({ product }) {
  return (
    <div>
      <h1>{product.name}</h1>
      <p dangerouslySetInnerHTML={{ __html: product.description }} />
      <div className="price">{product.price}</div>
      <AddToCartButton productId={product.id} />
    </div>
  );
}

Sepet Yönetimi (Client-Side)

// hooks/useCart.js
import { useState, useEffect } from 'react';
import { fetchAPI } from '../lib/graphql';

export function useCart() {
  const [cart, setCart] = useState(null);
  const [session, setSession] = useState(
    () => localStorage.getItem('woo-session')
  );

  const addToCart = async (productId, quantity = 1) => {
    const data = await fetchAPI(`
      mutation AddToCart($productId: Int!, $quantity: Int!) {
        addToCart(input: { productId: $productId, quantity: $quantity }) {
          cart {
            contents {
              nodes {
                product { node { name databaseId } }
                quantity
                total
              }
            }
            total
            subtotal
          }
        }
      }
    `, { productId, quantity });

    setCart(data.addToCart.cart);
  };

  const removeFromCart = async (cartItemKey) => {
    const data = await fetchAPI(`
      mutation RemoveFromCart($keys: [ID]!) {
        removeItemsFromCart(input: { keys: $keys }) {
          cart { total }
        }
      }
    `, { keys: [cartItemKey] });

    setCart(data.removeItemsFromCart.cart);
  };

  return { cart, addToCart, removeFromCart };
}

Müşteri Girişi ve Hesap Yönetimi (JWT)

Headless yapıda müşteri girişi, WordPress'in klasik çerez tabanlı oturumu yerine token tabanlı çalışır. wp-graphql-jwt-authentication benzeri bir eklenti ile giriş mutasyonu şu şekilde tasarlanır:

mutation LoginUser($username: String!, $password: String!) {
  login(input: { username: $username, password: $password }) {
    authToken
    refreshToken
    user {
      id
      email
      firstName
    }
  }
}
// Token'ı localStorage yerine httpOnly cookie'de saklamak XSS riskini azaltır
export async function loginUser(username, password) {
  const data = await fetchAPI(LOGIN_MUTATION, { username, password });
  // Next.js API Route üzerinden httpOnly cookie set edilir
  await fetch('/api/set-auth-cookie', {
    method: 'POST',
    body: JSON.stringify({ token: data.login.authToken }),
  });
  return data.login.user;
}

Sipariş geçmişi, adres defteri ve favori ürünler gibi müşteriye özel sayfalar, getServerSideProps (Pages Router) veya cookies() fonksiyonu (App Router) ile token doğrulanarak sunucu tarafında render edilmelidir; bu tür sayfalar kişiye özel olduğu için statik üretime (SSG) uygun değildir. refreshToken süresi dolmadan önce arka planda yenilenmezse kullanıcı beklenmedik şekilde oturumdan düşer, bu yüzden token yenileme mantığını useEffect içinde periyodik çalıştırmak yaygın bir pratiktir.

Ürün Arama ve Filtreleme (GraphQL)

Kategori, fiyat aralığı ve özellik (attribute) bazlı filtreleme e-ticaret kullanıcı deneyiminin temel taşıdır. WPGraphQL WooCommerce eklentisi bu filtreleri where parametresiyle destekler:

query FilterProducts($category: String, $minPrice: String, $maxPrice: String, $orderby: ProductsOrderByEnum) {
  products(
    where: {
      categoryIn: [$category]
      minPrice: $minPrice
      maxPrice: $maxPrice
      orderby: { field: $orderby, order: ASC }
    }
    first: 24
  ) {
    nodes {
      id
      name
      slug
      ... on SimpleProduct { price }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}

Büyük kataloglarda pageInfo.endCursor ile cursor tabanlı sayfalama kullanılmalıdır; klasik offset tabanlı sayfalama binlerce üründe belirgin şekilde yavaşlar. Filtre parametrelerini URL query string'e yazmak (?kategori=elektronik&min=100) hem kullanıcının tarayıcının geri/ileri tuşuyla önceki filtre durumuna dönebilmesini sağlar hem de filtreli sayfanın SSR ile doğrudan indexlenmesine imkân tanır — bu da SEO açısından ihmal edilmemesi gereken bir detaydır.

Ödeme Akışı

// Checkout → WooCommerce REST API (GraphQL ile checkout zor)
// İki yaklaşım:

// 1. WooCommerce REST API Checkout
const checkoutOrder = async (customerData) => {
  const response = await fetch('/api/checkout', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(customerData),
  });
  return response.json();
};

// pages/api/checkout.js (Next.js API Route)
export default async function handler(req, res) {
  if (req.method !== 'POST') return res.status(405).end();

  const orderRes = await fetch(`${process.env.WC_URL}/wp-json/wc/v3/orders`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: 'Basic ' + Buffer.from(
        `${process.env.WC_KEY}:${process.env.WC_SECRET}`
      ).toString('base64'),
    },
    body: JSON.stringify(req.body),
  });

  const order = await orderRes.json();
  res.json({ orderId: order.id });
}

Webhook ile Otomatik İçerik Güncelleme (On-Demand ISR)

ISR'de sabit bir revalidate: 60 süresi kullanmak, stok veya fiyat değiştiğinde en fazla 60 saniye boyunca ziyaretçiye eski verinin gösterilmesi anlamına gelir. Next.js'in on-demand revalidation özelliğiyle bu gecikme pratikte sıfırlanabilir:

// pages/api/revalidate.js — WooCommerce webhook'u bu endpoint'i tetikler
export default async function handler(req, res) {
  if (req.headers['x-webhook-secret'] !== process.env.REVALIDATE_SECRET) {
    return res.status(401).json({ message: 'Yetkisiz' });
  }

  try {
    const { slug } = req.body;
    await res.revalidate(`/products/${slug}`);
    return res.json({ revalidated: true });
  } catch (err) {
    return res.status(500).json({ message: 'Revalidate hatasi' });
  }
}

WooCommerce yönetim panelinde Ayarlar → Gelişmiş → Webhooks bölümünden "Ürün güncellendi" olayı için bu endpoint tanımlanır. Böylece stok veya fiyat değişikliği anında ilgili statik sayfaya yansır, kullanıcı hiçbir zaman güncel olmayan fiyatla karşılaşmaz. Sipariş oluşturma ve stok azaltma gibi kritik olaylarda da aynı webhook mekanizması kategori sayfalarını (stok tükendiğinde "Tükendi" etiketini göstermek için) tetikleyecek şekilde genişletilebilir.

Sonuç

Headless e-ticaret, Next.js ve WooCommerce GraphQL API ile maksimum performans ve SEO puanı sağlar. SSG ve ISR stratejileriyle ürün sayfaları CDN'den servis edilerek sub-second yükleme sürelerine ulaşılır. Büyükweb'in yüksek performanslı VDS altyapısı, headless e-ticaret backend'inizi güçlü bir şekilde destekler.


İlgili Büyükweb Hizmetleri:


E-Ticaret Başlangıç Kontrol Listesi

Yasal

  • Şirket/şahıs kurulumu
  • Vergi levhası
  • Mesafeli satış sözleşmesi
  • KVKK aydınlatma metni
  • Çerez politikası
  • İade koşulları

Teknik

  • Hosting/VDS seçimi
  • SSL sertifikası
  • E-ticaret platformu
  • Sanal pos (3D Secure)
  • Kargo entegrasyonu
  • E-fatura entegrasyonu
  • Google Analytics + Search Console

Pazarlama

  • Google Business Profile
  • Sosyal medya hesapları
  • Google Shopping
  • Facebook/Instagram Shop
  • E-posta pazarlama

E-Ticaret VDS vs Ev İnterneti

Özellik Ev İnterneti E-Ticaret VDS
IP Dinamik Sabit
Temizlik Bilinmiyor Temiz
Kesinti Elektrik/internet %99.8 uptime
Hız Değişken 1 Gbps
Güvenlik Düşük DDoS korumalı

Marketplace işlemleri için sabit ve temiz IP kritik. Ban riski en aza iner.

Profesyonel Hosting için Önemli Kriterler

Veri Merkezi Kalitesi

Veri merkezinin tier seviyesi, sunucu barındırma kalıtesini doğrudan etkiler. Tier III veri merkezleri yedekli güç, soğutma ve ağ altyapısı ile yüksek erişilebilirlik hedefler (Tier III sınıflandırma hedefi %99.982). Büyükweb'in İstanbul veri merkezi Tier III standartlarındadır; Büyükweb sözleşmesel SLA'sı %99.8'dir.

Teknik Destek Kalitesi

Türkçe ve teknik bilgi sahibi destek ekibi hosting hizmetinin vazgeçilmez parçasıdır. E-posta, canlı destek ve telefon kanallarından hızlı yanıt almak özellikle iş sürekliliği açısından kritiktir.

Ölçeklenebilirlik

İşletmeniz büyüdükçe hosting ihtiyaçlarınız da değişir. Paylaşımlı hostingten VDS'e, VDS'den dedicated sunucuya sorunsuz geçiş yapabilmek uzun vadeli planlamanız için önemlidir. Büyükweb tüm bu geçiş süreçlerini ücretsiz olarak yönetir.

Yedekleme ve Felaket Kurtarma

Günlük otomatik yedekleme, tek tıkla geri yükleme ve uzak yedekleme seçenekleri veri güvenliginiz için şart. JetBackup ile profesyonel yedekleme çözümü tüm Büyükweb hosting paketlerinde standarttır.

Güvenlik Katmanları

SSL sertifikası, WAF koruması, malware tarama, DDoS koruması ve güvenlik duvarı - tüm bu katmanlar birlikte çalışiarak web sitenizi korur. Büyükweb bu güvenliklerin hepsini standart olarak sunar.

Headless E-Ticaret SEO Stratejisi

Headless mimaride frontend (Next.js/Nuxt/Astro) ayrı, backend ayrıdır. Bu yapı SEO için bazı özel dikkat noktaları getirir:

Server-Side Rendering (SSR) zorunlu

Next.js'te SSG (Static Site Generation) veya SSR (Server-Side Rendering) kullanmadan sadece CSR (Client-Side Rendering) yaparsanız Google Bot bazı içerikleri göremeyebilir. Tercih:

  • Ürün sayfaları: SSG + ISR (Incremental Static Regeneration) ile build-time render + revalidate
  • Kategori listeleri: SSR (filtreler değişebildiği için)
  • Ana sayfa: SSG, 1-6 saat revalidate

Meta Tag Yönetimi

Headless'da meta tag'ler genellikle CMS'ten (WooCommerce, Strapi, Sanity vb.) gelir. Tüm ürünler için:

// Next.js App Router metadata
export async function generateMetadata({ params }) {
  const product = await fetchProduct(params.slug);
  return {
    title: product.seoTitle || `${product.name} | Marka`,
    description: product.seoDescription,
    openGraph: { images: [product.imageUrl] },
    alternates: { canonical: `https://siteniz.com/urun/${params.slug}` },
  };
}

JSON-LD Schema Otomatik Üretimi

Her ürün için Product + Offer + AggregateRating schema otomatik üretilmeli:

const schema = {
  "@context": "https://schema.org",
  "@type": "Product",
  "name": product.name,
  "image": product.images,
  "offers": { "@type": "Offer", "price": product.price, "priceCurrency": "TRY", "availability": "https://schema.org/InStock" },
};

Performans: Core Web Vitals

Headless mimari avantajı: ön tarafın özelleştirilebilir olması. Hedef:

Metrik Hedef
LCP (Largest Contentful Paint) < 2.5 sn
FID/INP < 200 ms
CLS (Cumulative Layout Shift) < 0.1
TTFB < 200 ms

TTFB için backend hızı kritik — Büyükweb VDS sunucu NVMe SSD altyapısı API yanıt sürelerini 50-100 ms aralığına çeker.

Rendering Stratejileri Karşılaştırması

Next.js dört farklı render stratejisi sunar ve headless e-ticarette hangi sayfa hangi stratejiyi kullanmalı sorusu doğrudan SEO ve performansı etkiler:

Strateji Ne Zaman Render Edilir En Uygun Kullanım SEO
SSG (Static) Build anında Statik sayfalar (Hakkımızda, SSS) Mükemmel
ISR Build + periyodik/webhook ile yenilenir Ürün, kategori sayfaları Mükemmel
SSR Her istekte sunucuda Sepet önizleme, filtreli listeleme, kişiselleştirilmiş içerik İyi
CSR Tarayıcıda, JS ile Müşteri paneli, admin ekranları Zayıf (indexlenmeyebilir)

Genel kural şudur: Google'ın indexlemesi gereken her sayfa (ürün, kategori, blog yazısı) SSG, ISR veya SSR'dan biriyle render edilmelidir; yalnızca giriş gerektiren ve arama sonuçlarında görünmesi beklenmeyen sayfalar (sepet, hesabım, sipariş takibi) CSR'a bırakılabilir. Karma bir stratejide bile TTFB'yi düşük tutmak backend'in yanıt hızına bağlıdır, bu yüzden WooCommerce'in çalıştığı sunucunun disk ve CPU performansı ISR/SSR build sürelerini doğrudan etkiler.

Image Optimizasyon

Next.js <Image> componenti kullanın; otomatik WebP/AVIF dönüştürme ve responsive size yapar:

<Image src={product.image} alt={product.name} width={600} height={600} priority={isAboveFold} />

CDN cache header'ları için Büyükweb hosting paneli üzerinden .htaccess veya Nginx config ile 1 yıl cache süresi ayarlayın.

Sorun Giderme: Sık Karşılaşılan Hatalar

Headless kurulumlarda ekiplerin en çok takıldığı dört noktayı ve çözümlerini derledik.

CORS hatası: "No 'Access-Control-Allow-Origin' header"

WordPress backend'i frontend'den farklı bir domain veya subdomain'de host ediliyorsa WPGraphQL varsayılan olarak yalnızca kendi origin'ine izin verir. functions.php içine frontend domain'ini eklemek gerekir:

add_filter('graphql_response_headers_to_send', function($headers) {
  $headers['Access-Control-Allow-Origin'] = 'https://magazaniz.com';
  $headers['Access-Control-Allow-Credentials'] = 'true';
  return $headers;
});

Sepet oturumu her istekte sıfırlanıyor

WooCommerce sepeti woocommerce-session header'ına bağlı çalışır. Bu header her fetchAPI çağrısında gönderilmezse — ya da frontend farklı bir domain'deyse ve tarayıcının SameSite çerez politikası devreye giriyorsa — sepet her seferinde boş döner. Çözüm, session token'ı response header'ından okuyup bir sonraki isteğe eklemektir; bu adım genellikle unutulan ve prod ortamında fark edilen bir hatadır.

next/image domain hatası

Ürün görselleri WordPress medya kütüphanesinden geliyorsa next.config.js içinde izinli domain tanımlanmalıdır, aksi halde build veya render sırasında hata alınır:

// next.config.js
module.exports = {
  images: {
    remotePatterns: [
      { protocol: 'https', hostname: 'api.magazaniz.com' },
    ],
  },
};

GraphQL sorgusu çok yavaş veya timeout veriyor

Derin iç içe (nested) sorgular WPGraphQL'de N+1 sorgu problemine yol açabilir. first parametresini makul bir aralıkta (24-48 arası) tutun, ihtiyaç duyulmayan alanları sorgulamayın ve mümkünse WPGraphQL Smart Cache benzeri bir eklentiyle sunucu tarafı önbellekleme aktif edin. Backend'in çalıştığı sunucuda Redis object cache kullanmak, tekrarlayan GraphQL sorgularının veritabanına her seferinde gitmesini önleyerek yanıt sürelerini belirgin şekilde kısaltır.

Sıkça Sorulan Sorular

Headless e-ticaret hosting'i klasiğinden farklı mı?

Frontend ayrı host edilir (Vercel/Netlify gibi platformlar veya kendi VDS), backend için ayrı sunucu (WooCommerce/Strapi). Büyükweb E-Ticaret VDS backend için optimize edilmiştir.

Türkiye'de headless yapanlar nelere dikkat etmeli?

KVKK uyumu için müşteri verisi yurt içinde olmalı. Büyükweb VDS Türkiye lokasyonu bu kriteri karşılar. Frontend hızı için Türkiye edge node sunan CDN tercih edin.

Headless WordPress (WooCommerce) altyapısı ne ister?

WooCommerce REST API hızlı yanıt için: Redis cache + LiteSpeed + 4+ GB RAM. Büyükweb WordPress Hosting bu konfigürasyonla optimize gelir.

WooCommerce backend'in veri güvenliği nasıl sağlanır?

Headless mimaride bile sipariş, müşteri ve stok verisi tamamen WooCommerce veritabanında tutulur; frontend sadece bu veriyi görüntüler. Bu yüzden backend'in barındığı sunucuda düzenli yedekleme kritik önemdedir. Büyükweb VDS ve hosting paketlerinde günlük otomatik yedekleme standart olarak sunulur, böylece bir sunucu arızası veya hatalı güncelleme durumunda sipariş verisi kaybolmaz.

ISR ile SSR arasında hangisini seçmeliyim?

Ürün ve kategori sayfaları gibi çoğu ziyaretçi için aynı içeriği gösteren sayfalarda ISR tercih edilmelidir — build maliyeti düşüktür ve CDN'den servis edilir. Kullanıcıya özel filtreleme, oturum durumu veya kişiselleştirilmiş fiyatlandırma içeren sayfalarda ise SSR gereklidir, çünkü her istekte farklı bir yanıt üretilmesi gerekir.

İlgili Büyükweb Hizmetleri

E-ticaret sitenizin yükü için ölçeklenebilir Türkiye lokasyonlu paketler:

Sorularınız için 0850 302 60 70 numaralı satış öncesi destek numaramıza ulaşabilir veya iletişim sayfamıza yazabilirsiniz.

E-Ticaret İlgili Hizmetlerimiz

Bu yazıda anlatılan teknik konuyu profesyonel altyapıyla deneyimleyin

Etiketler:

#headless e-ticaret#next.js#woocommerce graphql#wpgraphql#ssg#jamstack

Bu yazıyı paylaş

WhatsApp0850 302 60 70