Orderby meta_value yalnızca mevcut meta_key'e sahip yayınları döndürür


10

Aşağıdaki wp_query var:

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

echo = 10 sonuç çünkü a ile sadece 10 newsgönderi var meta_key = custom_author_name. Ancak news, belirli meta_keyle bir post_meta satırı olmayan yüzlerce yayın var. Söz konusu meta_query bulunmadığını lütfen unutmayın. Ben hiçbir meta_value atanır, çünkü ben sadece meta_value göre filtre değil, mesajları meta_key göre sıralamak çalışıyorum.

Tüm mesajları seçerek sipariş vermemelisiniz? ve sadece sipariş et?

Öyleyse sonuç neden filtreleniyor? Meta_key bulunamazsa, neden yalnızca boş bir dize ya da hepsiyle eşleşmiyor?

Değilse, neden olmasın?

Her haber postasına bir meta_key girersem (boş bir dize olsa bile) o zaman beklenen sonucu alırım. Ancak bu, orada olması gerekmeyen bir sürü tablo satırı gibi görünüyor.

Yanıtlar:


10

@ Ambroseya'nın cevabında belirtildiği gibi, bunun böyle çalışması gerekiyordu. Bir meta sorguyu bildirdikten sonra, belirli bir değer aramasanız bile, yalnızca bu meta anahtarın bildirildiği yayınları sorgular. Tüm yayınları meta anahtarına göre sıralamak istiyorsanız, aşağıdaki kodu kullanın:

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

Bunun yaptığı, meta anahtarı bildirilen ve bildirmeyen gönderileri arayan gelişmiş bir meta sorgu kullanmaktır. EXISTSİlk olanı olduğundan, sıralama yaptığınızda meta_valueilk sorguyu kullanır.


3
Bu benim 'orderby' => 'meta_value'için sıralamayı hiç değiştirmedi, kullandığımda sıra değiştirdi, ancak gerçek meta alanla ilgisi yoktu.
Jake

3

@Manny Fleurmond'un cevabını uygulamaya çalıştım ve @Jake gibi 'orderby' => 'meta_key'olması gereken yazım hatasını düzelttikten sonra bile işe yaramadım 'orderby' => 'meta_value'. (Ve şeyiyle olması gerektiği 'posts_per_page'değil 'post_per_page'ama bu konu baktı ediliyor etkilemez.)

@Manny Fleurmond'un cevabı (yazım hatalarını düzelttikten sonra) tarafından oluşturulan SQL sorgusuna bakarsanız, elde ettiğiniz şey budur:

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

Bu, WP'nin sorguyu ayrıştırma şeklini gösterir: her meta_query deyimi için bir tablo oluşturur, ardından bunlara nasıl katılacağını ve neye göre sipariş verileceğini bulur. Sadece tek bir cümle kullanıyorsanız 'compare' => 'EXISTS', ancak ikinci 'compare' => 'NOT EXISTS'maddeyi OR ile birleştirmemiz gerektiğinde sipariş iyi çalışır (gerektiği gibi) siparişi bozar. Sonuç olarak, LEFT JOIN hem ilk yan tümceyi / tabloyu hem de ikinci yan tümcesi / tabloyu birleştirmek için kullanılır - ve 'compare' => 'EXISTS'WP'nin her şeyi bir araya getirme biçimi, kullanılarak oluşturulan tablonun yalnızca HERHANGİ özel alandan meta_değerlerle doldurulduğu anlamına gelir 'custom_author_name'Bu cümle / tabloya göre sipariş vermek, yalnızca 'haberlerin' belirli post_type'ının sadece tek bir özel alana sahip olması durumunda istenen sonuçları vereceğini düşünüyorum.

Benim durumum için çalıştı çözüm diğer cümle / tablo - DEĞİL DEĞİL biri tarafından sipariş oldu. Görünüşte karşı-sezgisel biliyorum, ama WP sorgu varsayı ayrıştırma biçimi nedeniyle bu tablo meta_valuesadece peşinde olduğumuz özel alan tarafından doldurulur.

(Ben bunu anladım tek yolu benim durumum için bu sorgu eşdeğeri çalıştırarak oldu:

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

Tüm yaptığım gösterilen sütunları değiştirilir ve GROUP BY yan tümcesi kaldırılır. Bu bana neler olduğunu gösterdi - postmeta.meta_value sütununun tüm meta_key'lerden değerleri çektiğini gösterirken mt1.meta_value sütunu, haber özel alanından yalnızca meta_values ​​çekiyordu.)

Çözüm

@Manny Fleurmond'un dediği gibi, sipariş için kullanılan ilk cümledir, bu yüzden cevap sadece cümleleri yuvarlamaktır ve bunu verir:

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

Alternatif olarak, cümleleri ilişkilendirilebilir diziler yapabilir ve karşılık gelen anahtarla sıralayabilirsiniz:

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

Meta anahtar custom_author_nameayarlanmış ve sonra ayarlanmamışsa, bunun meta_keyyanıt vereceği EXISTSve etkisinin, a olan gönderilerin yanında kabartılacağı belirtilmelidir custom_author_name. Benim durumumda bir onay kutusu var, bu yüzden "value" => "1"bunun yerine kullanıyorum EXISTS, ancak dizelerin farklı bir yaklaşıma ihtiyacı olacak.
djb

1

Aslında böyle çalışır.

Bunu tablo satırları eklemeden yapmak istiyorsanız, iki sorgu yapmanız gerekir. Biri sınırlı sonuçlara sahip olan meta_key'e sahipken diğeri listenin tamamını alır; ardından iki sorgu sonucunu karşılaştırmak için PHP kullanın (yinelenenleri kaldırmak için meta_key sonuçlarını veya muhtemelen ayarınızda mantıklı olanları kaldırmak için).


0

Ne yazık ki, böyle çalışmaz WP_Query. Bu "meta" bileşeni eklediğiniz anda bir tür filtre oluşturdunuz. Döküm $query->requestve ne demek istediğimi göreceksin.

İkincisi, WP_Querybir meta anahtarla sipariş vermeyi hiç desteklemiyor . Belirli bir anahtar için meta değerine göre sipariş verebilirsiniz, ancak anahtarın kendisine göre değil. Yine, ne demek istediğimi görmek için sorguyu dökümü. Eğer denerseniz "sipariş" bileşenlerinin bırakıldığını göreceksiniz.

Bence, bu çalışmanın en temiz yolu birkaç kısa filtre:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.