10up / ElasticPress

A fast and flexible search and query engine for WordPress.
https://elasticpress.io
GNU General Public License v2.0
1.25k stars 311 forks source link

Facet counts do not match the result count #3799

Closed xmedia-nl closed 9 months ago

xmedia-nl commented 9 months ago

Describe your question

I made a custom searchpage that does a WP Query with the searchkeyword. On the searchpage I generate a few filters. I haven't used the default widgets because that makes the searchpage terribly slow. So what I did was read the ep_facet_aggs from the globals and use the product_cat, ep_meta_range_filterprice_min, ep_meta_range_filterprice_max and pa_merk (which is the product brand). Then I make a general WP Query with the keyword and posttype and add facets with the ep_facet_query_filters hook

Problem is that the ep_facet_aggs gives a count for that brand, but when adding the filter for that brand, the results don't always match the count. For instance, brand Hills says count is 7, but when adding this to the filter there are 0 results. Most brands do give the correct numbers of results, so the filter does work as intended. Can someone spot what I can improve to get the correct results?

The actual search can be tested here: https://landvandieren.nl/?s=kattenvoer

    public function do_search_query($keyword, $paged = 1)
    {
        $args = array(
            'ep_integrate'       => true,
            'ep_search_template' => true,
            'post_status'        => 'publish',
            'post_type'          => ['product'],
            's'                  => $keyword,
            'posts_per_page'     => 12,
            'paged'              => $paged,
            'custom_es_search'  => true,
        );

        $min_price = (isset($_POST['price_range'][0]) && $_POST['price_range'][0] !== "") ? $_POST['price_range'][0] : '';
        $max_price = (isset($_POST['price_range'][1]) && $_POST['price_range'][1] !== "") ? $_POST['price_range'][1] : '';
        if($min_price !== '' || $max_price !== ''){
            // sort by price
            $args['orderby'] = 'meta_value_num';
            $args['order'] = 'ASC';
            $args['meta_key'] = '_price';
        }

        $query = new \WP_Query($args);
        error_log('do_search_query ' . $keyword);
        return $query;
    }
    add_filter('ep_facet_query_filters', [$this, 'add_query_filters'], 50);

    [...]

    public function add_query_filters($filters)
    {

        if (!isset($_POST['action']) || $_POST['action'] != 'lvd_search') {
            return $filters;
        }

        if (isset($_POST['categories']) && !empty($_POST['categories']) && $_POST['categories'] != '') {
            $categories = $_POST['categories'];
            if (!is_array($categories)) {
                $categories = array($categories);
            }
            $filters[] = array(
                'term' => array(
                    'terms.product_cat.slug' => $categories[0],
                )
            );
        }
        if (isset($_POST['brands']) && !empty($_POST['brands']) && $_POST['brands'] != '') {
            $brands = $_POST['brands'];
            if (!is_array($brands)) {
                $brands = array($brands);
            }
            $filters[] = array(
                'term' => array(
                    'terms.pa_merk.slug' => $brands[0],
                )
            );
        }

        if (isset($_POST['price_range']) && ($_POST['price_range'][0] !== '' || $_POST['price_range'][1] !== '')) {

            $price_range = [];
            if (isset($_POST['price_range'][0]) && $_POST['price_range'][0] != '') {
                $price_range['gte'] = $_POST['price_range'][0];
            }
            if (isset($_POST['price_range'][1]) && $_POST['price_range'][1] != '') {
                $price_range['lte'] = $_POST['price_range'][1];
            }
            if (!empty($price_range)) {
                $filters[] = array(
                    'range' => array(
                        'meta._price.double' => $price_range,
                    )
                );
            }
        }

        error_log("Filters: ".print_r($filters, 1));
        return $filters;
    }

When a brand is selected, the filters look like this after the hook is processed

Array
(
    [0] => Array
        (
            [term] => Array
                (
                    [terms.pa_merk.slug] => hills
                )

        )

)

Code of Conduct

xmedia-nl commented 9 months ago

Found it! Weighting was disabled. I noticed the built-in widget did filter correctly, so I compared the query args and saw the weighting was missing on my custom query. For reference, this filter needed to return true: ep_enable_do_weighting

add_filter('ep_enable_do_weighting', [$this,'set_weighting'], 999, 4);
    public static function set_weighting($should_do_weighting, $weight_config, $args, $formatted_args)
    {
        if (isset($args['custom_es_search'])) {
            return true;
        }
        return $should_do_weighting;
    }
xmedia-nl commented 9 months ago

closed