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

19

Estoy trabajando en una plantilla de página de términos 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 personalizada), y si hay varios elementos en el mismo día (con formato YYYY -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 una 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 publish_date. Todos los demás elementos se ignoran y no se muestran. Probé una meta_query utilizando una relación de "o" y comparé la fecha de publicación como EXISTS y NO EXISTS, pero eso me devolvió 0 resultados.

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 publish_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, sería increíble!

Gracias de antemano.

    
pregunta CSSgirl 17.12.2013 - 17:06

5 respuestas

16

¡Gracias a todos por su ayuda!

Al final, la siguiente consulta me dio los resultados que deseaba, que eran mostrar y ordenar las publicaciones por un campo personalizado de "publish_date" primero: clasificación por fecha, y si hubiera múltiples en la misma fecha (por ejemplo, , 4 marcado junio 2013), los clasificaría por título. Luego, una vez que se hayan completado todas las publicaciones que tienen la Fecha de publicación completada, se repetirán de nuevo las publicaciones restantes, alfabéticamente por título.

Esto me da el conjunto de resultados 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',
));
    
respondido por el CSSgirl 18.12.2013 - 18:00
6

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 clave de metadatos o la clave de metadatos estaba vacía, así que esto es lo que tenía que hacer para tener todas las publicaciones. ordenados por fecha y mostrar aquellos con un valor de clave de metadatos primero:

$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' ),
);
    
respondido por el Ciprian Tepes 26.02.2016 - 17:27
1

Creo que deberías hacer 2 bucles separados. Puede capturar todas las publicaciones encontradas en el primer bucle y excluirlas del bucle secundario con la suficiente 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 bucle.

    
respondido por el GhostToast 17.12.2013 - 17:16
0

¿Existe alguna razón por la que no pueda imponer la clave de meta fecha_publicación para cada publicación solo con un valor vacío?

Entonces, en su acción save_post usted agregaría / actualizaría la clave meta, ya sea que el valor $_POST 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útalo navegando hasta enlace

Luego puedes usar la misma consulta que tienes. Si lo desea, puede agregar un filtro adicional que le permita 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;
}
    
respondido por el sanchothefat 17.12.2013 - 18:25
0

He creado una cláusula donde personalizada. Lo probé usando $wp_query->request justo antes de mi bucle principal, realmente no conozco bien el SQL, pero esto parece 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, puedes establecer compare en 'EXISTS' y cambiar la línea en add_trending_where a $where .= " OR ($wpdb->postmeta.post_id IS NULL)"; . Entonces solo tendrías que cambiar el valor de la clave en un solo lugar. Nuevamente, echo $wp_query->request y juega un poco si quieres entenderlo mejor o modifícalo.

EDITAR: Acabo de notar que esto no funciona si meta_key está configurado en la consulta. Podría usar $query->set('meta_key', NULL); si tiene que hacerlo.

EDIT 2: Conseguí esto trabajando con el método anterior. Por alguna razón, no fue al principio (quizás se haya establecido 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'));
}
    
respondido por el Ryan Taylor 25.03.2015 - 01:08

Lea otras preguntas en las etiquetas