Наверх

Генерация YML-файла для Яндекс-Маркета

<?php
@ini_set('display_errors', 1);

define('MODX_API_MODE', true);
require dirname(dirname(dirname(dirname(__FILE__)))) . '/index.php';
$modx->getService('error','error.modError');
$modx->setLogLevel(modX::LOG_LEVEL_INFO);
$modx->setLogTarget(XPDO_CLI_MODE ? 'ECHO' : 'HTML');

if ($modx->cacheManager->get('running', array('cache_key' => 'ymarket'))) {
     echo 'Скрипт работает, повторный запуск отменён';
    exit;
}

$running = true;
$modx->cacheManager->set('running', $running, 0, array('cache_key' => 'ymarket'));

$limit = 500;
$offset = $modx->cacheManager->get('offset', array('cache_key' => 'ymarket'));
$filename = __DIR__ . '/yandexmarket-gen.yml';

if (!$offset) {
    if (file_exists($filename)) {
        echo 'Файл существует, больше ничего не делаем';
        $running = false;
        $modx->cacheManager->set('running', $running, 0, array('cache_key' => 'ymarket'));
        exit;
    }
    echo 'Приступаю к генерации YML-файла' . PHP_EOL;
    $data = '<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE yml_catalog SYSTEM "shops.dtd">
<yml_catalog date="'.date("Y-m-d H:i").'" >
<shop>
<name>'.$modx->getOption('site_name').'</name>
<company>'.$modx->getOption('site_name').'</company>
<url>'.$modx->getOption('site_url').'</url>
<currencies>
<currency id="RUR" rate="1"/>
</currencies>
<categories>'.
    $modx->runSnippet('pdoResources', array(
        'parents' => 23,
        'where' => '{"class_key":"msCategory"}',
        'depth' => 0,
        'sortby' => '{"menuindex":"ASC"}',
        'limit' => 0, 'tpl' => 'categories'
    )) .
'</categories>
<offers>';
    
    if (!$handle = fopen($filename, 'w')) {
        echo "Не могу открыть файл $filename" . PHP_EOL;
        $running = false;
        $modx->cacheManager->set('running', $running, 0, array('cache_key' => 'ymarket'));
        exit;
    }
    if (fwrite($handle, $data) === FALSE) {
        echo "Не могу произвести запись в файл $filename" . PHP_EOL;
        $running = false;
        $modx->cacheManager->set('running', $running, 0, array('cache_key' => 'ymarket'));
        exit;
    }
    fclose($handle);
    unset($data);
    unset($handle);
    // echo 'Записана шапка файла' . PHP_EOL;
    $offset = 0;
}

$end_of_file = false;

if ($data = $modx->runSnippet('msProducts', array(
       'parents' => 0, 'limit' => $limit, 'offset' => $offset, 'tpl' => 'offer', 'includeContent' => 1, 'includeTVs' => 'img,image', 'where' => '{"Data.price:>":0}'
    ))) {
    if (is_writable($filename)) {
        if (!$handle = fopen($filename, 'a')) {
            echo "Не могу открыть файл $filename" . PHP_EOL;
            $running = false;
            $modx->cacheManager->set('running', $running, 0, array('cache_key' => 'ymarket'));
            exit;
        }
        if (fwrite($handle, $data) === FALSE) {
            echo "Не могу произвести запись в файл $filename" . PHP_EOL;
            $running = false;
            $modx->cacheManager->set('running', $running, 0, array('cache_key' => 'ymarket'));
            exit;
        }
        fclose($handle);
    } else {
        echo "Файл $filename недоступен для записи" . PHP_EOL;
        $running = false;
        $modx->cacheManager->set('running', $running, 0, array('cache_key' => 'ymarket'));
        exit;
    }
    // echo 'Записана группа товаров от '.$offset.' до ' . ($offset + $limit);
    $offset = $offset + $limit;
    $modx->cacheManager->set('offset', $offset, 0, array('cache_key' => 'ymarket'));
    unset($data);
    if ($offset > 200000) {
        $end_of_file = true;
    }
} else {
    $end_of_file = true;
}

if ($end_of_file) {
    $data = '</offers>
    </shop>
    </yml_catalog>';
    if (is_writable($filename)) {
        if (!$handle = fopen($filename, 'a')) {
            echo "Не могу открыть файл $filename" . PHP_EOL;
            $running = false;
            $modx->cacheManager->set('running', $running, 0, array('cache_key' => 'ymarket'));
            exit;
        }
        if (fwrite($handle, $data) === FALSE) {
            echo "Не могу произвести запись в файл $filename" . PHP_EOL;
            $running = false;
            $modx->cacheManager->set('running', $running, 0, array('cache_key' => 'ymarket'));
            exit;
        }
        fclose($handle);
    } else {
        echo "Файл $filename недоступен для записи" . PHP_EOL;
        $running = false;
        $modx->cacheManager->set('running', $running, 0, array('cache_key' => 'ymarket'));
        exit;
    }
    unlink(MODX_BASE_PATH . 'yandexmarket.yml');
    rename($filename, MODX_BASE_PATH . 'yandexmarket.yml');
    fopen($filename, 'w');
    echo 'Генерация файла YML завершена';
    $offset = 0;
    $modx->cacheManager->set('offset', $offset, 0, array('cache_key' => 'ymarket'));
}

$running = false;
$modx->cacheManager->set('running', $running, 0, array('cache_key' => 'ymarket'));
exit;


categories
<category id="[[+id]]" [[+parent:is=`23`:then=``:else=`parentId="[[+parent]]"`]]>[[+menutitle:default=`[[+pagetitle]]`:clearYML]]</category>
[[pdoResources? &parents=`{$id}` &where=`{ "class_key":"msCategory" }` &depth=`0` &sortby=`{ "menuindex":"ASC" }` &limit=`0` &tpl=`categories`]]


offer
<offer id="{$id}" available="true">
<url>{'site_url' | config}{$id | url}</url>
<price>{$price | replace : ' ' : ''}</price>
<currencyId>RUR</currencyId>
<categoryId>{$parent}</categoryId>
<picture>{'site_url' | config}{$thumb}</picture>
<name>{$pagetitle | clearYML}</name>
<model>{($article ?: 'id' ~ $id)| clearYML}</model>
<description>{(($content | striptags) ?: $description) | clearYML}</description>
<vendor>{$_pls['vendor.name'] | clearYML}</vendor>
<vendorCode>{($article ?: 'id' ~ $id) | clearYML}</vendorCode>
<sales_notes>Предоплата 100% Товар отгружается кратно упаковкам</sales_notes>
</offer>


clearYML
<?php
$output = str_replace(
    array('…', '&', '"', '>', '<', '\''),
    array('...', '&', '"', '>', '<', '&apos;'),
  $input);
  
return str_replace('&amp;', '&', $output);


22 комментария

  1. Артем 14 декабря 2018, 01:31 # 0
    Буду первопроходцем… Уважаемый Илья, подскажите, где вызвать данный сниппет? Пытался создать страницу — пустой шаблон с типом содержимого XML доступный для поиска и т.д, вызываю там этот сниппет, но не получается. Данная тема очень слабо освещена в интернете, прошу Вашей помощи.
    1. Илья Уткин 14 декабря 2018, 07:46 # 0
      Создайте файл /core/components/ymarket/generate.php, в этот файл вставьте код и настройте запуск этого файла по CRON каждую минуту. Внёс изменения в код, в предыдущем варианте было не всё правильно.
      1. Илья Уткин 14 декабря 2018, 09:52 # 0
        Скрипт начнёт создавать YML-файл, сохраняя его в файле /core/components/ymarket/yandexmarket-gen.yml

        Когда генерация будет завершена, содержимое файла будет скопировано в корень сайта. После этого, чтобы запустить генерацию нового файла, нужно просто удалить файл yandexmarket-gen.yml

        У меня настроена задача ежедневно удалять файл в 3 часа ночи. Тогда к утру файл для яндекс-маркета обновляется и каждый день он более-менее свежий.
    2. Артем 14 декабря 2018, 15:59 # 0
      Большое спасибо, буду пробовать!
      1. Виталий 31 января 2019, 13:48 # 0
        Здравствуйте. Все сделал по примеру. При проверке в яндекс вебмастере вот такая ошибка skrinshoter.ru/s/310119/iZ1WALBJ можете подсказать с чем это может быть связано? Ссылка на страницу yml
        1. Илья Уткин 31 января 2019, 13:58 # 0
          Здравствуйте. Вы не поменяли ID-шник вашего каталога вот здесь:
          'parents' => 23,
          1. Виталий 31 января 2019, 16:00(Комментарий был изменён) # 0
            Да. Такой косяк был, 30-го числа заменил skrinshoter.ru/s/310119/RT5yngEQ и заново сгенерировал файл. Может закэшировалось сильно? Хотя я все кэши почистил. Только что снова сгенерировал новый файл.
            1. Илья Уткин 01 февраля 2019, 19:04 # 0
              Значит, у вас не создан чанк categories. Пример этого чанка у меня не сохранился. Попробуйте воспроизвести его сами.
              1. Виталий 01 февраля 2019, 19:18 # 0
                А я еще думаю, в сниппете вижу обращение к чанкам. Значит нужно 2 чанка создать как я понял. Ок, попробую, спасибо.
                1. Илья Уткин 02 февраля 2019, 18:33 # 0
                  Оставите здесь в комментариях код чанков, если у вас получится? Чтобы другим пользователям было понятнее, что надо делать.
                  1. Виталий 07 февраля 2019, 12:03 # 0
                    Без проблем, но пока у меня чанки не работают. Не подскажете skrinshoter.ru/s/070219/ZIKsujvk в чем может быть проблема?
                    1. Илья Уткин 07 февраля 2019, 12:36 # 0
                      Неизвестная категория, значит у товара parent такой, которого нет в списке categories. Может, какие-то категории не попали в выборку?
                      1. Виталий 07 февраля 2019, 12:40 # 0
                        Вообще да. Попали в выборку лишь главные категории, а дочерние нет. Ниже указал свои чанки.
                        1. Виталий 07 февраля 2019, 12:50(Комментарий был изменён) # 0
                          Нашел косяк. Стояла глубина 0, чтобы вывести все дочерние категории поставил 99 глубину.

                          'depth' => 99
                          
                          1. Виталий 07 февраля 2019, 19:32 # 0
                            Снова ругается skrinshoter.ru/s/070219/qyLStMz2
            2. Виктор 01 февраля 2019, 18:27 # 0
              Здравствуйте. Подскажите, нужно создать сниппет, поставить нужный ид и что еще сделать?
              1. Илья Уткин 01 февраля 2019, 19:03 # 0
                А вот, выше в комментариях я добавил инструкцию.
                1. Виктор 01 февраля 2019, 19:33(Комментарий был изменён) # 0
                  Спасибо за ответ. т.е нужно только создать файл, в коде указать нужные ид и через какое-то время будет результат?
                  У меня ничего не происходит.
                  1. Илья Уткин 02 февраля 2019, 18:29 # 0
                    Нужно настроить CRON на запуск этого файла каждую минуту.
              2. Виталий 07 февраля 2019, 12:06 # 0
                У меня такие чанки:

                Категория
                <category id="[[+id]]" 
                [[+parent:is=`12`:then=``:else=`parentId="[[+parent]]"`]] >
                    [[+pagetitle:stripString=`&`:stripString=`
                `:striptags=``:replace=`&==&`]]
                </category>
                
                Продукт
                <offer id="[[+id]]" available="true">
                <url>http://site.ru/[[~[[+id]]]]</url>
                <price>[[+price:stripString=` `]]</price>
                <currencyId>RUR</currencyId>
                <categoryId>[[+parent]]</categoryId>
                <picture>http://site.ru/[[+image]]</picture>
                <name>[[+pagetitle]]</name>
                <model>[[+article]]</model>
                </offer>
                
                1. Raman Navadvorski 17 февраля 2019, 03:45(Комментарий был изменён) # 0
                  :replace=`&==& amp;`]]
                  
                  вот так должно быть (без пробелов) )
                  YML любит ругаться на запрещенные символы, поэтому их нужно вырезать или заменять на допустимые
                2. Ирина Чудесова 27 апреля 2023, 21:57(Комментарий был изменён) # 0
                  Здравствуйте. Создается пустой файл. Хостинг предоставил данные по ошибке. Подскажите с решением проблемы.
                  noreplzh@sakura:~/noreplzh.beget.tech/public_html [0] $ php7.4 -d display_errors -d error_reporting=E_ALL ~/noreplzh.beget.tech/public_html/core/components/ymarket/generate.php

                  Deprecated: Directive 'allow_url_include' is deprecated in Unknown on line 0
                  Приступаю к генерации YML-файла
                  [2023-04-27 21:51:10] (ERROR @ /home/n/noreplzh/noreplzh.beget.tech/public_html/core/components/ymarket/generate.php: 130) PHP warning: unlink(/home/n/noreplzh/noreplzh.beget.tech/public_html/yandexmarket.yml): No such file or directory
                  Генерация файла YML завершенаnoreplzh@sakura:~/noreplzh.beget.tech/public_html [0] $ php7.4 -d display_errors -d error_reporting=E_ALL ~/noreplzh.beget.tech/public_html/core/components/ymarket/generate.php

                  Deprecated: Directive 'allow_url_include' is deprecated in Unknown on line 0

                  Авторизация

                  через сервис Loginza:


                  Шаблоны MODX

                  1 2 Дальше »

                  Объектная
                  модель
                  MODX