Sayfa İçi SEO Rehberi: İçerik Mimarisi ve Internal Linking
Silo yapısı, topic clusters, internal linking stratejileri ve content decay yönetimi. Link equity dağıtımı ve UX sinyalleri.
Sayfa İçi SEO Rehberi: İçerik Mimarisi ve Internal Linking
İçerik mimarisi, sitenizin bilgi hiyerarşisini ve sayfalar arası ilişkileri tanımlar. Doğru bir mimari, hem kullanıcıların hem de arama motorlarının içeriğinizi anlamasını kolaylaştırır. Bu yazıda silo yapısı, topic clusters, internal linking stratejileri ve content decay yönetimini inceliyoruz.
Bu yazı, 5 parçalık Sayfa İçi SEO Rehberi serisinin üçüncü bölümüdür. Önceki yazılarda Arama Niyeti ve Teknik Sayfa Yapısı konularını ele almıştık.
İçindekiler
- Silo Yapısı ve Topic Clusters
- Internal Linking Stratejileri
- Link Equity Dağıtımı
- Content Decay: Eski İçerikleri Canlandırma
- Kullanıcı Deneyimi ve SEO Sinyalleri
- Breadcrumb Navigasyonu
- Pagination Best Practices
- Pratik Checklist
- Sık Sorulan Sorular
- Sonuç
Silo Yapısı ve Topic Clusters
Silo yapısı, ilgili içerikleri gruplandırarak tematik otorite oluşturur. Modern SEO'da buna Topic Cluster modeli denir.
Pillar-Cluster Model
Bu model, içerikleri hiyerarşik bir yapıda organize eder:
| Katman | Açıklama | Örnek |
|---|---|---|
| Pillar Page | Geniş konuyu kapsayan ana rehber | "Sayfa İçi SEO Rehberi" |
| Cluster Pages | Alt konuları derinlemesine ele alan sayfalar | "Meta Tags", "Schema Markup", "Internal Linking" |
Nasıl Çalışır:
- Pillar page tüm cluster page'lere link verir
- Her cluster page pillar'a geri link verir
- Cluster'lar birbiriyle de ilişkili yerlerde link paylaşır
Örnek: Bu yazı serisinde "Sayfa İçi SEO Rehberi" pillar, diğer 4 yazı (Semantik SEO, Metadata, Schema, JS SEO) cluster page'lerdir.
TypeScript ile Topic Cluster Yapısı
// lib/content-structure.ts
interface ClusterPage {
slug: string;
title: string;
relation: 'subtopic' | 'related' | 'comparison';
}
interface TopicCluster {
pillar: {
slug: string;
title: string;
keywords: string[];
};
clusters: ClusterPage[];
}
const seoCluster: TopicCluster = {
pillar: {
slug: 'sayfa-ici-seo-rehberi',
title: 'Sayfa İçi SEO: Kapsamlı Rehber',
keywords: ['sayfa içi seo', 'on-page seo', 'seo rehberi']
},
clusters: [
{
slug: 'sayfa-ici-seo-arama-niyeti-semantik',
title: 'Arama Niyeti ve Semantik SEO',
relation: 'subtopic'
},
{
slug: 'sayfa-ici-seo-teknik-yapi-metadata',
title: 'Teknik Sayfa Yapısı',
relation: 'subtopic'
},
{
slug: 'sayfa-ici-seo-schema-json-ld',
title: 'Schema.org ve JSON-LD',
relation: 'subtopic'
},
{
slug: 'seo-vs-sem-farki',
title: 'SEO vs SEM Karşılaştırma',
relation: 'comparison'
}
]
};Cluster'ın SEO Faydaları
- Tematik otorite: Google, belirli konuda derinlik gördüğünde güvenir
- Internal link gücü: Pillar ve cluster'lar birbirine link vererek güçlenir
- Kullanıcı deneyimi: İlgili içeriklere kolay navigasyon
- Crawl efficiency: Bot, ilişkili sayfaları daha hızlı keşfeder
Internal Linking Stratejileri
Internal linking, SEO'nun en hafife alınan ama en güçlü aracıdır. Doğru yapılandırılmış internal linkler, PageRank akışını yönlendirir.
Temel İlkeler
- Contextual links: İçerik içinde, bağlamla ilgili linkler en değerlidir
- Navigational links: Header, footer, sidebar linkleri daha az değerli ama gerekli
- Anchor text: Tıklanabilir metin, hedef sayfanın ne hakkında olduğunu söylemeli
Otomatik İlgili Yazılar Algoritması
// lib/related-posts.ts
import { getAllPosts, BlogPost } from './mdx';
interface RelatedPost {
slug: string;
title: string;
relevanceScore: number;
}
export async function findRelatedPosts(
currentPost: BlogPost,
limit = 5
): Promise<RelatedPost[]> {
const allPosts = await getAllPosts();
return allPosts
.filter(post => post.slug !== currentPost.slug)
.map(post => ({
slug: post.slug,
title: post.title,
relevanceScore: calculateRelevance(currentPost, post)
}))
.sort((a, b) => b.relevanceScore - a.relevanceScore)
.slice(0, limit);
}
function calculateRelevance(post1: BlogPost, post2: BlogPost): number {
let score = 0;
// Aynı kategori: +30 puan
if (post1.category === post2.category) {
score += 30;
}
// Ortak tag'ler: tag başına +15 puan
const sharedTags = post1.tags?.filter(tag =>
post2.tags?.includes(tag)
) || [];
score += sharedTags.length * 15;
// Başlıkta ortak kelimeler: kelime başına +5 puan
const words1 = post1.title.toLowerCase().split(/\s+/);
const words2 = post2.title.toLowerCase().split(/\s+/);
const commonWords = words1.filter(w =>
w.length > 3 && words2.includes(w)
);
score += commonWords.length * 5;
// Yayın tarihi yakınlığı: +10 puan (30 gün içinde)
const date1 = new Date(post1.date);
const date2 = new Date(post2.date);
const daysDiff = Math.abs(date1.getTime() - date2.getTime()) / (1000 * 60 * 60 * 24);
if (daysDiff < 30) {
score += 10;
}
return score;
}İlgili Yazılar Componenti
// components/RelatedPosts.tsx
import Link from 'next/link';
import { findRelatedPosts, BlogPost } from '@/lib/related-posts';
interface Props {
currentPost: BlogPost;
}
export async function RelatedPosts({ currentPost }: Props) {
const relatedPosts = await findRelatedPosts(currentPost, 3);
if (relatedPosts.length === 0) return null;
return (
<aside className="mt-12 p-6 bg-gray-50 dark:bg-gray-800 rounded-lg">
<h2 className="text-xl font-bold mb-4">İlgili Yazılar</h2>
<ul className="space-y-3">
{relatedPosts.map(post => (
<li key={post.slug}>
<Link
href={`/blog/${post.slug}`}
className="text-primary hover:underline"
>
{post.title}
</Link>
</li>
))}
</ul>
</aside>
);
}Link Equity Dağıtımı
Link equity (veya link juice), bir sayfanın sahip olduğu SEO değerinin linkler aracılığıyla aktarılmasıdır.
Nasıl Çalışır?
- Bir sayfa ne kadar çok kaliteli backlink alırsa, o kadar güçlüdür
- Bu güç, sayfadaki internal linkler aracılığıyla diğer sayfalara aktarılır
- Bir sayfadaki link sayısı arttıkça, her linke düşen pay azalır
Stratejik Link Equity Yönetimi
// lib/link-equity.ts
interface Page {
slug: string;
importance: 'high' | 'medium' | 'low';
internalLinksTo: string[];
externalBacklinks: number;
}
function calculateLinkPriority(pages: Page[]): Map<string, number> {
const priorities = new Map<string, number>();
pages.forEach(page => {
let priority = 0;
// Backlink sayısına göre temel puan
priority += page.externalBacklinks * 10;
// Önem seviyesine göre çarpan
const multiplier = {
high: 3,
medium: 2,
low: 1
};
priority *= multiplier[page.importance];
priorities.set(page.slug, priority);
});
return priorities;
}
// Yüksek öncelikli sayfalar daha fazla internal link almalıAnchor Text Stratejisi
❌ Kötü anchor text örnekleri:
- "buraya tıklayın"
- "daha fazla bilgi"
- "bu yazıyı okuyun"
✅ İyi anchor text örnekleri:
- "meta tag optimizasyonu rehberi"
- "canonical tag kullanımı"
- "Core Web Vitals hakkında detaylı bilgi"Anchor text, hedef sayfanın ana anahtar kelimesini içermeli ama aşırı optimizasyondan kaçının.
Content Decay: Eski İçerikleri Canlandırma
Content decay, zamanla içeriğin trafik ve sıralama kaybetmesidir. Bu doğal bir süreçtir ama yönetilebilir.
Decay Belirtileri
- Trafik 3+ ay boyunca düşüyor
- Sıralama kaybı yaşanıyor
- İçerik güncelliğini yitirmiş
- Rakipler daha güncel içerik üretmiş
Content Audit Scripti
// scripts/content-audit.ts
interface ContentHealth {
slug: string;
title: string;
lastUpdated: Date;
daysSinceUpdate: number;
trafficTrend: 'up' | 'stable' | 'declining';
action: 'keep' | 'refresh' | 'consolidate' | 'remove';
}
async function auditContent(): Promise<ContentHealth[]> {
const posts = await getAllPosts();
const now = new Date();
return posts.map(post => {
const lastUpdated = new Date(post.date);
const daysSinceUpdate = Math.floor(
(now.getTime() - lastUpdated.getTime()) / (1000 * 60 * 60 * 24)
);
// Basit karar mantığı
let action: ContentHealth['action'] = 'keep';
if (daysSinceUpdate > 365) {
action = 'refresh'; // 1 yıldan eski, güncelle
}
if (daysSinceUpdate > 730) {
action = 'consolidate'; // 2 yıldan eski, birleştir veya kaldır
}
return {
slug: post.slug,
title: post.title,
lastUpdated,
daysSinceUpdate,
trafficTrend: 'stable', // GA4 API ile gerçek veri alınabilir
action
};
});
}
// Çalıştır
auditContent().then(results => {
const needsAction = results.filter(r => r.action !== 'keep');
console.log('Aksiyon gerektiren içerikler:', needsAction);
});Refresh Stratejisi
İçeriği güncellerken:
- Güncel bilgilerle başla: Tarihler, istatistikler, sürüm numaraları
- Yeni bölümler ekle: Konuyla ilgili yeni gelişmeler
- Eski bilgileri kaldır: Artık geçerli olmayan içerikler
- Internal link'leri güncelle: Yeni içeriklere bağlantı ver
- Date'i güncelle: Frontmatter'da tarihi güncelle
Kullanıcı Deneyimi ve SEO Sinyalleri
Google, kullanıcı davranışlarını sıralama sinyali olarak kullanır. İyi UX = İyi SEO.
Önemli UX Metrikleri
- Dwell Time: Kullanıcının sayfada geçirdiği süre
- Pogo-sticking: SERP'e hızlı geri dönüş (kötü sinyal)
- Scroll Depth: Sayfanın ne kadar okunduğu
- Click-through Rate: SERP'ten tıklanma oranı
Scroll Depth Tracking
// hooks/useScrollDepth.ts
'use client';
import { useState, useEffect, useCallback } from 'react';
export function useScrollDepth() {
const [maxDepth, setMaxDepth] = useState(0);
const handleScroll = useCallback(() => {
const scrollHeight = document.documentElement.scrollHeight - window.innerHeight;
if (scrollHeight <= 0) return;
const scrolled = (window.scrollY / scrollHeight) * 100;
setMaxDepth(prev => Math.max(prev, Math.round(scrolled)));
}, []);
useEffect(() => {
window.addEventListener('scroll', handleScroll, { passive: true });
return () => window.removeEventListener('scroll', handleScroll);
}, [handleScroll]);
// Sayfa kapanırken analytics'e gönder
useEffect(() => {
return () => {
if (typeof window !== 'undefined' && window.gtag && maxDepth > 0) {
window.gtag('event', 'scroll_depth', {
percent: maxDepth,
page: window.location.pathname
});
}
};
}, [maxDepth]);
return maxDepth;
}Reading Progress Indicator
// components/ReadingProgress.tsx
'use client';
import { useScrollDepth } from '@/hooks/useScrollDepth';
export function ReadingProgress() {
const progress = useScrollDepth();
return (
<div className="fixed top-0 left-0 w-full h-1 bg-gray-200 z-50">
<div
className="h-full bg-primary transition-all duration-150"
style={{ width: `${progress}%` }}
/>
</div>
);
}Breadcrumb Navigasyonu
Breadcrumb'lar hem UX hem SEO için değerlidir. Google, breadcrumb'ları SERP'te gösterebilir.
SEO-Friendly Breadcrumb Component
// components/Breadcrumbs.tsx
import Link from 'next/link';
interface BreadcrumbItem {
label: string;
href: string;
}
interface Props {
items: BreadcrumbItem[];
}
export function Breadcrumbs({ items }: Props) {
// JSON-LD Schema
const schema = {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: items.map((item, index) => ({
'@type': 'ListItem',
position: index + 1,
name: item.label,
item: `https://beydemir.dev${item.href}`
}))
};
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
<nav aria-label="Breadcrumb" className="mb-6">
<ol className="flex items-center gap-2 text-sm text-gray-600">
{items.map((item, index) => (
<li key={item.href} className="flex items-center">
{index > 0 && (
<span className="mx-2 text-gray-400">/</span>
)}
{index === items.length - 1 ? (
<span aria-current="page" className="text-gray-900 dark:text-white">
{item.label}
</span>
) : (
<Link
href={item.href}
className="hover:text-primary transition-colors"
>
{item.label}
</Link>
)}
</li>
))}
</ol>
</nav>
</>
);
}
// Kullanım
<Breadcrumbs
items={[
{ label: 'Ana Sayfa', href: '/' },
{ label: 'Blog', href: '/blog' },
{ label: 'SEO Rehberi', href: '/blog/seo-rehberi' }
]}
/>Pagination Best Practices
Sayfalandırma, SEO açısından dikkatli yönetilmeli.
Sorunlar
- Duplicate content: Her sayfa benzer içerik taşır
- Crawl budget israfı: Bot, tüm sayfaları taramak zorunda
- Link equity dağılımı: Güç, sayfalara bölünür
Çözüm Stratejileri
// app/blog/page.tsx
import { Metadata } from 'next';
interface Props {
searchParams: { page?: string };
}
export async function generateMetadata({ searchParams }: Props): Promise<Metadata> {
const page = parseInt(searchParams.page || '1');
return {
title: page === 1 ? 'Blog' : `Blog - Sayfa ${page}`,
robots: page > 1
? { index: false, follow: true } // Sayfa 2+ noindex
: { index: true, follow: true },
alternates: {
canonical: '/blog', // Canonical her zaman ana sayfa
},
};
}Rel Prev/Next (Opsiyonel)
Google artık resmi olarak desteklemiyor ama hala faydalı olabilir:
// Pagination component'inde
{currentPage > 1 && (
<link rel="prev" href={`/blog?page=${currentPage - 1}`} />
)}
{currentPage < totalPages && (
<link rel="next" href={`/blog?page=${currentPage + 1}`} />
)}Load More Alternatifi
Infinite scroll veya "Daha Fazla Yükle" butonu, SEO açısından dikkatli yapılmalı:
// components/LoadMorePosts.tsx
'use client';
export function LoadMorePosts({ initialPosts, totalPosts }) {
const [posts, setPosts] = useState(initialPosts);
const [page, setPage] = useState(1);
// SEO için: İlk yükleme SSR ile yapılmalı
// Load more sonrası yüklenen içerikler client-side
return (
<>
{/* İlk içerikler SSR, crawlable */}
{posts.map(post => <PostCard key={post.slug} post={post} />)}
{/* Load more butonu */}
{posts.length < totalPosts && (
<button onClick={loadMore}>Daha Fazla Göster</button>
)}
{/* Hidden links for crawlers */}
<nav className="sr-only" aria-label="Pagination">
{Array.from({ length: Math.ceil(totalPosts / 10) }, (_, i) => (
<a key={i} href={`/blog?page=${i + 1}`}>Sayfa {i + 1}</a>
))}
</nav>
</>
);
}Pratik Checklist
- Topic cluster yapısı planlandı
- Pillar page ve cluster page'ler belirlendi
- Her cluster page, pillar'a link veriyor
- Pillar page, tüm cluster'lara link veriyor
- Contextual internal linkler eklendi (içerik içinde)
- Anchor text'ler açıklayıcı ve çeşitli
- İlgili yazılar bölümü mevcut
- 6 aydan eski içerikler audit edildi
- Breadcrumb navigasyonu eklendi
- Breadcrumb schema markup'ı var
- Pagination SEO-safe şekilde yapılandırıldı
- Reading progress indicator eklendi
Sık Sorulan Sorular
Bir sayfada kaç internal link olmalı?
Kesin bir sınır yok, ama kaliteyi koruyun. 100+ link makul ama hepsi bağlamla ilgili olmalı. Google, spam'i değil doğal linkleri sever.
Orphan page (yetim sayfa) nedir?
Hiçbir internal link almayan sayfalardır. Bot bu sayfaları keşfedemez. Site haritasında olsalar bile, internal link gücü almadıkları için zayıf kalırlar.
Nofollow internal link kullanmalı mıyım?
Genellikle hayır. Internal linklerde nofollow, link equity akışını engeller. Sadece kullanıcı tarafından oluşturulan içeriklerde (yorumlar) nofollow düşünülebilir.
Content decay'i nasıl tespit ederim?
Google Search Console'da son 6 ayı önceki 6 ayla karşılaştırın. Trafik düşüşü gösteren sayfaları belirleyin. Analytics'te de sayfa bazlı trend analizi yapın.
Topic cluster'da kaç cluster page olmalı?
En az 3-5, ideal olarak 8-10. Daha az olursa yeterli derinlik sağlamaz, çok fazla olursa yönetim zorlaşır. Her cluster, gerçekten ayrı bir alt konu olmalı.
Sonuç
İçerik mimarisi, SEO'nun stratejik temelidir. Bu yazıda öğrendikleriniz:
- Topic clusters tematik otorite oluşturur
- Internal linking güç dağıtımını yönlendirir
- Content decay aktif yönetim gerektirir
- UX sinyalleri SEO'yu doğrudan etkiler
- Breadcrumb ve pagination dikkatli yapılandırılmalı
Bir sonraki yazıda, Schema.org ve JSON-LD konularını inceleyeceğiz: Yapısal veri otomasyonu, rich snippets ve Google'ın içeriğinizi daha iyi anlaması için structured data.
Seri Navigasyonu:
- Arama Niyeti ve Semantik SEO
- Teknik Sayfa Yapısı ve Metadata
- İçerik Mimarisi ve Internal Linking (Bu yazı)
- Schema.org ve JSON-LD
- JavaScript SEO ve Performans
Projenizi Hayata Geçirelim
Web sitesi, mobil uygulama veya yapay zeka çözümü mü arıyorsunuz? Fikirlerinizi birlikte değerlendirelim.
Ücretsiz Danışmanlık Alın