WordPress’te bir eklenti geliştirirken er ya da geç şu ihtiyaçla karşılaşırsınız: eklentinizin ürettiği veriyi (lisans durumu, sipariş özeti, entegrasyon durumu, dashboard metriği ne olursa olsun) dışarıya, bir mobil uygulamaya veya başka bir sisteme güvenli şekilde açmanız gerekir. WordPress’in kendi REST API altyapısı bunun için hazır bir zemin sunuyor, ama register_rest_route() fonksiyonunu doğru permission_callback ve nonce mantığı olmadan kullanmak, sitenizi ciddi bir güvenlik açığına dönüştürebilir. Bu konuyu daha önce WordPress Connectors API ile harici servis entegrasyonu yazısında farklı bir açıdan ele almıştım; bu yazıda ise doğrudan özel endpoint yazımına, kimlik doğrulamaya ve production’da karşılaştığım hatalara odaklanıyorum.
- İçindekiler
- Neden Özel REST API Endpoint’e İhtiyaç Duyarız?
- Proje Senaryosu: Lisans Kontrolü İçin Özel Endpoint
- Gerekli Araçlar ve Ön Hazırlık
- Adım Adım: Özel REST API Endpoint Kaydı
- permission_callback ile Yetkilendirme Nasıl Yapılır?
- REST API İsteklerinde Nonce Kullanımı
- Karşılaşılan Hatalar ve Çözümleri
- Performans, Güvenlik ve SEO Kontrolleri
- İlgili Yazılar
- Kaynaklar
- Sonuç: Özel REST API Endpoint Geliştirme Özeti
- Sık Sorulan Sorular
- WordPress REST API’de permission_callback zorunlu mudur?
- Nonce süresi dolduğunda ne olur?
- Application Password ile nonce aynı anda kullanılır mı?
- Özel endpoint’i sadece belirli bir rol için nasıl kısıtlarım?
- REST API endpoint’i 404 dönüyor, neden?
- Girdi doğrulamasını nerede yapmalıyım?
- Rate limiting’i WordPress çekirdeği ile yapabilir miyim?
Bu yazıda; bir WooCommerce lisans kontrol paneli için geliştirdiğim örnek üzerinden özel bir REST API endpoint’inin nasıl kaydedildiğini, permission_callback ile yetkilendirmenin nasıl kurgulandığını, nonce ile CSRF korumasının nasıl sağlandığını ve gerçek projelerde karşıma çıkan hata mesajlarını adım adım anlatıyorum. Amaç, kopyala-yapıştır bir “merhaba dünya” endpoint’i değil; production’a çıkabilecek, güvenli ve sürdürülebilir bir yapı kurmak.
İçindekiler
- Neden Özel REST API Endpoint’e İhtiyaç Duyarız?
- Proje Senaryosu: Lisans Kontrolü İçin Özel Endpoint
- Gerekli Araçlar ve Ön Hazırlık
- Adım Adım: Özel REST API Endpoint Kaydı
- permission_callback ile Yetkilendirme Nasıl Yapılır?
- REST API İsteklerinde Nonce Kullanımı
- Karşılaşılan Hatalar ve Çözümleri
- Performans, Güvenlik ve SEO Kontrolleri
- İlgili Yazılar
- Kaynaklar
- Sonuç: Özel REST API Endpoint Geliştirme Özeti
- Sık Sorulan Sorular
Neden Özel REST API Endpoint’e İhtiyaç Duyarız?
WordPress çekirdeği zaten /wp/v2/posts, /wp/v2/users gibi hazır endpoint’ler sunuyor. Ancak bir eklenti kendi iş mantığını (örneğin bir lisans anahtarının geçerliliğini, bir entegrasyonun senkron durumunu veya bir mobil uygulamanın ihtiyaç duyduğu özel bir veri kümesini) dışarı açmak istediğinde, bu hazır endpoint’ler yetersiz kalır. Özel endpoint yazmanın asıl faydası, veriyi tam olarak ihtiyaç duyulan şekilde, gereksiz alanlar olmadan ve kendi yetkilendirme kurallarınızla sunabilmenizdir. Bunu doğru yapmayan projelerde en sık gördüğüm sorun, herkese açık (public) bırakılmış ve permission_callback içinde her zaman true dönen endpoint’lerin, site verisini istemeden dışarıya sızdırmasıdır.
Proje Senaryosu: Lisans Kontrolü İçin Özel Endpoint
Bir WooCommerce tabanlı ürün için lisans doğrulama sistemi geliştirdiğim projede, müşterinin satın aldığı ürünün lisans anahtarını harici bir masaüstü uygulamadan doğrulaması gerekiyordu. Burada iki seçenek vardı: mevcut bir sayfa şablonu üzerinden AJAX ile çözüm üretmek ya da temiz, versiyonlanabilir bir REST API endpoint’i açmak. İkincisini seçtim çünkü hem dokümante edilebilir hem de mobil/masaüstü istemcilerden bağımsız şekilde çağrılabilir bir yapı istiyordum. Benzer bir mimariyi eklenti tarafında nasıl kurguladığımı Lisans Doğrulama API Sistemi Nasıl Kurulur? yazısında da anlatmıştım; bu yazıda REST API’nin kayıt ve güvenlik katmanına daha çok odaklanıyorum. [Kendi projemden ekran görüntüsü eklenecek]
Eklentiyi organize ederken endpoint tanımlarını tek bir dev dosyada tutmak yerine, her kaynak (lisans, sipariş, entegrasyon durumu) için ayrı bir controller sınıfı kullandım: class Ob_Rest_Lisans_Controller gibi. Bu yaklaşım, endpoint sayısı arttıkça kodun okunabilirliğini korumamı sağladı ve her controller’ın kendi register_routes() metodunu rest_api_init içinde tek tek çağırmamı kolaylaştırdı. Küçük bir eklentide tek dosya yeterli olsa da, üç dört endpoint’i geçtiğiniz an bu ayrımı yapmanızı öneririm.
Gerekli Araçlar ve Ön Hazırlık
Başlamadan önce şunlara ihtiyacınız var:
- Yerel geliştirme ortamı (Local, XAMPP veya Docker tabanlı bir WordPress kurulumu)
- Özel bir eklenti dosyası veya tema
functions.phpyerine ayrı bir eklenti (production’da tema dosyasına yazmayın) - Postman veya Insomnia gibi bir API test aracı
- WordPress’te en az bir yönetici ve bir “abone” rolünde test kullanıcısı
- Application Password veya cookie tabanlı kimlik doğrulama için tarayıcı oturumu
Adım Adım: Özel REST API Endpoint Kaydı

Endpoint kaydı rest_api_init hook’u içinde yapılır. Temel iskelet şu şekildedir:
add_action( 'rest_api_init', function () {
register_rest_route( 'ozgurbayram/v1', '/lisans-durum/(?P<key>[a-zA-Z0-9-]+)', array(
'methods' => WP_REST_Server::READABLE,
'callback' => 'ob_lisans_durum_getir',
'permission_callback' => 'ob_lisans_yetki_kontrol',
'args' => array(
'key' => array(
'validate_callback' => function( $param ) {
return is_string( $param ) && strlen( $param ) > 10;
},
),
),
) );
} );
Burada dikkat edilmesi gereken üç nokta var: isim alanınızı (ozgurbayram/v1) benzersiz tutmak, args içinde validate_callback ile giren veriyi doğrulamak ve permission_callback‘i asla boş bırakmamak. Callback fonksiyonu içinde ise WP_REST_Response nesnesi döndürmek, ham dizi döndürmekten daha kontrollüdür çünkü HTTP durum kodunu (200, 403, 404) doğrudan yönetebilirsiniz.
İsim alanına versiyon numarası (v1) eklemek, ileride endpoint’in davranışını değiştirmeniz gerektiğinde eski istemcileri kırmadan yeni bir v2 yayınlamanıza olanak tanır. Bir mobil uygulama bu API’yi tüketiyorsa, uygulama mağazasındaki güncelleme onay sürecinin günler sürebileceğini unutmayın; bu yüzden geriye dönük uyumluluğu bozacak değişiklikleri her zaman yeni bir versiyon altında yayınlamayı tercih ediyorum.
permission_callback ile Yetkilendirme Nasıl Yapılır?
Gördüğüm en yaygın hata, permission_callback parametresinin tamamen atlanması ya da __return_true ile herkese açılmasıdır. Bu, eklenti geliştirme dokümantasyonunda bile eskiden örnek olarak geçiyordu ve birçok geliştirici bunu production koduna taşıdı. Doğru yaklaşım, isteği yapan kullanıcının rolünü veya taşıdığı özel bir yetkiyi kontrol etmektir:
function ob_lisans_yetki_kontrol( WP_REST_Request $request ) {
if ( ! is_user_logged_in() ) {
return new WP_Error(
'rest_forbidden',
'Bu isteği yapmak için giriş yapmalısınız.',
array( 'status' => 401 )
);
}
if ( ! current_user_can( 'manage_woocommerce' ) ) {
return new WP_Error(
'rest_forbidden',
'Bu işlemi yapmaya yetkiniz yok.',
array( 'status' => 403 )
);
}
return true;
}
Harici bir masaüstü/mobil istemciden erişim gerekiyorsa, çerez tabanlı oturum yerine Application Passwords (WordPress 5.6 ile çekirdeğe eklendi) kullanmak, kullanıcı adı/şifreyi doğrudan paylaşmadan güvenli bir Basic Auth katmanı sağlar. Kendi projemde lisans doğrulama isteklerini bu yöntemle imzaladım ve her istemciye ayrı bir uygulama şifresi verip, sorun çıkması durumunda tek bir şifreyi iptal edebildim.
REST API İsteklerinde Nonce Kullanımı

Nonce, özellikle tarayıcı içinden (aynı origin’den) yapılan AJAX/REST isteklerinde CSRF saldırılarına karşı koruma sağlar. Sunucu tarafında script’i kaydederken nonce’u şu şekilde tarayıcıya aktarıyorum:
wp_localize_script( 'ob-lisans-panel', 'obApi', array(
'root' => esc_url_raw( rest_url() ),
'nonce' => wp_create_nonce( 'wp_rest' ),
) );
İstemci tarafında ise her fetch isteğine bu nonce’u X-WP-Nonce header’ı olarak eklemek zorunludur, aksi halde çerez tabanlı kimlik doğrulama WordPress tarafından reddedilir:
fetch( obApi.root + 'ozgurbayram/v1/lisans-durum/ABC123', {
headers: { 'X-WP-Nonce': obApi.nonce }
} );
Önemli bir ayrım: nonce, çerez tabanlı (aynı site içi) isteklerde CSRF koruması sağlar; Application Password veya OAuth ile yapılan tamamen harici isteklerde nonce mantığı geçerli değildir, çünkü o istekler zaten farklı bir kimlik doğrulama katmanı kullanır. İkisini karıştırmak, projelerde en çok gördüğüm kavram karmaşasıdır.
Karşılaşılan Hatalar ve Çözümleri
Hata 1: rest_cookie_invalid_nonce (401)
Bu hata, tarayıcıdan yapılan istekte nonce eksik ya da süresi dolmuş olduğunda ortaya çıkar. Nonce ömrü varsayılan olarak 24-48 saat arasıdır; sayfa uzun süre açık kaldıysa nonce geçersiz hale gelir. Çözüm, sayfa yenilendiğinde nonce’u tazelemek veya heartbeat API ile periyodik yenileme yapmaktır.
Hata 2: rest_forbidden (403)permission_callback içindeki current_user_can() kontrolü beklenen rolle eşleşmediğinde döner. Genellikle geliştirici, endpoint’i yönetici hesabıyla test ettiği için fark etmez; gerçek kullanıcı (örneğin “editor” veya özel bir rol) ile test edilmediğinde production’da ortaya çıkar. Çözüm: her rolü ayrı ayrı test etmek ve gerekiyorsa özel bir capability tanımlamak.
Hata 3: 404 Not Found (route bulunamıyor)
Genellikle rest_api_init hook’unun eklenti yüklenmeden önce tetiklenmesi ya da permalink yapısının “Sade” (plain) olarak ayarlanmasından kaynaklanır. Permalink ayarlarını kaydetmek (Ayarlar > Kalıcı Bağlantılar sayfasına girip tekrar kaydetmek) çoğu zaman route’un rewrite kurallarını yeniler.
Hata 4: rest_invalid_param (400)args içindeki validate_callback beklenen formatı bulamadığında bu hata döner; genellikle istemci tarafında gönderilen parametre tipinin (string yerine sayı, veya tam tersi) yanlış olmasından kaynaklanır. Postman ile isteği tekrar oynatıp gövdeyi (body) satır satır kontrol etmek, sorunu hızlıca ortaya çıkarır.
[Gerçek hata mesajı ve log kaydı buraya eklenecek]
Performans, Güvenlik ve SEO Kontrolleri

- Güvenlik: Girdi verisini her zaman
sanitize_text_field(),absint()gibi fonksiyonlarla temizleyin; çıktıyıesc_html()ile kaçının. - Hız: Sık çağrılan endpoint’lerde
wp_cache_get()/wp_cache_set()ile transient veya object cache kullanmak, veritabanı yükünü azaltır. - Loglama: Başarısız yetkilendirme denemelerini bir log dosyasına yazmak, olası kaba kuvvet (brute force) denemelerini erken fark etmenizi sağlar.
- Rate limiting: WordPress çekirdeğinde yerleşik bir rate limit yoktur; yoğun kullanılan endpoint’lerde sunucu seviyesinde (Nginx/Apache) veya bir eklenti ile sınırlama eklemek gerekir.
- Indexleme: REST API endpoint’lerinizin arama motorları tarafından indexlenmesini istemiyorsanız,
robots.txtiçinde/wp-json/yolunu yönetmeyi değerlendirin; ancak bu, API’nin çalışmasını engellemez, sadece indexlenmesini etkiler.
İlgili Yazılar
- WordPress Connectors API ile Harici Servis Entegrasyonu
- WordPress Abilities API Nedir, Eklentilere Yetenek Nasıl?
- Lisans Doğrulama API Sistemi Nasıl Kurulur?
- Eklenti Mimarisi Nedir, PHP Projesinde Nasıl Planlanır?
- Role Based Access Control Nedir, Nasıl Kurulur?
Kaynaklar
- WordPress REST API Handbook
- WordPress REST API Authentication Dokümantasyonu
- Application Passwords Integration Guide (WordPress.org)
- OWASP CSRF (Cross-Site Request Forgery) Rehberi
Sonuç: Özel REST API Endpoint Geliştirme Özeti
Özel bir WordPress REST API endpoint’i yazmak teknik olarak birkaç satır kod kadar basit görünse de, güvenli ve sürdürülebilir bir yapı kurmak permission_callback, nonce/Application Password ayrımı ve girdi doğrulamasının birlikte doğru kurgulanmasını gerektiriyor. Bu yazıda anlattığım lisans kontrol senaryosunda olduğu gibi, endpoint’i önce en kısıtlayıcı yetkilendirme kuralıyla açıp ihtiyaca göre gevşetmek, tam tersine göre çok daha güvenli bir yaklaşım. Endpoint’i yayına almadan önce mutlaka farklı kullanıcı rolleriyle test edin ve başarısız yetkilendirme denemelerini loglayın.
Sık Sorulan Sorular
WordPress REST API’de permission_callback zorunlu mudur?
Teknik olarak zorunlu değildir ancak boş bırakıldığında WordPress bir uyarı (deprecation notice) üretir ve endpoint varsayılan olarak herkese açık kabul edilir. Production’da her zaman açık bir permission_callback tanımlamalısınız.
Nonce süresi dolduğunda ne olur?
Süresi dolmuş bir nonce ile yapılan istek rest_cookie_invalid_nonce hatasıyla 401 döner. Çözüm, sayfa yenilendiğinde ya da periyodik olarak nonce’u tazelemektir.
Application Password ile nonce aynı anda kullanılır mı?
Hayır, genellikle ikisi farklı senaryolar içindir. Nonce, çerez tabanlı aynı-origin isteklerde CSRF koruması sağlar; Application Password ise harici istemcilerin Basic Auth ile kimlik doğrulaması içindir.
Özel endpoint’i sadece belirli bir rol için nasıl kısıtlarım?
permission_callback içinde current_user_can( 'capability_adi' ) kontrolü ile istediğiniz role veya özel bir capability’ye göre kısıtlama yapabilirsiniz.
REST API endpoint’i 404 dönüyor, neden?
En sık nedenler: permalink ayarlarının yenilenmemesi, rest_api_init hook’unun doğru tetiklenmemesi veya route isim alanının/pattern’ın yanlış yazılmasıdır. Kalıcı Bağlantılar sayfasını tekrar kaydetmek çoğu zaman sorunu çözer.
Girdi doğrulamasını nerede yapmalıyım?
register_rest_route() içindeki args parametresinde validate_callback ve sanitize_callback ile; ayrıca callback fonksiyonu içinde de ek kontrol yapmak iyi bir pratiktir.
Rate limiting’i WordPress çekirdeği ile yapabilir miyim?
Hayır, WordPress çekirdeğinde yerleşik bir rate limit mekanizması yoktur. Sunucu seviyesinde (Nginx limit_req, Apache mod_ratelimit) veya üçüncü parti bir eklenti ile bu katmanı eklemeniz gerekir.
Bir Cevap Yaz
E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir.