Вчера внезапно осознал, что на этом сайте у меня нет подробного гайда про позиции заказов. Ну что же, вот и он – в нём поговорим про то, что это такое, а также про то, как добавлять, изменять и удалять позиции заказа в коде.
Кстати, прежде чем мы начнём, хочу порекомендовать вам два собственных видеокурса – по созданию темы WooCommerce и по созданию плагина для WooCommerce.
Чтобы быстро понять, что такое позиции заказа, рекомендую взглянуть на этот скриншот:
Итак, как вы возможно догадались позиции заказа бывают трёх типов:
line_item
,shipping
,fee
.Также позиции заказа имеют свои собственные таблицы в базе данных WooCommerce – это {префикс}woocommerce_order_items
и {префикс}woocommerce_order_itemmeta
– для метаданных.
Когда-то давно у меня возникал вопрос – зачем создавать отдельные таблицы в базе данных для элементов заказа, а не линковать товары по их айдишнику? И ответ очень прост на самом деле – предположим, что пользователь купил товар, а через месяц его цена изменилась. Но мы ведь не можем при этом перерассчитывать стоимость этого товара в старом заказе 🙃
Для получения позиций заказа мы можем использовать метод get_items()
объекта класса WC_Order
. У этого метода есть единственный параметр, $types
– тип позиций заказа, которые нам нужно получить, значения могут быть line_item
, fee
, shipping
. Можно передать несколько значений в виде массива. По умолчанию – line_item
, то есть только товары.
// предположим, что у нас заказ с ID=5, получим его объект $order_id = 5; $order = wc_get_order( $order_id ); // теперь из объекта получаем все типы позиций заказа $order_items = $order->get_items( array( 'line_item', 'fee', 'shipping' ) ); if ( ! is_wp_error( $order_items ) ) { // выводим их данные в цикле foreach( $order_items as $item_id => $order_item ) { echo $order_item->get_order_id(); // ID заказа echo $order_item->get_name(); // название позиции заказа echo $order_item->get_total(); // цена позиции echo $order_item->get_type(); // тип: line_item | fee | shipping // только для товаров: echo $order_item->get_quantity(); // количество товара echo $order_item->get_product_id(); // ID товара echo $order_item->get_variation_id(); // ID вариации echo $order_item->get_product(); // объект товара, ассоциированного с позицией } }
Также при помощи всего лишь двух функций – wc_add_order_item() и wc_add_order_item_meta() мы можем добавить позиции в заказ. Если вам интересно создание самого заказа через код, напишите в комментариях, я опубликую отдельный урок об этом.
Попробуем добавить позицию заказа типа line_item
, то есть товар.
// допустим мы будем добавлять позиции в заказ с ID=5 $order_id = 5; $order_item_id = wc_add_order_item( $order_id, array( 'order_item_name' => 'Шапочка', // может отличаться от названия товара 'order_item_type' => 'line_item', // указываем тип позиции – товар ) ); wc_add_order_item_meta( $order_item_id, '_qty', 2, true ); // количество wc_add_order_item_meta( $order_item_id, '_product_id', 13, true ); // ID товара // также можно добавить "_variation_id" wc_add_order_item_meta( $order_item_id, '_line_subtotal', 10, true ); // цена одной единицы wc_add_order_item_meta( $order_item_id, '_line_total', 20, true ); // общая стоимость $order = new WC_Order( $order_id ); $order->calculate_totals(); // пересчитываем стоимость заказа
Теперь давайте добавим сбор.
$order_item_id = wc_add_order_item( $order_id, array( 'order_item_name' => 'НДС 5%', 'order_item_type' => 'fee', ) ); wc_add_order_item_meta( $order_item_id, '_fee_amount', 20, true ); wc_add_order_item_meta( $order_item_id, '_line_total', 20, true ); $order = new WC_Order( $order_id ); $order->calculate_totals(); // пересчитываем стоимость заказа
Можем рассмотреть это на двух примерах – в первом примере мы переприкрепим позицию к другому заказу, для этого воспользуемся функцией wc_update_order_item().
wc_update_order_item( $order_item_id, array( 'order_id' => $new_order_id // ID нового заказа, к которому прикрепляем позицию ) );
Во втором примере мы лишь изменим количество товара в позиции функцией wc_update_order_item_meta(). Предположим, что цена товара равна 10, тогда при изменении количества товара на 3, общую стоимость нам тоже нужно изменить на 30.
wc_update_order_item_meta( $order_item_id, '_qty', 3 ); wc_update_order_item_meta( $order_item_id, '_line_total', 30 );
И ещё один момент – не забывайте пересчитывать весь заказ методом calculate_totals()
.
Классный момент это то, что когда вы удаляете целиком позицию из заказа функцией wc_delete_order_item(), то вам не нужно отдельно беспокоиться о его метаданных, т к они будут удалены автоматически.
wc_delete_order_item( $order_item_id );
Но если вы хотите удалить только определённый мета-ключ, при этом не удаляя позицию целиком, то можете воспользоваться функцией wc_delete_order_item_meta().
Чтобы оставить комментарий, пожалуйста, зарегистрируйтесь или войдите.
Добрый день!
Спасибо Вам за ваш труд и за ваши статьи - очень часто нахожу решение своих вопросов имеено у вас.
Сейчас пытаюсь вывести список позиций заказа и отправить в Телеграм.
Использую код из данной статьи (пробовал и из других источников - не работает)
Код следующий:
Далее $order_items пробегаю циклом - пусто.
Пробовал логировать его в файл - выводит {}
Пробовал вызывать get_items() с параметрами и без них - не помогает.
Есть мысль посмотреть как этот вывод позиций организован в самом WooCommerce при отправки e-mail, но может вы что-то сможете сказать, ЧЯДНТ.
Буду рад любым идеям,
Спасибо!
Добрый день!
Спасибо 🙏
Почему-то первое, что мне пришло в голову, это поменять
new WP_Order
наwc_get_order()
, но вероятно также, чтоwoocommerce_new_order
это слишком ранний хук для запуска подобного кода.Спасибо!
да, я пробовал с обоими вариантами new WP_Order и wc_get_order() - и все равно пустота.
Наверное вы правы: все-таки слишком ранний хук.
Буду искать альтернативные способы)
UPDATE: для того, чтобы выводился список товаров использовал хук woocommerce_checkout_order_processed, вместо woocommerce_new_order и все работает великолепно