functions.php’ye Güvenli Kod Ekleme: Child Theme Kullanımı

WordPress sitenizde bir şeyler özelleştirmek istediğinizde aklınıza gelen ilk yer genellikle functions.php dosyası olur. Tema editöründen direkt açıp kodu yapıştırırsınız, kaydedersiniz ve “tamam, oldu” dersiniz. Ama tema güncellendiğinde? Her şey gider. Ya da daha kötüsü, yanlış bir kod satırı beyaz ekrana yol açar ve paniklersiniz. Bu yazıda functions.php‘ye güvenli kod eklemenin tek doğru yolunu, yani child theme kullanımını, gerçek dünya senaryolarıyla birlikte ele alacağız.

Neden Ana Temanın functions.php’sine Dokunmamalısınız?

Bu sorunun cevabı aslında çok basit: Ana tema güncellendiğinde yaptığınız tüm değişiklikler silinir.

Peki insanlar neden yine de ana temayı düzenler? Çünkü child theme kurmak “ekstra iş” gibi görünür. Oysa bir kez doğru kurulum yaptıktan sonra, aynı sorunu bir daha yaşamazsınız.

Ana temayı direkt düzenlemenin diğer riskleri şunlar:

  • Beyaz ekran sorunu: Hatalı PHP kodu sitenizi tamamen çökertebilir. Admin paneline bile giremezsiniz.
  • Güvenlik açıkları: Tema güncellemeleri genellikle güvenlik yamalarını da içerir. Güncellemeyi atlarsanız açık kalırsınız.
  • Versiyon kontrolü zorlaşır: Neyi değiştirdiğinizi takip etmek neredeyse imkânsız hale gelir.
  • Ekip çalışmasında kaos: Başka bir geliştirici temayı güncellediğinde çalışmanız kaybolur.

Child Theme Nedir ve Nasıl Çalışır?

Child theme, ana temayı miras alarak üzerine kurulu olan bağımsız bir tema yapısıdır. WordPress, önce child theme’in dosyalarını yükler; eğer bir dosya child theme’de yoksa ana temadan alır. Bu sayede ana temayı hiç dokunmadan özelleştirebilirsiniz.

functions.php söz konusu olduğunda ise çalışma biraz farklıdır. Child theme’in functions.php dosyası, ana temanın functions.php dosyasını değiştirmez, onunla birlikte çalışır. İkisi de yüklenir, child theme’inki önce çalışır.

Child Theme Kurulumu: Adım Adım

Dizin Yapısını Oluşturma

wp-content/themes/ dizinine gidin ve ana temanızın adına -child ekleyerek yeni bir klasör oluşturun.

# SSH ile sunucuya bağlandıktan sonra
cd /var/www/html/wp-content/themes/

# Ana temanızın adı "twentytwentyfour" ise:
mkdir twentytwentyfour-child

# Klasöre girin
cd twentytwentyfour-child

style.css Dosyasını Oluşturma

Her child theme için zorunlu olan style.css dosyasını oluşturun. Bu dosya temayı WordPress’e tanıtır.

nano style.css

Dosyanın içeriği şu şekilde olmalıdır:

/*
Theme Name: TwentyTwentyFour Child
Theme URI: https://yoursite.com
Description: TwentyTwentyFour temasinin child temasi
Author: Sysadmin Blog
Author URI: https://yoursite.com
Template: twentytwentyfour
Version: 1.0.0
Text Domain: twentytwentyfour-child
*/

Burada en kritik satır Template: satırıdır. Ana temanın klasör adını tam olarak yazmanız gerekir, büyük/küçük harf dahil.

functions.php Dosyasını Oluşturma

nano functions.php

Child theme’in functions.php dosyası her zaman şu temel yapıyla başlamalıdır:

<?php
/**
 * Child Theme Functions
 * 
 * Ana temanin functions.php dosyasi ile birlikte calisir.
 * Tema guncellemelerinden etkilenmez.
 */

// Doğrudan erişimi engelle
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

// Ana tema stilini yükle
add_action( 'wp_enqueue_scripts', 'child_theme_enqueue_styles' );
function child_theme_enqueue_styles() {
    $parent_style = 'parent-style';
    
    wp_enqueue_style(
        $parent_style,
        get_template_directory_uri() . '/style.css'
    );
    
    wp_enqueue_style(
        'child-style',
        get_stylesheet_directory_uri() . '/style.css',
        array( $parent_style ),
        wp_get_theme()->get( 'Version' )
    );
}

Bu yapıyla ana temanın CSS’i düzgün yüklenir ve child theme CSS’i onun üzerine biner.

WordPress Panelinden Temayı Aktif Etme

Dosyaları oluşturduktan sonra WordPress admin panelinde Görünüm > Temalar bölümüne gidin. Child theme’inizi listede göreceksiniz. “Aktifleştir” butonuna tıklayın. Ana temanın küçük resmi olan temanızı seçin, endişelenmeyin, tasarım aynı kalacak.

Gerçek Dünya Senaryoları: Child Theme functions.php Örnekleri

Artık altyapı hazır. Şimdi gerçekten işe yarayan kod örneklerine geçelim.

Senaryo 1: WooCommerce Ürün Sayfasına Özel Mesaj Ekleme

Bir e-ticaret sitesi yönetiyorsunuz ve ürün sayfalarında “Ücretsiz kargo 500 TL ve üzeri siparişlerde geçerlidir” mesajını göstermek istiyorsunuz.

<?php
// Urun sayfasina kargo bilgisi ekle
add_action( 'woocommerce_single_product_summary', 'custom_shipping_notice', 25 );
function custom_shipping_notice() {
    echo '<div class="shipping-notice" style="background:#f0f8ff; padding:10px; 
          margin:10px 0; border-left:4px solid #0073aa; border-radius:3px;">';
    echo '<strong>Kargo Bilgisi:</strong> 500 TL ve uzeri siparislerde ucretsiz kargo!';
    echo '</div>';
}

Bu kodu ana temanın functions.php‘sine yazsaydınız ve tema güncelleştirilseydi, mesaj kaybolurdu. Child theme’de yazıldığı için güvende.

Senaryo 2: Admin Paneline Özel Menü Linki Ekleme

Müşterileriniz için yönetilen WordPress sitelerinde admin paneline hızlı erişim linki eklemek istiyorsunuz.

<?php
// Admin menusune ozel link ekle
add_action( 'admin_menu', 'add_custom_admin_link' );
function add_custom_admin_link() {
    add_menu_page(
        'Site Dokumanlari',
        'Dokumanlara Git',
        'manage_options',
        'https://docs.youragency.com',
        '',
        'dashicons-book',
        99
    );
}

// Harici linklerin yeni sekmede acilmasini sagla
add_action( 'admin_footer', 'open_custom_menu_links_in_new_tab' );
function open_custom_menu_links_in_new_tab() {
    ?>
    <script type="text/javascript">
        jQuery(document).ready(function($) {
            $('#adminmenu a[href^="http"]').attr('target', '_blank');
        });
    </script>
    <?php
}

Senaryo 3: Giriş Yapmış Kullanıcılara Özel İçerik

Üyelik sistemi kuruyorsunuz ve belirli shortcode’larla giriş yapmış kullanıcılara özel içerik göstermek istiyorsunuz.

<?php
// [uye_icerigi] shortcode'u - sadece giris yapmis kullanicilara goster
add_shortcode( 'uye_icerigi', 'restricted_content_shortcode' );
function restricted_content_shortcode( $atts, $content = null ) {
    if ( is_user_logged_in() ) {
        return '<div class="member-content">' . do_shortcode( $content ) . '</div>';
    } else {
        $login_url = wp_login_url( get_permalink() );
        return '<div class="login-required">
                    <p>Bu icerigi goruntulemek icin giris yapmaniz gerekiyor.</p>
                    <a href="' . esc_url( $login_url ) . '" class="button">Giris Yap</a>
                </div>';
    }
}

Kullanımı: [uye_icerigi]Sadece üyelere özel bu içerik...[/uye_icerigi]

Senaryo 4: Otomatik Resim Alt Etiketi Düzenleme

SEO ajansı için çalışıyorsunuz ve müşterinizin sitesinde yüklenen tüm resimlerin alt etiketini otomatik olarak düzenlemek istiyorsunuz.

<?php
// Resim alt etiketi bos ise dosya adindan olustur
add_filter( 'wp_get_attachment_image_attributes', 'auto_set_image_alt', 10, 2 );
function auto_set_image_alt( $attr, $attachment ) {
    if ( empty( $attr['alt'] ) ) {
        $filename = pathinfo( 
            get_attached_file( $attachment->ID ), 
            PATHINFO_FILENAME 
        );
        // Tire ve alt cizgileri bosluga cevir, ilk harfi buyut
        $attr['alt'] = ucwords( str_replace( array( '-', '_' ), ' ', $filename ) );
    }
    return $attr;
}

Senaryo 5: WooCommerce Sipariş Sonrası Admin Bildirimi

Müşteriniz her yeni sipariş geldiğinde ek bir e-posta adresi de bildirim alsın istiyor.

<?php
// Yeni siparis bildirimini ek adrese gonder
add_filter( 'woocommerce_email_recipient_new_order', 'add_extra_order_notification', 10, 2 );
function add_extra_order_notification( $recipient, $order ) {
    // Uretim ortaminda calis, test ortaminda calisme
    if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
        return $recipient;
    }
    
    $extra_email = '[email protected]';
    
    // Mevcut alicilara ekle
    if ( ! empty( $recipient ) ) {
        $recipient .= ',' . $extra_email;
    } else {
        $recipient = $extra_email;
    }
    
    return $recipient;
}

Senaryo 6: Arama Sonuçlarından Belirli Post Tiplerini Çıkarma

Blog yazıları ve ürünlerin birbirine karışmasını istemiyorsunuz, aramada sadece ürünler çıksın istiyorsunuz.

<?php
// Aramada sadece WooCommerce urunlerini goster
add_filter( 'pre_get_posts', 'customize_search_results' );
function customize_search_results( $query ) {
    // Admin panelini ve ana sorgu disindaki sorgulari atla
    if ( is_admin() || ! $query->is_main_query() ) {
        return;
    }
    
    // Sadece arama sayfasinda calis
    if ( $query->is_search() ) {
        $query->set( 'post_type', array( 'product' ) );
    }
}

Senaryo 7: Güvenlik İçin WordPress Versiyon Bilgisini Gizleme

Sunucu güvenlik taraması yapıldığında WordPress versiyonunun açıkta olduğunu gördünüz.

<?php
// WordPress versiyon bilgisini gizle
remove_action( 'wp_head', 'wp_generator' );

// Versiyon sorgularini da kaldir
add_filter( 'the_generator', '__return_empty_string' );

// RSS feed'lerden de kaldir
add_filter( 'get_the_generator_atom', '__return_empty_string' );
add_filter( 'get_the_generator_rss2', '__return_empty_string' );

// Script ve style URL'lerinden versiyon parametresini kaldir
add_filter( 'script_loader_src', 'remove_version_from_scripts', 15, 1 );
add_filter( 'style_loader_src', 'remove_version_from_scripts', 15, 1 );
function remove_version_from_scripts( $src ) {
    if ( strpos( $src, 'ver=' . get_bloginfo( 'version' ) ) ) {
        $src = remove_query_arg( 'ver', $src );
    }
    return $src;
}

Child Theme’i Organize Etme: Dosyaları Parçalara Bölme

functions.php dosyası büyüdükçe yönetmek zorlaşır. Profesyonel bir yaklaşım olarak kodları ayrı dosyalara bölüp functions.php‘den çağırabilirsiniz.

# Child theme dizin yapisi
twentytwentyfour-child/
├── style.css
├── functions.php
└── inc/
    ├── woocommerce.php
    ├── security.php
    ├── custom-shortcodes.php
    └── admin-tweaks.php

functions.php dosyanızı şu şekilde düzenleyin:

<?php
/**
 * Child Theme Functions - Ana Yukleyici
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

// Ana tema stilini yukle
add_action( 'wp_enqueue_scripts', 'child_theme_enqueue_styles' );
function child_theme_enqueue_styles() {
    wp_enqueue_style(
        'parent-style',
        get_template_directory_uri() . '/style.css'
    );
    wp_enqueue_style(
        'child-style',
        get_stylesheet_directory_uri() . '/style.css',
        array( 'parent-style' ),
        wp_get_theme()->get( 'Version' )
    );
}

// Alt dosyalari yukle
$includes = array(
    'inc/security.php',
    'inc/custom-shortcodes.php',
    'inc/admin-tweaks.php',
);

// WooCommerce aktifse woocommerce dosyasini yukle
if ( class_exists( 'WooCommerce' ) ) {
    $includes[] = 'inc/woocommerce.php';
}

foreach ( $includes as $file ) {
    $filepath = get_stylesheet_directory() . '/' . $file;
    if ( file_exists( $filepath ) ) {
        require_once $filepath;
    }
}

Bu yapı sayesinde WooCommerce eklentisi aktif değilse ilgili kodlar yüklenmez, hata almaz olursunuz.

Sık Yapılan Hatalar ve Çözümleri

?> Kapanış Etiketi Kullanmak

PHP dosyalarında kapanış etiketi kullanmak gereksizdir ve bazen “headers already sent” hatasına yol açar. Dosyanızın sonuna ?> yazmayın.

get_template_directory() ile get_stylesheet_directory() Karışıklığı

  • get_template_directory(): Her zaman ana temanın dizinini döndürür.
  • get_stylesheet_directory(): Aktif temanın (child theme kullanıyorsanız child theme’in) dizinini döndürür.

Child theme içinde kendi dosyalarınıza ulaşmak için her zaman get_stylesheet_directory() kullanın.

Fonksiyon İsmi Çakışmaları

Eğer ana temada my_custom_function() adında bir fonksiyon varsa ve siz de child theme’de aynı ismi kullanırsanız PHP fatal error alırsınız. Fonksiyon isimlerinizin önüne proje veya site adından türetilmiş bir prefix ekleyin:

<?php
// Kotu yontem - cakisma riski
function custom_header() { ... }

// Iyi yontem - benzersiz prefix ile
function mysitename_custom_header() { ... }

WP_DEBUG Olmadan Çalışmak

Geliştirme yaparken mutlaka wp-config.php dosyasında hata ayıklama modunu açın:

# wp-config.php icinde
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );

Bu ayarla hatalar ekranda görünmez ama /wp-content/debug.log dosyasına yazılır. Production’da WP_DEBUG‘ı false yapın.

Güvenlik Kontrol Listesi

Child theme functions.php‘nize kod eklerken şu kurallara uyun:

  • ABSPATH kontrolü: Her dosyanın başına if ( ! defined( 'ABSPATH' ) ) { exit; } ekleyin, böylece dosya doğrudan URL ile çağrılamaz.
  • Veri doğrulama: Kullanıcıdan gelen her veriye sanitize_text_field(), absint(), esc_url() gibi fonksiyonlar uygulayın.
  • Nonce kullanımı: Form işlemlerinde WordPress nonce sistemini kullanın.
  • Capability kontrolü: Admin işlevleri için current_user_can('manage_options') kontrolü yapın.
  • Doğrudan SQL sorgusu yazmayın: $wpdb->prepare() kullanın.

Staging Ortamında Test Edin

Canlı siteye kod atmadan önce mutlaka bir staging (test) ortamında deneyin. Popüler hosting panelleri bu özelliği sunuyor, ya da manuel olarak oluşturabilirsiniz:

# WP-CLI ile staging icin hizli kopya
wp db export backup-$(date +%Y%m%d).sql

# Staging sitenize kopyalayin, orada test edin
# Onaylanan kodu canliya alin

WP-CLI kullanıyorsanız child theme’i komut satırından da aktif edebilirsiniz:

# Child theme'i aktif et
wp theme activate twentytwentyfour-child

# Aktif temayı kontrol et
wp theme status

Sonuç

functions.php‘ye kod eklemek WordPress özelleştirmesinin olmazsa olmazı, ama bunu doğru yerde yapmak her şeyi değiştiriyor. Child theme kullanmak başta ekstra adım gibi görünse de aslında sizi şunlardan koruyor:

  • Tema güncellemesinde kod kaybı
  • Başkasının değişikliğiyle çakışma
  • Test edilmemiş kodun canlıya alınması
  • Güvenlik yamalarını atlama

Bu yazıda anlattığım yapıyı bir kez kurduktan sonra, her yeni proje için o child theme iskeletini kopyalayıp kullanabilirsiniz. inc/ klasörü altındaki organizasyon sayesinde 500 satır kod bile yönetilebilir hale gelir.

Tek bir kural: Ana temaya hiç dokunma. Gerisi gelir.

Bir yanıt yazın

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