لود مطالب بیشتر به صورت ایجکسی بدون افزونه

در این مطالب با همدیگه یاد میگیریم چطور با استفاده از ایجکس در وردپرس، پست ها رو بارگذاری کنیم و از لود دوباره صفحه جلوگیری کنیم تا هم پهنای باند کمتری از سایت ما مصرف بشه و هم کاربر تجربه بهتر و لذت بخشی رو در سایت تجربه کنه!

هر قالب در وردپرس دارای تکه کدی ثابت و تکرار شونده برای مطالب هستش که معمولا درون حلقه while برای تکرار و واکشی پست ها قرار میگیره؛ برای این مطلب به اون تکه کد نیاز داریم. برای هر قالب متفاوت هستش اما بسیار شبیه به هم 😶

مثلا برای قالب ما از کد حلقه پست بصورت زیر استفاده شده:

<div class="post-block">
    <a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>" class="post">
        <img src="<?php echo get_the_post_thumbnail_url(get_the_ID(), 'postthumb'); ?>" alt="<?php the_title(); ?>"
            title="<?php the_title(); ?>">

        <div class="info">
            <h3><?php the_title(); ?></h3>
            <?php foreach(get_the_category() as $cat) { ?>
                <span class="category"><?php echo $cat->name; ?></span>
            <?php } ?>
        </div>
    </a>
</div>

درخواست ایجکس در وردپرس معمولا به اینصورته که ابتدا مقادیری که برای پردازش با جاوااسکریپت و یا سرور نیاز دارید Localize می کنیم که بتونیم در جاوااسکریپت اونها رو بگیریم و به سرور پاس بدیم تا بتونیم کارهای مورد نظرمون رو انجام بدیم؛ 1- مقادیر مورد نیاز Localize می کنیم. 2- با جاوااسکریپت اونها رو پردازش میکنیم. 3- اطلاعات دلخواه و مورد نیاز رو به سرور ارسال می کنیم.

در قدم اول گفتیم باید مقادیر مورد نظرمون رو برای استفاده در جاوااسکریپت Localize کنیم؛ برای اینکار کد زیر رو در functions.php پوسته جایگذاری کنید:

add_action( 'wp_enqueue_scripts', function () {

wp_enqueue_script( 'ajax-load-more', get_template_directory_uri() . 'ajax-load-more.js', array('jquery-bizhan'), false, true );

global $wp_query;

$varToLocalaize = [
    'ajaxurl'         => admin_url( 'admin-ajax.php' ),
    'posts'           => json_encode( $wp_query->query_vars ),
    'current_page'    => get_query_var( 'paged' ) ? get_query_var('paged') : 1,
    'max_page'        => $wp_query->max_num_pages,
    'nonce'           => wp_create_nonce('load_more_nonce'),
];

wp_localize_script( 'ajax-load-more', 'load_more', $varToLocalaize);

});

تابع Localize در اکشن wp_enqueue_scripts استفاده میشه! به این مورد توجه کنید🙂

در تابع ابتدا فایل جاوااسکریپت رو متصل میکنیم (خط 3) تا بتونیم در اون اعمال مورد نظرمون رو انجام بدیم.

ایجکس یعنی اینکه اطلاعاتی رو بدون اینکه صفحه ریلود بشه، بگیریم و پردازش کنیم! برای اینکه اطلاعاتی رو دریافت کنیم باید بگیم که چه چیزی می‌خوایم بگیریم. اطلاعاتی که می‌خوایم بفرستیم در متغیر سراسری $wp_query قرار داره.

ابتدا این متغیر رو به صورت زیر قابل دسترسی میکنیم:

global $wp_query;

اطلاعاتی که میخوایم بفرستیم باید به صورت آرایه بفرستیم (خط 7). در این آرایه ابتدا مشخص میکنیم که درخواست باید به کجا ارسال بشه که (خط 8). سپس مشخص میکنیم که چه تعداد پست در هر درخواست ایجکسی دریافت بشه (خط 9). بعد مشخص می‌کنیم که در کدوم صفحه هستیم (خط 10)، اگر این مورد مشخص نشه، مثلا فقط 10 پست آخر رو دریافت میکنه!. بعد از اون تعداد کل صفحات رو ارسال میکنیم، به این خاطر که اگر صفحه آخر هستیم دیگه درخواستی ارسال نشه و در آخر هم برای موارد امنیتی یک nonce ایجاد میکنیم، برای جلوگیری از اتک خوردن از بات نت ها (مثلا سایتمون خیلی مشهوره 😂).

خب حالا که همه اطلاعات مورد نیازمون رو در آرایه ریختیم باید اون رو به javascript پاس بدیم که چون توی وردپرس هستیم با تابع wp_localize_script این کار به راحتی قابل انجام هستش؛ اما نکته ای که وجود داره اینه که باید handler تابع wp_enqueue_script فایل جاوااسکریپتی که می خواید در اون پردازش اطلاعات ایجکسی انجام بدید و handler مورد استفاده در تابع wp_localize_script یکسان باشه وگرنه وردپرس بهتون ارور میده! به آرگومان های اول در خط 3 و15 توجه کنید (یکسان هستند). آرگومان دوم یک نام دلخواه هستش که متغیرهای آرایه ای که ساختیم به اون نسبت داده میشه (وردپرس یک شی جاوااسکریپتی میسازه و مقادیر رو درون اون میریزه) و باهاش درجاوااسکریپت به مقادیر دسترسی خواهیم داشت! آرگومان سوم نیز آرایه ای که ساختیم هستش.

مستندات تابع wp_localize_script رو مطالعه کنید

بعد از اینکه کد بالا رو در فایل functions.php نوشتید، نوبت به کد جاوااسکریپت میرسه! فایلی با نام ajax-load-more و با پسوند js در تم بسازید و کد زیر رو توش بنویسید (کپی & پیست 😀):

jQuery(function ($) {

    var loadMoreBtn = $('.load-more-btn');
        btnTextLoading = 'در حال دریافت مطالب...',
        btnTextDefault = 'مطالب بیشتر',
        btnTextNoMore  = 'مطلب دیگری وجود ندارد!';

    
    if( load_more.current_page == load_more.max_page ) {
        loadMoreBtn.remove();
    }

    loadMoreBtn.click(function () {

        var data = {
            'action': 'load_more',
            'query': load_more.posts,
            'page':  load_more.current_page,
            'nonce': load_more.nonce
        };

        // if last page not loaded, yet. serve ajax call
        if(load_more.current_page != load_more.max_page) {
            $.ajax({
                url: load_more.ajaxurl,
                data: data,
                type: 'POST',
                beforeSend: function (xhr) {
                    if(loadMoreBtn.text() != btnTextNoMore) {
                        loadMoreBtn.text(btnTextLoading);
                    }
                },
                success: function (data) {
                    if (data) {

                        var new_items = $(data).hide();
                        $('.main-content .posts').append(new_items);
                        new_items.show('500');

                        // adding page number
                        load_more.current_page++;

                        if(load_more.current_page == load_more.max_page) {
                            loadMoreBtn.remove();
                        } else {
                            // reset button to default
                            loadMoreBtn.text(btnTextDefault);
                        }

                    } else {
                        loadMoreBtn.text(btnTextNoMore);
                    }
                }
            });
        }
    });
});

تا یادم نرفته باید بهتون بگم که باید قبلش کتابخونه jQuery رو اضافه کرده باشید! این کد بر اساس توابع jQuery نوشته شده.

توی خط سوم گفتیم که یه المان با کلاسِ load-more-btn توی سایت وجود داره، اون رو انتخاب کن. این المان همون دکمه ای هستش که کاربر روش کلیک میکنه و مطالب براش لود میشه. توی خط 4 و 5 و 6 هم متن های مختلف برای وضعیت های متفاوتی که ممکنه پیش بیاد رو توی متغیرهایی ریختیم.

توی خط 9 میگیم که اگر این صفحه ای که الان در اون هستیم آخرین صفحه سایت هستش، دکمه لود بیشتر رو حذف کن تا دکمه ای وجود نداشته باشه که کاربر بخواد روش کلیک کنه.

در خط 13 میگیم که اگر کاربر روی دکمه کلیک کرد کارهایی رو انجام بده؛ چه کاری؟! 🤔 کارهای زیر:

اول دیتاهایی که میخوایم سمت سرور استفاده کنیم و پردازش ها رو بر اساس اون اطلاعات انجام بدیم رو درون یک آبجکت ذخیره میکنیم و اسمش رو data میذاریم (اسمش هر چیزی میتونه باشه)

var data = {
            'action': 'load_more',
            'query': load_more.posts,
            'page':  load_more.current_page,
            'nonce': load_more.nonce
        };

این تکه کد بالا که بخشی از کد جاوااسکریپت هستش، یک شی (آبجکت) هستش که به زبان js نوشته شده. این که چه عملی در سمت سرور run بشه به قسمت action بستگی داره! بقیه خط ها رو میشه توی قسمت سمت چپ تغییر داد و نام دلخواه انتخاب کرد.

توی خط دوم مشخص میکنیم که چه کوئری ای باید واکشی بشه! مثلا فرض کنید شما توی برچسب ها یا دسته بندی ها یا جای دیگه هستید. این پارامتر برای اون موقع هستش. (توی صفحه اصلی باشید هم باز از این استفاده میشه اما بیشتر برای اون قسمت هاست)

توی خط سوم میگیم که توی کدوم صفحه هستیم و خط چهارم هم nonce ی که برامون ارسال شده رو برای ارسال به سرور میگیریم.

حالا توضیحات رو بر اساس کد جاوااسکریپت اصلی دنبال میکنیم. توی خط 23 گفتیم که اگر این برگه، برگه آخر نیست درخواست ajax رو ارسال کن! به کجا؟ به آدرسی که توی load_more.ajaxurl هستش! چه دیتایی؟ این دیتاها ⬅ data: data (data سمت چپ کلید هستش و data سمت راست همون شی ای هستش که ساختیم!). با چه متدی؟ متد POST.

شی ایجکس بخش های مختلفی داره که بسته به جواب های متفاوت دریافتی از سرور، میشه وضعیت های مختلفی رو چیاده سازی کرد. در اینجا ما به 2 حالت بیشتر نیاز نداریم و اون هم beforeSend و success هستش.

beforeSend برای زمانی هستش که کاربر روی دکمه کلیک کرده تا قبل از دریافت هر گونه جواب از سرور؛ که در اون گفته ایم اگر متن دکمه با متنی که در متغیر btnTextNoMore برابر نباشه یعنی هنوز مطلبی وجود داشته باشه، متن دکمه رو برابر با متغیر btnTextLoading قرار بده؛ یعنی بنویس “در حال دریافت مطالب…”.

در متد success هم میگیم که اگر data ای وجود داره ( از سرور جوابی دریافت شد )، اون رو درون متغیر new_items بریز و اونها رو مخفی کن، سپس اطلاعات (یا همون پست ها ) رو به بقیه اطلاعات موجود در صفحه اضافه کن، وقتی اینکار رو انجام دادی انها رو از حالت مخفی در بیار- خط 38 (اینکار باعث میشه بجای یهو ظاهر شدن پست ها، با انیمیشن به صورت نرم و زیبا اینکار انجام بشه)!

توی خط 41 یه شماره به شماره صفحه کوئری اضافه میکنیم تا دفعه بعد که کاربر روی دکمه “مطالب بیشتر” کلیک کرد، مطالب صفحه بعد براش لود بشه.

در خط 43 به بعد هم میگیم که اگر این صفحه ای که درش قرار داریم با تعداد کل صفحات کوئری برابره (اگر صفحه آخر هستیم) دکمه رو حذف کن تا کاربر نتونه روش کلیک کنه، چرا که آخرین مطالب هم واکشی شدن! در غیر این صورت متن دکمه رو به متن پیشفرض که “مطالب بیشتر” هستش تغییر بده.

بعد از تمام مطالب بالا باید سمت سرور کدهای php خودمون رو بنویسیم و چیزی که میخوایم رو به فرانت اند بفرستیم!

در وردپرس با 2 اکشن برای ایجکس سروکار داریم؛

1- wp_ajax_action

2- wp_ajax_noprive_action

بجای action نام تابعی که قرار است فراخوانی بشه رو میذاریم که در اینجا load_more هستش (این نام رو در کد جاوااسکریپت فراخوانی کردیم – خط 16). در حقیقت دو اکشن برای ایجکس رو برای این ساختن تا راحت تر کاربر login شده به سایت و کاربر معمولی رو مدیریت کرد. بصورت زیر عمل میکنیم:

add_action('wp_ajax_load_more', 'my_ajax_latest_blog_posts');
add_action('wp_ajax_noprive_load_more', 'my_ajax_latest_blog_posts');

function my_ajax_latest_blog_posts() {

    if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'load_more_nonce')) {
        exit;
    }

    $args = json_decode( stripslashes( $_POST['query'] ), true );
    $args['paged'] = $_POST['page'] + 1;
    $args['post_status'] = 'publish';

    query_posts( $args );

    if (have_posts()) {
        while (have_posts()) {
            the_post();
            get_template_part( 'includes/content/post-thumb' );
        } 
    }

    wp_reset_query();

    die;
}

ابتدا باید nonce رو بررسی کنیم تا مطمئن بشیم یک حمله نباشه! و امنیت حداقلی رو تامین کنیم (safety first 😂)

در خط 10 اینکه کوئری چی بوده رو بررسی می کنیم

در خط 11 صفحه بعد رو تنظیم میکنیم تا دوباره آخرین پست های موجود در صفحه واکشی نشن (خود وردپرس مغز نداره بفهمه!)

خط 12 مطمئن میشیم که پست هایی که وضعیت منتشر شده دارن رو نمایش بدیم

حالا توی خط 14 تمام این موارد رو به تابع query_posts ارسال میکنیم و بعد هم حلقه مشهور مطالب وردپرس رو مینویسیم. خط 19 کدی رو که در اول مطلب قرار داره رو در فایلی به نام post-thumb ذخیره کردیم و ازش استفاده میکنیم.

در خط 23 کوئری اصلی سایت رو ریست میکنیم و در آخر دستور die رو میدیم تا حلقه یکجایی شکسته بشه (منظور حلقه while نیست!)

به همین راحتی و خوشمزگی!

یکم پیچیده بنظر میاد ولی چندباری که کد رو بنویسید و اجرا کنید، متوجه روش عملکرد ajax در وردپرس خواهید شد!

درج نظر
نظر خود را درباره لود مطالب بیشتر به صورت ایجکسی بدون افزونه بنویسید.

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

نظرات کاربران

هنوز هیچ نظری برای این پست ثبت نشده است. شما اولین نفر باشید!