Jak mogę utworzyć meta_query z tablicą jako meta_field?

16

Oto argumenty mojego zapytania:

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

Działa topicsto, gdy jest łańcuchem, ale nie, gdy jest tablicą. Chciałbym, aby to zapytanie działało, gdy topicsjest na przykładarray( 'sports', 'nonprofit', etc. )

Czy istnieje sposób na budowanie meta-zapytań z tablicami jako meta_key?

mike23
źródło
Wyjaśnij - czy masz na myśli, że przechowywana wartość „tematów” jest tablicą? Lub, że przechowywana wartość jest ciągiem i chcesz przekazać wiele terminów do zapytania w tablicy?
MathSmath,
@MathSmath, mam na myśli, że przechowywana wartość jest tablicą.
mike23

Odpowiedzi:

31

Karmienie kwerendy tablicą możliwych wartości

Jeśli wartość w bazie danych jest łańcuchem i chcesz wprowadzić do zapytania kilka wartości:

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

Wyszukiwanie określonej wartości w szeregowym szeregu danych

Jeśli wartość w bazie danych jest tablicą kilku tematów i chcesz wyszukać pojedynczy temat w tej tablicy (zwróć uwagę, że tablicę w bazie danych można pobrać jako taką, ale żyje ona w bazie danych w postaci szeregowej, która jest string również):

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

Użycie „LIKE” jako wartości porównania nie jest tak jednoznaczną instrukcją, jak można się było spodziewać, ale jest to najlepsza opcja.

Oprócz tego jedyną inną opcją byłoby pobieranie wszystkich postów z ustawionymi „tematami” meta_key i iterowanie nad nimi ręcznie, innymi słowy, sprawdzanie wartości w pętli i wyświetlanie postów w tym stanie.

Johannes Pille
źródło
14

Aby odejść od odpowiedzi Johannesa, ponieważ jest to szeregowa tablica, jeśli zdarza się, że przechowuje się coś w rodzaju identyfikatora użytkownika (tak było w moim przypadku), być może trzeba potraktować to nieco inaczej.

Zapisano posta meta w następujący sposób:

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

Tak więc są liczbami całkowitymi, ale dzięki temu update_post_metazostały zapisane jako ciągi znaków.

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

Więc faktycznie porównujesz LIKE z serializowaną wersją ciągów tego, czego szukasz. Spędziłem dobre godziny, starając się, aby coś takiego działało i do tej pory było to najlepsze, co mogłem wymyślić.

sMyles
źródło
serialize (strval (1)) rozwiązał mój problem, Dzięki
Behzad
Dzisiaj przez przypadek trafiłem na tę starą odpowiedź. Podoba mi się twój dodatek. +1
Johannes Pille,
Właśnie się z tym spotkałem, chodzi mi o to, że muszę pobrać wszystkie posty, w których user_id nie ma w tablicy, ale powyższe rozwiązanie nie działa, więc zrobiłem to w ten sposób: 'meta_query' => array( array( 'key' => 'my_meta_key', 'value' => ':' . $user_id . ';', 'compare' => 'NOT LIKE' ) ) Ponieważ po serializacji wszystkie wartości są zapisywane w następujący sposób: ' :wartość;'
Bobz
4

Kolejna niewielka poprawa w stosunku do odpowiedzi @sMyles.

Miałem przypadki, w których identyfikatory były przechowywane zarówno jako ciągi znaków (np. Gdy zostały pobrane z danych wejściowych formularza), jak i jako liczby całkowite (np update_post_meta($post_id, authorized_users', array(get_current_user_id()));.). Jest to rodzaj dobrze znanego problemu polegającego na tym, wp_set_object_terms()że można używać identyfikatorów terminów do ustawiania warunków, ale jeśli nie użyjesz ich jako liczb całkowitych, masz około 50% szansy na utworzenie nowych warunków z tymi liczbami jako ich nazwami zamiast.

Może to spowodować, że będą one przechowywane zupełnie inaczej w szeregowej tablicy, co można zobaczyć na podstawie fragmentów takiego przypadku z bazy danych mojej witryny testowej:

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

Oba powyższe, po przejściu print_r()będą renderowane jako

Array
(
    [0] => 1
)

Aby to naprawić, wprowadziłem niewielką modyfikację meta_query, dodając relationkolejną wersję zapytania, która rzuciła wartość jako liczbę całkowitą zamiast ciągu.

Oto końcowy wynik:

        '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'
            ),
        ),

EDYCJA: Właśnie zdałem sobie sprawę, że ta metoda może narazić na ryzyko kolizji z indeksami tablic, co może umożliwić komuś nielegalny dostęp do materiałów, jeśli nie ma go w tablicy, ale jego identyfikator użytkownika pojawia się jako indeks. W związku z tym, chociaż działa to w przypadku omówienia problemu, lepszą praktyką jest dopilnowanie, aby wszystkie wartości, które chcesz wyszukać, były rzutowane jako ciągi przed zapisaniem ich, aby zamiast tego można było użyć metody @sMyles.

Kaji
źródło
To powinna być wybrana odpowiedź, najbardziej wiarygodna
Amin
2

Chciałbym uzyskać odpowiedź Johannesa. Jednak chcę to poprawić, ponieważ używając tego meta_query, spotkasz taki przypadek

twoja wartość to

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

podczas wyszukiwania

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

wtedy wynik zwróci zarówno „sport”, jak i „sport2”.

Aby to naprawić, zmień argumenty meta_query na

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

Jest tak, ponieważ wartość jest serializowana w bazie danych, a każdy element będzie oddzielony średnikiem. Tak więc powyższe argumenty będą działać

Jeśli elementy w wartości są liczbą, wystarczy usunąć podwójny cudzysłów „

$args = array(
        'post_type' => 'news',
        'meta_query' => array(
            array(
                'key' => 'topics',
                'value' => '1;',
                'compare' => 'LIKE'
            )
        )
    );
Ha Doan Ngoc
źródło
1

Walczyłem dzisiaj z czymś podobnym. Muszę wysłać zapytanie o pole relacji ACF (Advanced Custom Fields) z wieloma powiązanymi użytkownikami (macierz).

Po zaktualizowaniu pola przez php zapytanie nie działało. Po zaktualizowaniu go za pomocą interfejsu ACF zapytanie działało.

Problem polegał na tym, że mój kod php ustawił wartości relacji na int-wartości, a interfejs użytkownika ustawił na wartości łańcuchowe. Aby upewnić się, że obie działają, używam teraz tego zapytania (dopasowanego do przykładu tutaj):

$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
źródło