WP_DEBUG ile WordPress Eklenti Hata Ayıklama Rehberi
Bir WordPress sitesinde eklenti hatası ayıklamak, özellikle production ortamında işler ters gittiğinde gerçekten sinir bozucu olabiliyor. Müşterinin sitesi bozulmuş, telefon çalıyor, sen de hangi eklentinin ne yaptığını anlamaya çalışıyorsun. İşte tam bu noktada WP_DEBUG sistemi devreye giriyor ve hayat kurtarıyor.
WP_DEBUG Nedir ve Neden Önemlidir
WordPress, PHP’nin hata raporlama mekanizmasının üzerine kendi debug katmanını inşa etmiş. WP_DEBUG, temelde PHP hatalarını, uyarıları ve bildirim mesajlarını yüzeye çıkaran bir sabit. Ama bu tanım biraz yüzeysel kalıyor. Gerçekte WP_DEBUG ekosistemi birkaç farklı sabiti kapsıyor ve her biri farklı bir amaca hizmet ediyor.
Bir eklenti geliştiriyorsanız ya da mevcut bir eklentinin neden garip davrandığını anlamaya çalışıyorsanız, bu sistemi doğru konfigüre etmeden kör uçuş yapıyorsunuz demektir. PHP’nin kendi hata günlükleri size bazı bilgiler verse de WordPress’e özgü hook çakışmaları, veritabanı sorgu sorunları veya deprecated fonksiyon kullanımları gibi durumları yakalamanın en sistematik yolu WP_DEBUG’ı doğru kullanmaktan geçiyor.
wp-config.php Temel Konfigürasyonu
Her şey wp-config.php dosyasında başlıyor. Bu dosyayı açtığınızda muhtemelen şunu görüyorsunuzdur:
define( 'WP_DEBUG', false );
Bu satırı değiştirerek debug modunu aktif edebilirsiniz, ama bu kadarla yetinmek büyük bir hata. Sadece WP_DEBUG‘ı true yapmak, hataları doğrudan ekrana basar. Production sitede bu, ziyaretçilerin hata mesajları görmesi anlamına gelir. Hem güvenlik açığı hem de profesyonellik meselesi.
Doğru yaklaşım şöyle olmalı:
// Hata ayıklama modunu aktifleştir
define( 'WP_DEBUG', true );
// Hataları ekrana YAZMA, dosyaya yaz
define( 'WP_DEBUG_DISPLAY', false );
// Hataları log dosyasına kaydet
define( 'WP_DEBUG_LOG', true );
// PHP hata raporlamasını da kapsamlı tut
@ini_set( 'display_errors', 0 );
Bu dört satır, güvenli bir debug ortamının temelini oluşturuyor. WP_DEBUG_LOG true olduğunda WordPress, hataları /wp-content/debug.log dosyasına yazıyor. WP_DEBUG_DISPLAY false olduğunda ise bu hatalar ekrana çıkmıyor.
Öte yandan log dosyasının konumunu da özelleştirebilirsiniz:
// Log dosyasının konumunu değiştir
define( 'WP_DEBUG_LOG', '/var/log/wordpress/debug.log' );
Bu özellikle paylaşımlı hosting dışındaki ortamlarda çok işe yarıyor. Web kökünün dışında bir yere log yazmak, log dosyasının browser üzerinden erişilebilir olmasını engeller.
SCRIPT_DEBUG ve SAVEQUERIES
WP_DEBUG ailesinin iki üyesi daha var, bunları çoğu rehber atlıyor ama eklenti geliştirmede kritik roller oynuyorlar.
// Minify edilmemiş CSS ve JS dosyalarını yükle
define( 'SCRIPT_DEBUG', true );
// Tüm veritabanı sorgularını kaydet
define( 'SAVEQUERIES', true );
SCRIPT_DEBUG aktifleştirildiğinde WordPress, .min.js ve .min.css yerine orijinal, okunabilir versiyonları yüklüyor. Bir eklentinin JavaScript tarafında sorun arıyorsanız bu ayar olmadan browser konsolundaki hataları takip etmek gerçekten işkenceye dönüşüyor.
SAVEQUERIES ise başlı başına bir konu. Bu sabit aktif olduğunda WordPress, her sayfada çalıştırılan tüm SQL sorgularını $wpdb->queries dizisine kaydediyor. Performans sorunlarını araştırırken bu dizi altın değerinde oluyor.
Şöyle bir kod parçası ile bunu raporlayabilirsiniz:
<?php
// Sadece admin kullanıcılar için sorgu raporunu göster
if ( current_user_can( 'manage_options' ) && defined( 'SAVEQUERIES' ) && SAVEQUERIES ) {
add_action( 'shutdown', function() {
global $wpdb;
echo '<pre style="background:#1e1e1e;color:#d4d4d4;padding:20px;margin:20px;font-size:12px;">';
echo '<strong>Toplam Sorgu Sayisi: ' . count( $wpdb->queries ) . '</strong>' . PHP_EOL;
echo '<strong>Toplam Sure: ' . array_sum( array_column( $wpdb->queries, 1 ) ) . ' saniye</strong>' . PHP_EOL . PHP_EOL;
foreach ( $wpdb->queries as $key => $query ) {
printf(
"[%d] %.4f saniyen%snAciklama: %snn",
$key + 1,
$query[1],
$query[0],
$query[2]
);
}
echo '</pre>';
});
}
Bu kod parçasını bir mu-plugin olarak ekleyebilirsiniz. Sayfanın en altında admin kullanıcılar için tüm sorguları gösterir.
Gerçek Dünya Senaryosu: Deprecated Fonksiyon Sorunu
Geçen ay bir WooCommerce sitesinde ödeme sayfası ara ara beyaz ekran veriyordu. Log’a bakınca şöyle bir şey görecektim:
tail -f /wp-content/debug.log
Log çıktısı şöyle geldi:
[07-Mar-2024 14:23:11 UTC] PHP Deprecated: Function get_product() is deprecated since version 3.0.0!
Use wc_get_product() instead. in /var/www/html/wp-includes/functions.php on line 5831
[07-Mar-2024 14:23:11 UTC] PHP Fatal error: Call to undefined method WC_Product_Simple::get_price_html()
in /var/www/html/wp-content/plugins/custom-checkout-addon/includes/class-price-display.php on line 87
İki sorun açıkça görünüyor. Birincisi deprecated bir fonksiyon kullanımı, ikincisi ise artık var olmayan bir metot çağrısı. WP_DEBUG olmadan bu site sadece “beyaz ekran” verirdi ve sorunun kaynağını bulmak saatler sürebilirdi. Debug log ile sorunu dakikalar içinde eklentinin tam dosyasına ve satır numarasına kadar tespit ettik.
Custom Debug Fonksiyonları Yazmak
Production’a taşımadan önce kendi geliştirdiğiniz kodda hata ayıklamak için sadece WP_DEBUG’a güvenmek yetersiz kalıyor. Pratik bir çözüm olarak şöyle bir yardımcı fonksiyon seti kullanıyorum:
<?php
/**
* Gelismiş debug yardımcı fonksiyonları
* Bu dosyayı /wp-content/mu-plugins/debug-helpers.php olarak kaydet
*/
if ( ! function_exists( 'dd' ) ) {
/**
* Var_dump + die - Sadece WP_DEBUG aktifken calisir
*/
function dd( $data, $label = '' ) {
if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) {
return;
}
$output = '<pre style="background:#282c34;color:#abb2bf;padding:15px;margin:10px;border-left:4px solid #e06c75;font-size:13px;">';
if ( $label ) {
$output .= '<strong style="color:#e5c07b;">[ ' . esc_html( $label ) . ' ]</strong>' . PHP_EOL;
}
$backtrace = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 1 );
$output .= '<small style="color:#5c6370;">Kaynak: ' . $backtrace[0]['file'] . ':' . $backtrace[0]['line'] . '</small>' . PHP_EOL . PHP_EOL;
ob_start();
var_dump( $data );
$output .= ob_get_clean();
$output .= '</pre>';
echo $output;
die();
}
}
if ( ! function_exists( 'debug_log' ) ) {
/**
* Debug.log'a formatli yazma
*/
function debug_log( $data, $label = '' ) {
if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) {
return;
}
$message = '';
if ( $label ) {
$message .= '[' . $label . '] ';
}
if ( is_array( $data ) || is_object( $data ) ) {
$message .= print_r( $data, true );
} else {
$message .= $data;
}
error_log( $message );
}
}
Bu mu-plugin’i bir kez kurduğunuzda, geliştirdiğiniz tüm eklentilerde dd() ve debug_log() fonksiyonlarını kullanabiliyorsunuz. dd() fonksiyonu otomatik olarak hangi dosyanın hangi satırından çağrıldığını da gösteriyor, bu kalabalık bir kod tabanında çok büyük kolaylık sağlıyor.
Hook ve Filter Çakışmalarını Tespit Etmek
WordPress’in en güçlü yanı olan hook sistemi, aynı zamanda en büyük debug kabusu olabiliyor. İki eklenti aynı hook’a bağlanıyor, birbirinin çıktısını bozuyor ve siz oturup hangisinin suçlu olduğunu bulmaya çalışıyorsunuz.
Şu yaklaşım bu tür sorunlarda çok işe yarıyor:
<?php
/**
* Belirli bir hook'a bagli tum callback'leri listele
* Kullanim: hook_debug('the_content') seklinde cagirilabilir
*/
function hook_debug( $hook_name ) {
global $wp_filter;
if ( ! isset( $wp_filter[ $hook_name ] ) ) {
debug_log( $hook_name . ' icin kayitli hook bulunamadi.', 'HOOK_DEBUG' );
return;
}
$hooks = $wp_filter[ $hook_name ];
$output = PHP_EOL . '=== ' . $hook_name . ' Hook Listesi ===' . PHP_EOL;
foreach ( $hooks->callbacks as $priority => $callbacks ) {
$output .= PHP_EOL . 'Oncelik: ' . $priority . PHP_EOL;
foreach ( $callbacks as $callback ) {
$function = $callback['function'];
if ( is_array( $function ) ) {
$name = ( is_object( $function[0] ) ? get_class( $function[0] ) : $function[0] ) . '::' . $function[1];
} elseif ( $function instanceof Closure ) {
$name = 'Closure (Anonim Fonksiyon)';
} else {
$name = $function;
}
$output .= ' - ' . $name . ' (Arguman sayisi: ' . $callback['accepted_args'] . ')' . PHP_EOL;
}
}
error_log( $output );
}
// Kullanim ornegi - wp_loaded sonrasinda cagir
add_action( 'wp_loaded', function() {
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
hook_debug( 'woocommerce_checkout_order_processed' );
}
});
Bu fonksiyonu, sorunlu olduğunu düşündüğünüz hook’ta çalıştırdığınızda, debug.log dosyasına hangi eklentinin hangi callback’i hangi öncelikte kaydettiği yazılıyor. Bir WooCommerce sipariş işleme sorununda bu listeye baktığımda bazen 15-20 farklı callback görüyorum ve hangisinin çakışma yarattığını hemen anlayabiliyorum.
Query Monitor ile WP_DEBUG’ı Tamamlamak
WP_DEBUG iyi bir başlangıç ama Query Monitor eklentisi olmadan eksik kalıyor. Bu eklenti, WP_DEBUG’ın log dosyasına yazdığı her şeyi görsel bir arayüzde sunuyor ve üstüne çok daha fazlasını ekliyor.
Query Monitor aktifken şunları görebiliyorsunuz:
- Veritabanı sorguları: Her sorgunun süresi, çağıran eklenti, kullanılan index bilgisi
- Hook’lar ve action’lar: Sayfada çalışan tüm hook’ların listesi ve süreleri
- HTTP API çağrıları: Eklentilerin yaptığı dış API istekleri
- Block editör hataları: Gutenberg blokları için özel hata ayıklama
- Çevre bilgileri: PHP versiyonu, aktif eklentiler, tema bilgileri
Query Monitor, geliştirme ortamında mutlaka bulunması gereken bir araç. Ama dikkat: Production’da aktif bırakmak bir opsiyon değil, kesinlikle kaldırılması lazım.
Staging Ortamı için Otomatik Debug Konfigürasyonu
Bir staging ortamı kuruyorsanız, debug ayarlarını ortam değişkenine göre otomatik olarak açıp kapatmak hayat kolaylaştırıyor. wp-config.php’de şu şekilde yapabilirsiniz:
<?php
// Ortam tipini belirle (bu satir wp-config.php basinda olmali)
define( 'WP_ENVIRONMENT_TYPE', getenv('WP_ENV') ?: 'production' );
// Debug ayarlarini ortama gore yap
switch ( WP_ENVIRONMENT_TYPE ) {
case 'local':
case 'development':
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', true );
define( 'SCRIPT_DEBUG', true );
define( 'SAVEQUERIES', true );
break;
case 'staging':
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', '/var/log/wordpress/staging-debug.log' );
define( 'WP_DEBUG_DISPLAY', false );
define( 'SCRIPT_DEBUG', false );
define( 'SAVEQUERIES', false );
break;
case 'production':
default:
define( 'WP_DEBUG', false );
define( 'WP_DEBUG_LOG', false );
define( 'WP_DEBUG_DISPLAY', false );
define( 'SCRIPT_DEBUG', false );
define( 'SAVEQUERIES', false );
break;
}
Sunucuda WP_ENV ortam değişkenini Apache ya da Nginx konfigürasyonundan set edebiliyorsunuz:
# Apache .htaccess veya VirtualHost icin
SetEnv WP_ENV staging
# Nginx icin fastcgi_params'a ekle
fastcgi_param WP_ENV staging;
# Veya PHP-FPM pool konfigurasyonunda
env[WP_ENV] = staging
Bu yaklaşımla aynı wp-config.php dosyasını tüm ortamlarda kullanabiliyorsunuz, ortam bazlı ayrı dosyalar tutmak zorunda kalmıyorsunuz.
Debug.log Dosyasını Izlemek ve Analiz Etmek
Debug log dosyası zamanla büyüyüp yüzlerce megabayta ulaşabiliyor. Bunu yönetmek için birkaç pratik yaklaşım var.
Önce canlı takip:
# Sadece son satirlari takip et
tail -f /wp-content/debug.log
# Belirli bir kelimeyi iceren satirlari filtrele
tail -f /wp-content/debug.log | grep -i "fatal|error|warning"
# Eklenti adi ile filtrele
tail -f /wp-content/debug.log | grep "woocommerce"
# Son 100 hataya bak
tail -n 100 /wp-content/debug.log | grep "PHP Fatal"
Log dosyasının şişmesini önlemek için bir cron job ile logrotate konfigürasyonu yapılabilir:
# /etc/logrotate.d/wordpress-debug
/var/log/wordpress/debug.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 0644 www-data www-data
}
Ya da doğrudan WordPress tarafında haftalık log temizliği için şöyle bir mu-plugin yazabilirsiniz:
<?php
/**
* Debug log boyutunu kontrol et ve gerekirseSifirla
* /wp-content/mu-plugins/debug-log-manager.php
*/
add_action( 'wp_loaded', function() {
if ( ! defined( 'WP_DEBUG_LOG' ) || ! WP_DEBUG_LOG ) {
return;
}
$log_path = is_string( WP_DEBUG_LOG ) ? WP_DEBUG_LOG : WP_CONTENT_DIR . '/debug.log';
// Log dosyasi 50MB'yi astiysa arsivle
if ( file_exists( $log_path ) && filesize( $log_path ) > 52428800 ) {
$archive_path = $log_path . '.' . date( 'Y-m-d-H-i-s' ) . '.bak';
rename( $log_path, $archive_path );
error_log( 'Debug log arsivlendi: ' . $archive_path );
}
});
Eklenti Geliştirmede Hata Yakalamayı Standartlaştırmak
Kendi eklentinizi geliştiriyorsanız, hata yakalamayı bir standarda bağlamak uzun vadede çok zaman kazandırıyor. Özellikle try-catch bloklarını WP_DEBUG ile entegre etmek şöyle görünüyor:
<?php
class My_Plugin_Error_Handler {
private static $instance = null;
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Hatayi logla, gerekirse kullaniciya goster
*/
public function handle( Throwable $e, $context = [] ) {
$message = sprintf(
'[%s] %s (Dosya: %s, Satir: %d)',
get_class( $e ),
$e->getMessage(),
$e->getFile(),
$e->getLine()
);
// Her zaman error_log'a yaz
error_log( $message );
// Context varsa ayri logla
if ( ! empty( $context ) ) {
error_log( 'Context: ' . print_r( $context, true ) );
}
// WP_DEBUG aktifse stack trace'i de logla
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
error_log( 'Stack Trace: ' . $e->getTraceAsString() );
}
// Admin bar'da hata bildirimi goster (sadece admin icin)
if ( current_user_can( 'manage_options' ) && defined( 'WP_DEBUG' ) && WP_DEBUG ) {
add_action( 'admin_notices', function() use ( $message ) {
echo '<div class="notice notice-error"><p><strong>Plugin Debug:</strong> ' . esc_html( $message ) . '</p></div>';
});
}
}
}
// Kullanim ornegi
try {
$result = $this->process_payment( $order_id );
} catch ( Exception $e ) {
My_Plugin_Error_Handler::get_instance()->handle( $e, [
'order_id' => $order_id,
'user_id' => get_current_user_id(),
]);
return new WP_Error( 'payment_failed', 'Odeme islemi basarisiz oldu.' );
}
Sonuç
WP_DEBUG’ı sadece define( 'WP_DEBUG', true ) yapıp geçmek, arabanın sadece çalıştığını test etmek gibi bir şey. Gerçek güç, tüm bu araçları bir arada doğru konfigüre etmekten geliyor.
Gündüz ortamına göre debug ayarlarını yönetmek, log dosyalarını izlemek, hook çakışmalarını sistematik olarak tespit etmek ve kendi eklentilerinizde standart hata yakalama mekanizmaları oluşturmak; sizi reaktif sysadmin konumundan proaktif bir konuma taşıyor.
En önemli kural şunu bir daha söyleyeyim: Production’da WP_DEBUG_DISPLAY asla true olmamalı. Bu, hem güvenlik hem de kullanıcı deneyimi için kritik. Log’a yazabilirsiniz, dosyaya saklayabilirsiniz, ama ekrana bastırmak kesinlikle yanlış.
Bir sonraki eklenti hata ayıklama seansınızda, körlemesine var_dump ekleyip sayfayı yenilemeye çalışmak yerine, bu araçları sistematik biçimde kullanın. Hem zamanınızı hem de sinirlerinizi korursunuz.
