web-dev-qa-db-fra.com

Ordre les publications par champ personnalisé et si le champ personnalisé est vide, restituer les publications restantes

J'ai une page d'archive ordonnée par une valeur numérique dans un champ personnalisé. Cela renvoie correctement les publications ordonnées, mais n'affiche pas les publications qui n'ont pas de champ personnalisé.

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

Quel est le meilleur moyen de renvoyer correctement les publications commandées, suivies de toutes les publications auxquelles aucune valeur de champ personnalisé n'est associée?

Modifier : Juste pour élaborer - Le résultat final que je souhaite obtenir est une page d’archive des catégories dans laquelle des publications spécifiques sont affichées en premier, suivies des autres. Un peu comme des posts collants, mais seulement pour une archive de catégorie spécifique.

Edit Two : J'essaie la suggestion de Jessica et je pense que nous y sommes presque.

Le problème est que maintenant si je règle sur order=ASC, toutes les publications pour lesquelles le champ personnalisé est rempli sont affichées après les publications pour lesquelles aucune valeur n'est associée. Si je définis order=DESC, les publications qui ont une valeur de champ personnalisé sont renvoyées en premier, mais en sens inverse. Ainsi, il semblerait que 4, 3, 2, 1, puis le reste des messages sans valeur associée. Comment puis-je corriger l'ordre, de sorte qu'il affiche 1, 2, 3, 4, puis le reste des publications sans valeur dans le champ custom_order?

J'ai ajouté ce qui suit à mon functions.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);
2
Ryan

Lorsque vous spécifiez une méta_key, query_posts() effectue un INNER JOIN entre les tables wp_posts et wp_postmeta. Cela signifie que toutes les publications qui n'ont aucune méta-valeur pour la clé spécifiée ne seront jamais renvoyées dans cette requête.

Afin de faire ce dont vous avez besoin, vous devez utiliser la même requête que celle que vous avez posée dans votre question, en remplaçant orderby=meta_value par orderby=meta_value_num. Ensuite, vous pouvez filtrer 'get_meta_sql' pour que la jointure renvoie toutes les publications. Ajoutez ce qui suit à votre functions.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);
?>

EDIT: Pour corriger la commande, essayez d'ajouter ceci avec ce qui précède:

<?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);
?>

EDIT TWO - 2 boucles:

Voici comment je le ferais:

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

Notez que si vous pensez qu'il y aura plus de 24 articles commandés, la variable paginée sera fausse pour les articles non ordonnés; vous devrez peut-être définir une variable globale pour suivre le nombre de publications ordonnées/non ordonnées affichées jusqu'à présent et l'utiliser pour calculer des valeurs $paged distinctes pour chaque type.

4
jessica

Vous pouvez placer les identifiants de publication dans un tableau, puis interroger toutes les publications excluant ces identifiants:

$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 );
2
Milo

J'ai résolu ce problème très facilement, en utilisant un tableau pour la commande, comme ci-dessous:

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

Cela devrait résoudre le problème :)

1
luqita

C'est une bonne solution de contournement même si je ne l'aime pas du tout. C'est encore la limitation de l'api de requête de wordpress. J'aimais le faire avec mysql dans les vieux âges .. mais jouer avec WP est parfois..vous savez

//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());
    }
}
0
mitchiru

Pour ce qui est de la facilité et du fait que ma solution concerne le panneau d’administration, elle ne met pas l’accent sur l’efficacité. Ce que j'ai fait est de charger tous les messages, puis de les trier avec 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;
}

Peut-être que c'est utile à quelqu'un. :)

0
Langusten Gustel