我有一系列按meta_key值排序的帖子。如果需要的话,也可以按菜单顺序排列它们。我不知道如何更改它。我发现它映射到link-template.php中的neighbor_post_link,但随后开始看起来很难编码,建议您从头开始重写以替换它,还是存在更好的解决方案。

评论

这是解决您问题的理想插件:wordpress.org/support/topic / ... wordpress.org/extend/plugins / ...谢谢Ambrosite! :)

请注意,第二个答案似乎可以产生正确的结果。

#1 楼

了解内部结构

相邻(下一个/上一个)帖子的“排序”顺序实际上不是排序“顺序”。这是每个请求/页面上的单独查询,但会按post_date或查询父级(如果您具有当前显示的对象作为分层显示对象)对查询进行排序。

当您查看内部结构时的next_post_link(),那么您会发现它基本上是adjacent_post_link()的API包装器。后面的函数在内部调用get_adjacent_post(),并将$previous参数/标志设置为bool(true|false),以获取下一个或上一个帖子链接。

要过滤什么?您会看到get_adjacent_post()源链接的输出(aka查询结果)有一些不错的过滤器:(过滤器名称/参数)



"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子句,JOIN ed表和ORDER BY语句开始。在单个页面上多次运行该功能。

自动查询构建

正如@StephenHarris在评论中指出的那样,在构建SQL时可能会有一个核心功能会派上用场查询:get_meta_sql()-Codex中的示例。基本上,此函数仅用于构建在WP_Query中使用的meta SQL语句,但是在这种情况下(或其他情况下)也可以使用它。您放入其中的参数是一个数组,它将添加到WP_Query中。

$meta_sql = get_meta_sql(
    $meta_query,
    'post',
    $wpdb->posts,
    'ID'
);


返回值是数组:

$sql => (array) 'join' => array(),
        (array) 'where' => array()


因此您可以在回调中使用$sql['join']$sql['where']

需要牢记的依赖性

在您的情况下,最简单的方法是将其拦截在一个小型(μ)插件中或在您的themes.php文件中,然后根据$adjacent = $previous ? 'previous' : 'next';变量和$order = $previous ? 'DESC' : 'ASC';变量对其进行更改:

实际的过滤器名称

所以过滤器名称为:




br />

get_previous_post_joinget_next_post_join


包装为插件

...,过滤器回调将是(示例),如下所示:

<?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' );


评论


+1。仅供参考,(@ magnakai)如果对元查询执行类似的操作,请查看get_meta_sql()

–斯蒂芬·哈里斯(Stephen Harris)
2012年11月19日18:30



向您+1 @StephenHarris!没看过这个。简短的问题:当我从源中读取到您必须传递一个完全合格的查询对象时,如何使用上述过滤器来实现?据我所知,仅传递了查询字符串,因为查询是在过滤器之后执行的。

– kaiser
2012年11月19日18:58

不,$ meta_query只是要传递给WP_Query的meta_query参数的数组:在此示例中:$ meta_sql = get_meta_sql($ meta_query,'post',$ wpdb-> posts,'ID'); -这将生成需要添加的查询的JOIN和WHERE部分。

–斯蒂芬·哈里斯(Stephen Harris)
2012年11月19日19:41



@StephenHarris编辑一个(我)答案的完美时机。

– kaiser
2012年11月20日,0:28

@StephenHarris,我在应用get_meta_sql()的输出时遇到了麻烦-您能帮忙点缀吗?

–乔迪·沃伦(Jodi Warren)
2012年11月20日上午11:27

#2 楼

Kaiser的回答很棒而且很彻底,但是仅更改ORDER BY子句是不够的,除非您的menu_order与您的时间顺序相符。此要点:

<?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.SE的函数名。

如果仅更改ORDER BY子句,则查询仍会查找大于或小于当前发布日期的帖子。如果您的帖子不按时间顺序排列,那么您将找不到正确的帖子。

这会更改where子句,以查找menu_order大于或小于当前帖子的menu_order的帖子,除了修改orderby子句。

也不应对orderby子句进行硬编码以使用DESC,因为它将需要根据获取下一个还是上一个帖子链接进行切换。

评论


注意:WHERE子句查找“ YYYY-mm-dd HH:mm:ss”。如果不符合要求,将无法使用。由于该值不是由数据库设置的,而是由应用程序设置的,因此在构建正则表达式时必须首先检查该格式。

– kaiser
2014年4月6日在12:11

#3 楼

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

<?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; ?>


评论


在尝试获取get_previous_post_where,get_previous_post_join和get_previous_post_sort几个小时后,它们可以很好地与自定义帖子类型和包括元键的复杂排序一起使用,我放弃并使用了它。谢谢!

– squarecandy
18年7月12日在22:52

同样在这里,我不仅要按菜单顺序进行排序,而且还要查找具有特定meta_key和meta_value的帖子,因此这是最好的方法。我所做的唯一更改是将其包装为一个函数。

– MrCarrot
19年2月10日在8:35

此代码容易超出范围错误

– eballeste
20年4月2日,下午1:35

@eballeste,如果您指的是在第一时间获得第一篇文章,在第一时间获得最后一篇文章,请参阅下面的答案

– Eli Jayson
20-4-3在19:10

是的,看了之后又赞成,谢谢

– eballeste
20年4月8日在23:38

#4 楼

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' );


#5 楼

基于@SzabolcsPáll的回答,我已经创建了带有帮助程序方法的实用程序类,以便能够按菜单顺序获取类型的帖子,以及按菜单顺序获取下一和上一个帖子。我还添加了条件来检查当前帖子是第一条还是最后一条,以分别获取最新条或第一条帖子。

例如: >
完整课程:

// $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



#6 楼

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


WP_Query Powered Adjacent Post Link是一个插件对于开发人员。它将功能wpqpapl();添加到WordPress,可将有关上一个和下一个帖子的信息返回到当前。它接受在WP_Query类中使用的参数。


#7 楼

这对我有用:

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在相邻的WordPress帖子上

#8 楼

我也有这个问题。我神奇地使它像这样工作:


确保您的帖子类型设置为具有分层帖子。
然后使用简单的自定义帖子类型订单插件。
https://wordpress.org/plugins/simple-custom-post-order/
除了通过拖放轻松订购外,此插件确保按菜单顺序进行上一个和下一个工作。不幸的是,使用DSC而不是ASC可能会以错误的顺序工作。要解决此问题,我们可以创建反向发布导航功能。
请改用反向导航功能。我发现要点。 (添加到主题中的函数文件中)https://gist.github.com/jaredchu/3e3bcb866240d1d32a3b4ae55905b135#file-the_reverse_post_navigation


我不必写一句话自己编写代码:)

#9 楼

根据@SzabolcsPáll的回答和bbloomer在WooCommerce单个产品页面中添加下一个/上一个按钮的帖子,我创建了此代码。

它按meta键对所有产品进行排序,并在+下方的上/下一个按钮产品。

(meta键也可以是ACF字段!)




/**
 * @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: " 🠔 ";
            }
        }
    }
}


#10 楼

我发现了一种无需修改functions.php即可更轻松地实现基于元键的帖子导航的方法。

我的示例:您有一个products.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 } ?>


评论


-10为这个答案。如果您在法典规定不应使用query_posts的情况下使用它,怎么可能是更好的解决方案。

–Pieter Goosen
2014年5月21日晚上8:31

但它有效。那么替代方法是WP_Query还是什么?

–肯特·米勒(Kent Miller)
2014年5月21日在9:22

是的,应该像以前的答案一样使用WP_Query。

–Pieter Goosen
2014年5月21日在9:27

@KentMiller,法典页面上有一个内容丰富的图表,您可能还会发现这个问题很方便。熟悉这些约定非常值得。

–乔迪·沃伦(Jodi Warren)
2014年5月21日10:56