优化 WordPress“加载更多文章”功能

在制作 WordPress主题时,一个常见需求是“加载更多”功能,通过 AJAX 请求加载更多文章内容。以前写过一篇记录,见下文,本文将根据以前的代码优化使用 Fetch API 实现“加载更多文章”功能。

WordPress“加载更多文章”按钮优化

功能解析

使用 Fetch API 进行 AJAX 请求的基础流程如下:

  • 将新文章内容添加到页面。
  • 初始化“加载更多”按钮和相关值。
  • wp_localize_script 传递服务器路径,安全验证和文字提示。
  • 创建下一页数据的 Fetch 请求。
  • 通过 PHP 处理 AJAX 请求,并返回成功数据。

一、优化“加载更多”按钮

首先,优化加载按钮,使其可以包含当前分类和页面信息。

<?php
$query = $wp_query->query_vars; // 获取当前页面的查询参数
foreach ( $query as $key => $value ) {
    if ( empty( $value ) ) {
        unset( $query[ $key ] ); // 移除空参数
    }
}
$archive = 'data-archive=' . wp_json_encode( $query ); // 将参数转换为字符串
?>

<div class="post-wrap">
    <article>...</article>
    <article>...</article>
    ...
</div>
<button class='btn btn-custom btn-block more-posts' data-current-page="<?php echo get_query_var( 'paged' ) ? esc_attr( get_query_var( 'paged' ) ) : 1; ?>" data-max-page="<?php echo esc_attr( $wp_query->max_num_pages ); ?>" <?php echo esc_attr( $archive ); ?>>加载更多</button>

如果当前页面最大页数大于 1,则显示按钮:

<?php global $wp_query;
if (  $wp_query->max_num_pages > 1): ?>
    <button class='btn btn-custom btn-block more-posts' data-page="1">
        <?php esc_html_e( 'Load More', 'lerm' ); ?>
    </button>
<?php endif;?>

二、传递参数到 JS

使用 wp_localize_script 传递 AJAX 请求相关参数:

function lerm_enqueue_scripts() {
    wp_enqueue_script( 'lerm_js', get_stylesheet_directory_uri() . '/assets/js/lerm.js', array(), '2.0', true );
    wp_localize_script(
        'lerm_js',
        'adminajax',
        array(
            'ajaxurl'  => admin_url( 'admin-ajax.php' ),
            'nonce'    => wp_create_nonce( 'ajax_nonce' ),
            'noposts'  => __( 'No older posts found', 'lerm' ),
            'loadmore' => __( 'Load more', 'lerm' ),
            'loading'  => __( 'Loading...', 'lerm' ),
        )
    );
}
add_action( 'wp_enqueue_scripts', 'lerm_enqueue_scripts' );

三、在 JS 中实现 Fetch API

创建新的 JS 文件,如 lerm.js

let loadMorePosts = document.querySelector(".more-posts");
if (loadMorePosts) {
    loadMorePosts.addEventListener("click", e => {
        e.preventDefault();
        loadMorePosts.innerHTML = adminajax.loading;

        let params = new URLSearchParams({
            action: "lerm_load_more",
            security: adminajax.nonce,
            ...loadMorePosts.dataset,
        });

        fetch(adminajax.ajaxurl, {
            method: "POST",
            body: params
        })
        .then(response => {
            if (!response.ok) {
                throw new Error("Network response was not ok");
            }
            return response.json();
        })
        .then(data => {
            if (data.success) {
                appendPostsToDOM(data.data);
            } else {
                throw new Error(data.data || 'Unknown error occurred');
            }
        })
        .catch(error => {
            console.error('Error:', error);
            loadMorePosts.setAttribute('disabled', 'disabled');
            loadMorePosts.innerHTML = error.message;
        });
    });
}

const appendPostsToDOM = (data) => {
    const loadMoreBtn = document.querySelector(".more-posts");
    const postsList = document.querySelector(".ajax-posts");
    if (postsList) {
        postsList.insertAdjacentHTML('beforeend', data.content);
    }

    loadMoreBtn.dataset.currentPage = data.currentPage;
};

四、处理 AJAX 请求的 PHP

在 WordPress 中通过 wp_ajax_wp_ajax_nopriv_ 注册处理函数:

function ajax_handle() {
    check_ajax_referer( 'ajax_nonce', 'security', true );

    $postdata = wp_unslash( $_POST );

    if ( ! isset( $postdata['archive'], $postdata['currentPage'] ) ) {
        wp_send_json_error( __( 'Invalid request data', 'lerm' ) );
    }
    $query_args = json_decode( stripslashes( $postdata['archive'] ), true );

    if ( ! is_array( $query_args ) ) {
        wp_send_json_error( __( 'Invalid query parameters', 'lerm' ) );
    }

    $query_args = array_merge(
        $query_args,
        array(
            'post_type'      => 'post',
            'posts_per_page' => 10,
            'paged'          => (int) $postdata['currentPage'] + 1,
            'post_status'    => 'publish',
        )
    );
    $posts      = new WP_Query( $query_args );

    if ( ! $posts->have_posts() || $query_args['paged'] > $posts->max_num_pages ) {
        wp_send_json_error( __( 'No more posts!', 'lerm' ) );
    }

    ob_start();

    while ( $posts->have_posts() ) :
        $posts->the_post();
        get_template_part( 'template-parts/content/content', get_post_format() );
    endwhile;

    wp_reset_postdata();

    $content = ob_get_clean();

    wp_send_json_success(
        array(
            'content'     => $content,
            'maxPage'     => $posts->max_num_pages,
            'currentPage' => $query_args['paged'],
            'nextPage'    => $query_args['paged'] + 1,
            'hasMore'     => $query_args['paged'] < $posts->max_num_pages,
        )
    );
}
add_action( 'wp_ajax_lerm_load_more', 'ajax_handle' );
add_action( 'wp_ajax_nopriv_lerm_load_more', 'ajax_handle' );

主要优化点

  1. 在加载更多文章按钮动态处理current-page,当前页面query_vars
  2. 使用unset 移除了$wp_query->query_vars查询后的空参数,可有效减少字符串长度。
  3. 使用 ...loadMorePosts.dataset 处理传递的参数,更加简单有效。
  4. 在后台处理paged页面参数,传递数据和文章数据同步。

发表评论

游客欢迎您

“优化 WordPress“加载更多文章”功能” 有 1条评论

  1. 搜索页面有bug 将第一段代码的if ( empty( $value ))修改成if ( empty( $value ) || ! is_scalar( $value ) )就可以