WordPress Menü Öğelerinin Öncesine ve Sonrasına İçerik Ekleme
WordPress ile çalışırken menü öğelerini özelleştirmek istediğinizde, çoğu zaman tema editörüne veya sayfa şablonlarına dokunmak zorunda kalırsınız. Ama functions.php üzerinden yapabileceğiniz bazı hileler var ki bunlar hem daha temiz hem de güncelleme sonrası kaybolmayan çözümler sunuyor. Menü öğelerinin öncesine ve sonrasına içerik eklemek de tam olarak bu kategoriye giriyor. İkon eklemek, rozet göstermek, “YENİ” etiketi yapıştırmak veya promosyon metni koymak gibi ihtiyaçlar için walker sınıfını ve nav_menu_item_args filtresini kullanmak en doğru yol.
WordPress Menü Sistemini Anlamak
WordPress menü sistemi aslında oldukça katmanlı bir yapıya sahip. Bir menü oluşturduğunuzda arka planda wp_nav_menu() fonksiyonu devreye giriyor. Bu fonksiyon bir Walker_Nav_Menu sınıfı kullanarak menü öğelerini HTML’e çeviriyor.
Her menü öğesi için temel akış şu şekilde işliyor:
start_lvl(): Alt menü listesi başlarstart_el(): Menü öğesi başlar (li ve a etiketleri açılır)end_el(): Menü öğesi biterend_lvl(): Alt menü listesi biter
Biz bu süreçte içerik eklemek için iki ana yöntem kullanacağız. Birincisi Walker_Nav_Menu sınıfını extend etmek, ikincisi ise nav_menu_item_args filtresini kullanmak. Her iki yöntemin de kendi avantajları ve kullanım senaryoları var.
Yöntem 1: nav_menu_item_args Filtresi
En hızlı ve temiz çözüm nav_menu_item_args filtresi. Bu filtre WordPress 4.8.0 ile geldi ve menü öğesi argümanlarını değiştirmenize izin veriyor. before, after, link_before ve link_after parametrelerini bu filtre üzerinden manipüle edebilirsiniz.
Bu parametreler şu anlama geliyor:
- before: Link etiketinin (
) dışında, öğe içeriğinin başına eklenir - after: Link etiketinin dışında, öğe içeriğinin sonuna eklenir
- link_before: Link etiketi içinde, link metninin öncesine eklenir
- link_after: Link etiketi içinde, link metninin sonrasına eklenir
Tüm Menü Öğelerine İkon Eklemek
En klasik senaryo: Font Awesome ikonları menü öğelerinin başına eklemek.
add_filter( 'nav_menu_item_args', 'add_icon_to_menu_items', 10, 3 );
function add_icon_to_menu_items( $args, $item, $depth ) {
// Sadece belirli bir menüye uygula
if ( $args->theme_location === 'primary' ) {
$args->link_before = '<i class="fas fa-chevron-right menu-icon"></i>';
}
return $args;
}
Sadece Belirli Menü Öğelerine İçerik Eklemek
Pratikte çok daha fazla işinize yarayacak olan şu: belirli menü öğelerini ID’lerine veya CSS sınıflarına göre hedef alarak içerik eklemek.
add_filter( 'nav_menu_item_args', 'add_badge_to_specific_menu_item', 10, 3 );
function add_badge_to_specific_menu_item( $args, $item, $depth ) {
// Menü öğesinin başlığına göre kontrol
if ( $item->title === 'İletişim' ) {
$args->after = '<span class="menu-badge menu-badge--new">YENİ</span>';
}
// Menü öğesi ID'sine göre kontrol
if ( $item->ID === 42 ) {
$args->after = '<span class="menu-badge menu-badge--hot">🔥 HOT</span>';
}
// CSS sınıfına göre kontrol
if ( in_array( 'menu-item-promo', $item->classes ) ) {
$args->before = '<span class="promo-star">⭐</span>';
$args->after = '<span class="promo-label">%20 İndirim</span>';
}
return $args;
}
WooCommerce Sepet Sayacı Eklemek
E-ticaret sitelerinde “Sepet” menü öğesinin yanına ürün sayısını göstermek çok yaygın bir ihtiyaç. İşte bunu functions.php ile nasıl yapacağınız:
add_filter( 'nav_menu_item_args', 'add_cart_count_to_menu', 10, 3 );
function add_cart_count_to_menu( $args, $item, $depth ) {
// WooCommerce aktif mi kontrol et
if ( ! function_exists( 'WC' ) ) {
return $args;
}
// "Sepet" başlıklı menü öğesini hedef al
if ( strtolower( $item->title ) === 'sepet' || strtolower( $item->title ) === 'cart' ) {
$cart_count = WC()->cart->get_cart_contents_count();
if ( $cart_count > 0 ) {
$args->after = '<span class="cart-count">' . $cart_count . '</span>';
}
}
return $args;
}
// Sepet güncellendiğinde menüyü AJAX ile yenile
add_filter( 'woocommerce_add_to_cart_fragments', 'woocommerce_header_add_to_cart_fragment' );
function woocommerce_header_add_to_cart_fragment( $fragments ) {
$cart_count = WC()->cart->get_cart_contents_count();
$fragments['.cart-count'] = '<span class="cart-count">' . $cart_count . '</span>';
return $fragments;
}
Yöntem 2: Walker Sınıfını Extend Etmek
Daha karmaşık senaryolarda veya HTML yapısı üzerinde tam kontrol istediğinizde Walker_Nav_Menu sınıfını extend etmek gerekiyor. Bu yaklaşım daha fazla kod yazmanızı gerektiriyor ama karşılığında inanılmaz bir esneklik sağlıyor.
Temel Walker Sınıfı
class Custom_Walker_Nav_Menu extends Walker_Nav_Menu {
/**
* Menü öğesinin başlangıcında çalışır
* Link ve içerik burada oluşturulur
*/
public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
$indent = ( $depth ) ? str_repeat( "t", $depth ) : '';
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$classes[] = 'menu-item-' . $item->ID;
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth ) );
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
$id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args, $depth );
$id = $id ? ' id="' . esc_attr( $id ) . '"' : '';
$output .= $indent . '<li' . $id . $class_names .'>';
// Link argümanları
$atts = array();
$atts['title'] = ! empty( $item->attr_title ) ? $item->attr_title : '';
$atts['target'] = ! empty( $item->target ) ? $item->target : '';
$atts['rel'] = ! empty( $item->xfn ) ? $item->xfn : '';
$atts['href'] = ! empty( $item->url ) ? $item->url : '';
$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );
$attributes = '';
foreach ( $atts as $attr => $value ) {
if ( ! empty( $value ) ) {
$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
$attributes .= ' ' . $attr . '="' . $value . '"';
}
}
// Önceki içerik (link dışında)
$item_output = isset( $args->before ) ? $args->before : '';
// Link açılışı
$item_output .= '<a' . $attributes . '>';
// Link içi önceki içerik
$item_output .= isset( $args->link_before ) ? $args->link_before : '';
// Ana menü öğesi içeriği
$item_output .= apply_filters( 'the_title', $item->title, $item->ID );
// Alt menü göstergesi ekle (depth 0 için)
if ( $depth === 0 && in_array( 'menu-item-has-children', $classes ) ) {
$item_output .= '<span class="submenu-indicator"><i class="fas fa-angle-down"></i></span>';
}
// Link içi sonraki içerik
$item_output .= isset( $args->link_after ) ? $args->link_after : '';
// Link kapanışı
$item_output .= '</a>';
// Sonraki içerik (link dışında)
$item_output .= isset( $args->after ) ? $args->after : '';
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
}
Bu walker’ı kullanmak için wp_nav_menu() çağrısında belirtmeniz gerekiyor:
wp_nav_menu( array(
'theme_location' => 'primary',
'walker' => new Custom_Walker_Nav_Menu(),
'menu_class' => 'nav-menu',
'container' => 'nav',
) );
Gerçek Dünya Senaryosu: Restoran Menüsü
Diyelim ki bir restoran sitesi yapıyorsunuz. Menü öğelerinin “Yeni”, “Popüler”, “Vejeteryan” gibi etiketler alması gerekiyor. Bu bilgiyi WordPress’in menü öğesi meta verilerine kaydetmek ve sonra çekmek mümkün.
// Menü öğelerine özel alan ekle (wp-admin > Appearance > Menus)
add_filter( 'wp_setup_nav_menu_item', 'add_menu_item_badge_field' );
function add_menu_item_badge_field( $menu_item ) {
$menu_item->badge_text = get_post_meta( $menu_item->ID, '_menu_item_badge', true );
return $menu_item;
}
// Admin panelinde menü öğesi düzenleme alanına input ekle
add_action( 'wp_nav_menu_item_custom_fields', 'menu_item_badge_field_input', 10, 4 );
function menu_item_badge_field_input( $item_id, $item, $depth, $args ) {
$badge = get_post_meta( $item_id, '_menu_item_badge', true );
?>
<p class="field-custom-badge description description-wide">
<label for="edit-menu-item-badge-<?php echo $item_id; ?>">
Rozet Metni (ör: YENİ, HOT, %20)
<input type="text"
id="edit-menu-item-badge-<?php echo $item_id; ?>"
class="widefat edit-menu-item-badge"
name="menu-item-badge[<?php echo $item_id; ?>]"
value="<?php echo esc_attr( $badge ); ?>">
</label>
</p>
<?php
}
// Kaydetme işlemi
add_action( 'wp_update_nav_menu_item', 'save_menu_item_badge_field', 10, 3 );
function save_menu_item_badge_field( $menu_id, $menu_item_db_id, $args ) {
if ( isset( $_POST['menu-item-badge'][ $menu_item_db_id ] ) ) {
$badge = sanitize_text_field( $_POST['menu-item-badge'][ $menu_item_db_id ] );
update_post_meta( $menu_item_db_id, '_menu_item_badge', $badge );
} else {
delete_post_meta( $menu_item_db_id, '_menu_item_badge' );
}
}
// Rozeti menüde göster
add_filter( 'nav_menu_item_args', 'display_menu_item_badge', 10, 3 );
function display_menu_item_badge( $args, $item, $depth ) {
$badge = get_post_meta( $item->ID, '_menu_item_badge', true );
if ( ! empty( $badge ) ) {
// Rozet metnine göre CSS sınıfı belirle
$badge_class = 'menu-badge';
if ( strtolower( $badge ) === 'yeni' || strtolower( $badge ) === 'new' ) {
$badge_class .= ' menu-badge--new';
} elseif ( strtolower( $badge ) === 'hot' || strtolower( $badge ) === 'popüler' ) {
$badge_class .= ' menu-badge--hot';
} elseif ( strpos( $badge, '%' ) !== false ) {
$badge_class .= ' menu-badge--discount';
}
$args->after = '<span class="' . esc_attr( $badge_class ) . '">' . esc_html( $badge ) . '</span>';
}
return $args;
}
CSS ile Menü Rozetlerini Stilize Etmek
Fonksiyonel kodu yazdık, şimdi görsel kısım. Bu stilleri temanızın style.css dosyasına veya Customizer > Additional CSS alanına ekleyebilirsiniz.
/* functions.php içinde wp_head action ile inline CSS eklemek */
add_action( 'wp_head', 'menu_badge_inline_styles' );
function menu_badge_inline_styles() {
?>
<style type="text/css">
.menu-badge {
display: inline-block;
padding: 2px 6px;
font-size: 10px;
font-weight: 700;
line-height: 1;
border-radius: 3px;
margin-left: 5px;
vertical-align: middle;
text-transform: uppercase;
}
.menu-badge--new {
background-color: #28a745;
color: #ffffff;
}
.menu-badge--hot {
background-color: #dc3545;
color: #ffffff;
animation: pulse 1.5s infinite;
}
.menu-badge--discount {
background-color: #fd7e14;
color: #ffffff;
}
.cart-count {
display: inline-flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
background-color: #0073aa;
color: white;
border-radius: 50%;
font-size: 11px;
font-weight: bold;
margin-left: 4px;
}
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.7; }
100% { opacity: 1; }
}
.submenu-indicator {
margin-left: 4px;
font-size: 12px;
transition: transform 0.3s ease;
}
.menu-item-has-children:hover .submenu-indicator {
transform: rotate(180deg);
}
</style>
<?php
}
Derinliğe Göre Farklı İçerik Eklemek
$depth parametresi çok değerli. Üst düzey menü öğelerine farklı, alt menü öğelerine farklı içerik ekleyebilirsiniz.
add_filter( 'nav_menu_item_args', 'depth_based_menu_content', 10, 3 );
function depth_based_menu_content( $args, $item, $depth ) {
// Sadece primary menüyü hedef al
if ( ! isset( $args->theme_location ) || $args->theme_location !== 'primary' ) {
return $args;
}
if ( $depth === 0 ) {
// Üst düzey öğeler: Alt menüsü varsa ok ikonu ekle
if ( in_array( 'menu-item-has-children', (array) $item->classes ) ) {
$args->link_after = ' <span class="dropdown-arrow" aria-hidden="true">▾</span>';
}
} elseif ( $depth === 1 ) {
// Birinci seviye alt menü: Sol ok ekle
$args->link_before = '<span class="sub-arrow" aria-hidden="true">→</span> ';
} elseif ( $depth >= 2 ) {
// İkinci seviye ve daha derin: Çift ok ekle
$args->link_before = '<span class="sub-arrow deep" aria-hidden="true">⇒</span> ';
}
return $args;
}
Koşullu İçerik: Giriş Yapmış Kullanıcılar İçin
Kullanıcı durumuna göre menü öğesi içeriğini değiştirmek de sık karşılaşılan bir senaryo.
add_filter( 'nav_menu_item_args', 'conditional_menu_content_by_user', 10, 3 );
function conditional_menu_content_by_user( $args, $item, $depth ) {
// "Hesabım" veya "My Account" öğesi için
if ( in_array( $item->object, array( 'page' ) ) ) {
if ( is_user_logged_in() ) {
$current_user = wp_get_current_user();
// Kullanıcı avatarını ekle
$avatar = get_avatar( $current_user->ID, 20, '', '', array( 'class' => 'menu-avatar' ) );
$args->link_before = $avatar;
// Kullanıcı adını sonuna ekle
if ( strtolower( $item->title ) === 'hesabım' ) {
$args->after = '<span class="menu-username">Merhaba, ' . esc_html( $current_user->display_name ) . '</span>';
}
} else {
// Giriş yapmamış kullanıcılar için login ikonu
if ( strtolower( $item->title ) === 'hesabım' || strtolower( $item->title ) === 'giriş yap' ) {
$args->link_before = '<i class="fas fa-user-circle" aria-hidden="true"></i> ';
}
}
}
return $args;
}
Performans Notları
Bu filtreleri kullanırken dikkat etmeniz gereken birkaç önemli nokta var.
- Gereksiz veritabanı sorgusu yazmayın: Her menü öğesi için
get_post_meta()çağırıyorsanız, önce menü öğesinin hedef olup olmadığını kontrol edin - Transient kullanın: WooCommerce sepet sayısı gibi dinamik veriler için AJAX fragmentlerini tercih edin, her sayfa yüklemede direkt sorgu atmayın
- CSS dosyasını inline yazmayın: Üretim ortamında
wp_enqueue_style()ile harici CSS dosyası kullanmak her zaman daha iyi - Escape etmeyi unutmayın: Menüye eklediğiniz her HTML içeriğini
esc_html(),esc_attr()veyawp_kses_post()ile sanitize edin - functions.php cache’ini temizleyin: Büyük değişikliklerden sonra object cache varsa temizlemek gerekebilir
Yaygın Hatalar ve Çözümleri
Menü filtreleriyle çalışırken en sık karşılaşılan sorunlar şunlar:
- $args->after yerine $args[‘after’] yazmak: Menü argümanları obje olarak geliyor, dizi değil. Her zaman
->operatörünü kullanın - theme_location kontrolü yapmamak: Filtre tüm menülere uygulanır. Sadece belirli bir menüyü hedefliyorsanız mutlaka
$args->theme_locationkontrolü yapın - Walker ile filtre çakışması: Eğer hem özel walker hem de
nav_menu_item_argsfiltresi kullanıyorsanız, walker içindeki$args->before/$args->afterkullanımları çelişebilir. Tek yöntem seçin - HTML entity encode sorunu: Türkçe karakterler içeren rozetlerde
esc_html()kullanırken bazı karakterler entity’ye dönüşebilir.wp_specialchars_decode()ile düzeltebilirsiniz
Sonuç
WordPress menü sistemine içerik eklemek, ilk bakışta karmaşık görünse de aslında birkaç hook ve filtreden ibaret. nav_menu_item_args filtresi hızlı ve temiz çözümler için ideal, Walker_Nav_Menu extend etmek ise tam kontrol gerektiren durumlar için.
Gerçek projelerinizde en çok işinize yarayacak kombinasyon şu: rozetler ve ikonlar için nav_menu_item_args filtresi kullanın, WordPress admin panelinden yönetilebilir olması için özel menü meta alanları ekleyin. Böylece müşteriniz sizden bağımsız olarak menü rozetlerini güncelleyebilir.
Kod kalitesi açısından bakarsak, bu fonksiyonları her zaman bir plugin içinde tutmak en doğrusu. Ama küçük projeler veya müşteri sitelerinde tema functions.php dosyasına koymak da tamamen kabul edilebilir. Önemli olan, child theme kullanıyor olmak ve ana tema güncellemelerinde kodunuzun kaybolmaması.
