Obtener meta_id junto con meta_key y meta_value
¿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.

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
)
)

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.

@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á.

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.

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

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

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

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' );

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.

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 elmeta_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.

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.
