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

22

Я работаю над пользовательским шаблоном страницы терминов таксономии, в котором мы хотим, чтобы элементы, связанные с термином, были отсортированы по дате публикации (поле настраиваемой даты) - и если в один и тот же день есть несколько элементов (отформатированных как YYYY-MM- DD) затем сортировать их по заголовку и, наконец, сортировать по заголовку, если пользовательское поле не было заполнено (более старые элементы).

Итак, я попробовал его сотнями разных способов с WP_query, и он возвращает большинство результатов так, как я хочу - но в этом случае он возвращает только те элементы, которые имеют meta_key of публикации_даты. Все остальные элементы игнорируются и не отображаются. Я попробовал meta_query, используя отношение "или", и сравнил публикации_даты как EXISTS, а не EXISTS, но это вернуло мне 0 результатов.

Кроме того, на сайте все еще работает 3.5.2, и они не хотят обновляться.

Вот мой последний запрос, который возвращает мне сообщения, в которых настраиваемое поле publishing_date отображается в правильном порядке:

$term = get_queried_object(); // find the term of the taxonomy page we are on
$wp_query = new WP_Query( array(
'post_type' => 'resource',
'tax_query' => array(
    array(
        'taxonomy' => 'resource_types',
        'field' => 'slug',
        'terms' => $term->name,
    )), 

'meta_key' => 'publication_date',
'orderby' => 'meta_value_num',
'order' => 'DESC',
'paged' => $paged,
'posts_per_page' => '10',
));

Я также попытался использовать wpdb и выполнить SQL-запрос, но я действительно не уверен, как выполнить то, что я хочу сделать. Если бы кто-то мог мне помочь, это было бы здорово!

Заранее спасибо.

CSSgirl
источник
Удивил, что подход meta_query не сработал, но опять же, вы не можете упорядочить мета-значение с meta_query, не установив meta_key.
sanchothefat
Я думаю, что это проблема, которую я имею. Я, наконец, получил мета-запрос, работающий: 'meta_query' => array( 'relation' => 'OR', array( //check to see if date has been filled out 'key' => 'publication_date', 'compare' => '!=', 'value' => date('Y-m-d'), ), array( //if no date has been added show these posts too 'key' => 'publication_date', 'value' => date('Y-m-d'), 'compare' => 'NOT EXISTS' ) ),но порядок не работает: \
CSSgirl
да, к сожалению, упорядочение зависит от установки meta_key за пределы tax_query. Мой ответ ниже может помочь, хотя.
sanchothefat

Ответы:

19

Спасибо всем за вашу помощь!

В конце концов, приведенный ниже запрос дал мне результаты, которые я желал - чтобы показать и отсортировать записи сначала по настраиваемому полю «публикации_даты» - с сортировкой по дате, и если их было несколько для одной и той же даты (скажем, 4 помечены Июнь 2013), сортировка по названию. Затем, после прохождения всех постов, в которых указана Дата публикации, он снова будет перебирать оставшиеся посты в алфавитном порядке по заголовкам.

Это дает мне набор результатов в том же запросе и сохраняет мою нумерацию страниц:

$term = get_queried_object();
the_post();
$wp_query = new WP_Query( array(
'post_type' => 'resource',
    'tax_query' => array(
        array(
            'taxonomy' => 'resource_types',
            'field' => 'slug',
            'terms' => $term->name,
        )),
 'meta_query' => array(
       'relation' => 'OR',
        array( //check to see if date has been filled out
                'key' => 'publication_date',
                'compare' => '=',
                'value' => date('Y-m-d')
            ),
          array( //if no date has been added show these posts too
                'key' => 'publication_date',
                'value' => date('Y-m-d'),
                'compare' => 'NOT EXISTS'
            )
        ),
'meta_key' => 'publication_date',
'orderby' => 'meta_value title',
'order' => 'ASC',
'paged' => $paged,
'posts_per_page' => '10',
));
CSSgirl
источник
1
Ницца. Я никогда не думал запускать два meta_queryна одном ключе!
GhostToast
5
Для меня (с использованием WordPress 4.1.1), если я установил meta_keyего автоматически, он не включается даже с NOT EXISTS. Я действительно надеюсь, что делаю что-то не так.
Райан Тейлор
1
@RyanTaylor здесь то же самое - meta_key не должен быть установлен в запросе, чтобы это работало, но, похоже, он правильно упорядочивается по мета-значению, даже если мета-ключ не установлен.
jammypeach
2
Как и выше комментарии, для WP 4.1+ удалите или закомментируйте 'meta_key' => 'publication_date',.
MikeiLL
7

Несколько лет спустя код, размещенный CSSGirl, не работал для меня, потому что были некоторые посты, у которых не было мета-ключа, или мета-ключ был пуст, так что это то, что я должен был сделать, чтобы все посты были упорядочены по дате. и покажите те, у которых значение мета-ключа отображается первым:

$args          = array(
'post_type'   => $type,
'post_status' => 'publish',
'nopaging'    => TRUE,
'meta_query'  => array(
    'relation' => 'OR',
    array(
        'key'     => $meta_key,
        'compare' => 'NOT EXISTS',
    ),
    array(
        'relation' => 'OR',
        array(
            'key'   => $meta_key,
            'value' => 'on',
        ),
        array(
            'key'     => $meta_key,
            'value'   => 'on',
            'compare' => '!=',
        ),
    ),
),
'orderby'     => array( 'meta_value' => 'DESC', 'date' => 'DESC' ),
);
Киприан Тепес
источник
1

Я думаю, что вам нужно сделать 2 отдельных цикла. Вы можете захватить все сообщения, найденные в первом цикле, и довольно легко исключить их из дополнительного цикла:

$found_posts = array();
while($loop->have_posts()): $loop->the_post();
    // loop stuff
    $found_posts[] = get_the_id();
endwhile;

wp_reset_query();

$args = array(
    // other args
    'post__not_in' => $found_posts,
);

Затем запустите свой второй цикл.

GhostToast
источник
Пробую это сейчас, спасибо. Даст вам знать, если это работает!
CSSgirl
1
это сработало - но оно сломало нумерацию страниц - есть идеи, как заставить это работать? Вот как это выглядит сейчас:echo paginate_links( array( 'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ), 'format' => '?page=%#%', 'current' => max( 1, get_query_var('paged') ), 'total' => $publication_query->max_num_pages, 'prev_text' => __('Previous |'), 'next_text' => __('| Next'), ) );
CSSgirl
Хм. Не то, чтобы я мог думать.
GhostToast
1

Есть ли какая-то причина, по которой вы не могли принудительно установить мета-ключ публикации_даты для каждого сообщения только с пустым значением?

Таким образом, в вашем save_postдействии вы добавляете / обновляете мета-ключ независимо от того, $_POSTпусто это значение или нет.

Вам нужно будет запустить скрипт обновления, чтобы перебрать старые сообщения и добавить ключ с пустым значением, например:

add_action( 'admin_init', 'update_old_posts' );
function update_old_posts() {
    if ( ! isset( $_GET[ 'update_old_posts' ] ) )
         return;

    foreach( get_posts() as $post ) {
        if ( false === get_post_meta( $post->ID, 'publication_date', true ) ) {
             update_post_meta( $post->ID, 'publication_date', '' );
             echo "Updated {$post->post_title} <br />";
        }
    }

    die;
}

Запустите его, перейдя по ссылке http://example.com/wp-admin/?update_old_posts

Тогда вы можете использовать тот же запрос, что и у вас. Возможно, вы захотите добавить дополнительный фильтр, чтобы можно было упорядочивать по разным столбцам в разных направлениях, для меня имеет смысл отсортировать по дате в порядке убывания и заголовок в порядке возрастания.

add_filter( 'posts_orderby', 'multicolumn_orderby', 10, 2 );
function multicolumn_orderby( $orderby, $query ) {
    global $wpdb;

    // check it's the right query
    if ( $query->get( 'meta_key' ) == 'publication_date' ) {
         $orderby = "$wpdb->postmeta.meta_value+0 DESC, $wpdb->posts.post_title ASC";
    }

    return $orderby;
}
sanchothefat
источник
Хм, я не думал об этом. Я собираюсь попробовать и посмотреть, как это будет, спасибо!
CSSgirl
0

Я создал пользовательский пункт where. Я тестировал его $wp_query->requestпрямо перед основным циклом, я не очень хорошо знаю SQL, но, похоже, все заработало.

add_action('pre_get_posts', 'add_trending_sort', 11, 1);
function add_trending_sort($query){
  if(!$query->is_main_query())
    return;

  //Overwrite query arguments
  $query->set('meta_query', array(
    array(
      'key' => 'TRENDING',
      //'value' => 'asdfasdf',//may need a value for older versions of WordPress
      'compare' => 'NOT EXISTS',
    )
  ));
  $query->set('orderby', 'meta_value_num date');
  $query->set('order', 'DESC');
}

add_filter('posts_where', 'add_trending_where');
function add_trending_where($where = ''){
  global $wpdb, $wp_query;
  if(!$wp_query->is_main_query())//Not sure if this really works.  Should be OK
    return $where;

  $where .= " OR ( $wpdb->postmeta.meta_key = 'TRENDING' )";

  // Don't run this twice
  remove_filter('posts_where', 'add_trending_where');

  return $where;
}

В качестве альтернативы, вы можете установить compareна 'EXISTS'и изменить строку в add_trending_where к $where .= " OR ($wpdb->postmeta.post_id IS NULL)";. Тогда вам нужно будет только изменить значение ключа в одном месте. Опять же, эхом $wp_query->requestи поиграйте, если хотите лучше понять или подправить.

РЕДАКТИРОВАТЬ: я только заметил, что это не работает, если meta_keyзадано в запросе. Вы можете использовать, $query->set('meta_key', NULL);если вам нужно.

РЕДАКТИРОВАТЬ 2: Я получил это работая с методом выше. По некоторым причинам это не было сначала (возможно meta_key был установлен ... я не знаю).

add_action('pre_get_posts', 'add_trending_sort', 11, 1);
function add_trending_sort($query){
  // Bail if not the main "hidden" query, as opposed to a 'new WP_Query()' call
  if(!$query->is_main_query())
    return;

  // Set meta_query to get shares for orderby, and also get non-shared content.
  $query->set('meta_query', array(
    'relation' => 'OR',
    array(
      'key' => 'TRENDING',
      'compare' => 'NOT EXISTS',
    ),
    array(
      'key' => 'TRENDING',
      'compare' => 'EXISTS',
    )
  ));
  //$query->set('meta_key', NULL);
  $query->set('orderby', array('meta_value_num' => 'DESC', 'date' => 'DESC'));
}
Райан Тейлор
источник