Ordenar publicaciones por campo personalizado y si el campo personalizado está vacío, devuelva las publicaciones restantes

2

Tengo una página de archivo ordenada por un valor numérico en un campo personalizado. Esto devuelve las publicaciones ordenadas correctamente, pero no muestra las publicaciones que no tienen un campo personalizado.

$paged = (get_query_var('paged')) ? get_query_var('paged') : 1; 
query_posts("paged=$paged&cat=7&posts_per_page=24&meta_key=custom_order&orderby=meta_value_num&order=ASC");

¿Cuál es la mejor manera de devolver las publicaciones ordenadas correctamente, seguida de cualquier publicación que no tenga un valor de campo personalizado asociado?

Editar : solo para dar más detalles: el resultado final que quiero lograr es una página de archivo de categorías que muestra primero las publicaciones específicas, seguidas del resto. Al igual que las publicaciones adhesivas, pero solo para un archivo de categoría específica.

Editar dos : estoy probando la sugerencia de Jessica y creo que ya casi llegamos.

El problema es que ahora si configuro order=ASC y luego todas las publicaciones que tienen el campo personalizado rellenado, aparecen después de las publicaciones que no tienen un valor asociado. Si configuro order=DESC , las publicaciones que tienen un valor de campo personalizado se devuelven primero, pero a la inversa. Por lo tanto, aparecería 4, 3, 2, 1 y luego el resto de las publicaciones sin valor asociado. ¿Cómo puedo corregir el orden, para que muestre 1, 2, 3, 4 y luego el resto de las publicaciones sin valor en el campo custom_order ?

He agregado lo siguiente a mis funciones.php:

function wpse_55791_custom_order($clauses)
{
    global $wp_query;

    // check for order by custom_order
    if ($wp_query->get('meta_key') == 'custom_order' && $wp_query->get('orderby') == 'meta_value_num')
    {
        // change the inner join to a left outer join, 
        // and change the where so it is applied to the join, not the results of the query
        $clauses['join'] = str_replace('INNER JOIN', 'LEFT OUTER JOIN', $clauses['join']).$clauses['where'];
        $clauses['where'] = '';
    }
    return $clauses;
}
add_filter('get_meta_sql', 'wpse_55791_custom_order', 10, 1);
function wpse_55791_custom_orderby($orderby)
{
    global $wp_query;

    // check for order by custom_order
    if ($wp_query->get('meta_key') == 'custom_order' && $wp_query->get('orderby') == 'meta_value_num')
    {
        $orderby = "{$wpdb->postmeta}.meta_value='', ".$orderby;
    }
    return $orderby;
}
add_filter('posts_orderby', 'wpse_55791_custom_orderby', 10, 1);
    
pregunta Ryan 14.06.2012 - 22:05

5 respuestas

4

Cuando especifica una meta_key, query_posts() realiza una UNIÓN INTERNA entre las tablas wp_posts y wp_postmeta. Eso significa que cualquier publicación que no tenga un valor meta para la clave que especificó nunca se devolverá en esa consulta.

Para hacer lo que necesita, debe usar la misma consulta que publicó en su pregunta, pero cambiar de orderby=meta_value a orderby=meta_value_num . Luego puedes filtrar 'get_meta_sql' para que la unión devuelva todas las publicaciones. Agregue lo siguiente a sus funciones.php:

<?php
function wpse_55791_custom_order($clauses)
{
    global $wp_query;

    // check for order by custom_order
    if ($wp_query->get('meta_key') == 'custom_order' && $wp_query->get('orderby') == 'meta_value_num')
    {
        // change the inner join to a left join, 
        // and change the where so it is applied to the join, not the results of the query
        $clauses['join'] = str_replace('INNER JOIN', 'LEFT JOIN', $clauses['join']).$clauses['where'];
        $clauses['where'] = '';
    }
    return $clauses;
}
add_filter('get_meta_sql', 'wpse_55791_custom_order', 10, 1);
?>

EDITAR: para arreglar el pedido, intente agregar esto junto con lo anterior:

<?php
function wpse_55791_custom_orderby($orderby)
{
    global $wp_query, $wpdb;

    // check for order by custom_order
    if ($wp_query->get('meta_key') == 'custom_order' && $wp_query->get('orderby') == 'meta_value_num')
    {
        $orderby = "{$wpdb->postmeta}.meta_value='', ".$orderby;
    }
    return $orderby;
}
add_filter('posts_orderby', 'wpse_55791_custom_orderby', 10, 1);
?>

EDITAR DOS - 2 bucles:

Así es como lo haría:

$paged = (get_query_var('paged')) ? get_query_var('paged') : 1; 
$ordered_posts = new WP_Query(array(
    'paged' => $paged,
    'cat' => 7,
    'posts_per_page' => 24,
    'meta_key' => 'custom_order',
    'orderby' => 'meta_value_num',
    'order' => 'ASC',
));

$unordered = new WP_Query(array(
    'cat' => 7,
    'paged' => $paged,
    'posts_per_page' => 24 - $ordered_posts->post_count,
));

if ($ordered_posts->have_posts()) :
    while ($ordered_posts->have_posts()) : $ordered_posts->the_post();
    // loop 1
    endwhile;
endif;

if ($unordered_posts->have_posts()) :
    while ($unordered_posts->have_posts()) : $unordered_posts->the_post();
    // loop 2
    endwhile;
endif;

Tenga en cuenta que si cree que alguna vez habrá más de 24 publicaciones ordenadas, la variable paginada será incorrecta para las publicaciones no ordenadas; es posible que deba establecer una variable global para realizar un seguimiento de cuántas publicaciones ordenadas / no ordenadas se han mostrado hasta el momento y usarlas para calcular los valores de $paged separados para cada tipo.     

respondido por el jessica 19.06.2012 - 20:03
2

Puede colocar los ID de publicación en una matriz y luego consultar todas las publicaciones excluyendo esas ID:

$post_ids = array();
foreach( $wp_query->posts as $post ):
    $post_ids[] = $post->ID;
endforeach;

$args = array(
    'posts_per_page' => -1,
    'post__not_in' => $post_ids
);
$remaining = new WP_Query( $args );
    
respondido por el Milo 14.06.2012 - 22:50
1

Resolví esto de una manera muy fácil, usando una matriz para ordenar, como se muestra a continuación:

$posts = get_posts(array(
                    'orderby' => array(
                        'meta_key' => 'meta_key', /* your meta key here */
                        'meta_value' => 'meta_value_num',
                        'order' => 'DESC',
                    )
            ));   

Eso debería arreglarlo :)

    
respondido por el luqita 13.03.2015 - 21:11
0

Esta es una buena solución, incluso si no me gusta nada. Es nuevamente la limitación de la consulta api de wordpress. Me encantó hacerlo con mysql en las edades antiguas ... pero a veces me meto con WP ... ya sabes

//get only ordered posts
$args = array(
    'post_type'=>'supporters',
    'order' => 'ASC',
    'orderby' => 'meta_value_num',
    'meta_key' => 'wpcf-sorting'
);
$cat_posts = new WP_Query($args);

//collect ordered post ids
$post_ids = array();
foreach( $cat_posts->posts as $post ):
    $post_ids[] = $post->ID;
endforeach;


//get only unordered posts
$args = array(
    'post_type'=>'supporters',
    'posts_per_page' => -1,
    'post__not_in' => $post_ids
);
$cat_posts_unordered = new WP_Query($args);


if ($cat_posts->have_posts() || $cat_posts_unordered->have_posts()) {   
    while ($cat_posts->have_posts()) {
        $cat_posts->the_post();

        get_template_part( 'content-supporters', get_post_format());
    }
    while ($cat_posts_unordered->have_posts()) {
        $cat_posts_unordered->the_post();

        get_template_part( 'content-supporters', get_post_format());
    }
}
    
respondido por el mitchiru 26.07.2013 - 13:05
0

En términos de facilidad y como mi solución es para el panel de administración, no se enfoca en la eficiencia. Lo que hice es cargar todas las publicaciones y luego ordenarlas usando php.

function MY_PLUGIN_get_ordered_pages_by_cat_id($cat_id) {
    $all_pages = get_posts(
                array(
                    'post_type' => 'page',
                    'cat' => $cat_id,
                    'order' => 'ASC'
                )
            );

    $pages      = [];
    $page_len   = count($all_pages);
    foreach($all_pages as $page):
        $positon        = @get_post_meta($cat_id, '_page_position', true);
        $a_pos          = !empty($positon) ? $positon : $page_len++;
        $pages[$a_pos]  = $page;
    endforeach;
    sort($pages);
    return $pages;
}

Tal vez sea útil para alguien. :)

    
respondido por el Langusten Gustel 16.04.2014 - 16:59

Lea otras preguntas en las etiquetas