İçerik Aktarma

12 min readUpdated 27 Apr 2026

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.

  1. WordPress Admin → Tools → Export → All content yolunu izleyin. .xml dosyasını indirin.
  2. VeloCMS Admin → Tools → Import → WordPress bölümüne gidin ve .xml dosyasını yükleyin.
  3. Aktarıcı arka planda çalışır — büyük siteler (2000+ yazı) için bu işlem 10-15 dakika sürebilir.
  4. İşlem tamamlandıktan sonra, yönlendirme haritası CSV dosyasını indirin ve Cloudflare Yönlendirme Kuralları veya nginx aracılığıyla uygulayın.
Programmatic import (via CLI — large migrations)
# 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>
bash

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ıÖrnekYö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.

Re-run image sync only
# 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.json
bash

Substack'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.

  1. 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.
  2. Gelen ZIP dosyası `posts.csv` ve `subscriber-list.csv` dosyalarını içerir.
  3. 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.

  1. Ghost Admin → Settings → Labs → Export your content yolunu izleyin. `ghost-export.json` dosyasını indirin.
  2. VeloCMS Admin → Tools → Import → Ghost bölümüne gidin ve JSON dosyasını yükleyin.
  3. Ghost'un ücretli üye seviyesi VeloCMS'te 'paid' olarak, ücretsiz üyeler ise 'free' olarak eşlenir.
  4. Ghost'taki özel alan adları yönlendirme haritasında korunur.
Ghost import with custom redirects
# 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.csv
bash

Yö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.

Import redirects into Cloudflare via API
# 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/
bash

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ı

SenaryoHTTP durumuSEO etkisiÖnerilen durum
Kalıcı taşıma301 Moved PermanentlySEO değerini yeni URL'ye aktarır.Tüm blog taşımaları için standart.
Geçici taşıma302 FoundSEO değerini eski URL'de tutar.Kısa süreli A/B testleri.
İçerik silindi410 GoneSayfanın kalıcı olarak kaldırıldığını bildirir.Artık sunulmayan içerikler.

Yönlendirme Uygulama Seçenekleri

YöntemMaks. yönlendirmeKurulum zorluğuÖnerilen durum
Cloudflare Redirect Rules100 (ücretsiz plan)DüşükÇoğu site için.
nginx `map`~SınırsızOrtaKendi sunucusunu yönetenler.
next.config.js `redirects`~1000 (pratik limit)DüşükKüçük siteler, az yönlendirme.

CLI Aktarıcı Parametreleri

ParametreUygulandığı yerAçıklama
`--file`Tümüİçe aktarılacak dosyanın yolu.
`--platform`Tümü`wordpress`, `substack`, veya `ghost`.
`--include-products`WordPressWooCommerce ürünlerini de yazılara dahil eder.
`--skip-images`WordPress, GhostGö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

Dry run — validate without writing
# 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)
bash

Aktarım Sürecini Kontrol Etme

Check import status via PocketBase API
# 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.totalItems
bash

DNS Değişikliği Öncesi Yönlendirmeleri Hızlıca Test Etme

Spot-check 30 redirects from old site
# 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)
bash

Cloudflare'e Toplu Yönlendirme Yükleme

Cloudflare Bulk Redirects upload
# 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"
bash