WP_QUERY|是否帮助我创建具有‘OR’关系的搜索词?

时间:2020-02-25 作者:Jason Is My Name

我编写了一个非常复杂的脚本,它基本上允许用户从类别、标签以及搜索词中进行选择。然后通过WP\\u查询运行这些参数。

我可以使用“AND”关系成功地获得我想要的结果,这适用于用户将搜索参数填充到所有字段的情况;搜索词、标记和;类别。它还可以将三个参数中的一个参数留空,两个参数留空,并在所有参数留空时返回所有产品。

然后,我尝试添加一个选项来使用关系“OR”。这将允许他们仍然添加三个搜索参数,但结果只需应用于其中一个参数。如果用户仅从标记和类别中进行选择,则此操作有效,但是如果用户使用搜索词参数,则不会返回正确的结果。

我认为这是因为关系只设置为标签和类别,我需要将其扩展到搜索词。

希望您能够理解我试图实现的目标,在我的代码片段中,您可以假设所有变量的填充都是正确的,我只是想寻求帮助,将搜索项添加为关系为“OR”的参数。以下是我当前的WP\\U查询:

$paged              = !empty($_POST[\'page\'])                ? $_POST[\'page\']                : 1;
$display_count      = !empty($_POST[\'display_count\'])       ? $_POST[\'display_count\']       : 9;
$direction          = !empty($_POST[\'direction\'])           ? $_POST[\'direction\']           : \'\';
$search_term        = !empty($_POST[\'search_term\'])         ? $_POST[\'search_term\']         : \'\';
$search_tags        = !empty($_POST[\'search_tags\'])         ? $_POST[\'search_tags\']         : \'\';
$search_categories  = !empty($_POST[\'search_categories\'])   ? $_POST[\'search_categories\']   : \'\';
$search_relation    = !empty($_POST[\'search_relation\'])     ? $_POST[\'search_relation\']     : \'AND\';

$offset_modifier    = 0;
if      ($direction     === \'prev\') :
    $offset_modifier        = $paged - 2;
elseif  ($direction     === \'next\') :
    $offset_modifier        = $paged;
elseif  ($direction     === \'last\') :
    $offset_modifier        = $paged - 1;
endif;
$offsetcalc = $offset_modifier * $display_count;

$args = array(
    \'post_type\'         => \'product\',
    \'post_status\'       => \'publish\',
    \'orderby\'           => \'menu_order\',
    \'order\'             => \'ASC\',
    \'posts_per_page\'    => $display_count,
    \'page\'              => $paged,
    \'offset\'            => $offsetcalc,
    \'tax_query\'         => array()
);

if ( $search_term != \'\' ) :
    $args[\'s\'] = $search_term;
endif;

if ( $search_tags != \'\' ) :
    $args[\'tax_query\'][\'product_tag\'] = array(
        \'taxonomy\'          => \'product_tag\',
        \'field\'             => \'slug\',
        \'terms\'             => array($search_tags),
    );

    if (strpos($search_tags, \', \') !== false) {
        $args[\'tax_query\'][\'product_tag\'][\'relation\'] = $search_relation;
    }
endif;

if ( $search_categories != \'\' ) :
    $args[\'tax_query\'][\'product_cat\'] = array(
        \'taxonomy\'          => \'product_cat\',
        \'field\'             => \'slug\',
        \'terms\'             => array($search_categories),
    );

    if (strpos($search_categories, \', \') !== false) {
        $args[\'tax_query\'][\'product_cat\'][\'relation\'] = $search_relation;
    }
endif;

if ( $search_tags != \'\' && $search_categories != \'\' ) :
    $args[\'tax_query\'][\'relation\'] = $search_relation;
endif;

$the_query = new WP_Query( $args );

if ( $the_query->have_posts() ) :
因此,我尽最大努力使其在搜索词上具有“OR”的关系(请注意“if($search\\u term!=“”)):“;以及对$args[\'tax\\u query\'][\'relation\']=$搜索\\u关系"E;IF语句):

$paged              = !empty($_POST[\'page\'])                ? $_POST[\'page\']                : 1;
$display_count      = !empty($_POST[\'display_count\'])       ? $_POST[\'display_count\']       : 9;
$direction          = !empty($_POST[\'direction\'])           ? $_POST[\'direction\']           : \'\';
$search_term        = !empty($_POST[\'search_term\'])         ? $_POST[\'search_term\']         : \'\';
$search_tags        = !empty($_POST[\'search_tags\'])         ? $_POST[\'search_tags\']         : \'\';
$search_categories  = !empty($_POST[\'search_categories\'])   ? $_POST[\'search_categories\']   : \'\';
$search_relation    = !empty($_POST[\'search_relation\'])     ? $_POST[\'search_relation\']     : \'AND\';

$offset_modifier    = 0;
if      ($direction     === \'prev\') :
    $offset_modifier        = $paged - 2;
elseif  ($direction     === \'next\') :
    $offset_modifier        = $paged;
elseif  ($direction     === \'last\') :
    $offset_modifier        = $paged - 1;
endif;
$offsetcalc = $offset_modifier * $display_count;

$args = array(
    \'post_type\'         => \'product\',
    \'post_status\'       => \'publish\',
    \'orderby\'           => \'menu_order\',
    \'order\'             => \'ASC\',
    \'posts_per_page\'    => $display_count,
    \'page\'              => $paged,
    \'offset\'            => $offsetcalc,
    \'tax_query\'         => array()
);

if ( $search_term != \'\' ) :
    $args[\'tax_query\'][\'product_tit\'] = array(
        \'taxonomy\'          => \'product_tit\',
        \'field\'             => \'slug\',
        \'terms\'             => $search_term,
    );
endif;

if ( $search_tags != \'\' ) :
    $args[\'tax_query\'][\'product_tag\'] = array(
        \'taxonomy\'          => \'product_tag\',
        \'field\'             => \'slug\',
        \'terms\'             => array($search_tags),
    );

    if (strpos($search_tags, \', \') !== false) {
        $args[\'tax_query\'][\'product_tag\'][\'relation\'] = $search_relation;
    }
endif;

if ( $search_categories != \'\' ) :
    $args[\'tax_query\'][\'product_cat\'] = array(
        \'taxonomy\'          => \'product_cat\',
        \'field\'             => \'slug\',
        \'terms\'             => array($search_categories),
    );

    if (strpos($search_categories, \', \') !== false) {
        $args[\'tax_query\'][\'product_cat\'][\'relation\'] = $search_relation;
    }
endif;

if ((isset($search_term) && isset($search_tags)) || (isset($search_term) && isset($search_categories)) || (isset($search_tags) && isset($search_categories))) :
    $args[\'tax_query\'][\'relation\'] = $search_relation;
endif;

$the_query = new WP_Query( $args );

if ( $the_query->have_posts() ) :
我的更改不允许搜索词参数工作,我想我使用了错误的方法或错误的分类名称“product\\u tit”。。。

Please help me create the search term as a parameter with the \'OR\' relation and ensure it is narrowed down to the products title only

有人能帮忙吗?

非常感谢贡献者Jason。

编辑:不使用“或”关系的最新代码。

// PRODUCT PAGINATION AJAX FUNCTION
    function load_products_by_ajax_callback() {
        $paged              = !empty($_POST[\'page\'])                ? $_POST[\'page\']                : 1;
        $display_count      = !empty($_POST[\'display_count\'])       ? $_POST[\'display_count\']       : 9;
        $direction          = !empty($_POST[\'direction\'])           ? $_POST[\'direction\']           : \'\';
        $search_term        = !empty($_POST[\'search_term\'])         ? $_POST[\'search_term\']         : \'\';
        $search_tags        = !empty($_POST[\'search_tags\'])         ? $_POST[\'search_tags\']         : \'\';
        $search_categories  = !empty($_POST[\'search_categories\'])   ? $_POST[\'search_categories\']   : \'\';
        $search_relation    = !empty($_POST[\'search_relation\'])     ? $_POST[\'search_relation\']     : \'AND\';

        $offset_modifier    = 0;
        if      ($direction     === \'prev\') :
            $offset_modifier        = $paged - 2;
        elseif  ($direction     === \'next\') :
            $offset_modifier        = $paged;
        elseif  ($direction     === \'last\') :
            $offset_modifier        = $paged - 1;
        endif;
        $offsetcalc = $offset_modifier * $display_count;

        $args = array(
            \'post_type\'         => \'product\',
            \'post_status\'       => \'publish\',
            \'orderby\'           => \'menu_order\',
            \'order\'             => \'ASC\',
            \'posts_per_page\'    => $display_count,
            \'page\'              => $paged,
            \'offset\'            => $offsetcalc >= 1 ? $offsetcalc : \'\',
            \'tax_query\'         => array()
        );

        // Parse the search tags/categories list into an array.
        $tags               = strlen( $search_tags )            ? wp_parse_slug_list( $search_tags )        : \'\';
        $cats               = strlen( $search_categories )      ? wp_parse_slug_list( $search_categories )  : \'\';
        $has_search_term    = ( strlen( $search_term ) > 0 );
        $relation           = strtoupper( trim( $search_relation ) ); // normalize it into all caps

        // We don\'t use $args[\'s\']. Instead, we write our own custom SQL for searching
        // in the post title only. We also don\'t use the tax_query parameter (anymore).
        // This is basically $args[\'tax_query\'], except that we *don\'t* add it to $args.
        $tax_query = array();

        if ( ! empty( $search_tags ) ) {
            $tax_query[] = array(
                \'taxonomy\'  => \'product_tag\',
                \'terms\'     => wp_parse_slug_list( $search_tags ),
                \'field\'     => \'slug\',
                \'operator\'  => $search_relation,
            );
        }

        if ( ! empty( $search_categories ) ) {
            $tax_query[] = array(
                \'taxonomy\'  => \'product_cat\',
                \'terms\'     => wp_parse_slug_list( $search_categories ),
                \'field\'     => \'slug\',
                \'operator\'  => $search_relation,
            );
        }

        if ( ! empty( $tax_query ) ) { // if empty, don\'t set the relation
            $tax_query[\'relation\'] = $search_relation;
        }

        $_filter = true; // a (private) var for the closure below
        add_filter( \'posts_clauses\',
        function ( $clauses ) use ( &$_filter, $search_term, $tax_query ) {
            if ( ! $_filter ) {
                return $clauses;
            }

            global $wpdb;

            $search_where = \'\';
            if ( $search_term ) {
                $like  = \'%\' . $wpdb->esc_like( $search_term ) . \'%\';
                $search_where = $wpdb->prepare( "$wpdb->posts.post_title LIKE %s", $like );
            }

            if ( ! empty( $tax_query ) ) {
                $tax_query = new WP_Tax_Query( $tax_query );
                $is_and = ( \'AND\' === $tax_query->relation );

                $tax_query = $tax_query->get_sql( $wpdb->posts, \'ID\' );
                if ( empty( $tax_query[\'where\'] ) ) { // just in case..
                    if ( $search_where ) {
                        $clauses[\'where\'] .= " AND ( $search_where )";
                    }
                    return $clauses;
                }

                $clauses[\'join\'] .= $tax_query[\'join\'];
                if ( $is_and ) {
                    $clauses[\'where\'] .= $search_where ?
                        " AND ( $search_where ) {$tax_query[\'where\']}" :
                        $tax_query[\'where\'];
                } else {
                    $where = preg_replace( \'/^ *AND\\b/\', \'\', $tax_query[\'where\'] );
                    $clauses[\'where\'] .= $search_where ?
                        " AND ( ( $search_where ) OR{$where} )" :
                        $tax_query[\'where\'];
                }
                $clauses[\'groupby\'] = "$wpdb->posts.ID";
            } elseif ( $search_where ) {
                $clauses[\'where\'] .= " AND ( $search_where )";
            }

            return $clauses;
        } );

        $the_query = new WP_Query( $args );
        $_filter = false;
    
        if ( $the_query->have_posts() ) :

            woocommerce_product_loop_start();

            echo \'<div id="product-list" class="product-list">\';

                while ( $the_query->have_posts() ) :

                    $the_query->the_post();

                    wc_get_template_part( \'content\', \'productloop\' );

                endwhile;

            echo \'</div>\';

            woocommerce_product_loop_end();

        else :

            echo \'<div class="no-search-results">This search returned no results, please refine your parameters!</div>\';

        endif;

        $product_loop_count = $the_query->found_posts;
        echo \'<div class="product-list-count">\';
            echo \'<div class="product-loop-count-text">Total product count:&nbsp;</div><div id="product-loop-count">\' . $product_loop_count . \'</div>\';
        echo \'</div>\';
        
        wp_die();
    }
    add_action(\'wp_ajax_load_products_by_ajax\', \'load_products_by_ajax_callback\');
    add_action(\'wp_ajax_nopriv_load_products_by_ajax\', \'load_products_by_ajax_callback\');
// END PRODUCT PAGINATION AJAX FUNCTION

1 个回复
最合适的回答,由SO网友:Sally CJ 整理而成

(Revised on March 25 2020 UTC)

在这个修改后的答案中,我将从代码开始:

定义变量:(我故意只包括$args 零件)

// define POSTed/submitted variables here like $paged, $display_count and $direction

// define the offset/\'direction\' stuff here

// then define your $args array
$args = array(
    \'post_type\'      => \'product\',
    \'post_status\'    => \'publish\',
    \'orderby\'        => \'menu_order\',
    \'order\'          => \'ASC\',
    \'posts_per_page\' => $display_count,
    // You should use \'paged\' and not \'page\'.
    \'paged\'          => $paged,
    \'offset\'         => $offsetcalc >= 1 ? $offsetcalc : \'\',
    \'tax_query\'      => array(),
);

// This is basically $args[\'tax_query\'], except that we *don\'t* add it to $args.
$tax_query = array();

if ( ! empty( $search_tags ) ) {
    $tax_query[] = array(
        \'taxonomy\' => \'product_tag\',
        \'terms\'    => wp_parse_slug_list( $search_tags ),
        \'field\'    => \'slug\',
    );
}

if ( ! empty( $search_categories ) ) {
    $tax_query[] = array(
        \'taxonomy\' => \'product_cat\',
        \'terms\'    => wp_parse_slug_list( $search_categories ),
        \'field\'    => \'slug\',
    );
}

if ( ! empty( $tax_query ) ) { // if empty, don\'t set the relation
    $tax_query[\'relation\'] = $search_relation;
}

$_filter = true; // a (private) var for the closure below
add_filter( \'posts_clauses\',
function ( $clauses ) use ( &$_filter, $search_term, $tax_query ) {
    if ( ! $_filter ) {
        return $clauses;
    }

    global $wpdb;

    $search_where = \'\';
    if ( $search_term ) {
        $like  = \'%\' . $wpdb->esc_like( $search_term ) . \'%\';
        $search_where = $wpdb->prepare( "$wpdb->posts.post_title LIKE %s", $like );
    }

    if ( ! empty( $tax_query ) ) {
        $tax_query = new WP_Tax_Query( $tax_query );
        $is_and = ( \'AND\' === $tax_query->relation );

        $tax_query = $tax_query->get_sql( $wpdb->posts, \'ID\' );
        if ( empty( $tax_query[\'where\'] ) ) { // just in case..
            if ( $search_where ) {
                $clauses[\'where\'] .= " AND ( $search_where )";
            }
            return $clauses;
        }

        $clauses[\'join\'] .= $tax_query[\'join\'];
        if ( $is_and ) {
            $clauses[\'where\'] .= $search_where ?
                                 " AND ( $search_where ) {$tax_query[\'where\']}" :
                                 $tax_query[\'where\'];
        } else {
            $where = preg_replace( \'/^ *AND\\b/\', \'\', $tax_query[\'where\'] );
            $clauses[\'where\'] .= $search_where ?
                                 " AND ( ( $search_where ) OR{$where} )" :
                                 $tax_query[\'where\'];
        }
        $clauses[\'groupby\'] = "$wpdb->posts.ID";
    } elseif ( $search_where ) {
        $clauses[\'where\'] .= " AND ( $search_where )";
    }

    return $clauses;
} );

$the_query = new WP_Query( $args );
$_filter = false; // disable the filter, to avoid issues with other WP_Query calls

一点解释(对于上面的代码#2)

您要找的是WHERE 类似以下内容的子句:

(还有其他条件/变化,但这是主要条件)

WHERE post_type = \'product\' AND (
  ( post_title LIKE \'%<search term>%\' ) # Find posts that matched the search term,
  OR ( product_tag IN (<ids/slugs>) )   # ..or those that are in the specified tags
  OR ( product_cat IN (<ids/slugs>) )   # ..or categories.
)
在上面的代码#2中,我使用posts_clauses hook 补充一下WHERE 子句(并做其他相关的事情),但是为了为分类法(标记/类别)查询生成适当的SQL子句,我使用WP_Tax_Query (这是什么WP_Query 使用,顺便说一句)。

我正在使用的其他注释wp_parse_slug_list() 将(逗号分隔的)标记和类别解析为一个slug数组。您还应该使用它来确保我们有一个有效的数组,因为该函数运行良好

  • 记住如果offset0, 然后在$args, 这个offset 应设置为\'\' (即空字符串)而不是0, 确保$paged 按预期工作。

    只是一张个人便条。。。对不起,我忘了使用WP_Tax_Query 之前。;)