آموزش کش کردن داده ها در وردپرس با Transients API + مثال عملی

وردپرس در نسخه ۲٫۸ خود Transients API را معرفی کرد، قابلیتی که به توسعه دهندگان اجازه می دهد داده های موردنیاز خود را به آسانی در دیتابیس وردپرس (جدول wp_options) ذخیره و کش کنند، البته این داده ها گذرا یا موقتی هستند، در صورتی که برای آنها زمان انقضاء تعیین شده باشد پس از پایان بازه زمانی از بین خواهند رفت.

ما در طول این آموزش به جای استفاده از ترجمه موقتی از کلمه Transient استفاده می کنیم.

کار با Transient آنقدر سخت و پیچیده نیست، فقط باید با توابع زیر آشنا شوید:

  1. ()set_transient : کش کردن داده ها
  2. ()get_transient : بازیابی یا فراخوانی داده های کش شده
  3. ()delete_transient : حذف داده های کش شده

در ادامه هر کدام از توابع فوق را با جزئیات بیشتری بررسی می کنیم.

ایجاد Transient

برای ایجاد transient کافی است از تابع ()set_transient استفاده کنید، شیوه فراخوانی این تابع بدین صورت است.

set_transient( $transient, $value, $expiration );

 

  1. transient$ : نام transient(الزامی)
  2. value$ : مقدار transient(الزامی)، می تواند یک مقدار ساده، آبجکت یا آرایه باشد، تابع فوق به صورت خودکار آبجکت و آرایه را به رشته تبدیل می کند.
  3. expiration$ : زمان انقضاء transient به ثانیه(اختیاری)

اگر داده ها بدون هیچ مشکلی کش شوند این تابع مقدار true در غیر اینصورت false بر می گرداند.

همچنین وردپرس چندین ثابت زمانی ارائه می دهد که می توانید از آنها برای تنظیم زمان انقضاء استفاده کنید، این ثوابت در فایل default-constants.php و دایرکتوری wp-includes قرار دارند.

MINUTE_IN_SECONDS = 60 (seconds)
HOUR_IN_SECONDS = 60 * MINUTE_IN_SECONDS
DAY_IN_SECONDS = 24 * HOUR_IN_SECONDS
WEEK_IN_SECONDS = 7 * DAY_IN_SECONDS
YEAR_IN_SECONDS = 365 * DAY_IN_SECONDS

به عنوان مثال اگر می خواهید transient پس از ۳ ساعت منقضی شود از ثابت HOUR_IN_SECONDS بدین صورت استفاده کنید.

set_transient( "md_site_name", "modiredev.com", 3 * HOUR_IN_SECONDS );

 

پس از اجرای دستور بالا در جدول wp_options دو رکورد ایجاد خواهد شد، یکی برای نام(Key) و مقدار transient و دیگری زمان انقضاء، همانطور که ملاحظه می کنید به صورت خودکار به ابتدای نام transient رشته _transient_ اضافه شده است و فیلد autoload نیز با مقدار no ست شده است.

transient در جدول wp_options

 

سوال مهم: چه موقع فیلد autoload رکورد transient با yes مقداردهی می شود؟

با توجه به اینکه پارامتر سوم تابع set_transient اختیاری است، اگر مقدار این پارامتر ۰ و یا اصلا مشخص نشود بدین معنا است که transient هیچگاه منقضی نخواهد شد، در این صورت فیلد autoload با yes مقداردهی می شود.

set_transient( "md_site_name", "modiredev.com" );

 

اگر با جدول wp_options و مفهوم داده های Autoloaded آشنا نیستید حتما مطلب آموزشی آشنایی با ساختار جداول در دیتابیس وردپرس و بهبود عملکرد وردپرس با پاکسازی جدول wp_options و داده های Autoloaded را مطالعه فرمائید.

همچنین در وردپرس شبکه(Multi Site) برای ایجاد transient می توانید از تابع ()set_site_transient استفاده کنید، این تابع دقیقا مشابه ()set_transient عمل می کند اما دو تفاوت اساسی دارد:

  1. transient ایجاد شده در تمامی زیر سایت ها در دسترس خواهد بود.
  2. transient به صورت پیش فرض auto-load خواهد بود، یعنی همیشه با yes مقداردهی می شود، به عبارت دیگر تعیین مدت زمان انقضاء هیچگونه تاثیری در مقدار فیلد autoload ندارد.

در نهایت اگر نام transient از قبل در دیتابیس موجود باشد توابع ()set_transient و ()set_site_transient مقدار و زمان انقضاء را آپدیت خواهند کرد، به بیانی ساده تر این توابع به صورت add_or_update عمل می کنند.

فراخوانی Transient

پس از ایجاد transient باید از داده های آن استفاده کنید، برای این منظور نام transient را به تابع ()get_transient ارسال نمائید.

$tran_value = get_transient( "md_site_name" );

if( $tran_value === false )
{
	// do stuff to set the transient
}

 

اگر transient منقضی شده باشد یا اصلا موجود نباشد این تابع false در غیر اینصورت داده های کش شده را بر می گرداند.

بسیار مهم است که برای ذخیره مقادیر boolean به جای true و false از مقادیر ۰ و ۱ استفاده کنید.

به طور مشابه برای transient های ایجاد شده در وردپرس شبکه تابع ()get_site_transient موجود است.

حذف Transient

در نهایت برای حذف transiet قبل از پایان مدت زمان انقضاء کافی است نام آن را به تابع ()delete_transient ارسال کنید، این تابع در صورتی که عملیات حذف را به درستی انجام دهد مقدار true وگرنه false را بر می گرداند.

delete_transient( "md_site_name" );

 

برای حذف transient موجود در وردپرس شبکه هم از تابع ()delete_site_transient استفاده کنید.

استفاده از Transient در عمل

اکثر افراد تصور می کنند که کاربرد transient در ذخیره مقادیر ساده ای همچون روز هفته، عنوان سایت و …  خلاصه می شود، اما باید بدانید که از این قابلیت می توانید به منظور افزایش سرعت وب سایت و بهبود عملکرد وردپرس استفاده کنید.

برای درک بهتر موضوع به داده هایی فکر کنید که در بازه های زمانی طولانی تغییر می کنند، مثلا منوها یا ویجت های سایدبار، آیا لازم است هر دفعه که صفحات وب لود می شود کوئری پیچیده دریافت منو مستقیما از دیتابیس فراخوانی گردد؟

در ادامه برای درک بهتر موضوع دو مثال عملی را بررسی و پیاده سازی می کنیم:

۱- کش کردن منوها(Navigation Menu)

معمولا در قالب وب سایت از تابع ()wp_nav_menu برای فراخوانی و نمایش منوها استفاده می شود، این تابع منوی مدنظر را با کدهای HTML تولید می کند، اما می توانیم آن را به صورت رشته در transient ذخیره کنیم.

بنابراین در مرحله اول کدهای زیر را به فایل functions.php اضافه می کنیم.

function get_modiredev_transient_menu( $args = array() )
{
    $default = array(
        'menu' => '',
        'theme_location' => '',
        'echo' => true
    );

    $args = wp_parse_args( $args, $default );

    $transient_name = 'modiredev_menu_' . $args['theme_location'];

    $menu = get_transient( $transient_name );

    if ( $menu === false ) {
        $menu_args = $args;
        $menu_args['echo'] = false;
        $menu = wp_nav_menu( $menu_args );
        set_transient( $transient_name, $menu, 0 );
    }

    if ( $args['echo'] === false ) {
        return $menu;
    }

    echo $menu;
}

 

چند نکته در رابطه با کدهای بالا:

  • تابع wp_parse_args آرایه args$ و default$ را با یکدیگر مرج می کند.
  • با توجه به اینکه منوها در کلیه صفحات نشان داده می شود زمان انقضاء را ۰ در نظر گرفتیم، اینکار باعث خواهد شد که transient مدنظر ما به صورت Autoloaded و خودکار در همه صفحات لود شود.
  • برای اینکه تابع wp_nav_menu به جای تولید مستقیم خروجی(echo) فقط منوها را بازگرداند(return) در داخل if مقدار echo را به false تغییر دادیم.

برای استفاده از تابع get_modiredev_transient_menu کافی است آن را در قالب وب سایت تان به صورت زیر فراخوانی کنید.

<nav id="site-navigation">
   <?php
        get_modiredev_transient_menu( 
               array( 'theme_location' => 'main-menu' )
              );
    ?>
</nav>

 

با این حال یک مسئله اساسی وجود دارد، اگر مدیر وب سایت از پنل مدیریتی منو یا منوها را تغییر دهد وردپرس همچنان آیتم های کش شده را نشان خواهد داد و متوجه این موضوع نمی شود.

برای رفع مشکل باید در هنگام ذخیره منو داده های کش شده قبلی حذف و مجددا با مقادیر جدید آپدیت شوند، برای این منظور از اکشن wp_update_nav_menu استفاده می کنیم.

function update_modiredev_transient_menu()
{
    global $wpdb;
    $wpdb->query( "DELETE FROM $wpdb->options WHERE option_name LIKE '_transient_modiredev_menu_%'" );
}
add_action( 'wp_update_nav_menu' , 'update_modiredev_transient_menu' );

 

چرا برای حذف transient از کلاس wpdb$ استفاده کردیم؟

در این مثال ممکن است تعداد منوها بیشتر از یکی باشد، بنابراین مجبوریم تابع delete_transient را در داخل حلقه به تعداد منوها فراخوانی کنیم که اینکار تا حدودی باعث ایجاد سربار خواهد شد، بنابراین عملیات حذف را مستقیما انجام دادیم.

برای آشنایی بیشتر با کلاس wpdb$ مقاله دیتابیس وردپرس: مقدمه ای بر کلاس wpdb را مطالعه فرمائید.

۲- کش کردن پست های یک دسته خاص

به کمک transient API می توانید هر داده ای را کش کنید، توسعه دهندگان وردپرس از این قابلیت به منظور افزایش سرعت برنامه های خود استفاده می کنند. ما هم در دومین مثال قصد داریم پست ها یا نوشته های یک دسته خاص را به مدت یک ساعت کش کنیم، این مثال را می توانید به ویجت آخرین مطالب یا مطالب پربازید وب سایت تان تعمیم دهید.

$posts = get_transient( 'modiredev_devmag_posts' );

if ( $posts === false ) {
    $posts = new WP_Query( array(
        'category_name' => 'devmag'
    ) );
    set_transient( 'modiredev_devmag_posts', $posts, 3600 );
}

if ( $posts->found_posts ) {
    while ( $posts->have_posts() ) {
        $posts->the_post();
        ?>
        <h2><?php echo the_title(); ?></h2>
        <?php
    }
    wp_reset_postdata();
}

 

همچنین در مقاله آموزش ساخت ابزارک(ویجت) آخرین نظرات کاربران در وردپرس برای بهبود عملکرد ابزارک آخرین نظرات کاربران از Transient استفاده شده است.

جمع بندی

می توانید از transientها برای کش کردن نتایج کوئری های پیچیده یا کوئری هایی که مدت زمان زیادی به طول می انجامند استفاده کنید، به جای آنکه در هر بار لود صفحات خروجی این کوئری های سنگین از ابتدا اجرا شوند کافی است نتایج تولیده شده آنها که از قبل در دیتابیس وردپرس ذخیره شده است را فراخوانی و استفاده کنید، اینکار موجب افزایش سرعت، بهبود عملکرد و از همه مهمتر کاربران راضی تر خواهد شد.

در پایان اگر از transient در پروژه های خود استفاده کردید خوشحال می شویم سناریوی پیاده سازی خود را از بخش نظرات با ما به اشتراک بگذارید.

نظرات و سوالات کاربران
    1. درود بر شما.
      بیاید از این زاویه به قضیه نگاه کنیم، فرض کنید شما یک کوئری پیچیده و سنگین نوشتید که برای تولید و نمایش خروجی مدنظر خود چندین جدول از دیتابیس رو درگیر می کنه، از همه مهمتر اینکه این خروجی دائما در حال تغییر نیست، مثل منوهای سایت، آخرین دیدگاه ها، بهترین مقالات یک ماه گذشته و …

      وب سایت فرضی ما روزانه ۱۰۰۰ بازدیدکننده داره، در بدترین حالت زمان اجرای این کوئری پیچیده تقریبا ۲ ثانیه است، این زمان رو در ۱۰۰۰ رکوئست ضرب کنید ببنید در هر روز چه سرباری به دیتابیس تحمیل میشه، حالا حساب کنید این وب سایت چندین کوئری مختلف از این دست داشته باشه.

      راه حل بهینه چیه؟

      کش کردن نتیجه کوئری.
      چون داده های ما خیلی پویا نیستند، در اولین اجرای کوئری خروجی نهایی رو در دیتابیس ذخیره میکنیم، دفعات بعدی به جای اینکه کوئری رو مجددا اجرا کنیم نتیجه ای که قبلا ذخیره شده است رو بازیابی و به کاربر نمایش میدیم، فرض کنید این زمان ۰٫۰۰۱ ثانیه طول بکشه اون رو در ۱۰۰۰ ضرب کنید با زمان اجرای کوئری قبلی مقایسه کنید.

      توجه داشته باشید که بازیابی داده ها می تونه فقط یک بار از دیتابیس انجام بشه، بسته به مکانیزم Caching پیاده سازی شده در وب سایت، این داده ها میتونن در حافظه RAM سرور ذخیره بشن، پس دفعات بعدی حتی مراجعه به دیتابیس هم وجود نخواهد داشت، چون داده های مربوطه از RAM بازیابی میشن، به این روش In memory Caching میگن. اما دو مشکل داره، اگر سرور ریست یا خاموش بشه داده ها پاک میشن، حافظه سرور محدوده، بنابراین راه حل منطقی کش کردن داده ها در جایی ماندگار مثل دیتابیسه، این موضوع در کنار In memory caching میتونه سرعت وب سایت رو افزایش بده.

  1. ممنون مهندس
    مهندس یاور نیا اگر امکان داره یک مطلب هم در رابطه با قرار دادن کپچا گوگل با کد نویسی و نحوه وریفای کردن آن یک مطلب قرار بدیدهیچ منبع فارسی در این زمینه وجود نداره
    باز هم تسکر بابت مطالب مفیدتون

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *