如何让两个WP_Query用相同随机排序避免AJAX加载重复文章?
解决WordPress随机排序AJAX加载更多不重复且全量展示的问题
我最近碰到了一个挺常见的WordPress开发需求:首页要展示9篇随机排序的自定义文章类型my_posts,点击“加载更多”按钮通过AJAX每次再加9篇,核心要求是不能重复加载文章,且能展示全部32篇文章。
一开始我尝试了常规思路:把已显示的文章ID存入数组,用post__not_in参数排除,但遇到了棘手的问题——每次从剩余文章里随机取9篇,最后总会有部分文章无法被加载到(总共只显示了约28篇,而非全部32篇)。
后来我换了思路,通过预先生成全局随机ID序列,再分页截取加载的方式解决了问题,完整方案如下:
核心思路
先一次性获取所有随机排序的文章ID,把这个随机序列作为全局基准,后续每次加载都从这个序列里按页码截取9个ID来查询文章。这样既保证了随机顺序,又不会重复,还能确保所有文章都能被加载到。
1. 首次查询并渲染前9篇文章
先获取所有my_posts类型的文章并随机排序,只渲染前9篇,同时把剩余的文章ID存起来:
<?php // 一次性获取所有随机排序的文章 $args = array( 'post_type' => 'my_posts', 'posts_per_page' => -1, 'orderby' => 'rand' ); $the_query = new WP_Query($args); $index = 0; $idsInt = array(); while ($the_query->have_posts()): $the_query->the_post(); if ($index < 9) : // 渲染前9篇文章 get_template_part('part-template/content', get_post_format()); $index++; else : // 存储剩余文章的ID array_push($idsInt, get_the_ID()); endif; endwhile; wp_reset_postdata(); ?>
2. 转换ID数组为可传递的字符串格式
把存储的剩余ID数组转成适合在HTML属性中传递的字符串格式:
<?php $index = 0; $idsString = ''; foreach ($idsInt as $id) { if ($index == 0) { $idsString .= " \"" . $id . "\""; } else { $idsString .= ", \"" . $id . "\""; } $index++; } ?>
3. 渲染加载更多按钮并传递参数
在页面底部添加加载更多按钮,通过data-*属性传递剩余ID列表、AJAX地址和当前页码:
<div class="text-center"> <a id="btn-load-more" data-id='[<?php echo $idsString ?>]' class="home-load-more" data-page="1" data-url="<?php echo admin_url('admin-ajax.php'); ?>" > <span class="text"><?php _e('Load More') ?></span> </a> </div>
4. 编写AJAX请求脚本(script.js)
实现点击按钮时的AJAX逻辑,把页码和ID列表传递给后台处理函数:
$(document).on('click', '.home-load-more', function () { let that = $(this); let page = that.data('page'); let newPage = page + 1; let ajaxurl = that.data('url'); let ids = that.data('id'); $.ajax({ url: ajaxurl, type: 'post', data: { page: page, action: 'home_load_more', foo : ids }, error: function (response) { console.log(response); }, success: function (response) { if (!(response === "")) { that.data('page', newPage); $('.my_row').append(response); } } }); });
5. 编写后台AJAX处理函数
在主题的functions.php中添加处理AJAX请求的函数,根据页码截取对应9个ID,然后查询并渲染文章:
function home_load_more() { $ids = $_POST['foo']; $paged = $_POST["page"]; $postIn = array(); // 根据当前页码计算要截取的ID位置 for ($i = 0; $i < 9; $i++) { $currentIdIndex = ($paged - 1) * 9 + $i; // 没有更多ID时终止循环 if (!isset($ids[$currentIdIndex])) { break; } array_push($postIn, $ids[$currentIdIndex]); } if (empty($postIn)) { wp_reset_postdata(); die(); } // 根据截取的ID查询文章,保持预先生成的随机顺序 $query = new WP_Query(array( 'post_type' => 'my_posts', 'orderby' => 'post__in', 'post__in' => $postIn )); if ($query->have_posts()) { while ($query->have_posts()) { $query->the_post(); get_template_part('part-template/content', get_post_format()); } } wp_reset_postdata(); die(); } // 注册AJAX动作,支持登录和未登录用户 add_action('wp_ajax_home_load_more', 'home_load_more'); add_action('wp_ajax_nopriv_home_load_more', 'home_load_more');
这个方案完美解决了重复加载和无法全量展示的问题,如果你有更优的实现思路,欢迎在评论区交流~
内容的提问来源于stack exchange,提问作者Mathias Nicod
相关产品推荐
相关产品推荐

