WP_Query z „post_title LIKE 'coś%'”?


44

Muszę zrobić WP_Queryz LIKEna post_title.

Zacząłem od tego regularnego WP_Query:

$wp_query = new WP_Query( 
    array (
        'post_type'        => 'wp_exposants',
        'posts_per_page'   => '1',
        'post_status'      => 'publish',
        'orderby'          => 'title', 
        'order'            => 'ASC',
        'paged'            => $paged
    )
); 

Ale tak naprawdę chcę to zrobić w SQL:

$query = "
        SELECT      *
        FROM        $wpdb->posts
        WHERE       $wpdb->posts.post_title LIKE '$param2%'
        AND         $wpdb->posts.post_type = 'wp_exposants'
        ORDER BY    $wpdb->posts.post_title
";
$wpdb->get_results($query);

Dane wyjściowe drukują wyniki, których oczekuję, ale używam zwykłego, <?php while ( $wp_query->have_posts() ) : $wp_query->the_post(); ?>aby wyświetlić wyniki.
I to nie działa $wpdb->get_results().

Jak mogę osiągnąć to, co tutaj opisałem?

Odpowiedzi:


45

Rozwiązałbym to z włączonym filtrem WP_Query. Taki, który wykrywa dodatkową zmienną zapytania i używa jej jako prefiksu tytułu.

add_filter( 'posts_where', 'wpse18703_posts_where', 10, 2 );
function wpse18703_posts_where( $where, &$wp_query )
{
    global $wpdb;
    if ( $wpse18703_title = $wp_query->get( 'wpse18703_title' ) ) {
        $where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'' . esc_sql( $wpdb->esc_like( $wpse18703_title ) ) . '%\'';
    }
    return $where;
}

W ten sposób możesz nadal wywoływać WP_Query, po prostu przekazujesz tytuł jako wpse18703_titleargument (lub zmienisz nazwę na coś krótszego).


Ten jakoś brakuje $wpdb->prepare().
kaiser,

@kaiser: Minęło dużo czasu, ale myślę, że nie było to możliwe prepare(). $wpdb->prepare('LIKE "%s%%"', 'banana')wróci "LIKE ''banana'%'", więc musimy sami zbudować zapytanie i wykonać ucieczkę.
Jan Fabry,

1
@JanFabry Cieszę się, że cię widzę agaaaaaaaain! :) Wpadnij kiedyś na czacie, hm? StopPress chętnie cię zobaczy. O tym prepare(). Tak, to trudne i musiałem spróbować kilka razy, zanim się obejrzałem. Od czegoś Zrobiłem: $wpdb->prepare( ' AND {$wpdb->posts}.post_title LIKE %s ', esc_sql( '%'.like_escape( trim( $term ) ).'%' ) ). I jestem prawie pewien, że esc_sql()jest to niepotrzebne i po prostu paranoiczne.
kaiser

Wygląda na to, że nie możesz przeszukiwać łańcucha z '(apostrofem) w środku. Myślę, że to z powodu ucieczki? Nie znalazłem jeszcze rozwiązania
Vincent Decaux

19

Uproszczony:

function title_filter( $where, &$wp_query )
{
    global $wpdb;
    if ( $search_term = $wp_query->get( 'search_prod_title' ) ) {
        $where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'%' . esc_sql( like_escape( $search_term ) ) . '%\'';
    }
    return $where;
}

$args = array(
    'post_type' => 'product',
    'posts_per_page' => $page_size,
    'paged' => $page,
    'search_prod_title' => $search_term,
    'post_status' => 'publish',
    'orderby'     => 'title', 
    'order'       => 'ASC'
);

add_filter( 'posts_where', 'title_filter', 10, 2 );
$wp_query = new WP_Query($args);
remove_filter( 'posts_where', 'title_filter', 10, 2 );
return $wp_query;

13
Dołącz kod wraz z kodem.
s_ha_dum,

2
Wielkie uproszczenie
Timo Huovinen,

1
Myślę, że kod sam się wyjaśnił, przynajmniej dla mnie. Dziękujemy za udostępnienie pełnego skryptu.
Hassan Dad Khan

Użyj '$ wpdb-> esc_like (' zamiast 'esc_sql (like_escape ('
fdrv

@fdrv Masz rację, ale zgodnie z dokumentacją wp $ wpdb-> esc_like nadal potrzebujesz esc_sql (). Myślę więc, że poprawnym kodem będzie esc_sql ($ wpdb-> esc_like ($ search_term))
Waqas Bukhary

16

Chciałeś zaktualizować ten kod, nad którym pracowaliście dla wordpress 4.0 i wyżej, ponieważ esc_sql () jest przestarzałe w wersji 4.0 wyższej.

function title_filter($where, &$wp_query){
    global $wpdb;

    if($search_term = $wp_query->get( 'search_prod_title' )){
        /*using the esc_like() in here instead of other esc_sql()*/
        $search_term = $wpdb->esc_like($search_term);
        $search_term = ' \'%' . $search_term . '%\'';
        $where .= ' AND ' . $wpdb->posts . '.post_title LIKE '.$search_term;
    }

    return $where;
}

Reszta rzeczy jest taka sama.

Chciałbym również zaznaczyć, że możesz użyć zmiennej s w argumentach WP_Query, aby przekazać wyszukiwane hasła, które, jak sądzę, będą również wyszukiwać tytuł postu.

Lubię to:

$args = array(
    'post_type' => 'post',
    's' => $search_term,
    'post_status' => 'publish',
    'orderby'     => 'title', 
    'order'       => 'ASC'        
);
$wp_query = new WP_Query($args);

Czym dokładnie search_prod_titlejest? Czy powinienem zmienić to na coś innego?
Antonios Tsimourtos

Od kiedy jest esc_sqltracony? To nie jest. $wpdb->escapejest jednak ... developer.wordpress.org/reference/functions/esc_sql
Jeremy

Pamiętaj, że parametr s przeszukuje również treść postu, co może nie być pożądanym celem. =)
Christine Cooper

10

Po opublikowaniu tutaj jakiegoś wrażliwego rozwiązania dostarczam nieco uproszczoną i odkażoną wersję.

Najpierw tworzymy funkcję posts_wherefiltra, która pozwala wyświetlać tylko posty spełniające określone warunki:

function cc_post_title_filter($where, &$wp_query) {
    global $wpdb;
    if ( $search_term = $wp_query->get( 'cc_search_post_title' ) ) {
        $where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'%' . $wpdb->esc_like( $search_term ) . '%\'';
    }
    return $where;
}

Teraz dodajemy cc_search_post_titledo naszych argumentów zapytania:

$args = array(
    'cc_search_post_title' => $search_term, // search post title only
    'post_status' => 'publish',
);

I wreszcie owiń filtr wokół zapytania:

add_filter( 'posts_where', 'cc_post_title_filter', 10, 2 );
$query = new WP_Query($args);
remove_filter( 'posts_where', 'cc_post_title_filter', 10 );

Korzystanie z get_posts ()

Niektóre funkcje pobierające posty nie uruchamiają filtrów, więc dołączone funkcje filtru posts_where nie zmodyfikują zapytania. Jeśli planujesz używać get_posts()zapytania do swoich postów, musisz ustawić wartość suppress_filtersfalse w tablicy argumentów:

$args = array(
    'cc_search_post_title' => $search_term,
    'suppress_filters' => FALSE,
    'post_status' => 'publish',
);

Teraz możesz użyć get_posts():

add_filter( 'posts_where', 'cc_post_title_filter', 10, 2 );
$posts = get_posts($args);
remove_filter( 'posts_where', 'cc_post_title_filter', 10 );

Co z sparametrem?

sParametr jest dostępny:

$args = array(
    's' => $search_term,
);

Dodając wyszukiwane hasło do sparametru praca i przeszukuje tytuł postu, przeszukuje również treść postu.

Co z titleparametrem dodanym do WP 4.4?

Przekazywanie wyszukiwanego terminu do titleparametru:

$args = array(
    'title' => $search_term,
);

Rozróżnia małe i wielkie litery, a LIKEnie %LIKE%. Oznacza to, że wyszukiwanie hellonie zwróci postu z tytułem Hello Worldlub Hello.


Doskonały. Szukałem parametru „post_title” jako parametru i, oczywiście, niczego nie znalazłem.
MastaBaba

7

Opierając się na innych odpowiedziach przede mną, aby zapewnić elastyczność w sytuacji, w której chcesz wyszukać post zawierający słowo w polu meta LUB w tytule wpisu, podam tę opcję za pomocą argumentu „tytuł_plik_filtrowy”. W tej implementacji zezwalam tylko na wejścia „OR” lub „AND” z domyślną wartością „AND”.

function title_filter($where, &$wp_query){
    global $wpdb;
    if($search_term = $wp_query->get( 'title_filter' )){
        $search_term = $wpdb->esc_like($search_term); //instead of esc_sql()
        $search_term = ' \'%' . $search_term . '%\'';
        $title_filter_relation = (strtoupper($wp_query->get( 'title_filter_relation'))=='OR' ? 'OR' : 'AND');
        $where .= ' '.$title_filter_relation.' ' . $wpdb->posts . '.post_title LIKE '.$search_term;
    }
    return $where;
}

Oto przykład kodu w działaniu dla bardzo prostego typu posta „faq”, w którym pytaniem jest sam tytuł posta:

add_filter('posts_where','title_filter',10,2);
$s1 = new WP_Query( array(
    'post_type' => 'faq',
    'posts_per_page' => -1,
    'title_filter' => $q,
    'title_filter_relation' => 'OR',
    'post_status' => 'publish',
    'orderby'     => 'title', 
    'order'       => 'ASC',
    'meta_query' => array(
        'relation' => 'OR',
        array(
            'key' => 'faq_answer',
            'value' => $q,
            'compare' => 'LIKE'
        )
    )
));
remove_filter('posts_where','title_filter',10,2);

1
Dobry wgląd, dodając niestandardowe „zmienne zapytania” do argumentów przekazywanych argumentów WP_Query, aby mieć dostęp do nich w posts_wherefiltrze.
Tom Auger
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.