Подскажите правильную реализацию

Добрый день, на сайте есть 2 основных раздела — услуги и категории. Каждая услуга может находиться в нескольких категориях. Как правильно организовать такую структуру? Прикрепил картинкой для лучшего восприятия.

Мои мысли:
Внутри каждой услуги заводить TV множественный выбор и через @EVAL тянуть категории, далее отмечать необходимые, ну а в самой категории выводить отмеченные ID услуг через pdoResources?

1. Может есть более изящное решение? Или я на правильном пути?

2. Как быть с хлебными крошками и URL? Ведь хочется получить всё по-красоте:
/cat_1/service_1/
/cat_1/service_2/
/cat_2/service_1/
/cat_2/service_2/
Владимир
22 мая 2018, 19:48
modx.pro
3
980
0

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

Максим Кузнецов
23 мая 2018, 13:39
1
+3
Если не вдаваться в сильное извращение, я бы поступил так:

Шаг 1.
Создается мультиселект-tv-поле (tv1) для страниц услуг, в котором выводятся все категории (в формате pagetitle==id)

Шаг 2.
Все страницы услуг создаются в едином разделе (во «всех услугах» или каком-то скрытом, например)

Шаг 3.
Создается тв-поле «id подходящих услуг» для категорий с услугами (tv2).
Это нужно для того, чтобы отображения списка подходящих услуг в категории происходила быстрее (не тратя время на where IN для каждой услуги).

Шаг 4.
Вешется плагин на создание/изменение страниц услуги, при котором в tv2 всех выбранных категории из tv1 переносился id сохраненной услуги.

Шаг 5.
Теперь нужно позаботимся о том, чтобы страницы услуг были доступны внутри любой из подходящих категорий. При помощи кастомной маршрутизации на событие OnPageNotFound вешаем подходящий вам паттерн.
Предположим, что все услуги имеют следующий вид ссылок:
/services/(category_name)/(service_name)

Тогда логика будет примерно такая:
— срабатывает событие OnPageNotFound
— превращаем запрошенную ссылку в массив
— если длина массива == 3, а первый элемент в нем == 'services', то работаем дальше
— ищем страницу вида /services/(category_name)
— если находим, то ищем услугу с alias == (service_name)
— если находим и её, то из объекта найденной категории получаем значение tv2 и ищем в нем id услуги
— если есть совпадение, то делаем sendForward, иначе отпускаем плагин на 404.

Шаг 5.
Выводим список подходящих услуг в категории по принципу &resources=`[[*tv2]]`. В чанке вызова формируем ссылку на услуги примерно таким образом:
{$_modx->resource.parent | url}/{$alias}

$_modx->resource.parent | url лучше сформировать вне вызова сниппета и передать готовый результат уже в него, чтобы не плодить кучу одинаковых запросов

Хлебные кроши.
Тут все просто, если у нас сгенерирована виртуальная страница через sendForward, то в плагине передаем в неё какой-либо свой плейсхолдер. Дальше от него в шаблоне формируются if-условия. В случае с хлебными крошками можно просто выводить их до «родителя» и дописывать текущую страницу в последнем пункте.

Карта сайта и СЕО
Тут у вас есть, условно, 2 важных момента:

1. Канонический url, во избежании дублей (link rel=«canonical»).
Можно указать или родной url ресурса (там, где они физически хранятся), или создать еще одно tv-поля для страниц услуги «основная категория» и формировать адрес в зависимости от неё.
В случае, если был выбран второй вариант, доступность услуг по «физическому» адресу нужно перекрыть (опять же, в шаблоне услуг можно проверять наличие плейсхолдера из плагина, и при его отсутствии создавать редирект).

2. Карта сайта.
Если с каноническим url был выбран вариант «физического адреса», то с картой не нужно проводить дополнительных манипуляций. В противном случае, физические адреса из вызова pdoSitemap-a нужно исключить и дополнительно сгенерировать виртуальные ссылки. (для минимализации времени генерации результата я бы разбил sitemap на 2 раздела (основные страницы и страницы услуг).
    Владимир
    23 мая 2018, 22:49
    +1
    Большое человеческое спасибо за такой развёрнутый ответ! Пойду разбираться.
    Максим
    24 мая 2018, 07:24
    0
    Можно установить дополнение «Коллекция» и там через «подборки» одну и ту же страницу добавлять в разные категории. Ну или какая там у вас логика… суть в том, что не будет дублирования. Если используете минишоп2, то там тоже есть вкладка «категории», можно её использовать.
      Максим
      24 мая 2018, 07:33
      1
      0
      А вообще «категории» — это скорее «категории услуг» (шумоизоляция, ремонт, ...), а BMW и т.п. это скорее не категории, а посто «марки автомобилей» :) «категории авто» — это, на мой взгляд, «грузовая», «легковая», «автобус».

      Суть всего сказанного — нужно правильно разбить информацию по смыслу, тогда и проще будет понять реализацию (где ресурс, а где тв-поле и т.п.).
      Сергей
      24 мая 2018, 08:17
      0
      Так в minishop2 же стандартно есть «из коробки» такое — возможность привязывать «товар» к разным категориям. Как раз то что нужно.
        Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
        5