Is it somehow possible to get_post_meta or get_post_custom and have meta_id returned along with the meta_value? For example:

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

The basic idea is that because there may be multiple meta_values for the same meta_key, I would have to know the meta_id in order to reliably update/delete the post meta.

  • get_post_meta(); require third pram as true which you are missing get_post_meta( $post_id, 'my_key', true );
    – Anjum
    Commented Aug 19, 2013 at 21:03
  • @Anjum 3rd param is not required, is optional. if you pass 3rd param true you'll get only one value... so for OP pass that param is wrong.
    – gmazzap
    Commented Aug 19, 2013 at 21:06
  • @G. M what WordPress codex says: $single (boolean) (optional) If set to true then the function will return a single result, as a string. If false, or not set, then the function returns an array of the custom fields. This may not be intuitive in the context of serialized arrays. If you fetch a serialized array with this method you want $single to be true to actually get an unserialized array back. If you pass in false, or leave it out, you will have an array of one, and the value at index 0 will be the serialized string. Default: false
    – Anjum
    Commented Aug 19, 2013 at 21:10
  • 1
    @Anjum is exactly what I said. But if you read the question: there may be multiple meta_values for the same meta_key you understand that in this case using the 3rd param as true is wrong.
    – gmazzap
    Commented Aug 19, 2013 at 21:14
  • Yes, in my case I need to get multiple meta_values for the same meta_key.
    – ragulka
    Commented Aug 20, 2013 at 7:21

6 Answers 6


This function worked for me:

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;

it will return an array of objects like:

    [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] => another value

I don't know of a Core function/method to retrieve post meta with the key. That isn't to say that there definitively isn't one. There may be. I don't know everything about WordPress, I just pretend to :) Or maybe it has just slipped my mind right now.

However, the fourth parameter of update_post_meta is to ensure that you only update the value you want to update in cases where there are multiple keys.

(mixed) (optional) The old value of the custom field you wish to change. This is to differentiate between several fields with the same key. If omitted, and there are multiple rows for this post and meta key, all meta values will be updated.

You send the previously saved value in that fourth parameter and then only that entry is updated.

delete_post_meta operates similarly, but with the third parameter not the fourth.

  • @s_ha_dum how do you feel this answer is related to the question, asker need to get meta id by meta key and post id, which my function will be return for.
    – Anjum
    Commented Aug 19, 2013 at 21:16
  • 1
    The OP says, "The basic idea is that because there may be multiple meta_values for the same meta_key, I would have to know the meta_id in order to reliably update/delete the post meta." That is, the problem/concern is with reliably updating post meta where there are multiple keys. The part that reads "I would have to know the meta_id in order to reliably update/delete the post meta" is wrong. That is not necessary and WordPress Core code takes a different approach to the problem.
    – s_ha_dum
    Commented Aug 19, 2013 at 21:25
  • 2
    I think the OP has an XY problem in the question, in other words.
    – s_ha_dum
    Commented Aug 19, 2013 at 21:26
  • I come to a similar conclusion in my answer: wordpress.stackexchange.com/a/110780/178
    – hakre
    Commented Aug 19, 2013 at 21:36
  • I have actually tried this solution, but It just feels a bit awkward to rely on the meta value when dealing with serialized meta values. I was hoping there is a way to get the meta_id along with the meta_values, so that I could use update_metadata_by_mid and delete_metadata_by_mid
    – ragulka
    Commented Aug 20, 2013 at 7:21

add this code in your 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;

and then call where ever you want like

$meta_id = get_mid_by_key( your_post_id, 'your_meta_key' );
  • That only works when there is only one instance of a given meta_key. It will break when there are multiple meta_values with the same meta_key.
    – ragulka
    Commented Aug 20, 2013 at 7:09

It is odd that Wordpress provides functions to get, update and delete meta via meta_id since v3.3, but as of v3.7 does not have any functions that return the meta id. So, using the core functions from meta.php as reference, I implemented the below functions to be able to retrieve the meta ids along with the values.


Use the custom function below get_post_meta_db() to get the meta key ids and values, then use Wordpress' update_meta() and delete_meta() to manipulate the post meta.

For example:

$meta = get_post_meta_db( $post_id, 'my_key', true ); // Returns 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' );

Here are the custom function definitions:

 * Alternative to get_post_meta(), to retrieve 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 );

 * Alternative to get_metadata(). Differences:
 *  - returns every meta field (instead of only meta_values)
 *  - bypasses meta filters/actions
 *  - queries database, bypassing cache
 *  - returns raw meta_values (instead of unserializing arrays)
 * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
 * @param int    $object_id ID of the object metadata is for
 * @param string $meta_key  Optional. Metadata key to retrieve. By default, returns all metadata for specified object.
 * @param mixed  $meta_val  Optional. If specified, will only return rows with this meta_value.
 * @param bool   $single    Optional. If true, returns single row, else returns array of rows.
 * @param string $output    Optional. Any of ARRAY_A | ARRAY_N | OBJECT | OBJECT_K constants. @see wpdb::get_results()
 * @return array Single metadata row, array of rows, empty array if no matches, or false if there was an 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;

    // Build query
    global $wpdb;
    $query = $wpdb->prepare( "SELECT * FROM $table", $object_id );
    // Add passed conditions to query
    $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() );

    Uncomment this section to have this function unserialize values (like get_metadata())
    NOTE: This can be implemented more efficiently using array_map
    // Unserialize serialized meta_values
    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 );


  • These functions query the database, so use sparingly!
  • This implementation follows the convention seen in get_metadata_by_mid(), by not using the "get_post_metadata"/"get_user_metadata" pre-filters, and not updating the cache.
  • In my case, I only needed the raw data, so unlike get_metadata_by_mid(), this implementation does not unserialize the meta values.
  • These functions allow metadata to be selected by post_id/user_id, meta key, meta value, or any combination thereof.

The basic idea is that because there may be multiple meta_values for the same meta_key, I would have to know the meta_id in order to reliably update/delete the post meta.

What you call meta_id here technically does not exist in Wordpress. There is the post_id and that is also the id for all the meta (in meta sprak this is the object_id).

Next to that there is the meta_key and as you rightfully write, as there can be more than one value per each meta_key on the same object_id, there is ambiguity because all this depends on is the order in which the database presents values here - and that only indirect, because meta values also have their cache, the object cache.

So even you can see a meta_id in the database, it's not further used only to have a primary key in the db.

It is not part of the database result that is used within Wordpress PHP userland code and therefore it is not part of the meta-cache and therefore never makes it into the meta API functions (because they access the database via the meta cache API).

Which leads to the final conclusion:

As you talk about meta_id and it only exists in the database (dbprefix_postmeta table), your question can only mean to delete / update an entry in that table. Just normal SQL operations should suffice.


The WordPress core function has_meta returns associative arrays of meta data. Each meta data array contains the meta_id.


(array[]) Array of meta data arrays for the given post ID.

  • '...$0' (array) Associative array of meta data.
    • 'meta_key' (string) Meta key.
    • 'meta_value' (mixed) Meta value.
    • 'meta_id' (string) Meta ID as a numeric string.
    • 'post_id' (string) Post ID as a numeric string.

You can reliably update and delete meta values that share the same meta key using has_meta with update_metadata_by_mid and delete_metadata_by_mid.

In the OPs example, to update array('myvalue1', 1002) and delete array('myvalue2', 1003):

$metadata = has_meta( $post_id );

foreach ( $metadata as $item ) {
    // Convert the meta_id numeric string to an integer
    $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 );

Reference: has_meta is used by WordPress core to populate the form fields in the Custom Fields panel.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.