Next/Prev Post链接可以按菜单顺序或按元键排序吗?

时间:2012-11-19 作者:Jodi Warren

我有一系列帖子,它们是按meta\\u键值排序的。如有必要,也可以按菜单顺序排列。

下一个/上一个帖子链接(由next_post_link, previous_post_link, 或posts_nav_link 全部按时间顺序导航。虽然我理解这种默认行为,但我不知道如何改变它。我发现它映射到链接模板中相邻的\\u post\\u链接。php,但之后它似乎开始相当硬编码。是否建议从头开始重新编写以替换它,或者是否有更好的解决方案。

11 个回复
最合适的回答,由SO网友:kaiser 整理而成

理解内部结构,相邻(下一个/上一个)帖子的“排序”顺序并不是真正的排序“顺序”。每个请求/页面上都有一个单独的查询,but 它按post_date - 或者,如果您将分级帖子作为当前显示的对象,则为帖子父级。

当您查看next_post_link(), 然后您会看到它基本上是adjacent_post_link(). 后面的函数调用get_adjacent_post() 内部使用$previous 参数/标志设置为bool(true|false) 获取下一个或上一个帖子链接。

要过滤的内容

深入挖掘后,您会看到get_adjacent_post() Source link 为其输出提供了一些很好的过滤器(也称为查询结果):(过滤器名称/参数)

  • "get_{$adjacent}_post_join"

    $join
    // Only if `$in_same_cat`
    // or: ! empty( $excluded_categories` 
    // and then: 
    // " INNER JOIN $wpdb->term_relationships AS tr 
    //     ON p.ID = tr.object_id 
    // INNER JOIN $wpdb->term_taxonomy tt 
    //     ON tr.term_taxonomy_id = tt.term_taxonomy_id"; 
    // and if $in_same_cat then it APPENDS: 
    // " AND tt.taxonomy = \'category\' 
    // AND tt.term_id IN (" . implode(\',\', $cat_array) . ")";
    $in_same_cat
    $excluded_categories
    
  • "get_{$adjacent}_post_where"

    $wpdb->prepare(
          // $op = $previous ? \'<\' : \'>\'; | $current_post_date
           "WHERE p.post_date $op %s "
          // $post->post_type
          ."AND p.post_type = %s "
          // $posts_in_ex_cats_sql = " AND tt.taxonomy = \'category\' 
          // AND tt.term_id NOT IN (" . implode($excluded_categories, \',\') . \')\'; 
          // OR empty string if $in_same_cat || ! empty( $excluded_categories
          ."AND p.post_status = \'publish\' $posts_in_ex_cats_sql "
        ",
        $current_post_date,
        $post->post_type
    )
    $in_same_cat
    $excluded_categories
    
  • "get_{$adjacent}_post_sort"

    "ORDER BY p.post_date $order LIMIT 1"`
    
    所以你可以用它做很多事情。首先要过滤WHERE 条款,以及JOINed表格和ORDER BY 陈述

    结果缓存在当前请求的内存中,因此如果在单个页面上多次调用该函数,则不会添加额外的查询。

    自动查询建筑@StephenHarris 注释中指出,在构建SQL查询时,有一个核心函数可能会派上用场:get_meta_sql() - 示例in Codex. 基本上,此函数只用于构建在中使用的元SQL语句WP_Query, 但您也可以在这种情况下(或其他情况下)使用它。您在其中输入的参数是一个数组,与添加到WP_Query.

    $meta_sql = get_meta_sql(
        $meta_query,
        \'post\',
        $wpdb->posts,
        \'ID\'
    );
    
    返回值是一个数组:

    $sql => (array) \'join\' => array(),
            (array) \'where\' => array()
    
    所以你可以使用$sql[\'join\']$sql[\'where\'] 在您的回拨中。

    要记住的依赖关系在您的情况下,最简单的事情是在一个小插件(mu)或主题函数中拦截它。php文件,并根据$adjacent = $previous ? \'previous\' : \'next\'; 变量和$order = $previous ? \'DESC\' : \'ASC\'; 变量:

    实际过滤器名称,因此过滤器名称为:

    • get_previous_post_join, get_next_post_join
    • get_previous_post_where, get_next_post_where
    • get_previous_post_sort, get_next_post_sort

    包装为插件

    。。。过滤器回调(例如)如下所示:

    <?php
    /** Plugin Name: (#73190) Alter adjacent post link sort order */
    function wpse73190_adjacent_post_sort( $orderby )
    {
        return "ORDER BY p.menu_order DESC LIMIT 1";
    }
    add_filter( \'get_previous_post_sort\', \'wpse73190_adjacent_post_sort\' );
    add_filter( \'get_next_post_sort\', \'wpse73190_adjacent_post_sort\' );
    

SO网友:jjeaton

Kaiser\'s answer 是非常棒和彻底的,但是仅仅更改ORDER BY子句是不够的,除非您的menu_order 符合您的时间顺序。

我不能对此负责,但我在中发现了以下代码this gist:

<?php
/**
 * Customize Adjacent Post Link Order
 */
function wpse73190_gist_adjacent_post_where($sql) {
  if ( !is_main_query() || !is_singular() )
    return $sql;

  $the_post = get_post( get_the_ID() );
  $patterns = array();
  $patterns[] = \'/post_date/\';
  $patterns[] = \'/\\\'[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\\\'/\';
  $replacements = array();
  $replacements[] = \'menu_order\';
  $replacements[] = $the_post->menu_order;
  return preg_replace( $patterns, $replacements, $sql );
}
add_filter( \'get_next_post_where\', \'wpse73190_gist_adjacent_post_where\' );
add_filter( \'get_previous_post_where\', \'wpse73190_gist_adjacent_post_where\' );

function wpse73190_gist_adjacent_post_sort($sql) {
  if ( !is_main_query() || !is_singular() )
    return $sql;

  $pattern = \'/post_date/\';
  $replacement = \'menu_order\';
  return preg_replace( $pattern, $replacement, $sql );
}
add_filter( \'get_next_post_sort\', \'wpse73190_gist_adjacent_post_sort\' );
add_filter( \'get_previous_post_sort\', \'wpse73190_gist_adjacent_post_sort\' );
我已经修改了WP的函数名。东南部

如果只更改ORDER BY子句,查询仍会查找大于或小于当前发布日期的发布。如果你的帖子不按时间顺序排列,你就不会得到正确的帖子。

除了修改orderby子句外,这将更改where子句以查找menu\\u顺序大于或小于当前帖子menu\\u顺序的帖子。

orderby子句也不应该硬编码为使用DESC,因为它需要根据您是获得下一个还是上一个post链接进行切换。

SO网友:Szabolcs Páll

试图勾搭但没有成功。这可能只是我的配置问题,但对于那些无法使挂钩工作的人,这里有一个最简单的解决方案:

<?php
    $all_posts = new WP_Query(array(
        \'orderby\' => \'menu_order\',
        \'order\' => \'ASC\',
        \'posts_per_page\' => -1
    ));

    foreach($all_posts->posts as $key => $value) {
        if($value->ID == $post->ID){
            $nextID = $all_posts->posts[$key + 1]->ID;
            $prevID = $all_posts->posts[$key - 1]->ID;
            break;
        }
    }
?>
<?php if($prevID): ?>
    <span class="prev">
        <a href="<?= get_the_permalink($prevID) ?>" rel="prev"><?= get_the_title($prevID) ?></a>
    </span>
<?php endif; ?>
<?php if($nextID): ?>
    <span class="next">
        <a href="<?= get_the_permalink($nextID) ?>" rel="next"><?= get_the_title($nextID) ?></a>
    </span>
<?php endif; ?>

SO网友:Micheal Jess
function wpse73190_gist_adjacent_post_sort( $sql ) {
    $pattern = \'/post_date/\';
    $replacement = \'menu_order\';

    return preg_replace( $pattern, $replacement, $sql );
}

add_filter( \'get_next_post_sort\', \'wpse73190_gist_adjacent_post_sort\' );
add_filter( \'get_previous_post_sort\', \'wpse73190_gist_adjacent_post_sort\' );
SO网友:Eli Jayson

基于@Szabolcs Páll\'sanswer 我用助手方法创建了这个实用程序类,可以按菜单顺序获取类型的帖子,也可以按菜单顺序获取下一篇和上一篇帖子。我还添加了一些条件,以检查当前帖子是否是分别获得最后一篇或第一篇帖子的第一篇或最后一篇帖子。

例如:

// $currentPost is first by menu order
getPreviousPostByMenuOrder($postType, $$currentPost->ID)
// returns => last post by menu order

// $currentPost is last by menu order
getPreviousPostByMenuOrder($postType, $$currentPost->ID)
// returns => first post by menu order

完整类别:

class PostMenuOrderUtils {

    public static function getPostsByMenuOrder($postType){
        $args =[
            \'post_type\' => $postType,
            \'orderby\' => \'menu_order\',
            \'order\' => \'ASC\',
            \'posts_per_page\' => -1
        ];

        $posts = get_posts($args);

        return $posts;
    }

    public static function getNextPostByMenuOrder($postType, $postID){
        $posts = self::getPostsByMenuOrder($postType);

        $nextPost = null;

        foreach($posts as $key => $value) {
            if($value->ID == $postID){
                $nextPost = $posts[$key] !== end($posts) ? $posts[$key + 1] : $posts[0];

                break;
            }
        }

        return $nextPost;
    }

    public static function getPreviousPostByMenuOrder($postType, $postID){
        $posts = self::getPostsByMenuOrder($postType);


        $prevPost = null;

        foreach($posts as $key => $value) {
            if($value->ID == $postID){
                $prevPost = $key !== 0 ? $posts[$key - 1] : end($posts);
                break;
            }
        }

        return $prevPost;
    }

}

SO网友:Ted Whitehead

FWIW以下是您可以订购的方式menu_order 对于特定的自定义帖子类型:

/**
 * Customize adjacent post order
 */
add_filter(\'get_next_post_sort\', function($order) {
    if (is_singular(\'my_custom_post_type\')) {
        return \'ORDER BY p.menu_order ASC LIMIT 1\';
    }

    return $order;
}, 10);

add_filter(\'get_previous_post_sort\', function($order) {
    if (is_singular(\'my_custom_post_type\')) {
        return \'ORDER BY p.menu_order DESC LIMIT 1\';
    }

    return $order;
}, 10);

add_filter(\'get_next_post_where\', function() {
    if (is_singular(\'my_custom_post_type\')) {
        global $post, $wpdb;
        return $wpdb->prepare("WHERE p.menu_order > %s AND p.post_type = %s AND p.post_status = \'publish\'", $post->menu_order, $post->post_type);
    }
}, 10);

add_filter(\'get_previous_post_where\', function() {
    if (is_singular(\'my_custom_post_type\')) {
        global $post, $wpdb;
        return $wpdb->prepare("WHERE p.menu_order < %s AND p.post_type = %s AND p.post_status = \'publish\'", $post->menu_order, $post->post_type);
    }
}, 10);
希望这对其他人有帮助!

SO网友:Elron

基于@Szabolcs Páll\'sanswer 和bbloomer的职位adding next/prev buttons in WooCommerce Single Product Page, 我创建了此代码。

It sorts all products by meta key and adding prev/next buttons above + below the product.

(The meta key can be an ACF field too!)

/**
 * @snippet       Add next/prev buttons sorted by meta key or ACF field @ WooCommerce Single Product Page
 * @testedwith    WooCommerce 4.8.0
 * @source        Elron : https://wordpress.stackexchange.com/a/365334/98773
 * @thanks        bbloomer : https://businessbloomer.com/?p=20567
 * @thanks        Szabolcs Páll : https://wordpress.stackexchange.com/a/284045/98773
 */

add_action(\'woocommerce_before_single_product\', \'elron_prev_next_product\');

// and if you also want them at the bottom...
add_action(\'woocommerce_after_single_product\', \'elron_prev_next_product\');

function elron_prev_next_product()
{
   global $post;

   echo \'<div class="prev-next-buttons">\';

   $all_posts = new WP_Query(
      array(
         \'post_type\' => \'product\',
         \'meta_key\' => \'the_meta_key_or_acf_field\', // <-- CHANGE THIS
         \'orderby\' => \'meta_value\',
         \'order\' => \'DESC\',
         \'posts_per_page\' => -1
      )
   );

   foreach ($all_posts->posts as $key => $value) {
      if ($value->ID == $post->ID) {
         $nextID = $all_posts->posts[$key + 1]->ID;
         $prevID = $all_posts->posts[$key - 1]->ID;
         break;
      }
   }

   if ($prevID) : ?>
      <a href="<?= get_the_permalink($prevID) ?>" rel="prev" class="prev" title="<?= get_the_title($prevID) ?>"><?= esc_attr__(\'Previous product\') ?></a>
   <?php endif; ?>
   <?php if ($nextID) : ?>
      <a href="<?= get_the_permalink($nextID) ?>" rel="next" class="next" title="<?= get_the_title($nextID) ?>"><?= esc_attr__(\'Next product\') ?></a>
   <?php endif; ?>
<?php

   echo \'</div>\';
}
如果您想要我使用的额外scss文件:_prev-next-buttons.scss

.prev-next-buttons {
    background: $lightpurple;
    padding: 2em;
    text-align: center;

    a {
        opacity: 0.7;
        border-radius: 0.5em;
        border: $white 1px solid;
        color: $white;
        display: inline-block;
        padding: 0.5em 0.8em;
        text-decoration: none;
        margin: 0 0.1em;
        &:hover, &:focus {
            opacity: 1;
        }
    }

    .prev {
        &:before {
            content: "  ";
        }
    }
    .next {
        &:after {
            content: "  ";
        }
    }
}

.rtl {
    .prev-next-buttons {
        .prev {
            &:before {
                content: "  ";
            }
        }
        .next {
            &:after {
                content: "  ";
            }
        }
    }
}

SO网友:any_h

我发现这个小插件非常方便:http://wordpress.org/plugins/wp-query-powered-adjacent-post-link/

WP\\u Query-Powered nextual-Post-Link是一个面向开发人员的插件。它添加了函数wpqpapl(); 到WordPress,它可以将上一篇文章和下一篇文章的信息返回到当前。它接受用于WP_Query

SO网友:Philip

这对我很有用:

add_filter( \'get_previous_post_where\', \'so16495117_mod_adjacent_bis\' );
add_filter( \'get_next_post_where\', \'so16495117_mod_adjacent_bis\' );
function so16495117_mod_adjacent_bis( $where ) {
    global $wpdb;
    return $where . " AND p.ID NOT IN ( SELECT post_id FROM $wpdb->postmeta WHERE ($wpdb->postmeta.post_id = p.ID ) AND $wpdb->postmeta.meta_key = \'archive\' AND $wpdb->postmeta.meta_value = 1 )";
}
摘自:https://stackoverflow.com/questions/16495117/how-to-skip-certain-links-on-adjacent-posts-in-wordpress

SO网友:SaltnPixels

我对此也有意见。我神奇地让它像这样工作:

确保您的帖子类型设置为具有层次式帖子https://wordpress.org/plugins/simple-custom-post-order/
除了可以通过拖放轻松排序外,该插件还可以通过菜单顺序确保上一步和下一步的工作。不幸的是,它可能以错误的顺序使用DSC而不是ASC。为了解决这个问题,我们可以创建一个反向后期导航功能https://gist.github.com/jaredchu/3e3bcb866240d1d32a3b4ae55905b135#file-the_reverse_post_navigation而且我自己也不必写一个字的代码:)

SO网友:Kent Miller

我发现了一种更容易实现基于元键的帖子导航的方法,无需修改函数。php。

我的例子:你有一个产品。php和您想要在产品之间切换。上一个产品是下一个更便宜的,下一个产品是下一个更贵的。

下面是我的解决方案single.php:

<div class="post_navigation">

<?php

// Prepare loop
$args = (
\'post_type\' => \'products\',
\'post_status\' => \'publish\',
\'meta_key\' => \'price\',
\'orderby\' => \'meta_value_num\',
\'order\' => \'ASC\',
\'posts_per_page\' => -1
);
query_posts($args);

// Initialize array in which the IDs of ALL products posts will be stored
$posts = array();

// ... and now let\'s start the loop
while ( have_posts() ) : the_post();
$posts[] += $post->ID;
endwhile;

// Reset Query
wp_reset_query();

// Identify the position of the current product within the $posts-array 
$current = array_search(get_the_ID(), $posts);

// Identify ID of previous product
$prevID = $posts[$current-1];

// Identify ID of next product
$nextID = $posts[$current+1];

// Link "previous product"
if (!empty($prevID)) { ?>
<a href="/?p=<?php echo $prevID; ?>">previous product</a>
<?php }
// Link "next product"
if (!empty($nextID)) { ?>
<a href="/?p=<?php echo $nextID; ?>">next product</a>

<?php } ?>

结束

相关推荐

Query not sorting DESC

我正在使用以下查询:<?php $postslist = new WP_Query(\'meta_key=Ordermetakey&orderby=meta_value_num&order=ASC&posts_per_page=5\'); 对frontpage上的小帖子列表进行排序,以显示最新的帖子。它需要通过一个元键对它们进行排序并进行描述。奇怪的是,它显示了帖子的ASC,尽管我已经将ASC放在了这个查询中。元键的值是日期-时间戳:例如:120403=03-04-