Consulta para ordenar primero una lista por meta clave (si existe) y muestra las publicaciones restantes sin meta clave ordenadas por título

22

Estoy trabajando en una plantilla de página de término de taxonomía personalizada donde queremos que los elementos que están conectados al término estén ordenados por una fecha de publicación (campo de fecha personalizado), y si hay varios elementos en el mismo día (formateados como AAAA-MM- DD) para luego ordenarlos por título y, finalmente, ordenar por título si el campo personalizado no se ha completado (elementos más antiguos).

Entonces, lo intenté de cientos de maneras diferentes con un WP_query y devuelve la mayoría de los resultados como los quiero, pero en este caso solo devuelve los elementos que tienen la meta_key de publishing_date. Todos los demás elementos se ignoran y no se muestran. Intenté una meta_query usando una relación de "o" y comparé la fecha de publicación como EXISTS y NOT EXISTS, pero eso arrojó 0 resultados para mí.

Además, el sitio todavía está ejecutando 3.5.2 y no quieren actualizar.

Aquí está mi consulta más reciente que me muestra las publicaciones que tienen el campo personalizado publishing_date mostrado en el orden correcto:

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

También intenté usar wpdb y ejecutar una consulta SQL, pero realmente no estoy seguro de cómo lograr lo que quiero hacer. ¡Si alguien pudiera ayudarme, eso sería increíble!

Gracias por adelantado.

CSSgirl
fuente
Sorprendido, el enfoque meta_query no funcionó, pero, de nuevo, no puede ordenar por metavalor con una meta_query sin tener establecida la meta_key.
sanchothefat
Creo que ese es el problema que estoy teniendo. Finalmente conseguí una 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' ) ),pero el orden no funciona: \
CSSgirl
sí, el pedido depende de que meta_key se establezca fuera de tax_query desafortunadamente. Sin embargo, mi respuesta a continuación podría ayudar.
sanchothefat

Respuestas:

19

¡Gracias a todos por su ayuda!

Al final, la consulta a continuación me dio los resultados que deseaba, que era mostrar y ordenar las publicaciones por un campo personalizado de "fecha_publicación" primero, ordenar por fecha y si había varios de la misma fecha (digamos, 4 marcados Junio ​​de 2013), los ordenaría por título. Luego, una vez que se ejecuta a través de todas las publicaciones que tienen la fecha de publicación completa, volverá a recorrer las publicaciones restantes, alfabéticamente por título.

Esto me da los resultados establecidos en la misma consulta y mantiene mi paginación:

$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
fuente
1
Agradable. ¡Nunca pensé en ejecutar dos meta_queryen la misma tecla!
GhostToast
55
Para mí (usando WordPress 4.1.1), si lo configuro meta_keyautomáticamente no lo incluye ni siquiera con NOT EXISTS. Realmente espero estar haciendo algo mal.
Ryan Taylor
1
@RyanTaylor es lo mismo aquí: no se debe establecer meta_key en la consulta para que esto funcione, pero parece que se ordena correctamente por valor meta incluso cuando la clave meta no está configurada.
jammypeach
2
Como los comentarios anteriores, para WP 4.1+ elimine o comente 'meta_key' => 'publication_date',.
MikeiLL
7

Pocos años después, el código publicado por CSSGirl no funcionaba para mí porque había algunas publicaciones que no tenían la metaclave o la metaclave estaba vacía, así que esto es lo que tuve que hacer para ordenar todas las publicaciones por fecha y muestre primero los que tienen un valor de metaclave:

$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' ),
);
Tepes cifrados
fuente
1

Creo que necesitarías hacer 2 bucles separados. Puede capturar todas las publicaciones encontradas en el primer bucle y excluirlas del bucle secundario con bastante facilidad:

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

Luego ejecuta tu segundo ciclo.

Tostada fantasma
fuente
Intentando esto ahora, gracias. ¡Te avisaré si funciona!
CSSgirl
1
esto funcionó, pero rompió la paginación, ¿alguna idea de cómo hacer que esto funcione? Esto es lo que parece ahora: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 No es que se me ocurra.
GhostToast
1

¿Hay alguna razón por la que no pueda hacer que exista la metaclave publishing_date para cada publicación solo con un valor vacío?

Entonces, en su save_postacción, agregaría / actualizaría la meta clave si el $_POSTvalor está vacío o no.

Tendría que ejecutar un script de actualización para recorrer sus publicaciones anteriores y agregar la clave con un valor vacío, por ejemplo:

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

Ejecútelo navegando a http://example.com/wp-admin/?update_old_posts

Entonces puede usar la misma consulta que tiene. Es posible que desee agregar un filtro adicional para permitirle ordenar por diferentes columnas en diferentes direcciones, tendría sentido para mí ordenar por fecha en orden descendente y título en orden ascendente.

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
fuente
Hmm, no pensé en eso. Voy a intentarlo y ver cómo va, ¡gracias!
CSSgirl
0

Creé una cláusula where personalizada. Lo probé usando $wp_query->requestjusto antes de mi bucle principal, realmente no conozco bien SQL, pero esto pareció hacer que las cosas funcionen.

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, podría establecer comparea 'EXISTS'y cambiar la línea en add_trending_where a $where .= " OR ($wpdb->postmeta.post_id IS NULL)";. Entonces solo tendría que cambiar el valor de la clave en un lugar. Nuevamente, repita $wp_query->requesty juegue si quiere entender esto mejor o modificarlo.

EDITAR: Acabo de notar que esto no funciona si meta_keyestá configurado en la consulta. Podrías usar $query->set('meta_key', NULL);si es necesario.

EDIT 2: Obtuve esto trabajando con el método anterior. Por alguna razón no fue al principio (tal vez se configuró meta_key ... No lo sé).

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
fuente