Вопрос или проблема
Я использую следующий код, который сразу же отображает предопределенные атрибуты продукта для товара аукциона Dokan с выпадающими меню (вместо того, чтобы пользователю вручную нажимать «Добавить атрибут»). Я также добавил два пользовательских раздела атрибутов: «Номер ссылки» и «Год выпуска», где пользователь сам вводит значения.
// Подключение Choices.js и его CSS
function enqueue_choices_js() {
wp_enqueue_style('choices-css', 'https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/choices.min.css', array(), '1.0.0');
wp_enqueue_script('choices-js', 'https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js', array('jquery'), '1.0.0', true);
}
add_action('wp_enqueue_scripts', 'enqueue_choices_js');
// Основная функция для обработки выпадающих списков с Choices.js, проверки собственности, номера ссылки и года выпуска
function dokan_predefined_attributes_with_choices_and_custom_fields_js() {
global $post;
$product_id = isset($post) ? $post->ID : 0;
// Получение существующих значений для номера ссылки и года выпуска (если они есть)
$existing_reference_number = $product_id ? get_post_meta($product_id, '_reference_number', true) : '';
$existing_watch_year = $product_id ? get_post_meta($product_id, '_watch_year', true) : '';
?>
<style>
.dokan-attribute-obligatory {
font-weight: bold;
color: #d9534f;
}
.product-edit-new-container .dokan-attribute-variation-options .dokan-product-attribute-wrapper ul li.product-attribute-list .dokan-product-attribute-item {
padding: 10px;
}
.choices[data-type*=select-one] .choices__button {
margin-top: -20px;
margin-right: 30px;
}
.dokan-attribute-missing {
border: 1px solid #d9534f;
padding: 10px;
border-radius: 5px;
}
.ui-sortable-handle {
touch-action: auto;
}
.dokan-btn-disabled {
opacity: 0.5;
pointer-events: none;
}
.ownership-confirmation {
margin-bottom: 20px;
padding: 10px;
border: 2px solid #0a3d62;
background-color: #f9f9f9;
border-radius: 5px;
}
.ownership-confirmation h3 {
margin-bottom: 10px;
font-weight: bold;
color: #0a3d62;
}
.choices__item--choice.is-highlighted {
background-color: #0a3d62 !important;
color: white !important;
}
/* Добавить отступ между атрибутами */
.dokan-dashboard .dokan-dashboard-content ul li {
margin-top: 15px;
margin-bottom: 15px;
}
/* Красная звездочка для обязательных полей */
.required-asterisk {
color: #d9534f !important;
font-weight: 700 !important;
}
</style>
<script type="text/javascript">
jQuery(document).ready(function($) {
// Отслеживание состояния проверки собственности и статуса изображения продукта
let ownershipPhotoUploaded = !!$('#ownership_photo_upload').val();
let productImageUploaded = !!$('input.dokan-feat-image-id').val();
// Список предопределенных атрибутов
var predefined_attributes = [
{ slug: 'pa_brand', name: 'Бренд' },
{ slug: 'pa_condition', name: 'Состояние' },
{ slug: 'pa_box', name: 'Оригинальная коробка' },
{ slug: 'pa_papers', name: 'Оригинальные документы' },
{ slug: 'pa_case-size', name: 'Размер корпуса' },
{ slug: 'pa_material', name: 'Материал' },
{ slug: 'pa_dial-color', name: 'Цвет циферблата' }
];
// Функция для загрузки сохраненных терминов атрибутов
function getSavedAttributeValue(slug) {
return $('[name="attribute_values_' + slug + '"]').val() || '';
}
function getAttributeTerms(attributeSlug, callback, selectedValue="") {
$.ajax({
url: '<?php echo admin_url('admin-ajax.php'); ?>',
method: 'POST',
dataType: 'json',
data: {
action: 'get_wc_attribute_terms',
attribute_slug: attributeSlug
},
success: function(response) {
callback(response, selectedValue);
},
error: function() {
callback([], selectedValue);
}
});
}
function addPredefinedAttributesToList() {
var $attributeList = $("ul.dokan-attribute-option-list");
$attributeList.empty();
$.each(predefined_attributes, function(index, attribute) {
var savedValue = getSavedAttributeValue(attribute.slug);
var attributeHtml = `
<li class="product-attribute-list taxonomy ${attribute.slug}" data-taxonomy="${attribute.slug}">
<div class="dokan-product-attribute-heading">
<span><i class="fas fa-bars" aria-hidden="true"></i> <strong>${attribute.name}</strong><span class="required-asterisk"> *</span></span>
</div>
<div class="dokan-product-attribute-item dokan-clearfix">
<div class="content-half-part">
<label class="form-label" for="">Название</label>
<strong>${attribute.name}</strong>
<input type="hidden" name="attribute_names[]" value="${attribute.slug}">
<input type="hidden" name="attribute_position[]" class="attribute_position" value="0">
<input type="hidden" name="attribute_is_taxonomy[]" value="1">
<label class="checkbox-item form-label">
<input type="checkbox" checked="checked" name="attribute_visibility[]" value="1"> Видимо на странице товара
</label>
</div>
<div class="content-half-part dokan-attribute-values">
<label for="" class="form-label">Значение(я)</label>
<select style="width:100%;" class="dokan_attribute_values choices__input" name="attribute_values[${index}][]">
<option value="">Загрузка...</option>
</select>
</div>
</div>
</li>
`;
$attributeList.append(attributeHtml);
getAttributeTerms(attribute.slug, function(values, selectedValue) {
var optionsHtml="<option value="">Выберите значение</option>";
$.each(values, function(i, value) {
var selected = (value === selectedValue) ? 'selected' : '';
optionsHtml += '<option value="' + value + '" ' + selected + '>' + value + '</option>';
});
var $select = $(`select[name="attribute_values[${index}][]"]`);
$select.html(optionsHtml);
new Choices($select[0], {
searchEnabled: true,
removeItemButton: true,
itemSelectText: '',
});
}, savedValue);
});
}
function addCustomFields() {
// Номер ссылки и год выпуска перемещены наверх и выделены, если отсутствуют
var referenceNumberField = `
<li class="product-attribute-list taxonomy reference-number" data-taxonomy="reference-number">
<div class="dokan-product-attribute-heading">
<span><i class="fas fa-bars" aria-hidden="true"></i> <strong>Номер ссылки</strong><span class="required-asterisk"> *</span></span>
</div>
<div class="dokan-product-attribute-item dokan-clearfix">
<div class="content-half-part">
<label class="form-label" for="reference_number">Номер ссылки</label>
<input type="text" id="reference_number" name="reference_number" class="dokan-form-control" placeholder="Введите номер ссылки" value="<?php echo esc_attr($existing_reference_number); ?>" required>
</div>
</div>
</li>
`;
var watchYearField = `
<li class="product-attribute-list taxonomy watch-year" data-taxonomy="watch-year">
<div class="dokan-product-attribute-heading">
<span><i class="fas fa-bars" aria-hidden="true"></i> <strong>Год выпуска</strong><span class="required-asterisk"> *</span></span>
</div>
<div class="dokan-product-attribute-item dokan-clearfix">
<div class="content-half-part">
<label class="form-label" for="watch_year">Год выпуска</label>
<input type="text" id="watch_year" name="watch_year" class="dokan-form-control" placeholder="Введите год выпуска" value="<?php echo esc_attr($existing_watch_year); ?>" required>
</div>
</div>
</li>
`;
// Добавить пользовательские поля (номер ссылки и год выпуска) в начало списка атрибутов
$("ul.dokan-attribute-option-list").prepend(watchYearField);
$("ul.dokan-attribute-option-list").prepend(referenceNumberField);
// Условно добавить проверку собственности в зависимости от статуса продукта
if ($(".dokan-product-status-label:contains('Ожидает проверки'), .dokan-product-status-label:contains('В сети'), .dokan-product-status-label:contains('Черновик')").length === 0) {
var ownershipField = `
<div class="ownership-confirmation">
<h3>Проверка собственности <span class="required-asterisk">*</span></h3>
<p>Для подтверждения собственности, пожалуйста, загрузите фото ваших часов с отображением времени <strong id="generated-time"></strong>.</p>
<div class="dokan-form-group">
<label class="dokan-control-label" for="ownership_photo_upload">Загрузите фото</label>
<input type="file" name="ownership_photo_upload" id="ownership_photo_upload" accept="image/*" required>
</div>
</div>
`;
$('.dokan-attribute-variation-options').prepend('<div class="dokan-custom-fields">' + ownershipField + '</div>');
function generateRandomTime() {
var hours = Math.floor(Math.random() * 24);
var minutes = Math.floor(Math.random() * 60);
return ('0' + hours).slice(-2) + ':' + ('0' + minutes).slice(-2);
}
var randomTime = generateRandomTime();
$('#generated-time').text(randomTime);
}
}
addPredefinedAttributesToList();
addCustomFields();
function checkRequiredFields() {
var attributesFilled = checkAttributes();
var imageUploaded = checkFeaturedImage();
var customFieldsValid = checkCustomFields();
var $submitButton = $('input[name="update_auction_product"]');
if (attributesFilled && imageUploaded && customFieldsValid) {
$submitButton.prop('disabled', false).removeClass('dokan-btn-disabled');
} else {
$submitButton.prop('disabled', true).addClass('dokan-btn-disabled');
}
}
function checkAttributes() {
var missingValue = false;
$('ul.dokan-attribute-option-list select.dokan_attribute_values').each(function() {
if ($(this).val() === "" || $(this).val().length === 0) {
$(this).closest('.product-attribute-list').addClass('dokan-attribute-missing');
missingValue = true;
} else {
$(this).closest('.product-attribute-list').removeClass('dokan-attribute-missing');
}
});
// Проверка, отсутствует ли номер ссылки или год выпуска
if ($('#reference_number').val() === "") {
$('#reference_number').closest('.product-attribute-list').addClass('dokan-attribute-missing');
missingValue = true;
} else {
$('#reference_number').closest('.product-attribute-list').removeClass('dokan-attribute-missing');
}
if ($('#watch_year').val() === "") {
$('#watch_year').closest('.product-attribute-list').addClass('dokan-attribute-missing');
missingValue = true;
} else {
$('#watch_year').closest('.product-attribute-list').removeClass('dokan-attribute-missing');
}
return !missingValue;
}
function checkFeaturedImage() {
return !!$('input.dokan-feat-image-id').val() && $('input.dokan-feat-image-id').val() !== "0";
}
function checkCustomFields() {
var referenceNumber = $('#reference_number').val();
var watchYear = $('#watch_year').val();
// Проверять подтверждение собственности только если оно видно
var ownershipValid = $(".ownership-confirmation").length === 0 || !!$('#ownership_photo_upload').val();
return referenceNumber && watchYear && ownershipValid;
}
$(document).on('change', 'input.dokan-feat-image-id', function() {
productImageUploaded = !!$('input.dokan-feat-image-id').val();
checkRequiredFields();
});
$(document).on('click', '.dokan-remove-feat-image', function() {
setTimeout(function() {
productImageUploaded = false;
$('input.dokan-feat-image-id').val("0");
checkRequiredFields();
}, 100);
});
$(document).on('change', 'select.dokan_attribute_values, #ownership_photo_upload', function() {
checkRequiredFields();
});
checkRequiredFields();
});
</script>
<?php
}
add_action('wp_footer', 'dokan_predefined_attributes_with_choices_and_custom_fields_js');
// Обработчик AJAX для получения терминов WooCommerce для атрибута
function get_wc_attribute_terms() {
$attribute_slug = isset($_POST['attribute_slug']) ? sanitize_text_field($_POST['attribute_slug']) : '';
$taxonomy = $attribute_slug;
$terms = get_terms(array(
'taxonomy' => $taxonomy,
'hide_empty' => false,
));
$term_names = array();
if (!is_wp_error($terms)) {
foreach ($terms as $term) {
$term_names[] = $term->name;
}
}
wp_send_json($term_names);
}
add_action('wp_ajax_get_wc_attribute_terms', 'get_wc_attribute_terms');
add_action('wp_ajax_nopriv_get_wc_attribute_terms', 'get_wc_attribute_terms');
// Хук для сохранения пользовательских полей (номер ссылки и год выпуска) как атрибутов продукта WooCommerce
function save_reference_and_year_attributes($product_id) {
if (isset($_POST['reference_number'])) {
$reference_number = sanitize_text_field($_POST['reference_number']);
wp_set_object_terms($product_id, $reference_number, 'pa_reference-number');
}
if (isset($_POST['watch_year'])) {
$watch_year = sanitize_text_field($_POST['watch_year']);
wp_set_object_terms($product_id, $watch_year, 'pa_watch-year');
}
}
add_action('dokan_process_product_meta', 'save_reference_and_year_attributes', 10, 2);
У меня есть две проблемы:
-
Когда пользователь нажимает «Сохранить продукт», все значения атрибутов успешно сохраняются для продукта, за исключением номера ссылки и года выпуска, которые вводятся текстом.
-
Значения атрибутов не загружаются, когда я редактирую загруженный продукт (со статусом «Ожидает проверки», «Черновик» или «В сети»). Вместо этого пользователю придется заново выбирать все значения, если он захочет внести изменения и снова сохранить продукт.
Не мог бы кто-нибудь помочь мне?
С наилучшими пожеланиями,
Мартин
Ответ или решение
Добрый день, Мартин!
Судя по вашему коду и описанным проблемам, давайте решим каждую из них поэтапно.
Проблема 1: Сохранение значений атрибутов "Номер Refernce" и "Год Часа"
Ваша текущая реализация сохранения значений атрибутов, введённых в текстовые поля, вероятно, не работает, потому что вы не сохраняете их как метаданные продукта.
Вот обновленный код для обработки сохранения этих значений:
function save_reference_and_year_attributes($product_id) {
if (isset($_POST['reference_number'])) {
$reference_number = sanitize_text_field($_POST['reference_number']);
update_post_meta($product_id, '_reference_number', $reference_number); // Сохраняем как метаданные
wp_set_object_terms($product_id, $reference_number, 'pa_reference-number'); // Если нужно установить как термин атрибута
}
if (isset($_POST['watch_year'])) {
$watch_year = sanitize_text_field($_POST['watch_year']);
update_post_meta($product_id, '_watch_year', $watch_year); // Сохраняем как метаданные
wp_set_object_terms($product_id, $watch_year, 'pa_watch-year'); // Если нужно установить как термин атрибута
}
}
add_action('dokan_process_product_meta', 'save_reference_and_year_attributes', 10, 2);
Обратите внимание, что здесь используются функции update_post_meta
для сохранения ваших текстовых полей как метаданных товара. Таким образом, вы сможете получить их в будущем.
Проблема 2: Загрузка атрибутов при редактировании продукта
Вам необходимо убедиться, что при редактировании товара значения для "Номер Refernce" и "Год Часа" загружаются в ваши текстовые поля. Вы уже закладываете это в код, но чтобы убедиться, что метаданные правильно загружаются, измените свой JavaScript код следующим образом:
// Функция для добавления пользовательских полей
function addCustomFields() {
var referenceNumberField = `
<li class="product-attribute-list taxonomy reference-number" data-taxonomy="reference-number">
<div class="dokan-product-attribute-heading">
<span><i class="fas fa-bars" aria-hidden="true"></i> <strong>Reference Number</strong><span class="required-asterisk">*</span></span>
</div>
<div class="dokan-product-attribute-item dokan-clearfix">
<div class="content-half-part">
<label class="form-label" for="reference_number">Reference Number</label>
<input type="text" id="reference_number" name="reference_number" class="dokan-form-control" placeholder="Enter reference number" value="<?php echo esc_attr($existing_reference_number); ?>" required>
</div>
</div>
</li>
`;
var watchYearField = `
<li class="product-attribute-list taxonomy watch-year" data-taxonomy="watch-year">
<div class="dokan-product-attribute-heading">
<span><i class="fas fa-bars" aria-hidden="true"></i> <strong>Watch Year</strong><span class="required-asterisk">*</span></span>
</div>
<div class="dokan-product-attribute-item dokan-clearfix">
<div class="content-half-part">
<label class="form-label" for="watch_year">Watch Year</label>
<input type="text" id="watch_year" name="watch_year" class="dokan-form-control" placeholder="Enter watch year" value="<?php echo esc_attr($existing_watch_year); ?>" required>
</div>
</div>
</li>
`;
// Добавляем поля в верхнюю часть списка атрибутов
$("ul.dokan-attribute-option-list").prepend(watchYearField);
$("ul.dokan-attribute-option-list").prepend(referenceNumberField);
}
Убедитесь, что в вашем PHP коде доступ к $product_id
происходит сразу после проверки наличия $_POST
данных.
Заключение
После реализации изменений в коде вы должны убедиться, что значения "Номер Refernce" и "Год Часа" успешно сохраняются и загружаются при редактировании товара.
Проверьте эти изменения в вашем тестовом окружении и дайте знать, если проблемы всё ещё будут возникать. Удачи вам в ваших усилиях!
С уважением,
[Ваше Имя]