Недавно поступила просьба создать интеграцию с моим плагином Market Exporter и плагином WooCommerce Warehouses, чтобы можно было менять склад из которого идет выгрузка. Забегая вперед скажу, что я был не в восторге от предоставленной мне версии плагина, потому что она не работала с php 7.1 и не дружила с последней версией WooCommerce. Но я все же попытался помочь решить поставленную задачу.
Для тех кто не знает — Market Exporter экспортирует товарные предложения из WooCommerce в файл .yml, пригодный для импорта в Яндекс Маркет. Выгрузка происходит по товарам, которые есть в наличии и у которых задана цена. Плагин WooCommerce Warehouses, в свою очередь, позволяет задать товару несколько складов. Например, есть склад поставщика, где 250 товаров в наличии и склад магазина, где товара в наличии на данный момент нет. Так вот при настройках по умолчанию плагин Market Exporter выгрузил бы все товарные предложения, ведь они есть в наличии… на складе поставщика… Но это плохо, надо это решать.
Переходим от теории к практике. Нужно как-то безобидно интегрироваться в плагин и не изменить текущего функционала. Да, есть возможность напрямую переписать запрос к бд, который выгружает товар. Но для этого хорошо бы, чтобы в плагине были эти запросы. А их нет, т.к. используется функционал WooCommerce и WordPress. Да и нам нужна универсальность. Нам на помощь приходит фильтр posts_clauses.
Фильтр posts_clauses
позволяет получить доступ к запросу WP_Query
до его исполнения, когда сам запрос уже сформирован, но еще не исполнен. Если погуглить информацию о posts_clauses
, то можно будет узнать, что есть более конкретные фильтры для изменения WHERE
, JOIN
и т.д. Но для примера мы воспользуемся именно posts_clauses, как универсальным (не оптимальным!) фильтром.
Создаем фильтр:
add_filter( 'posts_clauses', 'filter_by_warehouse_id', 10, 2 );
или если у нас класс:
add_filter( 'posts_clauses', array( $this, 'filter_by_warehouse_id' ), 10, 2 );
И создаем метод filter_by_warehouse_id:
public function filter_by_warehouse_id( $clauses, $query_object ) {
global $wpdb;
$warehouse_id = 1;
$join = &$clauses['join'];
if ( ' INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) INNER JOIN wp_postmeta AS mt1 ON ( wp_posts.ID = mt1.post_id )' === $join ) {
$join .= " JOIN {$wpdb->prefix}inventory_manager_product_warehouse AS warehouse ON {$wpdb->prefix}posts.ID = warehouse.product_id";
$where = &$clauses['where'];
$where .= " AND ( warehouse.warehouse_id = {$warehouse_id} AND warehouse.stock > 0 )";
}
return $clauses;
}
Пробежимся по строчкам.
Строчка 3
global $wpdb;
Нам нужен будет глобальный объект $wpdb
, чтобы получить префикс для базы таблицы базы данных,
Строчка 5
$warehouse_id = 1;
Задаем ID склада, откуда будет идти выгрузка. Здесь мы его задаем вручную, но можно его забирать и из базы данных, и из select… да откуда угодно.
Строчка 7
$join = &$clauses['join'];
Ссылаемся на JOIN-часть WP_Query.
Строчка 9
if ( ' INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) INNER JOIN wp_postmeta AS mt1 ON ( wp_posts.ID = mt1.post_id )' === $join ) {
Не делайте так, но ради примера — сверяем запрос с тем, который нам нужен. И если он совпадает, то добавляем наш JOIN
(строчка 10).
Строчки 12-13 мы добавляем условие WHERE
.
$where = &$clauses['where'];
$where .= " AND ( warehouse.warehouse_id = {$warehouse_id} AND warehouse.stock > 0 )";
Итого. У нас есть запрос, который будет делать дополнительный запрос к таблице wp_inventory_manager_product_warehouse
и проверять наличие товара на заданном складе. Мы не нарушили работу плагина, не меняли его функционал, а лишь дополнили… Дальнейшие действия — повесить данный фильтр на опцию плагина или сделать некий интеграционный файл, который можно было бы включить в плагин/тему.