WordPress Menü Öğelerine Özel CSS Sınıfı Ekleme
WordPress ile çalışırken menü yönetimi çoğu zaman göründüğünden çok daha karmaşık bir hal alabilir. Özellikle tasarımcıların “şu butona farklı bir renk verelim” ya da “bu menü öğesine özel bir ikon ekleyelim” dediği anlarda, standart WordPress arayüzünün yetersiz kaldığını fark edersiniz. İşte tam bu noktada functions.php dosyasına ekleyeceğiniz birkaç satır kod, hayatınızı kurtarır.
Bu yazıda WordPress menü öğelerine programatik olarak özel CSS sınıfları eklemenin farklı yollarını inceleyeceğiz. Hem basit senaryolar hem de kurumsal projelerde karşılaşabileceğiniz karmaşık durumlar için gerçek dünya örnekleri paylaşacağım.
Neden functions.php Üzerinden CSS Sınıfı Ekleriz?
WordPress’in standart menü editörü, her menü öğesine manuel olarak CSS sınıfı ekleme imkanı sunuyor. Ama bu yöntemi “Görünüm > Seçenekler” panelinden CSS sınıfı kutucuğunu aktif etmeniz gerekiyor. Peki ya şu senaryolara ne dersiniz?
- Yüzlerce ürünü olan bir WooCommerce sitesinde “Sepet” linkine her güncellemede tekrar tekrar CSS sınıfı eklemek zorunda kalmak
- Müşteri her menü değişikliğinde sınıfları silip üzerine yazmak
- Kullanıcı rolüne göre dinamik olarak farklı sınıflar atamak istemeniz
- Belirli sayfa türlerine (kategori, etiket, özel yazı tipi) otomatik sınıf atamak
Tüm bu durumlarda programatik yaklaşım hem güvenilir hem de sürdürülebilir tek çözümdür.
Temel Yöntem: nav_menu_css_class Filtresi
WordPress, menü öğelerine CSS sınıfı eklemek için nav_menu_css_class adında bir filtre kancası sağlar. Bu filtrenin nasıl çalıştığını önce basit bir örnekle görelim.
// functions.php dosyasina ekleyin
function custom_menu_class($classes, $item, $args, $depth) {
// Her menu ogesine 'nav-item' sinifi ekle
$classes[] = 'nav-item';
return $classes;
}
add_filter('nav_menu_css_class', 'custom_menu_class', 10, 4);
Bu filtre dört parametre alır:
- $classes: Mevcut CSS sınıflarını içeren dizi
- $item: Menü öğesinin tüm verilerini içeren WP_Post nesnesi
- $args:
wp_nav_menu()fonksiyonuna geçilen argümanlar - $depth: Menü öğesinin derinliği (0 = üst seviye, 1 = birinci alt menü)
Belirli Menüye Özel Sınıf Ekleme
Çoğu projede birden fazla menü konumu vardır. Header menüsü, footer menüsü, mobil menü… Her birine farklı davranış kazandırmak için $args parametresini kullanabiliriz.
function custom_menu_class_by_location($classes, $item, $args, $depth) {
// Sadece 'primary' konumundaki menuye sinif ekle
if ($args->theme_location === 'primary') {
$classes[] = 'main-nav__item';
// Ust seviye ogeler icin ek sinif
if ($depth === 0) {
$classes[] = 'main-nav__item--top-level';
}
// Alt menu ogesi ise
if ($depth === 1) {
$classes[] = 'main-nav__item--sub';
}
}
// Footer menusu icin farkli sinif
if ($args->theme_location === 'footer') {
$classes[] = 'footer-nav__item';
}
return $classes;
}
add_filter('nav_menu_css_class', 'custom_menu_class_by_location', 10, 4);
Menü Öğesi Türüne Göre Dinamik Sınıf Atama
Gerçek dünya projelerinde menü öğeleri farklı türlerde olabilir: sayfalar, kategoriler, özel linkler, etiketler… Her türe göre farklı stil uygulamak isteyebilirsiniz.
function custom_class_by_item_type($classes, $item, $args, $depth) {
// Ozel link (custom URL)
if ($item->type === 'custom') {
$classes[] = 'nav-external-link';
// Dis link mi kontrol et
$site_url = get_site_url();
if (strpos($item->url, $site_url) === false && $item->url !== '#') {
$classes[] = 'nav-external-link--out';
}
}
// Sayfa turu
if ($item->object === 'page') {
$classes[] = 'nav-page-link';
// Anasayfa mi?
if ($item->object_id == get_option('page_on_front')) {
$classes[] = 'nav-home-link';
}
}
// Kategori turu
if ($item->object === 'category') {
$classes[] = 'nav-category-link';
$term = get_term($item->object_id, 'category');
if ($term && !is_wp_error($term)) {
$classes[] = 'nav-cat-' . $term->slug;
}
}
// WooCommerce urun kategorisi
if ($item->object === 'product_cat') {
$classes[] = 'nav-product-cat';
}
return $classes;
}
add_filter('nav_menu_css_class', 'custom_class_by_item_type', 10, 4);
Kullanıcı Rolüne Göre Sınıf Ekleme
Bu senaryo özellikle üyelik sistemlerinde ve WooCommerce projelerinde çok işe yarar. Farklı kullanıcı rollerine farklı görsel deneyim sunmak istediğinizde bu yaklaşımı kullanabilirsiniz.
function custom_class_by_user_role($classes, $item, $args, $depth) {
// Giris yapmis kullaniciya ozel
if (is_user_logged_in()) {
$current_user = wp_get_current_user();
// Yonetici icin
if (in_array('administrator', $current_user->roles)) {
$classes[] = 'nav-admin-item';
}
// Musteri icin (WooCommerce)
if (in_array('customer', $current_user->roles)) {
$classes[] = 'nav-customer-item';
}
// Editor icin
if (in_array('editor', $current_user->roles)) {
$classes[] = 'nav-editor-item';
}
} else {
// Misafir kullanici
$classes[] = 'nav-guest-item';
}
return $classes;
}
add_filter('nav_menu_css_class', 'custom_class_by_user_role', 10, 4);
WooCommerce Entegrasyonu: Sepet ve Hesap Linki
WooCommerce projelerinde sepet ikonu, hesap linki ve ödeme sayfası gibi özel öğeler için dinamik sınıflar eklemek çok yaygın bir ihtiyaçtır.
function woocommerce_menu_custom_classes($classes, $item, $args, $depth) {
if (!function_exists('WC')) {
return $classes;
}
$cart_page_id = wc_get_page_id('cart');
$checkout_page_id = wc_get_page_id('checkout');
$account_page_id = wc_get_page_id('myaccount');
// Sepet sayfasi
if ($item->object_id == $cart_page_id) {
$classes[] = 'nav-wc-cart';
$cart_count = WC()->cart ? WC()->cart->get_cart_contents_count() : 0;
if ($cart_count > 0) {
$classes[] = 'nav-wc-cart--has-items';
} else {
$classes[] = 'nav-wc-cart--empty';
}
}
// Odeme sayfasi
if ($item->object_id == $checkout_page_id) {
$classes[] = 'nav-wc-checkout';
$classes[] = 'nav-highlight'; // Odeme linkini vurgula
}
// Hesabim sayfasi
if ($item->object_id == $account_page_id) {
$classes[] = 'nav-wc-account';
if (is_user_logged_in()) {
$classes[] = 'nav-wc-account--logged-in';
} else {
$classes[] = 'nav-wc-account--logged-out';
}
}
return $classes;
}
add_filter('nav_menu_css_class', 'woocommerce_menu_custom_classes', 10, 4);
Menü ID’sine Göre Belirli Öğelere Sınıf Ekleme
Bazen çok spesifik bir menü öğesine özel sınıf eklemek istersiniz. Örneğin “İletişim” linkine her zaman kırmızı arkaplan vermek istiyorsunuz ama bunu kod üzerinden yönetmek istiyorsunuz.
function add_class_to_specific_menu_items($classes, $item, $args, $depth) {
// Belirli menu ogesi ID'lerine gore sinif ekle
// Bu ID'leri WordPress admin > Menus bolumunden bulabilirsiniz
$special_items = array(
42 => 'nav-contact nav-cta-button',
87 => 'nav-sale nav-badge',
156 => 'nav-new nav-highlight',
);
if (array_key_exists($item->ID, $special_items)) {
$extra_classes = explode(' ', $special_items[$item->ID]);
$classes = array_merge($classes, $extra_classes);
}
return $classes;
}
add_filter('nav_menu_css_class', 'add_class_to_specific_menu_items', 10, 4);
Menü öğesi ID’sini bulmak için şu yöntemi kullanabilirsiniz: WordPress admin panelinde Görünüm > Menüler sayfasına gidin, bir menü öğesinin üzerine geldiğinizde browser URL çubuğunu kontrol edin ya da sayfanın kaynağında menu-item- ile başlayan class’lara bakın.
Özel Meta Veriye Göre Sınıf Ekleme
Gelişmiş projelerde menü öğelerine özel meta veri ekleyip bu veriye göre sınıf atamak oldukça güçlü bir yöntemdir. Bunun için önce menü öğesine özel alan eklememiz gerekir.
// Oncelikle menu ogesine ozel meta alan ekleyelim
function add_menu_item_custom_fields($item_id, $item, $depth, $args) {
$custom_class = get_post_meta($item_id, '_menu_item_custom_class', true);
$is_featured = get_post_meta($item_id, '_menu_item_featured', true);
?>
<p class="field-custom-class description description-wide">
<label for="edit-menu-item-custom-class-<?php echo $item_id; ?>">
<?php esc_html_e('Ozel CSS Sinifi', 'textdomain'); ?>
<input type="text"
id="edit-menu-item-custom-class-<?php echo $item_id; ?>"
class="widefat code edit-menu-item-custom-class"
name="menu-item-custom-class[<?php echo $item_id; ?>]"
value="<?php echo esc_attr($custom_class); ?>" />
</label>
</p>
<p class="field-featured description description-wide">
<label>
<input type="checkbox"
name="menu-item-featured[<?php echo $item_id; ?>]"
value="1" <?php checked($is_featured, '1'); ?> />
<?php esc_html_e('Ozellistir (featured sinifi ekle)', 'textdomain'); ?>
</label>
</p>
<?php
}
add_action('wp_nav_menu_item_custom_fields', 'add_menu_item_custom_fields', 10, 4);
// Meta verileri kaydet
function save_menu_item_custom_fields($menu_id, $menu_item_db_id) {
if (isset($_POST['menu-item-custom-class'][$menu_item_db_id])) {
$custom_class = sanitize_html_class(
$_POST['menu-item-custom-class'][$menu_item_db_id]
);
update_post_meta($menu_item_db_id, '_menu_item_custom_class', $custom_class);
}
$is_featured = isset($_POST['menu-item-featured'][$menu_item_db_id]) ? '1' : '0';
update_post_meta($menu_item_db_id, '_menu_item_featured', $is_featured);
}
add_action('wp_update_nav_menu_item', 'save_menu_item_custom_fields', 10, 2);
// Kaydedilen meta veriye gore sinif ekle
function apply_custom_meta_classes($classes, $item, $args, $depth) {
$custom_class = get_post_meta($item->ID, '_menu_item_custom_class', true);
$is_featured = get_post_meta($item->ID, '_menu_item_featured', true);
if (!empty($custom_class)) {
$classes[] = $custom_class;
}
if ($custom_class === '1') {
$classes[] = 'nav-featured';
}
return $classes;
}
add_filter('nav_menu_css_class', 'apply_custom_meta_classes', 10, 4);
Mevcut Sayfaya ve Üst Kategoriye Göre Aktif Sınıf Yönetimi
WordPress varsayılan olarak aktif menü öğesine current-menu-item sınıfı ekler. Ama bazen bu yeterli olmaz ve daha granüler bir kontrol gerekir.
function enhanced_active_menu_classes($classes, $item, $args, $depth) {
// Mevcut sayfa bir WooCommerce urun sayfasiysa
// ilgili urun kategorisi menusu de aktif gorunsun
if (function_exists('is_product') && is_product()) {
global $post;
$product_cats = wp_get_post_terms($post->ID, 'product_cat', array('fields' => 'ids'));
if ($item->object === 'product_cat' && in_array($item->object_id, $product_cats)) {
$classes[] = 'current-product-cat-ancestor';
$classes[] = 'nav-active-category';
}
}
// Arsiv sayfasindaysa ilgili kategori linkini aktiflestir
if (is_category()) {
$current_cat = get_queried_object();
if ($item->object === 'category' && $item->object_id == $current_cat->term_id) {
$classes[] = 'nav-current-archive';
}
// Ust kategori ise ancestor sinifi ekle
$ancestors = get_ancestors($current_cat->term_id, 'category');
if (in_array($item->object_id, $ancestors)) {
$classes[] = 'nav-category-ancestor';
}
}
return $classes;
}
add_filter('nav_menu_css_class', 'enhanced_active_menu_classes', 10, 4);
Performans Optimizasyonu: Sınıf İşlemlerini Önbellekleme
Karmaşık menü sınıfı hesaplamalarında performans önemli bir faktördür. Özellikle her sayfa yüklemesinde veritabanına giden sorgular varsa, transient API kullanmak mantıklıdır.
function cached_menu_classes($classes, $item, $args, $depth) {
// Kullanici giris yapmamissa cache kullan
if (!is_user_logged_in()) {
$cache_key = 'menu_item_classes_' . $item->ID . '_' . $args->theme_location;
$cached_extra_classes = get_transient($cache_key);
if ($cached_extra_classes === false) {
// Hesaplama yap
$extra_classes = array();
// Ozel meta kontrolu (veritabani sorgusu)
$custom_class = get_post_meta($item->ID, '_menu_item_custom_class', true);
if (!empty($custom_class)) {
$extra_classes[] = $custom_class;
}
// Tip bazli siniflar
if ($item->object === 'category') {
$extra_classes[] = 'nav-is-category';
}
// 12 saat cache'le
set_transient($cache_key, $extra_classes, 12 * HOUR_IN_SECONDS);
$cached_extra_classes = $extra_classes;
}
$classes = array_merge($classes, $cached_extra_classes);
}
return $classes;
}
add_filter('nav_menu_css_class', 'cached_menu_classes', 10, 4);
// Menu guncellendikten sonra cache'i temizle
function clear_menu_class_cache($menu_id) {
global $wpdb;
$wpdb->query(
"DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_menu_item_classes_%'"
);
}
add_action('wp_update_nav_menu', 'clear_menu_class_cache');
Gerçek Dünya Senaryosu: Çok Dilli Site Menüsü
WPML veya Polylang kullanan çok dilli sitelerde aktif dile göre farklı menü stilleri uygulamak isteyebilirsiniz.
function multilingual_menu_classes($classes, $item, $args, $depth) {
// WPML aktif mi?
if (defined('ICL_LANGUAGE_CODE')) {
$current_lang = ICL_LANGUAGE_CODE;
$classes[] = 'nav-lang-' . $current_lang;
// RTL diller icin ozel sinif
$rtl_languages = array('ar', 'he', 'fa', 'ur');
if (in_array($current_lang, $rtl_languages)) {
$classes[] = 'nav-rtl-item';
}
}
// Polylang aktif mi?
if (function_exists('pll_current_language')) {
$current_lang = pll_current_language();
$classes[] = 'nav-pll-' . $current_lang;
}
return $classes;
}
add_filter('nav_menu_css_class', 'multilingual_menu_classes', 10, 4);
Tüm Yaklaşımları Bir Araya Getirme
Büyük projelerde bu fonksiyonların tamamını tek bir organize yapıda toplamak daha iyi bir pratiktir. Bir sınıf yapısı kullanmak kodu daha yönetilebilir kılar.
class Custom_Menu_Classes {
public function __construct() {
add_filter('nav_menu_css_class', array($this, 'add_classes'), 10, 4);
}
public function add_classes($classes, $item, $args, $depth) {
$classes = $this->location_classes($classes, $item, $args, $depth);
$classes = $this->type_classes($classes, $item, $args, $depth);
$classes = $this->user_classes($classes, $item, $args);
$classes = $this->woocommerce_classes($classes, $item);
$classes = $this->meta_classes($classes, $item);
return array_unique($classes); // Tekrar edenleri kaldir
}
private function location_classes($classes, $item, $args, $depth) {
$location = isset($args->theme_location) ? $args->theme_location : '';
$location_map = array(
'primary' => 'main-nav__item',
'footer' => 'footer-nav__item',
'mobile' => 'mobile-nav__item',
);
if (isset($location_map[$location])) {
$classes[] = $location_map[$location];
$classes[] = $location_map[$location] . '--depth-' . $depth;
}
return $classes;
}
private function type_classes($classes, $item, $args, $depth) {
$type_map = array(
'custom' => 'nav-custom-link',
'page' => 'nav-page',
'category' => 'nav-category',
'product_cat' => 'nav-product-cat',
);
if (isset($type_map[$item->object])) {
$classes[] = $type_map[$item->object];
}
return $classes;
}
private function user_classes($classes, $item, $args) {
if (is_user_logged_in()) {
$classes[] = 'nav-for-logged-in';
} else {
$classes[] = 'nav-for-guest';
}
return $classes;
}
private function woocommerce_classes($classes, $item) {
if (!function_exists('WC')) {
return $classes;
}
$wc_pages = array(
wc_get_page_id('cart') => 'nav-wc-cart',
wc_get_page_id('checkout') => 'nav-wc-checkout',
wc_get_page_id('myaccount') => 'nav-wc-account',
);
if (isset($wc_pages[$item->object_id])) {
$classes[] = $wc_pages[$item->object_id];
}
return $classes;
}
private function meta_classes($classes, $item) {
$custom_class = get_post_meta($item->ID, '_menu_item_custom_class', true);
if (!empty($custom_class)) {
$classes[] = sanitize_html_class($custom_class);
}
return $classes;
}
}
new Custom_Menu_Classes();
Dikkat Edilmesi Gereken Noktalar
Bu teknikleri uygularken bazı önemli noktaları aklınızda tutun:
- Güvenlik: Kullanıcıdan gelen CSS sınıfı değerlerini mutlaka
sanitize_html_class()fonksiyonuyla temizleyin - Performans: Her menü öğesi için veritabanı sorgusu yapmaktan kaçının, mümkün olduğunda transient kullanın
- Öncelik sırası:
add_filterile belirlediğiniz öncelik sayısı (varsayılan 10) önemlidir, çakışma durumunda bunu ayarlayın - Temizlik:
array_unique()kullanarak tekrar eden sınıfları HTML çıktısından temizleyin - Test: Her özelliği farklı kullanıcı rolleri ve tarayıcılarda test edin
- Belgeleme: Hangi ID’ye hangi sınıfın eklendiğini bir yorum satırıyla belgeyin, altı ay sonra unutursunuz
Sonuç
WordPress menü yönetimi, nav_menu_css_class filtresi sayesinde oldukça esnek bir yapıya kavuşuyor. Basit bir sınıf eklemesinden karmaşık kullanıcı rolü bazlı dinamik stil yönetimine kadar her şeyi programatik olarak halledebilirsiniz.
En önemli öneri şu: Tüm bu yaklaşımları tek bir iyi organize edilmiş sınıf veya dosya yapısında toplayın. Birbirinden bağımsız onlarca add_filter çağrısı functions.php dosyanızı kısa sürede okunaksız hale getirir. Sınıf tabanlı yaklaşım hem test edilebilirlik hem de bakım açısından çok daha sağlıklıdır.
WooCommerce projelerinde özellikle sepet ve hesap sayfası entegrasyonuna dikkat edin, bu öğeler sıklıkla değişen dinamik içerikler barındırdığından önbellekleme stratejinizi buna göre ayarlayın. Menü öğesi meta alanı yaklaşımı ise müşterilerinize teknik bilgi gerektirmeden özel sınıf ekleme imkanı tanıyan kullanıcı dostu bir çözüm sunuyor.
