WooCommerce. Расширяем бесплатный метод доставки

В 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 категории.

Заходите в раздел категории, наводите на любую категорию и внизу слева видите нужное.

Как узнать ID категории
Как узнать 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-теги, так что можно из использовать.

WooCommerce. Расширяем бесплатный метод доставки • 2 • Финты WordPress

Весь код

/**
 * Добавление новых полей
 *
 * @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 режимами вывода описаний: под тултипом и сразу.

Универсальный плагин для описаний к методам доставки
Универсальный плагин для описаний к методам доставки

Но есть нюанс, плагин я решил сделать платным, хотя и не сильно. Кому интересно пишите в личку.

5
3
голоса
Рейтинг статьи

Источник: wpruse.ru

Артем Абрамович

Меня зовут Артем Абрамович и я являюсь фрилансером-вордпресером. Занимаюсь настройкой и редактированием сайтов созданных на CMS WordPress. Это основная моя специализация, есть еще несколько работ, которыми я занимаюсь, но обо этом вы можете более подробно узнать из моего портфолио.

%d такие блоггеры, как: