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

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

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

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

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

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

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

Нужные хуки

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

Для добавления полей в нужную вкладку, в нашем случае это вкладка «Основные» используется хук

woocommerce_product_options_general_product_data

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

// Вкладка Доставка
woocommerce_product_options_shipping
// Вкладка Сопутствующие
woocommerce_product_options_related
// Вкладка Запасы
woocommerce_product_options_inventory_product_data
// Вкладка Атрибуты
woocommerce_product_options_attributes
// Вкладка Дополнительно
woocommerce_product_options_advanced
к содержанию

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

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

woocommerce_process_product_meta

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

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

Поля — дело индивидуальное для каждого товара. Товар в 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_field_type_ids = get_post_meta( $post->ID, '_product_field_type_ids', true );
      $product_ids = ! empty( $product_field_type_ids ) && isset($product_field_type_ids) ? array_map( 'absint',  $product_field_type_ids ) : array();
      if ( $product_ids ) {
         foreach ( $product_ids as $product_id ) {
            $product      = wc_get_product( $product_id );
            $product_name = $product->get_formatted_name();
            echo '<option value="' . esc_attr( $product_id ) . '" ' . selected(true, true, false )  . '>' .
                 esc_html( $product->get_formatted_name() ) . '</option>';
         }
      }
      ?>
   </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 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 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 get_post_meta( $post->ID, '_pack_height', true ); ?>"
      style="width: 15.75%;margin-right: 0;"/>
</span> <span
         class="description"><?php echo wc_help_tip( 'Введите размер товара в упаковке в формате ДхШхВ' ); ?></span>
   </p>
</div>

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

к содержанию

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

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">';// Группировка полей
   // текстовое поле
   woocommerce_wp_text_input( array(
      'id'                => '_text_field',
      'label'             => __( 'Текстовое поле', 'woocommerce' ),
      'placeholder'       => 'Текстовое поле',
      'desc_tip'          => 'true',
      'custom_attributes' => array( 'required' => 'required' ),
      'description'       => __( 'Введите здесь значение поля', 'woocommerce' ),
   ) );
   // цифровое поле
   woocommerce_wp_text_input( array(
      'id'                => '_number_field',
      'label'             => __( 'Цифровое поле', 'woocommerce' ),
      'placeholder'       => 'Ввод чисел',
      'description'       => __( 'Вводятся только числа', 'woocommerce' ),
      'type'              => 'number',
      'custom_attributes' => array(
         'step' => 'any',
         'min'  => '0',
      ),
   ) );
   // Тектовая область
   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', //Ширина поля в символах.
   ) );
   // Выбор значения
   woocommerce_wp_select( array(
      'id'      => '_select',
      'label'   => 'Выпадающий список',
      'options' => array(
         'one'   => __( 'Option 1', 'woocommerce' ),
         'two'   => __( 'Option 2', 'woocommerce' ),
         'three' => __( 'Option 3', 'woocommerce' ),
      ),
   ) );
   // Чекбокс
   woocommerce_wp_checkbox( array(
      'id'            => '_checkbox',
      'wrapper_class' => 'show_if_simple',
      'label'         => 'Чекбокс',
      'description'   => 'Выбери меня!',
   ) );
   // Радиокнопки
   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' => 'Три',
      ),
   ) );
   // скрытое поле
   woocommerce_wp_hidden_input( array(
      'id'    => '_hidden_field',
      'value' => 'hidden_value',
   ) );
   // Выбор товаров
   ?>
   <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_field_type_ids = get_post_meta( $post->ID, '_product_field_type_ids', true );
         $product_ids = ! empty( $product_field_type_ids ) && isset($product_field_type_ids) ? array_map( 'absint',  $product_field_type_ids ) : array();
         if ( $product_ids ) {
            foreach ( $product_ids as $product_id ) {
               $product      = wc_get_product( $product_id );
               $product_name = $product->get_formatted_name();
               echo '<option value="' . esc_attr( $product_id ) . '" ' . selected(true, true, false )  . '>' .
                    esc_html( $product->get_formatted_name() ) . '</option>';
            }
         }
         ?>
      </select><span class="woocommerce-help-tip" data-tip="Тут можно указать какое-нибудь описание"></span>
   </p>
   </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 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 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 get_post_meta( $post->ID, '_pack_height', true ); ?>"
         style="width: 15.75%;margin-right: 0;"/>
   </span> <span
            class="description"><?php echo wc_help_tip( 'Введите размер товара в упаковке в формате ДхШхВ' ); ?></span>
      </p>
   </div>
   <?php
}

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

к содержанию

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

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

add_action( 'woocommerce_process_product_meta', 'art_woo_custom_fields_save', 10 );
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 (  isset( $_POST['product_field_type'] ) && !empty($_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');
   }
}

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

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

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

Вывод полей

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

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

}
Вариант с проверками и форматированием
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_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
   }
}

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

к содержанию

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

Задача

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

Решение

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

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

  • надпись на кнопке;
  • ссылка на кнопке.
/*
 * Добавляем поля
 */
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;
	}
	
}
к содержанию

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

к содержанию

Еще один кейс

Задача

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

Решение

к содержанию

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

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 так и создание своих собственных полей и групп полей. Разжевал все очень подробно. Весь код в статье рабочий и проверенный.

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