Jak zapytać o posty według częściowego meta klucza?

9

Mam funkcję, która przechowuje status „Lubię to” dla posta jako meta postu. Chcę powiązać to „polubienie” z użytkownikiem, który go polubił, dlatego ustawiłem niestandardowe pole o nazwie „like_status_ {identyfikator_użytkownika}” (gdzie {identyfikator_użytkownika} to identyfikator aktualnie zalogowanego użytkownika), które przechowuję jako 0 lub 1. Tak więc dla postu z kilkoma „polubieniami” w db będzie kilka meta wartości, które są ustawione w ten sposób:

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

....i tak dalej.

W określonym poście potencjalnie są tysiące polubień. Jak uruchomiłbym zapytanie, które pokazałoby, czy komuś podobał się ten post?

Myślałem o czymś takim:

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

Próbuję przekazać powiadomienie każdemu, kto polubił post, gdy ktoś inny lubi ten post ... coś w stylu: „Hej, komuś podobał się post, który ci się podobał. Powinieneś to sprawdzić!” Potrzebuję jednak sposobu, aby dowiedzieć się, czy komuś podobał się ten post, a jeśli tak, to kim byłby, bym mógł go powiadomić.

Jeśli nie jest to możliwe, czy możesz zasugerować lepszy sposób przechowywania tych danych jako post_meta przy jednoczesnym zachowaniu wydajności szybkiego aktualizowania statusu pojedynczego użytkownika w poście?

codecribblr
źródło

Odpowiedzi:

6

Niestety nie można wykonać meta_querystosując LIKEporównanie na meta_keywartości podczas używania WP_Query. Byłem na tej drodze ...

Zamiast tego masz kilka innych opcji, jeśli chcesz zachować podobne relacje statusu jako meta post, a nie meta użytkownika i / lub meta w niestandardowej tabeli.

opcja 1

  • nie wymaga modyfikacji twojego meta schematu
  • używa wpdbklasy do wykonania niestandardowego zapytania

Przykład:

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

});

Uwaga: logikę można uprościć, jeśli chcesz.

Opcja 2

  • wymaga zmiany meta schematu
  • wymaga zapisania identyfikatora użytkownika jako wartości meta
  • pozwala używać WP_Queryrazem zmeta_query

Opcja 2 wymaga, aby zmienić swój meta-klucz z like_status_{user_id}na uniwersalny, taki jak like_statuslub liked_by_user_idgdzie z kolei zamiast przechowywać wartość 1przeciw kluczowi, zamiast tego przechowuje się identyfikator użytkownika jako wartość.

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

        }

    });

});
Adam
źródło
1
Teraz, odkąd 5.1, spójrz na moją odpowiedź poniżej
K. Tromp,
@ K.Tromp Huzzah!
Adam
Zaktualizuj zaakceptowaną odpowiedź, aby odzwierciedlić najnowszą funkcję WP lub odpowiedź @ K.Tromp oznaczoną jako najbardziej aktualna odpowiedź
zumek
10

Konkretnie trudno odpowiedzieć na twoje pytanie. Pierwsza część jest jednak łatwa. Niedawno zrobiłem coś podobnego w przypadku przepełnienia stosu

Meta-klucze są porównywane i pasują dokładnie. WP_Querynie mamy środków na dostosowanie tego zachowania za pomocą prostego parametru, ale zawsze możemy wprowadzić go samodzielnie, a następnie dostosować posts_whereklauzulę, aby LIKEporównać meta-klucze.

FILTR

To tylko podstawowy filtr, dostosuj go w razie potrzeby.

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

Jak widać, filtr jest uruchamiany tylko wtedy, gdy ustawimy nasz nowy parametr niestandardowy wildcard_on_keyna true. Kiedy to się sprawdza, po prostu zmieniamy =komparator na LIKEkomparator

Tylko uwaga na ten temat, LIKEporównania są z natury droższe w porównaniu z innymi porównaniami

ZAPYTANIE

Możesz po prostu wysłać zapytanie do swoich postów w następujący sposób, aby uzyskać wszystkie posty z meta-kluczami like_status_{user_id}

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

INNE PYTANIE

Pola niestandardowe nie mają wpływu na wydajność, możesz przeczytać mój post na ten temat tutaj . Niepokoi mnie jednak to, że każdy post może mieć setki lub tysiące polubień. Może to wpłynąć na zwiększenie wydajności i buforowanie tak dużej ilości niestandardowych danych w terenie. Może również zapchać twoją bazę danych ogromną ilością niepotrzebnych niestandardowych danych pola, co utrudnia utrzymanie.

Nie jestem wielkim fanem przechowywania danych zserializowanych w niestandardowych polach, ponieważ nie można wyszukiwać ani zamawiać według danych szeregowych. Sugerowałbym jednak przechowywanie wszystkich identyfikatorów użytkowników w tablicy pod jednym niestandardowym polem. Możesz po prostu zaktualizować tablicę o identyfikator użytkownika, gdy użytkownik lubi post. Uzyskiwanie niestandardowych danych pola i zapętlanie tablicy identyfikatorów oraz robienie czegoś z identyfikatorami jest łatwe. Spójrz tylkoget_post_meta()

Aktualizacja pola niestandardowego jest również łatwa. W tym celu musisz zajrzeć update_post_meta(), nie wiem, jak tworzysz własne pola, ale update_post_meta()zdecydowanie jest to coś, czego chciałbyś użyć.

Jeśli musisz wysyłać e-maile lub powiadomienia push, gdy pole niestandardowe jest aktualizowane, masz do dyspozycji następujące zaczepy. ( Patrz update_metadata()kontekst )

WNIOSEK

Tuż przed opublikowaniem tego ponownie, zanim przejdziesz do serializowanej trasy, upewnij się, że nie będziesz musiał sortować według posortowanych danych ani wyszukiwać określonych danych w serializowanych danych.

Pieter Goosen
źródło
1
Dziękujemy za wyjaśnienie dotyczące wydajności post_meta! Super przydatne.
codecribblr
To powinna być zaakceptowana odpowiedź, zawsze lepiej jest używać filtrów niż niestandardowych zapytań. Pamiętaj też, że jeśli używasz get_posts zamiast WP_Query, musisz przejść przez suppress_filters => false, inaczej nie spowoduje to wyzwolenia filtra. Aby wykonać LIKE na meta-kluczu, musisz również umieścić% przed i za klawiszem w tablicy, w zależności od typu wyszukiwania, które chcesz wykonać.
Earle Davies
A jak byś to przefiltrował, jeśli chcesz wysyłać zapytania do postów, ale WYKLUCZAĆ wszystkie posty z meta-kluczem według prefiksu? (np. wykluczyć wszystkie posty mające meta LIKE „my_prefix_”?
gordie
6

Od wersji 5.1 można teraz używać meta-zapytań, takich jak: wprowadź opis zdjęcia tutaj

K. Tromp
źródło
Ucieczka podkreślników wydaje się być problemem w tej metodzie, ale poza tym wygląda całkiem nieźle. Dzięki wyróżnienie.
Jake,
2

Jeśli później chcesz to rozszerzyć o bardziej szczegółowe statystyki, funkcje itp., Jeszcze inną alternatywą może być: niestandardowe tabele

  • plusy : dostosowane do twoich potrzeb i mogą być indeksowane w celu uzyskania lepszej wydajności.

  • Minusy : więcej pracy

Możliwe jest także obejście problemu przy użyciu niestandardowej taksonomii, która może zapewnić lepszą wydajność zapytań niż w przypadku zapytań po meta ze względu na sposób indeksowania tabel podstawowych.

Próbuję przekazać powiadomienie każdemu, kto polubił post, gdy ktoś inny lubi ten post ... coś w stylu: „Hej, komuś podobał się post, który ci się podobał. Powinieneś to sprawdzić!” Potrzebuję jednak sposobu, aby dowiedzieć się, czy komuś podobał się ten post, a jeśli tak, to kim byłby, bym mógł go powiadomić.

Nie jestem pewien, jakie powiadomienia tutaj masz na myśli, ale może to szybko stać się nieporęczne.

Przykład : użytkownik, który lubi ~ 1000 postów, a każdy post otrzymuje ~ 1000 polubień, wtedy w potokach jest 1 mln powiadomień, tylko dla tego użytkownika! Jeśli są to powiadomienia e-mail, dostawca hosta może nie być szczęśliwy, a użytkownik oszaleje. Może to być również kosztowne w przypadku zewnętrznej usługi e-mail.

birgire
źródło
W rzeczywistości wysyłam powiadomienia tylko raz na osobę na post. Więc to mniej, niż się wydaje - choć wciąż dużo. Powodem, dla którego próbuję użyć wbudowanych tabel, jest to, że chciałbym móc używać standardowego interfejsu API WP REST w dalszej części drogi w rzeczywistej aplikacji z tymi danymi.
codecribblr
-1

Zgodnie z dokumentacją WP_Meta_Query można użyć compareargumentu w meta_queryargumencie WP_Query. Możesz jednak porównać tylko, valuea nie keytak, więc możesz przemyśleć, jak to ustrukturyzować.

likeArgumentem będzie wyglądać następująco:

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

$query = new WP_Query($arguments);

Biorąc pod uwagę, że nie można przeprowadzić wyszukiwania „LIKE” na stronie keysugeruję, aby dodać polubione posty w meta użytkownika i przeprowadzić wyszukiwanie WP_User_Query dla użytkowników, którzy polubili ten post:

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

$users = new WP_User_Query($arguments);
LonnyLot
źródło