В WooCommerce есть штатные методы доставки, которые можно использовать сразу после установки.
Методы такие:
- Бесплатная доставка — название говорит само за себя
- Самовывоз — можно включить, когда доставка не требуется и клиент сам забирает товар
- Единая ставка — универсальный метод, для которого можно установить ставку и использовать
В статье расскажу как сделать бесплатный метод доставки более универсальным. Фактически — это кейс, и данный способ работает на реальном сайте.
Добавим к бесплатному методу:
- поле описания, которое выводиться на странице Оформления заказа
- логики, метод будет срабатывать, только если в заказе есть товары из определенной категории или с определенным артикулом
functions.php
через дочернюю тему или например пустой плагин. Прежде чем, вносить какие либо изменения, сделайте бекап сайта.Первое. Новые поля в настройки метода
Чтобы все управлялось удобно для пользователя, добавим новые поля, в которых можно будет указать нужные данные
/**
* Добавление новых полей
*
* @param array $arr
*
* @return array
*
* @author Artem Abramovich
* @testedwith WooCommerce 5.5
* @verphp 7.0
* @source https://wpruse.ru/woocommerce/expanding-the-free-shipping-method/
*/
function art_method_free_instance_form_fields( array $arr ): array {
// Добавляем новую опцию в селектор
$arr['requires']['options']['min_amount_sku_cat'] = 'Минимальная сумма заказа, артикулы, категории';
// Добавляем новые поля
$fields = [
'sku' => [
'title' => 'По артикулу',
'type' => 'text',
'placeholder' => 'Артикулы',
'description' => 'Укажите артикулы через запятую',
'default' => '',
'desc_tip' => true,
],
'category' => [
'title' => 'По категории',
'type' => 'text',
'placeholder' => 'Категории',
'description' => 'Укажите ID категорий через запятую',
'default' => '',
'desc_tip' => true,
],
'description' => [
'title' => 'Описание',
'type' => 'textarea',
'placeholder' => 'Описание метода доставки',
'description' => 'Укажите ID категорий через запятую',
'default' => '',
'desc_tip' => true,
],
];
return array_merge( $arr, $fields );
}
add_filter( 'woocommerce_shipping_instance_form_fields_free_shipping', 'art_method_free_instance_form_fields', 10, 1 );
Поля добавили. Надо отметить, что сначала добавляем новую опцию в выпадающий список, чтобы не зависеть от штатной логики работы метода. Потом только добавили три поля: Артикул, Категории, Описание.
Данные в поля Артикул и Категории вводятся через запятую, а в поле Категории указываются ID категории.
Теперь при нажатии на изменение метода будем видеть новые поля
Теперь добавим немного интерактива, сделаем чтобы поля скрывались, если выбран не наша опция
/**
* Скрытие полей в зависимости от выбранной настройки
*
* @author Artem Abramovich
* @testedwith WooCommerce 5.5
* @verphp 7.0
* @source https://wpruse.ru/woocommerce/expanding-the-free-shipping-method
*/
function art_method_free_enqueue_admin_js() {
wc_enqueue_js(
"jQuery( function( $ ) {
function wcFreeShippingShowHideCustomField( el ) {
var form = $( el ).closest( 'form' );
var skuField = $( '#woocommerce_free_shipping_sku', form ).closest( 'tr' );
var categorytField = $( '#woocommerce_free_shipping_category', form ).closest( 'tr' );
if ( 'min_amount_sku_cat' !== $( el ).val() ) {
skuField.hide();
categorytField.hide();
} else {
skuField.show();
categorytField.show();
}
}
$( document.body ).on( 'change', '#woocommerce_free_shipping_requires', function() {
wcFreeShippingShowHideCustomField( this );
} );
} );"
);
}
add_action( 'admin_footer', 'art_method_free_enqueue_admin_js', 10 );
Теперь все по красоте
к содержаниюВторое. Логика работы метода
Теперь заставим работать поля Артикул и Категории, пропишем логику показа метода.
/**
* Проверка сеществуют в заказе товары из нужных категорий и с нужным артикулом
*
* @param bool $is_available
* @param array $package
* @param \WC_Shipping_Free_Shipping $free_shipping
*
* @return bool
*
* @author Artem Abramovich
* @testedwith WooCommerce 5.5
* @verphp 7.0
* @source https://wpruse.ru/woocommerce/expanding-the-free-shipping-method
*/
function art_method_free_is_available( bool $is_available, array $package, WC_Shipping_Free_Shipping $free_shipping ) {
if ( 'min_amount_sku_cat' !== $free_shipping->requires ) {
return $is_available;
}
$is_available = false;
$setting_cats = [];
$setting_sku = [];
if ( $free_shipping->instance_settings['category'] ) {
$setting_cats = array_map( 'trim', explode( ',', $free_shipping->instance_settings['category'] ) );
}
if ( $free_shipping->instance_settings['sku'] ) {
$setting_sku = array_map( 'trim', explode( ',', $free_shipping->instance_settings['sku'] ) );
}
$product_cats = [];
$product_sku = [];
$compare_cats = [];
foreach ( $package['contents'] as $values ) {
$product_sku[] = $values['data']->get_sku();
$product_cats[] = $values['data']->get_category_ids();
}
foreach ( $product_cats as $cat_ids ) {
foreach ( $cat_ids as $cat_id ) {
$compare_cats[] = $cat_id;
}
}
if ( ! empty( array_intersect( $compare_cats, $setting_cats ) ) ) {
$is_available = true;
}
if ( ! empty( array_intersect( $product_sku, $setting_sku ) ) ) {
$is_available = true;
}
$total = WC()->cart->get_displayed_subtotal();
if ( $total >= $free_shipping->min_amount ) {
$is_available = true;
}
do_action( 'qm/info', $is_available );
return $is_available;
}
add_filter( 'woocommerce_shipping_free_shipping_is_available', 'art_method_free_is_available', 10, 3 );
Логика работает по следующим условиям:
- есть товар с указанным артикулом И,
- есть товар из указанной категории И,
- сумма заказа больше указанной,
то метод будет активным.
к содержаниюТретье. Вывод описания к методу
Теперь займемся описанием. Сначала добавим значение поля в данные доставки
/**
* Добавление значения описания из настроек в свойство
*
* @param WC_Shipping_Rate $rate
* @param array $args
* @param WC_Shipping_Free_Shipping $method
*
* @return \WC_Shipping_Rate
*
* @author Artem Abramovich
* @testedwith WooCommerce 5.5
* @verphp 7.0
* @source https://wpruse.ru/woocommerce/expanding-the-free-shipping-method
*/
function art_method_free_add_rate_property( $rate, $args, $method ) {
if ( false === strpos( $args['id'], 'free_shipping' ) ) {
return $rate;
}
$rate->description = $method->instance_settings['description'] ? wp_kses_post( $method->instance_settings['description'] ) : '';
return $rate;
}
add_filter( 'woocommerce_shipping_method_add_rate', 'art_method_free_add_rate_property', 20, 3 );
Осталось вывести описание
/**
* Вывод описания для бесплатного метода
*
* @param WC_Shipping_Rate $method
*
* @author Artem Abramovich
* @testedwith WooCommerce 5.5
* @verphp 7.0
* @source https://wpruse.ru/woocommerce/expanding-the-free-shipping-method
*/
function art_method_free_view_description( WC_Shipping_Rate $method ) {
if ( $method->description ) {
printf( '<div class="awdsm-description">%s</div>', wp_kses_post( wpautop( $method->description ) ) );
}
}
add_action( 'woocommerce_after_shipping_rate', 'art_method_free_view_description', 20, 1 );
Теперь красиво. В поле описания работают штатные html-теги, так что можно из использовать.
к содержаниюВесь код
/**
* Добавление новых полей
*
* @param array $arr
*
* @return array
*
* @author Artem Abramovich
* @testedwith WooCommerce 5.5
* @verphp 7.0
* @source https://wpruse.ru/woocommerce/expanding-the-free-shipping-method
*/
function art_method_free_instance_form_fields( array $arr ): array {
// Добавляем новую опцию в селектор
$arr['requires']['options']['min_amount_sku_cat'] = 'Минимальная сумма заказа, артикулы, категории';
// Добавляем новые поля
$fields = [
'sku' => [
'title' => 'По артикулу',
'type' => 'text',
'placeholder' => 'Артикулы',
'description' => 'Укажите артикулы через запятую',
'default' => '',
'desc_tip' => true,
],
'category' => [
'title' => 'По категории',
'type' => 'text',
'placeholder' => 'Категории',
'description' => 'Укажите ID категорий через запятую',
'default' => '',
'desc_tip' => true,
],
'description' => [
'title' => 'Описание',
'type' => 'textarea',
'placeholder' => 'Описание метода доставки',
'description' => 'Укажите ID категорий через запятую',
'default' => '',
'desc_tip' => true,
],
];
return array_merge( $arr, $fields );
}
add_filter( 'woocommerce_shipping_instance_form_fields_free_shipping', 'art_method_free_instance_form_fields', 10, 1 );
/**
* Скрытие полей в зависимости от выбранной настройки
*
* @author Artem Abramovich
* @testedwith WooCommerce 5.5
* @verphp 7.0
* @source https://wpruse.ru/woocommerce/expanding-the-free-shipping-method
*/
function art_method_free_enqueue_admin_js() {
wc_enqueue_js(
"jQuery( function( $ ) {
function wcFreeShippingShowHideCustomField( el ) {
var form = $( el ).closest( 'form' );
var skuField = $( '#woocommerce_free_shipping_sku', form ).closest( 'tr' );
var categorytField = $( '#woocommerce_free_shipping_category', form ).closest( 'tr' );
if ( 'min_amount_sku_cat' !== $( el ).val() ) {
skuField.hide();
categorytField.hide();
} else {
skuField.show();
categorytField.show();
}
}
$( document.body ).on( 'change', '#woocommerce_free_shipping_requires', function() {
wcFreeShippingShowHideCustomField( this );
} );
} );"
);
}
add_action( 'admin_footer', 'art_method_free_enqueue_admin_js', 10 );
/**
* Проверка сеществуют в заказе товары из нужных категорий и с нужным артикулом
*
* @param bool $is_available
* @param array $package
* @param \WC_Shipping_Free_Shipping $free_shipping
*
* @return bool
*
* @author Artem Abramovich
* @testedwith WooCommerce 5.5
* @verphp 7.0
* @source https://wpruse.ru/woocommerce/expanding-the-free-shipping-method
*/
function art_method_free_is_available( bool $is_available, array $package, WC_Shipping_Free_Shipping $free_shipping ) {
if ( 'min_amount_sku_cat' !== $free_shipping->requires ) {
return $is_available;
}
$is_available = false;
$setting_cats = [];
$setting_sku = [];
if ( $free_shipping->instance_settings['category'] ) {
$setting_cats = array_map( 'trim', explode( ',', $free_shipping->instance_settings['category'] ) );
}
if ( $free_shipping->instance_settings['sku'] ) {
$setting_sku = array_map( 'trim', explode( ',', $free_shipping->instance_settings['sku'] ) );
}
$product_cats = [];
$product_sku = [];
$compare_cats = [];
foreach ( $package['contents'] as $values ) {
$product_sku[] = $values['data']->get_sku();
$product_cats[] = $values['data']->get_category_ids();
}
foreach ( $product_cats as $cat_ids ) {
foreach ( $cat_ids as $cat_id ) {
$compare_cats[] = $cat_id;
}
}
if ( ! empty( array_intersect( $compare_cats, $setting_cats ) ) ) {
$is_available = true;
}
if ( ! empty( array_intersect( $product_sku, $setting_sku ) ) ) {
$is_available = true;
}
$total = WC()->cart->get_displayed_subtotal();
if ( $total >= $free_shipping->min_amount ) {
$is_available = true;
}
do_action( 'qm/info', $is_available );
return $is_available;
}
add_filter( 'woocommerce_shipping_free_shipping_is_available', 'art_method_free_is_available', 10, 3 );
/**
* Добавление значения описания из настроек в свойство
*
* @param WC_Shipping_Rate $rate
* @param array $args
* @param WC_Shipping_Free_Shipping $method
*
* @return \WC_Shipping_Rate
*
* @author Artem Abramovich
* @testedwith WooCommerce 5.5
* @verphp 7.0
* @source https://wpruse.ru/woocommerce/expanding-the-free-shipping-method
*/
function art_method_free_add_rate_property( $rate, $args, $method ) {
if ( false === strpos( $args['id'], 'free_shipping' ) ) {
return $rate;
}
$rate->description = $method->instance_settings['description'] ? wp_kses_post( $method->instance_settings['description'] ) : '';
return $rate;
}
add_filter( 'woocommerce_shipping_method_add_rate', 'art_method_free_add_rate_property', 20, 3 );
/**
* Вывод описания для бесплатного метода
*
* @param WC_Shipping_Rate $method
*
* @author Artem Abramovich
* @testedwith WooCommerce 5.5
* @verphp 7.0
* @source https://wpruse.ru/woocommerce/expanding-the-free-shipping-method
*/
function art_method_free_view_description( WC_Shipping_Rate $method ) {
if ( $method->description ) {
printf( '<div class="awdsm-description">%s</div>', wp_kses_post( wpautop( $method->description ) ) );
}
}
add_action( 'woocommerce_after_shipping_rate', 'art_method_free_view_description', 20, 1 );
к содержанию
Выводы
Способ трудоемкий, но зато какой эффект, согласитесь? Использовать бесплатный метод стало гораздо удобнее.
В целом данный способ подойдет, не только для штатного метода доставки, но и любого другого, который создан правильно и использует API WooCommerce.
На этом все, позвольте откланяться. Всем удачи и берегите себя!
P.S.
Насчет описаний к методам доставки. У меня есть готовый, универсальный плагин. Он может добавлять описания к любому методу доставки, который активен на сайте. С отдельной страницей настроек, с возможностью вывода картинок/иконок, да еще и 2 режимами вывода описаний: под тултипом и сразу.
Но есть нюанс, плагин я решил сделать платным, хотя и не сильно. Кому интересно пишите в личку.