다음 / 이전 게시물 링크를 메뉴 순서 나 메타 키로 정렬 할 수 있습니까?


32

meta_key 값으로 정렬 된 일련의 게시물이 있습니다. 필요한 경우 메뉴 순서로 정렬 할 수도 있습니다.

에 의해 생성 된 다음 / 이전 포스트 링크 ( next_post_link, previous_post_link또는 posts_nav_link내가이 기본 동작을 이해하지만 연대기 모든 탐색., 나는 그것이 링크 template.php에서 adjacent_post_link까지 매핑하는 것을 나는 발견했다. 그것을 변경하는 방법을 이해하지만,하지 않습니다 이 코드는 하드 코딩 된 것처럼 보이기 시작합니다. 교체하기 위해 처음부터 다시 작성하거나 더 나은 솔루션이 권장됩니다.


2
문제에 대한 완벽한 플러그인은 다음과 같습니다. wordpress.org/support/topic/… wordpress.org/extend/plugins/… 감사합니다 Ambrosite! :)
miguelb

1
두 번째 답변은 올바른 결과를 산출하는 것으로 보입니다.
Thomas

답변:


29

내부 이해

인접한 (다음 / 이전) 게시물의 "정렬"순서는 실제로 "순서"가 아닙니다. 각 요청 / 페이지에 대한 별도의 쿼리 이지만post_date 현재 표시된 개체로 계층 적 게시물이있는 경우-또는 게시물 부모 별로 쿼리를 정렬 합니다.

의 내부를 살펴보면 next_post_link()기본적으로의 API 래퍼임을 알 수 있습니다 adjacent_post_link(). 이후 함수 get_adjacent_post()$previous인수 / 플래그를 내부적으로 호출 bool(true|false)하여 다음 또는 이전 게시물 링크를 가져옵니다.

무엇을 필터링합니까?

자세히 살펴보면 get_adjacent_post() 소스 링크에 출력에 대한 멋진 필터가 있습니다 (일명 쿼리 결과). (필터 이름 / 인수)

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

그래서 당신은 그것으로 많이 할 수 있습니다 . ed 테이블과 명령문 WHERE뿐만 아니라 절 필터링으로 시작 합니다.JOINORDER BY

결과는 현재 요청에 대해 메모리에 캐시되므로 단일 페이지에서 해당 함수를 여러 번 호출해도 추가 쿼리가 추가되지 않습니다.

자동 쿼리 작성

으로 @StephenHarris이 코멘트에 지적, SQL 쿼리를 만들 때 유용하게 사용할 수있는 핵심 기능이있다 : get_meta_sql()- 예 분과에서 . 기본적 으로이 함수는에서 사용되는 메타 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) 플러그인 또는 테마 functions.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' );

2
+1. 메타 쿼리에 이와 같은 작업을 수행하는 경우 정보 (@magnakai)를 확인하십시오.get_meta_sql()
Stephen Harris

당신에게 @StephenHarris +1! 전에 본 적이 없습니다. 짧은 질문 : 완전한 쿼리 객체를 전달해야한다는 소스를 읽을 때 위에서 언급 한 필터를 사용하여 어떻게해야합니까? 내가 볼 수있는 한, 쿼리 후에 필터가 실행되므로 쿼리 문자열 만 전달됩니다.
카이저

2
아니, $meta_query당신이 통과하는 것과 배열입니다 WP_Query위해 meta_query, 인수 :이 예에서는 : $meta_sql = get_meta_sql( $meta_query, 'post', $wpdb->posts, 'ID');- 이것은 생성 JOINWHERE추가 할 필요가 쿼리의 일부를.
Stephen Harris

@StephenHarris 하나의 답변을 편집 할 수있는 완벽한 순간.
kaiser 2018

@StephenHarris, get_meta_sql ()의 출력을 적용하는 데 문제가 있습니다. 점을 합칠 수 있습니까?
조디 워렌

21

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 절만 변경해도 쿼리는 여전히 현재 게시 날짜보다 크거나 작은 게시물을 찾습니다. 게시물이 시간순으로 표시되지 않으면 올바른 게시물이 표시되지 않습니다.

그러면 order_ 절을 수정하는 것 외에도 menu_order가 현재 게시물의 menu_order보다 크거나 작은 게시물을 찾기 위해 where 절이 변경됩니다.

orderby 절은 DESC를 사용하도록 하드 코딩되어서는 안됩니다. 다음 포스트 링크를 받는지 또는 이전 포스트 링크를 받는지에 따라 전환해야하기 때문입니다.


3
참고 사항 :이 WHERE절은을 찾습니다 'YYYY-mm-dd HH:mm:ss'. 그것이 충족되지 않으면 작동하지 않습니다. 값은 DB가 아니라 응용 프로그램에 의해 설정되므로 정규식을 작성할 때 먼저 해당 형식을 확인해야합니다.
kaiser

5

성공하지 않고 연결하려고했습니다. 내 구성의 문제 일 수 있지만 훅을 사용할 수없는 사람들을 위해 가장 간단한 해결책은 다음과 같습니다.

<?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_joinget_previous_post_sort사용자 정의 포스트 유형 및 메타 키를 포함하는 복잡한 순서로 플레이 니스, 내가 포기하고이를 사용했다. 감사!
squarecandy

여기서도 메뉴 순서로 주문하고 싶을뿐만 아니라 특정 meta_key 및 meta_value가있는 게시물을 찾아 보았으므로 이것이 가장 좋은 방법이었습니다. 내가 한 유일한 변화는 함수로 감싸는 것입니다.
MrCarrot

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

1

@ Szabolcs Pá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

풀 클래스 :

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

이 작은 플러그인이 정말 편리하다는 것을 알았습니다 : http://wordpress.org/plugins/wp-query-powered-adjacent-post-link/

WP_Query Powered Adjacent Post Link는 개발자를위한 플러그인입니다. wpqpapl();이전 및 다음 게시물에 대한 정보를 현재로 되돌릴 수 있는 기능 을 WordPress에 추가합니다 . WP_Query클래스 에서 사용할 인수를 허용합니다 .


0

이것은 나를 위해 일했다 :

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


-1

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

그러나 작동합니다. 대안은 WP_Query 또는 무엇입니까?
Kent Miller

예, WP_Query이전 답변과 같이 사용해야합니다.
Pieter Goosen

1
@KentMiller, 코덱스 페이지 에 유익한 다이어그램이 있으며이 질문 이 도움 될 수도 있습니다. 이러한 규칙에 익숙해지는 것이 좋습니다.
Jodi Warren
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.