WordPress
Bu sayfada
WordPress’i başsız bir CMS gibi kullanın ve bütün siteyi çekin: /wp-json/wp/v2/posts üzerinde sayfalayın, slug başına bir HTML dosyası üretin ve API yanıtlarını derlemeler arasında önbelleğe alın.
Elinize geçenler
- Son yazıları listeleyen bir ana sayfa
/blog— her yazının tam arşivi/blog/[slug]— yazı başına bir statik HTML sayfası (binlerce yazıda da çalışır)- Yeniden derlemelerin her şeyi yeniden indirmek yerine WP yanıtlarını yeniden kullanması için
fetchWithCache
Proje düzeni
my-site/
sitelo.config.js
src/
lib/
wordpress.js # WP REST yardımcıları (sayfalı çekim)
index.ht.js # ana sayfa — son yazıları listele
blog/
index.ht.js # /blog — tam arşiv
[slug].ht.js # /blog/:slug — her yazı
css/
styles.cssexport default {
site: 'https://example.com',
// binlerce sayfa mı? eşzamanlılığı artır
renderConcurrency: 16,
renderBatchSize: 128,
}1. WordPress sitenizi gösterin
REST API modern WordPress’te varsayılan olarak açıktır. https://your-site.com/wp-json/wp/v2/posts adresinden doğrulayın.
Ortamda WP_URL değerini ayarlayın (ya da denerken doğrudan koda yazın):
WP_URL=https://your-wordpress-site.com2. Paylaşılan WordPress yardımcıları
getAllPosts(), X-WP-TotalPages başlığını okur ve her sayfayı gezer (WordPress per_page değerini 100 ile sınırlar). Slugları toplarken _embed kullanmayın — gömülüleri yalnızca tek tek yazılar için getirin.
import { fetchWithCache } from 'sitelo'
const WP_URL = process.env.WP_URL ?? 'https://your-wordpress-site.com'
const PER_PAGE = 100 // /wp/v2/posts için WP üst sınırı
async function wpFetch(path, query = {}) {
const url = new URL(`/wp-json/wp/v2${path}`, WP_URL)
for (const [key, value] of Object.entries(query)) {
if (value != null) url.searchParams.set(key, String(value))
}
const res = await fetchWithCache(url, undefined, {
maxAge: 3600,
cache: 'auto',
})
if (!res.ok) {
throw new Error(`WordPress ${res.status}: ${url}`)
}
return {
data: await res.json(),
totalPages: Number(res.headers.get('X-WP-TotalPages') ?? 1),
total: Number(res.headers.get('X-WP-Total') ?? 0),
}
}
export async function getPosts({ page = 1, perPage = 20, embed = true } = {}) {
const { data } = await wpFetch('/posts', {
page,
per_page: perPage,
_embed: embed ? '1' : undefined,
})
return data
}
/** Site tamamen çekilene dek /posts’un her sayfasında yürü. */
export async function getAllPosts({
perPage = PER_PAGE,
embed = false,
onPage,
} = {}) {
const first = await wpFetch('/posts', {
page: 1,
per_page: perPage,
_embed: embed ? '1' : undefined,
})
const posts = [...first.data]
onPage?.(1, first.totalPages, posts.length)
for (let page = 2; page <= first.totalPages; page += 1) {
const next = await wpFetch('/posts', {
page,
per_page: perPage,
_embed: embed ? '1' : undefined,
})
posts.push(...next.data)
onPage?.(page, first.totalPages, posts.length)
}
return posts
}
export async function getPostBySlug(slug) {
const { data } = await wpFetch('/posts', {
slug,
_embed: '1',
})
return data[0] ?? null
}
export function postPath(post) {
return `/blog/${post.slug}`
}
export function featuredImage(post) {
return post._embedded?.['wp:featuredmedia']?.[0]?.source_url
}3. Ana sayfa
import { getPosts, postPath } from './lib/wordpress.js'
export async function data() {
const posts = await getPosts({ perPage: 5 })
return { posts }
}
export default ({ data }) => `
<html lang="tr">
<head>
<title>Sitem</title>
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<h1>Blogdan son çıkanlar</h1>
<ul>
${data.posts
.map(
(post) => `
<li>
<a href="${postPath(post)}">${post.title.rendered}</a>
</li>`,
)
.join('')}
</ul>
<p><a href="/blog">Tüm yazılar</a></p>
</body>
</html>
`import { html, head, title, link, body, h1, ul, li, a, p } from 'javascript-to-html'
import { getPosts, postPath } from './lib/wordpress.js'
export async function data() {
const posts = await getPosts({ perPage: 5 })
return { posts }
}
export default ({ data }) =>
html({ lang: 'tr' },
head(
title('Sitem'),
link({ rel: 'stylesheet', href: '/styles.css' }),
),
body(
h1('Blogdan son çıkanlar'),
ul(
...data.posts.map((post) =>
li(a({ href: postPath(post) }, post.title.rendered)),
),
),
p(a({ href: '/blog' }, 'Tüm yazılar')),
),
)import { getPosts, postPath } from './lib/wordpress.js'
export async function data() {
const posts = await getPosts({ perPage: 5 })
return { posts }
}
export default function Home({ data }) {
return (
<html lang="tr">
<head>
<title>Sitem</title>
<link rel="stylesheet" href="/css/styles.css" />
</head>
<body>
<h1>Blogdan son çıkanlar</h1>
<ul>
{data.posts.map((post) => (
<li key={post.slug}>
<a href={postPath(post)}>{post.title.rendered}</a>
</li>
))}
</ul>
<p><a href="/blog">Tüm yazılar</a></p>
</body>
</html>
)
}4. Blog dizini
Arşiv 50–100 öğeyle sınırlanmasın diye getAllPosts() kullanın.
import { getAllPosts, postPath } from '../lib/wordpress.js'
export async function data() {
// Tam arşiv — tüm WP sitesinde sayfa sayfa ilerle
const posts = await getAllPosts({ embed: false })
return { posts }
}
export default ({ data }) => `
<html lang="tr">
<head>
<title>Blog</title>
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<h1>Blog (${data.posts.length})</h1>
<ul>
${data.posts
.map(
(post) => `
<li>
<a href="${postPath(post)}">${post.title.rendered}</a>
<time>${post.date.slice(0, 10)}</time>
</li>`,
)
.join('')}
</ul>
</body>
</html>
`import { html, head, title, link, body, h1, ul, li, a, time } from 'javascript-to-html'
import { getAllPosts, postPath } from '../lib/wordpress.js'
export async function data() {
// Tam arşiv — tüm WP sitesinde sayfa sayfa ilerle
const posts = await getAllPosts({ embed: false })
return { posts }
}
export default ({ data }) =>
html({ lang: 'tr' },
head(
title('Blog'),
link({ rel: 'stylesheet', href: '/styles.css' }),
),
body(
h1(`Blog (${data.posts.length})`),
ul(
...data.posts.map((post) =>
li(
a({ href: postPath(post) }, post.title.rendered),
time(post.date.slice(0, 10)),
),
),
),
),
)import { getAllPosts, postPath } from '../lib/wordpress.js'
export async function data() {
// Tam arşiv — tüm WP sitesinde sayfa sayfa ilerle
const posts = await getAllPosts({ embed: false })
return { posts }
}
export default function BlogIndex({ data }) {
return (
<html lang="tr">
<head>
<title>Blog</title>
<link rel="stylesheet" href="/css/styles.css" />
</head>
<body>
<h1>Blog ({data.posts.length})</h1>
<ul>
{data.posts.map((post) => (
<li key={post.slug}>
<a href={postPath(post)}>{post.title.rendered}</a>
<time>{post.date.slice(0, 10)}</time>
</li>
))}
</ul>
</body>
</html>
)
}5. Her yazıyı statik sayfalara çekin
generateStaticParams, dist/ içinde istediğiniz her slug’ı döndürmelidir. API’yi burada sayfalayın — getPosts({ perPage: 100 }) çağrısını bir kez yapıp durmayın.
import {
getAllPosts,
getPostBySlug,
featuredImage,
} from '../lib/wordpress.js'
export async function generateStaticParams() {
const ripStarted = performance.now()
console.log(
`[wordpress] yazılar çekiliyor… (${process.uptime().toFixed(1)}s başlangıçtan beri)`,
)
// Yayımlanmış her yazıyı çek (binlercesi sorun değil — istek başına 100)
const posts = await getAllPosts({
embed: false, // yalnızca slug; hız için _embed’i atla
onPage: (page, totalPages, count) => {
console.log(`[wordpress] sayfa ${page}/${totalPages} (${count} yazı)`)
},
})
const ripSeconds = ((performance.now() - ripStarted) / 1000).toFixed(1)
console.log(
`[wordpress] çekildi ${posts.length} yazı süre: ${ripSeconds}s` +
` (${process.uptime().toFixed(1)}s başlangıçtan beri)`,
)
return posts.map((post) => ({ slug: post.slug }))
}
export async function data({ params }) {
const post = await getPostBySlug(params.slug)
if (!post) throw new Error(`Yazı bulunamadı: ${params.slug}`)
return { post }
}
export default ({ data }) => {
const { post } = data
const image = featuredImage(post)
return `
<html lang="tr">
<head>
<title>${post.title.rendered}</title>
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<article>
<p><a href="/blog">← Blog</a></p>
<h1>${post.title.rendered}</h1>
<time>${post.date.slice(0, 10)}</time>
${image ? `<img src="${image}" alt="">` : ''}
<div class="content">
${post.content.rendered}
</div>
</article>
</body>
</html>
`
}import {
html, head, title, link, body, article, p, a, h1, time, img, div,
} from 'javascript-to-html'
import {
getAllPosts,
getPostBySlug,
featuredImage,
} from '../lib/wordpress.js'
export async function generateStaticParams() {
const ripStarted = performance.now()
console.log(
`[wordpress] yazılar çekiliyor… (${process.uptime().toFixed(1)}s başlangıçtan beri)`,
)
// Yayımlanmış her yazıyı çek (binlercesi sorun değil — istek başına 100)
const posts = await getAllPosts({
embed: false, // yalnızca slug; hız için _embed’i atla
onPage: (page, totalPages, count) => {
console.log(`[wordpress] sayfa ${page}/${totalPages} (${count} yazı)`)
},
})
const ripSeconds = ((performance.now() - ripStarted) / 1000).toFixed(1)
console.log(
`[wordpress] çekildi ${posts.length} yazı süre: ${ripSeconds}s` +
` (${process.uptime().toFixed(1)}s başlangıçtan beri)`,
)
return posts.map((post) => ({ slug: post.slug }))
}
export async function data({ params }) {
const post = await getPostBySlug(params.slug)
if (!post) throw new Error(`Yazı bulunamadı: ${params.slug}`)
return { post }
}
export default ({ data }) => {
const { post } = data
const image = featuredImage(post)
return html({ lang: 'tr' },
head(
title(post.title.rendered),
link({ rel: 'stylesheet', href: '/styles.css' }),
),
body(
article(
p(a({ href: '/blog' }, '← Blog')),
h1(post.title.rendered),
time(post.date.slice(0, 10)),
image ? img({ src: image, alt: '' }) : '',
div({ class: 'content' }, post.content.rendered),
),
),
)
}import {
getAllPosts,
getPostBySlug,
featuredImage,
} from '../lib/wordpress.js'
export async function generateStaticParams() {
const ripStarted = performance.now()
console.log(
`[wordpress] yazılar çekiliyor… (${process.uptime().toFixed(1)}s başlangıçtan beri)`,
)
// Yayımlanmış her yazıyı çek (binlercesi sorun değil — istek başına 100)
const posts = await getAllPosts({
embed: false, // yalnızca slug; hız için _embed’i atla
onPage: (page, totalPages, count) => {
console.log(`[wordpress] sayfa ${page}/${totalPages} (${count} yazı)`)
},
})
const ripSeconds = ((performance.now() - ripStarted) / 1000).toFixed(1)
console.log(
`[wordpress] çekildi ${posts.length} yazı süre: ${ripSeconds}s` +
` (${process.uptime().toFixed(1)}s başlangıçtan beri)`,
)
return posts.map((post) => ({ slug: post.slug }))
}
export async function data({ params }) {
const post = await getPostBySlug(params.slug)
if (!post) throw new Error(`Yazı bulunamadı: ${params.slug}`)
return { post }
}
export default function BlogPost({ data }) {
const { post } = data
const image = featuredImage(post)
return (
<html lang="tr">
<head>
<title>{post.title.rendered}</title>
<link rel="stylesheet" href="/css/styles.css" />
</head>
<body>
<article>
<p><a href="/blog">← Blog</a></p>
<h1>{post.title.rendered}</h1>
<time>{post.date.slice(0, 10)}</time>
{image ? <img src={image} alt="" /> : null}
<div
className="content"
dangerouslySetInnerHTML={{ __html: post.content.rendered }}
/>
</article>
</body>
</html>
)
}6. Derleme
WP_URL=https://your-wordpress-site.com sitelo buildİlk derleme WordPress üzerinden bir kez sayfalar ve getirme önbelleğini doldurur. Sonraki derlemeler maxAge dolana dek önbelleğe alınmış liste/ayrıntı yanıtlarını yeniden kullanır (cache: 'auto' → üretimde dosya sistemi). Binlerce yazı sayfası işliyorsanız sitelo.config.js içindeki renderConcurrency değerini yükseltin.
Notlar
WordPress’ten gelen HTML
title.rendered ve content.rendered WP’den gelen HTML dizeleridir. Onları şablonunuza olduğu gibi bırakın (yukarıdaki gibi) ya da CMS’e tümüyle güvenmiyorsanız temizleyin.
Özel içerik
Genel REST rotaları yalnızca yayımlanmış yazıları açar. Taslaklar ya da özel kimlik doğrulama için başlıkları fetchWithCache fonksiyonunun ikinci argümanına (standart fetch init) geçirin ve kararlı bir cacheKey kullanın.
Veri yükleme belgeleri · Yönlendirme belgeleri