web-dev-qa-db-ja.com

Next/Prev Postリンクをメニュー順またはメタキーで並べることはできますか?

私はmeta_keyの値で並べられた一連の投稿を持っています。必要に応じて、それらはメニュー順で並べることもできます。

Next/prev postリンク(next_post_linkprevious_post_linkposts_nav_linkはすべて年代順に移動します。このデフォルトの動作は理解できますが、変更方法がわかりません。link-templateの隣接リンクにマッピングされていることがわかりました。 php、しかしそれはかなりハードコードされているように見え始めますそれを置き換えるために最初からこれを書き直すことをお勧めしますか、それともより良い解決策があります。

31
Jodi Warren

内部を理解する

隣接する(次の/前の)投稿の「ソート」順序は、実際にはソートの「順序」ではありません。これはリクエスト/ページごとの個別のクエリです。 しかし post_date - または現在表示されているオブジェクトとして階層型の投稿がある場合は投稿の親でクエリをソートします。

next_post_link() の内部を見ると、それは基本的に adjacent_post_link() のAPIラッパーであることがわかります。後者の関数は、$previous引数/ flagをget_adjacent_post()に設定して内部的に bool(true|false) を呼び出し、次または前の投稿リンクを取得します。

何をフィルタリングしますか?

もっと深く掘り下げると、 get_adjacent_post()ということがわかります。 ソースリンク は、その出力用にいくつかのNiceフィルタを持っています(別名クエリ結果):(フィルタ名/引数)

  • "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"`
    

それであなたはそれでalotをすることができます。それはWHERE節、ならびにJOINedテーブルおよびORDER BYステートメントのフィルタリングから始まります。

結果は現在のリクエストのためにメモリにキャッシュされるので、単一のページでこの関数を複数回呼び出しても追加のクエリは追加されません。

自動クエリ作成

コメントで @StephenHarris が指摘したように、SQLクエリを構築するときに役に立つかもしれないコア関数があります: get_meta_sql() - 例 Codex 内。基本的にこの関数はWP_Queryで使われるメタ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']を使用できます。

覚えておくべき依存

あなたの場合、最も簡単なことは小さな(mu)プラグインかthemes functions.phpファイルでそれを傍受して$adjacent = $previous ? 'previous' : 'next';変数と$order = $previous ? 'DESC' : 'ASC';変数に応じて変更することです。

実際のフィルタ名

そのため、フィルタ名は次のとおりです。

  • get_previous_post_joinget_next_post_join
  • get_previous_post_whereget_next_post_where
  • get_previous_post_sortget_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' );
28
kaiser

カイザーの答え は素晴らしく徹底的ですが、あなたのmenu_orderがあなたの年代順に一致しない限り、ORDER BY句を変更するだけでは不十分です。

私はこれを信用することはできませんが、 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.SEの関数名を変更しました。

ORDER BY句のみを変更した場合でも、クエリは現在の投稿日よりも大きいまたは小さい投稿を検索します。投稿が年代順になっていないと、正しい投稿が得られません。

これは、orderby句を修正することに加えて、where句を変更して、menu_orderが現在の投稿のmenu_orderよりも大きいか小さい投稿を探すようにします。

また、orderby節はDESCを使用するようにハードコーディングしてはいけません。次の投稿リンクと前の投稿リンクのどちらを使用しているかに基づいて切り替える必要があるためです。

21
jjeaton
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' );
4
Micheal Jess

成功せずにフックしようとしました。私の設定の問題にすぎないかもしれませんが、フックを機能させることができない人のために、これが最も簡単な解決策です:

<?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; ?>
4
Szabolcs Páll

@SzabolcsPállの answer に基づいて、このユーティリティクラスをヘルパーメソッドで作成して、メニューの順番でタイプの投稿を取得し、メニューの順番で前後の投稿も取得できるようにしました。現在の投稿が最初の投稿であるか最後の投稿であるかを確認するための条件をそれぞれ最後または最初の投稿に追加しました。

例えば:

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

}
0
Eli Jayson

私はこの小さなプラグインが本当に便利だと思います: http://wordpress.org/plugins/wp-query-powered-adjacent-post-link/

WP_Query Powered Adjacent Post Linkは開発者向けのプラグインです。これはWordPressにwpqpapl();という関数を追加したもので、前と次の投稿に関する情報を現在のものに戻すことができます。 WP_Queryクラスで使用するための引数を受け入れます。

0
any_h

これは私のために働いた:

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

0
Philip