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

echo = 10 результатів, оскільки є лише 10 newsпублікацій з a meta_key = custom_author_name. Але є сотні newsпублікацій, у яких немає рядка post_meta з певним мета-ключем. Зауважте, що мета_запит не задіяний. Жоден мета_значення не призначається, тому що я намагаюся лише сортувати повідомлення за мета-ключем, а не фільтрувати за мета-значенням.

Чи не слід замовляти вибір усіх публікацій? і просто замовити їх?

Якщо так, чому результат фільтрується? Якщо мета_кей не знайдено, чому б не просто використати порожній рядок або зіставити всі?

Якщо ні, то чому б і ні?

Якщо я введіть мета-ключ у кожну публікацію новин (навіть якщо це порожній рядок), я отримаю очікуваний результат. Але це здається цілою великою кількістю рядків таблиць, які не повинні бути там.

Відповіді:


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', він змінив порядок, але це не мало нічого спільного з фактичним метаполем.
Джейк

3

Я спробував застосувати відповідь @Manny Fleurmond і мені подобається @Jake, я не зміг змусити її працювати навіть після виправлення друку, який 'orderby' => 'meta_key'повинен бути 'orderby' => 'meta_value'. (І для повноти це повинно бути 'posts_per_page'не так, 'post_per_page'але це не впливає на проблему, яку розглядають.)

Якщо ви подивитеся на запит SQL, який насправді генерується за допомогою відповіді @Manny Fleurmond (виправивши помилки), це ви отримаєте:

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, а потім з'ясування способів їх приєднання та до чого замовити. Упорядкування буде добре працювати, якби ви використовували лише один пункт із 'compare' => 'EXISTS', але приєднання другого 'compare' => 'NOT EXISTS'пункту з АБО (як ми повинні) зіпсує замовлення. Результат полягає в тому, що LEFT JOIN використовується для приєднання як першого пункту / таблиці, так і другого пункту / таблиці - і те, як WP поєднує все, означає, що таблиця, створена за допомогою 'compare' => 'EXISTS', насправді заповнюється мета-значеннями з будь-якого спеціального поля, а не лише з 'custom_author_name'поле, яке нас цікавить. Тому я думаю, що впорядкування за цим пунктом / таблицею дасть бажані результати лише в тому випадку, якщо конкретний пост_тип 'новини' має лише одне спеціальне поле.

Рішення, яке спрацювало в моїй ситуації, було замовлення за іншим пунктом / таблицею - НЕ ІСНУЄ. Я, здається, неінтуїтивно зрозумілий, але через те, як 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 тягне лише мета-значення з користувацького поля новин.)

Рішення

Як каже @Manny Fleurmond, це перше застереження, яке використовується для замовлення, тому відповідь полягає лише в тому, щоб поміняти положення круглими словами, надаючи це:

$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

1

Ось як насправді це працює.

Якщо ви хочете зробити це без додавання рядків таблиці, вам доведеться виконати два запити. Один з мета-ключем, який має обмежені результати, а другий, який отримує весь список; потім використовуйте 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.