چرا کش وردپرس شما بیاثر است؟ راهنمای تخصصی set_transient
تابع set_transient برای ذخیره داده کششده در وردپرس؛ بررسی پارامترها، expiration، sanitize، ساختار داده و اشتباهات رایج در بهینهسازی.
چرا ذخیره هوشمند داده تفاوت ایجاد میکند؟
در سایتهای پربازدید، هر عملیات سنگین میتواند اثر تجمعی داشته باشد. اگر یک افزونه در هر بار بارگذاری صفحه یک درخواست به API خارجی ارسال کند، در سایت با هزار بازدید روزانه، این رقم به هزار درخواست در روز میرسد. این حجم درخواست هم API را تحت فشار قرار میدهد، هم سرعت سایت را کاهش میدهد و هم ممکن است به بلاک شدن IP منجر شود. تابعset_transient راهحل این مسئله است. با ذخیره نتیجه یک بار، میتوانید در بازدیدهای بعدی همان نتیجه را بازخوانی کنید. این رویکرد که Caching نام دارد، یکی از اصول پایه بهینهسازی است.
تابع set_transient چیست؟
تابعset_transient() یک تابع هسته وردپرس است که در فایل wp-includes/option.php تعریف شده است. این تابع یک مقدار را با نام مشخص و تاریخ انقضای معین ذخیره میکند.
برخلاف update_option که مقدار را بدون تاریخ انقضا ذخیره میکند، Transient دارای عمر مشخص است و پس از انقضا، بهطور خودکار توسط وردپرس حذف میشود. این رفتار امکان مدیریت خودکار دادههای موقت را فراهم میکند.
نکته مهم این است که این تابع بر پایه set_transient در Object Cache و update_option در پایگاه داده کار میکند. اگر سایت از Redis یا Memcached استفاده کند، ذخیرهسازی بسیار سریعتر خواهد بود.
امضای تابع و پارامترها
امضای این تابع بهشکل زیر است:function set_transient( $transient, $value, $expiration = 0 ) {
if ( wp_using_ext_object_cache() ) {
$result = wp_cache_set( $transient, $value, 'transient', $expiration );
} else {
if ( $expiration ) {
$expiration = time() + $expiration;
update_option( '_transient_timeout_' . $transient, $expiration, false );
}
$result = update_option( '_transient_' . $transient, $value, false );
}
return $result;
}
پارامتر اول (transient) نام کلید کش است. باید رشتهای یکتا و بدون کاراکتر خاص باشد.
پارامتر دوم (value) مقداری است که ذخیره میشود. میتواند هر نوع داده سریالایزپذیر باشد.
پارامتر سوم (expiration) مدت اعتبار به ثانیه است. مقدار 0 به معنای عدم انقضای خودکار است.
خروجی تابع یک بولی است: true اگر ذخیره موفق باشد و false در غیر این صورت.
سازوکار داخلی تابع
تابعset_transient بسته به نوع Object Cache دو مسیر متفاوت دارد:
**مسیر External Object Cache**:
اگر سایت از Redis یا Memcached استفاده کند، تابع wp_cache_set فراخوانی میشود و داده با تاریخ انقضا در حافظه ذخیره میشود. این مسیر بسیار سریع است.
**مسیر Options Table**:
اگر Object Cache خارجی وجود نداشته باشد، وردپرس دو رکورد در جدول wp_options ذخیره میکند:
- _transient_timeout_{name}: زمان انقضا بهصورت timestamp یونیکس
- _transient_{name}: مقدار داده سریالایزشده
پارامتر Autoload برای هر دو رکورد false است تا در هر بار بارگذاری صفحه خوانده نشوند. این انتخاب معماری از نظر کارایی بسیار مهم است.
انتخاب expiration مناسب
انتخاب expiration مناسب، تعادل میان تازگی داده و صرفهجویی منابع است. این مقدار باید بر پایه ماهیت داده تعیین شود: - **دادههای پویا و پرتغییر** (نرخ ارز، وضعیت موجودی): ۵ تا ۱۵ دقیقه - **دادههای نیمهپایدار** (پستهای محبوب، آمار): ۱ تا ۶ ساعت - **دادههای پایدار** (پیکربندی خارجی، اطلاعات پروفایل): ۱۲ تا ۲۴ ساعت - **دادههای ثابت** (لیست کشورها، ساختارهای ثابت): ۱ هفته یا بیشتر استفاده از ثابتهای وردپرس توصیه میشود:set_transient( 'myplugin_data', $data, 15 * MINUTE_IN_SECONDS );
set_transient( 'myplugin_stats', $stats, HOUR_IN_SECONDS );
set_transient( 'myplugin_config', $config, DAY_IN_SECONDS );
set_transient( 'myplugin_static', $list, WEEK_IN_SECONDS );
نکته مهم: مقدار 0 به معنای عدم انقضای خودکار است. اگر از این مقدار استفاده کنید، باید خودتان با delete_transient داده را پاک کنید. راهنمای این تابع در صفحه delete_transient آمده است.
ساختار داده و sanitize
تابعset_transient داده را بهصورت خودکار سریالایز میکند. این یعنی میتوانید آرایه، شیء یا هر نوع داده پیچیده را ذخیره کنید.
اما یک نکته مهم: اگر داده شامل کاراکترهای غیر UTF-8 باشد یا شیئی غیرقابل سریالایز، ممکن است ذخیرهسازی شکست بخورد. همیشه داده را قبل از ذخیره پاکسازی کنید:
$data = array(
'title' => sanitize_text_field( $raw_title ),
'content' => wp_kses_post( $raw_content ),
'url' => esc_url_raw( $raw_url ),
'count' => absint( $raw_count ),
);
set_transient( 'myplugin_item', $data, HOUR_IN_SECONDS );
نکته مهم: پاکسازی در زمان ذخیره و escape در زمان نمایش، یک اصل امنیتی دوگانه است. برای مطالعه بیشتر روی توابع escape، به صفحه esc_html مراجعه کنید.
کاربردهای عملی در افزونه
کش کردن پاسخ API با مدیریت خطا:function myplugin_fetch_weather( $city ) {
$cache_key = 'myplugin_weather_' . md5( $city );
$cached = get_transient( $cache_key );
if ( false !== $cached ) {
return $cached;
}
$response = wp_remote_get(
'https://api.weather.com/v1/current?city=' . rawurlencode( $city ),
array( 'timeout' => 10 )
);
if ( is_wp_error( $response ) ) {
return false;
}
$status = wp_remote_retrieve_response_code( $response );
if ( 200 !== $status ) {
return false;
}
$body = wp_remote_retrieve_body( $response );
$data = json_decode( $body, true );
if ( ! is_array( $data ) || empty( $data['temperature'] ) ) {
return false;
}
$weather = array(
'temperature' => (float) $data['temperature'],
'humidity' => absint( $data['humidity'] ),
'timestamp' => time(),
);
set_transient( $cache_key, $weather, 30 * MINUTE_IN_SECONDS );
return $weather;
}
نکته مهم: در صورت خطا، داده کش نمیشود. این رویکرد از قفل شدن پاسخ نامعتبر جلوگیری میکند.
کش کردن کوئری سنگین:
function myplugin_get_category_stats() {
$cached = get_transient( 'myplugin_category_stats' );
if ( false !== $cached ) {
return $cached;
}
global $wpdb;
$rows = $wpdb->get_results(
'SELECT t.term_id, t.name, COUNT(p.ID) AS count
FROM {$wpdb->terms} t
INNER JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
INNER JOIN {$wpdb->term_relationships} tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
INNER JOIN {$wpdb->posts} p ON tr.object_id = p.ID
WHERE tt.taxonomy = "category" AND p.post_status = "publish"
GROUP BY t.term_id
ORDER BY count DESC',
ARRAY_A
);
$result = is_array( $rows ) ? $rows : array();
set_transient( 'myplugin_category_stats', $result, 6 * HOUR_IN_SECONDS );
return $result;
}
الگوهای حرفهای ذخیره
الگوی Cache Aside یکی از رایجترین الگوهای کش است:function myplugin_get_data() {
$cache_key = 'myplugin_data';
$cached = get_transient( $cache_key );
if ( false !== $cached ) {
return $cached;
}
$data = myplugin_expensive_operation();
if ( false !== $data ) {
set_transient( $cache_key, $data, HOUR_IN_SECONDS );
}
return $data;
}
الگوی Stale While Revalidate برای دادههای پرمصرف:
function myplugin_get_realtime_data() {
$cache_key = 'myplugin_realtime';
$cached = get_transient( $cache_key );
if ( false !== $cached ) {
$stale_key = $cache_key . '_stale';
if ( false === get_transient( $stale_key ) ) {
set_transient( $stale_key, 1, 5 * MINUTE_IN_SECONDS );
wp_schedule_single_event( time(), 'myplugin_refresh_cache' );
}
return $cached;
}
$data = myplugin_fetch_fresh_data();
set_transient( $cache_key, $data, 30 * MINUTE_IN_SECONDS );
return $data;
}
نکته مهم: الگوی Stale While Revalidate امکان بازگرداندن داده کهنه در لحظه و بهروزرسانی در پسزمینه را فراهم میکند. این الگو در سایتهای پربازدید بسیار مؤثر است.
نکات امنیتی و اشتباهات رایج
اشتباه اول، نبود expiration است. اگر همیشه0 بگذارید، دادههای قدیمی در سایت باقی میمانند و مصرف حافظه افزایش مییابد.
اشتباه دوم، نبود sanitize است. اگر داده خام از ورودی کاربر را ذخیره کنید، ممکن است به XSS منجر شود.
اشتباه سوم، نبود شرط است. اگر set_transient را بدون بررسی خروجی فراخوانی کنید، خطاهای ذخیرهسازی نادیده میمانند.
اشتباه چهارم، ذخیره دادههای حساس است. Transient در پایگاه داده یا Object Cache ذخیره میشود و ممکن است قابل دسترسی باشد. اطلاعات شخصی، کلیدهای API و رمزها نباید در Transient ذخیره شوند.
اشتباه پنجم، استفاده از نامهای غیریکتا است. اگر دو افزونه از نام یکسان استفاده کنند، دادهها تداخل پیدا میکنند.
اشتباه ششم، نبود تست است. باید سناریوهای ذخیره موفق، ذخیره ناموفق، انقضا و بازخوانی را بررسی کنید.
اشتباه هفتم، استفاده از Transient برای دادههای حجیم است. Transient برای دادههای متوسط مناسب است. برای دادههای بسیار حجیم، بهتر است از Object Cache سفارشی یا فایل استفاده کنید.
تحلیل فنی پیشرفته
در نگاه مهندسی، تابعset_transient() یک نقطه معماری در لایه Caching است که بر چند جنبه از سیستم اثر میگذارد. لایه اول لایه Storage Abstraction است. این تابع دو مسیر متفاوت دارد و مهاجرت از Options Table به Object Cache بدون تغییر کد امکانپذیر است.
لایه دوم لایه Serialization است. دادهها با سریالایز PHP ذخیره میشوند. اگر داده شامل Closure یا Resource باشد، ذخیرهسازی شکست میخورد.
لایه سوم لایه Autoload Management است. وردپرس بهدرستی رکوردهای Transient را با Autoload false ذخیره میکند تا کارایی حفظ شود.
لایه چهارم لایه Expiration Strategy است. انتخاب expiration مناسب، تعادل میان تازگی داده و صرفهجویی منابع را برقرار میکند.
لایه پنجم لایه Cache Invalidation است. اگر داده در سمت سرور تغییر کند و Transient همچنان معتبر باشد، کاربران داده قدیمی میبینند. باید در نقاط بهروزرسانی، delete_transient فراخوانی شود.
لایه ششم لایه Concurrency است. اگر چند درخواست همزمان به یک منبع سنگین داشته باشند و Transient خالی باشد، همگی ممکن است محاسبه را شروع کنند. الگوی Stale While Revalidate این مشکل را کاهش میدهد.
لایه هفتم لایه Security است. داده ذخیرهشده در پایگاه داده باید sanitize شود. داده حساس نباید ذخیره شود.
لایه هشتم لایه Multisite است. در شبکههای Multisite، Transient در هر سایت مستقل ذخیره میشود.
مفاهیم پایهای Cache Strategy در Cache در ویکیپدیا توضیح داده شده است.
برای مطالعه بیشتر روی توابع مرتبط، میتوانید به راهنمای get_transient، راهنمای delete_transient، راهنمای get_option، راهنمای update_option، راهنمای wp_remote_get، راهنمای wp_remote_post و راهنمای esc_html مراجعه کنید.
پرسشهای پرتکرار
تفاوتset_transient و update_option چیست؟ اولی با انقضای خودکار ذخیره میکند و دومی بدون انقضا.
اگر مقدار expiration صفر باشد، چه اتفاقی میافتد؟ Transient هرگز بهصورت خودکار منقضی نمیشود.
آیا میتوان داده آرایه ذخیره کرد؟ بله، وردپرس داده را سریالایز میکند.
آیا ذخیره مجدد روی Transient موجود، مقدار را بهروزرسانی میکند؟ بله، مقدار جدید جایگزین قبلی میشود و expiration بهروز میشود.
آیا Transient در Multisite بین سایتها مشترک است؟ خیر، هر سایت مستقل است.
نتیجه و مسیر ادامه
تابعset_transient() ابزار اصلی وردپرس برای ذخیره داده با انقضای خودکار است. استفاده درست از آن یعنی انتخاب expiration مناسب، sanitize داده قبل از ذخیره، نام یکتا با prefix اختصاصی و توجه به الگوهای کش. اشتباههای کوچک در این تابع اغلب به مصرف بیدلیل حافظه یا نمایش دادههای قدیمی منجر میشوند.
اگر این تابع را در پروژهای واقعی به کار بردهاید و رفتار غیرمنتظرهای دیدهاید — بهخصوص در ترکیب با External Object Cache یا در سناریوهای پرترافیک — تجربهتان میتواند راهگشای دیگران باشد. کدام بخش بیشترین زمان را از شما گرفت؟ دیدگاه خود را بنویسید.