Obtener meta_id junto con meta_key y meta_value

19 ago 2013, 23:48:26
Vistas: 21.1K
Votos: 5

¿Es posible de alguna manera obtener con get_post_meta o get_post_custom el meta_id junto con el meta_value? Por ejemplo:

$data = get_post_meta( $post_id, 'my_key' );
// devuelve esto:
array( 0 => array('myvalue1', 1002 ), 1 => array( 'myvalue2', 1003 ));

La idea básica es que, dado que puede haber múltiples meta_values para el mismo meta_key, necesitaría conocer el meta_id para poder actualizar/eliminar de forma fiable los metadatos del post.

5
Comentarios

get_post_meta(); requiere un tercer parámetro como true que estás omitiendo get_post_meta( $post_id, 'my_key', true );

Anjum Anjum
20 ago 2013 00:03:50

@Anjum El tercer parámetro no es obligatorio, es opcional. Si pasas el tercer parámetro como true obtendrás solo un valor... así que para el OP pasar ese parámetro está mal.

gmazzap gmazzap
20 ago 2013 00:06:02

@G. M lo que dice el Codex de WordPress: $single (boolean) (opcional) Si se establece como true, la función devolverá un solo resultado, como una cadena. Si es false, o no se establece, entonces la función devuelve un array de los campos personalizados. Esto puede no ser intuitivo en el contexto de arrays serializados. Si recuperas un array serializado con este método, querrás que $single sea true para obtener realmente un array deserializado. Si pasas false, o lo omites, tendrás un array de uno, y el valor en el índice 0 será la cadena serializada. Por defecto: false

Anjum Anjum
20 ago 2013 00:10:14

@Anjum es exactamente lo que dije. Pero si lees la pregunta: puede haber múltiples meta_values para el mismo meta_key entiendes que en este caso usar el 3er parámetro como true es incorrecto.

gmazzap gmazzap
20 ago 2013 00:14:19

Sí, en mi caso necesito obtener múltiples meta_values para el mismo meta_key.

ragulka ragulka
20 ago 2013 10:21:59
Todas las respuestas a la pregunta 6
0

Esta función me funcionó:

function get_complete_meta( $post_id, $meta_key ) {
  global $wpdb;
  $mid = $wpdb->get_results( $wpdb->prepare("SELECT * FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s", $post_id, $meta_key) );
  if( $mid != '' )
    return $mid;

  return false;
}

Devolverá un array de objetos como:

Array
(
    [0] => stdClass Object
        (
            [meta_id] => 1002
            [post_id] => 1
            [meta_key] => my_key
            [meta_value] => my_value
        )
    [1] => stdClass Object
        (
            [meta_id] => 1003
            [post_id] => 668
            [meta_key] => my_key
            [meta_value] => otro valor
        )
)
8 nov 2013 14:39:57
6

No conozco una función/método principal en WordPress para recuperar metadatos de publicación con la clave. Eso no quiere decir que definitivamente no exista. Puede que sí. No lo sé todo sobre WordPress, solo finjo que sí :) O quizás simplemente se me ha olvidado en este momento.

Sin embargo, el cuarto parámetro de update_post_meta sirve para asegurarte de que solo actualizas el valor que deseas actualizar en casos donde hay múltiples claves.

$prev_value
(mixed) (opcional) El valor antiguo del campo personalizado que deseas cambiar. Esto sirve para diferenciar entre varios campos con la misma clave. Si se omite, y hay múltiples filas para esta publicación y meta clave, todos los valores meta serán actualizados.

Envías el valor previamente guardado en ese cuarto parámetro y entonces solo esa entrada será actualizada.

delete_post_meta funciona de manera similar, pero con el tercer parámetro en lugar del cuarto.

20 ago 2013 00:00:08
Comentarios

@s_ha_dum ¿cómo consideras que esta respuesta está relacionada con la pregunta? El que pregunta necesita obtener el meta_id mediante una meta_key y un post_id, lo cual mi función devolverá.

Anjum Anjum
20 ago 2013 00:16:54

El OP dice: "La idea básica es que, como puede haber múltiples meta_values para la misma meta_key, tendría que conocer el meta_id para actualizar/eliminar de manera confiable el post meta". Es decir, el problema/preocupación es con la actualización confiable del post meta donde hay múltiples claves. La parte que dice "tendría que conocer el meta_id para actualizar/eliminar de manera confiable el post meta" es incorrecta. Eso no es necesario y el código núcleo de WordPress toma un enfoque diferente al problema.

s_ha_dum s_ha_dum
20 ago 2013 00:25:45

Creo que el OP tiene un problema XY en la pregunta, en otras palabras.

s_ha_dum s_ha_dum
20 ago 2013 00:26:22

Llego a una conclusión similar en mi respuesta: http://wordpress.stackexchange.com/a/110780/178

hakre hakre
20 ago 2013 00:36:54

De hecho probé esta solución, pero se siente un poco incómodo depender del meta valor cuando se trabaja con valores meta serializados. Esperaba que hubiera una forma de obtener el meta_id junto con los meta_values, para poder usar update_metadata_by_mid y delete_metadata_by_mid

ragulka ragulka
20 ago 2013 10:21:08

¿Qué es incómodo? El proceso es invisible desde tu lado. El Core hace el trabajo.

s_ha_dum s_ha_dum
20 ago 2013 16:29:55
Mostrar los 1 comentarios restantes
1

agrega este código en tu functions.php

function get_mid_by_key( $post_id, $meta_key ) {
    global $wpdb;
    $mid = $wpdb->get_var( $wpdb->prepare("SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s", $post_id, $meta_key) );
    if( $mid != '' )
    return (int) $mid;

    return false;
}

y luego llámalo donde lo necesites así

$meta_id = get_mid_by_key( tu_post_id, 'tu_meta_key' );
19 ago 2013 23:57:13
Comentarios

Eso solo funciona cuando hay una sola instancia de un meta_key dado. Fallará cuando hay múltiples meta_values con el mismo meta_key.

ragulka ragulka
20 ago 2013 10:09:49
0

Es extraño que WordPress proporcione funciones para obtener, actualizar y eliminar metadatos mediante meta_id desde la versión 3.3, pero hasta la versión 3.7 no tenga ninguna función que devuelva el meta id. Por lo tanto, utilizando las funciones principales de meta.php como referencia, implementé las siguientes funciones para poder recuperar los meta ids junto con los valores.

Solución

Utiliza la función personalizada get_post_meta_db() para obtener los ids y valores de las claves de metadatos, luego usa las funciones de WordPress update_meta() y delete_meta() para manipular los metadatos del post.

Por ejemplo:

$meta = get_post_meta_db( $post_id, 'my_key', true ); // Devuelve array( 
//   'post_id' => 5, 
//   'meta_id' = 33, 
//   'meta_key' => 'my_key', 
//   'meta_value' => 'the_value_for_my_key' );
update_meta( $meta['meta_id'], $meta['meta_key'], 'new_value' );

Aquí están las definiciones de las funciones personalizadas:

/**
 * Alternativa a get_post_meta(), para recuperar meta_ids. @see get_meta_db()
 */
function get_post_meta_db( $post_id, $meta_key = null, $single = false, $meta_val = null, $output = OBJECT ){
    return get_meta_db( 'post', $post_id, $meta_key, $meta_val, $single, $output );
}

/**
 * Alternativa a get_metadata(). Diferencias:
 *  - devuelve todos los campos de metadatos (en lugar de solo meta_values)
 *  - omite filtros/acciones de metadatos
 *  - consulta la base de datos, omitiendo la caché
 *  - devuelve meta_values sin procesar (en lugar de deserializar arrays)
 *
 * @param string $meta_type Tipo de objeto para el metadato (ej. comment, post o user)
 * @param int    $object_id ID del objeto del metadato
 * @param string $meta_key  Opcional. Clave de metadato a recuperar. Por defecto, devuelve todos los metadatos para el objeto especificado.
 * @param mixed  $meta_val  Opcional. Si se especifica, solo devuelve filas con este meta_value.
 * @param bool   $single    Opcional. Si es true, devuelve una sola fila, de lo contrario devuelve un array de filas.
 * @param string $output    Opcional. Cualquiera de las constantes ARRAY_A | ARRAY_N | OBJECT | OBJECT_K. @see wpdb::get_results()
 *
 * @return array Fila única de metadatos, array de filas, array vacío si no hay coincidencias o false si hubo un error.
 */
function get_meta_db( $meta_type, $object_id = null, $meta_key = null, $meta_val = null, $single = false, $output = OBJECT ){

    if( !$meta_type || !$table = _get_meta_table( $meta_type ) ) 
        return false;

    // Construir consulta
    global $wpdb;
    $query = $wpdb->prepare( "SELECT * FROM $table", $object_id );
    // Añadir condiciones pasadas a la consulta
    $where = array();
    if( $object_id = absint( $object_id ) )
        $where[] = $wpdb->prepare( sanitize_key( $meta_type.'_id' ).' = %d', $object_id );
    if( !empty($meta_key) )
        $where[] = $wpdb->prepare( 'meta_key = %s', wp_unslash( $meta_key ) );
    if( null !== $meta_val )
        $where[] = $wpdb->prepare( 'meta_value = %s', maybe_serialize(wp_unslash($meta_val)));
    if( !empty($where) )
        $query .= ' WHERE '.implode(' AND ', $where );
    if( $single )
        $query .= ' LIMIT 1';

    $rows = $wpdb->get_results( $query, $output );

    if( empty( $rows ) )
        return ( $single ? null : array() );

    /* 
    Descomenta esta sección para que esta función deserialice valores (como get_metadata())
    NOTA: Esto se puede implementar de manera más eficiente usando array_map
    // Deserializar meta_values serializados
    foreach( $rows as &$r ){
        $v =& ($output==ARRAY_A ? $r['meta_value'] : $output==ARRAY_N ? $r[3] : $r->meta_value );
        $v = maybe_unserialize( $v );
    } */

    return ( $single ? reset( $rows ) : $rows );
}

Notas:

  • Estas funciones consultan la base de datos, ¡úsalas con moderación!
  • Esta implementación sigue la convención vista en get_metadata_by_mid(), al no usar los pre-filtros "get_post_metadata"/"get_user_metadata" y no actualizar la caché.
  • En mi caso, solo necesitaba los datos sin procesar, por lo que a diferencia de get_metadata_by_mid(), esta implementación no deserializa los meta values.
  • Estas funciones permiten seleccionar metadatos por post_id/user_id, meta key, meta value o cualquier combinación de estos.
6 nov 2013 19:47:45
0

La idea básica es que, como puede haber múltiples valores meta (meta_values) para la misma clave meta (meta_key), necesitaría conocer el meta_id para actualizar/eliminar de manera confiable los metadatos del post.

Lo que llamas meta_id aquí técnicamente no existe en WordPress. Existe el post_id y ese también es el ID para todos los metadatos (en el lenguaje de metadatos esto es el object_id).

Junto a eso está la meta_key y como correctamente mencionas, como puede haber más de un valor por cada meta_key en el mismo object_id, existe ambigüedad porque todo depende del orden en que la base de datos presenta los valores aquí - y eso solo indirectamente, porque los valores meta también tienen su caché, el object cache.

Así que aunque puedes ver un meta_id en la base de datos, no se usa más allá de ser una clave primaria en la base de datos.

No es parte del resultado de la base de datos que se usa dentro del código PHP de WordPress en el entorno de usuario y por lo tanto no es parte de la caché de metadatos y nunca llega a las funciones de la API de metadatos (porque acceden a la base de datos a través de la API de caché de metadatos).

Lo que nos lleva a la conclusión final:

Como hablas del meta_id y solo existe en la base de datos (tabla dbprefix_postmeta), tu pregunta solo puede significar eliminar/actualizar una entrada en esa tabla. Operaciones SQL normales deberían ser suficientes.

20 ago 2013 00:33:13
0

La función principal de WordPress has_meta devuelve arrays asociativos de metadatos. Cada array de metadatos contiene el meta_id.

Retorno

(array[]) Array de arrays de metadatos para el ID de entrada dado.

  • '...$0' (array) Array asociativo de metadatos.
    • 'meta_key' (string) Clave de metadato.
    • 'meta_value' (mixed) Valor de metadato.
    • 'meta_id' (string) ID de metadato como cadena numérica.
    • 'post_id' (string) ID de entrada como cadena numérica.

Puedes actualizar y eliminar de manera confiable valores de metadatos que comparten la misma clave de metadato usando has_meta con update_metadata_by_mid y delete_metadata_by_mid.

En el ejemplo del OP, para actualizar array('myvalue1', 1002) y eliminar array('myvalue2', 1003):

$metadata = has_meta( $post_id );

foreach ( $metadata as $item ) {
    // Convertir la cadena numérica meta_id a un entero
    $meta_id    = intval( $item[ 'meta_id' ] );
    $meta_key   = $item[ 'meta_key' ];
    $meta_value = $item[ 'meta_value' ];

    if ( $meta_key === 'my_key' && $meta_value === 'myvalue1' ) {
        update_metadata_by_mid( 'post', $meta_id, 'new value' );
    } else if ( $meta_key === 'my_key' && $meta_value === 'myvalue2' ) {
        delete_metadata_by_mid( 'post', $meta_id );
    }
}

Referencia: has_meta es utilizado por el núcleo de WordPress para rellenar los campos del formulario en el panel de Campos Personalizados.

1 sept 2022 20:26:10