Query para ordenar uma lista pela meta key primeiro (se existir), e mostrar as postagens restantes sem a meta key ordenada pelo título

19

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

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

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

Aqui está minha consulta mais recente que me mostra as postagens que têm o campo personalizado publication_date 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',
));

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

Obrigado antecipadamente.

    
por CSSgirl 17.12.2013 / 17:06

5 respostas

16

Obrigado a todos pela sua ajuda!

No final, a consulta abaixo me rendeu os resultados desejados - que era mostrar e classificar as postagens por um campo personalizado de "publication_date" primeiro - classificando pela data e se houvesse vários da mesma data (digamos , 4 marcado em junho de 2013), classificaria esses por título. Então, depois de percorrer todas as postagens que têm a Data de Publicação preenchida, ela repetirá as postagens restantes, alfabeticamente por título.

Isso me fornece 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',
));
    
por CSSgirl 18.12.2013 / 18:00
6

Alguns anos depois, o código postado pelo CSSGirl não estava funcionando para mim porque havia alguns posts que não tinham a meta key ou a meta key estava vazia, então é isso que eu tive que fazer para ter todos os posts ordenada por data e mostrar as que têm um valor de meta key display 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' ),
);
    
por Ciprian Tepes 26.02.2016 / 17:27
1

Acho que você precisa fazer dois loops separados. Você pode capturar todos os posts encontrados no primeiro loop e excluí-los 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.

    
por GhostToast 17.12.2013 / 17:16
0

Existe alguma razão pela qual você não possa impor a meta-chave publication_date para existir para cada postagem apenas com um valor vazio?

Portanto, na sua ação save_post , você adicionaria / atualizaria a meta-chave, independentemente de o valor $_POST estar vazio ou não.

Você teria que executar um script de atualização para fazer o loop de suas postagens 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 até enlace

Depois, você pode usar a mesma consulta que você. Você pode querer adicionar um filtro extra para permitir que você ordene por diferentes colunas em diferentes direções, faria sentido 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;
}
    
por sanchothefat 17.12.2013 / 18:25
0

Eu criei uma cláusula where personalizada. Eu testei usando $wp_query->request antes do meu loop principal, eu realmente não conheço muito bem o SQL, mas isso parecia 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;
}

Como alternativa, você pode definir compare para 'EXISTS' e alterar a linha em add_trending_where para $where .= " OR ($wpdb->postmeta.post_id IS NULL)"; . Então você só teria que alterar o valor da chave em um só lugar. Mais uma vez, echo $wp_query->request e brincar se você quiser entender melhor ou ajustar isso.

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

EDIT 2: Eu tenho esse trabalho com o método acima. Por alguma razão, não foi no início (talvez meta_key foi definido ... 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'));
}
    
por Ryan Taylor 25.03.2015 / 01:08