web-dev-qa-db-fra.com

Comment créer une méta_query avec un tableau sous la forme meta_field?

Voici les arguments pour ma requête:

$args = array(
    'post_type' => 'news',
    'meta_query' => array(
        array(
            'key' => 'topics',
            'value' => 'sports',
        )
    )
);

Cela fonctionne lorsque topics est une chaîne, mais pas lorsqu'il s'agit d'un tableau. J'aimerais que cette requête fonctionne lorsque topics est par exemple array( 'sports', 'nonprofit', etc. )

Est-il possible de créer des méta-requêtes avec des tableaux en tant que méta_key?

13
mike23

Fournir à la requête un tableau de valeurs possibles

Si la valeur dans la base de données est une chaîne et que vous souhaitez alimenter la requête en plusieurs valeurs:

$args = array(
    'post_type' => 'news',
    'meta_query' => array(
        array(
            'key' => 'topics',
            'value' => array ( 'sports', 'nonprofit', 'community' ),
            'compare' => 'IN'
        )
    )
);

Recherche d'une valeur spécifique dans un tableau de données sérialisé

Si la valeur de la base de données est un tableau de plusieurs sujets et que vous souhaitez rechercher un seul sujet dans ce tableau (notez qu'un tableau de la base de données peut être récupéré en tant que tel, mais qu'il réside dans la base de données sous forme sérialisée, qui est une chaîne également):

$args = array(
    'post_type' => 'news',
    'meta_query' => array(
        array(
            'key' => 'topics',
            'value' => 'sports',
            'compare' => 'LIKE'
        )
    )
);

Utiliser "LIKE" comme valeur de comparaison n’est pas une instruction aussi précise que vous l’auriez espéré, mais c’est la meilleure option.

À côté de cela, votre seule autre option serait de récupérer tous les articles qui ont le meta_key "topics" défini et de les parcourir manuellement ou, en d'autres termes, de vérifier la valeur dans la boucle et d'afficher les articles sur ladite condition. .

27
Johannes Pille

Pour sortir de la réponse de Johannes, puisqu'il s'agit d'un tableau sérialisé, si vous stockez quelque chose comme les identifiants d'utilisateur (ce qui était mon cas), vous devrez peut-être le gérer un peu différemment.

Post meta était sauvegardé comme:

array( "1", "23", "99");

Donc oui, ce sont des entiers, mais ils ont été sauvegardés sous forme de chaînes via update_post_meta.

'meta_query' => array(
            array(
                    'key'     => 'my_meta_key',
                    'value'   => serialize( strval( 1 ) ),
                    'compare' => 'LIKE'
                )
            )

Vous faites donc une comparaison similaire avec la version chaîne sérialisée de ce que vous recherchez. J'ai passé quelques bonnes heures à essayer d'obtenir quelque chose comme ça et jusqu'à présent, c'était le meilleur que je pouvais trouver.

12
sMyles

Une autre légère amélioration par rapport à la réponse de @sMyles.

J'ai eu des cas où les identifiants ont été stockés à la fois en tant que chaînes (telles que celles extraites d'une entrée de formulaire) et en tant qu'entiers (par exemple, update_post_meta($post_id, authorized_users', array(get_current_user_id()));). C'est un peu comme le problème bien connu avec wp_set_object_terms() où vous pouvez utiliser des identifiants de termes pour définir les termes, mais si vous ne les exprimez pas sous forme d'entiers, vous avez environ 50% de chances de créer de nouveaux termes avec ces nombres. noms à la place.

Cela peut entraîner leur stockage très différemment dans un tableau sérialisé, comme le montrent les extraits d'un tel cas de la base de données de mon site de test:

a:1:{i:0;s:1:"1";} // 's' for 'string', also note the double quotes
a:1:{i:0;i:1;} // 'i' for 'integer', no quotes

Les deux éléments ci-dessus, lorsqu’ils sont alimentés par print_r(), seront rendus comme suit:

Array
(
    [0] => 1
)

Pour résoudre ce problème, j'ai légèrement modifié le meta_query en ajoutant une variable relation et une autre version de la requête qui convertit la valeur en entier, au lieu d'une chaîne.

Voici le résultat final:

        'meta_query' => array(
            'relation' => 'OR', // Lets it know that either of the following is acceptable
            array(
                'key' => 'bcm_enm_authorized_users',
                'value'   => serialize(strval(get_current_user_id())), // Saved as string
                'compare' => 'LIKE'
            ),
            array(
                'key' => 'bcm_enm_authorized_users',
                'value'   => serialize(intval(get_current_user_id())), // Saved as integer
                'compare' => 'LIKE'
            ),
        ),

EDIT: Je viens de me rendre compte que cette méthode risquait des collisions avec des index de tableaux, ce qui pourrait permettre à une personne d'accéder illégalement à des matériaux s'ils ne sont pas dans le tableau, mais leur ID utilisateur apparaît sous forme d'index. En tant que tel, alors que works si le problème est discuté, il est préférable de s’assurer que les valeurs que vous souhaitez rechercher sont converties en chaînes avant de les enregistrer, de sorte que vous puissiez utiliser la méthode de @sMyles. .

3
Kaji

Je voudrais aller pour la réponse de Johannes. Cependant, je veux améliorer cela car en utilisant cette méta_query, vous rencontrerez un cas comme celui-ci

votre valeur est

array('sports','movies', 'sports2');

quand tu cherches

$args = array(
    'post_type' => 'news',
    'meta_query' => array(
        array(
            'key' => 'topics',
            'value' => 'sports',
            'compare' => 'LIKE'
        )
    )
);

alors le résultat retournera à la fois 'sport' et 'sport2'.

Pour résoudre ce problème, modifiez les arguments de meta_query en

$args = array(
    'post_type' => 'news',
    'meta_query' => array(
        array(
            'key' => 'topics',
            'value' => 'sports";',
            'compare' => 'LIKE'
        )
    )
);

C'est parce que la valeur est sérialisée dans la base de données, et chaque élément sera séparé par un point-virgule. Ainsi, les arguments ci-dessus fonctionneront

Si les éléments de la valeur sont des nombres, il vous suffit de supprimer le guillemet double "

$args = array(
        'post_type' => 'news',
        'meta_query' => array(
            array(
                'key' => 'topics',
                'value' => '1;',
                'compare' => 'LIKE'
            )
        )
    );
2
Ha Doan Ngoc

Je me suis traîné avec quelque chose de similaire aujourd'hui. Je dois interroger un champ de relation ACF (Advanced Custom Fields) avec plusieurs utilisateurs associés (tableau).

Après la mise à jour du champ via php, la requête ne fonctionnait pas. Après la mise à jour via l'interface utilisateur ACF, la requête a fonctionné.

Le problème était que mon code php définissait les valeurs de relation comme étant des valeurs int, l'interface utilisateur le définissait comme valeurs de chaîne. Pour m'assurer que les deux fonctionnent, j'utilise cette requête maintenant (adapté à l'exemple ici):

$args = array(
    'post_type' => 'news',
    'meta_query' => array(
        'relation' => 'OR',
        array(
            'key' => 'topics',
            'value' => '1;',  // works for int-array
            'compare' => 'LIKE'
        ),
        array(
            'key' => 'topics',
            'value' => '"1"',  // works for string-array
            'compare' => 'LIKE'
        ),
    )
);
1
Julian Stark