Extender la consulta de búsqueda con $ oraciones adicionales valor

4

El siguiente paso en mi búsqueda para extender WordPress es alterar la forma en que WordPress utiliza la variable $sentence en posts_search para incluir una cadena adicional, cuando la variable $sentence cumple un cierto criterio.

El caso de uso específico aquí es que cuando alguien escribe algo como TL123 , también debería buscar TL-123 , con TL% como comodín aquí. Esto es para reducir los errores de búsqueda (para aquellos que no incluyen el guión).

He visto cómo podemos filtrar en posts_search con consultas SQL adicionales (en realidad estoy usando este con bastante éxito hasta ahora), pero estoy un poco confuso sobre cómo podría funcionar esto. Cualquier ayuda sería muy apreciada. Gracias!

Editar: para incluir más información sobre las necesidades gracias a @kaiser

  • Las búsquedas se realizan normalmente escribiendo TL123 , cuando en realidad el título real de la publicación es TL-123 en la mayoría de los casos; por lo tanto, el objetivo aquí es interceptar cuando la consulta de búsqueda incluye TL (NÚMERO) y también busca TL- (NÚMERO).

Una vez más, el truco aquí es que algunas publicaciones no incluyen TL, sino solo TL, por eso busco consultas de búsqueda que coincidan con ese patrón para buscar también una "frase parcial" adicional.

Gracias!

Actualizar

Bien, basado en la función de inicio de Kaiser, he encontrado lo siguiente:

function wpse66815_search_query_string( $search, &$wp_query )
{
    if (!is_admin() && is_search()) {

        print_r($search);

        global $wp_query;

        // get search term
        $search_term = array_shift($wp_query->query_vars['search_terms']);
        // specify string we'll use to replace
        $replace_var = 'TL';

        // find matches for that string
        preg_match_all("/{$replace_var}(?:[^0-9]*)(\d+)/i", $search_term, $out);

        // if there's no matches, return the normal search
        if ( empty($out[0]) )
            return $search;

        // find/generate the search term with the replacement
        $modified_search_term = preg_replace("/{$replace_var}(?:[^0-9]*)(\d+)/i", "{$replace_var}-$1", $search_term);

        // combine both the regular and modified search term
        $new_search[] = $search_term;
        $new_search[] = $modified_search_term;

        //var_dump($new_search);

        // generate the new search query
        foreach ( $new_search as $keyword )
        {
            $new_string_parts[] = $GLOBALS['wpdb']->prepare(
                 "
                    AND ((%s.post_title LIKE '%%%s%%') OR (%s.post_content LIKE '%%%s%%'))
                 "
                ,"{$GLOBALS['wpdb']->prefix}posts"
                ,like_escape( $keyword )
                ,"{$GLOBALS['wpdb']->prefix}posts"
                ,like_escape( $keyword )
            );
        }

        // set $search equal to results
        $search = implode( " ", $new_string_parts );

        //print_r($search);
    }

    return $search;
}
add_filter('posts_search', 'wpse66815_search_query_string',500,2);

La parte que no puedo pasar es en realidad es la consulta SQL real - > error abajo:

WordPress database error: [You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '.post_title LIKE 'tl123') OR ('wp__posts'.post_content LIKE 'tl123')) ' at line 2]

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND (('wp__posts'.post_title LIKE 'tl123') OR ('wp__posts'.post_content LIKE 'tl123')) AND (('wp__posts'.post_title LIKE 'TL-123') OR ('wp__posts'.post_content LIKE 'TL-123')) AND wp_posts.post_type IN ('post', 'page', 'attachment', 'galleries', 'idea_gallery', 'moulding_profiles', 'moulding_collection', 'moulding_combination') AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 2 AND wp_posts.post_status = 'private') ORDER BY wp_posts.post_date DESC LIMIT 0, 80

¿Algún indicador sobre dónde me equivoqué? Gracias!

Actualización # 2

He empezado a ver algunos problemas:

  • Estaba haciendo wp__posts en lugar de wp_posts (lo actualicé arriba)
  • Como se mencionó kaiser , es posible que la parte LIKE %s tenga que ser LIKE %%s% pero eso no se analiza correctamente.

El error es ahora:

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND (('wp_posts'.post_title LIKE 'tl123') OR ('wp_posts'.post_content LIKE 'tl123')) AND (('wp_posts'.post_title LIKE 'TL-123') OR ('wp_posts'.post_content LIKE 'TL-123')) AND wp_posts.post_type IN ('post', 'page', 'attachment', 'galleries', 'idea_gallery', 'moulding_profiles', 'moulding_collection', 'moulding_combination') AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 2 AND wp_posts.post_status = 'private') ORDER BY wp_posts.post_date DESC LIMIT 0, 80

El error anterior (por lo que puedo decir) en realidad está intentando buscar una publicación que sea a la vez tl123 y TL-123 , pero creo que OR es lo que quiero (ya que quiero devolver las publicaciones en una u otra situación).

Actualización # 3

Se actualizó la función para que escape correctamente %s , por lo que el error es ahora:

WordPress database error: [You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '.post_title LIKE '%tl123%') OR ('wp_posts'.post_content LIKE '%tl123%')) ' at line 2]

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND (('wp_posts'.post_title LIKE '%tl123%') OR ('wp_posts'.post_content LIKE '%tl123%')) AND (('wp_posts'.post_title LIKE '%TL-123%') OR ('wp_posts'.post_content LIKE '%TL-123%')) AND wp_posts.post_type IN ('post', 'page', 'attachment', 'galleries', 'idea_gallery', 'moulding_profiles', 'moulding_collection', 'moulding_combination') AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 2 AND wp_posts.post_status = 'private') ORDER BY wp_posts.post_date DESC LIMIT 0, 80

Actualización # 4

Esto es lo que terminé haciendo - > el foreach no estaba envolviendo correctamente (con el operador AND / OR como @kaiser mencionado), así que los separé en sus propias inserciones de matriz.

function wpse66815_search_query_string( $search, &$wp_query )
{
    if (!is_admin() && is_search()) {

        //print_r($search);

        global $wp_query,$wpdb;

        // get search term
        $search_term = array_shift($wp_query->query_vars['search_terms']);
        // specify string we'll use to replace
        $replace_var = 'TL';

        // find matches for that string
        preg_match_all("/{$replace_var}(?:[^0-9]*)(\d+)/i", $search_term, $out);

        // if there's no matches, return the normal search
        if ( empty($out[0]) )
            return $search;

        // find/generate the search term with the replacement
        $modified_search_term = preg_replace("/{$replace_var}(?:[^0-9]*)(\d+)/i", "{$replace_var}-$1", $search_term);

        // combine both the regular and modified search term
        $new_search[] = $search_term;
        $new_search[] = $modified_search_term;

        var_dump($new_search);

        // generate the new search query
        $new_string_parts[] = $wpdb->prepare( "AND ((({$wpdb->posts}.post_title LIKE '%%%s%%') OR ({$wpdb->posts}.post_content LIKE '%%%s%%'))",like_escape( $new_search[0] ),like_escape( $new_search[0] ));
        $new_string_parts[] = $wpdb->prepare( "OR (({$wpdb->posts}.post_title LIKE '%%%s%%') OR ({$wpdb->posts}.post_content LIKE '%%%s%%')))",like_escape( $new_search[1] ),like_escape( $new_search[1] ));

        // set $search equal to results
        $search = implode( " ", $new_string_parts );

        //print_r($search);
    }

    return $search;
}
add_filter('posts_search', 'wpse66815_search_query_string',500,2);

Tiene algunos problemas si alguien escribe tl123 tl456 (dos apariciones de la palabra clave tl ), pero estoy trabajando en esa parte. Gracias!

    
pregunta Zach 01.10.2012 - 20:44

1 respuesta

3

Con mucho gusto he escrito dos complementos para eso ayer:

Filtro / Núcleo

Así es como se ve una parte de consulta de búsqueda dentro del filtro posts_search :

' AND (((wp_XX_posts.post_title LIKE '%test%') OR (wp_XX_posts.post_content LIKE '%test%'))) '

donde wp_XX_ es solo el $wpdb->prefix para mi sitio de prueba WPSE dentro de mi instalación de MU local.

Plugin # 1: elimine los tipos de publicaciones que no necesitamos.

Aquí hay un complemento que modifica los tipos de publicación buscados, ya que esto es necesario a menudo.

<?php
/** Plugin Name: (#66815) »kaiser« Limit search query post types */

/**
 * Alter the searched post types
 * 
 * @param  object $query
 * @return object $query
 */
add_action( 'pre_get_posts', 'wpse66815_pre_get_posts' );
function wpse66815_pre_get_posts( $query )
{
    if ( $query->is_main_query() )
    {
        $query->set( 'post_type', 'YOUR_POST_TYPE' );
    }

    return $query;
}

Complemento # 2: modificar la cadena de búsqueda

Ahora que sabemos cómo se ve la cadena de búsqueda predeterminada para el título de la publicación y el contenido, solo tenemos que reconstruirla de la manera que la necesitamos:

<?php 
/** Plugin Name: (#66815) »kaiser« Modify search query string */

function wpse66815_search_query_string( $search_string )
{
    global $wpdb;

    $searched_for = preg_match_all(
        // Match a prefix (%), but exclude it from the capture
        // Any character, any number of repetitions
        // Match a suffix (%), but exclude it from the capture
        "/(?<=\%)(.*)(?=\%)/",
        $search_string,
        $search_string_matches
    );

    // We only need one element
    $searched_for = array_shift( $search_string_matches );

    // Now we need to search for [LETTERS (min 1)][NUMBER (zero or more)][CHARACTER (zero or more)]
    preg_match_all(
        "/([^a-zA-Z][\d+]*[-_ ]*)/",
        $searched_for,
        $string_part_matches
    );

    // Here we now got matches - if not, we can simply abort and leave the default
    $searched_for = array_shift( $string_part_matches );
    if ( empty( $searched_for ) )
        return $search_string;

    // Finally we need to split the string by all parts that are allowed
    // YOU NEED TO EDIT MY ANSWER HERE AND FILL IN WHAT WORKS FOR YOU
    $keywords = preg_split(
         "/([\s]*[\d+]*[-_ ]*)/",
         $searched_for,
         -1, // 0 & -1 are NO limit
         PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE
    );

    // Now loop and build an array for further processing
    // Our first search string is - of course - the default string
    $string_parts = array( $search_string );
    foreach ( $keywords as $keyword )
    {
        $new_string_parts[] = $GLOBALS['wpdb']->prepare(
            " AND ((%s.post_title LIKE '%s') OR (%s.post_content LIKE '%s')) ",
            $wpdb->posts,
            $wpdb->esc_like( $keyword ),
            $wpdb->posts,
            $wpdb->esc_like( $keyword )
        );
    }

    // Now lets glue them together, return and see what we get...
    return implode( " ", $new_string_parts );
}

Este complemento nd no se ha probado, ya que mis necesidades son diferentes y creo que algunas de las expresiones regulares no son completamente lo que necesitas. Tendrás que arreglar eso y actualizar esta respuesta (esto es su parte en "devolver a la comunidad" en esta C / A). Una buena herramienta para construir expresiones regulares, que acabo de encontrar, es Expresso . Es muy feo (como la presencia en la web), pero extremadamente útil.

    
respondido por el kaiser 02.10.2012 - 18:48

Lea otras preguntas en las etiquetas