Orderby meta_value는 기존 meta_key가있는 게시물 만 반환합니다.


10

다음 wp_query가 있습니다.

$args = array(
    'post_type' => 'news',
    'orderby' => 'meta_key',
    'order' => 'ASC',
    'meta_key'=>'custom_author_name',
    'post_per_page'=>-1
);

$query = new WP_Query($args);

echo $query->found_posts;

에 10 개의 news게시물 만 있으므로 echo = 10 개의 결과가 표시됩니다 meta_key = custom_author_name. 그러나 news특정 meta_key를 가진 post_meta 행이없는 수백 개의 게시물이 있습니다. meta_query와 관련된 것은 없습니다. meta_value로 필터링하지 않고 meta_key로 게시물을 정렬하려고하기 때문에 meta_value가 할당되지 않았습니다.

모든 게시물을 순서대로 선택해서는 안됩니까? 주문하면 되나요?

그렇다면 왜 결과가 필터링됩니까? meta_key를 찾을 수 없으면 빈 문자열을 사용하거나 모두 일치하는 것을 사용하지 않는 이유는 무엇입니까?

그렇지 않다면 왜 안됩니까?

모든 뉴스 게시물에 meta_key를 입력하면 (빈 문자열 인 경우에도) 예상 된 결과를 얻습니다. 그러나 그것은 거기에있을 필요가없는 많은 테이블 행처럼 보입니다.

답변:


10

@ambroseya의 답변에서 언급했듯이, 그것은 그렇게 작동해야합니다. 메타 쿼리를 선언하면 특정 값을 찾지 않더라도 해당 메타 키가 선언 된 게시물 만 쿼리합니다. 모든 게시물을 포함 시키려면 메타 키로 정렬하십시오. 다음 코드를 사용하십시오.

$args = array(
    'post_type' => 'news',
    'orderby' => 'meta_value',
    'order' => 'ASC',
    'meta_query' => array(
        'relation' => 'OR',
        array( 
            'key'=>'custom_author_name',
            'compare' => 'EXISTS'           
        ),
        array( 
            'key'=>'custom_author_name',
            'compare' => 'NOT EXISTS'           
        )
    ),
    'posts_per_page'=>-1
);

$query = new WP_Query($args);

echo $query->found_posts;

이 작업은 메타 키가 선언되어 있고 선언되지 않은 게시물을 찾는 고급 메타 쿼리를 사용합니다. 로 EXISTS정렬하는 것이 첫 번째이므로 정렬 기준으로 meta_value첫 번째 쿼리를 사용합니다.


3
이것은 나에게 전혀 순서를 바꾸지 않았고, 내가 사용할 때 'orderby' => 'meta_value'순서를 바꾸었지만 실제 메타 필드와는 아무런 관련이 없습니다.
Jake

3

나는 @Manny Fleurmond의 대답을 적용 시도하고 @Jake처럼 난 오타 수정 후 작업에 가져올 수 없습니다 'orderby' => 'meta_key'되어야한다 'orderby' => 'meta_value'. (완전성을 위해 반드시 지켜야하는 'posts_per_page'것은 'post_per_page'아니지만보고있는 문제에는 영향을 미치지 않습니다.)

@Manny Fleurmond의 답변에 의해 실제로 생성 된 SQL 쿼리 (오타 수정)를 보면 다음과 같습니다.

SELECT   wp_{prefix}_posts.* FROM wp_{prefix}_posts
LEFT JOIN wp_{prefix}_postmeta ON (wp_{prefix}_posts.ID = wp_{prefix}_postmeta.post_id AND wp_{prefix}_postmeta.meta_key = 'custom_author_name' )
LEFT JOIN wp_{prefix}_postmeta AS mt1 ON ( wp_{prefix}_posts.ID = mt1.post_id )
WHERE 1=1  AND ( 
    wp_{prefix}_postmeta.post_id IS NULL 
    OR 
    mt1.meta_key = 'custom_author_name'
) AND wp_{prefix}_posts.post_type = 'news' AND
(wp_{prefix}_posts.post_status = 'publish' OR wp_{prefix}_posts.post_author = 1 AND wp_{prefix}_posts.post_status = 'private')
GROUP BY wp_{prefix}_posts.ID ORDER BY wp_{prefix}_postmeta.meta_value ASC

이는 WP가 쿼리 변수를 구문 분석하는 방식을 보여줍니다. 각 meta_query 절에 대한 테이블을 생성 한 다음 이들을 조인하는 방법 및 정렬 방법을 파악합니다. 와 함께 단일 절만 사용하고 OR로 'compare' => 'EXISTS'두 번째 'compare' => 'NOT EXISTS'절을 조인 하면 순서가 엉망이됩니다. 결과적으로 LEFT JOIN은 첫 번째 절 / 테이블과 두 번째 절 / 테이블을 결합하는 데 사용되며 WP가 모든 것을 하나로 묶는 방식은 사용하여 생성 된 테이블 'compare' => 'EXISTS'이 실제로는 사용자 정의 필드의 meta_value로 채워지는 것을 의미합니다 . 'custom_author_name'관심있는 필드입니다. 따라서 'news'의 특정 post_type에 단일 사용자 정의 필드 만있는 경우 해당 절 / 테이블로 주문하면 원하는 결과 만 얻을 수 있다고 생각합니다.

내 상황에서 효과가 있었던 해결책은 다른 절 / 표-NOT EXISTS로 주문하는 것이 었습니다. 직관적으로 반 직관적이지만 WP가 쿼리 변수를 구문 분석하는 방식 때문에이 테이블 meta_value은 우리가 따르는 사용자 정의 필드로 채워지는 테이블 입니다.

(내가 알아 낸 유일한 방법은 내 경우 에이 쿼리와 동등한 것을 실행하는 것입니다.

SELECT   wp_{prefix}_posts.ID, wp_{prefix}_postmeta.meta_value, mt1.meta_value FROM wp_{prefix}_posts
LEFT JOIN wp_{prefix}_postmeta ON (wp_{prefix}_posts.ID = wp_{prefix}_postmeta.post_id AND wp_{prefix}_postmeta.meta_key = 'custom_author_name' )
LEFT JOIN wp_{prefix}_postmeta AS mt1 ON ( wp_{prefix}_posts.ID = mt1.post_id )
WHERE 1=1  AND ( 
    wp_{prefix}_postmeta.post_id IS NULL 
    OR 
    mt1.meta_key = 'custom_author_name'
) AND wp_{prefix}_posts.post_type = 'news' AND
(wp_{prefix}_posts.post_status = 'publish' OR wp_{prefix}_posts.post_author = 1 AND wp_{prefix}_posts.post_status = 'private')
ORDER BY wp_{prefix}_postmeta.meta_value ASC

내가 한 것은 표시되는 열을 변경하고 GROUP BY 절을 제거하는 것입니다. 그런 다음 postmeta.meta_value 열이 모든 meta_keys에서 값을 가져 오는 반면 mt1.meta_value 열은 뉴스 사용자 정의 필드에서 meta_values ​​만 가져 오는 것을 보여줍니다.)

해결책

@Manny Fleurmond가 말했듯이, 이것이 orderby에 사용되는 첫 번째 절이므로 답은 절을 교환하여 다음과 같이 제공합니다.

$args = array(
    'post_type' => 'news',
    'orderby' => 'meta_value',
    'order' => 'ASC',
    'meta_query' => array(
        'relation' => 'OR',
        array( 
            'key' => 'custom_author_name',
            'compare' => 'NOT EXISTS'           
        ),
        array( 
            'key' => 'custom_author_name',
            'compare' => 'EXISTS'           
        )
    ),
    'posts_per_page' => -1
);

$query = new WP_Query($args);

또는 다음과 같이 절을 연관 배열로 만들고 해당 키를 기준으로 순서를 지정할 수 있습니다.

$args = array(
    'post_type' => 'news',
    'orderby' => 'not_exists_clause',
    'order' => 'ASC',
    'meta_query' => array(
        'relation' => 'OR',
        'exists_clause' => array( 
            'key' => 'custom_author_name',
            'compare' => 'EXISTS'           
        ),
        'not_exists_clause' => array( 
            'key' => 'custom_author_name',
            'compare' => 'NOT EXISTS'           
        )
    ),
    'posts_per_page' => -1
);

$query = new WP_Query($args);

메타 키 custom_author_name가 설정되고 설정 해제 meta_key되면 응답 할 EXISTS것이며 결과는을 가진 게시물과 함께 버블 링 될 것입니다 custom_author_name. 내 경우에는 확인란 "value" => "1"대신 확인란을 사용 EXISTS하지만 문자열 대신 다른 방법이 필요합니다.
djb 2016 년

1

그것이 실제로 작동하는 방식입니다.

테이블 행을 추가하지 않고 그렇게하려면 두 개의 쿼리를 수행해야합니다. 하나는 결과가 제한적인 meta_key를 가지고 있고 다른 하나는 전체 목록을 가져옵니다. 그런 다음 PHP를 사용하여 두 개의 쿼리 결과를 비교하십시오 (중복을 제거하기 위해 다른 쿼리에서 meta_key 결과를 제거하거나 설정에 의미가있는 것).


0

불행히도, 그것은 WP_Query작동 하지 않습니다 . 해당 "메타"구성 요소를 추가하자마자 일종의 필터를 만들었습니다. 덤프 $query->request와 당신은 내가 무슨 뜻인지 볼 수 있습니다.

둘째, WP_Query메타 키로 주문을 전혀 지원하지 않습니다 . 특정 키 의 메타 값으로 정렬 할 수 있지만 키 자체로 는 정렬 할 수 없습니다. 다시 말하지만 쿼리를 덤프하여 의미하는 바를 확인하십시오. 시도하면 "주문"구성 요소가 누락됩니다.

내 의견으로는이 작업을 수행하는 가장 깨끗한 방법은 몇 가지 짧은 필터입니다.

function join_meta_wpse_188287($join) {
  remove_filter('posts_join','join_meta_wpse_188287');
  global $wpdb;
  return ' INNER JOIN '.$wpdb->postmeta.' ON ('.$wpdb->posts.'.ID = '.$wpdb->postmeta.'.post_id)';
}
add_filter('posts_join','join_meta_wpse_188287');

function orderby_meta_wpse_188287($orderby) {
  remove_filter('posts_orderby','orderby_meta_wpse_188287');
  global $wpdb;
  return $wpdb->postmeta.'.meta_key ASC';
}
add_filter('posts_orderby','orderby_meta_wpse_188287');

$args = array(
    'post_type' => 'news',
    'post_per_page'=>-1
);
$q = new WP_Query($args);
var_dump($q->request); // debug
var_dump(wp_list_pluck($q->posts,'post_title')); // debug
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.