2012-07-03 5 views
3

Это мой текущий запрос:порядок Wordpress Запрос на настраиваемое поле недостающих сообщений

query_posts(array_merge(array('tag' => $pagetag,'meta_key'=>priority,'orderby' =>meta_value, 'order' =>'ASC','paged' => get_query_var('paged')))); 

Моя проблема заключается в том, что запрос показывает мне только пост, который имеет значения для моего «meta_key» означает, что «приоритет» не НОЛЬ. Как я могу улучшить этот запрос, чтобы он все еще упорядочивал мою meta_key, но покажет все записи, которые также не являются NULL?

Заранее благодарен!

ответ

5

Проблема заключается в том, что WordPress добавляет INNER JOIN в таблицу wp_postmeta, как только вы укажете meta_key в ваших условиях. Один из способов обойти эту проблему, чтобы добавить фильтр на пункте order by, что-то вроде этого:

function so_orderby_priority($original_orderby_statement) { 
    global $wpdb; 

    return "(SELECT $wpdb->postmeta.meta_value 
       FROM $wpdb->postmeta 
       WHERE $wpdb->posts.ID = $wpdb->postmeta.post_id 
       AND $wpdb->postmeta.meta_key = 'priority') ASC"; 
} 

add_filter('posts_orderby', 'so_orderby_priority'); 

query_posts(
    array(
     'tag' => $pagetag, 
     'paged' => get_query_var('paged') 
    ) 
); 

remove_filter('posts_orderby', 'so_orderby_priority'); 

Примечание MySQL сортирует NULLs первый - если вы хотите, чтобы они отсортированы в прошлом, попробовать что-то вроде этого (предполагая, что все ваши приоритеты прийти до ZZZZZ по алфавиту):

function so_orderby_priority($original_orderby_statement) { 
    global $wpdb; 

    return "IFNULL(
       (SELECT $wpdb->postmeta.meta_value 
        FROM $wpdb->postmeta 
       WHERE $wpdb->posts.ID = $wpdb->postmeta.post_id 
        AND $wpdb->postmeta.meta_key = 'priority'), 
       'ZZZZZ') ASC"; 
} 

Редактировать

Вот немного больше объяснение, которое предполагает, что вы понимаете SQL, по крайней мере немного.

Ваш оригинальный query_posts в результате следующий запрос выполняется в базе данных:

SELECT wp_posts.* 
FROM wp_posts 
     INNER JOIN wp_term_relationships ON (wp_posts.id = wp_term_relationships.object_id) 
     INNER JOIN wp_postmeta ON (wp_posts.id = wp_postmeta.post_id) 
WHERE 1 = 1 
     AND (wp_term_relationships.term_taxonomy_id IN (3)) 
     AND wp_posts.post_type = 'post' 
     AND (wp_posts.post_status = 'publish' 
       OR wp_posts.post_status = 'private') 
     AND (wp_postmeta.meta_key = 'priority') 
GROUP BY wp_posts.id 
ORDER BY wp_postmeta.meta_value ASC 
LIMIT 0, 10; 

Это INNER JOIN wp_postmeta то, что удалили все сообщения без приоритета от ваших результатов.

meta_* Удаление связанных условий с вашей query_posts:

query_posts(
    array(
     'tag' => $pagetag, 
     'paged' => get_query_var('paged') 
    ) 
); 

решить эту проблему, но порядок сортировки по-прежнему не так. Новый SQL является

SELECT wp_posts.* 
FROM wp_posts 
     INNER JOIN wp_term_relationships ON (wp_posts.id = wp_term_relationships.object_id) 
WHERE 1 = 1 
     AND (wp_term_relationships.term_taxonomy_id IN (3)) 
     AND wp_posts.post_type = 'post' 
     AND (wp_posts.post_status = 'publish' 
       OR wp_posts.post_status = 'private') 
GROUP BY wp_posts.id 
ORDER BY wp_posts.post_date DESC 
LIMIT 0, 10; 

posts_orderby фильтр позволяет изменять положение ORDER BY: wp_posts.post_date DESC заменяется на то, что возвращается фильтра. Окончательный SQL становится:

SELECT wp_posts.* 
FROM wp_posts 
     INNER JOIN wp_term_relationships ON (wp_posts.id = wp_term_relationships.object_id) 
WHERE 1 = 1 
     AND (wp_term_relationships.term_taxonomy_id IN (3)) 
     AND wp_posts.post_type = 'post' 
     AND (wp_posts.post_status = 'publish' 
       OR wp_posts.post_status = 'private') 
GROUP BY wp_posts.id 
ORDER BY (SELECT wp_postmeta.meta_value 
      FROM wp_postmeta 
      WHERE wp_posts.id = wp_postmeta.post_id 
        AND wp_postmeta.meta_key = 'priority') ASC 
LIMIT 0, 10 

, который делает то, что вам нужно.

+0

Спасибо! Работал потрясающе ... хороший код ... Но я мог бы быть очень рад, если бы вы могли объяснить немного больше, что вы сделали. Im начинающий в php и на самом деле не полностью его понял ... Чем отличается от запроса функции к исходному запросу? И что конкретно сделал фильтр? – nimi

+0

Рад, что это помогло. Решение больше MySQL, чем PHP, поскольку 'query_posts' генерирует SQL для работы с базой данных за кулисами. Фильтр полностью заменяет порядок сортировки в SQL кодом, который сортирует результаты так, как вам нужно. Я отредактирую свой ответ, чтобы добавить немного больше деталей. – Hobo

+0

Спасибо! Отличный ответ и объяснение ... – nimi

1

мне нужно выполнить подобную задачу на странице users.php для пользовательской колонки я добавил и использовал следующий код, который я модифицированный от Hobo

add_action('pre_user_query', 'qd_users_column_orderby'); 

function qd_users_column_orderby($userquery){ 
    if('my_last_login'==$userquery->query_vars['orderby']) { //check if my cusomt meta_key is the column being sorted 

    global $wpdb; 

    $userquery->query_orderby = " ORDER BY(SELECT $wpdb->usermeta.meta_value 
     FROM $wpdb->usermeta 
     WHERE $wpdb->users.ID = $wpdb->usermeta.user_id 
     AND $wpdb->usermeta.meta_key = 'my_last_login') ".($userquery->query_vars["order"] == "ASC" ? "asc " : "desc ")." , wp_users.user_login ".($userquery->query_vars["order"] == "ASC" ? "asc " : "desc "); 
    } 
} 

Надеется, что это помогает кому-то нуждающийся в этой информации.

В попытке быть на всю оставшуюся часть необходимого кода для выполнения моей индивидуальной задачи ниже.

add_filter('manage_users_columns', 'qd_add_user_login_column'); 

function qd_add_user_login_column($columns) { 
    $columns['my_last_login'] = 'Last Logged In'; 
    return $columns; 
} 

add_action('manage_users_custom_column', 'qd_show_user_login_column_content', 10, 3); 

function qd_show_user_login_column_content($value, $column_name, $user_id) { 
    $user = get_userdata($user_id); 
    if ('my_last_login' == $column_name){ 
    $lastLogin = get_the_author_meta('my_last_login', $user_id); 
    if(!$lastLogin){ 
     return "Never"; 
    }else{ 
     date_default_timezone_set(get_option('timezone_string')); 
     return date('m/d/y g:ia', $lastLogin); 
    } 
    } 
    return $value; 
} 

add_filter('manage_users_sortable_columns', 'qd_users_table_sorting'); 

function qd_users_table_sorting($columns) { 
    $columns['my_last_login'] = 'my_last_login'; 
    return $columns; 
} 
+0

Я знаю, что этот ответ не совсем соответствует индивидуальному вопросу, но я хотел просто записать свой ответ здесь, так как я смог решить свою проблему, используя выделенный ответ. –

+1

Это на самом деле помогло мне споткнуться здесь. У меня есть дата last_login, хранящаяся как longtext в пользовательской области мета. Я также добавлял 3 новых столбца в таблицу users.php. Это был только метод (pre_user_query), который фактически работал для сортировки столбца пользователя даты, извлеченного из мета-области. Спасибо за ваш продуманный ответ. – bshea

-1

Самый простой способ сделать это, чтобы вставить пользовательское поле, используя save_post действие, поэтому каждый пост опубликован будет иметь свой собственный meta_key со значением по умолчанию.

Использовать MySQL-запрос для добавления post_meta для всех сообщений не имеет мета. Это оно.

Если/кто нужен код на помощь в этом, просто ответить :)

UPDATE

Как спросил Timusan, добавьте этот код в файл functions.php после изменения названия мета-ключ:

add_action('save_post', 'sidati_post_views_metakey'); 

function sidati_post_views_metakey ($post_id){ 

    /* 
    * $post_id = is the post ID 
    * 'sidati_post_views' => is your metakey name (sidati is prefix always nice to add your prefix) 
    * 0 => the inital value 
    * true => (bool) add true if you want this metakkey become unique 
    */ 

    add_post_meta($post_id, 'sidati_post_views', 0, true); 

} 


// THIS ACTION MUST RUN ONLY ONE TIME 
add_action('init', 'sidati_allposts_must_have_this'); 

function sidati_allposts_must_have_this(){ 

    /* Call the WordPress DataBase class */ 
    global $wpdb; 

    /* This Query will get us all the posts and pages without "sidati_post_views" metakey. */ 
    $ids = $wpdb->get_row("SELECT ID FROM wpdb->posts WHERE post_type IN ('post', 'page') AND post_status = 'publish' AND ID NOT IN (SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'sidati_post_views')"); 

    /* After get all posts/pages, now you need to add the meta keys (this may take a few munites if you have many posts/pages)*/ 
    foreach ($ids as $post_id) { 
     add_post_meta($post_id, 'sidati_post_views', 0, true); 
    } 
} 
+0

Добавление нескольких примеров кода из get-go (при публикации ответа) может сделать более понятным, что вы имеете в виду. – Timusan

0

выпуска: Сортировка по настраиваемого поля, не исключая сообщения, которые не имеют значение, установленное для этого настраиваемого поля.

Ответ Hobo объясняет это хорошо. Здесь я просто предлагаю более простую альтернативу, которая в моем случае оказалась легче (обратите внимание, что это не будет работать правильно, если вам нужно разбиение на страницы).

Я решил выполнить сортировку на PHP после запроса. Приятная часть заключается в том, что я лучше контролирую, где заканчиваются сообщения с нулевыми значениями (я хотел, чтобы они отображались последними).

$query = new WP_Query($args); 

//sort by rank 
function customSort($a, $b) 
{ 
    $a = get_field("sort_ranking", $a); 
    $b = get_field("sort_ranking", $b); 

    //handle nulls 
    $a = is_numeric($a) ? $a : 9999; 
    $b = is_numeric($b) ? $b : 9999; 

    if ($a == $b) return 0; 
    return ($a < $b) ? -1 : 1; 
} 
usort($query->posts, "customSort"); 

Здесь у меня есть числовое настраиваемое поле под названием sort_ranking, и я использую его для сортировки ASC. Сообщения с нулевым значением для этого поля назначаются 9999, чтобы они заканчивались в конце. (Примечание: я использую ACF, следовательно, функция get_field)

Надеюсь, это поможет кому-то!

Смежные вопросы