Получить meta_id вместе с meta_key и meta_value

19 авг. 2013 г., 23:48:26
Просмотры: 21.1K
Голосов: 5

Возможно ли как-то получить с помощью get_post_meta или get_post_custom значение meta_id вместе с meta_value? Например:

$data = get_post_meta( $post_id, 'my_key' );
// возвращает следующее:
array( 0 => array('myvalue1', 1002 ), 1 => array( 'myvalue2', 1003 ));

Основная идея в том, что поскольку для одного meta_key может быть несколько meta_values, мне нужно знать meta_id, чтобы надежно обновлять/удалять мета-данные записи.

5
Комментарии

get_post_meta(); требует третий параметр как true, который вы пропустили get_post_meta( $post_id, 'my_key', true );

Anjum Anjum
20 авг. 2013 г. 00:03:50

@Anjum 3-й параметр не обязателен, он опционален. Если вы передадите 3-й параметр как true, вы получите только одно значение... так что для ОП передача этого параметра будет ошибкой.

gmazzap gmazzap
20 авг. 2013 г. 00:06:02

@G. M что говорит WordPress codex: $single (boolean) (optional) Если установлено в true, функция вернет один результат в виде строки. Если false или не установлено, функция вернет массив пользовательских полей. Это может быть не интуитивно понятно в контексте сериализованных массивов. Если вы получаете сериализованный массив этим методом, вам нужно установить $single в true, чтобы получить десериализованный массив. Если вы передадите false или опустите параметр, вы получите массив из одного элемента, и значение с индексом 0 будет сериализованной строкой. По умолчанию: false

Anjum Anjum
20 авг. 2013 г. 00:10:14

@Anjum именно то, что я сказал. Но если прочитать вопрос: для одного meta_key может быть несколько meta_values, становится понятно, что в этом случае использование третьего параметра как true ошибочно.

gmazzap gmazzap
20 авг. 2013 г. 00:14:19

Да, в моем случае мне нужно получить несколько meta_values для одного и того же meta_key.

ragulka ragulka
20 авг. 2013 г. 10:21:59
Все ответы на вопрос 6
0

Эта функция сработала для меня:

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;
}

Она вернет массив объектов вида:

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] => another value
        )
)
8 нояб. 2013 г. 14:39:57
6

Я не знаю о существовании в ядре WordPress функции/метода для получения метаданных записи по ключу. Это не значит, что такой функции точно нет. Возможно, она существует. Я не знаю всего о WordPress, я просто делаю вид :) Или, может быть, я просто не могу вспомнить её сейчас.

Однако, четвертый параметр функции update_post_meta предназначен для того, чтобы гарантировать обновление только нужного значения в случаях, когда существует несколько записей с одинаковым ключом.

$prev_value
(mixed) (необязательный) Старое значение произвольного поля, которое вы хотите изменить. Это позволяет различить несколько полей с одинаковым ключом. Если параметр опущен, и существует несколько строк для этой записи и мета-ключа, все мета-значения будут обновлены.

Вы передаете ранее сохраненное значение в этом четвертом параметре, и тогда обновится только соответствующая запись.

Функция delete_post_meta работает аналогично, но с третьим параметром вместо четвертого.

20 авг. 2013 г. 00:00:08
Комментарии

@s_ha_dum как вы считаете, какое отношение этот ответ имеет к вопросу? Автору нужно получить meta_id по meta_key и post_id, что и будет возвращать моя функция.

Anjum Anjum
20 авг. 2013 г. 00:16:54

Автор вопроса пишет: "Основная идея в том, что поскольку для одного meta_key может быть несколько meta_values, мне нужно знать meta_id, чтобы надежно обновлять/удалять метаданные записи." То есть проблема/озабоченность связана с надежным обновлением метаданных при наличии нескольких ключей. Часть, где говорится "мне нужно знать meta_id, чтобы надежно обновлять/удалять метаданные записи" - неверна. Это не обязательно, и WordPress Core использует другой подход к решению этой проблемы.

s_ha_dum s_ha_dum
20 авг. 2013 г. 00:25:45

Я считаю, что у автора вопроса проблема XY, другими словами.

s_ha_dum s_ha_dum
20 авг. 2013 г. 00:26:22

Я прихожу к аналогичному выводу в своем ответе: http://wordpress.stackexchange.com/a/110780/178

hakre hakre
20 авг. 2013 г. 00:36:54

Я действительно пробовал это решение, но кажется несколько неудобным полагаться на значение meta при работе с сериализованными meta значениями. Я надеялся, что есть способ получить meta_id вместе с meta_values, чтобы можно было использовать update_metadata_by_mid и delete_metadata_by_mid

ragulka ragulka
20 авг. 2013 г. 10:21:08

Что в этом неудобного? Процесс невидим с вашей стороны. Ядро выполняет всю работу.

s_ha_dum s_ha_dum
20 авг. 2013 г. 16:29:55
Показать остальные 1 комментариев
1

Добавьте этот код в ваш 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;
}

и затем вызывайте где угодно, например

$meta_id = get_mid_by_key( your_post_id, 'your_meta_key' );
19 авг. 2013 г. 23:57:13
Комментарии

Это работает только тогда, когда существует только один экземпляр данного meta_key. Это сломается, если есть несколько meta_values с одинаковым meta_key.

ragulka ragulka
20 авг. 2013 г. 10:09:49
0

Странно, что WordPress предоставляет функции для получения, обновления и удаления метаданных по meta_id начиная с версии 3.3, но по состоянию на версию 3.7 не имеет функций, возвращающих meta id. Поэтому, используя основные функции из meta.php в качестве примера, я реализовал приведенные ниже функции для возможности получения meta id вместе со значениями.

Решение

Используйте пользовательскую функцию get_post_meta_db() для получения идентификаторов и значений мета-ключей, а затем функции WordPress update_meta() и delete_meta() для управления метаданными записи.

Например:

$meta = get_post_meta_db( $post_id, 'my_key', true ); // Возвращает массив( 
//   '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' );

Вот определения пользовательских функций:

/**
 * Альтернатива get_post_meta(), для получения 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 );
}

/**
 * Альтернатива get_metadata(). Отличия:
 *  - возвращает все поля метаданных (вместо только meta_values)
 *  - обходит фильтры/действия метаданных
 *  - запрашивает базу данных, минуя кеш
 *  - возвращает сырые meta_values (без преобразования сериализованных массивов)
 *
 * @param string $meta_type Тип объекта метаданных (например, comment, post или user)
 * @param int    $object_id ID объекта метаданных
 * @param string $meta_key  Опционально. Ключ метаданных для получения. По умолчанию возвращает все метаданные указанного объекта.
 * @param mixed  $meta_val  Опционально. Если указано, возвращает только строки с этим значением meta_value.
 * @param bool   $single    Опционально. Если true, возвращает одну строку, иначе массив строк.
 * @param string $output    Опционально. Любая из констант ARRAY_A | ARRAY_N | OBJECT | OBJECT_K. @see wpdb::get_results()
 *
 * @return array Одна строка метаданных, массив строк, пустой массив при отсутствии совпадений или false при ошибке.
 */
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;

    // Создание запроса
    global $wpdb;
    $query = $wpdb->prepare( "SELECT * FROM $table", $object_id );
    // Добавление условий в запрос
    $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() );

    /* 
    Раскомментируйте этот раздел для автоматического преобразования сериализованных значений (как в get_metadata())
    ПРИМЕЧАНИЕ: Это можно реализовать более эффективно с помощью array_map
    // Преобразование сериализованных 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 );
}

Примечания:

  • Эти функции выполняют запросы к базе данных, поэтому используйте их умеренно!
  • Эта реализация следует соглашению, используемому в get_metadata_by_mid(), не применяя предварительные фильтры "get_post_metadata"/"get_user_metadata" и не обновляя кеш.
  • В моем случае требовались только сырые данные, поэтому, в отличие от get_metadata_by_mid(), эта реализация не преобразует сериализованные значения meta.
  • Эти функции позволяют выбирать метаданные по post_id/user_id, meta key, meta value или любой их комбинации.
6 нояб. 2013 г. 19:47:45
0

Основная идея в том, что поскольку может быть несколько значений meta_value для одного и того же meta_key, мне нужно знать meta_id, чтобы надежно обновлять/удалять метаданные записи.

То, что вы называете meta_id, технически не существует в WordPress. Есть post_id, и это же идентификатор для всех метаданных (в терминах мета-системы это object_id).

Помимо этого есть meta_key, и, как вы правильно отметили, поскольку для одного object_id может быть несколько значений для каждого meta_key, возникает неоднозначность, потому что все зависит от порядка, в котором база данных представляет эти значения — и то лишь косвенно, так как метаданные также имеют свой кеш — object cache.

Даже если вы видите meta_id в базе данных, он дальше не используется, только как первичный ключ в БД.

Он не является частью результата запроса, который используется в PHP-коде WordPress на уровне пользователя, поэтому не входит в мета-кеш и никогда не попадает в API функций метаданных (потому что они обращаются к базе данных через API мета-кеша).

Что приводит нас к окончательному выводу:

Поскольку вы говорите о meta_id, который существует только в базе данных (таблица dbprefix_postmeta), ваш вопрос может означать только удаление/обновление записи в этой таблице. Для этого достаточно обычных SQL-операций.

20 авг. 2013 г. 00:33:13
0

Основная функция WordPress has_meta возвращает ассоциативные массивы метаданных. Каждый массив метаданных содержит meta_id.

Возвращаемое значение

(array[]) Массив массивов метаданных для указанного ID записи.

  • '...$0' (array) Ассоциативный массив метаданных.
    • 'meta_key' (string) Мета-ключ.
    • 'meta_value' (mixed) Мета-значение.
    • 'meta_id' (string) ID метаданных в виде строки с числом.
    • 'post_id' (string) ID записи в виде строки с числом.

Вы можете надежно обновлять и удалять мета-значения с одинаковыми мета-ключами, используя has_meta вместе с update_metadata_by_mid и delete_metadata_by_mid.

В примере автора вопроса, чтобы обновить array('myvalue1', 1002) и удалить array('myvalue2', 1003):

$metadata = has_meta( $post_id );

foreach ( $metadata as $item ) {
    // Конвертируем строку meta_id в целое число
    $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 );
    }
}

Справка: has_meta используется в ядре WordPress для заполнения полей формы в панели "Произвольные поля".

1 сент. 2022 г. 20:26:10