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

Доброго! Небольшое продолжение статьи про создание дополнительных полей через API WooCommerce, но теперь для вариативных товаров. И разбирать будем на конкретном примере.

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

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

к содержанию

Шаг первый. Создание поля

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

add_action( 'woocommerce_product_after_variable_attributes', 'art_term_production_fields', 10, 3 );
function art_term_production_fields( $loop, $variation_data, $variation ) {
woocommerce_wp_text_input( array(
'id'                => '_term_prod_var[' . $variation->ID . ']', // id поля
'label'             => 'Срок изготовления', // Надпись над полем
'description'       => 'Укажи срок изготовления, просто цифры в днях',// Описание поля
'desc_tip'          => 'true', // Всплывающая подсказка
'placeholder'       => 'Срок изготовления, дн', // Надпись внутри поля
'type'              => 'number', // Тип поля
'custom_attributes' => array( // Произвольные аттрибуты
'step' => 'any', // Шаг значений
'min'  => '0', // Минимальное значение
),
'value'             => get_post_meta( $variation->ID, '_term_prod_var', true ),
) );
}

Получаем вот такое поле, в каждой вариации товара

Произвольное поле вариативного товара

Можно вывести поле и в другом месте, где-то выше, например. Для этого используйте соответствующие хуки

  1. woocommerce_variation_options — после чекбоксов
  2. woocommerce_variation_options_pricing — после цены
  3. woocommerce_variation_options_inventory — после статуса остатков
  4. woocommerce_variation_options_dimensions — после размеров
  5. woocommerce_variation_options_tax — после класса доставки

Поле есть, но оно пока ничего не сохраняет. Давайте исправим это.

к содержанию

Шаг второй. Сохранение значений

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

add_action( 'woocommerce_save_product_variation', 'art_save_variation_settings_fields', 10, 2 );
function art_save_variation_settings_fields( $post_id ) {
$woocommerce__term_prod_var = $_POST['_term_prod_var'][ $post_id ];
if (isset($woocommerce__term_prod_var) && ! empty( $woocommerce__term_prod_var ) ) {
update_post_meta( $post_id, '_term_prod_var', esc_attr( $woocommerce__term_prod_var ) );
}
}

Алгоритм простой:

  • ловим значение в глобальной переменной $_POST;
  • проверяем нужное значение на существование;
  • если все нормально, тогда записываем/перезаписываем значение в поле.

Вот теперь все работает как надо. Поле есть и значения в нем сохраняются. Теперь надо эти значения вывести на странице товара.

к содержанию

Шаг третий. Вывод значений

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

add_filter( 'woocommerce_available_variation', 'load_variation_settings_fields' );
function load_variation_settings_fields( $variations ) {
$variations_time = get_post_meta( $variations['variation_id'], '_term_prod_var', true );
if ( isset( $variations_time ) && ! empty( $variations_time ) ) {
$variations['_term_prod_var'] = '<div class="term-production">';
$variations['_term_prod_var'] .= '<span>Срок изготовления </span>';
$variations['_term_prod_var'] .= get_post_meta( $variations['variation_id'], '_term_prod_var', true ) . ' дн.';
$variations['_term_prod_var'] .= '</div>';
}
return $variations;
}

Алгоритм тот же, что и выше:

  • получаем значение поля;
  • проверяем значение на существование;
  • если все нормально, тогда добавляем значение в массив.

Теперь надо вывести на странице товара. Нужных хуков не нашел, а потому придется воспользоваться заменой файлов. Для этого надо сделать так:

  • создать в коневой папке темы папку woocommerce;
  • в папку woocommerce скопировать из папки templates самого плагина папку single-product и все что в ней находиться;
  • открыть файл variation.php, который будет находиться по адресу ваша_тема/woocommerce/single-product/add-to-cart;

Осталось добавить в файл значение нашего поля

<div class="woocommerce-variation-custom-text-field ">
{{{ data.variation._term_prod_var }}}
</div>

Примерно так, можно выше или ниже, главное внутри тега <script> размещать код


В итоге получаем такой вывод, стилями можно навести красоты

На этом можно было бы и закончить, но возникает проблема: добавлять значения в поле если больше 2-3-х вариаций вручную еще можно, а что делать если этих вариаций десяток или два?

к содержанию

Шаг четвертый. Массовое изменение поля

Для этого есть в WooCommerce специальное решение по массовому заполнению полей всех вариаций сразу. Например, можно указать базовую цену сразу для всех вариаций

Такую же фичу можно сделать и для нашего поля. Сначала добавим в выпадающий список нужное значение

add_action( 'woocommerce_variable_product_bulk_edit_actions', 'art_actions_variation_settings_fields', 10, 1 );
function art_actions_variation_settings_fields() {
?>
<option data-global="true" value="variation_prod_time">Срок изготовления</option>
<?php
}

Получиться вот так

Теперь надо заставить работать данный пункт. Без ajax не обойтись. Добавляем код, который будет подрубать наш скрипт с аяксом сразу в подвал админки

add_action( 'admin_footer', 'art_script_add_all_variation_select' );
function art_script_add_all_variation_select() {
?>
<script>
jQuery(function ($) {
jQuery('.wc-metaboxes-wrapper').on('click', 'a.bulk_edit', function (event) {
var do_variation_term = jQuery('select.variation_actions').val();
var data = {},
value;
if ('variation_prod_time' === do_variation_term) {
value = window.prompt(woocommerce_admin_meta_boxes_variations.i18n_enter_a_value);
if (null !== value) {
data.value = value;
} else {
return;
}
jQuery.ajax({
url: woocommerce_admin_meta_boxes_variations.ajax_url,
data: {
action: 'woocommerce_bulk_edit_variations',
security: woocommerce_admin_meta_boxes_variations.bulk_edit_variations_nonce,
product_id: woocommerce_admin_meta_boxes_variations.post_id,
product_type: jQuery('#product-type').val(),
bulk_action: do_variation_term,
data: data
},
type: 'POST',
success: function (data) {
jQuery('.variations-pagenav .page-selector').val(1).first().change();
//console.log(data.product_id);
}
});
jQuery('#woocommerce-product-data').unblock();
}
});
});
</script>
<?php
}

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

add_action( 'woocommerce_bulk_edit_variations_default', 'action_woocommerce_bulk_edit_variations_default', 10, 4 );
function action_woocommerce_bulk_edit_variations_default( $bulk_action, $data, $product_id, $variations ) {
if ( 'variation_prod_time' === $bulk_action ) {
foreach ( $variations as $variation ) {
update_post_meta( $variation, '_term_prod_var', $data['value'] );
}
}
exit;
}

Вот и все. Профит! Весь код рабочий и проверен на реальных проектах.

к содержанию

Полностью весь код

Кроме изменений в файлах

/**
* Создаем текстовое поле
*
* @param $loop
* @param $variation_data
* @param $variation
*/
add_action( 'woocommerce_product_after_variable_attributes', 'art_term_production_fields', 10, 3 );
function art_term_production_fields( $loop, $variation_data, $variation ) {
woocommerce_wp_text_input( array(
'id'                => '_term_prod_var[' . $variation->ID . ']', // id поля
'label'             => 'Срок изготовления', // Надпись над полем
'description'       => 'Укажи срок изготовления, просто цифры в днях',// Описание поля
'desc_tip'          => 'true', // Всплывающая подсказка
'placeholder'       => 'Срок изготовления, дн', // Надпись внутри поля
'type'              => 'number', // Тип поля
'custom_attributes' => array( // Произвольные аттрибуты
'step' => 'any', // Шаг значений
'min'  => '0', // Минимальное значение
),
'value'             => get_post_meta( $variation->ID, '_term_prod_var', true ),
) );
}
/**
* Сохраняем значение поля
*
* @param $post_id
*/
add_action( 'woocommerce_save_product_variation', 'art_save_variation_settings_fields', 10, 2 );
function art_save_variation_settings_fields( $post_id ) {
$woocommerce__term_prod_var = $_POST['_term_prod_var'][ $post_id ];
if ( isset( $woocommerce__term_prod_var ) && ! empty( $woocommerce__term_prod_var ) ) {
update_post_meta( $post_id, '_term_prod_var', esc_attr( $woocommerce__term_prod_var ) );
}
}
/**
* Добавляем значение поле в массив данных
*
* @param $variations
*
* @return mixed
*/
add_filter( 'woocommerce_available_variation', 'art_load_variation_settings_fields' );
function art_load_variation_settings_fields( $variations ) {
$variations_time = get_post_meta( $variations['variation_id'], '_term_prod_var', true );
if ( isset( $variations_time ) && ! empty( $variations_time ) ) {
$variations['_term_prod_var'] = '<div class="term-production">';
$variations['_term_prod_var'] .= '<span>Срок изготовления </span>';
$variations['_term_prod_var'] .= get_post_meta( $variations['variation_id'], '_term_prod_var', true ) . ' дн.';
$variations['_term_prod_var'] .= '</div>';
}
return $variations;
}
/**
*  Добавляем пункт выпадающего списка в админке
*/
add_action( 'woocommerce_variable_product_bulk_edit_actions', 'art_actions_variation_settings_fields', 10, 1 );
function art_actions_variation_settings_fields() {
?>
<option data-global="true" value="variation_prod_time">Срок изготовления</option>
<?php
}
/**
* Добавляем аякс для массового изменения поля
*/
add_action( 'admin_footer', 'art_script_add_all_variation_select' );
function art_script_add_all_variation_select() {
?>
<script>
jQuery(function ($) {
jQuery('.wc-metaboxes-wrapper').on('click', 'a.bulk_edit', function (event) {
var do_variation_term = jQuery('select.variation_actions').val();
var data = {},
value;
if ('variation_prod_time' === do_variation_term) {
value = window.prompt(woocommerce_admin_meta_boxes_variations.i18n_enter_a_value);
if (null !== value) {
data.value = value;
} else {
return;
}
jQuery.ajax({
url: woocommerce_admin_meta_boxes_variations.ajax_url,
data: {
action: 'woocommerce_bulk_edit_variations',
security: woocommerce_admin_meta_boxes_variations.bulk_edit_variations_nonce,
product_id: woocommerce_admin_meta_boxes_variations.post_id,
product_type: jQuery('#product-type').val(),
bulk_action: do_variation_term,
data: data
},
type: 'POST',
success: function (data) {
jQuery('.variations-pagenav .page-selector').val(1).first().change();
//console.log(data.product_id);
}
});
jQuery('#woocommerce-product-data').unblock();
}
});
});
</script>
<?php
}
/**
* Сохранение значения для массового изменения
*
* @param $bulk_action
* @param $data
* @param $product_id
* @param $variations
*/
add_action( 'woocommerce_bulk_edit_variations_default', 'action_woocommerce_bulk_edit_variations_default', 10, 4 );
function action_woocommerce_bulk_edit_variations_default( $bulk_action, $data, $product_id, $variations ) {
if ( 'variation_prod_time' === $bulk_action ) {
foreach ( $variations as $variation ) {
update_post_meta( $variation, '_term_prod_var', $data['value'] );
}
}
exit;
}

Вопросы задаем в комментариях. Всем пока-пока…

11 комментариев
  • Антон

    17.12.2017

    Спасибо. Очень подробный и полезный материал.
    А как сделать, чтобы на 3 шаге дополнительные поля выводились не с ценой, а во вкладке дополнительной информации вместе с другими атрибутами. При изменении вариации там меняются вес и габариты, и ниже нужно вставить кастомные поля.

    • Артем

      06.01.2018

      Хороший вопрос. Ответа пока не знаю, как придумаю, так в статью добавлю

  • Павел

    16.01.2018

    Подскажите значения из этих вариативных полей можно передать например в контакт форм 7

    • Артем

      17.01.2018

      Передать можно, но придется с js возиться

  • Илья

    17.02.2018

    Подскажите, хтмл код в описании атрибутов как разрешить?

    • Артем

      18.02.2018

      Никак, это связано с безопасностью и код передавать через поле нельзя

  • Александр

    27.02.2018

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

    • Александр

      27.02.2018

      В итоге для обнуления удалил строчку "&& ! empty( $woocommerce__term_prod_var )"

      • Артем

        01.03.2018

        Можно и так, все от условий зависит

  • Константин

    21.07.2018

    Здравствуйте. Хочу поблагодарить вас за ваши труды, очень интересно и познавательно читать. У меня есть не большой вопрос. У меня все товары вариативные. Используя данный код, поле появляется именно в вариации, а мне необходимо сделать эти дополнительные поля для товара в общем, то есть на вкладке запасы.
    Пробовал использовать ваш код с этой статьи _https://wpruse.ru/woocommerce/custom-fields-in-products/, так поля появляются только у простого товара.
    Заранее благодарю за ответ.

    • Артем

      22.07.2018

      Доброго! Хм, ну по идее поля созданные по этой статье будут выводиться на любых товарах. Проверил. Поля создаются и выводить их можно на любом товаре. Что за вкладка Запасы?

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *
php js HTML CSS Code