ACF Pro’yu uzun süre kullandım. Custom post type’ları ACF UI’dan tanımlamak, flexible content ile blok benzeri yapılar kurmak kolaydı. Ama son 18 ayda yazdığım WordPress tema ve plugin’lerde ACF’i bir kenara bıraktım, native PHP register_post_type + Gutenberg block registration kullanıyorum. Bu yazıda neden geçtiğimi ve pratikte nasıl işlediğini anlatıyorum.
ACF’in rahatlığı ve gizli maliyeti
ACF’i seviyordum, çünkü client’a kolay anlatıyordum: “Buradan yeni alan ekleyebilirsiniz, content editor’ünüz direkt görecek.” UI’da alan tasarlamak gerçekten hızlı.
Ama 4-5 projede artık kabul etmediğim maliyetleri görmeye başladım:
Ekstra plugin bağımlılığı. ACF Pro lisans alıyorsunuz, her client’a ayrı lisans (veya bir lisansla çoklu site kullanmak ToS’a aykırı olabilir). Bir seferki ödeme değil yıllık.
Field group’lar DB’de yaşıyor. ACF field group’ları PHP’de tanımlamayı seçseniz bile meta yapısı DB’ye kaydediliyor, staging → production sync’inde sorunlu olabiliyor.
Meta query ağırlığı. get_field() her çağrıda DB’ye gidiyor, cache’lemek için ek kod. 50 custom field’ı olan bir post’ta loop içinde get_field() çağırdığınız sayfa hızı düşer.
Developer experience code review’da. ACF field tanımları UI’da yapılırsa git repo’da görünmez, code review imkânsız. PHP export edilirse uzun array’ler oluyor, diff okumak zor.
Version coupling. ACF versiyonu major upgrade yapınca tema test edilmeli. Plugin’e bağımlı tema bakımı zor.
Native CPT: register_post_type
Custom post type tanımlamak PHP ile 30 satır. Tema fonksiyonları içinde şu şekilde:
add_action('init', function() {
register_post_type('project', [
'label' => 'Projects',
'public' => true,
'has_archive' => 'projects',
'rewrite' => ['slug' => 'project'],
'supports' => ['title', 'editor', 'thumbnail', 'custom-fields'],
'show_in_rest' => true,
]);
});Taxonomies için register_taxonomy, meta alanları için register_post_meta ile native REST API entegrasyonu. Gutenberg editor otomatik olarak bu yapıyı tanır.
Bunun ACF’e göre avantajları:
- Git’e commit edilir, code review olur
- Activation/deactivation lifecycle net
- Plugin bağımlılığı yok
- Performance: DB’ye ek tablo yazılmaz
Gutenberg block: register_block_type
ACF Blocks yerine native Gutenberg block yazmak başta dik öğrenme eğrisi ama bir kere yapınca seviliyor.
Minimal native block yapısı:
block.jsondosyası ile block metadata- JS dosyası ile edit + save fonksiyonları (ya da dynamic render için server-side)
- CSS dosyası ile stil
{
"apiVersion": 3,
"name": "alicinaroglu/stat-card",
"title": "Stat Card",
"category": "design",
"attributes": {
"value": {"type": "string"},
"label": {"type": "string"}
},
"supports": {"html": false}
}PHP tarafında:
register_block_type(__DIR__ . '/blocks/stat-card');JavaScript edit component’i kullanıcıya alan gösterir, save function ise HTML üretir veya render callback server-side rendering yapar.
Dynamic block vs static block
Static block: JS save function HTML üretir, post_content’te kalıcı olarak kaydedilir. Render için ekstra iş yok.
Dynamic block: save function null döner, server-side PHP callback ile render edilir. Her sayfa render’ında fresh content alır. Veritabanından post listesi çeken, son içerik gösteren block’lar için dynamic daha uygun.
Ben genelde dynamic block seçiyorum, tema güncellemelerinde markup değişse eski post’lardaki content otomatik yeniden render ediliyor.
InnerBlocks ile nested yapı
Flexible content’in en güzel replacement’ı native InnerBlocks. Bir block container tanımlıyorsunuz, içine hangi block’ların ekleneceğini belirliyorsunuz:
<InnerBlocks
allowedBlocks={['core/heading', 'core/paragraph', 'alicinaroglu/cta-button']}
template={[['core/heading', {level: 2}]]}
/>Kullanıcı UI’da sayfayı block block oluşturuyor, ACF flexible content’in bütün esnekliğini veriyor ama native.
Meta field’lar için CMB2 veya native
Gutenberg editor’ün custom sidebar panel’i ile meta field tanımlamak mümkün. Advanced kullanıcılar için JS tabanlı plugin yaklaşımı gerekebilir. Kısa yoldan gitmek istersem CMB2 (ücretsiz, MIT license) kullanıyorum, ACF’den 4-5 kat hafif.
Öğrenme maliyeti gerçek ama değer
Native block geliştirmek ACF’ten daha zor. React bilmeniz, webpack / wp-scripts ile build etmeniz, block attributes ve save vs edit ayrımını anlamanız gerek.
Ama bu yatırım bir kere yapılıyor. 3. native block’u yazmaya kadar öğrenme eğrisini aşıyorsunuz, sonrası hızlı. ACF ise her projede yine UI tıklamak anlamına geliyor.
Bütçe açısından
Üç orta ölçek projede ACF Pro’dan native’e geçince:
- Lisans maliyetinden yılda yaklaşık 600 USD tasarruf
- TTFB p50 100-150ms iyileşme (plugin overhead’i gitti)
- Theme deployment zamanı yarıya indi (plugin dependency check’leri gitti)
Tavsiye
Yeni projede ACF kullanmayı bırakalı 18 ay oldu ve pişman değilim. Mevcut ACF kurulumlarını migrate etmek de beklediğimden basit: field’lar DB’de post_meta olarak yaşıyor, ACF’i kaldırınca get_post_meta direkt çalışıyor, sadece validation ve admin UI yeniden yazılmalı.
WordPress native’e daha yakın kalmak uzun vadeli bakım kolaylığı demek. Plugin ekosisteminin konforundan vazgeçmek başta zor ama meyvesini sonradan veriyor.