functions.php’de Sık Yapılan Hatalar ve Çözümleri
WordPress geliştirme sürecinde functions.php dosyası hem en güçlü hem de en tehlikeli alandır. Yanlış bir satır kodu tüm sitenizi çökertebilir, beyaz ekranla karşı karşıya bırakabilir ya da arka planda fark edilmeden performans sorunlarına yol açabilir. Bu yazıda gerçek dünyada sık karşılaşılan hataları, neden oluştuklarını ve nasıl düzeltileceğini ele alacağız.
functions.php Neden Bu Kadar Kritik?
functions.php, WordPress’in her sayfa yüklemesinde çalıştırdığı bir dosyadır. Admin paneli, ön yüz, AJAX istekleri fark etmeksizin her request’te bu dosya parse edilir. Bu yüzden içine yazdığınız bir sözdizimi hatası bile sitenizi tamamen erişilemez hale getirebilir.
Bir de şöyle düşünün: Shared hosting kullanıyorsunuz, FTP erişiminiz yok, sadece cPanel File Manager var ve bir hata yaptınız. İşte o an gerçek bir sysadmin testi başlar.
Hata 1: PHP Sözdizimi Hataları ve Beyaz Ekran
En klasik senaryo şudur: Bir fonksiyon eklediniz, sayfayı yenilediniz ve siteniz tamamen beyaz oldu. WordPress hata ayıklama modu kapalıysa hiçbir şey göremezsiniz.
Çözüm: Önce wp-config.php dosyasında debug modunu açın.
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
Sonra wp-content/debug.log dosyasını kontrol edin. Hata genellikle şu formatta görünür:
PHP Parse error: syntax error, unexpected '}' in /var/www/html/wp-content/themes/mytheme/functions.php on line 47
Bir diğer yöntem, dosyayı sunucu tarafında PHP CLI ile kontrol etmektir:
php -l /var/www/html/wp-content/themes/mytheme/functions.php
Bu komut sözdizimi hatası varsa satır numarasını verir, hata yoksa “No syntax errors detected” yazar. Bir şey deploy etmeden önce bu komutu çalıştırmayı alışkanlık haline getirin.
Yaygın sözdizimi hataları:
- Kapanmayan süslü parantez: Fonksiyon açıldı ama
}unutuldu - Eksik noktalı virgül:
$var = 'deger'yerine$var = 'deger'yazıldı - Yanlış tırnak kullanımı: HTML içinde çift tırnak kullanılması gereken yerde tek tırnak
- PHP short tag kullanımı: Bazı sunucularda
<?çalışmaz, her zaman<?phpkullanın
Hata 2: add_action ve add_filter’ı Yanlış Hook’a Bağlamak
Bu hata beyaz ekran vermez, bu yüzden daha sinsi bir hatadır. Fonksiyonunuz çalışmıyor gibi görünür ama aslında yanlış zamanda çalışıyor ya da hiç çalışmıyor.
// YANLIŞ: wp_head hook'una wp_enqueue_scripts yerine bağlamak
add_action('wp_head', 'my_custom_scripts');
function my_custom_scripts() {
wp_enqueue_script('jquery-custom', get_template_directory_uri() . '/js/custom.js', array('jquery'), '1.0', true);
}
// DOGRU: Script'leri her zaman wp_enqueue_scripts hook'una baglayin
add_action('wp_enqueue_scripts', 'my_custom_scripts');
function my_custom_scripts() {
wp_enqueue_script(
'jquery-custom',
get_template_directory_uri() . '/js/custom.js',
array('jquery'),
'1.0',
true
);
}
Neden önemli: wp_head hook’una script eklemek teknik olarak çalışabilir, ancak dependency yönetimi (bağımlılık sıralaması) bozulur, jQuery yüklenmeden önce jQuery’ye bağımlı bir script çalışmaya çalışabilir.
Sık karıştırılan hook’lar:
- init: Genel başlatma işlemleri, post type kayıtları
- wp_loaded: Tüm plugin ve tema dosyaları yüklendikten sonra
- after_setup_theme: Tema özellikleri (add_theme_support, register_nav_menus)
- widgets_init: Widget alanlarını kaydetmek için
- wp_enqueue_scripts: Script ve style yükleme (sadece ön yüz)
- admin_enqueue_scripts: Admin paneli için script ve style yükleme
Hata 3: Fonksiyon Adı Çakışmaları
WordPress çekirdeği, plugin’ler ve tema arasında fonksiyon adı çakışması gerçek bir sorundur. “Function already declared” hatası bu yüzden oluşur.
Fatal error: Cannot redeclare my_custom_function() (previously declared in /wp-content/plugins/some-plugin/functions.php:23) in /wp-content/themes/mytheme/functions.php on line 15
Çözüm 1: function_exists kontrolü
// Fonksiyonu tanimlamadan once varligini kontrol edin
if (!function_exists('my_custom_function')) {
function my_custom_function() {
// kodunuz buraya
return 'merhaba';
}
}
Çözüm 2: Prefix kullanımı
Kendi prefix’inizi belirleyin ve tüm fonksiyonlarınızda kullanın. Örneğin sitenizin adı “Harika Tema” ise:
// Kotu ornek - genel isim
function get_menu() { }
function setup_theme() { }
// Iyi ornek - prefix ile
function ht_get_menu() { }
function ht_setup_theme() { }
Çözüm 3: Sınıf (class) kullanımı
Daha büyük projelerde fonksiyonları bir sınıf içine almak en temiz çözümdür:
class HarikaTema_Functions {
public function __construct() {
add_action('wp_enqueue_scripts', array($this, 'load_scripts'));
add_action('after_setup_theme', array($this, 'theme_setup'));
}
public function load_scripts() {
wp_enqueue_style('main-style', get_stylesheet_uri());
}
public function theme_setup() {
add_theme_support('title-tag');
add_theme_support('post-thumbnails');
}
}
// Sinifi bir kez orneklendir
new HarikaTema_Functions();
Hata 4: wp_enqueue Olmadan Direkt Script Eklemek
Özellikle WordPress’e yeni başlayanların yaptığı bu hata, ciddi performans ve uyumluluk sorunlarına yol açar.
// YANLIŞ: wp_head'e direkt HTML yazmak
add_action('wp_head', function() {
echo '<script src="https://ornek.com/script.js"></script>';
echo '<link rel="stylesheet" href="https://ornek.com/style.css">';
});
Bu yaklaşımın sorunları:
- Script yönetimi bozulur: WordPress hangi script’lerin yüklendiğini takip edemez
- Çakışmalar oluşur: Aynı script iki kez yüklenebilir
- Dependency hatası: Bağımlılıklar doğru sırayla yüklenmez
- Cache plugin’leri çalışmaz: W3 Total Cache, WP Rocket gibi araçlar bu script’leri optimize edemez
// DOGRU: Her zaman wp_enqueue_scripts kullanin
add_action('wp_enqueue_scripts', 'ht_load_assets');
function ht_load_assets() {
// CSS
wp_enqueue_style(
'bootstrap',
'https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css',
array(),
'5.3.0'
);
wp_enqueue_style(
'main-style',
get_template_directory_uri() . '/assets/css/main.css',
array('bootstrap'), // Bootstrap'e bagimli
filemtime(get_template_directory() . '/assets/css/main.css') // Cache buster
);
// JavaScript
wp_enqueue_script(
'custom-app',
get_template_directory_uri() . '/assets/js/app.js',
array('jquery'),
'2.1.0',
true // Footer'a yukle
);
// Script'e PHP degeri aktar
wp_localize_script('custom-app', 'appData', array(
'ajaxUrl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('my_nonce'),
'siteUrl' => get_site_url()
));
}
Hata 5: WooCommerce Hook’larını Yanlış Kullanmak
WooCommerce kullanan sitelerde functions.php’e WooCommerce’e özel kodlar eklendiğinde, WooCommerce aktif değilse site patlar.
// TEHLIKELI: WooCommerce aktif degilse fatal error verir
add_filter('woocommerce_product_price', 'my_price_filter', 10, 2);
function my_price_filter($price, $product) {
return $price * 0.9; // Yüzde 10 indirim
}
// GUVENLI: Once WooCommerce'in aktif olup olmadigini kontrol edin
add_action('plugins_loaded', 'ht_init_woo_customizations');
function ht_init_woo_customizations() {
if (!class_exists('WooCommerce')) {
return; // WooCommerce yoksa dur
}
// WooCommerce hook'larini burada tanimlayin
add_filter('woocommerce_product_price', 'ht_price_filter', 10, 2);
add_action('woocommerce_before_add_to_cart_button', 'ht_custom_product_field');
}
function ht_price_filter($price, $product) {
// Sadece belirli kategorideki urunlerde indirim uygula
if (has_term('indirimli', 'product_cat', $product->get_id())) {
return $price * 0.9;
}
return $price;
}
function ht_custom_product_field() {
echo '<div class="custom-note">Ucretsiz kargo!</div>';
}
WooCommerce için ek güvenlik kontrolü:
// Plugin'in aktif olup olmadigini kontrol eden yardimci fonksiyon
function ht_is_plugin_active($plugin_file) {
$active_plugins = (array) get_option('active_plugins', array());
if (is_multisite()) {
$active_plugins = array_merge(
$active_plugins,
array_keys(get_site_option('active_sitewide_plugins', array()))
);
}
return in_array($plugin_file, $active_plugins);
}
// Kullanim
if (ht_is_plugin_active('woocommerce/woocommerce.php')) {
// WooCommerce kodlari buraya
}
Hata 6: Sonsuz Döngüye Giren Filter’lar
Bu hata özellikle the_content filter’ı kullanılırken sıkça karşılaşılan bir durumdur. Filter içinde aynı filter’ı tetikleyen bir işlem yapmak sonsuz döngüye girer.
// YANLIS: the_content filter icinde apply_filters('the_content') cagirmak
add_filter('the_content', 'ht_modify_content');
function ht_modify_content($content) {
// Bu satir sonsuz donguye girer!
$new_content = apply_filters('the_content', $content . '<p>Ek icerik</p>');
return $new_content;
}
// DOGRU: Filter'i gecici olarak kaldir
add_filter('the_content', 'ht_modify_content');
function ht_modify_content($content) {
// Once bu filter'i kaldir
remove_filter('the_content', 'ht_modify_content');
// Islemini yap
$extra = '<div class="ek-icerik"><p>Bu icerik otomatik eklendi.</p></div>';
// Filter'i tekrar ekle
add_filter('the_content', 'ht_modify_content');
return $content . $extra;
}
Hata 7: Doğrudan Veritabanı Sorgularını Yanlış Yazmak
$wpdb kullanırken SQL injection açığı bırakmak veya hatalı sorgu yazmak ciddi güvenlik sorunlarına yol açar.
// TEHLIKELI: Kullanici girdisini direkt sorguya koymak
function ht_get_user_data_unsafe($user_input) {
global $wpdb;
// BU COK TEHLIKELI - SQL Injection acigi var!
$results = $wpdb->get_results("SELECT * FROM wp_users WHERE user_login = '$user_input'");
return $results;
}
// GUVENLI: Prepare kullanarak SQL Injection'a karsi koruma
function ht_get_user_data_safe($username) {
global $wpdb;
// prepare() ile parametreleri temizle
$query = $wpdb->prepare(
"SELECT ID, user_login, user_email FROM {$wpdb->users} WHERE user_login = %s",
sanitize_user($username)
);
$results = $wpdb->get_row($query);
// Hata kontrolu
if ($wpdb->last_error) {
error_log('Veritabani hatasi: ' . $wpdb->last_error);
return false;
}
return $results;
}
// Toplu veri sorgulama ornegi
function ht_get_recent_orders($user_id, $limit = 10) {
global $wpdb;
$query = $wpdb->prepare(
"SELECT ID, post_status, post_date
FROM {$wpdb->posts}
WHERE post_type = 'shop_order'
AND post_author = %d
ORDER BY post_date DESC
LIMIT %d",
absint($user_id),
absint($limit)
);
return $wpdb->get_results($query);
}
Hata 8: Child Theme Kullanmadan Ana Temaya Kod Yazmak
Bu bir programlama hatası değil ama workflow açısından kritik bir hata. Ana tema güncellendiğinde tüm özelleştirmeleriniz gider.
Child theme functions.php’de parent tema fonksiyonlarını override etmek için:
// Child theme functions.php
// Parent tema fonksiyonunu override etme
add_action('after_setup_theme', 'ht_child_setup', 11); // Priority 11, parent'tan sonra calisir
function ht_child_setup() {
// Parent'in belirlediginin uzerine yaz
add_image_size('custom-thumbnail', 400, 300, true);
// Parent'in ekledigi bir desteği kaldır (ornegin)
remove_theme_support('custom-background');
}
// Parent temadan bir fonksiyonu devre disi birak
function ht_remove_parent_functions() {
remove_action('wp_footer', 'parent_theme_footer_scripts', 20);
}
add_action('wp_footer', 'ht_remove_parent_functions', 1);
Genel Güvenlik ve Performans Kontrol Listesi
Giriş verilerini her zaman sanitize edin:
// Kullanici girdilerini temizlemek icin WordPress fonksiyonlari
$text = sanitize_text_field($_POST['isim']);
$email = sanitize_email($_POST['eposta']);
$url = esc_url_raw($_POST['website']);
$integer = absint($_POST['sayi']);
$html = wp_kses_post($_POST['icerik']); // Sadece guvenli HTML taglarinea izin ver
$slug = sanitize_title($_POST['baslik']);
$key = sanitize_key($_POST['anahtar']);
$username = sanitize_user($_POST['kullanici']);
Nonce kullanmayı unutmayın:
// Form olusturma
function ht_render_form() {
?>
<form method="post">
<?php wp_nonce_field('ht_form_action', 'ht_nonce'); ?>
<input type="text" name="veri" />
<button type="submit">Gonder</button>
</form>
<?php
}
// Form isleme
function ht_process_form() {
if (!isset($_POST['ht_nonce'])) return;
if (!wp_verify_nonce($_POST['ht_nonce'], 'ht_form_action')) {
wp_die('Guvenlik dogrulama hatasi.');
}
// Nonce gecerliyse isleme devam et
$veri = sanitize_text_field($_POST['veri']);
// ...
}
add_action('init', 'ht_process_form');
functions.php Hata Ayıklama İpuçları
Sunucu erişiminiz varsa hata ayıklama süreci çok daha kolaydır. Birkaç pratik komut:
# WordPress debug logunu canli izle
tail -f /var/www/html/wp-content/debug.log
# PHP hatalarini izle (Apache)
tail -f /var/log/apache2/error.log | grep "wp-content/themes"
# Nginx icin
tail -f /var/log/nginx/error.log
# PHP syntax kontrolu (deploy oncesi)
find /var/www/html/wp-content/themes/mytheme/ -name "*.php" -exec php -l {} ;
# Izin sorunlarini kontrol et
ls -la /var/www/html/wp-content/themes/mytheme/functions.php
Beyaz ekranla karşılaştığınızda ve FTP erişiminiz varsa hızlı çözüm:
# functions.php'yi yedekle ve bos birakit (en hizli cozum)
cp functions.php functions.php.bak
echo "<?php // Gecici bos functions.php ?>" > functions.php
# Sonra kodu parcalar halinde geri ekle
Sonuç
functions.php, doğru kullanıldığında WordPress’in en güçlü araçlarından biridir. Ancak dikkat edilmesi gereken temel prensipler vardır:
- Her kod değişikliğinden önce yerel ortamda veya staging’de test edin
- Deploy öncesi mutlaka
php -lile syntax kontrolü yapın - Fonksiyon adlarınıza her zaman benzersiz prefix ekleyin
- Kullanıcıdan gelen her veriyi sanitize ve validate edin
- WooCommerce gibi plugin’lere bağımlı kodları her zaman varlık kontrolüyle sarmalayın
- Ana temayı hiçbir zaman direkt düzenlemeyin, child theme kullanın
- Debug loglarını aktif tutun ama production’da
WP_DEBUG_DISPLAYkapalı olsun
Bu kuralları uygulayan bir geliştirici, functions.php kaynaklı sorunların büyük çoğunluğunu yaşamaktan kurtulur. Geriye kalan edge case’ler için de debug araçlarını ve sunucu loglarını etkin kullanmak, sorunu dakikalar içinde çözmenizi sağlar.
