Obtener todos los valores de una clave de campo personalizado (publicación cruzada)

15 feb 2011, 15:01:03
Vistas: 66.9K
Votos: 54

Sé cómo obtener el valor de un campo personalizado para una entrada específica.

get_post_meta($post_id, $key, $single);

Lo que necesito es obtener todos los valores asociados con una clave de campo personalizado específica, a través de todas las entradas.

¿Alguien conoce una manera eficiente de hacer esto? No quisiera tener que recorrer todos los IDs de entradas en la base de datos.

Ejemplo:

4 entradas, todas con diferentes valores para un campo personalizado llamado 'Mood'. 2 entradas tienen el valor 'feliz', 1 entrada tiene 'enojado' y 1 entrada tiene 'triste'

Quiero mostrar: a través de todas las entradas tenemos: dos autores felices, uno enojado y uno triste.

Pero para MUCHAS entradas.

Lo que estoy buscando es:

  • una función de WP para obtener esto. o
  • una consulta personalizada para obtener esto de la manera más eficiente posible.
2
Comentarios

Parece que estás usando esto como una taxonomía. ¿Por qué no simplemente (automáticamente) agregar un término a estas publicaciones al guardar? Haría las consultas mucho más fáciles.

kaiser kaiser
15 feb 2011 17:11:16

@kaiser ¡No puedo agradecerte lo suficiente por ser un genio!

user2128576 user2128576
27 oct 2016 00:24:02
Todas las respuestas a la pregunta 7
3
65

Un posible enfoque sería utilizar uno de los métodos auxiliares de la clase WPDB para realizar una consulta más refinada basada en metadatos.

Usando la función $wpdb get_col es posible devolver un array simple de datos planos.

Aquí hay una función de ejemplo que consulta la base de datos para obtener todas las publicaciones de un tipo de publicación, estado de publicación y clave de metadatos específicos (o campo personalizado para los menos técnicos).

function get_meta_values( $meta_key = '', $post_type = 'post', $post_status = 'publish' ) {
    
    global $wpdb;
    
    if( empty( $meta_key ) )
        return;
    
    $meta_values = $wpdb->get_col( $wpdb->prepare( "
        SELECT pm.meta_value FROM {$wpdb->postmeta} pm
        LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
        WHERE pm.meta_key = %s 
        AND p.post_type = %s 
        AND p.post_status = %s 
    ", $meta_key, $post_type, $post_status ) );
    
    return $meta_values;
}

Por ejemplo, si deseas averiguar qué publicaciones tienen una clave de metadatos llamada rating, para el tipo de publicación movies y almacenar esa información en una variable, un ejemplo de dicha llamada sería:

$movie_ratings = get_meta_values( 'rating', 'movies' );

Si deseas hacer algo más que imprimir esos datos en pantalla, la función implode de PHP puede condensar rápidamente el array en una cadena.

// Imprimir los valores meta separados por un salto de línea
echo implode( '<br />', get_meta_values( 'YOURKEY' ));

También puedes usar los datos devueltos para calcular cuántas publicaciones tienen los valores meta haciendo una iteración (bucle) simple sobre los datos devueltos y construyendo un array de conteos, por ejemplo:

$movie_ratings = get_meta_values( 'rating', 'movies' );
if( !empty( $movie_ratings ) ) {
    $num_of_ratings = [];
    foreach( $movie_ratings as $meta_value ) {
        $num_of_ratings[$meta_value] = isset( $num_of_ratings[$meta_value] ) ? $num_of_ratings[$meta_value] + 1 : 1;
    }
}

// Mostrar el número de valoraciones
printf( '<pre>%s</pre>', print_r( $num_of_ratings ) );  

/*
Salida:
Array(
    [5] => 10
    [9] => 2
)
es decir, hay 10 publicaciones de películas con una valoración de 5 y 2 publicaciones de películas con una valoración de 9.
*/

Esta lógica podría aplicarse a varios tipos de datos y extenderse para funcionar de muchas maneras diferentes. Espero que mis ejemplos hayan sido útiles y lo suficientemente simples de seguir.


Usar transitorios para almacenar en caché los resultados

Y aquí hay una versión actualizada que utiliza transitorios de WordPress para almacenar en caché la consulta, ya que esa parece ser la principal crítica por usar $wpdb en otras respuestas proporcionadas.

function get_meta_values( string $meta_key, string $post_type = 'post', bool $distinct = false, string $post_status = 'publish' ) {
    
    global $wpdb, $wp_post_types;
    
    if( !isset( $wp_post_types[$post_type] ) )
        // Cadena existente de WP, debe traducirse tal cual
        return __( 'Invalid post type.' ); 
    
    $transient_key = 'get_' . $wp_post_types[$post_type]->name . '_type_meta_values';
   
    $get_meta_values = get_transient( $transient_key );

    if( true === (bool)$get_meta_values )
        return $get_meta_values;
    
    $distinct = $distinct ? ' DISTINCT' : '';
    
    $get_meta_values = $wpdb->get_col( $wpdb->prepare( "
        SELECT{$distinct} pm.meta_value FROM {$wpdb->postmeta} pm 
        LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id 
        WHERE pm.meta_key = %s 
        AND p.post_type = %s 
        AND p.post_status = %s 
    ", $meta_key, $post_type, $post_status ) );
    
    set_transient( $transient_key, $get_meta_values, DAY_IN_SECONDS );

    return $get_meta_values;
}

La constante DAY_IN_SECONDS es una de las varias constantes de tiempo en segundos configuradas por WordPress.

Se actualizaron los nombres de los argumentos y variables para hacerlos más consistentes con la nomenclatura de WordPress y también se implementó DISTINCT como un parámetro opcional siguiendo el consejo de Howdy_McGee en los comentarios.

16 feb 2011 00:48:36
Comentarios

También un dato curioso para futuros lectores, si quieres obtener solo valores meta únicos - escribes DISTINCT justo después del SELECT en la función anterior. Puede ser útil.

Howdy_McGee Howdy_McGee
7 feb 2014 20:24:07

Creo que esto es extremadamente útil

Pablo S G Pacheco Pablo S G Pacheco
1 may 2017 17:54:08

¿Cómo hacer esto y que devuelva los valores ordenados? Creo que usando ORDER BY pero no logro entender cómo usarlo

efirvida efirvida
17 abr 2018 06:43:28
4
20

No es bueno ni necesario usar el global $wpdb:

// función para obtener todos los valores meta posibles de la clave meta seleccionada.
function get_meta_values( $meta_key,  $post_type = 'post' ) {

    $posts = get_posts(
        array(
            'post_type' => $post_type,
            'meta_key' => $meta_key,
            'posts_per_page' => -1,
        )
    );

    $meta_values = array();
    foreach( $posts as $post ) {
        $meta_values[] = get_post_meta( $post->ID, $meta_key, true );
    }

    return $meta_values;

}

$meta_values = get_meta_values( $meta_key, $post_type );
4 oct 2015 00:32:20
Comentarios

Este sería mi método preferido para hacerlo, en la mayoría de los casos. Realiza cinco consultas en lugar de solo una, pero, como utiliza los procedimientos estándar de WordPress para generarlas y enviarlas, cualquier caché específica de la plataforma (como el Caché de Objetos de WP Engine o algún plugin aleatorio) entrará en acción. Los datos también se almacenarán en la caché interna de WordPress durante la duración de la solicitud, por lo que no será necesario recuperarlos de la base de datos nuevamente, si se necesitan.

Andrew Dinmore Andrew Dinmore
2 jun 2017 18:33:49

También se aplicarán filtros a los datos, lo que podría ser extremadamente importante en, por ejemplo, un sitio multilingüe. Por último, dado que solo utiliza funciones estándar del núcleo de WordPress, es mucho menos probable que se rompa con una actualización futura.

Andrew Dinmore Andrew Dinmore
2 jun 2017 18:34:59

Esto podría hacerse más eficiente limitando la consulta al ID de la publicación.

Añadir: 'fields' => 'ids'

Entonces, el array de consulta se vería así:

array( 'post_type' => $post_type, 'meta_key' => $meta_key, 'posts_per_page' => -1, 'fields' => 'ids' )

Pea Pea
13 abr 2020 21:31:16

Precaución: esto también filtra los valores meta que solo existen en publicaciones no publicadas, así que asegúrate de usar el argumento 'post_status' para que esto sea una funcionalidad y no un error

jnhghy - Alexandru Jantea jnhghy - Alexandru Jantea
24 jul 2020 01:25:19
1
14

Solo me gustaría agregar un pequeño detalle al código de t31os mencionado anteriormente. Cambié "SELECT" por "SELECT DISTINCT" para eliminar entradas duplicadas cuando usé este código yo mismo.

5 jun 2011 21:52:28
Comentarios

Puedo imaginar casos donde sería válido tener múltiples valores meta del mismo valor, y por lo tanto no hice esa adición a mi código. Si quieres valores distintos, esta sería la forma de hacerlo. Adicionalmente, también podrías agregarlo como un argumento para la función (así puedes usarlo o no, según sea apropiado).

t31os t31os
24 ene 2014 20:19:02
2

Para obtener todos los valores meta por una clave meta

Consultar wp->db en el codex de WordPress

$values = $wpdb->get_col("SELECT meta_value
    FROM $wpdb->postmeta WHERE meta_key = 'yourmetakey'" );
7 sept 2013 14:07:25
Comentarios

El problema con este enfoque es la falta de especificidad, obtendrás numerosos resultados con dicha consulta, que podrían incluir borradores, elementos eliminados, entradas, páginas y cualquier otro tipo de publicación que exista. Nunca deberías consultar lo que no necesitas, aquí definitivamente se requiere especificidad.

t31os t31os
24 ene 2014 20:23:09

Si bien es cierto que podrías obtener valores de otros tipos de publicaciones y estados, hay ocasiones en las que solo necesitas los valores y no has utilizado ese meta_key en ningún otro lugar excepto donde lo necesitas. Si todos/la mayoría de los valores son únicos, esta puede ser la mejor solución.

Luke Gedeon Luke Gedeon
23 jun 2018 21:36:44
3

la forma más rápida sería una consulta SQL personalizada y no estoy seguro pero puedes intentar

$wpdb->get_results("
  SELECT posts.* , COUNT(*) 'moodcount'
  FROM $wpdb->posts as posts
  JOIN $wpdb->postmeta as postmeta
  ON postmeta.post_id = posts.ID
  AND postmeta.meta_key = 'Mood'
  GROUP BY postmeta.meta_key
");

Si algo, al menos es un comienzo.

15 feb 2011 17:01:49
Comentarios

gracias, pero ¿no deberían evitarse las consultas personalizadas "a toda costa"? Preferiría usar la capa de abstracción de WP (¿es así como se llama?)... pero claro, si no es posible...

mikkelbreum mikkelbreum
8 jun 2011 13:53:26

Las consultas personalizadas, si están escritas correctamente, pueden ser mejores y solo deberías evitarlas si no sabes lo que estás haciendo.

Bainternet Bainternet
8 jun 2011 16:07:58

Estoy de acuerdo con mwb. Las consultas personalizadas son muy útiles y prácticas, pero creo que también son mucho más pesadas para la base de datos... especialmente al usar funciones SRT.

krembo99 krembo99
10 dic 2011 05:20:54
0

No hay razón por la cual no puedas combinar el código de t31os y Bainternet para tener una sentencia preparada reutilizable (al estilo WordPress) que devuelva el conteo y los valores en una sola operación eficiente.

Es una consulta personalizada pero sigue utilizando la capa de abstracción de bases de datos de WordPress, así que, por ejemplo, no importa cuáles sean realmente los nombres de las tablas o si cambian, y al ser una sentencia preparada estamos mucho más protegidos contra ataques SQL, etc.

En este caso ya no estoy verificando el tipo de publicación y estoy excluyendo cadenas vacías:

    $r = $wpdb->get_results(  $wpdb->prepare( "
        SELECT pm.meta_value AS name, count(*) AS count  FROM {$wpdb->postmeta} pm
        LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
        WHERE pm.meta_key = '%s'
        AND pm.meta_value != '' 
        AND p.post_type = '%s'
        GROUP BY pm.meta_value
        ORDER BY pm.meta_value          
        ", $key, $type) 
        );
    return $r;

En este caso particular...

Esto devolverá un array de objetos como este:

array  
 0 => 
 object(stdClass)[359]
  public 'name' => string 'Hamish' (length=6)
  public 'count' => string '3' (length=1)
 1 => 
 object(stdClass)[360]
  public 'name' => string 'Ida' (length=11)
  public 'count' => string '1' (length=1)
 2 => 
 object(stdClass)[361]
  public 'name' => string 'John' (length=12)
  public 'count' => string '1' (length=1)
31 ene 2012 15:23:34
2

Usa lo siguiente con foreach

 $key = get_post_custom_values( 'key' );

Asume que el nombre de tu campo personalizado (custom field key) es

29 jul 2017 14:06:22
Comentarios

Ten en cuenta que esto toma por defecto la entrada actual, cuando no se especifica un post_id.

birgire birgire
29 jul 2017 14:23:46

Esto simplemente devuelve todos los campos personalizados para una sola entrada, que por defecto es la que tiene ID "0". Ten en cuenta que la documentación menciona explícitamente que "los parámetros no deben considerarse opcionales".

Husky Husky
24 feb 2022 15:24:00