Добавление произвольных полей в товарах Woocommerce. Большая инструкция • 1 • Финты WordPress

Добавление произвольных полей в товарах Woocommerce. Большая инструкция

В Woocommerce есть очень мощный API произвольных полей, который позволяет добавлять много разных вкусных решений. В этой статье разберем, как добавлять произвольные поля к простым товарам.

Внимание!
Данная статья предназначена в первую очередь для разработчиков и тех, кто хочет подробнее разобраться. Если вы не любите ковыряться в коде, а поля все же нужны, то проще воспользоваться готовым решением. Например, плагином WooCommerce Custom Product Data Fields или WC Factory Fields
Внимание!
Весь код необходимо добавлять в файл functions.php или например пустой плагин. Прежде чем, вносить какие либо изменения, сделайте бекап сайта.

Продолжим. Вот такая штука у нас получиться.

Произвольные поля в товарах Woocommerce
Результат добавления полей
к содержанию

Теория. Необходимые хуки и функции

В Woocomerce на любой чих найдется нужный акшион или фильтр (то, что называется хуки). В случае добавления произвольных полей будут использоваться хуки для вывода полей на вкладках метабокса. В зависимости от вкладки можно использовать тот или иной хук. Но следует помнить, что некоторые поля и вкладки могут быть не видны в зависимости от типа товара.

Хуки на вкладках

Вкладка «Основные»

На вкладке «Основные» можно использовать несколько хуков.

woocommerce_product_options_pricing // после цен
woocommerce_product_options_downloads // после скачиваемого файла (для скачиваемых товаров)
woocommerce_product_options_tax // после налоговых ставок
woocommerce_product_options_general_product_data // после основного контента вкладки

Вкладка «Доставка»

Данная вкладка активна только для физических товаров. Все хуки на вкладке «Доставка».

woocommerce_product_options_dimensions // после размеров
woocommerce_product_options_shipping // после основного контента вкладки

Вкладка «Запасы»

Все хуки на вкладке «Запасы».

woocommerce_product_options_sku // после артикула
woocommerce_product_options_stock // перед управлением запасами
woocommerce_product_options_stock_fields // после управлением запасами
woocommerce_product_options_stock_status // после статуса остатка
woocommerce_product_options_sold_individually // после опции Продавать индивидуально
woocommerce_product_options_inventory_product_data // после основного контента вкладки
к содержанию

Вкладка «Сопутствующие»

Все хуки на вкладке «Сопутствующие».

woocommerce_product_options_related // после основного контента вкладки

Вкладка «Атрибуты»

Все хуки на вкладке «Атрибуты».

woocommerce_product_options_attributes // после основного контента вкладки

Вкладка «Дополнительно»

Все хуки на вкладке «Дополнительно».

woocommerce_product_options_reviews // после опции Включить отзывы
woocommerce_product_options_advanced // после основного контента вкладки

Вкладка «Вариации»

Вкладка видна только для вариативных товаров. Все хуки на вкладке «Вариации».

woocommerce_variable_product_before_variations // перед списком вариаций

Хуки для сохранения значения полей

Для сохранения наших полей будем использовать хук.

woocommerce_process_product_meta

Это базовый хук, который позволяет сохранять значения произвольных полей для простых товаров. Хук передает ID товара.

Как создавать произвольные поля для вариативных товаров смотрите в отдельной статье.

к содержанию

Хуки для вывода полей

Поля — дело индивидуальное для каждого товара. Товар в Woocomerce — это запись, соответственно можно выводить товары и просто редактируя нужный файл. Но это не наш метод. А потому будем использовать хуки. Например, используем хук для вывода поля перед и после кнопки «Добавить в корзину».

Перед кнопкой

woocommerce_before_add_to_cart_form

После кнопки

woocommerce_after_add_to_cart_form
к содержанию

Функции вывода полей

Согласно API Woocommerce существуют такие функции добавления полей

  • Простое поле — woocommerce_wp_text_input();
  • Область текста — woocommerce_wp_textarea_input();
  • Скрытое поле — woocommerce_wp_hidden_input();
  • Поле чекбокса — woocommerce_wp_checkbox();
  • Выпадающий список — woocommerce_wp_select();
  • Радиокнопки — woocommerce_wp_radio();

Более подробно посмотреть функции можно в документации

Вот эти функции и будем использовать. Но это еще не все, для большего эффекта, напишем собственные поля, независимые от API.

к содержанию

Практика. Создаем, сохраняем и выводим произвольные поля

Создание полей

Итак, начнем. Создаем функцию и прикручиваем ее к нужному хуку.

add_action( 'woocommerce_product_options_general_product_data', 'art_woo_add_custom_fields' );
function art_woo_add_custom_fields() {
	global $product, $post;
	echo '<div class="options_group">';// Группировка полей 
	 //...здесь добавляем нужные функции
	echo '</div>';
}

Пока ничего сложного. Просто функция, которая ничего не делает. Блок с классом options_group позволяет визуально разделять группы полей с помощью нижней границы.

к содержанию

Текстовое поле

// текстовое поле
woocommerce_wp_text_input( array(
   'id'                => '_text_field',
   'label'             => __( 'Текстовое поле', 'woocommerce' ),
   'placeholder'       => 'Текстовое поле',
   'desc_tip'          => 'true',
   'custom_attributes' => array( 'required' => 'required' ),
   'description'       => __( 'Введите здесь значение поля', 'woocommerce' ),
) );

Обратите внимание, на два момента.

Во-первых, атрибут custom_attributes позволяет передать в функцию любые дополнительные параметры. В данном конкретно случае — это параметр определяет обязательное поле.

Во-вторых, использование атрибута desc_tip, позволяет выводить описание поля не как обычно, а во всплывающей подсказке. Иногда это очень удобно. Данный атрибут работает с любым типом полей.

к содержанию

Числовое поле

Это то же простое текстовое поле, но с типом number. Тип из арсенала HTML5 позволяет ограничить ввод данных только числами.

// цифровое поле
woocommerce_wp_text_input( array(
   'id'                => '_number_field',
   'label'             => __( 'Цифровое поле', 'woocommerce' ),
   'placeholder'       => 'Ввод чисел',
   'description'       => __( 'Вводятся только числа', 'woocommerce' ),
   'type'              => 'number',
   'custom_attributes' => array(
      'step' => 'any',
      'min'  => '0',
   ),
) );

Можно определить произвольные атрибуты: 

  • шаг,
  • минимальное и максимальное значение.

Атрибут step — это значение по умолчанию, min — минимальное значение. Ожидается ввод любого положительного числа

к содержанию

Текстовая область

// Тектовая область
woocommerce_wp_textarea_input( array(
   'id'            => '_textarea', // Идентификатор поля
   'label'         => 'Область текста', // Заголовок поля
   'placeholder'   => 'Ввод текста', // Надпись внутри поля
   'class'         => 'textarea-field', // Произвольный класс поля
   'style'         => 'width: 70%; background:red', // Произвольные стили для поля
   'wrapper_class' => 'wrap-textarea', // Класс обертки поля
   'desc_tip'      => 'true', // Включение подсказки
   'description'   => 'Здесь можно что-нибудть вводить',// Описение поля
   'name'          => 'textarea-field', // Имя поля
   'rows'          => '5', //Высота поля в строках текста.
   'col'           => '10', //Ширина поля в символах.
) );

Ничего сложно. В конкретном случае еще переданы дополнительные параметры (общие для все типов полей):

  • class — позволяет добавлять к полям произвольные класс;
  • style — добавление произвольных стилей (в данном случае задана ширина и цвет фона);
  • wrapper_class — произвольный класс для обертки всего поля;
  • name — собственный параметр name.
Внимание! Это относиться ко всем типам полей. Напомню, в глобальную переменную $_POST приходят значения поля name и при изменении параметра name на собственный, ловить надо именно это значение, а не id Иначе, просто не сохраниться значение поля.
к содержанию

Выпадающий список. Select

// Выбор значения
woocommerce_wp_select( array(
   'id'      => '_select',
   'label'   => 'Выпадающий список',
   'options' => array(
      'one'   => __( 'Option 1', 'woocommerce' ),
      'two'   => __( 'Option 2', 'woocommerce' ),
      'three' => __( 'Option 3', 'woocommerce' ),
   ),
) );

Добавляется параметр options, в который передается массив значений.

Поле с чекбоксом. Checkbox

// Чекбокс
woocommerce_wp_checkbox( array(
   'id'            => '_checkbox',
   'wrapper_class' => 'show_if_simple',
   'label'         => 'Чекбокс',
   'description'   => 'Выбери меня!',
) );

Просто поле с галочкой. Возвращает Да/Нет.

Радиокнопки. Radio buttons

// Радиокнопки
woocommerce_wp_radio( array(
   'id'            => '_radiobutton',
   'label'         => 'Радиокнопки',
   'class'         => 'radio-field', // Произвольный класс поля
   'style'         => '', // Произвольные стили для поля
   'wrapper_class' => 'wrap-radio', // Класс обертки поля
   'desc_tip'      => 'true', // Включение подсказки
   'description'   => 'Выберите значение',// Описение поля
   'name'          => 'radio-field', // Имя поля
   'options'       => array(
      'one'   => 'Один',
      'two'   => 'Два',
      'three' => 'Три',
   ),
) );

Примерно тоже самое, что и селект, только внешний вид разный. Хотя селектом пользоваться иногда удобнее.

к содержанию

Произвольное поле. Выбор товаров с поиском

<p class="form-field product_field_type">
	<label for="product_field_type">Выбор товаров</label>
	<select
		id="product_field_type"
		name="product_field_type[]"
		class="wc-product-search"
		multiple="multiple"
		style="width: 50%;"
		data-placeholder="<?php esc_attr_e( 'Search for a product…', 'woocommerce' ); ?>"
		data-action="woocommerce_json_search_products_and_variations"
		data-exclude="<?php echo intval( $post->ID ); ?>">
		<?php
		$product_ids            = [];
		$product_field_type_ids = get_post_meta( $post->ID, '_product_field_type_ids', true );

		if ( ! empty( $product_field_type_ids ) ) {
			$product_ids = array_map( 'absint', $product_field_type_ids );
		}

		if ( $product_ids ) {
			foreach ( $product_ids as $product_id ) {
				$product = wc_get_product( $product_id );

				echo sprintf(
					'<option value="%s" %s>%s</option>',
					esc_attr( $product_id ),
					selected( true, true, false ),
					esc_html( $product->get_formatted_name() )
				);
			}
		}
		?>
	</select>
	<span class="woocommerce-help-tip" data-tip="Тут можно указать какое-нибудь описание"></span>
</p>

Аналог поля на вкладке Сопутствующие Апсел или Кроссел. Вводите первые три буквы из названия товара и происходит автоматический поиск. Находит все товары, кроме текущего. Удобная вещь.

к содержанию

Произвольная группа полей

<div class="options_group">
	<h2><strong>Произвольная группа полей</strong></h2>
	<p class="form-field custom_field_type">
		<label for="custom_field_type">
			<?php echo 'Размер в упаковке (mm)'; ?>
		</label>
		<span class="wrap">
			<input
				placeholder="Длина"
				class="input-text wc_input_decimal"
				size="6"
				type="text"
				name="_pack_length"
				value="<?php echo esc_attr( get_post_meta( $post->ID, '_pack_length', true ) ); ?>"
				style="width: 15.75%;margin-right: 2%;"/>
			<input
				placeholder="Ширина"
				class="input-text wc_input_decimal"
				size="6"
				type="text"
				name="_pack_width"
				value="<?php echo esc_attr( get_post_meta( $post->ID, '_pack_width', true ) ); ?>"
				style="width: 15.75%;margin-right: 2%;"/>
			<input
				placeholder="Высота"
				class="input-text wc_input_decimal"
				size="6"
				type="text"
				name="_pack_height"
				value="<?php echo esc_attr( get_post_meta( $post->ID, '_pack_height', true ) ); ?>"
				style="width: 15.75%;margin-right: 0;"/>
		</span>
		<span
			class="description">
			<?php echo esc_html( wc_help_tip( 'Введите размер товара в упаковке в формате ДхШхВ' ) ); ?>
		</span>
	</p>
</div>

Просто группа из трех полей. В данном случае, реальный пример для ввода дополнительных размеров, которое используется в одном из моих проектов.

к содержанию

Полный код со всеми видами полей, в том числе и произвольными

/**
 * Полный код со всеми видами полей, в том числе и произвольными
 *
 * @testedwith    WooCommerce 5.5
 * @verphp        7.0
 * @author        Artem Abramovich
 *
 * @source https://wpruse.ru/woocommerce/custom-fields-in-products/
 */
function art_woo_add_custom_fields() {

	global $product, $post;

	echo '<div class="options_group">'; // Группировка полей.

	// текстовое поле.
	woocommerce_wp_text_input(
		[
			'id'                => '_text_field',
			'label'             => __( 'Текстовое поле', 'woocommerce' ),
			'placeholder'       => 'Текстовое поле',
			'desc_tip'          => 'true',
			'custom_attributes' => [ 'required' => 'required' ],
			'description'       => __( 'Введите здесь значение поля', 'woocommerce' ),
		]
	);

	// Цифровое поле.
	woocommerce_wp_text_input(
		[
			'id'                => '_number_field',
			'label'             => __( 'Цифровое поле', 'woocommerce' ),
			'placeholder'       => 'Ввод чисел',
			'description'       => __( 'Вводятся только числа', 'woocommerce' ),
			'type'              => 'number',
			'custom_attributes' => [
				'step' => 'any',
				'min'  => '0',
			],
		]
	);

	// Тектовая область.
	woocommerce_wp_textarea_input(
		[
			'id'            => '_textarea', // Идентификатор поля.
			'label'         => 'Область текста', // Заголовок поля.
			'placeholder'   => 'Ввод текста', // Надпись внутри поля.
			'class'         => 'textarea-field', // Произвольный класс поля.
			'style'         => 'width: 70%; background:red', // Произвольные стили для поля.
			'wrapper_class' => 'wrap-textarea', // Класс обертки поля.
			'desc_tip'      => 'true', // Включение подсказки.
			'description'   => 'Здесь можно что-нибудть вводить', // Описание поля.
			'name'          => 'textarea-field', // Имя поля.
			'rows'          => '5', // Высота поля в строках текста.
			'col'           => '10', // Ширина поля в символах.
		]
	);

	// Выбор значения.
	woocommerce_wp_select(
		[
			'id'      => '_select',
			'label'   => 'Выпадающий список',
			'options' => [
				'one'   => __( 'Option 1', 'woocommerce' ),
				'two'   => __( 'Option 2', 'woocommerce' ),
				'three' => __( 'Option 3', 'woocommerce' ),
			],
		]
	);

	// Чекбокс.
	woocommerce_wp_checkbox(
		[
			'id'            => '_checkbox',
			'wrapper_class' => 'show_if_simple',
			'label'         => 'Чекбокс',
			'description'   => 'Выбери меня!',
		]
	);

	// Радиокнопки.
	woocommerce_wp_radio(
		[
			'id'            => '_radiobutton',
			'label'         => 'Радиокнопки',
			'class'         => 'radio-field', // Произвольный класс поля.
			'style'         => '', // Произвольные стили для поля.
			'wrapper_class' => 'wrap-radio', // Класс обертки поля.
			'desc_tip'      => 'true', // Включение подсказки.
			'description'   => 'Выберите значение', // Описение поля.
			'name'          => 'radio-field', // Имя поля.
			'options'       => [
				'one'   => 'Один',
				'two'   => 'Два',
				'three' => 'Три',
			],
		]
	);

	// Скрытое поле.
	woocommerce_wp_hidden_input(
		[
			'id'    => '_hidden_field',
			'value' => 'hidden_value',
		]
	);
	echo '</div>'; // Закрывающий тег Группировки полей
	// Выбор товаров.
	?>
	<p class="form-field product_field_type">
		<label for="product_field_type">Выбор товаров</label>
		<select
			id="product_field_type"
			name="product_field_type[]"
			class="wc-product-search"
			multiple="multiple"
			style="width: 50%;"
			data-placeholder="<?php esc_attr_e( 'Search for a product…', 'woocommerce' ); ?>"
			data-action="woocommerce_json_search_products_and_variations"
			data-exclude="<?php echo intval( $post->ID ); ?>">
			<?php
			$product_ids            = [];
			$product_field_type_ids = get_post_meta( $post->ID, '_product_field_type_ids', true );

			if ( ! empty( $product_field_type_ids ) ) {
				$product_ids = array_map( 'absint', $product_field_type_ids );
			}

			if ( $product_ids ) {
				foreach ( $product_ids as $product_id ) {
					$product = wc_get_product( $product_id );

					echo sprintf(
						'<option value="%s" %s>%s</option>',
						esc_attr( $product_id ),
						selected( true, true, false ),
						esc_html( $product->get_formatted_name() )
					);
				}
			}
			?>
		</select>
		<span class="woocommerce-help-tip" data-tip="Тут можно указать какое-нибудь описание"></span>
	</p>

	<div class="options_group">
		<h2><strong>Произвольная группа полей</strong></h2>
		<p class="form-field custom_field_type">
			<label for="custom_field_type">
				<?php echo 'Размер в упаковке (mm)'; ?>
			</label>
			<span class="wrap">
			<input
				placeholder="Длина"
				class="input-text wc_input_decimal"
				size="6"
				type="text"
				name="_pack_length"
				value="<?php echo esc_attr( get_post_meta( $post->ID, '_pack_length', true ) ); ?>"
				style="width: 15.75%;margin-right: 2%;"/>
			<input
				placeholder="Ширина"
				class="input-text wc_input_decimal"
				size="6"
				type="text"
				name="_pack_width"
				value="<?php echo esc_attr( get_post_meta( $post->ID, '_pack_width', true ) ); ?>"
				style="width: 15.75%;margin-right: 2%;"/>
			<input
				placeholder="Высота"
				class="input-text wc_input_decimal"
				size="6"
				type="text"
				name="_pack_height"
				value="<?php echo esc_attr( get_post_meta( $post->ID, '_pack_height', true ) ); ?>"
				style="width: 15.75%;margin-right: 0;"/>
		</span>
			<span
				class="description">
			<?php echo esc_html( wc_help_tip( 'Введите размер товара в упаковке в формате ДхШхВ' ) ); ?>
		</span>
		</p>
	</div>
	<?php
}

add_action( 'woocommerce_product_options_general_product_data', 'art_woo_add_custom_fields' );

Если коротко, то можно создать любое поле. Все зависит только от ваших желаний и умений.

к содержанию

Сохранение полей

Для сохранения полей используем хук woocommerce_process_product_meta.

Дальше просто — выдергиваем нужное значение из переменной $_POST, если там что-то есть то записываем в поле. Подробно расписывать не буду, вроде и так понятно и весь код откомментирован.

/**
 * Сохранение данных произвольльных полей методами ядра
 *
 * @testedwith    WooCommerce 5.5
 * @verphp        7.0
 * @author        Artem Abramovich
 *
 * @source https://wpruse.ru/woocommerce/custom-fields-in-products/
 */
function art_woo_custom_fields_save( $post_id ) {

	// Сохранение текстового поля.
	$woocommerce_text_field = $_POST['_text_field'];
	if ( ! empty( $woocommerce_text_field ) ) {
		update_post_meta( $post_id, '_text_field', esc_attr( $woocommerce_text_field ) );
	}

	// Сохранение цифрового поля.
	$woocommerce_number_field = $_POST['_number_field'];
	if ( ! empty( $woocommerce_number_field ) ) {
		update_post_meta( $post_id, '_number_field', esc_attr( $woocommerce_number_field ) );
	}

	// Сохранение области тектса.
	$woocommerce_textarea = $_POST['textarea-field'];
	if ( ! empty( $woocommerce_textarea ) ) {
		update_post_meta( $post_id, '_textarea', esc_html( $woocommerce_textarea ) );
	}

	// Сохранение выпадающего списка.
	$woocommerce_select = $_POST['_select'];
	if ( ! empty( $woocommerce_select ) ) {
		update_post_meta( $post_id, '_select', esc_attr( $woocommerce_select ) );
	}

	// Сохранение радиокнопок.
	$woocommerce_radio = $_POST['radio-field'];
	if ( ! empty( $woocommerce_radio ) ) {
		update_post_meta( $post_id, '_radiobutton', esc_attr( $woocommerce_radio ) );
	}

	// Сохранение чекбоксов.
	$woocommerce_checkbox = isset( $_POST['_checkbox'] ) ? 'yes' : 'no';
	update_post_meta( $post_id, '_checkbox', $woocommerce_checkbox );

	// Сохранение группы произвольных полей.
	$woocommerce_pack_length = $_POST['_pack_length'];
	if ( ! empty( $woocommerce_pack_length ) ) {
		update_post_meta( $post_id, '_pack_length', esc_attr( $woocommerce_pack_length ) );
	}

	$woocommerce_pack_width = $_POST['_pack_width'];
	if ( ! empty( $woocommerce_pack_width ) ) {
		update_post_meta( $post_id, '_pack_width', esc_attr( $woocommerce_pack_width ) );
	}

	$woocommerce_pack_height = $_POST['_pack_height'];
	if ( ! empty( $woocommerce_pack_height ) ) {
		update_post_meta( $post_id, '_pack_height', esc_attr( $woocommerce_pack_height ) );
	}

	// Hidden Field
	$woocommerce_hidden_field = $_POST['_hidden_field'];
	if ( ! empty( $woocommerce_hidden_field ) ) {
		update_post_meta( $post_id, '_hidden_field', esc_attr( $woocommerce_hidden_field ) );
	}

	// Сохранение произвольного поля по выбору товаров с поиском
	if ( ! empty( $_POST['product_field_type'] ) && isset( $_POST['product_field_type'] ) ) {
		// Проверяем данные, если они существуют и не пустые, то записываем данные в поле
		update_post_meta( $post_id, '_product_field_type_ids', array_map( 'absint', (array) $_POST['product_field_type'] ) );
	} else {
		// Иначе удаляем созданное поле из бд
		delete_post_meta( $post_id, '_product_field_type_ids' );
	}
}

add_action( 'woocommerce_process_product_meta', 'art_woo_custom_fields_save', 10 );

Другой способ сохранения полей через методы самого WooCommerce.

/**
 * Сохранение данных произвольльных полей методами WooCommerce
 *
 * @testedwith    WooCommerce 5.5
 * @verphp        7.0
 * @author        Artem Abramovich
 *
 * @source https://wpruse.ru/woocommerce/custom-fields-in-products/
 */
add_action( 'woocommerce_process_product_meta', 'art_woo_custom_fields_save', 10 );
function art_woo_custom_fields_save( $post_id ) {

	// Вызываем объект класса
	$product = wc_get_product( $post_id );

	// Сохранение текстового поля
	$text_field = isset( $_POST['_text_field'] ) ? sanitize_text_field( $_POST['_text_field'] ) : '';
	$product->update_meta_data( 'special_price', $text_field );

	// Сохранение цифрового поля
	$number_field = isset( $_POST['_number_field'] ) ? sanitize_text_field( $_POST['_number_field'] ) : '';
	$product->update_meta_data( '_number_field', $number_field );

	// Сохранение области тектса
	$textarea_field = isset( $_POST['textarea-field'] ) ? sanitize_text_field( $_POST['textarea-field'] ) : '';
	$product->update_meta_data( '_textarea', $textarea_field );

	// Сохранение выпадающего списка
	$select_field = isset( $_POST['_select'] ) ? sanitize_text_field( $_POST['_select'] ) : '';
	$product->update_meta_data( '_textarea', $select_field );

	// Сохранение радиокнопок
	$radio_field = isset( $_POST['radio-field'] ) ? sanitize_text_field( $_POST['radio-field'] ) : '';
	$product->update_meta_data( '_radiobutton', $radio_field );

	// Сохранение чекбоксов
	$checkbox_field = isset( $_POST['_checkbox'] ) ? 'yes' : 'no';
	$product->update_meta_data( '_checkbox', $checkbox_field );

	// Сохранение группы произвольных полей
	$pack_length = isset( $_POST['_pack_length'] ) ? sanitize_text_field( $_POST['_pack_length'] ) : '';
	$pack_width  = isset( $_POST['_pack_width'] ) ? sanitize_text_field( $_POST['_pack_width'] ) : '';
	$pack_height = isset( $_POST['_pack_height'] ) ? sanitize_text_field( $_POST['_pack_height'] ) : '';

	$product->update_meta_data( 'pack_length', $pack_length );
	$product->update_meta_data( 'pack_width', $pack_width );
	$product->update_meta_data( 'pack_height', $pack_height );

	// Сохранение скрытого поля
	$hidden_field = isset( $_POST['_hidden_field'] ) ? sanitize_text_field( $_POST['_hidden_field'] ) : '';
	$product->update_meta_data( '_hidden_field', $hidden_field );

	// Сохраняем все значения
	$product->save();

}

Код рабочий. Идеи по улучшению, пишите в комментариях.

Вот так должно получиться в итоге

Произвольные поля в товарах Woocommerce
к содержанию

Вывод полей

Вывод значений производится через штатную функцию самого WordPress get_post_meta(). Примерно так

// Отображение значения настраиваемого поля
echo get_post_meta ( $post->ID , 'my-field-slug', true );

А конкретно по примерным полям из статьи, то можно вывод подвесить в нужном месте карточки товара.

Тоже самое, только используя методы WooCommerce

// Отображение значения настраиваемого поля
echo $product->get_meta( 'special_price', true );
где $product - объект товара

// Объект товара можно получить так
$product = wc_get_product();
к содержанию

Перед кнопкой Добавить в корзину

Выведем текстовое, цифровое и область текста.

Самый простой вариант
add_action( 'woocommerce_before_add_to_cart_form', 'art_get_text_field_before_add_card' );
function art_get_text_field_before_add_card() {
	global $post;
	echo get_post_meta( $post->ID, '_text_field', true );
	echo get_post_meta( $post->ID, '_number_field', true );
	echo get_post_meta( $post->ID, '_textarea', true );
}

Тоже самое, только используя методы WooCommerce

add_action( 'woocommerce_before_add_to_cart_form', 'art_get_text_field_before_add_card' );
function art_get_text_field_before_add_card() {

	$product = wc_get_product();
	echo $product->get_meta( '_text_field', true );
	echo $product->get_meta( '_number_field', true );
	echo $product->get_meta( '_textarea', true );

}
Вариант с проверками и форматированием
add_action( 'woocommerce_before_add_to_cart_form', 'art_get_text_field_before_add_card' );
function art_get_text_field_before_add_card() {
	global $post, $product;
	$text_field     = get_post_meta( $post->ID, '_text_field', true );
	$num_field      = get_post_meta( $post->ID, '_number_field', true );
	$textarea_field = get_post_meta( $post->ID, '_textarea', true );
	if ( $text_field ) {
		?>
		<div class="text-field">
			<strong>Текстовое поле: </strong>
			<?php echo $text_field; ?>
		</div>
	<?php }
	if ( $num_field ) { ?>
		<div class="number-field">
			<strong>Цифровое поле: </strong>
			<?php echo $num_field; ?>
		</div>
	<?php }
	if ( $textarea_field ) { ?>
		<div class="textarea-field">
			<strong>Область текста: </strong>
			<?php echo $textarea_field; ?>
		</div>
		<?php
	}
}

Тоже самое, только используя методы WooCommerce

add_action( 'woocommerce_before_add_to_cart_form', 'art_get_text_field_before_add_card' );
function art_get_text_field_before_add_card() {

	// Вызываем объект товара
	$product = wc_get_product();

	// Записываем значения полей в переменные
	$text_field     = $product->get_meta( '_text_field', true );
	$num_field      = $product->get_meta( '_number_field', true );
	$textarea_field = $product->get_meta( '_textarea', true );

	// Выводим значения полей
	if ( $text_field ) :
		?>
		<div class="text-field">
			<strong>Текстовое поле: </strong>
			<?php echo $text_field; ?>
		</div>
	<?php endif;
	if ( $num_field ) : ?>
		<div class="number-field">
			<strong>Цифровое поле: </strong>
			<?php echo $num_field; ?>
		</div>
	<?php endif;
	if ( $textarea_field ) : ?>
		<div class="textarea-field">
			<strong>Область текста: </strong>
			<?php echo $textarea_field; ?>
		</div>
	<?php
	endif;
}

Вывод полей с форматированием будет выглядеть так

Произвольные поля в товарах Woocommerce
к содержанию

После кнопки Добавить в корзину

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

Пример кода (написано на коленке для примера, но все работает)

add_action( 'woocommerce_after_add_to_cart_form', 'art_get_text_field_after_add_card' );
function art_get_text_field_after_add_card() {
	global $post, $product;
	$select_field = get_post_meta( $post->ID, '_select', true );
	$radio_field  = get_post_meta( $post->ID, '_radiobutton', true );
	$check_field  = get_post_meta( $post->ID, '_checkbox', true );
	if ( $select_field ) {
		echo '<div><strong>Вывод значения при выборе в селекте</strong>';
		switch ( $select_field ) {
			case 'one':
				echo '<div>Первая опция селекта</div>';
				break;
			case 'two':
				echo '<div>Вторая опция селекта</div>';
				break;
			case 'three':
				echo '<div>Третья опция селекта</div>';
				break;
		}
		echo '</div>';
	}
	if ( $radio_field ) {
		echo '<div><strong>Вывод значения при выборе радиокнопки</strong>';
		switch ( $radio_field ) {
			case 'one':
				echo '<div>Значение первой радиокнопки</div>';
				break;
			case 'two':
				echo '<div>Значение второй радиокнопки</div>';
				break;
			case 'three':
				echo '<div>Значение третьей радиокнопки</div>';
				break;
		}
		echo '</div>';
	}
	if ( $check_field ) {
		echo '<div><strong>Срабатывание чекбокса</strong>';
		if ( $check_field === 'yes' ) {
			echo '<div>Чек выбран</div>';
		} else {
			echo '<div>Чек НЕ выбран</div>';
		}
		echo '</div>';
	}
}

В итоге получаем.
Были такие значения в админке

Произвольные поля в товарах Woocommerce

И получаем, такой вывод

Произвольные поля в товарах Woocommerce

Изменяем значения

Произвольные поля в товарах Woocommerce

Получаем

Произвольные поля в товарах Woocommerce
к содержанию

Вывод группы полей во вкладке Дополнительная информация

Используем хук woocommerce_product_additional_information и получаем такой код

add_action( 'woocommerce_product_additional_information', 'art_get_fields_tab_additional_information' );
function art_get_fields_tab_additional_information() {
	global $post;
	$length_field = get_post_meta( $post->ID, '_pack_length', true );
	$width_field  = get_post_meta( $post->ID, '_pack_width', true );
	$height_field = get_post_meta( $post->ID, '_pack_height', true );
	?>
	<table class="shop_attributes_addon">
		<tbody>
		<tr>
			<th>Размеры упаковки, <?php echo get_option( 'woocommerce_dimension_unit' );?></th>
			<td class="product_length"><?php echo $length_field; ?></td>
			<td class="product_width"><?php echo $width_field; ?></td>
			<td class="product_height"><?php echo $height_field; ?></td>
		</tr>
		</tbody>
	</table>
	<?php
}

Вот так это выглядит

Произвольные поля в товарах Woocommerce
к содержанию

Вывод выбранных товаров перед вкладками с информацией

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

Итак, наше поле возвращает нам массив ID товаров, значит нам достаточно запихать сей массив в функцию wc_get_products и вывести нужные товары. Примерно так, выводим список заголовков выбранных товаров.

add_action( 'woocommerce_single_product_summary', 'art_get_list_product', 65 );
function art_get_list_product() {
	global $post;
	$product_field_id = get_post_meta( $post->ID, '_product_field_type_ids', true );
	$product_lists = wc_get_products( array(
		'include'        => $product_field_id,
	));
	echo '<ul>';
	foreach ($product_lists as $list){
		echo '<li><a href="'. get_permalink($list->get_ID()) .'">'. $list->get_formatted_name() .'</a></li>';
	}
	echo '</ul>';
}

Код не идеальный, надо конечно и проверки сделать, но все работает. Получим такой вот список выбранных товаров

Произвольные поля в товарах Woocommerce
к содержанию

Вывод значения полей на страницах архивов

Зачем выводить эти данные в ленте товаров не знаю, но вдруг нужно. Для вывода на витрине, странице рубрик, похожих и т.д. требуется использовать соответствующие хуки. Для примера

Перед ценой
Вывод значений полей на страницах архивов
add_action( 'woocommerce_after_shop_loop_item_title', 'artabr_add_field_before_price', 9 );
function artabr_add_field_before_price() {
   global $post, $product;
   $text_field     = get_post_meta( $post->ID, '_text_field', true );
   $num_field      = get_post_meta( $post->ID, '_number_field', true );
   $textarea_field = get_post_meta( $post->ID, '_textarea', true );
   if ( $text_field ) {
      ?>
      <div class="text-field">
         <strong>Текстовое поле: </strong>
         <?php echo $text_field; ?>
      </div>
   <?php }
   if ( $num_field ) { ?>
      <div class="number-field">
         <strong>Цифровое поле: </strong>
         <?php echo $num_field; ?>
      </div>
   <?php }
   if ( $textarea_field ) { ?>
      <div class="textarea-field">
         <strong>Область текста: </strong>
         <?php echo $textarea_field; ?>
      </div>
      <?php
   }
}
После цены
Вывод значений полей на страницах архивов
add_action( 'woocommerce_after_shop_loop_item_title', 'artabr_add_field_after_price', 11 );
function artabr_add_field_after_price() {
   global $post, $product;
   $text_field     = get_post_meta( $post->ID, '_text_field', true );
   $num_field      = get_post_meta( $post->ID, '_number_field', true );
   $textarea_field = get_post_meta( $post->ID, '_textarea', true );
   if ( $text_field ) {
      ?>
      <div class="text-field">
         <strong>Текстовое поле: </strong>
         <?php echo $text_field; ?>
      </div>
   <?php }
   if ( $num_field ) { ?>
      <div class="number-field">
         <strong>Цифровое поле: </strong>
         <?php echo $num_field; ?>
      </div>
   <?php }
   if ( $textarea_field ) { ?>
      <div class="textarea-field">
         <strong>Область текста: </strong>
         <?php echo $textarea_field; ?>
      </div>
      <?php
   }
}

Хуков много, можно по разному вывести при необходимости.

к содержанию

Группировка произвольных полей на произвольной вкладке

Любая вкладка в метабоксе WooCommerce состоит из двух частей:

  • сама вкладка
  • содержание вкладки

Создание произвольной вкладки

Все вкладки формируются в классе WC_Meta_Box_Product_Data. Для добавления новой вкладки воспользуемся фильтром woocommerce_product_data_tabs.

/**
 * Создание произвольной вкладки
 *
 * @param  array $tabs Массив вкладок.
 *
 * @return array
 *
 * @author        Artem Abramovich
 * @testedwith    WooCommerce 5.5
 * @verphp        7.0
 * @source https://wpruse.ru/woocommerce/custom-fields-in-products/
 */
function art_added_tabs( array $tabs ): array {

	$tabs['special_panel'] = [
		'label'    => 'Произвольный', // название вкладки.
		'target'   => 'special_panel_product_data', // идентификатор вкладки.
		'class'    => [ 'hide_if_grouped' ], // классы управления видимостью вкладки в зависимости от типа товара.
		'priority' => 5, // приоритет вывода.
	];

	return $tabs;
}

add_filter( 'woocommerce_product_data_tabs', 'art_added_tabs', 10, 1 );
Произвольная вкладка

Изменяя атрибут priority можно изменять положение вкладки в общем списке. Чем больше значение, тем ниже вкладка будет располагаться.

Атрибут class позволяет добавить к вкладке любой класс. Но используя стандартные классы WooCommerce, можно управлять поведением вкладки.

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

  • show_if_simple — показывать только для простых товаров
  • show_if_variable — показывать только для вариативных товаров
  • show_if_grouped — показывать только для сгруппированных товаров
  • show_if_external — показывать только для внешних товаров
  • hide_if_simple — скрывать для простых товаров
  • hide_if_variable — скрывать для вариативных товаров
  • hide_if_grouped — скрывать для сгруппированных товаров
  • hide_if_external — скрывать для внешних товаров
к содержанию

Изменение иконки вкладки

Для иконки можно использовать что угодно. SVG, просто картинки или существующие шрифты Dashicons или набор самого WooCommerce.

Для изменения иконки достаточно добавить немного стилей:

/**
 * Добавление иконки для произвольной вкладки
 *
 * @author        Artem Abramovich
 * @testedwith    WooCommerce 5.5
 * @verphp        7.0
 * @source https://wpruse.ru/woocommerce/custom-fields-in-products/
 */
function art_added_tabs_icon() {

	?>
	<style>
		#woocommerce-coupon-data ul.wc-tabs li.special_panel_options a::before,
		#woocommerce-product-data ul.wc-tabs li.special_panel_options a::before,
		.woocommerce ul.wc-tabs li.special_panel_options a::before {
			font-family: WooCommerce;
			content: "\e03d";
		}
	</style>
	<?php

}

add_action( 'admin_footer', 'art_added_tabs_icon' );
Произвольная вкладка с произвольной иконкой
к содержанию

Добавление содержимого вкладки

Для добавления содержимого используется тот же принцип что и при добавлении на любую другую вкладку. Только используется хук woocommerce_product_data_panels.

Для примера добавим текстовое поле и произвольную группу полей.

/**
 * Вывод данных произвольльных полей на произвольной вкладке
 *
 * @testedwith    WooCommerce 5.5
 * @verphp        7.0
 * @author        Artem Abramovich
 *
 * @source https://wpruse.ru/woocommerce/custom-fields-in-products/
 */
function art_added_tabs_panel() {

	$product = wc_get_product();

	?>
	<div id="special_panel_product_data" class="panel woocommerce_options_panel">
		<div class="options_group">
			<?php

			$arg = [
				'id'          => 'special_price',
				'label'       => 'Специальная цена',
				'data_type'   => 'price',
				'desc_tip'    => true,
				'description' => 'Укажите значение специальной цены',
			];
			woocommerce_wp_text_input( $arg );
			?>

		</div>
		<div class="options_group">
			<h2><strong>Произвольная группа полей</strong></h2>
			<p class="form-field custom_field_type">
				<label for="custom_field_type"><?php echo 'Размер в упаковке (mm)'; ?></label>
				<span class="wrap">
				   <input
					   placeholder="Длина"
					   class="input-text wc_input_decimal"
					   size="6"
					   type="text"
					   name="_pack_length"
					   value="<?php echo esc_attr( $product->get_meta( '_pack_length', true ) ); ?>"
					   style="width: 15.75%;margin-right: 2%;"/>
				   <input
					   placeholder="Ширина"
					   class="input-text wc_input_decimal"
					   size="6"
					   type="text"
					   name="_pack_width"
					   value="<?php echo esc_attr( $product->get_meta( '_pack_width', true ) ); ?>"
					   style="width: 15.75%;margin-right: 2%;"/>
				   <input
					   placeholder="Высота"
					   class="input-text wc_input_decimal"
					   size="6"
					   type="text"
					   name="_pack_height"
					   value="<?php echo esc_attr( $product->get_meta( '_pack_height', true ) ); ?>"
					   style="width: 15.75%;margin-right: 0;"/>
				</span>
				<span class="description"><?php echo esc_html( wc_help_tip( 'Введите размер товара в упаковке в формате ДхШхВ' ) ); ?></span>
			</p>
		</div>
	</div>
	<?php

}

add_action( 'woocommerce_product_data_panels', 'art_added_tabs_panel' );

Получаем такой вид

Содержимое произвольной вкладки

Важно! ID обертки полей вкладки должен соответствовать атрибуту target, который указан при регистрации вкладки.

А дальше уже стандартно. Сохраняем значения и выводим там где требуется.

Для сохранения и вывода рекомендую использовать методы самого WooCommerce.

к содержанию

Кейс. Дополнительные поля на вкладке «Основные»

Задача

  • Добавить дополнительные поля на вкладке Основные
  • Вывести значения полей в виде кнопки на странице товара и страницах архивов

Решение

Первое. Создаем поля

Это самое простое. Нужна кнопка, которую можно сформировать из двух полей:

  • надпись на кнопке;
  • ссылка на кнопке.
/*
 * Добавляем поля
 */
add_action( 'woocommerce_product_options_general_product_data', 'demolink_woo_add_custom_fields' );
function demolink_woo_add_custom_fields() {
	echo '<div class="options_group">';// Группировка полей
	
	// текстовое поле
	woocommerce_wp_text_input( array(
		'id'          => '_demo_name',
		'label'       => __( 'Надпись на кнопке', 'woocommerce' ),
		'placeholder' => 'Надпись',
		'desc_tip'    => 'true',
		'description' => __( 'Укажите надпись', 'woocommerce' ),
	) );
	
	// текстовое поле
	woocommerce_wp_text_input( array(
		'id'          => '_demo_link',
		'label'       => __( 'Ссылка на демо', 'woocommerce' ),
		'placeholder' => 'Ссылка',
		'desc_tip'    => 'true',
		'data_type'   => 'url',
		'description' => __( 'Введите ссылку', 'woocommerce' ),
	) );
	
	echo '</div>';
	
}

/*
 * Сохраняем значение полей
 */
add_action( 'woocommerce_process_product_meta', 'demolink_woo_custom_fields_save', 10 );
function demolink_woo_custom_fields_save( $post_id ) {
	
	update_post_meta( $post_id, '_demo_link', esc_url( $_POST['_demo_link'] ) );
	update_post_meta( $post_id, '_demo_name', esc_attr( $_POST['_demo_name'] ) );
	
}
к содержанию

Второе. Вывод полей

Для вывода значений на странице товара используем хук woocommerce_before_add_to_cart_form, на страницах архивов — woocommerce_after_shop_loop_item с приоритетом.

add_action( 'woocommerce_after_shop_loop_item', 'demolink_get_button', 5 );
add_action( 'woocommerce_before_add_to_cart_form', 'demolink_get_button' );
function demolink_get_button() {
	global $post, $product;
	$demo_link = get_post_meta( $post->ID, '_demo_link', true );
	$demo_name = get_post_meta( $post->ID, '_demo_name', true );
	
	if ( $demo_link ) {
		$demo_btn = '<div class="demo-link">';
		$demo_btn .= '<a href="' . $demo_link . '" class="demo-link-button button alt" target="_blank">' . $demo_name . '</a>';
		$demo_btn .= '</div>';
		echo $demo_btn;
	}
	
}
к содержанию

Третье. Результат

к содержанию

Кейс. Произвольное текстовое поле с редактором TinyMCE 

Задача

  • создать произвольное текстовое поле с редактором TinyMCE 
  • вывести значение поля во вкладке «Детали» на странице товара

Решение

к содержанию

Первое. Создаем новое поле

add_action( 'woocommerce_product_options_general_product_data', 'art_woo_add_custom_fields' );
function art_woo_add_custom_fields() {
	global $product, $post;
	?>
	<div class="options_group">
		<h2><strong>Дополнительное описание с редактором</strong></h2>
		<?php
		wp_editor(get_post_meta( $post->ID, '_custom_desc', true ), 'custom_desc', array(
			'wpautop'       => 1,
			'media_buttons' => 1,
			'textarea_name' => 'custom_desc',
			'textarea_rows' => 5,
			'tabindex'      => null,
			'editor_css'    => '<style>.quicktags-toolbar, .wp-editor-tools, .wp-editor-wrap, .wp-switch-editor {padding: 5px 10px;}</style>',
			'editor_class'  => 'form-field',
			'teeny'         => 0,
			'dfw'           => 0,
			'tinymce'       => 1,
			'quicktags'     => 1,
			'drag_drop_upload' => false
		) );
		
		?>
	</div>
	<?php
}

add_action( 'woocommerce_process_product_meta', 'art_woo_custom_fields_save', 10 );
function art_woo_custom_fields_save( $post_id ) {
	// Сохранение области тектса
	$woocommerce_textarea = $_POST['custom_desc'];
	if ( ! empty( $woocommerce_textarea ) ) {
		update_post_meta( $post_id, '_custom_desc', $woocommerce_textarea );
	}

}
к содержанию

Второе. Выводим значение

add_action( 'woocommerce_product_additional_information', 'art_get_fields_tab_additional_information' );
function art_get_fields_tab_additional_information() {
	global $post;
	$custom_desc= get_post_meta( $post->ID, '_custom_desc', true );
	?>
	<div class="shop_attributes_addon">
		<p>Дополнительное описание</p>
		<p><?php echo $custom_desc; ?></p>
	</div>
	<?php
}

Третье. Результат

к содержанию

Заключение

В статье разобрал создание и вывод различных типов полей для простых товаров в Woocommerce.  Как с использованием штатного API так и создание своих собственных полей и групп полей. Разжевал все очень подробно. Весь код в статье рабочий и проверенный.

На этом все, если остались вопросы, пишите в комментариях, не забудьте поделиться статьей в соцсетях. Всем успехов, пока-пока!

4.3 12 голоса
Рейтинг статьи

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

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

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