Как запросить сообщения по частичному мета-ключу?

9

У меня есть функция, которая сохраняет статус «как» для поста как мета поста. Я хочу связать это «лайк» с пользователем, которому он понравился, поэтому я настраиваю настраиваемое поле с именем «like_status_ {user_id}» (где {user_id} - идентификатор текущего пользователя, вошедшего в систему), которое я сохраняю как 0 или 1. Так что для поста с несколькими «лайками» в БД будет несколько мета-значений, которые настроены так:

'meta_key' = 'like_status_0'
'meta_value' = 1
'meta_key' = 'like_status_2'
'meta_value' = 1
'meta_key' = 'like_status_34'
'meta_value' = 1

....и так далее.

На определенном посте потенциально могут быть тысячи лайков. Как бы я запустил запрос, показывающий, нравится ли кому-то еще этот пост?

Я думал что-то вроде этого:

$query = new WP_Query(array(
    'meta_key' => 'like_status_{user_id}',
    'meta_value' => 1,
));

Я пытаюсь разослать уведомление всем, кому понравился пост, когда кому-то еще нравится этот пост ... что-то вроде: "Эй, кому-то еще понравился этот пост, который вам понравился. Вы должны проверить его!" Но мне нужен способ узнать, понравился ли кому-то еще этот пост, и если да, то кем он будет, чтобы я мог уведомить их.

Если это невозможно, не могли бы вы предложить лучший способ хранения этих данных в виде post_meta, сохраняя при этом эффективность быстрого обновления статуса одного пользователя в сообщении?

codescribblr
источник

Ответы:

6

К сожалению , вы не можете выполнить , meta_queryиспользуя LIKEсравнение по meta_keyстоимости при использовании WP_Query. Я был на этом пути ...

Вместо этого у вас есть пара других опций, если вы хотите поддерживать такие же отношения статуса, как мета публикации, а не мета пользователя или мета в пользовательской таблице.

Опция 1

  • не требует модификации вашей мета-схемы
  • использует wpdbкласс для выполнения пользовательского запроса

Пример:

//when a user likes a post...
$current_user_id = get_current_user_id();
add_post_meta($current_user_id, "like_status_{$current_user_id}", 1, false);

//later in the request...
global $wpdb;

$results = $wpdb->get_results(
    "
    SELECT meta_key 
    FROM {$wpdb->prefix}postmeta 
    WHERE meta_key 
    LIKE 'like_status_%'
    ",
    ARRAY_N
);

$results = array_map(function($value){

    return (int) str_replace('like_status_', '', $value[0]);

}, $results);

array_walk($results, function($notify_user_id, $key){

    //apply to all users except the user who just liked the post
    if ( $notify_user_id !== $current_user_id ) {
        //notify logic here...           
    }

});

Примечание: логика может быть дополнительно упрощена, если вы хотите.

Вариант 2

  • требует, чтобы вы изменили свою мета-схему
  • требует, чтобы вы сохранили идентификатор пользователя в качестве мета-значения
  • позволяет использовать WP_Queryвместе сmeta_query

Вариант 2 требует, чтобы вы изменили свой мета-ключ like_status_{user_id}на что-то универсальное, например, like_statusили liked_by_user_idгде, в свою очередь, вместо сохранения значения 1против ключа вы вместо этого сохраняете идентификатор пользователя в качестве значения.

//when a user likes a post...
$current_user_id = get_current_user_id();
add_post_meta($current_user_id, "liked_by_user_id", $current_user_id, false);

//later in the request
$args = array(
    'post_type'  => 'post', //or a post type of your choosing
    'posts_per_page' => -1,
    'meta_query' => array(
        array(
            'key' => 'liked_by_user_id',
            'value' => 0,
            'type' => 'numeric'
            'compare' => '>'
        )
    )
);

$query = new WP_Query($args);   

array_walk($query->posts, function($post, $key){

    $user_ids = get_post_meta($post->ID, 'liked_by_user_id');

    array_walk($user_ids, function($notify_user_id, $key){

        //notify all users except the user who just like the post
        if ( $notify_user_id !== $current_user_id ) {

            //notify logic here...
            //get user e.g. $user = get_user_by('id', $notify_user_id);

        }

    });

});
Адам
источник
1
Теперь, начиная с
К. Тромп
@ K.Tromp Huzzah!
Адам
Пожалуйста, обновите принятый ответ, чтобы отразить последние возможности WP или ответ @ K.Tromp, помеченный как самый актуальный ответ
zumek
10

Сложно конкретно ответить на ваш вопрос. Первая часть проста, хотя. Я недавно сделал что-то похожее на stackoverflow

Мета-ключи сравниваются и точно совпадают. WP_Queryу нас нет средств для настройки этого поведения с помощью простого параметра, но мы всегда можем сами его ввести, а затем настроить posts_whereпредложение для LIKEсравнения мета-ключей.

ФИЛЬТР

Это просто базовый фильтр, настройте его по мере необходимости.

add_filter( 'posts_where', function ( $where, \WP_Query $q )
{ 
    // Check for our custom query var
    if ( true !== $q->get( 'wildcard_on_key' ) )
        return $where;

    // Lets filter the clause
    $where = str_replace( 'meta_key =', 'meta_key LIKE', $where );

    return $where;
}, 10, 2 );

Как видите, фильтр срабатывает только тогда, когда мы устанавливаем наш новый пользовательский параметр wildcard_on_keyв true. Когда это проверяется, мы просто меняем =компаратор на LIKEкомпаратор

Просто отметим, что LIKEсравнения по своей природе обходятся дороже, чем другие сравнения

ВОПРОС

Вы можете просто запросить ваши сообщения, как следует, чтобы получить все сообщения с мета-ключами like_status_{user_id}

$args = [
    'wildcard_on_key' => true,
    'meta_query'      => [
        [
            'key'   => 'like_status_',
            'value' => 1,
        ]
    ]
];
$query = new WP_Query( $args );

ДРУГОЙ ВОПРОС

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

Я не очень большой поклонник хранения сериализованных данных в пользовательских полях, так как нельзя выполнять поиск или сортировку по сериализованным данным. Однако я бы предложил хранить все идентификаторы пользователя в массиве под одним настраиваемым полем. Вы можете просто обновить массив с идентификатором пользователя, когда пользователю нравится сообщение. Получить данные настраиваемого поля и циклы по массиву идентификаторов и сделать что-то с идентификаторами очень просто. Просто посмотрите наget_post_meta()

Обновление настраиваемого поля также легко. Для этого вам нужно разобраться update_post_meta(), я не знаю, как вы создаете свои настраиваемые поля, но update_post_meta()это определенно то, что вы хотели бы использовать.

Если вам нужно отправлять электронные письма или push-уведомления при обновлении настраиваемого поля, у вас есть следующие хуки, с которыми можно работать. ( См. update_metadata()Для контекста )

ВЫВОД

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

Питер Гусен
источник
1
Спасибо за ваше объяснение производительности post_meta! Супер полезно.
codescribblr
Это должен быть принятый ответ, всегда лучше использовать фильтры, а не использовать пользовательские запросы. Также обратите внимание, что если вы используете get_posts, а не WP_Query, вам нужно пройти через suppress_filters => false, иначе фильтр не сработает. Чтобы выполнить LIKE для мета-ключа, вам также нужно поместить% перед и позади ключа в массиве в зависимости от того, какой тип поиска вы хотите выполнить.
Эрл Дэвис,
И как бы вы отфильтровали его, если хотите запрашивать посты, но ИСКЛЮЧИТЬ все посты, имеющие мета-ключ поста по префиксу? (например, исключить все сообщения, имеющие мета-метку LIKE 'my_prefix_'?
gordie
6

Начиная с Wordpress 5.1 теперь возможно использовать мета-запрос, например: введите описание изображения здесь

К. Тромп
источник
Экранирование подчеркивания кажется проблемой с этим методом, но в остальном это выглядит довольно хорошо. Спасибо, подчеркнув.
Джейк
2

Если позже вы захотите расширить это, добавив более подробную статистику, функции и т. Д., Тогда еще одной альтернативой может быть: пользовательские таблицы

  • Плюсы : с учетом ваших потребностей и могут быть проиндексированы для повышения производительности.

  • минусы : больше работы

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

Я пытаюсь разослать уведомление всем, кому понравился пост, когда кому-то еще нравится этот пост ... что-то вроде: "Эй, кому-то еще понравился этот пост, который вам понравился. Вы должны проверить его!" Но мне нужен способ узнать, понравился ли кому-то еще этот пост, и если да, то кем он будет, чтобы я мог уведомить их.

Не уверен, какие уведомления вы имеете в виду здесь, но это может быстро стать громоздким.

Пример : пользователь, которому нравится ~ 1000 сообщений, и каждое сообщение получает ~ 1000 лайков, тогда в каналах есть 1M уведомлений, только для этого пользователя! Если это почтовые уведомления, то хост-провайдер может быть недоволен, и пользователь сходит с ума. Это также может быть дорого с почтовым сервисом третьей стороны.

birgire
источник
На самом деле я отправляю уведомления только один раз на человека на пост. Так что это меньше, чем кажется - хотя все еще много. Причина, по которой я пытаюсь использовать встроенные таблицы, заключается в том, что я хотел бы иметь возможность использовать стандартный WP REST API в будущем в реальном приложении с этими данными.
codescribblr
-1

Согласно документации WP_Meta_Query вы можете использовать compareаргумент в meta_queryаргументе WP_Query. Тем не менее, вы можете сравнить только с, valueа не с, keyпоэтому вы можете пересмотреть, как вы это структурируете.

likeАргумент будет выглядеть следующим образом :

$arguments = array(
    'meta_query' => array(
        array(
            'key' => 'foo',
            'value' => 'ba',
            'compare' => 'LIKE'
        )
    )
);

$query = new WP_Query($arguments);

Учитывая, что вы не можете выполнить поиск "LIKE" в разделе, keyя бы предложил вам добавить понравившиеся посты в пользовательскую мета и выполнить поиск WP_User_Query для пользователей, которым понравился этот пост:

$arguments = array(
    'meta_query' => array(
        array(
            'key' => 'liked_post',
            'value' => '<post_id>'
        )
    )
);

$users = new WP_User_Query($arguments);
LonnyLot
источник