Como posso criar uma meta_query com uma matriz como meta_field?

16

Aqui estão os argumentos para minha consulta:

$args = array(
    'post_type' => 'news',
    'meta_query' => array(
        array(
            'key' => 'topics',
            'value' => 'sports',
        )
    )
);

Isso funciona quando topicsé uma string, mas não quando é uma matriz. Gostaria que essa consulta funcionasse quando, topicspor exemplo,array( 'sports', 'nonprofit', etc. )

Existe uma maneira de criar consultas meta com matrizes como uma meta_key?

mike23
fonte
Por favor, esclareça - você quer dizer que o valor armazenado de "tópicos" é uma matriz? Ou que o valor armazenado é uma sequência e você deseja passar vários termos para a consulta em uma matriz?
MathSmath
@ MathSmath, quero dizer que o valor armazenado é uma matriz.
mike23

Respostas:

30

Alimentando a consulta com uma matriz de valores possíveis

Se o valor no banco de dados for uma sequência e você desejar alimentar a consulta com vários valores:

$args = array(
    'post_type' => 'news',
    'meta_query' => array(
        array(
            'key' => 'topics',
            'value' => array ( 'sports', 'nonprofit', 'community' ),
            'compare' => 'IN'
        )
    )
);

Procurando por um valor específico em uma matriz serializada de dados

Se o valor no banco de dados for uma matriz de vários tópicos e você desejar procurar um único tópico nessa matriz (observe que uma matriz no banco de dados pode ser recuperada como tal, mas reside no banco de dados na forma serializada, que é um string também):

$args = array(
    'post_type' => 'news',
    'meta_query' => array(
        array(
            'key' => 'topics',
            'value' => 'sports',
            'compare' => 'LIKE'
        )
    )
);

Usar 'LIKE' como o valor de comparação não é uma instrução tão clara quanto você poderia esperar, mas é a melhor opção.

Além disso, sua única outra opção seria recuperar todas as postagens que possuem os meta_key "topics" definidos e iterá-las manualmente ou, em outras palavras, verificar o valor no loop e exibir as postagens na referida condição.

Johannes Pille
fonte
14

Para sair da resposta de Johannes, já que é uma matriz serializada, se você estiver armazenando algo como IDs de usuário (que foi o meu caso), talvez seja necessário lidar com isso de maneira um pouco diferente.

A meta de postagem estava sendo salva como:

array( "1", "23", "99");

Então, sim, eles são números inteiros, mas através update_post_metadeles estavam sendo salvos como strings.

'meta_query' => array(
            array(
                    'key'     => 'my_meta_key',
                    'value'   => serialize( strval( 1 ) ),
                    'compare' => 'LIKE'
                )
            )

Então, na verdade, você está fazendo uma comparação LIKE com a versão serializada do que está procurando. Passei algumas horas tentando fazer com que algo assim funcionasse e, até agora, foi o melhor que consegui.

sMyles
fonte
serialize (strval (1)) resolveu o meu problema, graças
Behzad
Hoje me deparei com essa resposta antiga por acaso. Eu gosto da sua adição. +1
Johannes Pille
Acabei de me deparar com isso também, o que quero dizer é que preciso obter todas as postagens em que user_id não esteja na matriz, mas a solução acima não funciona, por isso fiz assim: 'meta_query' => array( array( 'key' => 'my_meta_key', 'value' => ':' . $user_id . ';', 'compare' => 'NOT LIKE' ) ) porque quando serializados, todos os valores são salvos como: ' :valor;'
Bobz
4

Outra pequena melhora em relação à resposta do @sMyles.

Eu tive casos em que os IDs foram armazenados como seqüências de caracteres (como quando extraídos de uma entrada de formulário) e como números inteiros (por exemplo update_post_meta($post_id, authorized_users', array(get_current_user_id()));). Esse é o problema conhecido em wp_set_object_terms()que você pode usar IDs de termo para definir os termos, mas se você não os converter como números inteiros, terá 50% de chance de criar novos termos com esses números como seus nomes. em vez de.

Isso pode resultar no armazenamento diferenciado em uma matriz serializada, como pode ser visto nos trechos de um caso desse no banco de dados do site de teste:

a:1:{i:0;s:1:"1";} // 's' for 'string', also note the double quotes
a:1:{i:0;i:1;} // 'i' for 'integer', no quotes

Ambos os itens acima, quando alimentados print_r(), renderizam como

Array
(
    [0] => 1
)

Para corrigir isso, fiz um pequeno ajuste no meta_queryadicionando uma relatione outra versão da consulta que convertia o valor como um número inteiro em vez de uma string.

Aqui está o resultado final:

        'meta_query' => array(
            'relation' => 'OR', // Lets it know that either of the following is acceptable
            array(
                'key' => 'bcm_enm_authorized_users',
                'value'   => serialize(strval(get_current_user_id())), // Saved as string
                'compare' => 'LIKE'
            ),
            array(
                'key' => 'bcm_enm_authorized_users',
                'value'   => serialize(intval(get_current_user_id())), // Saved as integer
                'compare' => 'LIKE'
            ),
        ),

EDIT: Acabei de perceber que esse método poderia correr o risco de colisões com índices de matriz, o que poderia permitir a alguém acesso ilícito a materiais se eles não estiverem na matriz, mas seu ID de usuário aparece como um índice. Dessa forma, embora isso funcione se você tiver o problema discutido, a melhor prática é garantir que quaisquer valores que você deseja procurar sejam convertidos em seqüências de caracteres antes de salvá-los, para que você possa usar o método @sMyles '.

Kaji
fonte
Esta deve ser a resposta selecionada, mais confiável
Amin
2

Eu aceitaria a resposta de Johannes. No entanto, quero melhorar isso, porque usando essa meta_query, você encontrará um caso como este

seu valor é

array('sports','movies', 'sports2');

quando você pesquisa

$args = array(
    'post_type' => 'news',
    'meta_query' => array(
        array(
            'key' => 'topics',
            'value' => 'sports',
            'compare' => 'LIKE'
        )
    )
);

o resultado retornará 'sport' e 'sport2'.

Para corrigir isso, altere os argumentos meta_query para

$args = array(
    'post_type' => 'news',
    'meta_query' => array(
        array(
            'key' => 'topics',
            'value' => 'sports";',
            'compare' => 'LIKE'
        )
    )
);

Isso ocorre porque o valor é serializado no banco de dados e cada item será separado por ponto e vírgula. Assim, os argumentos acima funcionarão

Se os itens no valor forem números, basta remover as aspas duplas "

$args = array(
        'post_type' => 'news',
        'meta_query' => array(
            array(
                'key' => 'topics',
                'value' => '1;',
                'compare' => 'LIKE'
            )
        )
    );
Ha Doan Ngoc
fonte
1

Eu lutei com algo semelhante hoje. Eu tenho que consultar um campo de relacionamento ACF (Advanced Custom Fields) com vários usuários relacionados (matriz).

Após atualizar o campo via php, a consulta não funcionou. Após atualizá-lo pela interface do usuário do ACF, a consulta funcionou.

O problema era que meu código php definia os valores de relacionamento como int-values, a interface do usuário definia-os como string-values. Para garantir que ambos funcionem, eu uso essa consulta agora (ajustada ao exemplo aqui):

$args = array(
    'post_type' => 'news',
    'meta_query' => array(
        'relation' => 'OR',
        array(
            'key' => 'topics',
            'value' => '1;',  // works for int-array
            'compare' => 'LIKE'
        ),
        array(
            'key' => 'topics',
            'value' => '"1"',  // works for string-array
            'compare' => 'LIKE'
        ),
    )
);
Julian Stark
fonte