Consulta para classificar uma lista por meta-chave primeiro (se houver) e mostrar as postagens restantes sem a meta-chave ordenada por título

22

Estou trabalhando em um modelo de página de termo de taxonomia personalizado em que queremos que os itens conectados ao termo sejam classificados por uma data de publicação (campo de data personalizado) - e se houver vários itens no mesmo dia (formatado como AAAA-MM- DD) para classificá-las por título e, finalmente, classificar por título, se o campo personalizado não tiver sido preenchido (itens mais antigos).

Então, tentei centenas de maneiras diferentes com um WP_query e ele retornou a maioria dos resultados como eu os desejava - mas, neste caso, está retornando apenas os itens que possuem a meta_key de publicação_data. Todos os outros itens estão sendo ignorados e não são exibidos. Eu tentei uma meta_query usando uma relação de "ou" e comparei a publicação_data como EXISTS e NOT EXISTS, mas isso retornou 0 resultados para mim.

Além disso, o site ainda está executando o 3.5.2 e eles não desejam atualizar.

Aqui está minha consulta mais recente que mostra as postagens que têm o campo personalizado de publicação_data exibido na ordem correta:

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

Também tentei usar o wpdb e executar uma consulta SQL, mas realmente não sei como realizar o que quero fazer isso. Se alguém pudesse me ajudar, isso seria incrível!

Desde já, obrigado.

CSSgirl
fonte
Surpreendeu que a abordagem meta_query não funcionasse, mas, novamente, você não pode solicitar pelo valor meta com uma meta_query sem ter o meta_key definido.
Sanchothefat
Eu acho que esse é o problema que estou tendo. Finalmente consegui uma meta consulta funcionando: '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' ) ),mas a ordem não está funcionando: \
CSSgirl
sim, a ordem depende da meta_key ser definida fora da tax_query, infelizmente. Minha resposta abaixo pode ajudar.
Sanchothefat

Respostas:

19

Obrigado a todos por sua ajuda!

No final, a consulta abaixo obteve os resultados que eu desejava - que era para mostrar e classificar as postagens por um campo personalizado de "publicação_data" primeiro - classificando pela data e se houvesse várias da mesma data (por exemplo, 4 marcadas Junho de 2013), os classificaria por título. Depois, após executar todas as postagens que têm a Data de Publicação preenchida, percorrerá novamente as postagens restantes, em ordem alfabética por título.

Isso recebe os resultados definidos na mesma consulta e mantém minha paginação:

$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
fonte
1
Agradável. Eu nunca pensei em executar dois meta_queryna mesma chave!
GhostToast
5
Para mim (usando o WordPress 4.1.1), se eu configurá- meta_keylo automaticamente, não o incluirei NOT EXISTS. Eu realmente espero que esteja fazendo algo errado.
Ryan Taylor
1
@RyanTaylor o mesmo aqui - meta_key não deve ser definido na consulta para que isso funcione, mas parece que ele deve ser ordenado corretamente por valor meta, mesmo quando a meta chave não está definida.
jammypeach
2
Como os comentários acima, para o WP 4.1+, remova ou comente 'meta_key' => 'publication_date',.
21716 MikeiLL
7

Poucos anos depois, o código postado por CSSGirl não estava funcionando para mim porque havia algumas postagens que não tinham a meta-chave ou a meta-chave estava vazia, então era isso que eu precisava fazer para ter todas as postagens ordenadas por data e mostre os que apresentam um valor de meta-chave primeiro:

$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' ),
);
Ciprian Tepes
fonte
1

Eu acho que você precisaria fazer 2 loops separados. Você pode capturar todas as postagens encontradas no primeiro loop e excluí-las do loop secundário com bastante facilidade:

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

Em seguida, execute seu segundo loop.

GhostToast
fonte
Tentando isso agora, obrigado. Avisará se funciona!
CSSgirl
1
isso funcionou - mas quebrou a paginação - alguma idéia de como fazer isso funcionar? Aqui está o que parece agora: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
Hmm. Não que eu possa pensar.
GhostToast
1

Existe algum motivo para que você não possa impor a meta-chave publicação_data a existir para cada postagem apenas com um valor vazio?

Portanto, em sua save_postação, você adicionaria / atualizaria a meta-chave, independentemente de o $_POSTvalor estar vazio ou não.

Você precisaria executar um script de atualização para percorrer as postagens mais antigas e adicionar a chave com um valor vazio, por exemplo:

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

Execute-o navegando para http://example.com/wp-admin/?update_old_posts

Então você pode usar a mesma consulta que você possui. Convém adicionar um filtro extra para permitir que você ordene por colunas diferentes em direções diferentes; faria sentido para mim classificar por data em ordem decrescente e título em ordem crescente.

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
fonte
Hmm, eu não pensei nisso. Vou tentar e ver como vai, obrigado!
CSSgirl
0

Eu criei uma cláusula where personalizada. Eu testei usando $wp_query->requestantes do meu loop principal, eu realmente não conheço SQL tão bem, mas isso pareceu fazer as coisas funcionarem.

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

Alternativamente, você pode definir comparea 'EXISTS'e altere a linha em add_trending_where para $where .= " OR ($wpdb->postmeta.post_id IS NULL)";. Então você só precisa alterar o valor da chave em um só lugar. Mais uma vez, ecoe $wp_query->requeste divirta-se, se você quiser entender isso melhor ou ajustá-lo.

Edição: Acabei de perceber que isso não funciona se meta_keyestiver definido na consulta. Você pode usar $query->set('meta_key', NULL);se precisar.

Edição 2: eu tenho isso trabalhando com o método acima. Por alguma razão, não foi a princípio (talvez meta_key tenha sido configurada ... eu não sei).

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'));
}
Ryan Taylor
fonte