در وردپرس، انتخاب بین Transient و Option یکی از تصمیم‌های کلیدی معماری داده است که اثر مستقیم بر عملکرد، پایداری و مقیاس‌پذیری سایت دارد و اشتباه در آن می‌تواند به بدهی فنی پرهزینه تبدیل شود. Transient برای داده‌های موقت با انقضا طراحی شده و Option برای تنظیمات پایدار بدون انقضا، اما مرز این دو در پروژه‌های واقعی اغلب اشتباه گرفته می‌شود و به رفتار غیرقابل پیش‌بینی منجر می‌گردد. تفاوت Autoload، رفتار در Multisite و تعامل با Object Cache خارجی، لایه‌های پنهانی هستند که در تصمیم معماری باید لحاظ شوند و نادیده گرفتن آن‌ها، هزینه نگهداشت را چند برابر می‌کند. Transient در نبود Object Cache Persistent، به‌صورت پیش‌فرض در wp_options ذخیره می‌شود و همین موضوع می‌تواند wp_options را به یک منبع کندی تبدیل کند. تست Transient و Option در سه سطح ذخیره‌سازی، انقضا و رفتار کش انجام می‌شود و بدون آن، انتشار به تولید ریسک بالایی دارد. در این راهنما از اصول پایه تا استقرار تولیدی این دو مکانیزم را با نگاه مهندسی و کد عملی پوشش می‌دهیم.

در پروژه‌های واقعی، وقتی سایت با wp_options حجیم مواجه می‌شوم، ریشه مشکل تقریباً همیشه یک چیز است: Transientهایی که به Autoload اضافه شده‌اند. این راهنما از همان نقطه‌ای شروع می‌کند که تجربه می‌گوید بیشترین ارزش را دارد.

Transient و Option چیستند و چرا انتخاب بین آن‌ها مهم است؟

Option یک مکانیزم ذخیره‌سازی جفت کلید/مقدار در جدول wp_options است که برای داده‌های پایدار طراحی شده و انقضا ندارد. Transient یک مکانیزم مشابه است که در آن یک TTL (Time To Live) تعریف می‌شود و پس از انقضا، داده به‌صورت خودکار حذف می‌شود.

تفاوت اصلی در دو حوزه است: هدف استفاده و رفتار ذخیره‌سازی. Option برای تنظیمات سایت، API Key و داده‌های ثابت است. Transient برای کش نتایج سنگین، داده‌های خارجی موقت و نتیجه محاسبات پرهزینه.

پیش از ادامه، راهنمای Object Cache و کش آبجکت حرفه‌ای را مطالعه کنید. اگر با ساختار جدول wp_options آشنایی ندارید، راهنمای بهینه‌سازی دیتابیس وردپرس بدون حذف اطلاعات مهم نقطه شروع مناسبی است.

نشانه‌هایی که انتخاب اشتباه داشته‌اید

اگر Transientها هرگز پاک نمی‌شوند، اگر wp_options از چند مگابایت عبور کرده، اگر Autoload حجم بالایی دارد، یا اگر تنظیمات پایداری در Transient ذخیره کرده‌اید، احتمالاً انتخاب اشتباهی داشته‌اید.

ساختار ذخیره‌سازی در wp_options

هر دو مکانیزم، در نهایت در جدول wp_options ذخیره می‌شوند. ساختار جدول شامل option_id، option_name، option_value و autoload است.

SELECT option_name, LENGTH(option_value) AS size, autoload
FROM wp_options
WHERE option_name LIKE '%transient%'
ORDER BY size DESC
LIMIT 20;

این کوئری، بزرگ‌ترین Transientهای سایت را نشان می‌دهد و نقطه شروع مناسبی برای پاک‌سازی است.

کلید Transient و کلید Timeout

هر Transient در واقع دو رکورد در wp_options دارد:

  1. _transient_{name} که مقدار داده است.
  2. _transient_timeout_{name} که زمان انقضا را نگه می‌دارد.
SELECT option_name, autoload
FROM wp_options
WHERE option_name IN (
    '_transient_wpk_cache',
    '_transient_timeout_wpk_cache'
);

Autoload و اثر آن بر عملکرد

Option دارای پارامتر autoload است. اگر autoload = 'yes' باشد، وردپرس در هر بار بارگذاری صفحه، مقدار را از دیتابیس می‌خواند و در حافظه کش می‌کند.

این رفتار، برای Optionهای پرکاربرد مطلوب است اما در حجم بالا، به یکی از بزرگ‌ترین عوامل کندی تبدیل می‌شود.

SELECT SUM(LENGTH(option_value)) AS autoload_size
FROM wp_options
WHERE autoload = 'yes';

اگر این عدد از ۱ مگابایت عبور کند، باید Autoload را بازبینی کنید.

Transient و Autoload

Transient به‌صورت پیش‌فرض با autoload = 'no' ذخیره می‌شود. اما برخی Pluginها اشتباهاً Transient را با autoload = 'yes' ذخیره می‌کنند.

UPDATE wp_options
SET autoload = 'no'
WHERE option_name LIKE '%transient%' AND autoload = 'yes';

انقضا و TTL در Transient

انقضای Transient با پارامتر سوم تعیین می‌شود:

<?php
// ذخیره با انقضای ۱۵ دقیقه
set_transient( "wpk_api_response", $data, 15 * MINUTE_IN_SECONDS );

// بدون انقضا (معادل Option)
set_transient( "wpk_api_response", $data, 0 );

// خواندن
$data = get_transient( "wpk_api_response" );

// حذف دستی
delete_transient( "wpk_api_response" );

انتخاب TTL باید بر اساس الگوی تغییر داده باشد. اگر داده هر ساعت تغییر می‌کند، TTL ۳۰ دقیقه منطقی است. راهنمای Transients API در وردپرس را ببینید.

Transient بدون انقضا

استفاده از expiration = 0، Transient را به یک Option با نام متفاوت تبدیل می‌کند. این الگو در برخی Pluginها رایج است اما توصیه نمی‌شود، چون هدف Transient را از بین می‌برد.

تعامل Transient با Object Cache

اگر سایت از Object Cache Persistent مثل Redis یا Memcached استفاده کند، Transient در آن ذخیره می‌شود نه در wp_options. این تغییر، عملکرد را به‌شدت بهبود می‌دهد.

// بررسی محل ذخیره Transient
$cache_backend = wp_using_ext_object_cache() ? "Redis/Memcached" : "Database";
error_log( "Transient backend: " . $cache_backend );

در نبود Object Cache خارجی، Transient در wp_options ذخیره می‌شود و همین موضوع می‌تواند به حجم بالای جدول منجر شود.

مقایسه عملکرد

معیارTransient در DBTransient با Redis
زمان خواندن5-20ms0.5-2ms
زمان نوشتن10-30ms1-3ms
اثر بر wp_optionsبالاصفر
مقیاس‌پذیریمحدودبالا

کدام را برای چه داده‌ای انتخاب کنیم؟

قاعده تصمیم‌گیری:

  1. Option: تنظیمات پایدار، API Key، پیکربندی Plugin، داده‌هایی که تا زمان تغییر دستی باقی می‌مانند.
  2. Transient: کش نتایج کوئری سنگین، پاسخ API خارجی، محاسبات پرهزینه، لیست محصولات فیلترشده.
// درست: تنظیمات پایدار
update_option( "wpk_crm_api_key", "sk_live_..." );

// درست: کش موقت
set_transient( "wpk_top_products", $products, HOUR_IN_SECONDS );

// اشتباه: تنظیمات در Transient
set_transient( "wpk_crm_api_key", "sk_live_...", DAY_IN_SECONDS );

// اشتباه: کش موقت در Option
update_option( "wpk_top_products", $products );

معیار انتخاب در یک نگاه

سؤالOptionTransient
داده باید بعد از ۲۴ ساعت باقی بماند؟بلهخیر
داده قابل بازسازی است؟خیربله
داده در هر صفحه لازم است؟بلهخیر
داده پرهزینه برای بازسازی است؟خیربله

الگوهای حرفه‌ای استفاده ترکیبی

الگوی قدرتمند، ترکیب Transient با Fallback به Option است.

<?php
function wpk_get_exchange_rate() {
    $rate = get_transient( "wpk_usd_rate" );

    if ( false === $rate ) {
        $rate = wpk_fetch_rate_from_api();
        if ( $rate ) {
            set_transient( "wpk_usd_rate", $rate, HOUR_IN_SECONDS );
            update_option( "wpk_usd_rate_last_known", $rate );
        } else {
            $rate = get_option( "wpk_usd_rate_last_known", 0 );
        }
    }

    return $rate;
}

این الگو، هم کش را فعال می‌کند و هم در زمان قطعی API، آخرین مقدار معتبر را برمی‌گرداند.

الگوی Cache Stampede Prevention

در سایت‌های پربازدید، اگر Transient منقضی شود و صدها درخواست همزمان به API بزنند، بار سنگینی ایجاد می‌شود. راه‌حل، استفاده از یک قفل موقت است.

<?php
function wpk_get_expensive_data() {
    $data = get_transient( "wpk_data" );
    if ( false !== $data ) {
        return $data;
    }

    if ( ! get_transient( "wpk_data_lock" ) ) {
        set_transient( "wpk_data_lock", 1, 30 );
        $data = wpk_fetch_expensive_data();
        set_transient( "wpk_data", $data, HOUR_IN_SECONDS );
        delete_transient( "wpk_data_lock" );
        return $data;
    }

    return get_option( "wpk_data_fallback", array() );
}

Transient و Option در Multisite

در Multisite، Option در جدول wp_{blog_id}_options ذخیره می‌شود. برای Option سراسری، از get_site_option() استفاده کنید.

// Option سراسری (شبکه)
update_site_option( "wpk_network_setting", $value );

// Option سطح سایت
update_option( "wpk_site_setting", $value );

// Transient سطح سایت
set_transient( "wpk_cache", $data, HOUR_IN_SECONDS );

// Transient سراسری (شبکه)
set_site_transient( "wpk_network_cache", $data, HOUR_IN_SECONDS );

توصیه می‌کنم در Multisite، داده‌های تکراری بین سایت‌ها را در Site Transient نگه دارید. راهنمای راهنمای Multisite وردپرس را ببینید.

هماهنگی کش در Multisite

در Multisite، پاک کردن کش یک سایت، به‌طور خودکار کش سایت‌های دیگر را پاک نمی‌کند. توصیه می‌کنم برای داده‌های مشترک، از Site Transient استفاده کنید.

پاک‌سازی و مدیریت داده‌های منقضی

Transientهای منقضی به‌طور خودکار حذف نمی‌شوند مگر در زمان دسترسی. پاک‌سازی دوره‌ای ضروری است.

DELETE FROM wp_options
WHERE option_name LIKE '%_transient_timeout_%'
  AND option_value < UNIX_TIMESTAMP();

پس از حذف Timeoutها، داده‌های متناظر نیز باید پاک شوند.

اسکریپت پاک‌سازی حرفه‌ای

<?php
function wpk_cleanup_expired_transients() {
    global $wpdb;
    $timeouts = $wpdb->get_col(
        "SELECT option_name FROM {$wpdb->options}
         WHERE option_name LIKE '%_transient_timeout_%'
           AND option_value < UNIX_TIMESTAMP()"
    );

    foreach ( $timeouts as $timeout ) {
        $transient_name = str_replace( "_transient_timeout_", "", $timeout );
        delete_transient( $transient_name );
    }

    return count( $timeouts );
}

اجرای این اسکریپت در یک Cron روزانه توصیه می‌شود.

پاک‌سازی خودکار با wp_options پاک‌سازی

برای حذف Optionهای منقضی، می‌توانید از WP-CLI استفاده کنید.

wp transient delete --expired

تست و پایش

پایش Transientها را می‌توان با یک اسکریپت Cron انجام داد که تعداد و حجم Transientها را در لاگ ثبت می‌کند.

<?php
add_action( "wpk_transient_audit", function() {
    global $wpdb;
    $count = (int) $wpdb->get_var(
        "SELECT COUNT(*) FROM {$wpdb->options} WHERE option_name LIKE '%_transient_%'"
    );
    $bytes = (int) $wpdb->get_var(
        "SELECT SUM(LENGTH(option_value)) FROM {$wpdb->options} WHERE option_name LIKE '%_transient_%'"
    );
    error_log( sprintf( "Transients: %d, Size: %d KB", $count, $bytes / 1024 ) );
} );

اشتباهات رایج در تست

اشتباه اول، نبود تست با Object Cache خارجی. اشتباه دوم، نبود تست با Multisite. اشتباه سوم، نبود تست انقضا. اشتباه چهارم، نبود تست Cache Stampede. اشتباه پنجم، نبود تست پاک‌سازی.

پرسش‌های پرتکرار درباره Transient و Option

تفاوت اصلی Transient و Option چیست؟

Transient انقضا دارد و برای کش است. Option پایدار است و برای تنظیمات.

آیا Transient همیشه در Object Cache ذخیره می‌شود؟

خیر، فقط اگر Object Cache Persistent فعال باشد. در غیر این صورت در wp_options ذخیره می‌شود.

آیا Option با Autoload = yes بر سرعت اثر دارد؟

بله، Autoload در هر صفحه بارگذاری می‌شود. حجم زیاد Autoload، سایت را کند می‌کند.

آیا Transient منقضی خودکار حذف می‌شود؟

خیر، فقط در زمان دسترسی یا با پاک‌سازی دوره‌ای.

آیا می‌توانم Transient را با Autoload = yes ذخیره کنم؟

از نسخه ۴.۶ امکان‌پذیر شده اما توصیه نمی‌شود.

در Multisite کدام را استفاده کنم؟

برای تنظیمات شبکه از Site Option و برای کش مشترک از Site Transient استفاده کنید. راهنمای راهنمای Multisite را ببینید.

نتیجه و مسیر ادامه

Transient و Option دو ابزار متفاوت با اهداف متفاوت هستند. کلید موفقیت، انتخاب درست بر اساس ماهیت داده، مدیریت Autoload، فعال‌سازی Object Cache و پاک‌سازی دوره‌ای است. اگر این لایه‌ها با دقت طراحی شوند، دیتابیس در طول سال‌ها سبک و سریع باقی می‌ماند.

پیشنهاد می‌کنم مسیر یادگیری را با Object Cache و کش آبجکت حرفه‌ای ادامه دهید و سپس Heartbeat API و کاهش بار سرور را به‌عنوان مکمل مطالعه کنید. همچنین مفهوم Cache را در ویکی‌پدیا مرور کنید.

اگر روی پروژه واقعی خود با Transient و Option کار کرده‌اید، برایم جالب است بدانید کدام بخش — Autoload یا پاک‌سازی — بیشترین چالش را ایجاد کرده است. تجربه خودتان را در دیدگاه‌ها بنویسید.