You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WordPress中Alpine.js AJAX加载更多重复帖子问题求助

问题:WordPress + Alpine.js 加载更多按钮重复加载帖子

使用Alpine.js为WordPress实现帖子AJAX加载功能,分类筛选按钮可正常切换分类并加载对应帖子,但「加载更多」按钮功能异常:点击后加载的是已显示的重复帖子,而非新帖子,无报错信息。

前端代码

<html>
    <head>
         <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
         <script>
    Alpine.data("filterPosts", (adminURL) => ({
        posts: "",
        limit: 6,
        total: null,
        category: null,
        post_type_js: post_id,
        showDefault: true,
        showFiltered: false,
        offset: 0,
        loadingMore: false,
        
        filterPosts(id) {
            this.showDefault = false;
            this.showFiltered = true;
            this.category = id;
            this.offset = 0;
            this.fetchPosts();
        },
        
         loadMore() {
            this.loadingMore = true;
            this.offset += this.limit;
            this.showFiltered = true;
            this.fetchPosts(true);
        },
    
        fetchPosts(append = false) {
            var formData = new FormData();
            formData.append("action", "filterPosts");
            formData.append("limit", this.limit);
            formData.append("post_type_js", this.post_type_js);
            formData.append("offset", this.offset);

            if (this.category) {
                formData.append("category", this.category);
            }
    
        fetch(adminURL, {
            method: "POST",
            body: formData,
        })
        .then((res) => res.json())
        .then((res) => {
                if (append) {
                    this.posts = this.posts.concat(res.posts);
                } else {
                    this.posts = res.posts;
                }
                this.loadingMore = false;
                this.total = res.total;
            });
        },
        
        getTotal() {
        var formData = new FormData();
        formData.append("action", "filterPosts");
    
        fetch(adminURL, {
            method: "POST",
            body: formData,
        })
        .then((res) => res.json())
        .then((res) => {
            this.total = res.total;
        });
    },
    
    init() {
        this.getTotal();
    }
    
    }));
    })
         </script>
         
       
    </head>
    <body>
        <div x-data="filterPosts('<?php echo admin_url('admin-ajax.php'); ?>')">
    <section <?php theme_section_attr_id() ?> <?php theme_section_attr_class('main-section js-posts') ?>>
      <div class="container">
        <div class="heading mx-0">
          <?php $before_title = get_sub_field('before_title');
          if ($before_title) : ?>
            <strong class="sub-title"><?php echo $before_title ?></strong>
          <?php endif ?>
          <?php $title = get_sub_field('title');
          if ($title) : ?>
            <h2><?php echo $title ?> </h2>
          <?php endif ?>
        </div>
    
          <div class="head js-posts-search-text">
            <?php if ($search_value) : ?>
              <h2 class="h5 fw-semibold"><?php printf(__('Showing results for “%s”', 'base'), $search_value) ?></h2>
            <?php endif ?>
          </div>
          
    <!--alipne js dynamic post start-->
        <div class="has-filter row flex-md-row-reverse">
            <div class="col-md-8 col-lg-9 js-posts-holder">
                
            <!-- Posts Column -->
                <div x-show.important="showDefault" class="row cards-area js-posts-items">
                    <!-- Default posts query -->
                    <?php get_template_part( 'template-parts/posts-filter/default-query' ); ?>
                </div>
                    <!-- Filtered posts -->
                <div x-show.important="showFiltered" x-html="posts" class="row cards-area js-posts-items">
                </div>
                <!-- Load More Posts -->
                
           <!-- Load More Posts -->
    <div x-show="total && (posts.split('<!--post-item-->').length -1) < total" @click="loadMore()"  class="text-center mt-12 pt-5">
        <button :disabled="loadingMore">
            <span x-show="!loadingMore">加载更多</span>
            <span x-show="loadingMore">加载中...</span>
        </button>
    </div>
             </div>
                
            <!-- Filtered posts -->
            <div class="col-md-4 col-lg-3">
                 <?php get_template_part( 'template-parts/posts-filter/filter-query' ); ?>
            <!-- Filtered end -->
             </div>   
        </div>
        </div>
    <!--alipne js dynamic post end-->
    
    </section>
    </div>
    
    </body>
    </html>

后端代码

// the ajax function
add_action('wp_ajax_filterPosts', 'filterPosts');
add_action('wp_ajax_nopriv_filterPosts', 'filterPosts');

function filterPosts()
{
    $response = [
        'posts' => "",
        'total' => 0,
    ];
        // New args for an All Posts Query
    $all_args = array(
        'posts_per_page' => -1,
        'post_status' => 'publish',
    );

    
    $filter_args = array(
        'post_status' => 'publish',
    );

    if ($_POST['limit']) {
        $filter_args['posts_per_page'] = $_POST['limit'];
    }
    
    if ($_POST['offset']) {
        $filter_args['offset'] = $_POST['offset'];
    }
    
    if ($_POST['post_type_js']) {
        $filter_args['post_type'] = $_POST['post_type_js'];
    }

    if ($_POST['category']) {
        $filter_args['cat'] = $_POST['category'];
        
        $all_args['cat'] = $_POST['category'];

    }

    $filter_query = new WP_Query($filter_args);
    
    $all_query = new WP_Query($all_args);

    $response['total'] = $all_query->found_posts;

    if ($filter_query->have_posts()):
        while ($filter_query->have_posts()): 
            $filter_query->the_post();
            $response['posts'] .= '<!--post-item-->';
            $response['posts'] .= load_template_part('/template-parts/posts-filter/single-post');
        endwhile;
        wp_reset_postdata();
    endif;

    echo json_encode($response);
    die();
}


function load_template_part($template_name, $part_name = null, $args = [])
{
    ob_start();
    get_template_part($template_name, $part_name, $args);
    $var = ob_get_contents();
    ob_end_clean();
    return $var;
}

关键修复点说明

  1. 后端接收offset参数:在filter_args中添加offset处理,确保WP_Query从指定位置读取帖子,避免重复加载。
  2. 前端offset增量与limit统一:loadMore中改为this.offset += this.limit,保证每次加载数量和初始分页一致。
  3. 完善加载状态与按钮控制:新增loadingMore变量控制按钮状态,当已加载数量等于总帖子数时自动隐藏按钮。
  4. 返回总帖子数:后端响应添加total字段,前端用于判断是否还有更多帖子可加载。

内容的提问来源于stack exchange,提问作者Beep

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 03:55:55