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

Ниже представлен пример кода генерации YML файла на PHP по упрошенной схеме для выгрузки на Яндекс.Маркет.

Предполагается что у магазина в БД есть две таблицы – товары и категории, цены хранятся в таблице товаров. Для доступа к БД используется PDO.

В коде нет информации о доставке, данных о производителях и т.д. Полное описание на yandex.ru

<?php
// Подключение к БД
$dbh = new PDO('mysql:dbname=db_name;host=localhost', 'логин', 'пароль');

$out = '<?xml version="1.0" encoding="UTF-8"?>' . "\r\n";
$out .= '<yml_catalog date="' . date('Y-m-d H:i') . '">' . "\r\n";
$out .= '<shop>' . "\r\n";

// Короткое название магазина, должно содержать не более 20 символов
$out .= '<name>Название магазина</name>' . "\r\n";

// Полное наименование компании, владеющей магазином
$out .= '<company>ООО «Пупкин»</company>' . "\r\n";

// URL главной страницы магазина
$out .= '<url>https://example.com/</url>' . "\r\n";

// Список курсов валют магазина
$out .= '<currencies>' . "\r\n";
$out .= '<currency id="RUR" rate="1"/>' . "\r\n";
$out .= '</currencies>' . "\r\n";

// Список категорий магазина:
// id     - ID категории
// parent - ID родительской категории
// name   - Название категории
$sth = $dbh->prepare("SELECT `id`, `parent`, `name` FROM `category`");
$sth->execute();
$category = $sth->fetchAll(PDO::FETCH_ASSOC);

$out .= '<categories>' . "\r\n";
foreach ($category as $row) {
	if (empty($row['parent'])) {
		$out .= '<category id="' . $row['id'] . '">' . $row['name'] . '</category>' . "\r\n";
	} else {
		$out .= '<category id="' . $row['id'] . '" parentId="' . $row['parent'] . '">' . $row['name'] . '</category>' . "\r\n";
	}
}

$out .= '</categories>' . "\r\n";

// Вывод товаров:
$sth = $dbh->prepare("SELECT * FROM `prods`");
$sth->execute();
$prods = $sth->fetchAll(PDO::FETCH_ASSOC);

$out .= '<offers>' . "\r\n";
foreach ($prods as $row) {
	$out .= '<offer id="' . $row['id'] . '">' . "\r\n";

	// URL страницы товара на сайте магазина
	$out .= '<url>https://example.com/prod/' . $row['id'] . '.html</url>' . "\r\n";

	// Цена, предполагается что в БД хранится цена и цена со скидкой
	if (!empty($row['price_sale'])) {
		$out .= '<price>' . $row['price_sale'] . '</price>' . "\r\n";
		$out .= '<oldprice>' . $row['price'] . '</oldprice>' . "\r\n";
	} else {
		$out .= '<price>' . $row['price'] . '</price>' . "\r\n";
	}

	// Валюта товара
	$out .= '<currencyId>RUR</currencyId>' . "\r\n";

	// ID категории
	$out .= '<categoryId>' . $row['category'] . '</categoryId>' . "\r\n";

	// Изображения товара, до 10 ссылок
	$out .= '<picture>https://example.com/img/1.jpg</picture>' . "\r\n";
	$out .= '<picture>https://example.com/img/2.jpg</picture>' . "\r\n";

	// Название товара
	$out .= '<name>'.$row['name'].'</name>' . "\r\n";

	// Описание товара, максимум 3000 символов
	$out .= '<description><![CDATA[' . stripslashes($row['text']) . ']]></description>' . "\r\n";    
	$out .= '</offer>' . "\r\n";
}

$out .= '</offers>' . "\r\n";
$out .= '</shop>' . "\r\n";
$out .= '</yml_catalog>' . "\r\n";

header('Content-Type: text/xml; charset=utf-8');
echo $out;
exit;
PHP

Пример сгенерированного файла:

<?xml version="1.0" encoding="UTF-8"?>
<yml_catalog date="2022-04-01T14:37:38+03:00">
    <shop>
        <name>Название магазина</name>
        <company>ООО «Пупкин»</company>
        <url>https://example.com/</url>
        <currencies>
            <currency id="RUR" rate="1"/>
        </currencies>
        <categories>
            <category id="1" parentId="0">Бытовая техника</category>
            <category id="2" parentId="1">Мелкая техника для кухни</category>
        </categories>
        <offers>
            <offer id="1">
                <url>https://example.com/prod/1.html</url>               
                <price>8990</price>
                <oldprice>10000</oldprice>
                <currencyId>RUR</currencyId>    
                <categoryId>10</categoryId>   
                <picture>https://example.com/img/1.jpg</picture>
                <picture>https://example.com/img/2.jpg</picture>
                <name>Мороженица Brand 3811</name>
                <description><![CDATA[Компактный прибор с вместительной чашей (1 кг) поможет приготовить вкусные лакомства для всей семьи.]]></description>
            </offer>
        </offers>
    </shop>
</yml_catalog>

Если в магазине очень много товаров, то лучше сделать формирование XML-файла по крону и запаковать его в ZIP-архив (далее использовать его в качестве источника в Яндекс.Маркете).

// Вывод в браузер не нужен
//header('Content-Type: text/xml; charset=utf-8');
//echo $out;
//exit;

$fd = fopen(__DIR__ . '/market.xml', 'w') or die('Не удалось создать файл');
fwrite($fd, $out);
fclose($fd);

$zip = new ZipArchive();
$zip->open(__DIR__ . '/market.zip', ZipArchive::CREATE|ZipArchive::OVERWRITE);
$zip->addFile(__DIR__ . '/market.xml', 'market.xml');
$zip->close();

exit;
PHP
30.11.2016, обновлено 08.12.2022
21116

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

Доброго дня. Подскажите пожалуйста, а как сделать что бы данный файл генерировался когда произошло изменение в цене на автомате?
Алексей Дементьев Алексей Дементьев
12 января 2021 в 10:41
Запускать по рассписанию создание файла с нужной переодичностью. Самое простое, дальше зависит от cms сайта.
Владимир Арцыман Владимир Арцыман
29 января 2023 в 15:16
Подгрузил файлик yandex.php в корень сайта. В результате открытия в браузере выдает вместо русских букв знаки вопроса. Редактор https://www.xmlvalidation.com/index.php?id=1&L=0 выдает ошибку для этой строки: $out .= '<?xml version="1.0" encoding="utf-8"?>' . "\r\n"; следующего содержания: Content is not allowed in prolog. php - файл сохранен в кодировке UTF-8. Сама база данных на хостинге в кодировке utf8mb4_unicode_ci. Лишних знаков с помощью hex-редактора в строке $out .= '<?xml version="1.0" encoding="utf-8"?>' . "\r\n"; не обнаружил. В чем может быть причина? Код ниже
<?php
$dbh = new PDO('mysql:dbname=db_povargrodno;host=localhost', 'db_povargrodno', 'F6d3A8x0');
$out .= '<?xml version="1.0" encoding="UTF-8"?>' . "\r\n";
$out .= '<yml_catalog date="' . date('Y-m-d H:i') . '">' . "\r\n";
$out .= '<shop>' . "\r\n";
 
// Короткое название магазина, должно содержать не более 20 символов
$out .= '<name>Услуги повара в Гродно</name>' . "\r\n";
 
// Полное наименование компании, владеющей магазином
$out .= '<company>ООО «Восторг Торг»</company>' . "\r\n";
 
// URL главной страницы магазина
$out .= '<url>https://povarvgrodno.ru/</url>' . "\r\n";
 
// Список курсов валют магазина
$out .= '<currencies>' . "\r\n";
$out .= '<currency id="BYN" rate="1"/>' . "\r\n";
$out .= '</currencies>' . "\r\n";
 
// Список категорий магазина:
// id     - ID категории
// parent - ID родительской категории
// name   - Название категории
$sth = $dbh->prepare("SELECT `id`, `type`, `brand`, `title` FROM `category`");
$sth->execute();
$category = $sth->fetchAll(PDO::FETCH_ASSOC);
 
$out .= '<categories>' . "\r\n";
foreach ($category as $row) {
	if (empty($row['parent'])) {
		$out .= '<category id="' . $row['id'] . '">' . $row['brand'] . '</category>' . "\r\n";
	} else {
		$out .= '<category id="' . $row['id'] . '" parentId="' . $row['brand'] . '">' . $row['title'] . '</category>' . "\r\n";
	}
}
$out .= '</categories>' . "\r\n";

// Вывод товаров:
$sth = $dbh->prepare("SELECT * FROM  `table_products` WHERE visible='1' ");
$sth->execute();
$prods = $sth->fetchAll(PDO::FETCH_ASSOC);
 
$out .= '<offers>' . "\r\n";
foreach ($prods as $row) {
	$out .= '<offer id="' . $row['products_id'] . '">' . "\r\n";

	// Название товара
	$out .= '<name id="' . $row['products_id'] . '">'.$row["brand"].' ' . $row['title'] . '</name>' . "\r\n";
 
	// URL страницы товара на сайте магазина
	$out .= '<url>http://povarvgrodno.ru/view_content.php?id=' . $row['products_id'] . '</url>' . "\r\n";
 
	// Цена, предполагается что в БД хранится цена и цена со скидкой
	//if (!empty($row['price'])) {
	//	$out .= '<price>' . $row['price'] . '</price>' . "\r\n";
	//	$out .= '<oldprice>' . $row['price'] . '</oldprice>' . "\r\n";
	//} else {
		$out .= '<price>' . $row['price'] . '</price>' . "\r\n";
	//}
 
	// Валюта товара
	$out .= '<currencyId>BYN</currencyId>' . "\r\n";
 
	// ID категории
	$out .= '<categoryId>' . $row['brand_id'] . '</categoryId>' . "\r\n";
 
	// Изображения товара, до 10 ссылок
	$out .= '<picture>'.("http://povarvgrodno.ru/img/goods/".$row['image']).'</picture>'."\r\n";

	// Описание товара, максимум 3000 символов
	$out .= '<description><![CDATA[' . stripslashes($row['mini_features']) . ']]></description>' . "\r\n";    
	$out .= '</offer>' . "\r\n";
}
 
$out .= '</offers>' . "\r\n";
$out .= '</shop>' . "\r\n";
$out .= '</yml_catalog>' . "\r\n";
 
header('Content-Type: text/xml; charset=utf-8');
echo $out;
exit;
?>
Владимир Арцыман Владимир Арцыман
29 января 2023 в 17:20
Решил проблему следующим образом:
$db_host = 'localhost';
$db_user = 'username';
$db_pass = 'passname';
$db_database = 'database_name';
$dsn = "mysql:host=$db_host;dbname=$db_database;";
$options = array(
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"
);
$dbh = new PDO($dsn, $db_user, $db_pass, $options);
Ксения Петрова Ксения Петрова
17 июня 2023 в 20:02
Приветствую. У меня такая проблема:
из этой таблицы `wp_wc_product_meta_lookup` я беру product_id
$out .= '<offer internal-id="' . $row['product_id'] . '">' . "\r\n";
а далее нужно брать данные из таблицы `wp_posts`
$out .= '<creation-date>' . $row['post_date'] . '</creation-date>' . "\r\n";
но в ней не 'product_id, а ID
а потом еще данные из `wp_wc_product_attributes_lookup`
по term_id
Вообще не пойму как это всё соединить.

, чтобы добавить комментарий.

Другие публикации

PHP-класс обертка для PDO
Класс значительно упрощает работу с PDO, сокращает код. Реализован на статических классах и не требует создание экземпляра класса.
22941
+11
Генерация XML файла для Google Merchant
Пример генерации XML-фида для Google Merchant на PHP с минимальным набором обязательных полей.
7356
+2
Выполнение заданий по Cron
Cron — UNIX-программа, которая используются для периодического выполнения заданий в определённое время. Расписание и действия описываются инструкциями в файлах crontab, их можно посмотреть через SSH,...
46426
+2
ZIP в PHP (ZipArchive)
Класс ZipArchive позволяет быстро и удобно работать с ZIP-архивам, рассмотрим основные возможности класса.
19562
+6
RSS-файл для Яндекс Турбо-страниц
Турбо-страницы позволяют пользователям посмотреть легкую версию сайта, которая загружается быстрее в десятки раз, а...
22821
+7
XML-файл объявлений для Авито
Если товары с вашего сайта постоянно выставляются на Авито в ручном режиме, то есть возможность автоматизировать процесс и сделать публикацию товаров с помощью сервиса «Авито Автозагрузка» с помощью...
4939
0