YML для староверов MODx Evolution
Задача: создать файл фида для сайта на MODx Evo и загрузить его в Маркет. Ну или отправить менеджеру Яндекса, который это сделает.
Впервые я столкнулся с задачей генерации фидов для контекстной рекламы Гугл и Яндекс в 2018 году. Это были огромные каталоги дистрибьюторов Schneider Electric из тысяч товаров.
Сложность вызвало формирование utm-меток, пришлось переписываться по этому поводу с Яндексом и несколько раз менять техзадание.
В данной публикации я не буду концентрировать внимание на формировании урлов товарных позиций, важнее реализация. Детали можно будет дорабатывать и допиливать как угодно.
Рассмотрю вариант формирования фида в относительно свежих версиях MODx Evolution 1.4.11 — 1.4.19, где есть сниппет DLSitemap. Мне эта штука понравилась, когда решал задачку создания умной xml-карты сайта.
Сначала создаем документ yml1 с пустым шаблоном blank типа text/xml.
Смотрим, что у наc за каталог, какой у него уровень вложенности. В моем примере корневая папка каталога имеет id=22, структура простейшая: есть категории и товары. Далее я подскажу, что изменится, если уровней вложенности больше. Важно, что в фиде есть раздел категорий (categories) и самих товаров (offers).
Создаём tv-параметр типа CheckBox со значением по умолчанию 0 и присваиваем его всем шаблонам товаров и категорий. Идея в том, что это позволит исключить любой товар или категорию из фида.
Готовим чанки-шаблоны для строчек фида.
yml-category:
<category id="[+id+]">[+pagetitle+]</category>
Для случая, когда в категорию вложены подкатегории, и уже в подкатегориях находятся товары (но тогда и код сниппета ниже нужно будет корректировать делать еще один блок фида с подкатегориями и увеличивать параметр уровня вложенности при вызове сниппета DocLister для блока offers ):
<category id="[+id+]" parentId="[+parent+]">[+pagetitle+]</category>
yml-offer (не забудьте подставить в код свой домен вместо capweb.ru):
<offer id="[+id+]" available="true"> <name>[+pagetitle+]</name> <url>https://capweb.ru[(base_url)][~[+id+]~]/?from=ya_market&utm_source=ya_market&utm_medium=cpc&utm_campaign=[!getparenttitle? &gid=[+id+]!]&utm_term=[+id+]</url> <price>[+tv.price+]</price> <currencyId>RUB</currencyId> <categoryId>[+parent+]</categoryId> <param name="Базовый цвет">[+tv.product_color+]</param> <param name="Базовый размер">[+tv.product_size+]</param> <manufacturer_warranty>true</manufacturer_warranty> <delivery>true</delivery> <pickup>true</pickup> <store>true</store> <picture>https://capweb.ru/[+tv.image+]</picture> <description>[+tv.metaDescription+]</description> </offer>
Для работы этого tpl понадобится создать и простенький сниппет getparenttitle, получающий pagetitle родительского ресурса. Я решил, что такое значение метки будет наглядным и полезным, хотя можно вместо этого использовать просто id родителя [+parent+].
Код сниппета getparenttitle:
<?php $gid = (isset($gid)) ? $gid : '24'; $parent = $modx->getParent($gid,1,'pagetitle'); return $parent['pagetitle'];
Заметьте, в этом варианте url каждого товара имеет utm-метки, из-за чего код фида становится невалидным. Можно попробовать заменить знак амперcанда на &. Можно просто удалить utm-метки из чанка-шаблона.
Важно! Ваши tv-параметры для шаблона товаров отличаются от приведенных выше, поэтому после выполнения всех шагов данной инструкции рекомендую вернуться в этот tpl под названием yml-offer, редактировать имена tv и смотреть на конечный результат в виде исходного кода сгенерированного xml-файла. Значения параметров должны подхватываться корректно.
Делаем измененную копию сниппета DLSitemap — DLSitemap1 с приведённым ниже кодом (не забудьте вставить адрес своего сайта вместо capweb.ru, свой email.
<?php include_once(MODX_BASE_PATH . 'assets/lib/APIHelpers.class.php'); if (!isset($params['config'])) { $params['config'] = 'sitemap:core'; } /// Additional params //$params['addWhereList'] = 'c.type IN ("document") AND c.id NOT IN (3321,3065,3066,3220,33,41,31,43,3283,3293,3030,3031,38,39,23,3052,3196)'; //$allChildren_ul = implode(',',$modx->getChildIds(32, 1)); //$allChildren_ul_cin = ' AND c.id NOT IN ('.$allChildren_ul.')'; //$params['addWhereList'] = $params['addWhereList'].$allChildren_ul_cin; $params['addWhereList'] = 'c.type IN ("document")'; // Это выбор документов $allChildren_ul = implode(',',$modx->getChildIds(22, 2)); // Каталог, уровень вложенности 2 $allChildren_ul_cin = ' AND c.id IN ('.$allChildren_ul.')'; $params['addWhereList'] = $params['addWhereList'].$allChildren_ul_cin; ////////////// $out = $modx->runSnippet('DocLister', $params); ///// $params1['parents'] = 22; $params1['depth'] = 0; $params1['tpl'] = 'yml-category'; $params1['tvList'] = 'no-yml'; $params1['addWhereList'] = 'c.isfolder IN ("1")'; // AND no-yml IN ("0") AND no-yml NOT IN ("1") AND tv.no-yml NOTIN ("1") $params1['filters']='tv:no-yml:notin:1'; // content:c.id:notin:0; notin:1 AND(tv:no-yml:0) $params1['sortBy']=`docid`; $params1['sortDir']='ASC'; $categories = $modx->runSnippet('DocLister', $params1); $params2['parents'] = 22; $params2['depth'] = 1; $params2['tpl'] = 'yml-offer'; $params2['tvList'] = 'no-yml,price,product_color,product_size,about_text,image,metaDescription'; $params2['addWhereList'] = 'c.isfolder IN ("0")'; // AND no-yml IN ("0") AND no-yml NOT IN ("1") AND tv.no-yml NOTIN ("1") $params2['filters']='tv:no-yml:notin:1'; $params2['sortBy']=`docid`; $params2['sortDir']='ASC'; $offers = $modx->runSnippet('DocLister', $params2); if (!empty($out)) { $out = "<?xml version=\"1.0\" encoding=\"{$modx->config['modx_charset']}\"?> <yml_catalog date=\"".date('Y-m-d H:i')."\"> <shop> <name>[(site_name)]</name> <company>[(client_company_name)]</company> <url>https://capweb.ru</url> <platform>MODx</platform> <version>1.0</version> <email>capweb@mail.ru</email> <local_delivery_cost>0</local_delivery_cost> <currencies> <currency id=\"RUB\" rate=\"1\"/> </currencies> <categories> {$categories}</categories> <offers> {$offers}</offers> </shop> </yml_catalog>"; } return $out;
Остается лишь вызвать созданный сниппет DLSitemap1 из области контента пустого документа yml1.
Признаю, что можно было не упоминать DLSitemap всуе, а просто назвать сниппет произвольным именем.
Закомментированные и некоторые лишние строки не удалил, чтобы видно было ход мысли.
Вот и всё, и, чтобы эта статья была чуть побольше, приведу ссылку на другую публикацию: Полезные книги по маркетингу
Данный рецепт подходит и для Evolution, и для Revolution, но для Revo придется переписывать коды на язык этого движка. Sapienti sat.
Ответственный за этот не очень удобочитаемый контент — Сергей. Если что-то не получается, пишите, контакты тут.
Спасибо за внимание всем роботам и людям, да, и тебе (Вам, если требуется более официальное обращение) в том числе, дочитавшим до этой строки.
Следующая статья: Интервью с Яндексом 2013 г. https://capweb.ru/yandex_interview.html
Предыдущая статья: MODx: решение проблемы 1970. Форматирование дат по-русски. https://capweb.ru/modx-01-01-1970.html