带分页的wp_query中的随机顺序



我有一个短代码,查询一些自定义的帖子,也有添加分页。所有方法都有效,但我想随机化顺序。然而,当我在我的参数中设置顺序为"rand"时,我的分页中的每个页面都是完全随机的-这意味着,同一篇文章可以在不同的页面上多次显示。我如何随机化所有帖子的顺序,但不是在每页级别?下面是我的代码:

function slaProductsArchive( $atts ){
global $paged;
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$numposts = intval($atts['num']);
$cat = $atts['cat'];
$args = array(  
'post_type' => 'product',
'post_status' => 'publish',
'posts_per_page' => $numposts, 
'orderby' => 'rand',
'product-category' => $cat,
'paged' => $paged,
);
$loop = new WP_Query( $args ); 
while ( $loop->have_posts() ) : $loop->the_post(); 
// Display my posts
endwhile;
$output .= '</div>';
$output .= '<div class="slaPagination"><span class="prev-posts-links">' . get_previous_posts_link('<i class="fas fa-arrow-left"></i> Previous') . '</span> ';
$output .= '<span class="next-posts-links">' . get_next_posts_link('Next <i class="fas fa-arrow-right"></i>', $loop->max_num_pages) . '</span></div>';

wp_reset_postdata(); 
return $output;
}
add_shortcode('slaProductsArchive', 'slaProductsArchive');

您可以根据如何处理来做一些事情。一些想法:

  1. 用改变
  2. 的东西播种random顺序
  3. 存储"已显示"的订单,并排除它们
  4. 抓取所有帖子并使用种子对它们进行洗牌

当然还有其他的方式,数字2和3在非常特殊的用途之外并不是特别优雅。所以让我们把注意力集中在第一个问题上,播种random

posts_orderby过滤器是你正在寻找的。它允许你,嗯…过滤帖子的排序。

add_filter( 'posts_orderby', 'so_69214414_edit_orderby' );
function so_69214414_edit_orderby( $orderby ){
$seed = ''; // We need to figure out what to seed with
return " RAND({$seed}) ";
}

计算出$seed的定义是什么,这实际上取决于您,以及您希望随机顺序更改的频率。

它的工作原理是,如果你RAND(1)-它将随机播种1,所以只要帖子是不变的,他们总是在这个顺序。RAND(2)将产生与RAND(1)完全不同的顺序-但每次使用RAND(2)都是相同的。例如:

RAND(1) : [1, 3, 6, 2, 4, 5]
RAND(2) : [3, 5, 2, 1, 4, 6]
RAND(2) : [3, 5, 2, 1, 4, 6]
RAND(2) : [3, 5, 2, 1, 4, 6]
RAND(1) : [1, 3, 6, 2, 4, 5]
RAND(3) : [5, 1, 4, 3, 6, 2]

我的一个WP站点使用的是:$seed = date('M d, Y')。这样,帖子总是"随机化"的。每天午夜,但第一页,第二页,第三页等总是有序的。例如:

Day 1: p1[1, 3] p2[6, 2] p3[5, 4]
Day 2: p1[3, 5] p2[4, 1] p3[2, 6]

如果这对你的用例不起作用,你可以使用PHP会话并在那里存储一个随机数,或者你可以在cookie中存储一个随机数-并在每次用户访问"第1页"时刷新它。所以第1页总是随机的,但第2、3、4页总是从那个熟了的种子中提取,等等

只要找出你希望种子改变的频率,然后把它放在posts_orderby过滤器中,你就可以了。

只是确保你使用add_filter之前你调用new WP_Query(),然后remove_filter之后,如果你不希望它应用到其他任何地方!

为此,我使用了WC-Session,因为您正在使用产品,我假设您正在使用WooCommerce。每个页面都存储在一个会话变量中,所以如果您返回到前一个页面,它与之前相同。它还编写了一个单独的帖子数组,以便您可以使用post__not_in

虽然这生成了一个随机的顺序,但是一旦页面被创建,刷新时它就是那个顺序。

我还更新了您对shortcode_atts的使用情况,并提出了一个条件,以防没有产品类别集。

function slaProductsArchive( $atts ){
$atts = shortcode_atts(
array(
'num' => 10,
'cat' => ''
),
$atts, 'slaProductsArchive' );
// Retrieve Previous WC Session Vars
$done = WC()->session->get('viewed_randoms', array());
$my_page = WC()->session->get('my_page', array());

global $paged;
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
if (!array_key_exists($paged, $my_page)) {
if ( !empty( $atts['cat'] ) ) {
$args = array(
'post_type'      => 'product',
'post_status'    => 'publish',
'posts_per_page' => absint( $atts['num'] ),
'orderby'        => 'rand',
'paged'          => $paged,
'product_cat'    => $atts['cat'],
'post__not_in'   => $done
);
} else {
$args = array(
'post_type'      => 'product',
'post_status'    => 'publish',
'posts_per_page' => absint( $atts['num'] ),
'orderby'        => 'rand',
'paged'          => $paged,
'post__not_in'   => $done
);
}
} else {
$args = array(
'post_type'      => 'product',
'post_status'    => 'publish',
'post__in' => $my_page[$paged]
);
}
// Initialize $output ** This wasn't here before ** 
$output = '<div>';
// A variable to store the POST ID's of this loop
$this_loop = array();

$loop = new WP_Query( $args );
while ( $loop->have_posts() ) : $loop->the_post();

// just to show something from the loop
// You can remove this and put your own loop here 
$output .= '<p>' . get_the_title() . ' ' . get_the_ID(). '</p>';
// Set two array of the POST ID's
$done[] = get_the_ID();
$this_loop[] = get_the_ID();

endwhile;
$output .= '</div>';
$output .= '<div class="slaPagination"><span class="prev-posts-links">' . get_previous_posts_link( '<i class="fas fa-arrow-left"></i> Previous' ) . '</span> ';
$output .= '<span class="next-posts-links">' . get_next_posts_link( 'Next <i class="fas fa-arrow-right"></i>', $loop->max_num_pages ) . '</span></div>';
// Set My Page Key =  Page Number - Value = each post ID
$my_page[$paged] = $this_loop;
// Store WC Session Var
WC()->session->set('viewed_randoms', $done);
WC()->session->set('my_page', $my_page);
wp_reset_postdata();
return $output;
}
add_shortcode( 'slaProductsArchive', 'slaProductsArchive' );

不使用WooCommerce的替代方法

在这个方法中,我初始化一个PHP会话,并使用会话ID的cookie来存储一个瞬态,因为所有其余的都是在发送头之后完成的。因此,会话仅用于会话ID。你也可以简单地设置一个你想要的任何名称的cookie,并将其用于一个组成的会话,纯粹是为了使用这个会话的瞬态。

function dd_register_session(){
if(!session_id() && !headers_sent()) {
session_start();
session_write_close();
}
}
add_action('init','dd_register_session', 1);
add_action('wp_logout', 'end_session');
add_action('wp_login', 'end_session');
add_action('end_session_action', 'end_session');
function end_session() {
session_destroy ();
}
function slaProductsArchive( $atts ){
$atts = shortcode_atts(
array(
'num' => 10,
'cat' => ''
),
$atts, 'slaProductsArchive' );
// Retrieve Previous Session Data
$done = $my_page = array();
if (isset($_COOKIE['PHPSESSID'])) {
if ( false !== ( $session_data = get_transient( $_COOKIE['PHPSESSID'] ) ) ) {
$done = $session_data['done'];
$my_page = $session_data['my_page'];
}
}
global $paged;
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
if (!array_key_exists($paged, $my_page)) {
if ( !empty( $atts['cat'] ) ) {
$args = array(
'post_type'      => 'product',
'post_status'    => 'publish',
'posts_per_page' => absint( $atts['num'] ),
'orderby'        => 'rand',
'paged'          => $paged,
'product_cat'    => $atts['cat'],
'post__not_in'   => $done
);
} else {
$args = array(
'post_type'      => 'product',
'post_status'    => 'publish',
'posts_per_page' => absint( $atts['num'] ),
'orderby'        => 'rand',
'paged'          => $paged,
'post__not_in'   => $done
);
}
} else {
$args = array(
'post_type'   => 'product',
'post_status' => 'publish',
'post__in'    => $my_page[$paged],
'orderby'     => 'post__in'
);
}
// Initialize $output ** This wasn't here before **
$output = '<div>';
// A variable to store the POST ID's of this loop
$this_loop = array();
$loop = new WP_Query( $args );
while ( $loop->have_posts() ) : $loop->the_post();
// just to show something from the loop
// You can remove this and put your own loop here
$output .= '<p>' . get_the_title() . ' ' . get_the_ID(). '</p>';
// Set two array of the POST ID's
$done[] = get_the_ID();
$this_loop[] = get_the_ID();
endwhile;
$output .= '</div>';
$output .= '<div class="slaPagination"><span class="prev-posts-links">' . get_previous_posts_link( '<i class="fas fa-arrow-left"></i> Previous' ) . '</span> ';
$output .= '<span class="next-posts-links">' . get_next_posts_link( 'Next <i class="fas fa-arrow-right"></i>', $loop->max_num_pages ) . '</span></div>';
// Set My Page Key =  Page Number - Value = each post ID
$my_page[$paged] = $this_loop;
if (isset($_COOKIE['PHPSESSID'])) {
set_transient( $_COOKIE['PHPSESSID'] , array('done' => $done, 'my_page' => $my_page), 10 * MINUTE_IN_SECONDS );
}
wp_reset_postdata();
return $output;
}
add_shortcode( 'slaProductsArchive', 'slaProductsArchive' );

最新更新