Meta Box ile WordPress Yazılarına Özel Alan Ekleme

WordPress geliştirme dünyasında meta box konusu, benim için hep “şimdi öğrendin mi, yoksa bir daha mı uğraşacaksın?” sorusunu akla getiriyor. Müşteri bir gün geliyor, diyor ki “ürün sayfasına teknik özellikler ekleyeceğiz ama bu alanlar tema değişince kaybolmasın.” İşte o anda ya hazır bir eklenti kuruyorsun ya da işi doğru yapıyorsun. Bu yazıda doğru yapmayı anlatacağım.

Meta Box Nedir, Neden Önemlidir?

WordPress’in standart editörü (hem klasik hem Gutenberg) içerik yazarlarına belirli alanlar sunar: başlık, içerik, etiket, kategori. Ama gerçek dünyada işler bu kadar basit değil. Bir emlak sitesinde “oda sayısı”, “metrekare”, “kat” gibi alanlar lazım. Bir film arşivinde “yönetmen”, “yapım yılı”, “tür” bilgileri gerekiyor. Bunları yazı içeriğine gömmek hem düzensiz hem de programatik olarak erişilmesi zor.

Meta box’lar, WordPress yönetim panelindeki yazı/sayfa düzenleme ekranına eklediğin özel kutucuklardır. İçine istediğin form alanlarını koyarsın, veriler postmeta tablosuna kaydedilir, her yerden get_post_meta() ile çekersin. Temiz, taşınabilir, güvenilir.

Meta Box eklentisi ise WordPress’in kendi add_meta_box() API’sini çok daha kullanışlı hale getiren bir araç. Hem ücretsiz sürümü hem de eklentileri olan premium bir ekosistemi var. Bu yazıda ağırlıklı olarak ücretsiz çekirdek eklentiyi ve PHP tabanlı kayıt yöntemini kullanacağız; çünkü production ortamında kod tabanında kontrol senin elinde olmalı.

Kurulum ve Temel Yapı

Eklentiyi WordPress deposundan kurabilirsin ya da Composer ile projeye dahil edebilirsin. Composer yolunu tercih ediyorum çünkü staging/production geçişlerinde versiyon takibi çok daha kolay oluyor.

composer require meta-box/meta-box

Eğer doğrudan eklenti olarak kuruyorsan wp-cli ile:

wp plugin install meta-box --activate

Kurulum sonrası eklentinin çalıştığını doğrula:

wp plugin list | grep meta-box

Şu çıktıyı görmen lazım: meta-box, active ve sürüm numarası. Burası çalışıyorsa devam edebiliriz.

İlk Meta Box’ı Oluşturmak

Meta Box eklentisi, alan tanımlarını rwmb_meta_boxes filtresi üzerinden alıyor. Bu filtreye bir dizi döndürüyorsun, eklenti gerisini hallediyor. Tema functions.php içine ya da tercihen özel bir eklenti içine yazabilirsin. Ben her zaman özel eklenti tarafını öneririm; tema değişince kaybolmasın diye.

Basit bir senaryo: Film arşivi sitesi, her yazıya yönetmen adı, çıkış yılı ve puan eklemek istiyor.

<?php
/**
 * Plugin Name: Film Arşivi Meta Alanları
 * Description: Film yazıları için özel meta alanları
 * Version: 1.0.0
 */

add_filter( 'rwmb_meta_boxes', 'film_arsivi_meta_box_kaydet' );

function film_arsivi_meta_box_kaydet( $meta_boxes ) {
    $meta_boxes[] = [
        'title'      => 'Film Bilgileri',
        'id'         => 'film_bilgileri',
        'post_types' => [ 'post' ],
        'context'    => 'normal',
        'priority'   => 'high',
        'fields'     => [
            [
                'id'   => 'film_yonetmen',
                'name' => 'Yönetmen',
                'type' => 'text',
                'desc' => 'Filmin yönetmeninin tam adını girin',
            ],
            [
                'id'   => 'film_yili',
                'name' => 'Çıkış Yılı',
                'type' => 'number',
                'min'  => 1888,
                'max'  => 2099,
                'step' => 1,
            ],
            [
                'id'      => 'film_puan',
                'name'    => 'Puan (1-10)',
                'type'    => 'number',
                'min'     => 1,
                'max'     => 10,
                'step'    => 0.5,
            ],
        ],
    ];

    return $meta_boxes;
}

Bu kodu aktif ettiğinde, yazı düzenleme ekranında “Film Bilgileri” başlıklı bir meta box belirecek. İçinde üç alan var. Kaydedince veriler wp_postmeta tablosuna yazılıyor.

Alan Tiplerini Doğru Seçmek

Meta Box’ın en güçlü yanı alan tipi zenginliği. Yanlış alan tipi seçmek sonradan baş ağrısı yaratıyor; bunu tecrübeyle öğrendim.

Temel alan tipleri:

  • text: Tek satır metin, çoğu durumda ilk tercih
  • textarea: Uzun metin, HTML girişi istemiyorsan
  • number: Sayısal değerler, min/max/step desteğiyle birlikte
  • select: Açılır menü, sabit seçenekler için
  • checkbox: Evet/hayır durumları
  • date: Tarih seçici, YYYY-MM-DD formatında saklar
  • image: Medya kütüphanesinden resim seçimi
  • url: URL doğrulaması yapılan metin alanı
  • email: E-posta formatı doğrulaması

Emlak sitesi örneğine geçelim. Bu sefer daha karmaşık bir yapı kuracağız:

add_filter( 'rwmb_meta_boxes', 'emlak_meta_box_kaydet' );

function emlak_meta_box_kaydet( $meta_boxes ) {
    $meta_boxes[] = [
        'title'      => 'Emlak Özellikleri',
        'id'         => 'emlak_ozellikleri',
        'post_types' => [ 'property' ],
        'context'    => 'normal',
        'priority'   => 'high',
        'fields'     => [
            [
                'id'          => 'emlak_fiyat',
                'name'        => 'Fiyat (TL)',
                'type'        => 'number',
                'min'         => 0,
                'step'        => 1000,
                'placeholder' => '1500000',
            ],
            [
                'id'      => 'emlak_tip',
                'name'    => 'İlan Tipi',
                'type'    => 'select',
                'options' => [
                    'satilik' => 'Satılık',
                    'kiralik' => 'Kiralık',
                    'devren'  => 'Devren',
                ],
                'std'     => 'satilik',
            ],
            [
                'id'   => 'emlak_metrekare',
                'name' => 'Alan (m²)',
                'type' => 'number',
                'min'  => 1,
            ],
            [
                'id'      => 'emlak_oda_sayisi',
                'name'    => 'Oda Sayısı',
                'type'    => 'select',
                'options' => [
                    '1+0' => 'Stüdyo',
                    '1+1' => '1+1',
                    '2+1' => '2+1',
                    '3+1' => '3+1',
                    '4+1' => '4+1',
                    '5+'  => '5 ve üzeri',
                ],
            ],
            [
                'id'   => 'emlak_balkon',
                'name' => 'Balkon',
                'type' => 'checkbox',
                'std'  => 0,
            ],
            [
                'id'   => 'emlak_kat',
                'name' => 'Kat',
                'type' => 'number',
                'min'  => -2,
                'max'  => 100,
            ],
        ],
    ];

    return $meta_boxes;
}

Özel Post Type ile Çalışmak

post_types anahtarı dizisine istediğin post type’ı yazabilirsin. post, page, custom post type adı, hepsi çalışır. Birden fazla post type için:

'post_types' => [ 'property', 'commercial_property', 'land' ],

Custom post type’ı yoksa önce onu kaydetmen lazım. Bunu da aynı eklenti dosyasına ekleyebilirsin:

add_action( 'init', 'emlak_post_type_kaydet' );

function emlak_post_type_kaydet() {
    register_post_type( 'property', [
        'label'  => 'Emlak İlanları',
        'public' => true,
        'supports' => [ 'title', 'editor', 'thumbnail', 'excerpt' ],
        'has_archive' => true,
        'rewrite' => [ 'slug' => 'emlak' ],
        'show_in_rest' => true,
    ] );
}

Bu noktada wp flush-rewrite-rules çalıştırmayı unutma:

wp rewrite flush

Verileri Temada Göstermek

Meta box ile kaydettiğin verileri temada iki farklı şekilde çekebilirsin. Meta Box eklentisinin kendi helper fonksiyonu olan rwmb_meta() ya da standart WordPress fonksiyonu get_post_meta(). Her ikisi de çalışır ama rwmb_meta() bazı alan tipleri için daha temiz çıktı verir (örneğin resim alanlarında).

<?php
// Tek bir değer çekmek için
$yonetmen = rwmb_meta( 'film_yonetmen' );
$yil      = rwmb_meta( 'film_yili' );
$puan     = rwmb_meta( 'film_puan' );

// Ya da standart WP fonksiyonu ile
$fiyat = get_post_meta( get_the_ID(), 'emlak_fiyat', true );
?>

<div class="film-detay">
    <p><strong>Yönetmen:</strong> <?php echo esc_html( $yonetmen ); ?></p>
    <p><strong>Yıl:</strong> <?php echo esc_html( $yil ); ?></p>
    <p><strong>Puan:</strong> <?php echo esc_html( $puan ); ?>/10</p>
</div>

Emlak ilanı kartı için daha kapsamlı bir örnek:

<?php
$fiyat       = get_post_meta( get_the_ID(), 'emlak_fiyat', true );
$tip         = get_post_meta( get_the_ID(), 'emlak_tip', true );
$metrekare   = get_post_meta( get_the_ID(), 'emlak_metrekare', true );
$oda_sayisi  = get_post_meta( get_the_ID(), 'emlak_oda_sayisi', true );
$kat         = get_post_meta( get_the_ID(), 'emlak_kat', true );
$balkon      = get_post_meta( get_the_ID(), 'emlak_balkon', true );

$tip_etiket = [
    'satilik' => 'Satılık',
    'kiralik' => 'Kiralık',
    'devren'  => 'Devren',
];
?>

<div class="ilan-kart">
    <h2><?php the_title(); ?></h2>
    
    <?php if ( $fiyat ) : ?>
        <div class="fiyat">
            <?php echo number_format( $fiyat, 0, ',', '.' ); ?> TL
            <?php if ( $tip === 'kiralik' ) echo '/ay'; ?>
        </div>
    <?php endif; ?>
    
    <ul class="ozellikler">
        <?php if ( $tip ) : ?>
            <li><?php echo esc_html( $tip_etiket[ $tip ] ?? $tip ); ?></li>
        <?php endif; ?>
        <?php if ( $oda_sayisi ) : ?>
            <li><?php echo esc_html( $oda_sayisi ); ?></li>
        <?php endif; ?>
        <?php if ( $metrekare ) : ?>
            <li><?php echo esc_html( $metrekare ); ?> m²</li>
        <?php endif; ?>
        <?php if ( $kat !== '' ) : ?>
            <li><?php echo esc_html( $kat ); ?>. Kat</li>
        <?php endif; ?>
        <?php if ( $balkon ) : ?>
            <li>Balkon Var</li>
        <?php endif; ?>
    </ul>
</div>

WP_Query ile Meta Alanlara Göre Filtreleme

Sadece veri kaydetmek değil, o veriye göre sorgu yapmak da önemli. Fiyata göre sıralama, oda sayısına göre filtreleme gibi işlemler için WP_Query‘yi meta_query parametresiyle kullanıyorsun.

<?php
// 2+1 ve 3 milyon TL altındaki satılık ilanları getir
$args = [
    'post_type'      => 'property',
    'posts_per_page' => 12,
    'meta_query'     => [
        'relation' => 'AND',
        [
            'key'     => 'emlak_tip',
            'value'   => 'satilik',
            'compare' => '=',
        ],
        [
            'key'     => 'emlak_oda_sayisi',
            'value'   => '2+1',
            'compare' => '=',
        ],
        [
            'key'     => 'emlak_fiyat',
            'value'   => 3000000,
            'compare' => '<',
            'type'    => 'NUMERIC',
        ],
    ],
    'orderby'  => 'meta_value_num',
    'meta_key' => 'emlak_fiyat',
    'order'    => 'ASC',
];

$ilanlar = new WP_Query( $args );

Burada type => 'NUMERIC' kritik. Bunu unutursan WordPress değerleri string olarak karşılaştırır ve “300000” değeri “29000”dan küçük çıkabilir. Bu hatayı production’da keşfetmek hiç hoş değil.

Gelişmiş Kullanım: Tekrarlayan Alanlar (Repeater)

Meta Box’ın ücretsiz sürümünde repeater (tekrarlayan alan grupları) yok ama premium MB Repeater eklentisiyle bu özelliği ekleyebilirsin. Eğer bütçen yoksa alternatif bir yaklaşım var: serialize edilmiş array’ler. Ama bunu önermiyorum, sorgu yazmak kabusa dönüyor.

Premium repeater örneği (MB Repeater eklentisi kuruluysa):

$meta_boxes[] = [
    'title'      => 'Proje Aşamaları',
    'id'         => 'proje_asamalari',
    'post_types' => [ 'project' ],
    'fields'     => [
        [
            'id'     => 'asamalar',
            'name'   => 'Aşamalar',
            'type'   => 'group',
            'clone'  => true,
            'sort_clone' => true,
            'fields' => [
                [
                    'id'   => 'asama_adi',
                    'name' => 'Aşama Adı',
                    'type' => 'text',
                ],
                [
                    'id'   => 'asama_tarih',
                    'name' => 'Tamamlanma Tarihi',
                    'type' => 'date',
                ],
                [
                    'id'      => 'asama_durum',
                    'name'    => 'Durum',
                    'type'    => 'select',
                    'options' => [
                        'bekliyor'   => 'Bekliyor',
                        'devam'      => 'Devam Ediyor',
                        'tamamlandi' => 'Tamamlandı',
                    ],
                ],
            ],
        ],
    ],
];

Meta Box’ı REST API ile Açmak

Gutenberg editörü ve headless WordPress mimarileri için meta alanlarını REST API’ye açman gerekiyor. Bunu register_meta() fonksiyonu ile yapabilirsin ya da Meta Box ayarlarında 'show_in_rest' => true ekleyebilirsin.

add_action( 'init', 'meta_alanlari_rest_api_acma' );

function meta_alanlari_rest_api_acma() {
    $alanlar = [
        'film_yonetmen',
        'film_yili',
        'film_puan',
    ];

    foreach ( $alanlar as $alan ) {
        register_post_meta( 'post', $alan, [
            'show_in_rest'  => true,
            'single'        => true,
            'type'          => 'string',
            'auth_callback' => function() {
                return current_user_can( 'edit_posts' );
            },
        ] );
    }
}

Bundan sonra REST API üzerinden değerlere erişebilirsin:

curl -X GET "https://siten.com/wp-json/wp/v2/posts/123" 
  -H "Authorization: Bearer TOKEN"

Dönen JSON’da meta anahtarının altında alan değerlerini göreceksin.

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

Yıllar içinde hem kendi hatalarımdan hem de “bu neden çalışmıyor” sorularından derlediğim liste:

  • Alan ID’si çakışması: film_yili yerine sadece yili gibi genel isimler kullanma. Başka eklentilerle çakışabilir. Her zaman proje özelinde bir prefix ekle.
  • Tip dönüşümü unutmak: number tipinde kaydettiğin değer get_post_meta ile her zaman string gelir. Matematiksel işlem yapacaksan (float) ya da (int) cast’i unut.
  • Güvenlik açığı: Temada veriyi echo ederken esc_html(), esc_url(), esc_attr() kullanmayı ihmal etme. Meta Box kayıt aşamasında sanitize eder ama çıktıda da escape etmek zorundasın.
  • Çakışan script: Bazı sayfa oluşturucular (Elementor, Divi) editör sayfasında JavaScript hataları üretiyor. Meta Box’ın kendi script dosyası çakışırsa rwmb_enqueue_scripts filtresini kullanarak sadece belirli ekranlarda yüklenmeye zorlayabilirsin.
  • Boş değer kontrolü: get_post_meta boş string yerine bazen false döndürebilir. empty() kontrolü == false kontrolünden güvenilir.

Sonuç

Meta Box, WordPress’in gömülü meta alanı sistemini ciddi biçimde güçlendiriyor. Ücretsiz sürüm bile bir sysadmin ya da eklenti geliştiricisi için yeterince güçlü; text, number, select, checkbox, date, image alanlarıyla gerçek dünya ihtiyaçlarının büyük çoğunluğunu karşılıyor.

Bu yazıda anlattıklarımı özetlemek gerekirse: eklentiyi kod tabanlı kurmak production güvenliği için daha sağlam, alan tiplerini işe uygun seçmek ilerideki sorgu işlerini kolaylaştırıyor, çıktılarda güvenlik escape’lerini asla atlamamak gerekiyor ve meta alanlarını REST API’ye açmak headless ya da Gutenberg geliştirme için neredeyse zorunlu.

Eğer işin sadece basit birkaç metin alanıyla sınırlı kalacaksa Advanced Custom Fields (ACF) de benzer işi görür. Ama kod kontrolü senin elinde olsun, Composer ile versiyon yönetimi yapayım, premium gereksinimleri minimal tutayım diyorsan Meta Box daha temiz bir seçim. Zaten eklenti geliştirme işi büyüdükçe rwmb_meta_boxes filtresinin ne kadar esnek olduğunu kendin de göreceksin.

Bir yanıt yazın

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