Продолжение статьи про создание дополнительных полей для товаров через API WooCommerce, но теперь для вариативных товаров. И разбирать будем на конкретном примере.
- Шаг первый. Создание поля
- Шаг второй. Сохранение значений
- Шаг третий. Вывод значений
- Шаг четвертый. Массовое изменение поля
- Полностью весь код
- Дополнение. Добавление полей от плагина ACF Pro в вариативные товары и их вывод
- Шаг первый. Создание, вывод и сохранение полей
- Шаг два. Вывод значений полей.
- Заключение
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 ),
) );
}
Получаем вот такое поле, в каждой вариации товара
Можно вывести поле и в другом месте, где-то выше, например. Для этого используйте соответствующие хуки
woocommerce_variation_options
— после чекбоксовwoocommerce_variation_options_pricing
— после ценыwoocommerce_variation_options_inventory
— после статуса остатковwoocommerce_variation_options_dimensions
— после размеров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;
}
к содержанию
Дополнение. Добавление полей от плагина ACF Pro в вариативные товары и их вывод
Немного странная задача, но если на сайте используется ACF Pro, то можно его прикрутить и к вариативным товарам.
functions.php
или например пустой плагин. В данном конкретном случае, лучше делать через плагин. Так как в темах могут быть конфликтующие скрипты. Прежде чем, вносить какие либо изменения, сделайте бекап сайта.Шаг первый. Создание, вывод и сохранение полей
Для примера создадим несколько полей через штатный интерфейс.
У меня 3 поля:
- повторитель
- текст
- картинка (для вывода использую только ссылку)
Добавляем дополнительный тип поля, что бы привязать созданные поля к вариациям
/**
* Добавление нового типа поста в типах ACF Pro
*
* @param $choices
*
* @return mixed
*
* @author unknown
* @verphp 7.0
* @testedwith WC 6.0
* @testedwith ACF Pro 5.12
*/
function art_added_to_acf_variation_post( $choices ) {
$choices['product_variation'] = 'Product Variation';
return $choices;
}
add_filter( 'acf/location/rule_values/post_type', 'art_added_to_acf_variation_post' );
Поле добавления сниппета, в типах записи ACF появиться новый тип.
Выбираем новый тип записи Product Variation и сохраняем нашу группу полей
Теперь выведем поля, на вариациях, что бы их можно было заполнять.
/**
* Вывод полей на вариациях товара
*
* @param $loop_index
* @param $variation_data
* @param $variation_post
*
* @return void
*
* @author unknown
* @verphp 7.0
* @testedwith WC 6.0
* @testedwith ACF Pro 5.12
*/
function art_render_fields_to_variation( $loop_index, $variation_data, $variation_post ) {
$GLOBALS['wc_loop_variation_id'] = $variation_post->ID;
foreach ( acf_get_field_groups() as $field_group ) {
acf_render_fields( $variation_post->ID, acf_get_fields( $field_group ) );
}
$GLOBALS['wc_loop_variation_id'] = null;
}
add_action( 'woocommerce_product_after_variable_attributes', 'art_render_fields_to_variation', 10, 3 );
Поля появились, но работаю пока некорректно, точнее ни повторитель, ни добавление картинок не работает. Чтобы бы все заработало, добавим еще один сниппет
/**
* Подключаем скрипт для работы повторителя и други=х полей завязанных на скрипты
*
* @param $field
*
* @return void
*
* @author unknown
*
* @verphp 7.0
* @testedwith WC 6.0
* @testedwith ACF Pro 5.12
*/
function art_added_script_after_render( $field ) {
?>
<script>
( function ( $ ) {
acf.doAction( 'append', $( '#post' ) );
})( jQuery );
</script>
<?php
}
add_action( 'acf/render_field/type=repeater', 'art_added_script_after_render', 10, 1 );
Теперь всё заработало: и повторитель добавляет, и картинки загружаются. Осталось только нужные значения сохранять в базу. Давайте это и сделаем.
Сначала требуется правильно указать идентификаторы полей. Для этого и используем подмену и указываем нужные значения
/**
* ПОдменя идентификатора поля
*
* @param $field
*
* @return mixed
*
* @author unknown
* @verphp 7.0
* @testedwith WC 6.0
* @testedwith ACF Pro 5.12
*/
function art_prepare_fields_to_variation( $field ) {
if ( empty( $GLOBALS['wc_loop_variation_id'] ) ) {
return $field;
}
$field['name'] = preg_replace( '/^acf\[/', 'acf_variation[' . $GLOBALS['wc_loop_variation_id'] . '][', $field['name'] );
return $field;
}
add_filter( 'acf/prepare_field', 'art_prepare_fields_to_variation', 10, 1 );
Теперь можно сохранять нужные значения
/**
* Сохранение полей
*
* @param $variation_id
* @param $loop_index
*
* @return void
*
* @author unknown
* @verphp 7.0
* @testedwith WC 6.0
* @testedwith ACF Pro 5.12
*/
function art_save_fields_variations( $variation_id, $loop_index ) {
if ( ! isset( $_POST['acf_variation'][ $variation_id ] ) ) {
return;
}
if ( ! empty( $_POST['acf_variation'][ $variation_id ] ) && is_array( $fields = $_POST['acf_variation'][ $variation_id ] ) ) {
foreach ( $fields as $key => $val ) {
update_field( $key, $val, $variation_id );
}
}
}
add_action( 'woocommerce_save_product_variation', 'art_save_fields_variations', 1000, 2 );
к содержанию
Шаг два. Вывод значений полей.
Для вывода потребуется замена файла. Выше уже описано как это сделать, но еще раз продублирую:
- создать в коневой папке темы папку
woocommerce
, если её ещё нет; - в папку
woocommerce
скопировать из папкиtemplates
самого плагина папкуsingle-product
и все что в ней находиться; - открыть файл
variation.php
, который будет находиться по адресуваша_тема/woocommerce/single-product/add-to-cart
;
Пока выводить нечего. потому, давайте в общий массив атрибутов добавим значения наших полей.
/**
* Добавление значений полей к атрибутам вариаций
*
* @param $variations
*
* @return mixed
*
* @author unknown
* @verphp 7.0
* @testedwith WC 6.0
* @testedwith ACF Pro 5.12
*/
function art_added_fields_to_variation_attributes( $variations ) {
$variations['repeater'] = get_field( '11', $variations['variation_id'] );
$variations['text_addon'] = get_field( '333', $variations['variation_id'] );
$variations['image_addon'] = get_field( '444', $variations['variation_id'] );
return $variations;
}
add_filter( 'woocommerce_available_variation', 'art_added_fields_to_variation_attributes', 10, 1 );
Если посмотреть инспектор кода, то увидим, что общем объекте атрибутов, появились и наши значения
Причем, как положено, для каждой вариации, свои значения.
Теперь изменяем файл variation.php
Вывод текстового поля
<div class="woocommerce-variation-text_addon">{{{ data.variation.text_addon }}}</div>
Вывод изображения
Если выводиться массив изображения
<div class="woocommerce-variation-image_addon"><img src='{{{ data.variation.image_addon.url }}}'></div>
В данном случае, из объекта массива изображения берем только url
основной картинки, но можно и дргие значения брать
Если изображение ссылкой выводиться
<div class="woocommerce-variation-image_addon"><img src='{{{ data.variation.image_addon }}}'></div>
Вывод повторителя
Тут сложнее, нужен цикл перебора значений. Вывдем значения в виде простого списка
<div class="woocommerce-variation-repeater">
<ul>
<# _.each( data.variation.repeater, function( listItem ){ #>
<li>
{{{ data.variation.text_two }}}
<img src='{{{ listItem.image }}}'>
</li>
<# }); #>
</ul>
</div>
к содержанию
Заключение
В целом, основные сложности в вариативных товарах заключатся только в выводе значений. А так как, в вариациях используется шаблонизатор Underscore.js, то глянув на документацию можно вывести любые значения.
Как-то так так. Пишите в коментариях, что думаете.