Extensão da consulta de pesquisa com valor adicional $ sentença

4

Em seguida, em minha busca para estender o WordPress está alterando como o WordPress usa a variável $sentence em posts_search para incluir uma string adicional, quando a variável $sentence atende a um determinado critério.

O exemplo específico aqui é que quando alguém digita algo como TL123 , ele também deve procurar TL-123 , com TL% sendo o curinga aqui. Isso é para reduzir erros de pesquisa (para aqueles que não incluem o hífen).

Já vi como podemos filtrar em posts_search com consultas SQL adicionais (estou realmente usando este com muito bom sucesso até agora), mas estou um pouco confuso sobre como isso poderia funcionar. Qualquer ajuda seria muito apreciada. Obrigado!

Editar - para incluir mais informações sobre as necessidades graças ao @kaiser

  • As pesquisas são normalmente feitas digitando TL123 , quando na realidade o título atual é TL-123 na maioria dos casos - então, o objetivo aqui é interceptar quando a consulta de pesquisa inclui TL (NUMBER) e também procura TL - (NUMBER).

Novamente, o truque aqui é que algumas postagens não incluem TL- mas apenas TL, por isso estou procurando por consultas de pesquisa que correspondam a esse padrão para pesquisar também uma "frase parcial" adicional.

Obrigado!

Atualizar

Tudo bem, então, baseado na função inicial do Kaiser, eu tenho o seguinte:

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

A parte que não posso passar é, na verdade, a consulta SQL real - > erro abaixo:

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

Alguma indicação de onde eu errei? Obrigado!

Atualização nº 2

Eu comecei a ver alguns problemas:

  • Ele estava fazendo wp__posts em vez de wp_posts (atualizei isso acima)
  • Como kaiser mencionou, a porção LIKE %s talvez precise ser LIKE %%s% , mas não está analisando corretamente.

Erro agora:

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

O erro acima (pelo que posso dizer) está realmente tentando procurar uma postagem que seja tl123 e TL-123 , mas acho que OR é o que eu quero (como quero retornar postagens em uma ou outra situação).

Atualização nº 3

Função atualizada para escapar corretamente de %s , então o erro é agora:

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

Atualização # 4

Veja o que acabei fazendo - > o foreach não estava empacotando corretamente (com o operador AND / OR como mencionado pelo @kaiser), então os separei em suas próprias inserções 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);

Ele tem alguns problemas se alguém digitar tl123 tl456 (duas ocorrências da palavra-chave tl ), mas estou trabalhando nessa parte. Obrigado!

    
por Zach 01.10.2012 / 20:44

1 resposta

3

Felizmente eu escrevi dois plugins para isso ontem:

Filtro / núcleo

Essa é a aparência de uma parte da consulta de pesquisa dentro do filtro posts_search :

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

onde wp_XX_ é apenas o $wpdb->prefix do meu site de teste WPSE dentro da minha instalação local da MU.

Plugin # 1 - elimine os tipos de postagem que não precisamos.

Aqui está um plug-in que modifica os tipos de post pesquisados, pois isso é necessário com frequência.

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

Plugin # 2 - modifique a string de pesquisa

Agora que sabemos como a sequência de pesquisa padrão para o título e o conteúdo da postagem parece, basta recriá-la da maneira que precisamos:

<?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 plugin nd não foi testado, já que minhas necessidades são diferentes e eu acho que algumas das regexes não são completamente o que você precisa - você terá que consertar isso e atualizar esta resposta (isto é sua parte em "dar a comunidade de volta" neste Q / A). Uma boa ferramenta para criar a regex, que acabei de encontrar, é Expresso . É muito feio (como a presença na web), mas extremamente útil.

    
por kaiser 02.10.2012 / 18:48

Tags