Ajax SEO Friendly filter в WinterCms

Пример под любые фильтры. Seo специалист скажет спасибо!

В прошлой статье мы добавляли фильтр на octobercms (он же на WinterCms). Сейчас добавим ajax фильтрацию, но seo friendly. То есть без GET хвостов.

Расматривать будем на примере Snowboard от WinterCms. Но переделать под обычный jquеry думаю сможет каждый.

Теория

После предыдущего урока у нас остался рабочий фильтр, но в хвост ссылки он добавляет GET параметры. Причем некрасивые: ?category=2&type=3&color=red. Можно просто добавить ajax запрос, но нам подружить сайт с поисковыми системами, да и делиться ссылками хочется красивыми: /clothers/dresses/red.

По задумке каждый пункт в фильтре у нас должен будет отдельной моделью. И каждый элемент этой модели должен иметь alias (slug) свойство. Если его нет добавьте. В html разметке мы оставляем в value тот же id элемента. И для тех у кого отключен js в брайзере фильтр продолжит работать по старому способу. Но это лирика.

В каждом пункте фильтра мы можем через чекбокс выбрать несколько вариантов. Поэтому мы должны предусмотреть какой-нибудь разделить. У нас он бдет -and-, тогда с некоторыми варианта ссыла получится такой: clothers/dresses-and-shirts/red-and-green

Практика

Добавляем js код

// Указываем класс всех чекбоков и устаналиваем событие на их изменения
const checkbox = document.getElementsByClassName('checkbox');
for (let i = 0; i < checkbox.length; i++) {
    checkbox[i].addEventListener('change', (event) => {
        // Указываем id нашей формы
        var form = document.getElementById('filter');

        // Для примера возьмем 2 группы чекбосов с разными name'ами
        let types = form.querySelectorAll("input[name^='types[']:checked");
        let colors = form.querySelectorAll("input[name^='colors[']:checked");
        const data = {
            types: Array.from(types).map(checkbox => checkbox.value),
            colors: Array.from(colors).map(checkbox => checkbox.value),
        };

        // запускаем ajax через Snowboard
        Snowboard.request(form, 'onFilter', {
            data: data,
            success(Request) {
                history.pushState({}, null, Request.slug);
            }
        });
    })
}

То есть на выходе у нас просто должен меняться url страницы на тот который вернет наш обработчик onFilter. Создадим его:

function onFilter()
{
    $chosenTypes = post('types');
    $chosenColors = post('colors');
    $types_ids = explode(',', $chosenTypes);
    $colors_ids = explode(',', $chosenColors);
    
    // генерируем и отправляем в js новый слаг для фильтра
    $slug = [];
    // Если мы получаем цвета, то из их id получаем свойство со слагом.
    if($colors_ids) {
        $colors_slugs = Color::whereIn('id', $colors_ids)->pluck('slug')->all();
        if(!empty($colors_slugs)) {
            $slug[] = implode('-and-', $colors_slugs);
        }
    }
    if($types_ids) {
        $types_slugs = Type::whereIn('id', $types_ids)->pluck('slug')->all();
        if(!empty($types_slugs)) {
            $slug[] = implode('-and-', $types_slugs);
        }
    }
    $return['slug'] = '/clothes/'.implode('/', $slug);

    // Выводим новых специов по фильтру. Запрос делаем сами, вывожу для примера
    $items = Shop::when($chosenColors, function ($query, $chosenColors) {
        return $query->whereHas('colors', function ($query) use ($chosenColors) {
            $query->whereIn('id', explode(',', $chosenColors));
        });
    })->get();
    
    // Выводим по ajax в элемент с id="products" чанк productsList с переменной items
    $return['#products'] = $this->renderPartial('productsList', 
        [
            'items'=>$items, 
        ]
    );
    
    return $return;
}

Вот и все! Ссылка в браузере меняется. Результат отфильтрованной модели выводится.

Но если мы обновим нашу страницу, то ссылка покажет ошибку. Поэтому нужно предусмотреть это и создать новую страницу с теми же запросами, но чтобы страница генерировалсь из slug (предварительно разделив их по символу -and-).


Опубликовано 13 марта 2023 г. в категориях: Winter CMS October CMS

Если Вам необходимо внедрить данную разработку на свой проект, свяжитесь со мной, обсудим цену и срок.

Связаться со мной Fill 1