WooCommerce. Скрытие полей заказа в зависимости от выбранного способа доставки • 1 • Финты WordPress

WooCommerce. Скрытие полей заказа в зависимости от выбранного способа доставки

Иногда нужно сделать так, чтобы в зависимости от способа доставки выводились разные поля на странице оформления заказа. Можно скрывать эти поля стилями или скриптом, но возникает проблема валидации: заказ невозможно будет отправить, потому что не заполнены обязательные поля. Пришлось придумать собственное решение.

Выглядит оно так

Внимание!
Весь код необходимо добавлять в файл functions.php через дочернюю тему или например пустой плагин. Прежде чем, вносить какие либо изменения, сделайте бекап сайта.
к содержанию

Шаг первый. Добавляем форму полей во фрагмент

В WooCommerce есть такой функционал фрагментов, в них можно добавлять нужный html и выводить в нужном месте. Итак, добавляем фрагмент

Код изменен. Предыдущий фрагмент будет работать, но если в магазине используется личный кабинет, то будут проблемы. Так как данная форма подключается в файле checkout/form-billing.php, правильнее использовать такой код

/**
 * Добавляем часть формы к фрагменту
 *
 * @sourcecode    https://wpruse.ru/woocommerce/hiding-fields-on-chosen-delivery/
 *
 * @param $fragments
 *
 * @return mixed
 *
 * @sourcecode    https://wpruse.ru/woocommerce/hiding-fields-on-chosen-delivery/
 * @author        Artem Abramovich
 * @testedwith    WC 5.5
 */
function awoohc_add_update_form_billing( $fragments ) {

	$checkout = WC()->checkout();

	parse_str( $_POST['post_data'], $fields_values );

	ob_start();

	echo '<div class="woocommerce-billing-fields__field-wrapper">';

	$fields = $checkout->get_checkout_fields( 'billing' );

	foreach ( $fields as $key => $field ) {
		$value = $checkout->get_value( $key );

		if ( isset( $field['country_field'], $fields[ $field['country_field'] ] ) ) {
			$field['country'] = $checkout->get_value( $field['country_field'] );
		}

		if ( ! $value && ! empty( $fields_values[ $key ] ) ) {
			$value = $fields_values[ $key ];
		}

		woocommerce_form_field( $key, $field, $value );
	}

	echo '</div>';

	$fragments['.woocommerce-billing-fields__field-wrapper'] = ob_get_clean();

	return $fragments;
}

add_filter( 'woocommerce_update_order_review_fragments', 'awoohc_add_update_form_billing', 99 );

UPD 1. Что изменилось? Если используется личный кабинет, то при переключении методов доставки происходит дублирование полей формы регистрации. Чтобы такого не происходило, во фрагмент добавляем только нужные поля.

UPD 2. Что изменилось?  В комментариях указали на косяк — при переключении не сохраняются значения полей: Имя, Фамилия, Почта, Телефон. Полечил. Все оказалось гораздо проще. Спасибо Денису Янчевскому за подсказку, теперь замечательно работает без проверок на js

к содержанию

Шаг второй. Убираем лишние поля

Предполагается, что способы доставки настроены. Для примера созданы два способа. Теперь требуется указать нужный идентификатор способа доставки. Самый простой способ — посмотреть в исходном коде

Узнать идентификатор способа доставки

Выделенные строки и есть идентификаторы. Теперь достаточно сделать проверку и если получаем нужный способ доставки, удаляем лишние поля

/**
 * Скрываем поля для бесплатного способа доставки
 *
 * @param $fields
 *
 * @return mixed
 *
 * @sourcecode    https://wpruse.ru/woocommerce/hiding-fields-on-chosen-delivery/
 * @author        Artem Abramovich
 * @testedwith    WC 5.5
 */
function awoohc_override_checkout_fields( $fields ) {

	// получаем выбранные методы доставки.
	$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );

	// проверяем текущий метод и убираем не ненужные поля.
	if ( false !== strpos( $chosen_methods[0], 'free_shipping' ) ) {
		unset(
			$fields['billing']['billing_company'],
			$fields['billing']['billing_address_1'],
			$fields['billing']['billing_address_2'],
			$fields['billing']['billing_city'],
			$fields['billing']['billing_postcode'],
			$fields['billing']['billing_state'],
			$fields['billing']['billing_phone'],
			$fields['billing']['billing_email']
		);
	}

	return $fields;
}

add_filter( 'woocommerce_checkout_fields', 'awoohc_override_checkout_fields' );

Это пример. В каждом случае, допиливайте под свой проект. 

к содержанию

Шаг третий. Обновление страницы

Все работает, кроме обновления страницы. Добавим немного магии ajax, так как вся обработка полей на странице «Оформление заказа» происходит через ajax.

Как это работает?

  • ловим выполнение обновления
  • ловим событие выбора способа доставки
  • запускаем прелоад
  • загружаем фрагмент из первого шага
/**
 * Прелоад при переключении доставки
 *
 * @sourcecode    https://wpruse.ru/woocommerce/hiding-fields-on-chosen-delivery/
 * @author        Artem Abramovich
 * @testedwith    WC 5.5
 */
function awoohc_add_script_update_shipping_method() {

	if ( is_checkout() ) {
		?>
		<!--Скроем поле Страна. Если успользуется поле Страна, то следцет убрать скрытие-->
		<style>
			#billing_country_field {
				display: none !important;
			}
		</style>

		<!--Выполняем обновление полей при переключении доставки-->
		<script>
			  jQuery( document ).ready( function( $ ) {
				  $( document.body ).on( 'updated_checkout updated_shipping_method', function( event, xhr, data ) {
					  $( 'input[name^="shipping_method"]' ).on( 'change', function() {
						  $( '.woocommerce-billing-fields__field-wrapper' ).block( {
							  message: null,
							  overlayCSS: {
								  background: '#fff',
								  'z-index': 1000000,
								  opacity: 0.3
							  }
						  } );
					  } );
				  } );
			  } );
		</script>
		<?php
	}
}

add_action( 'wp_footer', 'awoohc_add_script_update_shipping_method' );

Код подключается на хук wp_footer, при желании его можно вынести в отдельный файл. Код проверялся на стандартной теме StoreFront. Все должно работать корректно.

И еще сделано обновление полей не после обновления методов доставки, а параллельно с этим обновлением

к содержанию

Весь код полностью

Просто запихать в в файл functions.php

/**
 * Добавляем часть формы к фрагменту
 *
 * @sourcecode    https://wpruse.ru/woocommerce/hiding-fields-on-chosen-delivery/
 *
 * @param $fragments
 *
 * @return mixed
 *
 * @sourcecode    https://wpruse.ru/woocommerce/hiding-fields-on-chosen-delivery/
 * @author        Artem Abramovich
 * @testedwith    WC 5.5
 */
function awoohc_add_update_form_billing( $fragments ) {

	$checkout = WC()->checkout();

	parse_str( $_POST['post_data'], $fields_values );

	ob_start();

	echo '<div class="woocommerce-billing-fields__field-wrapper">';

	$fields = $checkout->get_checkout_fields( 'billing' );

	foreach ( $fields as $key => $field ) {
		$value = $checkout->get_value( $key );

		if ( isset( $field['country_field'], $fields[ $field['country_field'] ] ) ) {
			$field['country'] = $checkout->get_value( $field['country_field'] );
		}

		if ( ! $value && ! empty( $fields_values[ $key ] ) ) {
			$value = $fields_values[ $key ];
		}

		woocommerce_form_field( $key, $field, $value );
	}

	echo '</div>';

	$fragments['.woocommerce-billing-fields__field-wrapper'] = ob_get_clean();

	return $fragments;
}

add_filter( 'woocommerce_update_order_review_fragments', 'awoohc_add_update_form_billing', 99 );

/**
 * Скрываем поля для бесплатного способа доставки
 *
 * @param $fields
 *
 * @return mixed
 *
 * @sourcecode    https://wpruse.ru/woocommerce/hiding-fields-on-chosen-delivery/
 * @author        Artem Abramovich
 * @testedwith    WC 5.5
 */
function awoohc_override_checkout_fields( $fields ) {

	// получаем выбранные методы доставки.
	$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );

	// проверяем текущий метод и убираем не ненужные поля.
	if ( false !== strpos( $chosen_methods[0], 'free_shipping' ) ) {
		unset(
			$fields['billing']['billing_company'],
			$fields['billing']['billing_address_1'],
			$fields['billing']['billing_address_2'],
			$fields['billing']['billing_city'],
			$fields['billing']['billing_postcode'],
			$fields['billing']['billing_state'],
			$fields['billing']['billing_phone'],
			$fields['billing']['billing_email']
		);
	}

	return $fields;
}

add_filter( 'woocommerce_checkout_fields', 'awoohc_override_checkout_fields' );

/**
 * Прелоад при переключении доставки
 *
 * @sourcecode    https://wpruse.ru/woocommerce/hiding-fields-on-chosen-delivery/
 * @author        Artem Abramovich
 * @testedwith    WC 5.5
 */
function awoohc_add_script_update_shipping_method() {

	if ( is_checkout() ) {
		?>
		<!--Скроем поле Страна. Если успользуется поле Страна, то следцет убрать скрытие-->
		<style>
			#billing_country_field {
				display: none !important;
			}
		</style>

		<!--Выполняем обновление полей при переключении доставки-->
		<script>
			  jQuery( document ).ready( function( $ ) {
				  $( document.body ).on( 'updated_checkout updated_shipping_method', function( event, xhr, data ) {
					  $( 'input[name^="shipping_method"]' ).on( 'change', function() {
						  $( '.woocommerce-billing-fields__field-wrapper' ).block( {
							  message: null,
							  overlayCSS: {
								  background: '#fff',
								  'z-index': 1000000,
								  opacity: 0.3
							  }
						  } );
					  } );
				  } );
			  } );
		</script>
		<?php
	}
}

add_action( 'wp_footer', 'awoohc_add_script_update_shipping_method' );

Добавление маски для поля телефона на странице оформления заказа, и его правильной инициализации читаем тут →

Вот и все. А теперь реальный кейс

к содержанию

Реальный кейс

Задача

  • два метода доставки: «Самовывоз», «Новая почта»
  • убрать лишние поля на странице «Оформление заказа»
  • добавить дополнительное поля для метода «Новая почта»
  • значение нового поля должно добавляться в заказ и приходить с письмом

Должно получиться так

WooCommerce. Скрытие полей заказа в зависимости от выбранного способа доставки • 2 • Финты WordPress

В методе «Самовывоз» остаются поля:

  • Имя;
  • Город;
  • Телефон;
  • Email.

В методе «Новая почта»

  • Имя;
  • Город;
  • Телефон;
  • Email
  • Номер отделения
к содержанию

Решение

Первое. Добавляем фрагмент

См. Шаг первый

Второе. Добавляем условие переключения

add_filter( 'woocommerce_checkout_fields', 'awoohc_override_checkout_fields' );
function awoohc_override_checkout_fields( $fields ) {
	unset( $fields['billing']['billing_company'] );
	unset( $fields['billing']['billing_address_1'] );
	unset( $fields['billing']['billing_address_2'] );
	unset( $fields['billing']['billing_postcode'] );
	unset( $fields['billing']['billing_company'] );
	unset( $fields['billing']['billing_state'] );
	unset( $fields['billing']['billing_last_name'] );
	$fields['billing']['billing_city']['label']          = 'Город';
	$fields['billing']['billing_first_name']['class'][0] = 'form-row-wide';
	$fields['billing']['billing_email']['class'][0]      = 'form-row-last';
	$fields['billing']['billing_phone']['class'][0]      = 'form-row-first';
	$chosen_methods                                      = WC()->session->get( 'chosen_shipping_methods' );
	if ( 'flat_rate:2' === $chosen_methods[0] ) {
		$fields['billing']['billing_city']['class'][0] = 'form-row-first';
	} else {
		unset( $fields['billing']['billing_number_post_office'] );
	}
	
	return $fields;
}

Обратите внимание! Не нужные поля убираем сразу, а только потом делаем проверку. И проверка при этом обратная — если не выбран нужный метод доставки, то убираем новое поле.

В некоторые поля сразу вносим изменения:

  • В поле «Населенный пункт» меняем ярлык на «Город»
  • В поле «Имя» изменяем ширину на полную
  • В полях «Емайл» и «Телефон» изменяем ширину на половину, причем поле «Телефон» будет выводиться слева, а «Емайл» — справа

Третье. Добавляем новое поле

Добавляем новое поле с именем number_post_office

add_filter( 'woocommerce_default_address_fields', 'awoohc_override_default_address_fields' );
function awoohc_override_default_address_fields( $address_fields ) {
	$address_fields['number_post_office'] = array(
		'label'       => 'Номер отделения',
		'placeholder' => '',
		'required'    => true,
		'class'       => array( 'form-row-last' ),
		'clear'       => true,
		'priority'    => 75,
	);
	
	return $address_fields;
}

Так как для добавления поля используем хук woocommerce_default_address_fields, то реально имя поля будет billing_number_post_office. Именно под таким именем сохраняем поле в метаданные заказа

add_action( 'woocommerce_checkout_update_order_meta', 'awoohc_checkout_field_update_order_meta' );
function awoohc_checkout_field_update_order_meta( $order_id ) {
	
	if ( ! empty( $_POST['billing_number_post_office'] ) ) {
		update_post_meta( $order_id, 'billing_number_post_office', sanitize_text_field( $_POST['billing_number_post_office'] ) );
	}
}

Теперь надо настроить поля заказа, чтобы данные выводились на странице заказа и связанных с ней. Для начала добавим новое поле в общий массив полей при администрировании заказа

add_filter( 'woocommerce_admin_billing_fields', 'awoohc_add_admin_billing_fields', 10 );
function awoohc_add_admin_billing_fields( $address ) {
	$address['billing_number_post_office'] = array(
		'label' => 'Номер отделения',
		'show'  => true,
	);
	
	return $address;
}

Теперь выведем значение поля в адресе

add_filter( 'woocommerce_get_order_address', 'awoohc_add_billing_fields_get_order' );
function awoohc_add_billing_fields_get_order( $address ) {
	$order_id                              = isset( $_GET ) ? wc_get_order_id_by_order_key( $_GET ) : '';
	$address['billing_number_post_office'] = get_post_meta( $order_id, 'billing_number_post_office', true );
	
	return $address;
}

И сразу отформатируем для полей адреса доставки и адреса оплаты

add_filter( 'woocommerce_order_formatted_shipping_address', 'awoohc_add_billing_fields', 10, 2 );
add_filter( 'woocommerce_order_formatted_billing_address', 'awoohc_add_billing_fields', 10, 2 );
function awoohc_add_billing_fields( $fields, $order ) {
	$fields['billing_number_post_office'] = get_post_meta( $order->get_id(), 'billing_number_post_office', true );
	
	return $fields;
}

Приведем внешний адреса к привычному для России и СНГ

add_filter( 'woocommerce_formatted_address_replacements', 'awoohc_formatted_address_replacements', 10, 2 );
function awoohc_formatted_address_replacements( $replacements, $address ) {
	$replacements['{billing_number_post_office}'] = ( isset( $address['billing_number_post_office'] ) && ! empty( $address['billing_number_post_office'] ) ) ?
		'№ отделения: ' .  esc_html( $address['billing_number_post_office']) : '';
	
	return $replacements;
}
add_filter( 'woocommerce_localisation_address_formats', 'awoohc_address_format' );
function awoohc_address_format( $formats ) {
	$formats['RU'] = "{country}\n{postcode}\n{state}\nг.{city}\n{billing_number_post_office}";
	$formats['UA'] = "{country}\n{postcode}\n{state}\nг.{city}\n{billing_number_post_office}";
	
	return $formats;
}

Четвертое. Добавляем обновление через ajax

Все точно так же, как в третьем шаге, только добавляет сохранение значения нового поля.

add_action( 'wp_footer', 'awoohc_add_script_update_shipping_method' );
function awoohc_add_script_update_shipping_method() {
	if ( is_checkout() ) {
		?>
		<!--Скроем поле Страна. Если успользуется поле Страна, то следцет убрать скрытие-->
		<style>
			#billing_country_field {
				display: none !important;
			}
		</style>		<!--Выполняем обновление полей при переключении доставки-->
		<script>
            jQuery(document).ready(function ($) {

                $(document.body).on('updated_checkout updated_shipping_method', function (event, xhr, data) {
                    $('input[name^="shipping_method"]').on('change', function () {
                        $('.woocommerce-billing-fields__field-wrapper').block({
                            message: null,
                            overlayCSS: {
                                background: '#fff',
                                'z-index': 1000000,
                                opacity: 0.3
                            }
                        });
                    });
                    var first_name = $('#billing_first_name').val(),
                        last_name = $('#billing_last_name').val(),
                        phone = $('#billing_phone').val(),
                        email = $('#billing_email').val(),
                        number_post_office = $('#billing_number_post_office').val();

                    $(".woocommerce-billing-fields__field-wrapper").html(xhr.fragments[".woocommerce-billing-fields"]);
                    $(".woocommerce-billing-fields__field-wrapper").find('input[name="billing_first_name"]').val(first_name);
                    $(".woocommerce-billing-fields__field-wrapper").find('input[name="billing_last_name"]').val(last_name);
                    $(".woocommerce-billing-fields__field-wrapper").find('input[name="billing_phone"]').val(phone);
                    $(".woocommerce-billing-fields__field-wrapper").find('input[name="billing_email"]').val(email);
                    $(".woocommerce-billing-fields__field-wrapper").find('input[name="billing_email"]').val(number_post_office);
                    $('.woocommerce-billing-fields__field-wrapper').unblock();
                });
            });
		
		</script>
		<?php
	}
}

Вот и весь кейс. Ничего сложного

к содержанию

Выводы

В итоге разобрали как можно сделать вывод полей на странице «Оформление заказа». И даже на пример реального кейса. 

Все должно работать без проблем, если что, пишите в комметариях

Всем удачи! И не забудьте поделиться статьей в соцсетях!

4.7 10 голоса
Рейтинг статьи

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

Автор и ведущий проекта «Финты WordPress». WordPress & WooCommerce разработчик. Четыре года создаю плагины и темы. В свободное время пишу статьи, видеообзоры, гайды.

Подписаться
Уведомить о
guest
165 комментарев
Новые
Старые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
165
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x