WordPress’te Yazılara Otomatik Etiket Bulutu Ekleme
WordPress sitenizde içerik üretmek kadar o içeriği keşfedilebilir kılmak da önemli. Ziyaretçileriniz siteye geldiğinde ilgili yazılara kolayca ulaşabilmeli, etiketler arasında gezinebilmeli. İşte bu noktada etiket bulutu devreye giriyor. Ama standart WordPress widget’ı ile yetinmek zorunda değilsiniz. functions.php üzerinden özelleştirilmiş, akıllı bir etiket bulutu sistemi kurabilirsiniz.
Bu yazıda, WordPress’in yerleşik etiket sistemini functions.php fonksiyonlarıyla genişleterek yazılarınıza otomatik etiket bulutu eklemeyi ele alacağız. Hem tek yazı sayfalarında hem de arşiv sayfalarında çalışan, performanslı ve özelleştirilebilir bir yapı kuracağız.
Neden Özel Etiket Bulutu Sistemi?
WordPress’in varsayılan wp_tag_cloud() fonksiyonu işe yarar ama sınırlı. Herhangi bir yazının altına otomatik olarak ilgili etiketleri bir bulut şeklinde göstermez. Widget olarak sidebar’a ekleyebilirsiniz ama bu tüm etiketleri gösterir, yazıya özel değildir.
Gerçek dünya senaryosu düşünelim: 500 yazılık bir teknoloji blogunuz var. Her yazının altında o yazıyla ilgili etiketler gösterilsin, üstelik etiketin kaç yazıda kullanıldığına göre font boyutu değişsin, popüler etiketler daha büyük görünsün. Bunu WordPress panel’inden kutudan çıkar çıkmaz yapamazsınız. functions.php devreye giriyor.
Temel Yapı: İlk Fonksiyonumuz
Önce en basit halinden başlayalım. Bir yazının etiketlerini alıp HTML olarak döndüren bir fonksiyon yazalım:
// functions.php
function my_post_tag_cloud( $post_id = null ) {
if ( ! $post_id ) {
$post_id = get_the_ID();
}
$tags = get_the_tags( $post_id );
if ( ! $tags || is_wp_error( $tags ) ) {
return '';
}
$output = '<div class="post-tag-cloud">';
$output .= '<span class="tag-cloud-label">Etiketler: </span>';
foreach ( $tags as $tag ) {
$tag_link = get_tag_link( $tag->term_id );
$output .= '<a href="' . esc_url( $tag_link ) . '" class="tag-cloud-link" rel="tag">';
$output .= esc_html( $tag->name );
$output .= '</a> ';
}
$output .= '</div>';
return $output;
}
Bu temel fonksiyon, belirli bir yazının etiketlerini alıp link olarak döndürüyor. esc_url() ve esc_html() kullanmayı unutmayın, güvenlik her zaman önce gelir.
Otomatik Ekleme: the_content Hook
Şimdi bu fonksiyonu yazı içeriğinin altına otomatik ekleyelim. Her yazıya manuel olarak shortcode koymak yerine hook kullanacağız:
// functions.php
function auto_append_tag_cloud( $content ) {
// Sadece tekil yazı sayfalarında çalışsın
if ( ! is_single() || ! in_the_loop() || ! is_main_query() ) {
return $content;
}
// Sadece 'post' post tipinde çalışsın
if ( get_post_type() !== 'post' ) {
return $content;
}
$tag_cloud = my_post_tag_cloud();
if ( ! empty( $tag_cloud ) ) {
$content .= $tag_cloud;
}
return $content;
}
add_filter( 'the_content', 'auto_append_tag_cloud' );
is_single(), in_the_loop() ve is_main_query() kontrollerini yapmak kritik. Aksi halde bu kod sidebar widget’larında, RSS feed’de ve beklenmedik yerlerde de çalışır.
Font Boyutunu Popülerliğe Göre Ayarlama
Gerçek bir etiket bulutu, etiketin kullanım sıklığına göre farklı boyutlarda görünür. Bu özelliği kendi fonksiyonumuza ekleyelim:
// functions.php
function my_weighted_tag_cloud( $post_id = null ) {
if ( ! $post_id ) {
$post_id = get_the_ID();
}
$tags = get_the_tags( $post_id );
if ( ! $tags || is_wp_error( $tags ) ) {
return '';
}
// Tüm etiketlerin kullanım sayılarını al
$tag_counts = array();
foreach ( $tags as $tag ) {
$tag_counts[ $tag->term_id ] = $tag->count;
}
// Min ve max değerleri bul
$min_count = min( $tag_counts );
$max_count = max( $tag_counts );
// Font boyutu aralığı (px cinsinden)
$min_font = 12;
$max_font = 28;
$output = '<div class="post-tag-cloud weighted">';
$output .= '<span class="tag-cloud-title">Bu Yazının Etiketleri</span>';
foreach ( $tags as $tag ) {
$tag_link = get_tag_link( $tag->term_id );
$count = $tag->count;
// Font boyutunu hesapla
if ( $max_count === $min_count ) {
$font_size = ( $min_font + $max_font ) / 2;
} else {
$font_size = $min_font + ( ( $count - $min_count ) / ( $max_count - $min_count ) ) * ( $max_font - $min_font );
}
$font_size = round( $font_size, 1 );
$output .= sprintf(
'<a href="%s" class="tag-link tag-link-%d" style="font-size: %spx;" title="%d yazıda kullanıldı" rel="tag">%s</a>',
esc_url( $tag_link ),
(int) $tag->term_id,
$font_size,
(int) $count,
esc_html( $tag->name )
);
}
$output .= '</div>';
return $output;
}
Bu fonksiyon, etiketin sitedeki toplam kullanım sayısını ($tag->count) baz alarak 12px ile 28px arasında bir font boyutu hesaplıyor. Matematiksel olarak linear interpolation kullanıyoruz.
Shortcode ile Kullanım
Bazen belirli sayfalara veya özel konumlara manuel olarak etiket bulutu eklemek isteyebilirsiniz. Bunun için bir shortcode oluşturalım:
// functions.php
function tag_cloud_shortcode( $atts ) {
$atts = shortcode_atts(
array(
'post_id' => null,
'min_font' => 12,
'max_font' => 28,
'taxonomy' => 'post_tag',
),
$atts,
'etiket_bulutu'
);
$post_id = $atts['post_id'] ? (int) $atts['post_id'] : get_the_ID();
$terms = wp_get_post_terms( $post_id, $atts['taxonomy'] );
if ( is_wp_error( $terms ) || empty( $terms ) ) {
return '<p class="no-tags">Bu yazı için etiket bulunmuyor.</p>';
}
$output = '<div class="shortcode-tag-cloud">';
foreach ( $terms as $term ) {
$term_link = get_term_link( $term );
if ( is_wp_error( $term_link ) ) {
continue;
}
$output .= '<a href="' . esc_url( $term_link ) . '" class="sc-tag-link">';
$output .= esc_html( $term->name );
$output .= ' <sup class="tag-count">(' . (int) $term->count . ')</sup>';
$output .= '</a>';
}
$output .= '</div>';
return $output;
}
add_shortcode( 'etiket_bulutu', 'tag_cloud_shortcode' );
Artık herhangi bir yazı veya sayfada [etiket_bulutu] yazarak etiket bulutunu gösterebilirsiniz. [etiket_bulutu post_id="42" taxonomy="category"] şeklinde parametreler de geçebilirsiniz. Üstelik bu shortcode kategoriler dahil herhangi bir taxonomy ile çalışıyor.
CSS ile Stil Verme
Fonksiyonları yazdık ama görsel taraf da önemli. Stilleri functions.php üzerinden inline olarak veya ayrı bir stylesheet olarak ekleyebiliriz. Küçük projeler için inline yaklaşım pratik:
// functions.php
function tag_cloud_inline_styles() {
$css = '
.post-tag-cloud {
margin: 30px 0 20px;
padding: 20px;
background: #f8f9fa;
border-left: 4px solid #0073aa;
border-radius: 4px;
line-height: 2.2;
}
.post-tag-cloud .tag-cloud-title {
display: block;
font-weight: 700;
font-size: 14px;
text-transform: uppercase;
letter-spacing: 0.5px;
color: #555;
margin-bottom: 10px;
}
.post-tag-cloud a.tag-link,
.post-tag-cloud a.sc-tag-link {
display: inline-block;
margin: 4px 6px;
padding: 4px 12px;
background: #fff;
border: 1px solid #ddd;
border-radius: 20px;
color: #0073aa;
text-decoration: none;
transition: all 0.2s ease;
}
.post-tag-cloud a.tag-link:hover,
.post-tag-cloud a.sc-tag-link:hover {
background: #0073aa;
color: #fff;
border-color: #0073aa;
}
.tag-count {
font-size: 10px;
color: #999;
}
';
wp_add_inline_style( 'style', $css );
}
add_action( 'wp_enqueue_scripts', 'tag_cloud_inline_styles' );
wp_add_inline_style() fonksiyonu, stillerinizi mevcut tema stiline bağlı olarak ekler. 'style' yerine kendi tema stylesheet handle’ınızı kullanın.
Cache Desteği ile Performans Optimizasyonu
500+ yazılık bir sitede her sayfa yüklemesinde veritabanından etiketleri çekmek gereksiz yük oluşturur. Transient API ile cache ekleyelim:
// functions.php
function my_cached_tag_cloud( $post_id = null ) {
if ( ! $post_id ) {
$post_id = get_the_ID();
}
// Cache key oluştur
$cache_key = 'post_tag_cloud_' . (int) $post_id;
// Önce cache'e bak
$cached = get_transient( $cache_key );
if ( false !== $cached ) {
return $cached;
}
// Cache yoksa hesapla
$tags = get_the_tags( $post_id );
if ( ! $tags || is_wp_error( $tags ) ) {
return '';
}
$output = '<div class="post-tag-cloud cached">';
foreach ( $tags as $tag ) {
$tag_link = get_tag_link( $tag->term_id );
$output .= '<a href="' . esc_url( $tag_link ) . '" class="tag-link" rel="tag">';
$output .= esc_html( $tag->name );
$output .= '</a>';
}
$output .= '</div>';
// 24 saat cache'le
set_transient( $cache_key, $output, DAY_IN_SECONDS );
return $output;
}
// Yazı güncellenince cache'i temizle
function clear_tag_cloud_cache( $post_id ) {
delete_transient( 'post_tag_cloud_' . (int) $post_id );
}
add_action( 'save_post', 'clear_tag_cloud_cache' );
add_action( 'set_object_terms', function( $object_id ) {
delete_transient( 'post_tag_cloud_' . (int) $object_id );
});
Bu yapıda etiket bulutu ilk kez oluşturulduğunda 24 saat boyunca cache’leniyor. Yazı güncellendiğinde veya etiket değiştirildiğinde cache otomatik temizleniyor. Performans açısından ciddi fark yaratır.
İlgili Etiketlere Göre Yazı Önerisi Sistemi
Etiket bulutunu bir adım ileri taşıyalım. Mevcut yazının etiketlerine göre benzer yazıları listeleyen bir sistem kuralım. Bu, kullanıcı etkileşimini ciddi artırır:
// functions.php
function related_posts_by_tags( $post_id = null, $limit = 5 ) {
if ( ! $post_id ) {
$post_id = get_the_ID();
}
$tags = wp_get_post_tags( $post_id, array( 'fields' => 'ids' ) );
if ( empty( $tags ) ) {
return '';
}
$cache_key = 'related_posts_' . $post_id;
$cached = get_transient( $cache_key );
if ( false !== $cached ) {
return $cached;
}
$related_query = new WP_Query( array(
'tag__in' => $tags,
'post__not_in' => array( $post_id ),
'posts_per_page' => (int) $limit,
'orderby' => 'rand',
'post_status' => 'publish',
'ignore_sticky_posts' => true,
'no_found_rows' => true, // Performans için
) );
if ( ! $related_query->have_posts() ) {
return '';
}
$output = '<div class="related-posts-by-tags">';
$output .= '<h3 class="related-title">Benzer Yazılar</h3>';
$output .= '<ul class="related-posts-list">';
while ( $related_query->have_posts() ) {
$related_query->the_post();
$output .= '<li>';
$output .= '<a href="' . esc_url( get_permalink() ) . '">';
$output .= esc_html( get_the_title() );
$output .= '</a>';
$output .= ' <span class="related-date">' . get_the_date( 'd.m.Y' ) . '</span>';
$output .= '</li>';
}
wp_reset_postdata();
$output .= '</ul></div>';
set_transient( $cache_key, $output, 12 * HOUR_IN_SECONDS );
return $output;
}
// Bunu da the_content hook'una ekle
add_filter( 'the_content', function( $content ) {
if ( is_single() && in_the_loop() && is_main_query() && get_post_type() === 'post' ) {
$content .= my_cached_tag_cloud();
$content .= related_posts_by_tags();
}
return $content;
} );
no_found_rows => true parametresi önemli. WordPress’in toplam sayfa sayısını hesaplamamasını sağlıyor, bu da gereksiz bir COUNT() sorgusu yapılmaması anlamına geliyor.
Custom Post Type Desteği
Pek çok site sadece standart yazı tipiyle çalışmıyor. Portfolyo, ürün, kurs gibi custom post type’larınız varsa bunlara da özel taxonomy desteği ekleyebilirsiniz:
// functions.php
function universal_term_cloud( $post_id = null, $taxonomies = null ) {
if ( ! $post_id ) {
$post_id = get_the_ID();
}
$post_type = get_post_type( $post_id );
// Varsayılan taxonomy haritası
$default_taxonomies = array(
'post' => array( 'post_tag' ),
'portfolio' => array( 'portfolio_tag', 'portfolio_category' ),
'product' => array( 'product_tag' ),
'course' => array( 'course_tag', 'difficulty' ),
);
if ( null === $taxonomies ) {
$taxonomies = isset( $default_taxonomies[ $post_type ] )
? $default_taxonomies[ $post_type ]
: array( 'post_tag' );
}
$all_terms = array();
foreach ( $taxonomies as $taxonomy ) {
$terms = wp_get_post_terms( $post_id, $taxonomy );
if ( ! is_wp_error( $terms ) && ! empty( $terms ) ) {
$all_terms = array_merge( $all_terms, $terms );
}
}
if ( empty( $all_terms ) ) {
return '';
}
$output = '<div class="universal-term-cloud">';
foreach ( $all_terms as $term ) {
$term_link = get_term_link( $term );
if ( is_wp_error( $term_link ) ) {
continue;
}
$taxonomy_label = get_taxonomy( $term->taxonomy )->labels->singular_name;
$output .= sprintf(
'<a href="%s" class="term-link tax-%s" data-taxonomy="%s" title="%s kategorisinden">%s</a>',
esc_url( $term_link ),
esc_attr( $term->taxonomy ),
esc_attr( $term->taxonomy ),
esc_attr( $taxonomy_label ),
esc_html( $term->name )
);
}
$output .= '</div>';
return $output;
}
Bu fonksiyon, hangi post type’ta olduğunuzu algılıyor ve o post type’a uygun taxonomy’leri otomatik seçiyor. WooCommerce ürünleri için product_tag, portfolyo için portfolio_tag gibi.
Admin Paneli: Toplu Etiket İstatistikleri
Son olarak, admin panelinde etiket kullanım istatistiklerini gösteren küçük bir araç ekleyelim. Bu, içerik stratejinizi şekillendirmenize yardım eder:
// functions.php
function tag_statistics_dashboard_widget() {
$tags = get_tags( array(
'orderby' => 'count',
'order' => 'DESC',
'number' => 10,
'hide_empty' => false,
) );
if ( empty( $tags ) ) {
echo '<p>Henüz etiket yok.</p>';
return;
}
echo '<ul style="margin:0; padding:0; list-style:none;">';
foreach ( $tags as $tag ) {
$edit_link = get_edit_term_link( $tag->term_id, 'post_tag' );
$bar_width = ( $tag->count / $tags[0]->count ) * 100;
printf(
'<li style="margin-bottom:10px;">
<a href="%s" style="font-weight:600; color:#0073aa;">%s</a>
<span style="float:right; color:#666; font-size:12px;">%d yazı</span>
<div style="background:#e0e0e0; height:4px; border-radius:2px; margin-top:4px;">
<div style="background:#0073aa; width:%d%%; height:4px; border-radius:2px;"></div>
</div>
</li>',
esc_url( $edit_link ),
esc_html( $tag->name ),
(int) $tag->count,
(int) $bar_width
);
}
echo '</ul>';
}
function register_tag_stats_widget() {
wp_add_dashboard_widget(
'tag_statistics_widget',
'En Çok Kullanılan Etiketler (Top 10)',
'tag_statistics_dashboard_widget'
);
}
add_action( 'wp_dashboard_setup', 'register_tag_stats_widget' );
Bu kod, WordPress dashboard’unuza “En Çok Kullanılan Etiketler” widget’ı ekler. Her etiketin kaç yazıda kullanıldığını görmek, hangi konularda daha fazla içerik üretmeniz gerektiğini anlamanıza yardım eder.
Sık Yapılan Hatalar
Etiket bulutu uygulamalarında karşılaşılan yaygın sorunları listeleyelim:
in_the_loop()kontrolü yapmamak: Hook’u her yerde çalıştırırsınız, sidebar ve footer’da da görünürwp_reset_postdata()unutmak: Custom WP_Query sonrası global$postdeğişkeni bozulur, büyük sorunlara yol açar- Cache key çakışması: Farklı post type’lar için aynı cache key formatını kullanmak karışıklık yaratır, key’e post type ekleyin
- Taxonomy doğrulaması yapmamak:
wp_get_post_terms()çağrısından önce taxonomy’nin var olup olmadığını kontrol edin - XSS açıkları: Kullanıcıdan gelen verileri
esc_html()veesc_url()ile temizlemeden çıktılamak güvenlik riski oluşturur
Sonuç
functions.php üzerinden kurulan etiket bulutu sistemi, hem kullanıcı deneyimini hem de SEO’yu doğrudan etkiler. Ziyaretçiler ilgili içeriklere kolayca ulaşırken, arama motorları da içerikler arasındaki ilişkileri daha iyi anlıyor.
Bu yazıda ele aldığımız yapıyı özetleyecek olursak:
- Temel etiket fonksiyonu: Her yazının etiketlerini alıp HTML döndürür
the_contenthook: Otomatik ekleme için en temiz yöntem- Ağırlıklı bulutu: Font boyutunu kullanım sıklığına göre ayarlar
- Shortcode: Esnek ve elle kontrol edilebilir ekleme
- Transient cache: Performansı korur
- İlgili yazılar: Etiketlerden yararlanarak kullanıcı etkileşimini artırır
- Dashboard widget: İçerik stratejinize veri sağlar
Projenizin büyüklüğüne göre bu parçaları birleştirebilir veya sadece ihtiyacınız olanı alabilirsiniz. Küçük bir blog için sadece temel fonksiyon ve the_content hook yeterli olabilir. Büyük bir içerik sitesi için cache, ilgili yazılar ve dashboard widget’ı birlikte kullanmak mantıklı.
Son bir not: Bu kodları functions.php‘ye eklemeden önce mutlaka bir child theme kullanın. Ana temanın güncellemesi fonksiyonlarınızı silecektir.
