functions.php Nedir: WordPress Özelleştirmenin Temeli

WordPress ile ciddi anlamda uğraşmaya başladığınızda, er ya da geç karşınıza çıkan bir dosya var: functions.php. Bu dosya, WordPress temalarının kalbinde yer alır ve sitenize özel davranışlar kazandırmanın en temel yoludur. Ama çoğu insan bu dosyayı ya hiç dokunmadan bırakır ya da internetten kopyalanan kodları körü körüne yapıştırarak sitelerini bozar. İkisi de doğru yaklaşım değil.

Bu yazıda functions.php dosyasının ne olduğunu, nasıl çalıştığını ve gerçek dünya senaryolarında nasıl kullanıldığını adım adım ele alacağız. Hem yeni başlayanlar hem de “şimdiye kadar hep kopyala yapıştır yaptım, ne zaman öğrensem” diyenler için kapsamlı bir rehber olacak.

functions.php Nedir ve Nerede Bulunur?

functions.php, WordPress temalarında bulunan ve PHP ile yazılmış özel bir dosyadır. Her temanın kendi functions.php dosyası olabilir ve bu dosya, WordPress yüklendiğinde otomatik olarak çalıştırılır. Yani burada yazdığınız her fonksiyon, her hook, her filtre, sayfa yüklenmeden önce aktif hale gelir.

Dosyanın konumu şu şekildedir:

/wp-content/themes/tema-adi/functions.php

Eğer child theme kullanıyorsanız (ki kullanmalısınız, bunu birazdan açıklayacağım):

/wp-content/themes/tema-adi-child/functions.php

WordPress, önce child theme’nin functions.php dosyasını, ardından parent theme’ninki çalıştırır. Bu sıralama önemli, çünkü child theme’de parent theme’nin fonksiyonlarını override edebilirsiniz.

Neden functions.php Kullanıyoruz?

Şimdi şunu soruyor olabilirsiniz: “Bunu neden yapayım ki, tema ayarlarından her şeyi halledemez miyim?” Halledemezsiniz. En azından her şeyi değil.

WordPress’in kendi arayüzü size belirli özelleştirme seçenekleri sunar. Ama WordPress’in davranışını gerçekten değiştirmek istiyorsanız, yani “her yazı başlığının önüne otomatik olarak kategori adı gelsin” veya “admin panelinde belirli kullanıcılar bazı menüleri görmesin” gibi şeyler yapmak istiyorsanız, functions.php olmadan bunu yapamazsınız.

Kısaca şunlar için kullanılır:

  • Hook ve filter kullanımı: WordPress’in çalışma akışına müdahale etmek
  • Kısayol etiketleri (shortcode) oluşturmak: [benim-shortcodum] gibi
  • Özel widget alanları tanımlamak
  • Script ve style dosyalarını kayıt altına almak
  • Admin panelini özelleştirmek
  • WooCommerce davranışlarını değiştirmek
  • REST API endpoint’leri eklemek

Child Theme Kullanmadan functions.php’ye Dokunmayın

Bu konuyu açmadan geçemeyeceğim. Parent theme’nin functions.php dosyasını doğrudan düzenlerseniz, tema güncellendiğinde yaptığınız tüm değişiklikler silinir. Bu sadece teorik bir risk değil, bizzat yaşadığım ve müşterilerden gördüğüm somut bir problem.

Child theme oluşturmak için önce şu dizini yaratın:

mkdir /wp-content/themes/tema-adi-child

Ardından iki dosya oluşturun. İlki style.css:

/*
Theme Name: Tema Adi Child
Template: tema-adi
Version: 1.0.0
*/

İkincisi ise functions.php:

<?php
// Child theme style dosyasını yükle
add_action('wp_enqueue_scripts', function() {
    wp_enqueue_style(
        'parent-style',
        get_template_directory_uri() . '/style.css'
    );
    wp_enqueue_style(
        'child-style',
        get_stylesheet_directory_uri() . '/style.css',
        ['parent-style']
    );
});

Artık tüm özelleştirmelerinizi güvenle child theme’nin functions.php dosyasına ekleyebilirsiniz.

Hook Sistemi: functions.php’nin Kalbi

WordPress’i güçlü yapan şey hook sistemidir. İki tür hook var: action ve filter.

Action hook’ları: Belirli bir olay gerçekleştiğinde kod çalıştırır. Geri dönüş değeri beklenmez.

Filter hook’ları: Bir veriyi alır, işler ve değiştirilmiş halini geri döndürür.

Action Hook Örneği

<?php
// Admin paneline özel CSS ekle
function ozel_admin_css() {
    echo '<style>
        #wpadminbar { background-color: #1a1a2e !important; }
        #adminmenu .wp-menu-name { font-size: 13px; }
    </style>';
}
add_action('admin_head', 'ozel_admin_css');

// Kullanıcı giriş yaptığında log tut
function kullanici_giris_log($kullanici_adi) {
    $log_mesaji = date('Y-m-d H:i:s') . ' - Giriş: ' . $kullanici_adi . PHP_EOL;
    file_put_contents(WP_CONTENT_DIR . '/giris-log.txt', $log_mesaji, FILE_APPEND);
}
add_action('wp_login', 'kullanici_giris_log');

Filter Hook Örneği

<?php
// Yazı başlığına kategori adı ekle
function basliga_kategori_ekle($baslik, $post_id) {
    if (!is_admin() && is_single()) {
        $kategoriler = get_the_category($post_id);
        if (!empty($kategoriler)) {
            $kategori_adi = $kategoriler[0]->name;
            $baslik = '[' . $kategori_adi . '] ' . $baslik;
        }
    }
    return $baslik;
}
add_filter('the_title', 'basliga_kategori_ekle', 10, 2);

// Excerpt uzunluğunu değiştir
function ozet_uzunlugu($uzunluk) {
    return 30; // Varsayılan 55 kelime yerine 30 kelime
}
add_filter('excerpt_length', 'ozet_uzunlugu', 999);

Gerçek Dünya Senaryosu 1: Admin Panelini Temizleme

Müşteriye teslim ettiğiniz bir WordPress sitesi düşünün. Admin paneli gereksiz menülerle dolu, müşteri neye tıklayacağını bilmiyor. İşte bu durumda functions.php devreye girer.

<?php
// Belirli kullanıcı rolleri için admin menülerini gizle
function admin_menulerini_duzenle() {
    // Sadece yönetici değilse bu kodları çalıştır
    if (!current_user_can('administrator')) {
        remove_menu_page('edit.php?post_type=acf-field-group'); // ACF menüsü
        remove_menu_page('tools.php');        // Araçlar
        remove_menu_page('options-general.php'); // Ayarlar
        remove_menu_page('edit-comments.php');   // Yorumlar
        
        // Alt menü kaldırma
        remove_submenu_page('themes.php', 'theme-editor.php');
        remove_submenu_page('plugins.php', 'plugin-editor.php');
    }
}
add_action('admin_menu', 'admin_menulerini_duzenle', 999);

// Dashboard widget'larını temizle
function dashboard_widgetlari_kaldir() {
    if (!current_user_can('administrator')) {
        remove_meta_box('dashboard_quick_press', 'dashboard', 'side');
        remove_meta_box('dashboard_primary', 'dashboard', 'side');
        remove_meta_box('dashboard_activity', 'dashboard', 'normal');
        remove_meta_box('dashboard_right_now', 'dashboard', 'normal');
    }
}
add_action('wp_dashboard_setup', 'dashboard_widgetlari_kaldir');

Gerçek Dünya Senaryosu 2: Özel Shortcode Oluşturma

İçerik editörünüzün sık sık “şu bilgi kutusunu nasıl eklerim” diye sorduğunu düşünün. Bunun için özel bir shortcode oluşturmak en temiz çözümdür.

<?php
// Bilgi kutusu shortcode'u
function bilgi_kutusu_shortcode($atts, $icerik = null) {
    $atts = shortcode_atts([
        'tur'   => 'info',    // info, uyari, hata, basari
        'baslik' => 'Bilgi',
    ], $atts);

    $ikonlar = [
        'info'   => 'ℹ️',
        'uyari'  => '⚠️',
        'hata'   => '❌',
        'basari' => '✅',
    ];

    $renk_siniflar = [
        'info'   => '#e3f2fd',
        'uyari'  => '#fff3e0',
        'hata'   => '#ffebee',
        'basari' => '#e8f5e9',
    ];

    $tur      = sanitize_text_field($atts['tur']);
    $baslik   = sanitize_text_field($atts['baslik']);
    $ikon     = isset($ikonlar[$tur]) ? $ikonlar[$tur] : $ikonlar['info'];
    $bg_renk  = isset($renk_siniflar[$tur]) ? $renk_siniflar[$tur] : $renk_siniflar['info'];

    ob_start();
    ?>
    <div style="background: <?php echo esc_attr($bg_renk); ?>; border-left: 4px solid #333; padding: 15px; margin: 20px 0; border-radius: 4px;">
        <strong><?php echo $ikon . ' ' . esc_html($baslik); ?></strong>
        <p style="margin: 8px 0 0;"><?php echo wp_kses_post($icerik); ?></p>
    </div>
    <?php
    return ob_get_clean();
}
add_shortcode('bilgi_kutusu', 'bilgi_kutusu_shortcode');
// Kullanım: [bilgi_kutusu tur="uyari" baslik="Dikkat!"]Bu bir uyarı mesajıdır.[/bilgi_kutusu]

Gerçek Dünya Senaryosu 3: Özelleştirilmiş Login Sayfası

WordPress’in varsayılan login sayfası kurumsal sitelerde oldukça garip durur. Logo değiştirmek ve bazı davranışları özelleştirmek için:

<?php
// Login sayfası logosunu değiştir
function ozel_login_logo() {
    ?>
    <style type="text/css">
        #login h1 a, .login h1 a {
            background-image: url(<?php echo esc_url(get_stylesheet_directory_uri()); ?>/images/logo.png);
            height: 80px;
            width: 200px;
            background-size: contain;
            background-repeat: no-repeat;
        }
    </style>
    <?php
}
add_action('login_enqueue_scripts', 'ozel_login_logo');

// Login logo URL'sini siteye yönlendir
function ozel_login_logo_url() {
    return home_url();
}
add_filter('login_headerurl', 'ozel_login_logo_url');

// Login hata mesajlarını genel bir mesajla değiştir (güvenlik için)
function ozel_login_hata_mesaji() {
    return 'Kullanıcı adı veya şifre hatalı. Lütfen tekrar deneyin.';
}
add_filter('login_errors', 'ozel_login_hata_mesaji');

// Başarısız giriş denemelerini logla
function basarisiz_giris_log($kullanici_adi) {
    $ip = $_SERVER['REMOTE_ADDR'];
    $log = date('Y-m-d H:i:s') . " | Başarısız giriş | Kullanıcı: {$kullanici_adi} | IP: {$ip}" . PHP_EOL;
    error_log($log, 3, WP_CONTENT_DIR . '/guvenlik-log.txt');
}
add_action('wp_login_failed', 'basarisiz_giris_log');

Gerçek Dünya Senaryosu 4: WooCommerce Özelleştirmeleri

WooCommerce’i kullanan siteler için functions.php gerçekten kritik bir öneme sahip. Sıkça karşılaşılan özelleştirmelere bakalım.

<?php
// WooCommerce ürün sayfasına özel bilgi ekle
function urun_sayfasi_ek_bilgi() {
    global $product;
    
    if ($product->is_type('simple') && $product->is_in_stock()) {
        echo '<div class="kargo-bilgi" style="background:#f0f9ff; padding:10px; margin:10px 0; border-radius:4px;">';
        echo '🚚 <strong>Ücretsiz Kargo:</strong> 500 TL üzeri siparişlerde geçerlidir.';
        echo '</div>';
    }
}
add_action('woocommerce_single_product_summary', 'urun_sayfasi_ek_bilgi', 25);

// Sepetteki minimum sipariş tutarını kontrol et
function minimum_siparis_kontrolu() {
    $minimum_tutar = 150;
    
    if (WC()->cart->subtotal < $minimum_tutar && !is_admin()) {
        $mesaj = sprintf(
            'Minimum sipariş tutarı %s TL'dir. Sepetinizde %s TL değerinde ürün var.',
            $minimum_tutar,
            WC()->cart->subtotal
        );
        wc_add_notice($mesaj, 'error');
    }
}
add_action('woocommerce_check_cart_items', 'minimum_siparis_kontrolu');

// Belirli ürün kategorisine indirim uygula
function kategori_indirimi($indirim, $indirimlenecek_fiyat, $oran, $vergi_dahil, $sepet_ogesi) {
    $hedef_kategori = 'elektronik';
    $indirim_orani  = 10; // %10 indirim
    
    $urun_id = $sepet_ogesi['product_id'];
    
    if (has_term($hedef_kategori, 'product_cat', $urun_id)) {
        $indirim += $indirimlenecek_fiyat * ($indirim_orani / 100);
    }
    
    return $indirim;
}
add_filter('woocommerce_product_get_sale_price', 'kategori_indirimi', 10, 2);

Script ve Style Yönetimi

functions.php‘nin en sık kullanıldığı alanlardan biri de script ve style dosyalarını doğru şekilde yüklemektir. Bunu wp_head() ile değil, her zaman wp_enqueue_scripts hook’u ile yapmalısınız.

<?php
function tema_script_ve_stiller() {
    // Ana stil dosyası
    wp_enqueue_style(
        'tema-ana-stil',
        get_stylesheet_directory_uri() . '/assets/css/main.css',
        [],
        filemtime(get_stylesheet_directory() . '/assets/css/main.css') // Cache busting
    );

    // jQuery'e bağımlı özel script
    wp_enqueue_script(
        'tema-ana-script',
        get_stylesheet_directory_uri() . '/assets/js/main.js',
        ['jquery'],
        filemtime(get_stylesheet_directory() . '/assets/js/main.js'),
        true // Footer'da yükle
    );

    // PHP'den JS'ye veri aktar
    wp_localize_script('tema-ana-script', 'temaAyarlar', [
        'ajaxUrl'    => admin_url('admin-ajax.php'),
        'nonce'      => wp_create_nonce('tema_nonce'),
        'homeUrl'    => home_url(),
        'siteName'   => get_bloginfo('name'),
    ]);

    // Sadece tekil sayfalarda yüklenecek script
    if (is_single()) {
        wp_enqueue_script(
            'paylasim-script',
            get_stylesheet_directory_uri() . '/assets/js/share.js',
            ['jquery'],
            '1.0.0',
            true
        );
    }
}
add_action('wp_enqueue_scripts', 'tema_script_ve_stiller');

Güvenlik İçin functions.php’de Yapılması Gerekenler

Sistem yöneticisi bakış açısıyla, functions.php aynı zamanda WordPress sitenizin güvenliğini artırmak için kullanabileceğiniz bir yerdir.

<?php
// WordPress sürüm bilgisini gizle
function wp_versiyon_gizle() {
    return '';
}
add_filter('the_generator', 'wp_versiyon_gizle');

// XML-RPC'yi devre dışı bırak (brute force saldırılarını azaltır)
add_filter('xmlrpc_enabled', '__return_false');

// Dosya düzenlemeyi devre dışı bırak (admin panelinden tema/eklenti düzenleme)
if (!defined('DISALLOW_FILE_EDIT')) {
    define('DISALLOW_FILE_EDIT', true);
}

// REST API'yi giriş yapmamış kullanıcılara kapat
function rest_api_kimlik_dogrulama($sonuc) {
    if (!empty($sonuc)) {
        return $sonuc;
    }
    
    if (!is_user_logged_in()) {
        return new WP_Error(
            'rest_not_logged_in',
            'REST API sadece giriş yapmış kullanıcılar için erişilebilir.',
            ['status' => 401]
        );
    }
    
    return $sonuc;
}
// Not: Bu filtreyi dikkatli kullanın, bazı eklentiler public REST API gerektirebilir
// add_filter('rest_authentication_errors', 'rest_api_kimlik_dogrulama');

// Yorumlarda HTML etiketlerini sınırla
function yorum_html_sinirlama($izin_verilen) {
    $izin_verilen['a'] = ['href' => [], 'title' => []];
    $izin_verilen['em'] = [];
    $izin_verilen['strong'] = [];
    unset($izin_verilen['script']);
    unset($izin_verilen['iframe']);
    return $izin_verilen;
}
add_filter('allowed_tags', 'yorum_html_sinirlama');

functions.php’yi Düzenli Tutmak

functions.php zamanla kaosa dönebilir. 500 satırlık karmaşık bir dosya hem bakımı zorlaştırır hem de hata ayıklamayı felç eder. Bunun için şunu öneririm: functions.php‘yi bir orkestra şefi gibi kullanın, asıl işi ayrı dosyalara bölün.

<?php
// functions.php sadece bu dosyaları çağırsın
$include_dosyalari = [
    '/inc/tema-destek.php',      // Tema özellikleri
    '/inc/guvenlik.php',         // Güvenlik fonksiyonları
    '/inc/shortcodes.php',       // Shortcode'lar
    '/inc/admin-ozellestime.php', // Admin özelleştirmeleri
    '/inc/woocommerce.php',      // WooCommerce fonksiyonları
    '/inc/ajax-islemler.php',    // AJAX handler'lar
];

foreach ($include_dosyalari as $dosya) {
    $tam_yol = get_stylesheet_directory() . $dosya;
    if (file_exists($tam_yol)) {
        require_once $tam_yol;
    }
}

Böylece her inc/ altındaki dosya kendi konusuna odaklanır ve sistemi anlamak çok daha kolay olur.

Dikkat Edilmesi Gereken Yaygın Hatalar

Yıllar içinde hem kendi hatalarımdan hem de başkalarının sitelerini kurtarırken öğrendiklerimden derlediğim uyarılar:

  • Syntax hatası durumunda site tamamen çöker: functions.php‘de bir PHP hatası, tüm sitenin “white screen of death” vermesine yol açar. Her zaman önce staging ortamında test edin.
  • Hook önceliği önemlidir: add_action ve add_filter‘ın üçüncü parametresi olan öncelik sayısını doğru kullanın. Düşük sayı, önce çalışır anlamına gelir.
  • Fonksiyon adı çakışmalarına dikkat edin: search, login, user gibi genel isimler yerine sitenize özgü ön ekler kullanın. Örneğin benim_sitem_login_logo().
  • die() veya exit() kullanmayın: Bir hook içinde bu komutları çalıştırmak sayfanın yarım yüklenmesine neden olur.
  • Eklenti işlevlerini doğrudan çağırmayın: Önce eklentinin yüklenip yüklenmediğini kontrol edin. function_exists('woocommerce_add_to_cart') gibi kontroller şart.
  • $_GET, $_POST verilerini sanitize edin: functions.php‘de kullanıcı girdisi işliyorsanız mutlaka sanitize_text_field(), absint() gibi fonksiyonları kullanın.

Sonuç

functions.php dosyası, WordPress’i gerçekten anlamanın ve kontrol altına almanın kapısıdır. Tema ayarlarının sınırlarına takılmak yerine, bu dosya aracılığıyla WordPress’in neredeyse her davranışını değiştirebilirsiniz. Ancak bu güç, beraberinde sorumluluk da getirir.

Başlangıç için şu adımları izlemenizi öneririm: Önce child theme oluşturun, ardından küçük denemelerle başlayın. Bir hook ekleyin, etkisini görün, geri alın, tekrar deneyin. WordPress Codex ve Developer Handbook bu yolculukta en iyi arkadaşlarınız olacak.

Sistem yönetimi bakış açısıyla söylersem, functions.php aslında bir konfigürasyon dosyasıdır. Tıpkı nginx.conf veya httpd.conf gibi, onu doğru anlamadan rastgele satırlar eklemek felakete davet çıkarmaktır. Ama bir kez mantığını kavradığınızda, WordPress siteleriniz üzerinde tam kontrol sahibi olursunuz ve müşterilerin “bunu yapabilir miyiz?” sorularına çoğunlukla “evet, beş dakika içinde” diyebilirsiniz.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir