İçerik Aktarma
Bir blogu taşımak, bir platformun ya güven kazandığı ya da kaybettiği o kritik andır. VeloCMS bu işi ciddiye alıyor ve en yaygın üç kaynak olan WordPress, Substack ve Ghost için özel aktarıcılarla geliyor. Her aktarıcı, taşıma sırasında en çok baş ağrıtan iki konuyu titizlikle ele alıyor: görseller (kaybolmadan R2'ye taşınması) ve URL'ler (SEO değerinizin buharlaşmaması için yönlendirmelerin korunması). Bu rehber, her platform için izlemeniz gereken adımları anlatıyor.
WordPress'ten İçerik Aktarma
WordPress, WXR (WordPress eXtended RSS) adında bir formatta dışa aktarım yapar — bu aslında bir XML dosyasıdır. VeloCMS'in WordPress aktarıcısı bu dosyayı okur, yazıların HTML'ini TipTap uyumlu içerik formatına dönüştürür, referans verilen tüm görselleri indirip sizin R2 bucket'ınıza yeniden yükler ve eski WordPress link yapınızdan yeni VeloCMS linklerine bir yönlendirme haritası oluşturur.
- WordPress Admin → Tools → Export → All content yolunu izleyin. .xml dosyasını indirin.
- VeloCMS Admin → Tools → Import → WordPress bölümüne gidin ve .xml dosyasını yükleyin.
- Aktarıcı arka planda çalışır — büyük siteler (2000+ yazı) için bu işlem 10-15 dakika sürebilir.
- İşlem tamamlandıktan sonra, yönlendirme haritası CSV dosyasını indirin ve Cloudflare Yönlendirme Kuralları veya nginx aracılığıyla uygulayın.
# For migrations with 1000+ posts, use the CLI importer directly
# (bypasses the 30s admin timeout)
POCKETBASE_URL=https://your-pb.up.railway.app POCKETBASE_ADMIN_EMAIL=[email protected] POCKETBASE_ADMIN_PASSWORD=yourpassword R2_BUCKET_NAME=velocms-media node scripts/import-wordpress.mjs --file ./export.xml --tenant-id <tenant-id>WordPress URL Eşlemesi
WordPress, kalıcı bağlantı ayarlarınıza bağlı olarak birkaç farklı link formatı kullanır. Aktarıcı, dışa aktarım dosyasından eski yapınızı algılar ve Cloudflare için 301 yönlendirme kuralları oluşturur:
| WordPress formatı | Örnek | Yönlendirildiği yer |
|---|---|---|
| Day and name | `/2023/10/26/sample-post/` | `/blog/sample-post` |
| Month and name | `/2023/10/sample-post/` | `/blog/sample-post` |
| Post name | `/sample-post/` | `/blog/sample-post` |
Görsellerin R2'ye Yüklenmesi
WordPress yazı içeriğinde referans verilen her bir görsel, aktarım sırasında indirilip sizin Cloudflare R2 bucket'ınıza yeniden yüklenir. Aktarıcı, yazı içeriğindeki orijinal WordPress alan adı URL'lerini sizin R2 genel URL'niz ile değiştirir. Eğer bir görselin indirilmesi başarısız olursa (mesela 404 hatası veya rate limit yüzünden), bu durum `import-errors.json` dosyasına kaydedilir ve yazı, orijinal URL korunarak aktarılır. Yani endişelenmenize gerek yok, görsel senkronizasyonunu daha sonra tekrar çalıştırabilirsiniz.
# After the main import, sync any failed images
node scripts/import-wordpress.mjs --file ./export.xml --tenant-id <id> --images-only --retry-errors ./import-errors.jsonSubstack'ten İçerik Aktarma
Substack iki dosya halinde dışa aktarım yapar: yazılar için bir CSV (meta veriler + HTML içerik) ve aboneler için ayrı bir CSV. VeloCMS her ikisini de yönetir — yazılar `posts` koleksiyonunuza, aboneler ise `blog_members` içine gider. Substack'ten gelen yazı HTML'i oldukça temizdir ve özel bir dönüştürücüye ihtiyaç duymadan sorunsuzca aktarılır.
- Substack → Settings → Exports bölümünden dışa aktarım talebinde bulunun. İndirme bağlantısını içeren bir e-posta alacaksınız.
- Gelen ZIP dosyası `posts.csv` ve `subscriber-list.csv` dosyalarını içerir.
- VeloCMS Admin → Tools → Import → Substack bölümüne gidin ve her iki dosyayı da yükleyin (veya sadece yazılara ya da abonelere ihtiyacınız varsa tek birini).
Ghost'tan İçerik Aktarma
Ghost, yazıları, sayfaları, etiketleri ve üyeleri tek bir JSON dosyasında dışa aktarır. VeloCMS'in Ghost aktarıcısı bu dosyanın tamamını işler — Ghost'un Mobiledoc/Lexical formatını zengin metin düzenlemesi için TipTap JSON'a dönüştürür, Ghost etiketlerini VeloCMS kategorilerine eşler ve üyeleri üyelik seviyeleriyle birlikte aktarır.
- Ghost Admin → Settings → Labs → Export your content yolunu izleyin. `ghost-export.json` dosyasını indirin.
- VeloCMS Admin → Tools → Import → Ghost bölümüne gidin ve JSON dosyasını yükleyin.
- Ghost'un ücretli üye seviyesi VeloCMS'te 'paid' olarak, ücretsiz üyeler ise 'free' olarak eşlenir.
- Ghost'taki özel alan adları yönlendirme haritasında korunur.
# Programmatic Ghost import with redirect map output
POCKETBASE_URL=https://your-pb.up.railway.app POCKETBASE_ADMIN_EMAIL=[email protected] POCKETBASE_ADMIN_PASSWORD=yourpassword node scripts/import-ghost.mjs --file ./ghost-export.json --tenant-id <id> --output-redirects ./ghost-redirects.csvYönlendirmeleri Koruma
Her aktarıcı, `kaynak,hedef,durum_kodu` formatında bir `redirects.csv` dosyası oluşturur. Aktarım bittikten sonra bu yönlendirmeleri CDN katmanında (Cloudflare Yönlendirme Kuralları) veya sunucunuzda (nginx/Caddy) uygulamanız gerekir. Bunları Next.js'in `next.config.ts` dosyasında yapmak da bir seçenek ama büyük bloglar için pek tavsiye edilmez. Neden mi? Çünkü `next.config.ts` içindeki binlerce yönlendirme kuralı, build dosyasını gereksiz yere şişirir.
# Upload bulk redirects to Cloudflare using the Bulk Redirects API
curl -X POST "https://api.cloudflare.com/client/v4/accounts/$CLOUDFLARE_ACCOUNT_ID/rules/lists" -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" -H "Content-Type: application/json" -d '{"name":"velocms-migration-redirects","kind":"redirect"}'
# Then upload the redirect items CSV via:
# https://developers.cloudflare.com/rules/bulk-redirects/Referans
WordPress WXR Alanı → VeloCMS Alan Eşlemesi
| WordPress Alanı | VeloCMS Alanı | Notlar |
|---|---|---|
| `title` | `title` | Doğrudan eşleme. |
| `content:encoded` | `content` | HTML, TipTap JSON formatına dönüştürülür. |
| `wp:post_date` | `published_at` | Tarih formatı korunur. |
| `category` (domain='category') | `categories` | Etiketler (post_tag) de kategorilere eşlenir. |
| `wp:status` | `status` | `publish` → `published`, `draft` → `draft` |
Yönlendirme Stratejisi Referansı
| Senaryo | HTTP durumu | SEO etkisi | Önerilen durum |
|---|---|---|---|
| Kalıcı taşıma | 301 Moved Permanently | SEO değerini yeni URL'ye aktarır. | Tüm blog taşımaları için standart. |
| Geçici taşıma | 302 Found | SEO değerini eski URL'de tutar. | Kısa süreli A/B testleri. |
| İçerik silindi | 410 Gone | Sayfanın kalıcı olarak kaldırıldığını bildirir. | Artık sunulmayan içerikler. |
Yönlendirme Uygulama Seçenekleri
| Yöntem | Maks. yönlendirme | Kurulum zorluğu | Önerilen durum |
|---|---|---|---|
| Cloudflare Redirect Rules | 100 (ücretsiz plan) | Düşük | Çoğu site için. |
| nginx `map` | ~Sınırsız | Orta | Kendi sunucusunu yönetenler. |
| next.config.js `redirects` | ~1000 (pratik limit) | Düşük | Küçük siteler, az yönlendirme. |
CLI Aktarıcı Parametreleri
| Parametre | Uygulandığı yer | Açıklama |
|---|---|---|
| `--file` | Tümü | İçe aktarılacak dosyanın yolu. |
| `--platform` | Tümü | `wordpress`, `substack`, veya `ghost`. |
| `--include-products` | WordPress | WooCommerce ürünlerini de yazılara dahil eder. |
| `--skip-images` | WordPress, Ghost | Görsel indirme ve R2'ye yükleme adımını atlar. |
Substack → VeloCMS Alan Eşlemesi
| Substack CSV Alanı | VeloCMS Alanı | Notlar |
|---|---|---|
| `title` | `title` | Doğrudan eşleme. |
| `body_html` | `content` | HTML, TipTap JSON formatına dönüştürülür. |
| `post_date` | `published_at` | Tarih formatı korunur. |
| `type` | `access_level` | `paid` → `paid`, `free` → `public` |
Ghost → VeloCMS Alan Eşlemesi
| Ghost JSON Alanı | VeloCMS Alanı | Notlar |
|---|---|---|
| `title` | `title` | Doğrudan eşleme. |
| `mobiledoc` / `lexical` | `content` | Her iki format da TipTap JSON'a dönüştürülür. |
| `published_at` | `published_at` | Doğrudan eşleme. |
| `tags` | `categories` | Ghost etiketleri kategori olarak aktarılır. |
| `visibility` | `access_level` | `members` → `free`, `paid` → `paid` |
Taşımadan Önce Prova Yapma
# Parse and validate the export without writing anything to PocketBase.
# Shows what would be imported: post count, image count, member count, errors.
node scripts/import-wordpress.mjs --file ./export.xml --tenant-id <id> --dry-run
# Example output:
# Posts to import: 2,341
# Images to download: 1,847
# Categories to create: 12
# Validation errors: 3 (see ./dry-run-errors.json)Aktarım Sürecini Kontrol Etme
# List recently imported posts (last 10, sorted by creation time)
curl -G '$POCKETBASE_URL/api/collections/posts/records' --data-urlencode 'sort=-created' --data-urlencode 'perPage=10' --data-urlencode 'fields=id,title,slug,status,created' -H 'Authorization: Bearer <admin-token>'
# Count total posts in tenant
curl '$POCKETBASE_URL/api/collections/posts/records?perPage=1' -H 'Authorization: Bearer <admin-token>'
# Check response.totalItemsDNS Değişikliği Öncesi Yönlendirmeleri Hızlıca Test Etme
# Before changing DNS, confirm your redirect rules work against the old domain.
# Redirect CSV format: source,destination,status_code
while IFS=',' read -r source dest _code; do
actual=$(curl -s -o /dev/null -w "%{redirect_url}" "https://oldsite.com$source")
expected="https://newsite.com$dest"
if [ "$actual" = "$expected" ]; then
echo "PASS: $source"
else
echo "FAIL: $source → got $actual (expected $expected)"
fi
done < <(tail -n +2 redirects.csv | shuf | head -30)Cloudflare'e Toplu Yönlendirme Yükleme
# Step 1: Create a redirect list
LIST_ID=$(curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/$CLOUDFLARE_ACCOUNT_ID/rules/lists" -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" -H "Content-Type: application/json" -d '{"name":"migration-redirects","kind":"redirect"}' | jq -r '.result.id')
# Step 2: Upload items to the list
# (The importer outputs redirect items JSON via --output-cf-json flag)
node scripts/import-wordpress.mjs --file ./export.xml --tenant-id <id> --output-cf-json ./cf-redirects.json
curl -X POST "https://api.cloudflare.com/client/v4/accounts/$CLOUDFLARE_ACCOUNT_ID/rules/lists/$LIST_ID/items" -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" -H "Content-Type: application/json" --data-binary "@cf-redirects.json"