Hướng dẫn từng bước tải thêm bài viết với Ajax. Không dùng plugin

27/03 Tin tức 2,390 lượt xem

Tạo nút tải thêm bài viết cho WordPress có đơn giản không? Có một vài người đăng đã đặt câu hỏi với tôi như vậy. Nên tôi viết bài này để hướng dẫn thực hiện việc đó. Từng bước, từng bước nhé!

Bước 1: Tạo nút “tải thêm”

Hãy bỏ qua bước này nếu bạn muốn tải thêm bài viết khi cuộn (scroll).

Viết mã HTML cho nút, tuy nhiên cần kiểm tra để không hiển thị nút khi không có đủ bài viết. Tôi kiểm tra nó với $wp_query->max_num_pages

global $wp_query;
 
// don't display the button if there are not enough posts
if ($wp_query->max_num_pages > 1) {
    echo '<a class="hkt-loadmore">More posts</a>';
}

Style một chút cho nút nhé

.hkt-loadmore{
    background-color: #ddd;
    border-radius: 2px;
    display: block;
    text-align: center;
    font-size: 14px;
    font-size: 0.875rem;
    font-weight: 800;
    letter-spacing:1px;
    cursor:pointer;
    text-transform: uppercase;
    padding: 10px 0;
    transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out, color 0.3s ease-in-out;  
}
.hkt-loadmore:hover{
    background-color: #767676;
    color: #fff;
}

Bước 2: Thêm file jQuery thực hiện

Tạo file js: myloadmore.js (ở code ví dụ này, mình đặt file này tại thư mục gốc của theme) rồi truyền tham số truy vấn cho nó bằng cách thêm đoạn mã sau vào file functions.php của theme đang sử dụng.

function hkt_load_more_scripts()
{
    global $wp_query; 
 
    // In most cases it is already included on the page and this line can be removed
    wp_enqueue_script('jquery');
 
    // register our main script but do not enqueue it yet
    wp_register_script( 'myloadmore', get_stylesheet_directory_uri() . '/myloadmore.js', array('jquery') );
 
    // now the most interesting part
    // we have to pass parameters to myloadmore.js script but we can get the parameters values only in PHP
    // you can define variables directly in your HTML but I decided that the most proper way is wp_localize_script()
    wp_localize_script( 'myloadmore', 'hkt_loadmore_params', array(
        'ajaxurl' => site_url() . '/wp-admin/admin-ajax.php', // WordPress AJAX
        'posts' => json_encode($wp_query->query_vars), // everything about your loop is here
        'current_page' => get_query_var('paged') ? get_query_var('paged') : 1,
        'max_page' => $wp_query->max_num_pages
    ) );
 
 	wp_enqueue_script('myloadmore');
}
add_action('wp_enqueue_scripts', 'hkt_load_more_scripts');

Lưu ý: Nút tải thêm mình đang làm được dùng cho vòng lặp chính. Nếu bạn cần nó cho vòng lặp tùy chỉnh, hãy để lại câu hỏi trong bình luận, tôi sẽ giúp bạn.

Bước 3: Viết code js cho file myloadmore.js

Mình sẽ viết code nó cho 2 lựa chọn: Dùng nút tải thêm và tải thêm khi cuộn trang

Option 1: Dùng nút tải

jQuery(function($) { // use jQuery code inside this to avoid "$ is not defined" error
    $('.hkt-loadmore').click(function(){
        var button = $(this),
            data = {
            'action': 'loadmore',
            'query': hkt_loadmore_params.posts, // that's how we get params from wp_localize_script() function
            'page' : hkt_loadmore_params.current_page
        };
 
        $.ajax({ // you can also use $.post here
            url : hkt_loadmore_params.ajaxurl, // AJAX handler
            data : data,
            type : 'POST',
            beforeSend : function (xhr) {
                button.text('Loading...'); // change the button text, you can also add a preloader image
            },
            success : function( data ){
                if(data) { 
                    button.text('More posts').prev().before(data); // insert new posts
                    hkt_loadmore_params.current_page++;
 
                    if ( hkt_loadmore_params.current_page == hkt_loadmore_params.max_page ) 
                        button.remove(); // if last page, remove the button
 
                    // you can also fire the "post-load" event here if you use a plugin that requires it
                    // $(document.body).trigger('post-load');
                } else {
                    button.remove(); // if no data, remove the button as well
                }
            }
        });
    });
});

Lưu ý: Dòng 19 (insert new posts) có thể khác nhau do cấu trúc HTML bạn sử dụng. Ban có thể tìm hiểu một số phương thức về DOM jQuery trước: prev(), next(), parent(), …

Option 2: Tải thêm khi cuộn trang

jQuery(function($) {
    var canBeLoaded = true, // this param allows to initiate the AJAX call only if necessary
        bottomOffset = 2000; // the distance (in px) from the page bottom when you want to load more posts
 
    $(window).scroll(function(){
        var data = {
            'action': 'loadmore',
            'query': hkt_loadmore_params.posts,
            'page' : hkt_loadmore_params.current_page
        };
        if( $(document).scrollTop() > ($(document).height() - bottomOffset) && canBeLoaded == true ){
            $.ajax({
                url : hkt_loadmore_params.ajaxurl,
                data:data,
                type:'POST',
                beforeSend: function(xhr) {
                    // you can also add your own preloader here
                    // you see, the AJAX call is in process, we shouldn't run it again until complete
                    canBeLoaded = false; 
                },
                success:function(data) {
                    if(data) {
                        $('#main').find('article:last-of-type').after( data ); // where to insert posts
                        canBeLoaded = true; // the ajax is completed, now we can run it again
                        hkt_loadmore_params.current_page++;
                    }
                }
            });
        }
    });
});

Bước 4: Xử lý Ajax

Chèn đoạn code sau vào file functions.php của theme

function hkt_loadmore_ajax_handler()
{
    // prepare our arguments for the query
    $args = json_decode(stripslashes($_POST['query'] ), true);
    $args['paged'] = $_POST['page'] + 1; // we need next page to be loaded
    $args['post_status'] = 'publish';
 
    // it is always better to use WP_Query but not here
    query_posts( $args );
 
    if(have_posts()) :
        // run the loop
        while(have_posts()): the_post();
            // look into your theme code how the posts are inserted, but you can use your own HTML of course
            // do you remember? - my example is adapted for Twenty Seventeen theme
            get_template_part( 'template-parts/post/content', get_post_format() );
            // for the test purposes comment the line above and uncomment the below one
            // the_title();
        endwhile;
 
    endif;
    die; // here we exit the script and even no wp_reset_query() required!
}
add_action('wp_ajax_loadmore', 'hkt_loadmore_ajax_handler'); // wp_ajax_{action}
add_action('wp_ajax_nopriv_loadmore', 'hkt_loadmore_ajax_handler'); // wp_ajax_nopriv_{action}

Nếu bạn có bất kỳ câu hỏi nào, vui lòng để lại ý kiến comment. Chúc bạn thành công!