FUTIA
OTOMASYON8 dk okuma

WordPress Cron ile Otomatik İçerik Yayınlama: Gerçek Kod Rehberi

WordPress'te cron job kullanarak içerik üretimini tamamen otomatikleştirdim. Gerçek kod örnekleri ve 6 yıllık deneyimimden pratik hatalarla.

WordPress Cron ile Otomatik İçerik Yayınlama: Gerçek Kod Rehberi
Miraç Eroğlu
15 Mayıs 2026

Son 2 yılda 40'tan fazla WordPress sitesine cron tabanlı otomasyon kurdum. İtalyanmutfagi.com için 618 tarif, kamupersonelhaber.com için günlük 50+ ilan, doktorbul.com için 79.000 profil, hepsi cron job'larla yayınlandı. Bu yazıda WordPress'in kendi cron sistemini nasıl kullanacağını, gerçek production kodlarıyla anlatacağım. Teorik bilgi değil, benim 2 yıldır production'da çalışan, hata aldığım ve düzelttiğim sistemler.

Çoğu rehber wp_schedule_event() fonksiyonunu gösterip geçiyor. Ben sana gerçek senaryoları göstereceğim: API'den veri çekip içerik oluşturma, hata yönetimi, rate limiting, duplicate kontrolü, memory optimizasyonu. Hollanda'dan Türk markalarına servis verirken karşılaştığım her sorunu ve çözümü burada bulacaksın.

WordPress Cron Sistemi Nasıl Çalışır

WordPress'in wp-cron.php dosyası gerçek bir cron job değil, pseudo-cron. Her sayfa ziyaretinde tetiklenir, zamanı gelen görevleri çalıştırır. Bu yöntem shared hosting'de işe yarar ama ciddi dezavantajları var.

Ben FUTIA projelerinde iki yöntem kullanıyorum:

1. Düşük trafikli siteler (günde 500 ziyaret altı): WordPress'in kendi wp-cron'u 2. Yüksek trafikli veya kritik görevler: Sistem cron + wp-cron.php devre dışı

İkinci yöntemde wp-config.php'ye şunu ekliyorum:

define('DISABLE_WP_CRON', true);

Sonra sunucu crontab'ına gerçek bir görev ekliyorum:

/15 * curl https://siteadi.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1

Bu kod her 15 dakikada wp-cron.php'yi tetikler. Sayfa yükünden bağımsız, güvenilir çalışır. Kamupersonelhaber.com'da bu yöntemi kullanıyorum çünkü ilan.gov.tr API'sinden günde 3 kez veri çekmem gerekiyor, ziyaretçi trafiğine bağlı kalamam.

Temel Cron Job Oluşturma

İlk örnek: Her gün saat 09:00'da bir fonksiyon çalıştırmak. Tema functions.php veya custom plugin:

function futia_schedule_daily_task() { if (!wp_next_scheduled('futia_daily_content')) { wp_schedule_event(strtotime('09:00:00'), 'daily', 'futia_daily_content'); } } add_action('wp', 'futia_schedule_daily_task');

function futia_run_daily_content() { // İçerik üretme kodun buraya error_log('FUTIA: Daily content task ran at ' . current_time('mysql')); } add_action('futia_daily_content', 'futia_run_daily_content');

Bu kod wp hook'una bağlanır, her sayfa yüklemesinde wp_next_scheduled() kontrol eder. Eğer görev zaten planlanmışsa duplicate oluşturmaz.

Ama dikkat: strtotime('09:00:00') sunucu saatine göre çalışır. WordPress'in kendi saat dilimini kullanmak için:

$timezone = wp_timezone(); $next_run = new DateTime('tomorrow 09:00', $timezone); wp_schedule_event($next_run->getTimestamp(), 'daily', 'futia_daily_content');

Ben bunu doktorbul.com'da öğrendim. İlk kurulumda sunucu UTC'deydi, görev gece 02:00'da çalışıyordu. Türkiye saatine göre 05:00. Yukarıdaki kod sorunu çözdü.

API'den Veri Çekip İçerik Oluşturma

Gerçek bir senaryo: Kamupersonelhaber.com için ilan.gov.tr API'sinden her 8 saatte bir veri çekip WordPress post olarak yayınlıyorum. İşte production kodunun basitleştirilmiş hali:

function futia_schedule_ilan_fetch() { if (!wp_next_scheduled('futia_fetch_ilanlar')) { wp_schedule_event(time(), 'futia_8hours', 'futia_fetch_ilanlar'); } } add_action('wp', 'futia_schedule_ilan_fetch');

function futia_custom_cron_schedules($schedules) { $schedules['futia_8hours'] = array( 'interval' => 28800, 'display' => 'Her 8 Saatte' ); return $schedules; } add_filter('cron_schedules', 'futia_custom_cron_schedules');

function futia_fetch_and_create_ilanlar() { $api_url = 'https://ilan.gov.tr/api/v1/ilanlar'; $response = wp_remote_get($api_url, array( 'timeout' => 30, 'headers' => array( 'Authorization' => 'Bearer ' . get_option('ilan_api_key') ) ));

if (is_wp_error($response)) { error_log('FUTIA: API error - ' . $response->get_error_message()); return; }

$body = json_decode(wp_remote_retrieve_body($response), true);

if (empty($body['data'])) { return; }

foreach ($body['data'] as $ilan) { // Duplicate kontrolü $existing = get_posts(array( 'post_type' => 'ilan', 'meta_key' => 'ilan_id', 'meta_value' => $ilan['id'], 'posts_per_page' => 1 ));

if (!empty($existing)) { continue; }

// Post oluştur $post_id = wp_insert_post(array( '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']); } } } add_action('futia_fetch_ilanlar', 'futia_fetch_and_create_ilanlar');

Bu kodda dikkat edilmesi gereken noktalar:

1. wp_remote_get() timeout 30 saniye. API yavaşsa PHP timeout vermez. 2. Duplicate kontrolü meta_key ile. Aynı ilan_id varsa atla. 3. sanitize_text_field() ve wp_kses_post() güvenlik için zorunlu. 4. error_log() ile hata takibi. Ben Sentry kullanıyorum ama başlangıç için log yeterli.

Bu sistem kamupersonelhaber.com'da 8 aydır çalışıyor, günde ortalama 50 ilan yayınlıyor. Hiç manuel müdahale etmedim.

Memory ve Performance Optimizasyonu

İtalyanmutfagi.com için 618 tarif oluştururken ilk versiyonda memory hatası aldım. Tek cron job'da 618 post oluşturmaya çalıştım, 256MB PHP memory limit yetmedi.

Çözüm: Batch processing. Her çalıştırmada 20 post oluştur, sonraki 20'yi bir sonraki çalıştırmada yap:

function futia_batch_recipe_creation() { $batch_size = 20; $processed = get_option('futia_processed_recipes', 0); $total = 618;

if ($processed >= $total) { return; // Tüm tarifler oluşturuldu }

$recipes = futia_get_recipe_data($processed, $batch_size);

foreach ($recipes as $recipe) { $post_id = wp_insert_post(array( 'post_title' => $recipe['title'], 'post_content' => $recipe['content'], 'post_status' => 'publish', 'post_type' => 'recipe' ));

if ($post_id) { // Schema.org Recipe markup update_post_meta($post_id, 'recipe_schema', json_encode(array( '@context' => 'https://schema.org/', '@type' => 'Recipe', 'name' => $recipe['title'], 'recipeIngredient' => $recipe['ingredients'], 'recipeInstructions' => $recipe['instructions'] ))); } }

update_option('futia_processed_recipes', $processed + $batch_size); } add_action('futia_batch_recipes', 'futia_batch_recipe_creation');

Bu yaklaşımla 618 tarif 31 çalıştırmada (618/20) oluştu. Her 15 dakikada bir batch, toplam 7.75 saat. Memory kullanımı hiç 128MB'ı geçmedi.

Bir diğer optimizasyon: wp_suspend_cache_addition(true). Büyük veri işlerken WordPress object cache'i şişirir, bu da memory kullanır:

function futia_batch_recipe_creation() { wp_suspend_cache_addition(true);

// Batch işlemlerin

wp_suspend_cache_addition(false); }

Rate Limiting ve API Kurallarına Uyum

Doktorbul.com'da 79.000 doktor profili oluştururken harici bir API kullandım. API'nin rate limit'i dakikada 60 istek. Ben bunu aşarsam IP ban yerdim.

Çözüm: wp_remote_get() sonrası sleep() eklemek:

function futia_fetch_doctor_profiles() { $batch_size = 50; // Dakikada 60 limit, güvenli marj $doctors = futia_get_pending_doctors($batch_size);

foreach ($doctors as $doctor) { $response = wp_remote_get('https://api.example.com/doctors/' . $doctor['id']);

if (!is_wp_error($response)) { $data = json_decode(wp_remote_retrieve_body($response), true); futia_create_doctor_post($data); }

sleep(1); // 1 saniye bekle, dakikada max 60 istek } }

Bu kod her istek arasında 1 saniye bekler. 50 profil için 50 saniye sürer ama API kurallarını ihlal etmez. Ben bunu 79.000 profil için 1580 batch'te çalıştırdım, hiç sorun yaşamadım.

Başka bir yöntem: Transient API ile rate limit takibi:

function futia_api_call_with_limit($url) { $calls = get_transient('futia_api_calls');

if ($calls === false) { $calls = 0; }

if ($calls >= 60) { error_log('FUTIA: Rate limit reached, waiting'); return false; }

$response = wp_remote_get($url); set_transient('futia_api_calls', $calls + 1, 60); // 60 saniye TTL

return $response; }

Transient 60 saniye sonra sıfırlanır, yeni bir döngü başlar. Bu yöntem sleep()'ten daha verimli çünkü gereksiz bekleme yok.

Hata Yönetimi ve Logging

Production'da her şey ters gidebilir. API down olur, database connection kesilir, PHP timeout verir. Ben her cron job'a try-catch ve detaylı logging ekliyorum:

function futia_safe_cron_execution() { try { $start_time = microtime(true);

// Ana işlemin futia_fetch_and_create_content();

$end_time = microtime(true); $duration = round($end_time - $start_time, 2);

error_log(sprintf( 'FUTIA: Cron completed in %s seconds, memory: %s MB', $duration, round(memory_get_peak_usage(true) / 1024 / 1024, 2) ));

} catch (Exception $e) { error_log('FUTIA: Cron failed - ' . $e->getMessage());

// Slack veya email bildirimi gönder wp_mail( 'info@futia.net', 'Cron Job Failed', $e->getMessage() . "\n\n" . $e->getTraceAsString() ); } } add_action('futia_daily_content', 'futia_safe_cron_execution');

Bu kod her çalıştırmada süre ve memory kullanımını logluyor. Hata olursa email gönderiyor. Ben production'da Slack webhook kullanıyorum ama wp_mail() başlangıç için yeterli.

Bir diğer önemli nokta: Cron job'ın çalışıp çalışmadığını kontrol etmek. Ben wp_get_scheduled_event() ile yapıyorum:

function futia_check_cron_health() { $event = wp_get_scheduled_event('futia_daily_content');

if (!$event) { error_log('FUTIA: Cron job is not scheduled!'); // Yeniden planla wp_schedule_event(time(), 'daily', 'futia_daily_content'); } } add_action('admin_init', 'futia_check_cron_health');

Bu kod admin paneline her girişte cron job'ın planlanmış olup olmadığını kontrol eder. Silinmişse yeniden oluşturur.

Claude API ile İçerik Üretimi Entegrasyonu

Memuratamalari.com'da Claude Haiku API kullanarak günlük analiz yazıları üretiyorum. Cron job her gün saat 08:00'da tetikleniyor, o günün haberlerini Claude'a gönderiyor, gelen analizi post olarak yayınlıyor:

function futia_generate_daily_analysis() { $today_news = futia_get_today_news(); // O günün haberleri

$prompt = "Aşağıdaki memur haberlerini analiz et, genel trendleri özetle:\n\n"; foreach ($today_news as $news) { $prompt .= "- " . $news['title'] . "\n"; }

$response = wp_remote_post('https://api.anthropic.com/v1/messages', array( 'timeout' => 60, 'headers' => array( 'x-api-key' => get_option('claude_api_key'), 'anthropic-version' => '2023-06-01', 'content-type' => 'application/json' ), 'body' => json_encode(array( 'model' => 'claude-3-haiku-20240307', 'max_tokens' => 1024, 'messages' => array( array( 'role' => 'user', 'content' => $prompt ) ) )) ));

if (is_wp_error($response)) { error_log('FUTIA: Claude API error - ' . $response->get_error_message()); return; }

$body = json_decode(wp_remote_retrieve_body($response), true); $analysis = $body['content'][0]['text'];

wp_insert_post(array( 'post_title' => 'Günlük Analiz: ' . date('d.m.Y'), 'post_content' => wpautop($analysis), 'post_status' => 'publish', 'post_type' => 'post', 'post_category' => array(get_cat_ID('Analizler')) )); } add_action('futia_daily_analysis', 'futia_generate_daily_analysis');

Bu sistem 6 aydır çalışıyor, günlük 40.400 organik aramaya ulaşmasında büyük rolü var. Claude Haiku hızlı ve ucuz (1M token $0.25), günlük maliyet $0.02 civarı.

Debugging ve Test Etme

Cron job'ları test ederken wp-cron.php'nin çalışmasını beklemek zaman kaybı. Ben do_action() ile manuel tetikliyorum:

// functions.php veya custom plugin if (isset($_GET['test_cron']) && current_user_can('manage_options')) { do_action('futia_daily_content'); die('Cron manually triggered'); }

Sonra tarayıcıda https://siteadi.com/?test_cron adresine gidiyorum, cron job anında çalışıyor. Production'da bu kodu kaldırıyorum tabii.

Bir diğer yöntem: WP-CLI kullanmak. SSH erişimin varsa:

wp cron event run futia_daily_content

Bu komut cron job'ı anında çalıştırır, çıktısını terminal'de gösterir. Ben sunucu tarafında test ederken bunu kullanıyorum.

Cron job'ların listesini görmek için:

wp cron event list

Bu komut tüm planlanmış görevleri, bir sonraki çalışma zamanlarını gösterir. Debugging için çok kullanışlı.

Gerçek Production Senaryoları

Diolivo.com.tr'de CartBounty sepet kurtarma sistemini cron job'la entegre ettim. Her 2 saatte bir terk edilmiş sepetleri kontrol ediyor, 24 saat geçmişse email gönderiyor:

function futia_abandoned_cart_reminder() { global $wpdb;

$carts = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}cartbounty WHERE cart_time < DATE_SUB(NOW(), INTERVAL 24 HOUR) AND email_sent = 0 LIMIT 50" );

foreach ($carts as $cart) { $user_data = maybe_unserialize($cart->cart_contents);

wp_mail( $cart->email, 'Sepetinizde ürünler kaldı', futia_generate_cart_email($user_data) );

$wpdb->update( $wpdb->prefix . 'cartbounty', array('email_sent' => 1), array('id' => $cart->id) ); } } add_action('futia_cart_reminder', 'futia_abandoned_cart_reminder');

Bu sistem 6 ayda %340 trafik büyümesine katkı sağladı. Sepet kurtarma oranı %18, her email ortalama 47 TL gelir getiriyor.

Futia.net'te 3 ayda 2000+ video üretmek için multi-step cron sistemi kurdum:

1. Her gün saat 01:00: Script'leri üret (Claude API) 2. Her gün saat 03:00: Seslendirme yap (ElevenLabs API) 3. Her gün saat 05:00: Video render et (Remotion) 4. Her gün saat 07:00: YouTube'a yükle

Her adım ayrı bir cron job, bir önceki adımın çıktısını kullanıyor. Bu pipeline 3 aydır kesintisiz çalışıyor.

Bu tür otomasyonları kurmak istiyorsan benimle iletişime geçebilirsin. WhatsApp: +90 532 491 17 05 veya info@futia.net. WordPress + cron + API entegrasyonları konusunda 2 yıllık production deneyimim var, senin projen için de özel çözüm geliştirebilirim.

Sıkça Sorulanlar

WordPress cron job'ları gerçek cron job'lardan nasıl farklı?

WordPress wp-cron.php pseudo-cron sistemi kullanır, sayfa ziyaretlerinde tetiklenir. Gerçek cron job'lar sunucu tarafında zamanlanır, ziyaretçi trafiğinden bağımsız çalışır. Yüksek trafikli veya kritik görevler için wp-config.php'de DISABLE_WP_CRON true yapıp sunucu crontab'ına gerçek görev eklemeni öneririm. Ben FUTIA projelerinde trafik 500/gün üzerindeyse bu yöntemi kullanıyorum.

Cron job'ım çalışmıyor, nasıl debug ederim?

İlk olarak wp_get_scheduled_event() ile görevin planlanmış olup olmadığını kontrol et. Sonra error_log() ekleyerek çalışma anını logla. Manuel test için do_action() kullan veya WP-CLI'da 'wp cron event run gorev_adi' komutunu çalıştır. Ben production'da her cron job'a try-catch ve email bildirimi ekliyorum, hata olduğunda anında haberdar oluyorum. Sentry gibi error tracking servisleri de çok işe yarıyor.

Büyük veri işlerken memory hatası alıyorum, çözüm nedir?

Batch processing kullan. Tek seferde tüm veriyi işlemek yerine 20-50'lik gruplar halinde işle, her batch'te get_option() ile progress takip et. wp_suspend_cache_addition(true) ile WordPress object cache'ini devre dışı bırak. PHP memory_limit'i artırabilirsin ama asıl çözüm batch'lemek. Ben italyanmutfagi.com'da 618 tarifi 20'şerli batch'lerle oluşturdum, hiç memory sorunu yaşamadım.

API rate limit'ini aşmamak için ne yapmalıyım?

Her API isteği arasına sleep(1) ekle veya Transient API ile çağrı sayısını takip et. Ben doktorbul.com'da 79.000 profil için dakikada 50 istek limiti koydum, her istek sonrası 1 saniye bekledim. Transient yöntemi daha verimli: set_transient('api_calls', $count, 60) ile 60 saniye TTL, limit dolunca false dön. Bu yaklaşım sleep()'ten daha hızlı çünkü gereksiz bekleme yok.

Claude API'yi cron job'a nasıl entegre ederim?

wp_remote_post() ile Anthropic API'sine istek at, timeout'u 60 saniye yap çünkü yanıt geç gelebilir. Model olarak claude-3-haiku-20240307 kullan, hızlı ve ucuz (1M token $0.25). Prompt'u dinamik oluştur, response'u parse edip wp_insert_post() ile yayınla. Ben memuratamalari.com'da günlük analiz üretiyorum, 6 aydır sorunsuz çalışıyor. API key'i get_option() ile yönet, hardcode etme.

YAZAR HAKKINDA
Miraç Eroğlu

Hacettepe mezunu, 6 yıldır sosyal medya, 2 yıldır AI otomasyon.

Daha fazla bilgi →

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.