WordPress Cron ile Otomatik İçerik Yayınlama: Kod Örnekleri ve Uygulama
WordPress'te zamanlanmış görevler için WP-Cron kullanıyorsanız, içerik otomasyonunun %80'ini yanlış yapıyorsunuz. İşte gerçek kod örnekleri ve çalışan bir sistem.

WordPress'te her gün saat 09:00'da otomatik içerik yayınlamak istiyorsunuz. "Schedule Post" eklentisi kuruyorsunuz, çalışmıyor. WP-Cron ayarlarıyla uğraşıyorsunuz, tutarsız sonuçlar alıyorsunuz. Sorun basit: WordPress'in cron sistemi gerçek bir cron değil, ziyaretçi trafiğine bağlı pseudo-cron. Ben 2019'da bir haber sitesi için saatte 4 içerik yayınlayan sistem kurarken aynı hatayı yaptım. 3 gün boyunca içerikler rastgele saatlerde yayınlandı, bazıları hiç yayınlanmadı. Çözüm, WordPress'in varsayılan mantığını bypass etmek ve gerçek sunucu cron'u ile entegre çalışan bir yapı kurmaktı. Bu yazıda size WordPress'te zamanlanmış içerik yayınlamanın doğru mimarisini, çalışan kod örneklerini ve FUTIA'da kamupersonelhaber.com için kurduğumuz günlük 50+ ilan sisteminin teknik detaylarını anlatacağım. Teorik bilgi değil, production'da çalışan kod göreceksiniz. ## WordPress WP-Cron Neden Güvenilmez? WordPress'in wp-cron.php dosyası her sayfa yüklendiğinde tetiklenir. Yani sitenize kimse girmezse, zamanlanmış görevler çalışmaz. Bu mantık küçük bloglar için sorun değil ama otomatik içerik sistemleri için felaket. Kamupersonelhaber.com'da şöyle bir durum yaşadık: Gece 02:00'da ilan.gov.tr API'sinden çekilen yeni ilanlar yayınlanmalıydı. Site trafiği gece düşük olduğu için bazı ilanlar sabah 08:00'e kadar bekleyebiliyordu. Google'ın gözünde içerik tazeliği gecikmesi demek, indexleme önceliği kaybı demek. WP-Cron'un ikinci sorunu eşzamanlılık. Aynı anda 10 kişi siteyi ziyaret ederse, wp-cron.php 10 kez tetiklenir. Her biri "zamanı gelmiş görevler var mı?" diye kontrol eder. Veritabanı kilitleri, duplicate işlemler, sunucu yükü. 500 gönderi yayınlayan bir sitede bu kaos yaratır. Çözüm: WP-Cron'u devre dışı bırakıp gerçek sunucu cron'u kullanmak. wp-config.php dosyanıza şunu ekleyin: ```php define('DISABLE_WP_CRON', true);
*/15 * * * * wget -q -O - https://yourdomain.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1
/15 * curl -s https://yourdomain.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1
*/10 * * * * cd /home/username/public_html && wp cron event run --due-now >/dev/null 2>&1
// functions.php veya özel plugin içinde function futia_schedule_content_sync() { if (!wp_next_scheduled('futia_daily_content_import')) { wp_schedule_event(strtotime('02:00:00'), 'daily', 'futia_daily_content_import'); } } add_action('wp', 'futia_schedule_content_sync'); function futia_import_and_publish_content() { // API'den veri çek $response = wp_remote_get('https://ilan.gov.tr/api/v1/ilanlar?limit=50'); if (is_wp_error($response)) { error_log('FUTIA Content Import: API hatası - '. $response->get_error_message()); return; } $data = json_decode(wp_remote_retrieve_body($response), true); if (empty($data['ilanlar'])) { return; } foreach ($data['ilanlar'] as $ilan) { // Duplicate kontrol $existing = get_posts([ 'post_type' => 'ilan', 'meta_key' => 'ilan_id', 'meta_value' => $ilan['id'], 'posts_per_page' => 1 ]); if (!empty($existing)) { continue; // Zaten var, geç } // Yeni gönderi oluştur $post_id = wp_insert_post([ 'post_title' => sanitize_text_field($ilan['baslik']), 'post_content' => wp_kses_post($ilan['icerik']), 'post_status' => 'publish', 'post_type' => 'ilan', 'post_author' => 1 ]); if ($post_id) { update_post_meta($post_id, 'ilan_id', $ilan['id']); update_post_meta($post_id, 'basvuru_tarihi', $ilan['son_tarih']); // Kategori ata wp_set_object_terms($post_id, $ilan['kategori_slug'], 'ilan_kategorisi'); } } // Log tut update_option('futia_last_import', current_time('mysql')); update_option('futia_last_import_count', count($data['ilanlar'])); } add_action('futia_daily_content_import', 'futia_import_and_publish_content');
function futia_log_cron_event($message, $type = 'info') { $log_file = WP_CONTENT_DIR. '/futia-cron.log'; $timestamp = current_time('Y-m-d H:i:s'); $log_entry = "[{$timestamp}] [{$type}] {$message}\n"; file_put_contents($log_file, $log_entry, FILE_APPEND); // Kritik hatalar için e-posta if ($type === 'error') { wp_mail('info@futia.net', 'Cron Hatası', $message); }
} // Kullanımı:
futia_log_cron_event('İçerik import başladı', 'info');
futia_log_cron_event('API bağlantı hatası: timeout', 'error');
function futia_bulk_insert_posts($posts_data) { global $wpdb; // Hook'ları kapat remove_action('save_post', 'wp_transition_post_status', 10); remove_action('wp_insert_post', 'wp_insert_post', 10); // Yoast SEO, Rank Math gibi eklentilerin hook'larını da kapat remove_all_actions('save_post'); foreach ($posts_data as $post) { // Manuel SQL insert (daha hızlı) $wpdb->insert( $wpdb->posts, [ 'post_author' => 1, 'post_date' => current_time('mysql'), 'post_date_gmt' => current_time('mysql', 1), 'post_content' => $post['content'], 'post_title' => $post['title'], 'post_status' => 'publish', 'post_name' => sanitize_title($post['title']), 'post_type' => 'post' ], ['%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s'] ); $post_id = $wpdb->insert_id; // Meta veriler if (!empty($post['meta'])) { foreach ($post['meta'] as $key => $value) { add_post_meta($post_id, $key, $value, true); } } } // Cache'i temizle wp_cache_flush(); }
function futia_schedule_staggered_posts($posts_data, $start_date, $posts_per_day) { $current_date = strtotime($start_date); $daily_count = 0; foreach ($posts_data as $index => $post) { if ($daily_count >= $posts_per_day) { $current_date = strtotime('+1 day', $current_date); $daily_count = 0; } // Her gönderi için rastgele saat (09:00 - 18:00 arası) $random_hour = rand(9, 18); $random_minute = rand(0, 59); $publish_time = date('Y-m-d H:i:s', strtotime("+{$random_hour} hours +{$random_minute} minutes", $current_date)); wp_insert_post([ 'post_title' => $post['title'], 'post_content' => $post['content'], 'post_status' => 'publish', 'post_date' => $publish_time, 'post_date_gmt' => get_gmt_from_date($publish_time) ]); $daily_count++; }
} // Kullanımı:
futia_schedule_staggered_posts($tarifler, '2024-01-01', 10);
function futia_cron_status_page() { add_menu_page( 'Cron Durumu', 'Cron İzleme', 'manage_options', 'futia-cron-status', 'futia_render_cron_status' ); } add_action('admin_menu', 'futia_cron_status_page'); function futia_render_cron_status() { $cron_jobs = _get_cron_array(); $now = time(); echo '
Zamanlanmış Görevler
'; echo '| Görev | Sonraki Çalışma | Durum |
|---|---|---|
| {$hook} | "; echo "{$next_run} | "; echo "{$status} | "; echo "
Son İçerik İmport
'; echo 'Tarih: '. $last_import. '
'; echo 'İçerik Sayısı: '. $last_count. '
'; echo '2. Yeni ilanlar tespit edilir (son 24 saatteki)
3. Her ilan için duplicate kontrol yapılır (ilan_id meta key)
4. Yeni ilanlar "ilan" custom post type olarak yayınlanır
5. İlan kategorileri otomatik atanır (eğitim, sağlık, güvenlik vs.)
6. Son başvuru tarihi meta olarak kaydedilir
7. Başvuru tarihi geçen ilanlar otomatik arşivlenir (ayrı bir cron) Sistem 6 aydır çalışıyor. Toplam 9.200+ ilan yayınlandı, hiç manuel müdahale gerekmedi. Aylık organik arama trafiği 40.400'e ulaştı. Teknik detay: İlan içerikleri Claude Haiku API ile zenginleştirilir. Ham API verisi 150-200 kelime, biz bunu 600-800 kelimeye çıkarıyoruz. İlan başına maliyet 0.02 TL. ```php
function futia_enrich_ilan_content($raw_content, $title) { $api_key = get_option('anthropic_api_key'); $prompt = "Bu kamu ilanını detaylandır, başvuru şartlarını açıkla, görev tanımını genişlet. Orijinal bilgileri koru, ekstra context ekle.\n\nİlan: {$title}\n\nİçerik: {$raw_content}"; $response = wp_remote_post('https://api.anthropic.com/v1/messages', [ 'headers' => [ 'x-api-key' => $api_key, 'anthropic-version' => '2023-06-01', 'content-type' => 'application/json' ], 'body' => json_encode([ 'model' => 'claude-3-haiku-20240307', 'max_tokens' => 1024, 'messages' => [[ 'role' => 'user', 'content' => $prompt ]] ]), 'timeout' => 30 ]); if (is_wp_error($response)) { return $raw_content; // Hata varsa orijinal içeriği kullan } $data = json_decode(wp_remote_retrieve_body($response), true); return $data['content'][0]['text']?? $raw_content;
}
composer require woocommerce/action-scheduler
require_once 'vendor/autoload.php'; function futia_schedule_with_action_scheduler() { if (function_exists('as_schedule_recurring_action')) { as_schedule_recurring_action( strtotime('tomorrow 2am'), DAY_IN_SECONDS, 'futia_daily_import', [], 'futia-content' ); }
}
add_action('init', 'futia_schedule_with_action_scheduler'); function futia_process_scheduled_import() { // İçerik import kodu
}
add_action('futia_daily_import', 'futia_process_scheduled_import');
- Veritabanı tabanlı, trafik bağımsız
- Otomatik retry mekanizması
- Admin panelinde görsel takip
- Paralel işlem desteği Dezavantajı: Ekstra veritabanı tabloları (actionscheduler_actions, actionscheduler_logs). Büyük sitelerde temizlik gerektirir. Ben küçük projelerde WP-Cron + sunucu cron kullanıyorum, büyük projelerde Action Scheduler tercih ediyorum. WordPress'te cron ile otomatik içerik yayınlamak teknik bir iş ama doğru kurulduğunda sisteminiz kendi kendine çalışır. Kamupersonelhaber.com'daki gibi günde 50+ içerik yayınlayan bir yapı kurmak isterseniz, benimle iletişime geçebilirsiniz. info@futia.net adresine yazın. FUTIA olarak site kurulumundan API entegrasyonuna, cron yapılandırmasından aylık bakıma kadar tüm süreci yönetiyoruz.
Sıkça Sorulanlar
WP-Cron'u devre dışı bırakırsam mevcut zamanlanmış gönderilerim ne olur?
Mevcut zamanlanmış gönderileriniz etkilenmez, sadece tetiklenme mekanizması değişir. WP-Cron'u kapatıp sunucu cron'u kurduğunuzda, WordPress'in zamanlanmış gönderi sistemi aynı şekilde çalışmaya devam eder. Fark şu: Önceden ziyaretçi trafiğine bağlıyken, artık belirlediğiniz sabit aralıklarla (örneğin her 15 dakikada) kontrol edilir. Hatta daha güvenilir hale gelir çünkü düşük trafikli saatlerde bile zamanında yayınlanır.
Paylaşılan hosting'de (shared hosting) gerçek cron job kurabilir miyim?
Evet, çoğu paylaşımlı hosting sağlayıcısı cPanel veya Plesk üzerinden cron job tanımlama imkanı sunar. cPanel'de 'Cron Jobs' bölümüne girip komut ekleyebilirsiniz. Eğer SSH erişiminiz yoksa bile, web tabanlı cron servislerini (örneğin EasyCron, cron-job.org) kullanabilirsiniz. Bu servisler belirttiğiniz aralıklarla sitenizin wp-cron.php dosyasına HTTP isteği gönderir. Ücretsiz planları genellikle 5-15 dakikalık aralıklar için yeterli.
API'den çektiğim içeriklerde duplicate nasıl önlerim?
En güvenilir yöntem, API'den gelen her içerik için benzersiz bir ID'yi WordPress meta verisi olarak saklamaktır. Örneğin ilan.gov.tr'den gelen her ilanın bir 'ilan_id' değeri var. Yeni içerik eklemeden önce get_posts() ile bu meta değerini sorguluyorum. Eğer aynı ilan_id'ye sahip gönderi varsa, ekleme işlemini atlıyorum. Alternatif olarak post_title veya post_name üzerinden de kontrol yapılabilir ama bunlar değişebileceği için meta key yöntemi daha güvenli. 6 aydır kamupersonelhaber.com'da hiç duplicate oluşmadı.
Toplu içerik eklerken SEO eklentileri (Yoast, Rank Math) sorun çıkarır mı?
Evet, özellikle hook'ları devre dışı bırakarak toplu ekleme yapıyorsanız SEO eklentilerinin otomatik özellikleri (meta açıklama, schema, XML sitemap güncelleme) çalışmaz. Çözüm iki aşamalı: Önce ham içerikleri hızlıca ekleyin, sonra ayrı bir cron job ile SEO meta verilerini güncelleyin. Örneğin Yoast için wpseo_title, wpseo_metadesc gibi meta key'leri manuel doldurabilirsiniz. Ya da toplu ekleme sonrası Yoast'un kendi API'sini kullanarak meta verileri oluşturabilirsiniz. Doktorbul.com'da 79.000 profil eklerken bu yöntemi kullandık.
Cron işlemlerim çalışmıyor, nasıl debug ederim?
İlk adım: WordPress admin panelinde Tools > Site Health > Info > Scheduled Events bölümüne bakın, cron job'larınız listelenmiş mi kontrol edin. İkinci adım: Sunucu cron loglarını inceleyin (genellikle /var/log/cron veya cPanel'de Cron Job Logs). Üçüncü adım: wp-content klasörüne debug.log açın (wp-config.php'de WP_DEBUG_LOG true yapın) ve cron fonksiyonlarınıza error_log() ekleyin. Ben her cron işleminde başlangıç ve bitiş zamanını logluyorum. Eğer log'da hiçbir kayıt görmüyorsanız, cron job'unuz hiç tetiklenmiyor demektir, sunucu tarafı ayarlarını kontrol edin.
Bu yazıdaki tekniklerden birini uygulamak ister misiniz? Kısa bir form doldurun, 48 saat içinde ücretsiz ön inceleme raporu mailinize düşsün.