WordPress Sticky Post Özelleştirme: Öne Çıkan Yazı

WordPress’te bir yazıyı “sticky” yani öne çıkan olarak işaretlediğinizde, o yazı blog listenizin en üstüne sabitlenir. Basit ama güçlü bu özellik, çoğu site sahibi tarafından yeterince kullanılmıyor. Oysaki doğru özelleştirmelerle sticky post’lardan ciddi anlamda faydalanabilirsiniz: özel görsel tasarım, farklı içerik gösterimi, kategori bazlı filtreleme ve daha fazlası. Bu yazıda functions.php dosyasına ekleyeceğiniz kod parçacıklarıyla WordPress sticky post özelliğini nasıl ustaca kullanacağınızı ele alacağız.

Sticky Post Nedir ve Nasıl Çalışır?

WordPress, her yazıyı veritabanında wp_postmeta tablosunda çeşitli meta verilerle saklar. Bir yazıyı sticky olarak işaretlediğinizde ise bu bilgi aslında wp_options tablosunda sticky_posts anahtarı altında bir dizi olarak tutulur. Yani sticky post, meta veri değil seçenek verisidir.

Bu teknik detay neden önemli? Çünkü sticky post’ları WP_Query ile sorgularken bazı özel parametreler kullanmanız gerekiyor. Ayrıca sticky post’ların davranışını özelleştirmek istediğinizde doğru kancaları (hook) bilmek işinizi kolaylaştırıyor.

WordPress varsayılan olarak sticky post’lara özel bir şey yapmaz; sadece onları listenin başına taşır. Görsel ayrım, özel içerik veya farklı şablonlar için bizim müdahale etmemiz gerekiyor.

Body Class ile Sticky Yazılara CSS Sınıfı Ekleme

WordPress, post_class() fonksiyonu aracılığıyla sticky yazılara zaten sticky CSS sınıfını ekliyor. Ancak bazı tema geliştirici bu sınıfı kullanmıyor ya da siz daha spesifik bir sınıf yapısı istiyorsunuz. Bunu özelleştirmek için post_class filtresini kullanabilirsiniz.

// functions.php
function custom_sticky_post_class( $classes ) {
    if ( is_sticky() && is_home() && ! is_paged() ) {
        $classes[] = 'featured-post';
        $classes[] = 'highlighted-sticky';
    }
    return $classes;
}
add_filter( 'post_class', 'custom_sticky_post_class' );

Bu kod sayesinde ana sayfadaki sticky yazılar hem sticky hem de featured-post ve highlighted-sticky sınıflarını alır. CSS tarafında bu sınıfları şu şekilde kullanabilirsiniz:

/* style.css veya wp_head ile eklenen CSS */
.featured-post {
    border: 3px solid #e74c3c;
    background-color: #fef9f9;
    padding: 20px;
    position: relative;
}

.featured-post::before {
    content: "⭐ Öne Çıkan";
    background: #e74c3c;
    color: white;
    padding: 4px 12px;
    font-size: 12px;
    position: absolute;
    top: 0;
    left: 0;
}

Sticky Yazılara Özel Rozet (Badge) Ekleme

Ziyaretçilere bir yazının öne çıkan yazı olduğunu göstermenin en etkili yolu görsel bir rozet eklemektir. Bunu the_title filtresini veya the_content filtresini kullanarak yapabiliriz.

// functions.php
function add_sticky_badge_to_title( $title ) {
    if ( is_sticky( get_the_ID() ) && is_home() ) {
        $badge = '<span class="sticky-badge" style="
            background:#e74c3c;
            color:white;
            font-size:11px;
            padding:2px 8px;
            border-radius:3px;
            margin-right:8px;
            vertical-align:middle;
            font-weight:bold;
        ">ÖNE ÇIKAN</span>';
        $title = $badge . $title;
    }
    return $title;
}
add_filter( 'the_title', 'add_sticky_badge_to_title' );

Ancak burada dikkatli olmak gerekiyor. the_title filtresi sadece blog listesinde değil, navigasyon menülerinde ve widget’larda da çalışır. Daha güvenli bir yaklaşım için in_the_loop() kontrolü ekleyelim:

// functions.php - Daha güvenli versiyon
function add_sticky_badge_to_title_safe( $title, $post_id ) {
    if ( 
        is_sticky( $post_id ) && 
        is_home() && 
        in_the_loop() && 
        ! is_paged() 
    ) {
        $badge = sprintf(
            '<span class="sticky-badge">%s</span> ',
            esc_html__( 'Öne Çıkan', 'your-theme-textdomain' )
        );
        return $badge . $title;
    }
    return $title;
}
add_filter( 'the_title', 'add_sticky_badge_to_title_safe', 10, 2 );

Sticky Post’ları Programatik Olarak Yönetme

Bazen bir yazıyı kod üzerinden sticky yapmak veya sticky durumunu kaldırmak isteyebilirsiniz. Bu işlemi yapan özel fonksiyonlar yazalım:

// functions.php
// Yazıyı sticky yap
function make_post_sticky( $post_id ) {
    $sticky_posts = get_option( 'sticky_posts', array() );
    
    if ( ! in_array( $post_id, $sticky_posts ) ) {
        $sticky_posts[] = (int) $post_id;
        update_option( 'sticky_posts', $sticky_posts );
        return true;
    }
    return false; // Zaten sticky
}

// Yazıdan sticky durumunu kaldır
function make_post_unsticky( $post_id ) {
    $sticky_posts = get_option( 'sticky_posts', array() );
    
    if ( in_array( $post_id, $sticky_posts ) ) {
        $sticky_posts = array_diff( $sticky_posts, array( (int) $post_id ) );
        update_option( 'sticky_posts', array_values( $sticky_posts ) );
        return true;
    }
    return false; // Zaten sticky değil
}

// Tüm sticky post ID'lerini getir
function get_all_sticky_post_ids() {
    return get_option( 'sticky_posts', array() );
}

// Kullanım örnekleri:
// make_post_sticky( 42 );
// make_post_unsticky( 42 );
// $ids = get_all_sticky_post_ids();

Bu fonksiyonlar gerçek dünyada çok işe yarar. Örneğin bir müşteri projesi üzerinde çalışırken yönetici paneli olmadan toplu içerik yönetimi yapmanız gerektiğinde, ya da bir eklenti geliştirirken programatik sticky yönetimine ihtiyaç duyduğunuzda bu yapıyı kullanabilirsiniz.

Sticky Post Sayısını Sınırlama

Bir site yöneticisi bazen yanlışlıkla çok fazla yazıyı sticky olarak işaretler. Bu durumda ana sayfa düzeni bozulabilir. Maksimum sticky post sayısını sınırlamak için pre_update_option_sticky_posts filtresini kullanabiliriz:

// functions.php
function limit_sticky_posts_count( $new_value, $old_value ) {
    $max_sticky = 3; // En fazla 3 sticky post
    
    if ( is_array( $new_value ) && count( $new_value ) > $max_sticky ) {
        // Yöneticiye bildirim gönder
        add_action( 'admin_notices', function() use ( $max_sticky ) {
            echo '<div class="notice notice-warning is-dismissible">';
            echo '<p><strong>Uyarı:</strong> En fazla ' . $max_sticky . ' adet öne çıkan yazı ekleyebilirsiniz. Ekleme yapılamadı.</p>';
            echo '</div>';
        });
        
        // Eski değeri koru veya sadece ilk N tanesini al
        return array_slice( $new_value, 0, $max_sticky );
    }
    
    return $new_value;
}
add_filter( 'pre_update_option_sticky_posts', 'limit_sticky_posts_count', 10, 2 );

Sticky Post’ları Kategoriye Göre Öne Çıkarma

Varsayılan WordPress davranışı sticky post’ları her kategoride göstermez, sadece ana blog listesinde öne çıkarır. Kategori arşivlerinde de sticky davranışını simüle etmek istiyorsanız şu yaklaşımı kullanabilirsiniz:

// functions.php
function sticky_posts_in_category( $query ) {
    // Sadece kategori arşivlerinde ve ana sorgu için çalışır
    if ( 
        ! is_admin() && 
        $query->is_main_query() && 
        $query->is_category() 
    ) {
        $sticky_ids = get_option( 'sticky_posts', array() );
        
        if ( empty( $sticky_ids ) ) {
            return;
        }
        
        $current_category = $query->get( 'cat' );
        
        // Bu kategoride sticky olan yazıları bul
        $sticky_in_cat = array();
        foreach ( $sticky_ids as $sticky_id ) {
            if ( in_category( $current_category, $sticky_id ) ) {
                $sticky_in_cat[] = $sticky_id;
            }
        }
        
        if ( ! empty( $sticky_in_cat ) ) {
            // Mevcut ignore listesini al ve güncelle
            $current_ignore = $query->get( 'post__not_in', array() );
            
            // Önce sticky'leri getir, sonra kalanları
            $query->set( 'ignore_sticky_posts', 0 );
        }
    }
}
add_action( 'pre_get_posts', 'sticky_posts_in_category' );

Sticky Post’lar için Özel Şablon (Template) Kullanımı

Sticky post’lara tamamen farklı bir görünüm vermek istiyorsanız, the_content ya da şablon düzeyinde müdahale edebilirsiniz. Tema dosyalarınıza dokunmadan sadece functions.php üzerinden bu işi halletmenin yolu:

// functions.php
function custom_sticky_post_content_wrapper( $content ) {
    if ( ! is_sticky( get_the_ID() ) || ! is_home() || ! in_the_loop() ) {
        return $content;
    }
    
    $sticky_thumbnail = '';
    
    if ( has_post_thumbnail() ) {
        $sticky_thumbnail = sprintf(
            '<div class="sticky-featured-image">%s</div>',
            get_the_post_thumbnail( get_the_ID(), 'medium', array( 
                'class' => 'sticky-thumb',
                'loading' => 'eager' // Öne çıkan yazı için lazy loading kapalı
            ))
        );
    }
    
    $sticky_meta = sprintf(
        '<div class="sticky-meta">
            <span class="sticky-date">%s</span>
            <span class="sticky-author">%s %s</span>
            <span class="sticky-cats">%s</span>
        </div>',
        get_the_date(),
        esc_html__( 'Yazar:', 'your-theme' ),
        get_the_author(),
        get_the_category_list( ', ' )
    );
    
    $wrapped = sprintf(
        '<div class="sticky-post-inner">
            %s
            <div class="sticky-post-text">
                %s
                %s
            </div>
        </div>',
        $sticky_thumbnail,
        $sticky_meta,
        $content
    );
    
    return $wrapped;
}
add_filter( 'the_content', 'custom_sticky_post_content_wrapper' );

Bu yaklaşım güzel ama dikkat edilmesi gereken bir nokta var: the_content filtresi tek yazı sayfalarında da çalışır. is_single() veya is_singular() kontrolleriyle bunu önleyebilirsiniz.

Sticky Post’ları REST API ile Filtreleme

Headless WordPress kullanıyorsanız veya AJAX ile içerik çekiyorsanız REST API üzerinden sticky post’ları yönetmek isteyebilirsiniz. Varsayılan olarak REST API sticky post’ları öne almaz. Bunu düzeltmek için:

// functions.php
function sticky_posts_in_rest_api( $args, $request ) {
    // Eğer istek özellikle sticky istiyorsa
    if ( isset( $request['sticky'] ) && $request['sticky'] ) {
        $sticky_ids = get_option( 'sticky_posts', array() );
        
        if ( ! empty( $sticky_ids ) ) {
            $args['post__in'] = $sticky_ids;
            $args['ignore_sticky_posts'] = 1;
            $args['orderby'] = 'post__in';
        }
    }
    
    return $args;
}
add_filter( 'rest_post_query', 'sticky_posts_in_rest_api', 10, 2 );

// REST API yanıtına sticky bilgisi ekle
function add_sticky_field_to_rest( $response, $post, $request ) {
    $response->data['is_sticky'] = is_sticky( $post->ID );
    return $response;
}
add_filter( 'rest_prepare_post', 'add_sticky_field_to_rest', 10, 3 );

Bu kodu ekledikten sonra REST API’ye şu şekilde istek atabilirsiniz:

# Sticky post'ları getir
curl https://siteniz.com/wp-json/wp/v2/posts?sticky=true

# Yanıtta is_sticky alanı artık mevcut
# { "id": 42, "is_sticky": true, ... }

WP_Query ile Sticky Post’ları Özelleştirme

Bazen ana sorgu yerine özel sorgular kullanmanız gerekir. Sticky post’ları içeren ve dışarıda bırakan özel sorgular nasıl yazılır:

// functions.php veya şablon dosyası

// Sadece sticky post'ları getir
function get_sticky_posts_query( $posts_per_page = 3 ) {
    $sticky_ids = get_option( 'sticky_posts', array() );
    
    if ( empty( $sticky_ids ) ) {
        return new WP_Query( array( 'post__in' => array(0) ) ); // Boş sorgu
    }
    
    return new WP_Query( array(
        'post__in'            => $sticky_ids,
        'posts_per_page'      => $posts_per_page,
        'ignore_sticky_posts' => 1,
        'orderby'             => 'date',
        'order'               => 'DESC',
        'post_status'         => 'publish',
    ));
}

// Sticky post'ları hariç tutan sorgu
function get_non_sticky_posts_query( $posts_per_page = 10, $paged = 1 ) {
    $sticky_ids = get_option( 'sticky_posts', array() );
    
    $args = array(
        'posts_per_page'      => $posts_per_page,
        'ignore_sticky_posts' => 1,
        'paged'               => $paged,
        'post_status'         => 'publish',
    );
    
    if ( ! empty( $sticky_ids ) ) {
        $args['post__not_in'] = $sticky_ids;
    }
    
    return new WP_Query( $args );
}

// Kullanım örneği - shortcode olarak
function sticky_posts_shortcode( $atts ) {
    $atts = shortcode_atts( array(
        'count' => 3,
        'show_excerpt' => 'yes',
    ), $atts, 'sticky_posts' );
    
    $query = get_sticky_posts_query( (int) $atts['count'] );
    
    if ( ! $query->have_posts() ) {
        return '<p>Öne çıkan yazı bulunamadı.</p>';
    }
    
    $output = '<div class="sticky-posts-list">';
    
    while ( $query->have_posts() ) {
        $query->the_post();
        $output .= '<article class="sticky-item">';
        $output .= '<h3><a href="' . esc_url( get_the_permalink() ) . '">' . esc_html( get_the_title() ) . '</a></h3>';
        
        if ( $atts['show_excerpt'] === 'yes' ) {
            $output .= '<p>' . esc_html( get_the_excerpt() ) . '</p>';
        }
        
        $output .= '</article>';
    }
    
    wp_reset_postdata();
    
    $output .= '</div>';
    return $output;
}
add_shortcode( 'sticky_posts', 'sticky_posts_shortcode' );

Bu shortcode’u içerik editöründe [sticky_posts count="5" show_excerpt="no"] şeklinde kullanabilirsiniz.

Sticky Post Durumu Değiştiğinde Önbelleği Temizleme

Performans için önbellek kullanıyorsanız (WP Rocket, W3 Total Cache veya özel Redis/Memcached kurulumu), sticky durumu değiştiğinde önbelleği temizlemeniz gerekir. Aksi halde ziyaretçiler eski halini görmeye devam eder:

// functions.php
function clear_cache_on_sticky_change( $new_value, $old_value, $option ) {
    // Sadece sticky_posts seçeneği değiştiğinde
    if ( $option !== 'sticky_posts' ) {
        return;
    }
    
    // WP Rocket önbelleğini temizle
    if ( function_exists( 'rocket_clean_domain' ) ) {
        rocket_clean_domain();
    }
    
    // W3 Total Cache temizle
    if ( function_exists( 'w3tc_flush_all' ) ) {
        w3tc_flush_all();
    }
    
    // WP Super Cache temizle
    if ( function_exists( 'wp_cache_clear_cache' ) ) {
        wp_cache_clear_cache();
    }
    
    // LiteSpeed Cache temizle
    if ( class_exists( 'LiteSpeed_Cache_API' ) ) {
        LiteSpeed_Cache_API::purge_all();
    }
    
    // Özel transient temizleme
    delete_transient( 'homepage_sticky_posts' );
    delete_transient( 'sidebar_featured_posts' );
    
    // WordPress object cache temizle
    wp_cache_delete( 'sticky_posts', 'options' );
    
    error_log( 'Sticky posts değişti, önbellek temizlendi. Tarih: ' . current_time('mysql') );
}
add_action( 'updated_option', 'clear_cache_on_sticky_change', 10, 3 );

Sticky Post’lar İçin Admin Sütunu Ekleme

Yönetici panelindeki yazılar listesinde hangi yazıların sticky olduğunu kolayca görmek için özel bir sütun ekleyebilirsiniz:

// functions.php
// Sütun başlığını ekle
function add_sticky_column_header( $columns ) {
    $columns['is_sticky'] = '⭐ Öne Çıkan';
    return $columns;
}
add_filter( 'manage_posts_columns', 'add_sticky_column_header' );

// Sütun içeriğini doldur
function populate_sticky_column( $column_name, $post_id ) {
    if ( $column_name === 'is_sticky' ) {
        if ( is_sticky( $post_id ) ) {
            echo '<span style="color:#e74c3c;font-size:18px;" title="Öne Çıkan Yazı">⭐</span>';
        } else {
            echo '<span style="color:#ccc;font-size:18px;" title="Normal Yazı">☆</span>';
        }
    }
}
add_action( 'manage_posts_custom_column', 'populate_sticky_column', 10, 2 );

// Sütunu sıralanabilir yap
function sticky_column_sortable( $columns ) {
    $columns['is_sticky'] = 'is_sticky';
    return $columns;
}
add_filter( 'manage_edit-post_sortable_columns', 'sticky_column_sortable' );

// Sıralama mantığını ekle
function sticky_column_orderby( $query ) {
    if ( 
        ! is_admin() || 
        $query->get( 'orderby' ) !== 'is_sticky' 
    ) {
        return;
    }
    
    $sticky_ids = get_option( 'sticky_posts', array() );
    
    if ( ! empty( $sticky_ids ) ) {
        $query->set( 'post__in', $sticky_ids );
        $query->set( 'ignore_sticky_posts', 1 );
    }
}
add_action( 'pre_get_posts', 'sticky_column_orderby' );

Gerçek Dünya Senaryo: Haber Sitesi Örneği

Diyelim ki bir haber sitesi yönetiyorsunuz. Son dakika haberleri sticky olarak işaretleniyor ve bunların kırmızı bir banner ile öne çıkması gerekiyor. Ayrıca 24 saat sonra sticky durumu otomatik kalkacak. İşte bu senaryoyu çözen kod:

// functions.php

// Sticky yazılara otomatik süre sonu ekle
function set_sticky_expiry_meta( $post_id ) {
    if ( is_sticky( $post_id ) ) {
        // Eğer daha önce süre belirlenmemişse, 24 saat ekle
        $existing_expiry = get_post_meta( $post_id, '_sticky_expires_at', true );
        
        if ( ! $existing_expiry ) {
            $expires = current_time( 'timestamp' ) + ( 24 * HOUR_IN_SECONDS );
            update_post_meta( $post_id, '_sticky_expires_at', $expires );
        }
    }
}
add_action( 'save_post', 'set_sticky_expiry_meta' );

// Cron ile süresi dolan sticky'leri kaldır
function remove_expired_sticky_posts() {
    $sticky_ids = get_option( 'sticky_posts', array() );
    
    if ( empty( $sticky_ids ) ) {
        return;
    }
    
    $now = current_time( 'timestamp' );
    $changed = false;
    
    foreach ( $sticky_ids as $key => $post_id ) {
        $expires_at = get_post_meta( $post_id, '_sticky_expires_at', true );
        
        if ( $expires_at && $now > $expires_at ) {
            unset( $sticky_ids[ $key ] );
            delete_post_meta( $post_id, '_sticky_expires_at' );
            $changed = true;
            
            error_log( sprintf( 
                'Yazı #%d sticky süresi doldu, kaldırıldı. Tarih: %s',
                $post_id,
                current_time('mysql')
            ));
        }
    }
    
    if ( $changed ) {
        update_option( 'sticky_posts', array_values( $sticky_ids ) );
    }
}

// Cron zamanlamasını kayıt et
function schedule_sticky_expiry_cron() {
    if ( ! wp_next_scheduled( 'check_sticky_expiry' ) ) {
        wp_schedule_event( time(), 'hourly', 'check_sticky_expiry' );
    }
}
add_action( 'wp', 'schedule_sticky_expiry_cron' );
add_action( 'check_sticky_expiry', 'remove_expired_sticky_posts' );

Olası Sorunlar ve Çözümleri

  • Sayfalama sorunu: Sticky post’lar her sayfada tekrar görünür. Bunu önlemek için is_paged() kontrolünü mutlaka ekleyin.
  • Özel post type’larda sticky çalışmıyor: Varsayılan olarak sticky özelliği sadece standart post tipi için çalışır. Özel post type’larda benzer işlevi için sticky_posts seçeneğini manuel yönetmeniz gerekir.
  • REST API’de görünmüyor: rest_post_query filtresini kullanarak yukarıda gösterdiğimiz gibi REST API desteği ekleyin.
  • Önbellek sorunları: Sticky durumu değiştiğinde mutlaka önbelleği temizleyin.
  • Çoklu dil (WPML/Polylang) uyumu: Çeviri eklentileri kullanırken sticky ID’lerinin dil bazlı yönetilmesi gerekebilir.

Sonuç

WordPress sticky post özelliği, kutudan çıktığı haliyle oldukça sınırlı görünse de functions.php üzerinden yapılan müdahalelerle son derece güçlü bir araca dönüşebilir. Bu yazıda öğrendiklerinizi özetleyecek olursak:

  • CSS sınıfları ve rozet ekleme ile görsel ayrım yapabilirsiniz
  • Programatik yönetim fonksiyonları ile sticky durumunu kod üzerinden kontrol edebilirsiniz
  • Sticky sayısını sınırlayarak site düzenini koruyabilirsiniz
  • REST API entegrasyonu ile headless projelerde de kullanabilirsiniz
  • Otomatik süre sonu ile cron kullanarak dinamik sticky yönetimi yapabilirsiniz
  • Admin sütunları ile yönetici deneyimini iyileştirebilirsiniz

Tüm bu kodları functions.php dosyasına doğrudan ekleyebileceğiniz gibi, daha iyi bir pratik olarak bir child theme içinde ya da site-specific eklenti olarak kullanmanızı öneririm. Bu sayede tema güncellemelerinde kodlarınız kaybolmaz ve yönetim çok daha temiz olur.

Bir yanıt yazın

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