WP_Query کلاسی است که در وردپرس تعریف شده و به توسعه دهندگان اجازه می دهد تا کوئری های سفارشی در سایت خود بنویسند و مطالب یا محصولات را با استفاده از پارامترهای مختلف در وبسایت خود نمایش دهند. با استفاده از WP_Query امکان استعلام مستقیم از پایگاه داده وردپرس نیز میسر است. با این حال، WP_Query یکی از روش های پیشنهادی برای استعلام پست ها (نوشته ها) از پایگاه داده وردپرس می باشد.
در زیر یک نمونه wp_query که مطالبی از یک دسته را نمایش می دهد آمده است:
<?php
// The Query
$the_query = new WP_Query( 'category_name=example' );
?>
حال به عنوان مثال، نمایش 3 پست آخر سایت با استفاده از wp_query بررسی می شود.
بطور معمول طراحان قالب و سازندگان افزونه از قطعه کد زیر استفاده می کنند:
<?php
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'order' => 'DESC',
'orderby' => 'date',
'posts_per_page' => '3'
);
$parent = new WP_Query( $args );
?>
این کوئری در نگاه اول صحیح است، اما در نظر داشته باشید که محتوای اصلی یک وب سایت وردپرسی در دو جدول Post و PostMeta نگهداری می شود و اگر وب سایت دارای مطالب یا محصولات زیادی باشد، اجرای مداوم این کوئری باعث مصرف بسیار بالای منابع پردازشی و کندی لود سایت خواهد شد زیرا کوئری های اضافی زیادی را در پایگاه داده وردپرس اجرا می کند تا صرفا 3 مطلب آخر وبسایت را نمایش دهد.
راه حل چیست؟
در کوئری بالا نیازی به جستجو در جدول PostMeta نمی باشد لذا می توان با تنظیم update_post_meta_cache روی false در زمان و مصرف منابع سرویس صرفه جویی نمود:
<?php
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'order' => 'DESC',
'orderby' => 'date',
'posts_per_page' => '3',
'update_post_meta_cache' => false, // نکته1
'update_post_term_cache' => false, //
نکته1: عدم اجرای کوئری در جدول post_meta
اگر به postmeta برای پرس و جو نیاز ندارید، می توانید با تنظیم "update_post_meta_cache" روی false در زمان خود صرفه جویی کنید.
'ignore_sticky_posts' => true, // نکته2
'no_found_rows' => true // برای شمارش پستها - در صورت نیاز به صفحهبندی حذف کنید
);
$parent = new WP_Query( $args );
?>
نکته2: پست های sticky را نادیده بگیر
این مثال دقیقا همان کار کوئری اول را انجام می دهد با این تفاوت که سه دستور دیگر نیز به آن اضافه شده است. حال هر دو قطعه کد را در صفحه اصلی وبسایت اجرا نموده و تفاوت آن ها را در LightHouse بررسی کنید.
قبل از بهینه سازی کوئری :
تصویر(1)
بعد از بهینه سازی کوئری :
تصویر(2)
این موضوع باعث سرعت لود بهتر و همچنین کاهش مصرف منابع پردازشی سرویس خواهد شد.
در نظر داشته باشید برای بررسی سایت در LightHouse صرفا نیاز است آدرس وب سایت را در مرورگر کروم وارد نموده و کلید F12 را از روی کیبورد خود فشار دهید، سپس مطابق تصویر روی گزینه "LightHouse" و سپس "Generate report" کلیک نمایید.
تصویر(3)
از wp_query به شکل های مختلفی استفاده می شود که اغلب باعث کندی در لود سایت و درگیر شدن منابع پردازشی سرور می گردد.
مثال زیر را در نظر بگیرید که برای نمایش 5 پست آخر وردپرس طراحی شده و نیاز به مقادیر مختلفی مانند عنوان، نام، موضوع و تصویر پست دارد و نمی توان جستجو در جدول postmeta را از آن حذف نمود.
<code>
$args = array(
'orderby' => 'ID',
'order' => 'DESC',
'posts_per_page' => 5,
);
$the_query = new WP_Query( $args );
if ( $the_query->have_posts() ) {
while ( $the_query->have_posts() ) : $the_query->the_post();
echo '<div>';
echo '<img alt="'.get_the_post_thumbnail_caption( get_the_ID() ).'" src="'.get_the_post_thumbnail_url(get_the_ID(),'thumbnail').'">';
echo '<a href="'.get_the_permalink().'" title="'.get_the_title().'">'.get_the_title().'</a>';
echo 'نام فیلم : '.get_post_meta( get_the_ID(), 'author_movie_name', true );
echo '<br>';
echo 'موضوع : ';
$post_categories = wp_get_post_categories( get_the_ID() );
echo implode(" , ", $post_categories);
echo '<div>';
endwhile;
} else {
// no posts found
}
/* Restore original Post Data */
wp_reset_postdata();
</code>
قطعه کد مذکور بیش از 10 دستور را در پایگاه داده اجرا می کند تا 5 مطلب آخر وبسایت را نمایش دهد. حالا فرض کنید با هر بار ورود کاربر به وب سایت این قطعه کد اجرا شود، مسلما زمانی که بازدید در لحظه وبسایت بالا باشد، اجرای مداوم دستورات در پایگاه داده باعث ایجاد کندی شدید در لود سایت و درگیر شدن بیش از حد منابع سرویس می شود. راه حل مشکلات این چنینی چیست؟
آیا نیاز است هربار دستورات در پایگاه داده اجرا شوند؟ مسلما خیر.
صرفا زمانی که دیتابیس بروز شده و به نوعی پست جدیدی در سایت درج گردید، لازم است دستورات برای دریافت داده های جدید از پایگاه داده اجرا شوند.
برای انجام این مورد، نیاز است یک تابع نوشته شده و تمام موارد مورد نیاز مانند نام، عنوان، لینک، تصویر و دسته بندی پست ها در آن فراخوانی شود، مانند مثال زیر:
function wp_get_the_home_page_content() {
/* Set empty Array For Post*/
$export = array();
$args = array(
'orderby' => 'ID',
'order' => 'DESC',
'posts_per_page' => 5,
);
$the_query = new WP_Query( $args );
if ( $the_query->have_posts() ) {
while ( $the_query->have_posts() ) : $the_query->the_post();
$export[] = array(
'thumbnail_url' => get_the_post_thumbnail_url(get_the_ID(),'thumbnail'),
'thumbnail_caption' => get_the_post_thumbnail_caption( get_the_ID() ),
'post_url' => get_the_permalink(),
'post_title' => get_the_title(),
'movie_author' => get_post_meta( get_the_ID(), 'author_movie_name', true ),
'category' => wp_get_post_categories( get_the_ID() )
);
endwhile;
}
/* Restore original Post Data */
wp_reset_postdata();
/* Set Content to Option Table */
update_option( 'my_theme_home_page', $export, 'no' );
}
در این تابع ابتدا کوئری ارسال و سپس مواردی که نیاز به خروجی آن بود، به آرایه اضافه شده است. در نهایت نیز تابع با نام my_theme_home_page در جدول option ذخیره شد.
حال برای اینکه با هر بار افزودن مطلب جدید در سایت این تابع بروز رسانی شود، باید در بخشی از وب سایت فراخوانی گردد.
اما سوالی که به وجود می آید این است: چگونه تابع باید متوجه شد که اطلاعات وردپرس به روز شده است؟
با اکشن و فیلترهایی که در زمان اضافه کردن، ویرایش یا حذف پست ها و محصولات در پایگاه داده وردپرس رخ می دهند، می توان متوجه به روز شدن اطلاعات پایگاه داده وردپرس شد.
با استفاده از اکشن زیر می توانید متوجه اضافه شدن یا ویرایش یک پست در وردپرس شوید:
add_action( 'save_post', 'your_function', 10, 3 );
اطلاع از حذف یک پست در وردپرس:
add_action('before_delete_post','your_function');
add_action('after_delete_post', function($postid) { });
اطلاع از حذف یا ایجاد یک فهرست:
add_action( "wp_create_nav_menu", "your_function");
add_action("wp_update_nav_menu", "your_function");
اطلاع از حذف یا اضافه شدن یک رسانه:
dd_action( "add_attachment", "your_function");
add_action("delete_attachment", "your_function");
اطلاع از حذف یا اضافه شدن یک دیدگاه:
add_action( 'delete_comment', function($comment_id) { } );
add_action('wp_insert_comment','comment_inserted',99,2);
اطلاع از حذف یا اضافه شدن یک کاربر به وبسایت:
add_action( 'user_register', function($user_id) { }, 10, 1 );
add_action( 'delete_user', function($user_id) { } );
اطلاع از حذف یا اضافه شدن یک ابزارک به وردپرس:
add_action( 'wp_register_sidebar_widget', function($widget) { } );
بسیاری از فیلترها و اکشن های دیگر که همان نقاط تغییر در محتوای پایگاه داده وردپرس می باشند را می توانید در لینک زیر مشاهده کنید:
https://developer.wordpress.org/reference/hooks/
حال نیاز است اکشن یا فیلتر مدنظر به تابع ساخته شده قلاب شود:
add_action( 'save_post', 'wp_get_the_home_page_content', 10, 3 );
add_action('before_delete_post','wp_get_the_home_page_content');
از این پس هر بار که مطلبی اضافه، ویرایش یا حذف شود، کوئری در دیتابیس اجرا و محتویات بروز شده را نمایش می دهد.
در نظر داشته باشید که اکشن ها را می توانید در فایل functions.php قالب یا هر بخش دیگری از سایت که مدنظرتان است، قرار دهید.
اکنون نیاز است قطعه کد زیر را در کدهای قالب یا هر صفحه از سایت که مدنظرتان است اضافه کنید:
$post_list = get_option('my_theme_home_page');
foreach($post_list as $e) {
echo '<div>';
echo '<img alt="'.$e['thumbnail_caption'].'" src="'.$e['thumbnail_url'].'">';
echo '<a href="'.$e['post_url'].'" title="'.$e['post_title'].'">'.$e['post_title'].'</a>';
echo 'نام فیلم : '.$e['movie_author'];
echo '<br>';
echo 'موضوع : ';
echo implode(" , ", $e['category']);
echo '<div>';
}
سخن پایانی :
با تکنیک های این چنینی دیگر کوئری های زیادی در پایگاه داده وردپرس اجرا نمی شوند و منابع پردازشی سرویس نیز درگیر نخواهند شد. در نتیجه لود وب سایت بهبود چشمگیری پیدا خواهد کرد. بهینه سازی قالب وب سایت، شما را از مشکلات متعدد در زمان بازدید های بالا یا پروژه های بزرگ در امان نگه خواهد داشت که نیاز است به عنوان یک مدیر یا طراح قالب برای جلوگیری از مشکلات آینده، موارد این چنینی را در پیاده سازی قالب و اسکریپت تان رعایت نمایید.