WP_Query mit "post_title LIKE 'something%'"?

44

Ich muss ein WP_Querymit LIKEauf das machen post_title.

Ich habe mit diesem regulären angefangen 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
    )
); 

Aber was ich eigentlich machen möchte, sieht in SQL so aus:

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

Die Ausgabe druckt die Ergebnisse, die ich erwarte, aber ich benutze die reguläre <?php while ( $wp_query->have_posts() ) : $wp_query->the_post(); ?>, um die Ergebnisse anzuzeigen.
Und das funktioniert nicht mit $wpdb->get_results().

Wie kann ich das erreichen, was ich hier beschrieben habe?

Ludo
quelle

Antworten:

45

Ich würde dies mit einem Filter auf lösen WP_Query. Eine, die eine zusätzliche Abfragevariable erkennt und diese als Präfix des Titels verwendet.

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

Auf diese Weise können Sie immer noch anrufen WP_Query. Sie übergeben lediglich den Titel als wpse18703_titleArgument (oder ändern den Namen in einen kürzeren Namen).

Jan Fabry
quelle
Dieser fehlt irgendwie der $wpdb->prepare().
Kaiser
@kaiser: Es ist schon lange her, aber ich denke das war mit nicht möglich prepare(). $wpdb->prepare('LIKE "%s%%"', 'banana')würde zurückkehren "LIKE ''banana'%'", also müssen wir die Abfrage selbst konstruieren und auch die Escape-Operation ausführen.
Jan Fabry
1
@ JanFabry Freut mich, Sie wieder zu sehen! :) Schau mal im Chat vorbei, hm? StopPress würde sich freuen, Sie zu sehen. Über das prepare(). Ja, das ist schwierig und ich musste es mehrmals versuchen, bevor ich mich darum kümmerte. Von etwas habe ich gerade: $wpdb->prepare( ' AND {$wpdb->posts}.post_title LIKE %s ', esc_sql( '%'.like_escape( trim( $term ) ).'%' ) ). Und ich bin mir ziemlich sicher, dass das esc_sql()unnötig und nur paranoid ist.
Kaiser
Es scheint, dass Sie eine Zeichenfolge mit '(Apostroph) nicht suchen können . Ich denke, es ist wegen der Flucht? Ich habe die Lösung noch nicht gefunden
Vincent Decaux
19

Vereinfacht:

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;
Rao
quelle
13
Bitte fügen Sie Ihrem Code eine Erklärung bei.
s_ha_dum
2
Große Vereinfachung
Timo Huovinen
1
Code ist meiner Meinung nach selbsterklärend, zumindest für mich. Vielen Dank für das Teilen des vollständigen Skripts.
Hassan Dad Khan
Verwenden Sie '$ wpdb-> esc_like (' anstelle von 'esc_sql (like_escape ('
fdrv
@fdrv Du hast recht aber laut wp docs brauchst $ wpdb-> esc_like noch esc_sql (). Ich denke, der richtige Code wäre esc_sql ($ wpdb-> esc_like ($ search_term))
Waqas Bukhary
16

Wollte diesen Code aktualisieren, an dem ihr für WordPress 4.0 und höher gearbeitet habt, da esc_sql () in 4.0 höher veraltet ist.

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

Der Rest des Zeugs ist dasselbe.

Ich möchte auch darauf hinweisen, dass Sie die Variable s in WP_Query-Argumenten verwenden können, um Suchbegriffe zu übergeben, die auch nach dem Titel des Beitrags suchen, glaube ich.

So was:

$args = array(
    'post_type' => 'post',
    's' => $search_term,
    'post_status' => 'publish',
    'orderby'     => 'title', 
    'order'       => 'ASC'        
);
$wp_query = new WP_Query($args);
Ashan Jay
quelle
Was genau search_prod_titleist Sollte ich dies zu etwas anderem ändern?
Antonios Tsimourtos
Seit wann wird esc_sqlberaubt? Es ist nicht. $wpdb->escapeist aber ... developer.wordpress.org/reference/functions/esc_sql
Jeremy
Beachten Sie, dass der Parameter s auch den Inhalt des Posts durchsucht, was möglicherweise nicht das gewünschte Ziel ist. =)
Christine Cooper
10

Da hier eine verwundbare Lösung veröffentlicht wurde, habe ich eine etwas vereinfachte und bereinigte Version.

Zunächst erstellen wir eine Funktion für den posts_whereFilter, mit der Sie nur Posts anzeigen können, die bestimmten Bedingungen entsprechen:

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

Nun fügen wir cc_search_post_titleunseren Abfrageargumenten hinzu:

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

Und schließlich wickeln Sie den Filter um die Abfrage:

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

Get_posts () verwenden

Bestimmte Funktionen, die Posts abrufen, führen keine Filter aus, sodass die von Ihnen angehängten posts_where-Filterfunktionen die Abfrage nicht ändern. Wenn Sie get_posts()vorhaben, Ihre Posts abzufragen, müssen Sie suppress_filtersin Ihrem Argumentarray den Wert false festlegen :

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

Jetzt können Sie verwenden 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 );

Was ist mit dem sParameter?

Der sParameter ist verfügbar:

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

Wenn Sie Ihren Suchbegriff in den sParameter work einfügen und den Beitragstitel durchsuchen, wird auch der Beitragsinhalt durchsucht.

Was ist mit dem titleParameter, der mit WP 4.4 hinzugefügt wurde?

Übergabe eines Suchbegriffs an den titleParameter:

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

Ist case sensitive und LIKEnicht %LIKE%. Diese mittlere Suche nach hellogibt keinen Beitrag mit dem Titel Hello Worldoder zurück Hello.

Christine Cooper
quelle
Ausgezeichnet. Ich habe nach 'post_title' als Parameter gesucht und offensichtlich nichts gefunden.
MastaBaba,
7

Aufbauend auf anderen Antworten vor mir gebe ich diese Option über das Argument "title_filter_relation" an, um Flexibilität in der Situation zu bieten, in der Sie einen Beitrag suchen möchten, der ein Wort in einem Metafeld ODER im Titel des Beitrags enthält. In dieser Implementierung erlaube ich nur "OR" - oder "AND" -Eingaben mit dem Standardwert "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;
}

Hier ist ein Beispiel für den Code in Aktion für einen sehr einfachen Beitragstyp "faq", bei dem die Frage der Beitragstitel selbst ist:

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);
David Choy
quelle
1
Guter Einblick, indem Sie den übergebenen Abfrageargs benutzerdefinierte "Abfragevariablen" hinzufügen, um WP_Queryim posts_whereFilter darauf zugreifen zu können .
Tom Auger