¿Cómo puedo crear una meta_query con una matriz como meta_field?

16

Aquí están los argumentos para mi consulta:

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

Esto funciona cuando topicses una cadena, pero no cuando es una matriz. Me gustaría que esta consulta funcione cuando topicses, por ejemplo,array( 'sports', 'nonprofit', etc. )

¿Hay alguna manera de construir meta consultas con matrices como meta_key?

mike23
fuente
Por favor aclare: ¿quiere decir que el valor almacenado de "temas" es una matriz? ¿O que el valor almacenado es una cadena y desea pasar varios términos a la consulta en una matriz?
MathSmath
@ MathSmath, quiero decir que el valor almacenado es una matriz.
mike23

Respuestas:

31

Alimentando la consulta una matriz de valores posibles

Si el valor en la base de datos es una cadena y desea alimentar la consulta con varios valores:

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

Búsqueda de un valor específico en una matriz de datos serializada

Si el valor en la base de datos es una matriz de varios temas y desea buscar un solo tema dentro de esa matriz (tenga en cuenta que una matriz en la base de datos se puede recuperar como tal, pero vive en la base de datos en forma serializada, que es un cadena también):

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

Usar 'LIKE' como el valor de comparación no es una instrucción tan clara como podría haber esperado, pero es la mejor opción.

Además de eso, su única otra opción sería recuperar todas las publicaciones que tienen los "temas" meta_key establecidos e iterar sobre ellos manualmente o, en otras palabras, verificar el valor dentro del bucle y mostrar las publicaciones en dicha condición.

Johannes Pille
fuente
14

Para salirse de la respuesta de Johannes, dado que es una matriz serializada, si está almacenando algo como la identificación del usuario (que era mi caso), es posible que deba manejarlo de manera un poco diferente.

La meta del mensaje se estaba guardando como:

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

Entonces sí, son enteros, pero a través de update_post_metaellos se guardaron como cadenas.

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

Entonces, en realidad estás haciendo una comparación ME GUSTA con la versión de cadena serializada de lo que estás buscando. Pasé un par de horas tratando de hacer que algo como esto funcionara y hasta ahora fue lo mejor que se me ocurrió.

sMyles
fuente
serialize (strval (1)) resolvió mi problema, gracias
Behzad
Encontré esta vieja respuesta por casualidad hoy. Me gusta tu adición. +1
Johannes Pille
También me encontré con esto, lo mío es que necesito obtener todas las publicaciones donde user_id no está en la matriz, pero la solución anterior no funciona, así que lo hice así: 'meta_query' => array( array( 'key' => 'my_meta_key', 'value' => ':' . $user_id . ';', 'compare' => 'NOT LIKE' ) ) porque cuando se serializan, todos los valores se guardan como: ' :valor;'
Bobz
4

Otra ligera mejora de la respuesta de @sMyles.

He tenido casos en los que las ID se han almacenado como cadenas (como cuando se toman de una entrada de formulario) y como enteros (por ejemplo update_post_meta($post_id, authorized_users', array(get_current_user_id()));). Esto es algo así como el problema bien conocido con el wp_set_object_terms()que puede usar ID de términos para establecer los términos, pero si no los convierte como enteros primero, tiene una probabilidad del 50% de crear nuevos términos con esos números como sus nombres en lugar.

Esto puede hacer que se almacenen de manera bastante diferente en una matriz serializada, como se puede ver en los extractos de tal caso de la base de datos de mi sitio de prueba:

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

Ambos de los anteriores, cuando se alimentan, se print_r()mostrarán como

Array
(
    [0] => 1
)

Para solucionar esto, realicé un pequeño ajuste al meta_queryagregar una relationy otra versión de la consulta que arrojó el valor como un entero en lugar de una cadena.

Aquí está el resultado 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'
            ),
        ),

EDITAR: Acabo de darme cuenta de que este método podría correr el riesgo de colisiones con los índices de la matriz, lo que podría permitir a alguien el acceso ilícito a los materiales si no están en la matriz, pero su ID de usuario aparece como un índice. Como tal, si bien esto funciona si tiene el problema discutido, una mejor práctica es asegurarse de que los valores que desea buscar se conviertan como cadenas antes de guardarlos para que pueda usar el método de @sMyles.

Kaji
fuente
Esta debería ser la respuesta seleccionada, la más confiable
Amin
2

Iría por la respuesta de Johannes. Sin embargo, quiero mejorar eso porque usando esa meta_query, conocerás un caso como este

tu valor es

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

cuando buscas

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

entonces el resultado devolverá 'sport' y 'sport2'.

Para arreglar eso, cambie los argumentos meta_query en

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

Es porque el valor se serializa en la base de datos, y cada elemento estará separado por punto y coma. Por lo tanto, los argumentos anteriores funcionarán

Si los elementos en el valor son número, solo necesita eliminar la comilla doble "

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

Me encontré con algo similar hoy. Tengo que consultar un campo de relación ACF (Campos personalizados avanzados) con múltiples usuarios relacionados (matriz).

Después de actualizar el campo a través de php, la consulta no funcionó. Después de actualizarlo a través de la interfaz de usuario de ACF, la consulta funcionó.

El problema era que mi código php estableció los valores de relación como valores int, la IU lo configuró como valores de cadena. Para asegurarme de que ambos funcionan, uso esta consulta ahora (ajustada al ejemplo aquí):

$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'
        ),
    )
);
Julian Stark
fuente