WordPress Yazılarına Okuma Süresi Ekleme
Okuyuculara “bu yazıyı okumak ne kadar sürer?” sorusunun cevabını vermek, kullanıcı deneyimi açısından küçük ama etkili bir detay. Medium, Dev.to gibi platformların standart hale getirdiği bu özelliği WordPress sitenize eklemek için eklenti kurmaya gerek yok. Birkaç satır PHP kodu ile bunu kendiniz halledebilirsiniz. Bu yazıda functions.php üzerinden okuma süresi hesaplama sistemini adım adım kuracağız, farklı senaryolara göre özelleştireceğiz ve performans açısından dikkat edilmesi gereken noktalara değineceğiz.
Temel Okuma Süresi Fonksiyonu
Önce en sade haliyle başlayalım. Ortalama bir yetişkin dakikada 200-250 kelime okur. Biz hesaplamalarımızda 200 kelimeyi baz alacağız, bu biraz daha gerçekçi bir süre verir.
// functions.php dosyanıza ekleyin
function get_reading_time( $post_id = null ) {
if ( ! $post_id ) {
$post_id = get_the_ID();
}
$content = get_post_field( 'post_content', $post_id );
$clean_content = wp_strip_all_tags( $content );
$word_count = str_word_count( $clean_content );
$reading_time = ceil( $word_count / 200 );
if ( $reading_time < 1 ) {
$reading_time = 1;
}
return $reading_time;
}
Bu fonksiyon size sadece sayıyı döndürür. Bunu template dosyalarınızda şöyle kullanabilirsiniz:
// single.php veya content.php içinde
$sure = get_reading_time( get_the_ID() );
echo '<span class="reading-time">' . $sure . ' dakika okuma süresi</span>';
Basit ve işlevsel. Ama gerçek dünyada işler biraz daha karmaşık. Şimdi bu fonksiyonu geliştirelim.
Daha Kapsamlı Bir Hesaplama Sistemi
Sadece kelime saymak yeterli değil çünkü içerik bazen görsel ağırlıklı olabilir, bazen kod blokları içerebilir. Aşağıdaki versiyon bunları da göz önünde bulunduruyor:
function get_advanced_reading_time( $post_id = null, $wpm = 200 ) {
if ( ! $post_id ) {
$post_id = get_the_ID();
}
$content = get_post_field( 'post_content', $post_id );
// Kod bloklarını çıkar (okuma süresine ekleme)
$content = preg_replace( '/<pre[^>]*>[sS]*?</pre>/i', '', $content );
$content = preg_replace( '/```[sS]*?```/', '', $content );
// HTML taglarını temizle
$clean_content = wp_strip_all_tags( $content );
// Kelime sayısı
$word_count = str_word_count( $clean_content );
// Görsel sayısı (her görsel 12 saniye olarak hesaplanır)
preg_match_all( '/<img[^>]+>/i', get_post_field( 'post_content', $post_id ), $images );
$image_count = count( $images[0] );
$image_time = $image_count * 12; // saniye cinsinden
// Toplam süreyi hesapla
$text_time_seconds = ( $word_count / $wpm ) * 60;
$total_seconds = $text_time_seconds + $image_time;
$total_minutes = ceil( $total_seconds / 60 );
if ( $total_minutes < 1 ) {
$total_minutes = 1;
}
return array(
'minutes' => $total_minutes,
'word_count' => $word_count,
'image_count' => $image_count,
);
}
Bu fonksiyon artık bir dizi döndürüyor. Kullanımı şöyle:
$reading_data = get_advanced_reading_time( get_the_ID() );
echo '<div class="post-meta-reading">';
echo '<span class="reading-time-icon">🕐</span>';
echo '<span>' . $reading_data['minutes'] . ' dk okuma</span>';
echo '<span class="word-count">(' . number_format( $reading_data['word_count'] ) . ' kelime)</span>';
echo '</div>';
Shortcode Olarak Kullanım
Bazen Gutenberg editöründe veya sayfa oluşturucularla çalışırken shortcode daha kullanışlı olabiliyor. Bunu da ekleyelim:
function reading_time_shortcode( $atts ) {
$atts = shortcode_atts(
array(
'post_id' => get_the_ID(),
'wpm' => 200,
'format' => 'full', // 'full' veya 'short'
'class' => 'reading-time',
),
$atts,
'reading_time'
);
$data = get_advanced_reading_time( $atts['post_id'], $atts['wpm'] );
if ( 'short' === $atts['format'] ) {
$output = $data['minutes'] . ' dk';
} else {
$output = $data['minutes'] . ' dakika okuma süresi';
}
return '<span class="' . esc_attr( $atts['class'] ) . '">' . esc_html( $output ) . '</span>';
}
add_shortcode( 'reading_time', 'reading_time_shortcode' );
Editörde şöyle kullanabilirsiniz:
[reading_time]
[reading_time format="short"]
[reading_time wpm="250" class="meta-reading-time"]
Otomatik Post Meta Olarak Kaydetme
Her sayfa yüklenişinde hesaplama yapmak yerine, yazı kaydedildiğinde okuma süresini post meta olarak depolayabilirsiniz. Bu özellikle yüksek trafikli sitelerde önemli bir performans kazanımı sağlar.
function save_reading_time_meta( $post_id ) {
// Otomatik kayıt sırasında çalışmasın
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
// Sadece yayınlanmış yazılar için çalış
if ( 'post' !== get_post_type( $post_id ) ) {
return;
}
// Kullanıcı yetkisi kontrolü
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return;
}
$reading_data = get_advanced_reading_time( $post_id );
update_post_meta( $post_id, '_reading_time_minutes', $reading_data['minutes'] );
update_post_meta( $post_id, '_reading_time_word_count', $reading_data['word_count'] );
}
add_action( 'save_post', 'save_reading_time_meta' );
// Meta'dan okuma süresini getiren yardımcı fonksiyon
function get_cached_reading_time( $post_id = null ) {
if ( ! $post_id ) {
$post_id = get_the_ID();
}
$cached = get_post_meta( $post_id, '_reading_time_minutes', true );
// Meta yoksa hesapla ve kaydet
if ( ! $cached ) {
$data = get_advanced_reading_time( $post_id );
$cached = $data['minutes'];
update_post_meta( $post_id, '_reading_time_minutes', $cached );
}
return (int) $cached;
}
Bu yaklaşımın avantajı şu: Yazı bir kez kaydedildiğinde hesaplama yapılır ve veritabanına yazılır. Sonraki her ziyarette sadece bir meta sorgusu yapılır, içerik tekrar parse edilmez. 1000 kişi aynı yazıyı okursa 1000 kez hesaplama yerine sadece 1 kez hesaplama yapılmış olur.
WP_Query ile Liste Sayfalarında Kullanım
Blog listesi, kategori arşivi veya anasayfada birden fazla yazı gösterirken okuma süresini de listelemek isteyebilirsiniz. Burada dikkat edilmesi gereken nokta, döngü içinde her yazı için ayrı sorgu yapmaktan kaçınmak:
// Archive veya index sayfaları için optimize edilmiş versiyon
function display_reading_time_in_loop() {
$post_id = get_the_ID();
// Önce cache'e bak
$reading_time = wp_cache_get( 'reading_time_' . $post_id, 'reading_times' );
if ( false === $reading_time ) {
$reading_time = get_cached_reading_time( $post_id );
// 1 saatlik cache
wp_cache_set( 'reading_time_' . $post_id, $reading_time, 'reading_times', 3600 );
}
return $reading_time;
}
// Template'de kullanım örneği
function reading_time_html( $post_id = null ) {
if ( ! $post_id ) {
$post_id = get_the_ID();
}
$minutes = get_cached_reading_time( $post_id );
$output = '<span class="reading-time" aria-label="Tahmini okuma süresi: ' . $minutes . ' dakika">';
$output .= '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="14" height="14" aria-hidden="true">';
$output .= '<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67V7z"/>';
$output .= '</svg>';
$output .= ' ' . $minutes . ' dk';
$output .= '</span>';
return $output;
}
Özel Post Type Desteği
Eğer sitenizde portfolio, course veya recipe gibi özel post type’larınız varsa bunları da sisteme dahil edebilirsiniz:
function register_reading_time_for_post_types() {
// Okuma süresi hesaplanacak post type'lar
$supported_post_types = apply_filters(
'reading_time_post_types',
array( 'post', 'page', 'course', 'portfolio' )
);
foreach ( $supported_post_types as $post_type ) {
add_action( 'save_post_' . $post_type, 'save_reading_time_meta' );
}
}
add_action( 'init', 'register_reading_time_for_post_types' );
apply_filters kullanmak burada iyi bir pratik. Başka bir eklenti veya tema kodu, kendi post type’ını bu listeye ekleyebilir:
// Başka bir dosyada veya çocuk temada
add_filter( 'reading_time_post_types', function( $types ) {
$types[] = 'product'; // WooCommerce ürünleri için
return $types;
} );
REST API Entegrasyonu
Headless WordPress veya mobil uygulama geliştiriyorsanız okuma süresini REST API yanıtlarına eklemek isteyebilirsiniz:
function add_reading_time_to_rest_api() {
$supported_types = array( 'post', 'page' );
foreach ( $supported_types as $post_type ) {
register_rest_field(
$post_type,
'reading_time',
array(
'get_callback' => function( $post_data ) {
return array(
'minutes' => get_cached_reading_time( $post_data['id'] ),
'word_count' => (int) get_post_meta( $post_data['id'], '_reading_time_word_count', true ),
);
},
'update_callback' => null,
'schema' => array(
'description' => 'Tahmini okuma süresi',
'type' => 'object',
),
)
);
}
}
add_action( 'rest_api_init', 'add_reading_time_to_rest_api' );
Artık /wp-json/wp/v2/posts/123 gibi bir istek yaptığınızda yanıt içinde reading_time alanı gelecek:
// API yanıtı örneği (JSON)
// "reading_time": {
// "minutes": 7,
// "word_count": 1450
// }
Toplu Güncelleme Scripti
Sistemi kurduğunuzda mevcut yazılarınızın meta değerleri boş olacak. Tüm eski yazılar için toplu güncelleme yapmak istiyorsanız bunu WP-CLI üzerinden çalıştırabilirsiniz. Önce fonksiyonu ekleyin:
function bulk_update_reading_times() {
// Sadece admin ekranında veya WP-CLI ile çalışsın
if ( ! is_admin() && ! ( defined( 'WP_CLI' ) && WP_CLI ) ) {
return;
}
$args = array(
'post_type' => array( 'post', 'page' ),
'post_status' => 'publish',
'posts_per_page' => -1,
'fields' => 'ids', // Sadece ID'leri çek, performans için
);
$post_ids = get_posts( $args );
$updated = 0;
foreach ( $post_ids as $post_id ) {
$data = get_advanced_reading_time( $post_id );
update_post_meta( $post_id, '_reading_time_minutes', $data['minutes'] );
update_post_meta( $post_id, '_reading_time_word_count', $data['word_count'] );
$updated++;
}
return $updated;
}
Sonra bunu WP-CLI ile tetikleyebilirsiniz:
# wp-cli.php veya özel WP-CLI komutu ile
wp eval 'echo bulk_update_reading_times() . " yazı güncellendi.";'
Büyük sitelerde bu işlem uzun sürebilir. 500’den fazla yazınız varsa posts_per_page yerine sayfalandırma yapmanızı öneririm:
// Batch işlem - 50'şer yazı günceller
wp eval '
$args = array(
"post_type" => "post",
"post_status" => "publish",
"posts_per_page" => 50,
"paged" => 1,
"fields" => "ids"
);
$posts = get_posts($args);
foreach($posts as $id) {
$d = get_advanced_reading_time($id);
update_post_meta($id, "_reading_time_minutes", $d["minutes"]);
}
echo count($posts) . " yazı güncellendi";
'
Gerçek Dünya Senaryoları ve İpuçları
Çok dilli siteler: WPML veya Polylang kullanıyorsanız her dil için ayrı okuma süresi meta’sı saklamanız gerekebilir. _reading_time_minutes_tr, _reading_time_minutes_en gibi dil kodu ekleyerek bunu yönetebilirsiniz. Türkçe kelimeler İngilizce’ye göre farklı uzunluklarda olabileceğinden WPM değerini dile göre ayarlamak da mantıklı olabilir.
ACF (Advanced Custom Fields) içerikleri: Eğer post content dışında ACF alanlarında da metin tutuyorsanız bunları hesaplamaya dahil etmek isteyebilirsiniz:
function get_reading_time_with_acf( $post_id ) {
$content = get_post_field( 'post_content', $post_id );
// ACF metin alanları varsa ekle
if ( function_exists( 'get_field' ) ) {
$acf_summary = get_field( 'post_summary', $post_id );
$acf_body = get_field( 'extra_content', $post_id );
if ( $acf_summary ) {
$content .= ' ' . $acf_summary;
}
if ( $acf_body ) {
$content .= ' ' . $acf_body;
}
}
$clean = wp_strip_all_tags( $content );
$words = str_word_count( $clean );
$minutes = ceil( $words / 200 );
return max( 1, $minutes );
}
Kategori bazlı WPM ayarı: Teknik yazılarda okuyucular daha yavaş ilerler. Örneğin “tutorial” kategorisindeki yazılar için 150 WPM daha gerçekçi bir değer olabilir:
function get_category_adjusted_reading_time( $post_id = null ) {
if ( ! $post_id ) {
$post_id = get_the_ID();
}
$wpm = 200; // Varsayılan
$categories = get_the_category( $post_id );
foreach ( $categories as $cat ) {
if ( 'tutorial' === $cat->slug || 'teknik' === $cat->slug ) {
$wpm = 150;
break;
}
if ( 'haber' === $cat->slug || 'duyuru' === $cat->slug ) {
$wpm = 250;
break;
}
}
$content = wp_strip_all_tags( get_post_field( 'post_content', $post_id ) );
$words = str_word_count( $content );
$minutes = ceil( $words / $wpm );
return max( 1, $minutes );
}
CSS ile Görsel Tasarım
Kodu ekledikten sonra şablonunuzun görünümüne uygun basit bir CSS ile güzel bir sonuç elde edebilirsiniz. Bu CSS’yi temanızın style.css dosyasına veya Görünüm > Özelleştir > Ek CSS bölümüne ekleyebilirsiniz:
/* Bu CSS'yi style.css veya wp_head hook'u ile ekleyin */
/*
.reading-time {
display: inline-flex;
align-items: center;
gap: 4px;
font-size: 0.85em;
color: #666;
font-weight: 500;
}
.reading-time svg {
fill: currentColor;
flex-shrink: 0;
}
.reading-time-badge {
background: #f0f4ff;
border: 1px solid #d0deff;
border-radius: 20px;
padding: 3px 10px;
color: #3a5bd9;
}
*/
Sık Karşılaşılan Sorunlar
str_word_count Türkçe karakter sorunu: PHP’nin str_word_count fonksiyonu bazı sunucu konfigürasyonlarında Türkçe karakterleri doğru saymayabilir. Güvenli bir alternatif:
function turkish_word_count( $text ) {
// HTML temizle
$text = wp_strip_all_tags( $text );
// Birden fazla boşluğu teke indir
$text = preg_replace( '/s+/', ' ', trim( $text ) );
if ( empty( $text ) ) {
return 0;
}
return count( explode( ' ', $text ) );
}
Bu fonksiyon str_word_count yerine explode kullandığı için Türkçe karakterlerde sorun çıkarmaz.
Revizyon yazılarına uygulanması: save_post hook’u revizyon kaydetmede de tetiklenir. Yukarıdaki save_reading_time_meta fonksiyonunda wp_is_post_revision kontrolü eklemek güvenli olur:
// save_reading_time_meta fonksiyonuna şunu ekleyin:
if ( wp_is_post_revision( $post_id ) ) {
return;
}
Sonuç
Okuma süresi göstermek için eklenti kurmak gereksiz bir yük. Birkaç satır functions.php kodu ile hem daha hafif hem de tam kontrol sizde olan bir çözüme sahip olabilirsiniz. Özetlemek gerekirse:
- Temel kullanım için
get_reading_time()fonksiyonu yeterli - Performans kritikse
save_posthook’u ile meta olarak kaydedin - Yüksek trafik için
wp_cache_set/getekleyin - Toplu güncelleme için WP-CLI’dan yararlanın
- Türkçe karakter için
str_word_countyerineexplodetabanlı fonksiyon kullanın - REST API entegrasyonu ile headless projelerde de kullanabilirsiniz
Kodu kendi temanıza göre uyarlayın, WPM değerini sitenizin hedef kitlesi ve içerik tipine göre ayarlayın. 200 WPM genel bir ortalama olsa da teknik içeriklerde 150, haber sitelerinde 250 daha gerçekçi sonuçlar verir.
