web-dev-qa-db-fra.com

Ordonner les postes en fonction de l'ordre défini par l'utilisateur pour les méta-valeurs?

J'ai mis en place des CPT et en stockant une méta clé/val pour chacun d'eux. Lorsque je reçois ces publications, je dois les classer en fonction de la méta-valeur, mais l'ordre des méta-valeurs sera défini dans un tableau par moi . Le classement par défaut des valeurs méta est alphabétique ou numérique , ce que je ne souhaite pas.

Je vais l'expliquer dans un exemple:

Post 1 =>
Meta key: Fruit
Meta value: Apple

Post 2 =>
Meta key: Fruit
Meta value: Melon

Post 3 =>
Meta key: Fruit
Meta value: Guava

Post 4 =>
Meta key: Fruit
Meta value: Banana

Je reçois la commande d'une source externe et je souhaite obtenir les publications dans cet ordre. Exemple: je reçois une commande dans un tableau: ['Apple', 'Banana', 'Guava', 'Melon']. Quand je vais chercher les CPT, je dois les avoir dans cet ordre. (Ignorez l'ordre alphabétique, j'essaie juste de donner un exemple général).

Comment y parvenir en utilisant un meta_query ou toute autre solution?

S'il existe un fil existant, veuillez me rediriger vers celui-ci.

2
Rutwick Gangurde

Ma solution proposée a déjà été postée par @cybmeta (+1), mais je l’ajoute quand même, puisqu’elle le traite de manière générale; -)

De la même manière, les paramètres WP_Query:

'post__in' => [1,2,3],
'orderby' => 'post__in'

donner à utiliser l'ordre défini personnalisé:

ORDERBY FIELD( wp_posts.ID, 1, 2, 3 )

nous pouvons définir notre propre méta-commande en utilisant:

'meta__in' => [ 'Apple', 'orange', 'banana' ],
'orderby' => 'meta__in'

pour obtenir la partie SQL suivante:

ORDERBY FIELD( wp_postmeta.meta_value, 'Apple', 'orange', 'banana' )

Nous définissons d’abord notre propre version de la fonction d’assistance wp_parse_id_list().

/**
* Note that this function is based on the core wp_parse_id_list() function.
* Clean up an array, comma- or space-separated list of string keys.
*
* @uses sanitize_key()
* @param array|string $list List of keys.
* @return array Sanitized array of keys.
*/
function wpse_parse_meta_list( $list )
{
    if ( ! is_array( $list ) )
        $list = preg_split('/[\s,]+/', $list);

    return array_unique( array_map( 'sanitize_key', $list ) );
}   

Plugin de démonstration

Ensuite, nous construisons le plugin de démonstration suivant, pour ajouter un support pour la commande 'meta__in', en WP_Query:

<?php
/**
 * Plugin Name: Support for order by meta__in in WP_Query
 */

add_filter( 'posts_orderby', function ( $orderby, \WP_Query $q )
{
    if( $meta__in = $q->get( 'meta__in' ) )
    {
        if( is_array( $meta__in ) && ! empty( $meta__in ) )
        {
            global $wpdb;   

            // Transform the meta__in array into a comma separated strings of keys
            // Example [ 'Apple', 'banana' ] --> "Apple", "banana"
            $list = '"' . join( '","', wpse_parse_meta_list( $meta__in ) ) . '"';           

            // Override the orderby part with custom ordering:
            $orderby = " FIELD( {$wpdb->postmeta}.meta_value, {$list} ) ";
        }
    }
    return $orderby;
}, 10, 2 );

/**
 * Note that this function is based on the core wp_parse_id_list() function.
 * Clean up an array, comma- or space-separated list of string keys.
 *
 * @uses sanitize_key()
 * @param array|string $list List of keys.
 * @return array Sanitized array of keys.
 */
function wpse_parse_meta_list( $list )
{
    if ( ! is_array( $list ) )
        $list = preg_split('/[\s,]+/', $list);

    return array_unique( array_map( 'sanitize_key', $list ) );
}   

où nous avons ajouté la fonction d'assistance dans le plugin.

Remarques

Nous utilisons uniquement le paramètre 'meta__in' pour la commande et non pour les restrictions supplémentaires WHERE, comme c'est le cas avec le paramètre 'post__in'. Mais cela pourrait être une extension intéressante ;-)

Notez également que get_posts(), qui n'est qu'un wrapper WP_Query, a le paramètre suivant configuré par défaut:

'suppress_filters' => true 

c'est-à-dire qu'il n'accepte pas les filtres posts_* par défaut.

Ainsi, si vous ne pouvez pas utiliser WP_Query ou get_posts() avec le suppress_filters => false, vous aurez alors besoin d’une autre approche, par exemple. suggéré par @PieterGoosen.

2
birgire

Si la valeur du champ méta est une valeur unique (non sérialisée), ce filtre pourrait fonctionner:

add_filter( 'posts_orderby', 'custom_posts_orderby' );
function custom_posts_orderby( $orderby_statement ) {

    $custom_order = array( 'Apple', 'Banana', 'Guava', 'Melon' );

    $custom_order = implode ( ", ", $custom_order );

    $orderby_statement = "FIELD( meta_value, " . $custom_order . " )";

    return $orderby_statement;

}

Notez que cela affectera toutes les requêtes, vous devez donc définir les conditions pour appliquer le filtre ou non.

Vous pouvez voir plus d'exemples pour construire le _ORDER BY FIELD() statemnet dans ce post .

1
cybmeta

Comme je l'ai dit, à mon humble avis, avec votre meilleure option pour ce dont vous avez besoin, vous aurez usort() pour trier le tableau retourné

Voici une théorie non testée

$sortorder = ['Apple', 'Banana', 'Guava', 'Melon'];
$args = [
    'meta_query' => [
        [
            'key'   => 'Fruit',
            'value' => $sortorder
        ]
    ],
];
$q = new WP_Query( $args );

@usort( $q->posts, function( $a, $b ) use ( $sortorder  ) {
    // Get the meta values from the two posts to be compared
    $array_a = get_post_meta( $a->ID, 'Fruit', true );
    $array_b = get_post_meta( $b->ID, 'Fruit', true );

    // Reverse our $sortorder, key/value becomes value/key
    $flipped_order = array_flip( $sortorder );

    // Let start our sorting
    // If our meta values are the same order by date
    if ( $flipped_order[$array_a] != $flipped_order[$array_b] ) {
        return $flipped_order[$array_a] - $flipped_order[$array_b] // Swop around to reverse ordering
    } else {
        return $a->post_date < $b->post_date; // Change to > if you need oldest posts first
    }
});

// Run your loop normally

MODIFIER

Je n'ai apporté aucune sécurité à mon code. Pour vous assurer que $sortorder est un tableau valide, vous devez alors nettoyer et valider les valeurs avant de les utiliser pour éviter les codes malveillants.

Vous pouvez également effectuer cette opération pour la requête principale. La seule chose à faire est d’envelopper la fonction usort() dans le filtre the_posts, puis d’utiliser $posts à la place de $q->posts

1
Pieter Goosen