Como faço para consultar postagens por meta-chave parcial?

9

Eu tenho uma função que armazena o status "like" para uma postagem como meta meta. Quero associar esse "curtir" ao usuário que gostou, portanto, configurei um campo personalizado chamado "like_status_ {user_id}" (em que {user_id} é o ID do usuário conectado no momento) que eu armazeno como 0 ou 1. Portanto, para um post com vários "likes", haveria vários meta-valores no banco de dados configurados da seguinte maneira:

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

....e assim por diante.

Há potencialmente milhares de curtidas em uma postagem específica. Como eu executaria uma consulta exibida se outra pessoa também gostasse dessa postagem?

Eu estava pensando algo assim:

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

Estou tentando enviar uma notificação a todos que gostaram de uma postagem quando alguém gosta dessa postagem ... algo como: "Ei, alguém gostou da postagem que você gostou. Você deve conferir!" Mas eu preciso de uma maneira de descobrir se alguém mais gostou desse post e, se sim, quem seria para que eu pudesse notificá-lo.

Se não for possível, você poderia sugerir uma maneira melhor de armazenar esses dados como post_meta, mantendo a eficiência de atualizar rapidamente o status semelhante de um único usuário em uma postagem?

codescribblr
fonte

Respostas:

6

Infelizmente, você não pode executar meta_queryuma LIKEcomparação do meta_keyvalor ao usar WP_Query. Eu estive por esse caminho ...

Em vez disso, você tem algumas outras opções se desejar manter relacionamentos de status semelhantes como pós-meta e não meta-usuário e / ou meta em uma tabela personalizada.

Opção 1

  • não requer modificação do seu meta-esquema
  • usa a wpdbclasse para executar uma consulta personalizada

Exemplo:

//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...           
    }

});

Nota: a lógica pode ser mais simplificada, se você desejar.

opção 2

  • requer que você altere seu meta-esquema
  • requer que você armazene o ID do usuário como o valor meta
  • permite que você use WP_Queryjunto commeta_query

A opção 2 exige que você altere sua meta-chave de like_status_{user_id}para algo universal como like_statusou liked_by_user_idonde, por sua vez, em vez de armazenar o valor de 1contra a chave, armazene o ID do usuário como o valor.

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

        }

    });

});
Adão
fonte
11
É agora desde 5.1 ter um olhar para a minha resposta abaixo
K. Tromp
@ K.Tromp Huzzah!
Adam
10

É bastante difícil responder concretamente à sua pergunta. A primeira parte é fácil. Recentemente, fiz algo semelhante no stackoverflow

As meta chaves são comparadas e correspondem exatamente. WP_Querynão temos como ajustar esse comportamento com um parâmetro simples, mas sempre podemos nos apresentar e ajustar a posts_wherecláusula para fazer uma LIKEcomparação nas meta-chaves.

O FILTRO

Este é apenas um filtro básico, ajuste-o conforme necessário.

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

Como você pode ver, o filtro é acionado apenas quando definimos nosso novo parâmetro personalizado, wildcard_on_keycomo true. Quando isso ocorre, simplesmente mudamos o =comparador para o LIKEcomparador

Apenas uma observação, LIKEcomparações são inerentemente mais caras do que outras comparações

A PERGUNTA

Você pode simplesmente consultar suas postagens da seguinte forma para obter todas as postagens com meta chaves like_status_{user_id}

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

OUTRA QUESTÃO

Os campos personalizados não têm impacto no desempenho. Você pode ler minha postagem sobre este assunto aqui . No entanto, estou preocupado com o fato de você dizer que cada post pode ter centenas ou milhares de curtidas. Isso pode afetar a obtenção e o armazenamento em cache de uma quantidade tão grande de dados de campo personalizados. Ele também pode entupir seu banco de dados com uma enorme quantidade de dados de campo personalizados desnecessários, o que dificulta a manutenção.

Não sou muito fã de armazenar dados serializados em campos personalizados, pois não é possível pesquisar ou solicitar dados serializados. No entanto, eu sugeriria o armazenamento de todos os IDs de usuário em uma matriz em um campo personalizado. Você pode simplesmente atualizar a matriz com o ID do usuário quando um usuário gosta de uma postagem. É fácil obter os dados do campo personalizado e fazer um loop sobre a matriz de IDs e fazer algo com as IDs. Basta dar uma olhadaget_post_meta()

A atualização de um campo personalizado também é fácil. Para isso, você precisará analisar update_post_meta(), não sei como criar seus campos personalizados, mas update_post_meta()é definitivamente algo que você gostaria de usar.

Se você precisar enviar e-mails ou notificações por push quando um campo personalizado for atualizado, você terá os seguintes ganchos disponíveis para trabalhar. ( Veja update_metadata()para o contexto )

CONCLUSÃO

Pouco antes de postar isso, novamente, antes de seguir a rota serializada, verifique se você não precisa classificar pelos dados classificados ou procurar dados específicos dentro dos dados serializados.

Pieter Goosen
fonte
11
Obrigado por sua explicação sobre o desempenho post_meta! Super útil.
codescribblr
Essa deve ser a resposta aceita, é sempre melhor usar filtros em vez de usar consultas personalizadas. Além disso, observe que se você estiver usando get_posts em vez de WP_Query, precisará passar por suppress_filters => false ou isso não acionará o filtro. Para executar o LIKE na meta-chave, você também precisa colocar% na frente e atrás da chave na matriz, dependendo do tipo de pesquisa semelhante que você deseja fazer.
Earle Davies
E como você o filtraria se quiser consultar as postagens, mas EXCLUIR todas as postagens com uma meta-chave de postagem por prefixo? . (por exemplo, excluir todas as mensagens com um post meta LIKE 'my_prefix_'?
gordie
5

Desde o wordpress 5.1, agora é possível usar a meta query como: insira a descrição da imagem aqui

K. Tromp
fonte
O escape de sublinhados parece ser um problema com esse método, mas, caso contrário, parece muito bom. Obrigado destacando.
Jake #
2

Se, posteriormente, você desejar estender isso, com estatísticas, recursos, etc, mais detalhados, outra alternativa poderá ser: tabela (s) personalizada (s)

  • profissionais : adaptados às suas necessidades e podem ser indexados para obter melhor desempenho.

  • contras : mais trabalho

Também pode haver uma solução alternativa usando uma taxonomia customizada, que pode oferecer melhor desempenho de consulta do que as meta-consultas posteriores, devido à maneira como as tabelas principais são indexadas.

Estou tentando enviar uma notificação a todos que gostaram de uma postagem quando alguém gosta dessa postagem ... algo como: "Ei, alguém gostou da postagem que você gostou. Você deve conferir!" Mas eu preciso de uma maneira de descobrir se alguém mais gostou desse post e, se sim, quem seria para que eu pudesse notificá-lo.

Não tenho certeza do tipo de notificação que você quer dizer aqui, mas isso pode se tornar volumoso rapidamente.

Exemplo : um usuário que gosta de ~ 1000 postagens e cada postagem recebe ~ 1000 curtidas, então há 1 milhão de notificações nos canais, apenas para esse usuário! Se forem notificações por email, o provedor de host pode não estar feliz e o usuário ficaria louco. Isso também pode ser caro com um serviço de email de terceiros.

Birgire
fonte
Na verdade, estou apenas enviando as notificações uma vez por pessoa e por postagem. Portanto, é menos do que parece - embora ainda seja muito. O motivo pelo qual estou tentando usar tabelas internas é que eu gostaria de poder usar a API REST WP padrão no caminho em um aplicativo real com esses dados.
codescribblr
-1

De acordo com a documentação WP_Meta_Query , você pode usar o compareargumento no meta_queryargumento WP_Query. No entanto, você só pode comparar no valuee não no, keyportanto, pode querer repensar como você estrutura isso.

Um likeargumento seria assim:

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

$query = new WP_Query($arguments);

Como você não pode fazer uma pesquisa 'LIKE', keysugiro que você adicione as postagens curtidas na meta do usuário e faça uma pesquisa WP_User_Query para usuários que curtiram essa postagem:

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

$users = new WP_User_Query($arguments);
LonnyLot
fonte