WordPress Heartbeat API’yi Kontrol Altına Alma

WordPress siteniz yavaşlıyorsa ve sunucu kaynaklarınız gereksiz yere tükeniyorsa, suçlu çoğu zaman fark etmediğiniz bir yerden geliyor: Heartbeat API. Bu mekanizma, WordPress’in arka planda sürekli sunucunuzla “konuşmasını” sağlıyor. Peki bu konuşma ne zaman zararlı hale gelir ve nasıl kontrol altına alırsınız? Gelin, functions.php üzerinden yapabileceğiniz her şeyi adım adım inceleyelim.

WordPress Heartbeat API Nedir?

WordPress 3.6 ile hayatımıza giren Heartbeat API, tarayıcı ile sunucu arasında düzenli aralıklarla AJAX istekleri göndererek bazı özelliklerin çalışmasını sağlar. Bu özellikler şunlardır:

  • Otomatik taslak kaydetme: Yazı yazarken içeriğiniz kaybolmasın diye arka planda kaydeder
  • Çoklu kullanıcı kilitleme: Aynı yazıyı iki kişi düzenlemesin diye kilit mekanizması
  • Oturum süresi uyarısı: “Oturumunuz sona eriyor” bildirimleri
  • WooCommerce stok güncellemeleri: Gerçek zamanlı stok takibi

Teknik olarak baktığımızda, bu API /wp-admin/admin-ajax.php üzerinden POST istekleri gönderiyor. Varsayılan ayarlarda bu istek her 15 ila 60 saniyede bir tekrarlanıyor. Şimdi düşünün: Aynı anda 50 kullanıcı WordPress admin panelinde açık tutuyorsa, sunucunuz dakikada onlarca gereksiz istek işliyor demektir.

Paylaşımlı hosting kullanıyorsanız veya düşük kaynaklı bir VPS üzerindeyseniz, bu durum ciddi performans sorunlarına yol açar. WooCommerce kurulu sitelerde heartbeat aktivitesi çok daha yoğun olabiliyor.

Sorunun Gerçek Boyutu

Bir müşteri sitesinde şunu yaşadım: WooCommerce mağazası, günde 200-300 sipariş alan orta ölçekli bir site. Sunucu kaynak kullanımı sürekli yüksek, MySQL bağlantıları zaman zaman max_connections limitine dayanıyor. New Relic ile analiz yaptığımızda, gün içindeki AJAX isteklerinin yaklaşık %35’inin sadece Heartbeat kaynaklı olduğunu gördük.

Çözüm basitti: Heartbeat’i tamamen kapatmak değil, kontrollü şekilde yönetmek. İşte bu yazıda anlatacağım da tam olarak bu.

Temel Yaklaşımlar

Heartbeat API’yi yönetmek için üç farklı strateji var:

  • Tamamen devre dışı bırakmak: En agresif yöntem, bazı WordPress özelliklerini kırar
  • Belirli sayfalarda devre dışı bırakmak: Önerilen yaklaşım, hassas dengeyi korur
  • Frekansı azaltmak: Heartbeat çalışmaya devam eder ama daha seyrek istek atar

Şimdi bu stratejilerin her birini kod örnekleriyle görelim.

functions.php’ye Ekleme Yapma Rehberi

Tüm bu kodları wp-content/themes/temaniz/functions.php dosyasına ekleyeceksiniz. Eğer child theme kullanıyorsanız (ki her zaman kullanmanızı öneririm), child theme’nin functions.php dosyasına ekleyin. Değişiklik yapmadan önce yedek almayı unutmayın.

# functions.php'yi düzenlemeden önce yedekleyin
cp /var/www/html/wp-content/themes/yourtheme/functions.php 
   /var/www/html/wp-content/themes/yourtheme/functions.php.bak

# Dosyayı açın
nano /var/www/html/wp-content/themes/yourtheme/functions.php

Heartbeat’i Tamamen Devre Dışı Bırakma

En basit ama en sert yöntemden başlayalım. Bunu yaparsanız otomatik taslak kaydetme ve çoklu düzenleme kilidi gibi özellikler çalışmaz.

<?php
// Heartbeat API'yi tamamen devre dışı bırak
add_action('init', function() {
    wp_deregister_script('heartbeat');
}, 1);

Bu yöntem çok kaba. Sadece heartbeat’in neden olduğu sorunları test etmek için geçici olarak kullanın. Üretim ortamında bu kadar agresif olmaya gerek yok.

Sadece Ön Yüzde Devre Dışı Bırakma

Ziyaretçilerin gördüğü sayfalarda heartbeat çalışmamalı, bu kesin. Sadece admin panelinde ve yazı editöründe aktif olması yeterli.

<?php
// Sadece ön yüzde heartbeat'i kapat
add_action('init', function() {
    if (!is_admin()) {
        wp_deregister_script('heartbeat');
    }
}, 1);

Bu kod sitenizin ön yüzünde heartbeat’i tamamen kapatırken, WordPress yönetim panelinde çalışmaya devam etmesine izin verir. Çoğu site için bu kadar bile büyük bir performans artışı sağlar. Özellikle blog ve içerik siteleri için bu ayar yeterlidir.

Sayfa Bazlı Hassas Kontrol

Daha gelişmiş bir yaklaşım: Heartbeat’i hangi admin sayfalarında çalıştırmak istediğinizi belirleyin. Yazı editörü dışındaki tüm admin sayfalarında kapatabilirsiniz.

<?php
// Heartbeat'i sadece post edit sayfasında aktif tut
add_action('init', function() {
    global $pagenow;
    
    // Ön yüzde her zaman kapat
    if (!is_admin()) {
        wp_deregister_script('heartbeat');
        return;
    }
    
    // Admin'de sadece belirli sayfalarda aktif bırak
    $allowed_pages = [
        'post.php',        // Yazı düzenleme
        'post-new.php',    // Yeni yazı oluşturma
    ];
    
    if (!in_array($pagenow, $allowed_pages)) {
        wp_deregister_script('heartbeat');
    }
}, 1);

Bu yaklaşım çok daha akıllıca. Örneğin WooCommerce sipariş listesinde, medya kütüphanesinde, eklenti listesinde heartbeat’e gerek yok. Sadece gerçekten ihtiyaç duyulan yerlerde çalıştırın.

Heartbeat Frekansını Azaltma

Heartbeat’i kapatmak istemiyorsunuz ama daha seyrek çalıştırmak istiyorsunuz. İşte burada heartbeat_settings filtresi devreye giriyor.

<?php
// Heartbeat frekansını azalt
add_filter('heartbeat_settings', function($settings) {
    // Interval değeri saniye cinsinden (min: 15, max: 120)
    $settings['interval'] = 60; // Varsayılan 15-60 arası, biz 60'a çekiyoruz
    return $settings;
});

Interval değeri için bilmeniz gerekenler:

  • 15: Minimum değer, en sık kontrol
  • 60: Varsayılan maksimum değer
  • 120: Maksimum değer, en seyrek kontrol (bazı kaynaklarda 300’e kadar çıkılabileceği belirtilse de resmi destek 120’ye kadar)

Eğer WooCommerce kullanıyorsanız ve gerçek zamanlı stok takibi önemliyse, bu değeri çok yüksek tutmayın. 60 saniye genellikle iyi bir denge noktasıdır.

Kapsamlı Heartbeat Yönetim Fonksiyonu

Şimdiye kadar anlattıklarımı tek bir fonksiyonda birleştirelim. Bu, production’da kullanabileceğiniz, bakımı kolay bir yapı:

<?php
/**
 * WordPress Heartbeat API Optimizasyonu
 * 
 * Bu fonksiyon heartbeat'i sayfa bazlı yönetir:
 * - Ön yüzde tamamen kapalı
 * - Admin'de sadece editör sayfalarında aktif
 * - Aktif olduğu yerlerde frekans azaltılmış
 */
function optimize_heartbeat_api() {
    global $pagenow;
    
    // 1. Ön yüzde tamamen kapat
    if (!is_admin()) {
        wp_deregister_script('heartbeat');
        return;
    }
    
    // 2. Login sayfasında kapat
    if (in_array($pagenow, ['wp-login.php'])) {
        wp_deregister_script('heartbeat');
        return;
    }
    
    // 3. Heartbeat'e ihtiyaç duymayan admin sayfaları
    $disable_on_pages = [
        'upload.php',           // Medya kütüphanesi
        'plugins.php',          // Eklentiler
        'themes.php',           // Temalar
        'users.php',            // Kullanıcılar
        'tools.php',            // Araçlar
        'options-general.php',  // Genel ayarlar
        'edit-comments.php',    // Yorumlar
        'edit.php',             // Yazı/sayfa listesi (editör değil, liste)
    ];
    
    if (in_array($pagenow, $disable_on_pages)) {
        wp_deregister_script('heartbeat');
        return;
    }
    
    // 4. Aktif kaldığı yerlerde frekansı optimize et
    add_filter('heartbeat_settings', function($settings) {
        $settings['interval'] = 60; // 15 yerine 60 saniye
        return $settings;
    });
}
add_action('init', 'optimize_heartbeat_api', 1);

Bu yapıyı birkaç farklı müşteri sitesinde uyguladık. Ortalama olarak admin-ajax.php üzerindeki yük yaklaşık %60-70 oranında azalıyor.

WooCommerce İçin Özel Ayarlar

WooCommerce mağazanız varsa biraz daha dikkatli olmanız gerekiyor. WooCommerce bazı işlemler için heartbeat’e bağımlı. Sipariş yönetimi ve stok takibi bunu kullanıyor.

<?php
/**
 * WooCommerce uyumlu Heartbeat optimizasyonu
 */
function woocommerce_compatible_heartbeat() {
    global $pagenow;
    
    if (!is_admin()) {
        wp_deregister_script('heartbeat');
        return;
    }
    
    // WooCommerce sayfalarını tespit et
    $current_page = isset($_GET['page']) ? sanitize_text_field($_GET['page']) : '';
    $post_type = isset($_GET['post_type']) ? sanitize_text_field($_GET['post_type']) : '';
    
    // WooCommerce sipariş ve ürün düzenleme sayfaları
    $woo_needs_heartbeat = (
        $pagenow === 'post.php' ||
        $pagenow === 'post-new.php' ||
        ($pagenow === 'edit.php' && $post_type === 'shop_order') ||
        strpos($current_page, 'woocommerce') !== false
    );
    
    if (!$woo_needs_heartbeat) {
        wp_deregister_script('heartbeat');
        return;
    }
    
    // WooCommerce sayfalarında frekansı biraz daha agresif tut
    // ama yine de varsayılandan az olsun
    add_filter('heartbeat_settings', function($settings) {
        $settings['interval'] = 45;
        return $settings;
    });
}
add_action('init', 'woocommerce_compatible_heartbeat', 1);

Kullanıcı Rolüne Göre Heartbeat Yönetimi

Bir adım daha ileri gidelim: Kimi kullanıcıların heartbeat’e gerçekten ihtiyacı var? Editörler ve yazarlar evet, ama sadece okuma yetkisi olan bir abone neden heartbeat kullansın?

<?php
/**
 * Kullanici rolune gore heartbeat yonetimi
 */
function role_based_heartbeat() {
    // Ön yüzde her zaman kapat
    if (!is_admin()) {
        wp_deregister_script('heartbeat');
        return;
    }
    
    // Kullanıcı giriş yapmamışsa kapat
    if (!is_user_logged_in()) {
        wp_deregister_script('heartbeat');
        return;
    }
    
    $current_user = wp_get_current_user();
    
    // Heartbeat'e ihtiyaç duymayan roller
    $low_priority_roles = ['subscriber', 'customer'];
    
    // Kullanıcının rollerinden herhangi biri düşük öncelikli mi?
    $user_roles = (array) $current_user->roles;
    $has_low_priority_role = !empty(array_intersect($user_roles, $low_priority_roles));
    
    if ($has_low_priority_role) {
        wp_deregister_script('heartbeat');
        return;
    }
    
    // Yönetici ve editörler için optimize edilmiş frekans
    if (in_array('administrator', $user_roles)) {
        // Admin için biraz daha sık - gerçek zamanlı takip önemli olabilir
        add_filter('heartbeat_settings', function($settings) {
            $settings['interval'] = 30;
            return $settings;
        });
    } else {
        // Diğer roller için daha seyrek
        add_filter('heartbeat_settings', function($settings) {
            $settings['interval'] = 60;
            return $settings;
        });
    }
}
add_action('init', 'role_based_heartbeat', 1);

Etkinliği Test Etme

Değişikliklerinizin çalışıp çalışmadığını doğrulamak için birkaç yöntem:

Birinci yöntem, tarayıcı geliştirici araçlarıyla test:

  • Chrome/Firefox’ta F12 tuşuna basın
  • Network sekmesine gidin
  • Filtre kutusuna admin-ajax yazın
  • Sayfada bekleyin ve gelen istekleri gözlemleyin

Eğer heartbeat kapatılmışsa hiç istek görmemelisiniz. Eğer sadece frekans azaltılmışsa, istekler arasındaki sürenin arttığını göreceksiniz.

İkinci yöntem, sunucu log analizi:

# Apache için admin-ajax.php isteklerini say
grep "admin-ajax.php" /var/log/apache2/access.log | 
  grep "heartbeat" | 
  wc -l

# Nginx için
grep "admin-ajax.php" /var/log/nginx/access.log | 
  awk '{print $1}' | 
  sort | uniq -c | sort -rn | head -20

# Gerçek zamanlı izleme
tail -f /var/log/nginx/access.log | grep "admin-ajax"

Üçüncü yöntem, MySQL sorgu sayısını izleme:

# MySQL slow query log'u aktif edin
mysql -u root -p -e "SET GLOBAL slow_query_log = 'ON';"
mysql -u root -p -e "SET GLOBAL long_query_time = 1;"

# Heartbeat kaynaklı sorguları izleyin
mysqladmin -u root -p processlist | grep -i "heartbeat"

Tüm Kodları Bir Arada Kullanma

Yukarıda anlattığım tüm yaklaşımları gerçek dünya için birleştirdiğimde ortaya şu çıkıyor:

<?php
/**
 * Heartbeat API Master Controller
 * 
 * Kurulum: functions.php dosyasına ekleyin
 * Uyumluluk: WordPress 5.0+, WooCommerce 5.0+
 */

// Konfigürasyon - ihtiyacınıza gore degistirin
define('HEARTBEAT_FRONTEND_DISABLE', true);   // Ön yüzde kapat
define('HEARTBEAT_INTERVAL_ADMIN', 60);        // Admin için interval (saniye)
define('HEARTBEAT_INTERVAL_EDITOR', 30);       // Editör sayfası için interval

function master_heartbeat_controller() {
    global $pagenow;
    
    // Ön yüzde kapat
    if (defined('HEARTBEAT_FRONTEND_DISABLE') && 
        HEARTBEAT_FRONTEND_DISABLE && 
        !is_admin()) {
        wp_deregister_script('heartbeat');
        return;
    }
    
    if (!is_admin()) return;
    
    // Editör sayfaları - heartbeat aktif, optimized interval
    $editor_pages = ['post.php', 'post-new.php'];
    
    if (in_array($pagenow, $editor_pages)) {
        add_filter('heartbeat_settings', function($settings) {
            $settings['interval'] = HEARTBEAT_INTERVAL_EDITOR;
            return $settings;
        });
        return; // Bu sayfalarda aktif bırak
    }
    
    // WooCommerce sipariş sayfaları - aktif bırak
    $post_type = isset($_GET['post_type']) ? sanitize_text_field($_GET['post_type']) : '';
    if ($pagenow === 'edit.php' && $post_type === 'shop_order') {
        add_filter('heartbeat_settings', function($settings) {
            $settings['interval'] = HEARTBEAT_INTERVAL_ADMIN;
            return $settings;
        });
        return;
    }
    
    // Diğer tüm admin sayfaları - kapat
    wp_deregister_script('heartbeat');
}
add_action('init', 'master_heartbeat_controller', 1);

// Heartbeat aktifken bile gereksiz veri göndermesini engelle
add_filter('heartbeat_received', function($response, $data) {
    // Sadece gerekli verilere izin ver
    $allowed_keys = ['wp-auth-check', 'wp-refresh-post-lock', 'wp-check-locked-posts'];
    
    foreach ($data as $key => $value) {
        if (!in_array($key, $allowed_keys)) {
            unset($response[$key]);
        }
    }
    
    return $response;
}, 10, 2);

Dikkat Edilmesi Gereken Noktalar

Heartbeat API’yi kapatmak ya da kısıtlamak bazı sonuçlar doğurabilir. Bunlara hazırlıklı olun:

  • Otomatik kaydetme çalışmaz: Editör dışındaki sayfalarda heartbeat kapatılınca otomatik taslak kaydetme de durur. Bu genellikle sorun değildir çünkü liste sayfalarında düzenleme yapmazsınız.
  • Çoklu düzenleme uyarısı kaybolur: İki admin aynı yazıyı düzenlemeye çalıştığında uyarı gelmeyebilir. Küçük ekipler için sorun değil ama büyük editorial ekiplerinde dikkat edin.
  • WooCommerce bildirimler: Bazı WooCommerce gerçek zamanlı bildirimleri heartbeat üzerinden çalışır. Kapatırsanız bu bildirimler gecikebilir.
  • Üçüncü parti eklentiler: Bazı eklentiler heartbeat’i kendi iletişimleri için kullanır. Test ortamında mutlaka doğrulayın.

Değişiklik yaptıktan sonra en az 48 saat izleme yapın. Özellikle editörlük yapan kullanıcılardan geri bildirim alın.

Performans Kazanımı Ne Kadar Olur?

Kesin rakamlar vermek zor çünkü site trafiğine, eş zamanlı admin kullanıcı sayısına ve sunucu kapasitesine göre değişiyor. Ancak genel gözlemlerim şu yönde:

  • Düşük trafikli blog sitelerde heartbeat optimizasyonu çok fark yaratmaz. Kaynak kullanımı zaten düşüktür.
  • Orta ölçekli WooCommerce mağazalarda (günde 100+ sipariş) admin-ajax.php yükü %40-60 oranında azalır.
  • Çok sayıda admin kullanıcısı olan büyük medya sitelerinde sunucu CPU kullanımında gözle görülür düşüş yaşanır.
  • Paylaşımlı hostingde hemen fark edersiniz: Sayfa yüklenme süreleri kısalır.

Önemli bir not: Bu optimizasyon tek başına bir sihir değil. Caching, CDN, veritabanı optimizasyonu gibi diğer tekniklerle birlikte uygulandığında gerçek anlamda etkili olur. Heartbeat optimizasyonunu daha büyük bir performans stratejisinin parçası olarak görün.

Sonuç

WordPress Heartbeat API, yanlış yönetildiğinde sessiz bir kaynak katili olabilir. Doğru yönetildiğinde ise önemli bir performans kazanımı sağlayabilirsiniz. Burada anlattığım yaklaşımı özetleyeyim:

  • Ön yüzde heartbeat’i tamamen kapatın, buna ihtiyaç yok
  • Admin panelinde sadece gerçekten ihtiyaç duyulan sayfalarda (editör, WooCommerce) aktif bırakın
  • Aktif kaldığı yerlerde interval değerini makul bir seviyeye çekin (30-60 saniye)
  • Kullanıcı rollerine göre farklılaştırma yapın
  • Değişikliklerinizi mutlaka test ortamında deneyin, ardından production’a alın

Bu işlemlerin tamamını bir eklenti üzerinden de yapabilirsiniz (Heartbeat Control gibi eklentiler var), ancak küçük bir functions.php kodu yeterliyken ekstra eklenti yüklemek benim tercihim değil. Kod basit, bakımı kolay ve tam kontrol sizde.

Siteye özgü ihtiyaçlarınıza göre bu kodları uyarlayın. Her WordPress kurulumu farklıdır ve tek bir çözüm herkese uymaz. Deneyip gözlemleyin, gerekirse ayarlayın.

Bir yanıt yazın

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