[mFilter2] Вывод товаров со смежными значениями

Небольшая заготовка из вчерашнего рукоделия.

Имеем сайт с подбором товаров по характеристикам, реализованным на mFilter2.
Один из параметров «Мощность активная» выглядит так (увеличение по клику):


Как видно, есть большое разнообразие товаров с близкими значениями мощностей, но общее количество товаров не столь велико.
Это приводит к тому, что когда посетитель выбирает, к примеру, мощность 10 кВт, то он видит 1 товар в результатах подбора. А специфика продукции такова, что логично предложить пользователю аналогичные изделия как с чуть меньшей мощностью, например 9 кВт, так и с большей, до 12-15 кВт.

Нет, конечно можно сказать, что пусть нащелкает нужные цифры в подборе, но всегда есть «но». На страницу «Товары с мощностью 10 кВт» (где уже стоит галочка в фильтре) пользователь приходит из поисковых систем, фильтра он не видел и не нажимал. Если на странице будет 1 товар, пользователь может быстро уйти, решив, что мы предлагаем крайне скудный ассортимент, так и не увидев, что есть фильтр.

В общем, небольшая зарисовка на тему того, как при выборе в фильтре параметра со значением 10, показать все товары в диапазоне -x%....+y%.



1. Расширяем класс фильтрации. Документация.

2. Код нового класса. Новый тип фильтрации назовем «tolerance».
<?php
class myCustomFilter extends mse2FiltersHandler {

	/** Значение допуска для фильтра вверх, +30% */
	private $toleranceUp = 0.3;
	/** Значение допуска для фильтра вниз, -15% */
	private $toleranceDown = 0.15;

	/**
	 * Данный метод совпадает с buildDefaultFilter
	 *
	 * @param array $values
	 * @param string $name
	 *
	 * @return array Prepared values
	 */
	public function buildToleranceFilter(array $values, $name = '') {
		if (count($values) < 2 && empty($this->config['showEmptyFilters'])) {
			return array();
		}
		$results = array();
		foreach ($values as $value => $ids) {
			if ($value !== '') {
				$results[$value] = array(
					'title' => $value,
					'value' => $value,
					'type' => 'default',
					'resources' => $ids
				);
			}
		}
		ksort($results);
		return $results;
	}

	/**
	 * Переопределяем стандартный метод filterDefault
	 * Здесь мы ищем не совпадение параметра с запрашиваемым, а задаем диапазон ±X%, в который должно попасть значение
	 * Конечно же, метод применим только к числовым параметрам
	 *
	 * @param array $requested Filtered ids of resources
	 * @param array $values Filter data with value and ids of matching resources
	 * @param array $ids Ids of currently active resources
	 *
	 * @return array
	 */
	public function filterTolerance(array $requested, array $values, array $ids) {
		$matched = array();
		$tmp = array_flip($ids);
		foreach ($requested as $value) {
			$min = ($value - ($value * $this->toleranceDown));
			$max = ($value + ($value * $this->toleranceUp));
			foreach ($values as $number => $resources) {
				if ($number >= $min && $number <= $max) {
					foreach ($resources as $id) {
						if (isset($tmp[$id])) {
							$matched[] = $id;
						}
					}
				}
			}
		}
		return $matched;
	}
}
3. Используем фильтр:
[[!mFilter?
    &filters=`ms|power:tolerance`
]]
Наумов Алексей
26 февраля 2019, 10:29
modx.pro
15
1 462
+10

Комментарии: 6

Павел Гвоздь
26 февраля 2019, 10:34
0
А в самом поле фильтра не правильнее бы сделать значения диапазоном?
0.11-0.3
0.4-0.8
1-1.5
    Наумов Алексей
    26 февраля 2019, 10:38
    0
    Вариации разные возможны… конкретно в нашем случае это не было бы идеальным решением.
    Василий Наумкин
    26 февраля 2019, 10:51
    +1
    Или даже слайдером — он давно умеет работать с нецелыми числами.
      Наумов Алексей
      26 февраля 2019, 11:09
      0
      Да, конечно. Но мне нужны отдельные страницы на каждое значение из фильтра. Каждый чекбокс со скриншота — это ссылка на свою страницу. Слайдер так не может :)
        Василий Наумкин
        26 февраля 2019, 11:19
        0
        Слайдер тоже сохраняет данные в url.

        Правда вариантов тогда получится гораздо больше, что, наверное, не очень хорошо для SEO.
    Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
    6