REST API’de Özel Alan Kayıt Etme: register_rest_field Kullanımı
WordPress REST API’si ile çalışırken kaçınılmaz olarak şu soruyla karşılaşırsın: “Bu endpoint’ten dönen veriye neden kendi alanlarımı ekleyemiyorum?” İşte tam bu noktada register_rest_field() fonksiyonu devreye giriyor. Bu fonksiyon, mevcut REST API kaynak tiplerine özel alan eklemenin resmi ve temiz yolu. Doğrudan veritabanı sorgularını hacklemek yerine, WordPress’in sağladığı bu API ile hem güvenli hem de sürdürülebilir bir yapı kurabilirsin.
register_rest_field Nedir ve Neden Kullanmalısın?
WordPress REST API, post, page, user, comment gibi kaynak tiplerini JSON formatında döndürür. Ama çoğu zaman bu standart alanlar yetmez. Bir ürünün özel meta verisini API üzerinden sunman gerekebilir, kullanıcı profiline ekstra bilgi eklemen gerekebilir ya da bir custom post type’ın özel alanlarını harici bir uygulamaya beslemen gerekebilir.
register_rest_field(), tam da bu ihtiyaç için tasarlanmış. Fonksiyon üç temel şeyi yapmanı sağlıyor:
- GET isteklerinde API yanıtına yeni alan eklemek
- POST/PUT isteklerinde gelen veriyi işlemek (yani alana yazma izni vermek)
- Alanın şemasını tanımlamak (API belgelerinde görünsün diye)
Bu fonksiyonu functions.php dosyasına ya da bir eklentiye ekleyebilirsin. Ben genellikle production ortamlarda bunu ayrı bir eklenti olarak tutmayı tercih ederim, ama tema geliştirme sürecinde functions.php de gayet işe yarıyor.
Temel Sözdizimi
register_rest_field( $object_type, $attribute, $args );
Parametreleri açıklayalım:
- $object_type: Alan eklemek istediğin kaynak tipi.
'post','page','user','comment'ya da custom post type slug’ı olabilir. Dizi de geçebilirsin:array('post', 'page') - $attribute: API yanıtında görünecek alan adı. String olarak veriyorsun, örneğin
'ozel_alan' - $args: Alanın davranışını belirleyen argüman dizisi
– get_callback: GET isteğinde çalışacak fonksiyon – update_callback: POST/PUT isteğinde çalışacak fonksiyon – schema: Alanın veri tipi ve açıklaması
Bu fonksiyonu her zaman rest_api_init kancasına bağlı çalıştırmalısın. Aksi halde REST API henüz yüklenmeden kayıt yapmaya çalışmış olursun ve beklenmedik hatalar alırsın.
İlk Örnek: Basit Bir Meta Alanı Okumak
Diyelim ki postlarına _ozel_yazar_notu adında bir meta alanı kaydediyorsun ve bunu REST API üzerinden sunmak istiyorsun.
add_action( 'rest_api_init', function() {
register_rest_field( 'post', 'yazar_notu', array(
'get_callback' => function( $post_arr ) {
return get_post_meta( $post_arr['id'], '_ozel_yazar_notu', true );
},
'schema' => array(
'description' => 'Yazara ait ozel not',
'type' => 'string',
),
) );
} );
Bu kadar. Artık /wp-json/wp/v2/posts endpoint’ine GET isteği attığında her post objesi içinde yazar_notu alanını göreceksin. Eğer alan boşsa boş string dönecek, bu da frontend tarafında güvenle işleyebileceğin bir değer.
İkinci Örnek: Alana Yazma İşlemi Eklemek
Sadece okumak değil, yazmak da istiyorsan update_callback parametresini ekliyorsun. Aşağıdaki örnekte kullanıcı bu alanı REST API üzerinden güncelleyebilecek.
add_action( 'rest_api_init', function() {
register_rest_field( 'post', 'yazar_notu', array(
'get_callback' => function( $post_arr ) {
return get_post_meta( $post_arr['id'], '_ozel_yazar_notu', true );
},
'update_callback' => function( $value, $post ) {
if ( ! current_user_can( 'edit_post', $post->ID ) ) {
return new WP_Error(
'rest_forbidden',
'Bu alani duzenleme yetkiniz yok.',
array( 'status' => 403 )
);
}
$value = sanitize_text_field( $value );
return update_post_meta( $post->ID, '_ozel_yazar_notu', $value );
},
'schema' => array(
'description' => 'Yazara ait ozel not',
'type' => 'string',
),
) );
} );
Burada dikkat etmem gereken iki şey var: yetki kontrolü ve sanitizasyon. current_user_can() ile yazma yetkisi olmayan kullanıcıların bu alanı değiştirmesini engelliyorum. sanitize_text_field() ile de gelen veriyi temizliyorum. Bu iki adımı atlama, özellikle public API’lerde ciddi güvenlik açıklarına yol açabilir.
Üçüncü Örnek: Kullanıcı Kaynağına Alan Eklemek
Kullanıcı profillerine telefon numarası gibi özel bir alan eklemek istediğini düşün. WooCommerce kullanan sitelerde bu çok yaygın bir senaryo.
add_action( 'rest_api_init', function() {
register_rest_field( 'user', 'telefon_numarasi', array(
'get_callback' => function( $user_arr ) {
return get_user_meta( $user_arr['id'], 'billing_phone', true );
},
'update_callback' => function( $value, $user ) {
if ( ! current_user_can( 'edit_user', $user->ID ) ) {
return new WP_Error(
'rest_forbidden',
'Kullanici bilgilerini duzenleme yetkiniz yok.',
array( 'status' => 403 )
);
}
$value = sanitize_text_field( $value );
return update_user_meta( $user->ID, 'billing_phone', $value );
},
'schema' => array(
'description' => 'Kullanicinin fatura telefon numarasi',
'type' => 'string',
),
) );
} );
Bu örnekte WooCommerce’in billing_phone meta anahtarını kullandım. Bu sayede hem WooCommerce admin panelinden hem de REST API üzerinden aynı veriyi yönetebilirsin.
Dördüncü Örnek: Custom Post Type ile Kullanım
Diyelim ki etkinlik adında bir custom post type’ın var ve her etkinliğin bir tarihi var (_etkinlik_tarihi meta alanında saklı). Bu veriyi API’de sunmak için:
add_action( 'rest_api_init', function() {
register_rest_field( 'etkinlik', 'etkinlik_tarihi', array(
'get_callback' => function( $post_arr ) {
$tarih = get_post_meta( $post_arr['id'], '_etkinlik_tarihi', true );
if ( empty( $tarih ) ) {
return null;
}
// Tarihi standart ISO 8601 formatına cevir
$timestamp = strtotime( $tarih );
return date( 'Y-m-dTH:i:s', $timestamp );
},
'update_callback' => function( $value, $post ) {
if ( ! strtotime( $value ) ) {
return new WP_Error(
'gecersiz_tarih',
'Gecerli bir tarih formatı girin.',
array( 'status' => 400 )
);
}
return update_post_meta( $post->ID, '_etkinlik_tarihi', sanitize_text_field( $value ) );
},
'schema' => array(
'description' => 'Etkinlik tarihi (ISO 8601)',
'type' => 'string',
'format' => 'date-time',
),
) );
} );
Burada tarih formatı dönüşümü yapıyorum. Harici uygulamalar genellikle ISO 8601 bekler, veritabanında ise farklı bir format saklıyor olabilirsin. Bu dönüşümü get_callback içinde yaparak API tüketicisini bu detaydan soyutlamış oluyorsun. Güzel bir pratik bu.
Beşinci Örnek: Hesaplanmış Alan Döndürmek
register_rest_field() sadece meta alanları okumakla sınırlı değil. Hesaplanmış değerler de döndürebilirsin. Örneğin bir yazının okunma süresini hesaplayıp döndürmek istersen:
add_action( 'rest_api_init', function() {
register_rest_field( 'post', 'okunma_suresi', array(
'get_callback' => function( $post_arr ) {
$icerik = get_post_field( 'post_content', $post_arr['id'] );
$icerik = strip_tags( $icerik );
$kelime_sayisi = str_word_count( $icerik );
// Ortalama okuma hizi: dakikada 200 kelime
$dakika = ceil( $kelime_sayisi / 200 );
return array(
'dakika' => $dakika,
'kelime_sayisi' => $kelime_sayisi,
'metin' => $dakika . ' dakika okuma suresi',
);
},
'schema' => array(
'description' => 'Tahmini okunma suresi',
'type' => 'object',
'properties' => array(
'dakika' => array( 'type' => 'integer' ),
'kelime_sayisi' => array( 'type' => 'integer' ),
'metin' => array( 'type' => 'string' ),
),
),
) );
} );
Bu örnekte bir obje döndürdüm ve schema’yı da buna göre tanımladım. REST API bu şema bilgisini /wp-json/wp/v2/posts endpoint’inin OPTIONS isteğinde otomatik olarak sunuyor. API belgelerini otomatik oluşturan araçlar için bu çok değerli.
Altıncı Örnek: WooCommerce Ürünlerine Alan Eklemek
WooCommerce ürünleri product post type’ı altında çalışır. Bir ürüne özel bir garanti süresi alanı eklemek istediğini düşün:
add_action( 'rest_api_init', function() {
register_rest_field( 'product', 'garanti_suresi', array(
'get_callback' => function( $post_arr ) {
$ay = get_post_meta( $post_arr['id'], '_garanti_ay', true );
if ( empty( $ay ) ) {
return null;
}
return array(
'ay' => (int) $ay,
'metin' => $ay . ' ay garanti',
);
},
'update_callback' => function( $value, $post ) {
if ( ! current_user_can( 'edit_products' ) ) {
return new WP_Error(
'rest_forbidden',
'Urun duzenleme yetkiniz yok.',
array( 'status' => 403 )
);
}
$ay = absint( $value );
if ( $ay < 0 || $ay > 120 ) {
return new WP_Error(
'gecersiz_deger',
'Garanti suresi 0-120 ay arasında olmalı.',
array( 'status' => 400 )
);
}
return update_post_meta( $post->ID, '_garanti_ay', $ay );
},
'schema' => array(
'description' => 'Urun garanti suresi',
'type' => 'object',
),
) );
} );
Dikkat etmen gereken nokta: WooCommerce REST API’si (/wp-json/wc/v3/products) ayrı bir endpoint sistemi kullanıyor. register_rest_field() WordPress core REST API’si için çalışır. Eğer WooCommerce’in kendi API’sine alan eklemek istiyorsan woocommerce_rest_prepare_product_object gibi özel kancaları kullanman gerekiyor.
Yedinci Örnek: Birden Fazla Post Type’a Aynı Anda Kayıt
Bazı alanlar birden fazla kaynak tipinde kullanılabilir. Bunu tek seferde halledebilirsin:
add_action( 'rest_api_init', function() {
$desteklenen_tipler = array( 'post', 'page', 'etkinlik', 'haber' );
register_rest_field( $desteklenen_tipler, 'seo_baslik', array(
'get_callback' => function( $post_arr ) {
$seo_baslik = get_post_meta( $post_arr['id'], '_seo_baslik', true );
if ( empty( $seo_baslik ) ) {
return get_the_title( $post_arr['id'] );
}
return $seo_baslik;
},
'update_callback' => function( $value, $post ) {
if ( ! current_user_can( 'edit_post', $post->ID ) ) {
return new WP_Error(
'rest_forbidden',
'Duzenleme yetkiniz yok.',
array( 'status' => 403 )
);
}
return update_post_meta(
$post->ID,
'_seo_baslik',
sanitize_text_field( $value )
);
},
'schema' => array(
'description' => 'SEO baslik alani',
'type' => 'string',
'maxLength' => 60,
),
) );
register_rest_field( $desteklenen_tipler, 'seo_aciklama', array(
'get_callback' => function( $post_arr ) {
return get_post_meta( $post_arr['id'], '_seo_aciklama', true );
},
'update_callback' => function( $value, $post ) {
if ( ! current_user_can( 'edit_post', $post->ID ) ) {
return new WP_Error(
'rest_forbidden',
'Duzenleme yetkiniz yok.',
array( 'status' => 403 )
);
}
return update_post_meta(
$post->ID,
'_seo_aciklama',
sanitize_textarea_field( $value )
);
},
'schema' => array(
'description' => 'SEO meta aciklamasi',
'type' => 'string',
'maxLength' => 160,
),
) );
} );
Bu yapıyı kullanarak basit bir özel SEO alanı sistemi kurmuş oldun. Yoast gibi eklentileri kuramadığın ya da kurmak istemediğin projelerde işe yarıyor.
Dikkat Etmen Gereken Noktalar
Performans Konusu
Her get_callback çağrısı bir veritabanı sorgusu tetikleyebilir. Özellikle liste endpoint’lerinde (/wp-json/wp/v2/posts gibi) bu sorun büyür. 10 yazı döndürüyorsa ve 5 özel alanın varsa, 50 ekstra sorgu demek. Bunu önlemek için WordPress’in object cache’ini kullanabilir ya da posts_clauses filtresiyle veriyi ana sorguda çekebilirsin.
add_action( 'rest_api_init', function() {
register_rest_field( 'post', 'goruntuleme_sayisi', array(
'get_callback' => function( $post_arr ) {
$cache_key = 'goruntuleme_' . $post_arr['id'];
$cached = wp_cache_get( $cache_key, 'ozel_rest_alanlar' );
if ( false !== $cached ) {
return $cached;
}
$deger = (int) get_post_meta( $post_arr['id'], '_goruntuleme_sayisi', true );
wp_cache_set( $cache_key, $deger, 'ozel_rest_alanlar', 300 );
return $deger;
},
'schema' => array(
'description' => 'Yazinin goruntuleme sayisi',
'type' => 'integer',
),
) );
} );
Güvenlik Kontrol Listesi
- Her
update_callbackiçinde mutlaka yetki kontrolü yap - Gelen veriyi sanitize et: string için
sanitize_text_field(), HTML içeren alanlar içinwp_kses_post(), sayısal değerler içinabsint()veyafloatval() - Hassas alanları sadece yetkili kullanıcılara dön:
get_callbackiçinde de yetki kontrolü yapabilirsin - Dönüş değerlerini doğrula: Beklenmedik null veya false değerlerini handle et
Schema Tanımı Neden Önemli
Schema tanımlamak zorunlu değil ama yapmaman büyük hata olur. WordPress REST API discovery sistemi bu bilgiyi kullanır. Gutenberg editörü, mobil uygulamalar ve üçüncü parti araçlar bu şemayı okuyarak alanının nasıl davranacağını anlıyor. Ayrıca REST API, gelen verinin şemaya uyup uymadığını otomatik olarak doğrulayabilir.
Sık Yapılan Hatalar
rest_api_inityerineinitkancasını kullanmak: Bazen çalışıyor gibi görünse de doğru değilget_callback‘in ilk parametresinin tam post nesnesi değil, dizi olduğunu unutmak:$post_arr['id']kullanman gerekiyor,$post_arr->IDdeğilupdate_callback‘in ikinci parametresinin iseWP_Postnesnesi olduğunu gözden kaçırmak: Burada$post->IDdoğru kullanım- Sanitizasyon yapmadan doğrudan veritabanına yazmak
Gerçek Dünya Senaryosu: Mobil Uygulama Entegrasyonu
Bir müşteri için haber sitesi geliştirdiğini düşün. Mobil uygulama ekibi REST API üzerinden içerik çekiyor ve onlara şunu iletiyorlar: “Her haberin önizleme görselinin URL’si, kısa açıklaması ve tahmini okunma süresi tek endpoint’ten gelmeli.”
Bu ihtiyacı şöyle çözersin: Üç ayrı register_rest_field() çağrısıyla onizleme_gorseli, kisa_aciklama ve okunma_suresi alanlarını /wp-json/wp/v2/posts endpoint’ine eklersin. Mobil ekip tek bir API isteğiyle tüm bu veriyi çeker, ne frontend’de ayrı çağrılar yapar ne de backend’de karmaşık özel endpoint’ler yazman gerekir.
Bu yaklaşımın güzelliği şu: WordPress core güncellemelerinden etkilenmiyorsun, standart REST API altyapısını kullanıyorsun ve üçüncü parti araçlarla uyumluluğu korumuş oluyorsun.
register_meta ile Farkı
WordPress’te aynı işi yapan gibi görünen başka bir fonksiyon daha var: register_meta(). Eğer show_in_rest parametresini true olarak geçersen meta alanı REST API’de otomatik olarak görünür. Peki hangisini kullanmalısın?
- register_meta kullan: Basit, tekli meta alanları için. Özel dönüşüm veya hesaplama yapmayacaksan.
- register_rest_field kullan: Hesaplanmış değerler döndüreceksen, birden fazla meta alanını birleştireceksen, özel sanitizasyon veya validasyon mantığın varsa, alan adını meta key’den farklı tutmak istiyorsan.
Sonuç
register_rest_field() WordPress REST API’sini özelleştirmenin en temiz ve resmi yolu. Doğrudan filtreleri hacklemek ya da tamamen yeni endpoint’ler yazmak yerine bu fonksiyonu kullanmak, kodunu hem WordPress standartlarıyla uyumlu tutuyor hem de gelecekteki güncellemelere karşı dayanıklı hale getiriyor.
Özellikle şu senaryolarda bu fonksiyona ihtiyaç duyacaksın: mobil uygulama entegrasyonları, headless WordPress projeleri, harici CRM ya da pazarlama araçlarıyla API senkronizasyonu ve Gutenberg bloklarına özel meta veri sağlama. Her durumda güvenlik kontrollerini ve sanitizasyonu atlamadan, schema tanımını eksiksiz yaparak kullan.
Bir kez mantığını kavradıktan sonra çok kullanışlı bir araç haline geliyor. Sonraki yazıda register_rest_route() ile tamamen özel endpoint’ler yazmayı ele alacağım, o da bu konunun doğal devamı niteliğinde.
