Вопрос или проблема
Мне нужна помощь относительно магазина WooCommerce, который я создаю. Это для дизайнера текстиля на заказ, идея заключается в том, что клиенты могут просматривать пустой шаблон продукта, раскрашивать его по своему вкусу и отправлять его для изготовления на заказ.
Основная идея:
- Администратор загружает файл SVG в пользовательское поле продукта (ACF) — работает
- На пользовательском шаблоне single-product.php WC, если поле SVG не пустое, загружается соответствующий файл SVG и скрипт раскраски. — работает
- Клиент раскрашивает SVG с помощью скрипта раскраски по своему усмотрению. — работает
- Реализована кнопка «Добавить в корзину», чтобы выполнить AJAX $_POST запрос с элементом SVG DOM. Он отправляется на сервер. — работает
- Отображение SVG как в корзине, так и на странице «Спасибо». — работает
- Пользовательский SVG также должен отображаться на странице Админ «Просмотр заказа», чтобы дизайнер знал, как был раскрашен шаблон. — эта часть не работает.
Я подозреваю, что поскольку он добавляется к метаданным элемента заказа с помощью $item->update_meta_data('custom_svg_content', $values['custom_svg_content']);
SVG очищается, и он не отображается правильно на странице просмотра заказа администратором. Он удаляет все теги, поэтому у меня остается только встроенный CSS SVG. В других местах это работает, однако я считаю, что мое решение не идеальное, так как я пропускаю очистку.
Мои вопросы: Где мне нужно добавить очистку, и какой метод следует использовать для отображения SVG на странице «Просмотр заказа» администратора? Интересно также по поводу уязвимостей и того, есть ли лучший способ сделать это (конвертировать SVG в PNG через Imagick и работать с ним?)
Я действительно ценю любые комментарии или помощь, которые могли бы направить меня в правильном направлении. Спасибо!
Соответствующая часть functions.php:
function enqueue_custom_ajax_add_to_cart_script() {
wp_enqueue_script( 'custom-ajax-add-to-cart', get_template_directory_uri() . '/js/custom-ajax-add-to-cart.js', array( 'jquery' ), null, true );
// Передаем URL AJAX и nonce в скрипт
wp_localize_script( 'custom-ajax-add-to-cart', 'custom_ajax_params', array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'custom_ajax_nonce' ),
));
}
add_action( 'wp_enqueue_scripts', 'enqueue_custom_ajax_add_to_cart_script' );
add_action('wp_ajax_add_to_cart', 'custom_ajax_add_to_cart');
add_action('wp_ajax_nopriv_add_to_cart', 'custom_ajax_add_to_cart');
function custom_ajax_add_to_cart() {
// Проверка nonce и других мер безопасности
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'custom_ajax_nonce')) {
wp_send_json_error('Неверный nonce');
wp_die();
}
// Получение ID продукта и содержимого SVG из POST запроса
$product_id = absint($_POST['product_id']);
$svg_content = wp_unslash($_POST['svg_content']); // Очистка содержимого SVG
// Логирование полученных данных
error_log('ID продукта: ' . $product_id);
error_log('Содержимое SVG: ' . $svg_content); // Логируем содержимое SVG
// Создание уникального ключа для обеспечения отдельных строк для каждого экземпляра
$unique_key = md5($product_id . $svg_content); // Уникальный ключ для цвета SVG
// Подготовка данных элемента корзины с пользовательским содержимым SVG
$cart_item_data = array(
'custom_svg_content' => $svg_content,
'unique_key' => $unique_key, // Создание уникального ключа
);
// Добавление продукта в корзину с пользовательскими данными
$added = WC()->cart->add_to_cart($product_id, 1, 0, array(), $cart_item_data);
if ($added) {
wp_send_json_success();
} else {
wp_send_json_error('Не удалось добавить продукт в корзину');
}
}
function display_custom_svg_in_cart($item_data, $cart_item) {
// Проверка, существует ли содержимое SVG в элементе корзины
if (isset($cart_item['custom_svg_content']) && !empty($cart_item['custom_svg_content'])) {
// Добавление содержимого SVG к данным элемента
echo $cart_item['custom_svg_content']; //используя этот код для отображения только SVG без очистки
}
return $item_data;
}
add_filter('woocommerce_get_item_data', 'display_custom_svg_in_cart', 10, 2);
// Сохранение пользовательского содержимого SVG в элементах заказа без очистки
add_action('woocommerce_checkout_create_order_line_item', 'save_custom_svg_to_order_item', 10, 4);
function save_custom_svg_to_order_item($item, $cart_item_key, $values, $order) {
if (isset($values['custom_svg_content'])) {
// Сохранение необработанного содержимого SVG в метаданных заказа, рассматривая его как необработанный HTML
$item->update_meta_data('custom_svg_content', $values['custom_svg_content']);
}
}
add_action('woocommerce_order_item_meta_end', 'display_custom_svg_on_order_page', 10, 4);
function display_custom_svg_on_order_page($item_id, $item, $order, $plain_text) {
// Получение пользовательского содержимого SVG из метаданных элемента заказа
$custom_svg = $item->get_meta('custom_svg_content');
if ($custom_svg) {
// Обеспечить вывод содержимого SVG как необработанного HTML (обойти экранирование)
echo '<div class="custom-svg-content" style="margin-top: 10px;">';
echo $custom_svg; // Вывод SVG как содержимого необработанного HTML
echo '</div>';
}
}
Соответствующая часть single-product.php:
<!---------------- РАСКРАСКА ------------------>
<?php
if(get_field('svg')) {
$svg_path = get_field('svg');
$svg_content = file_get_contents( $svg_path );
echo '<center><div id="svgContainer" style="max-height:100vh;">' . $svg_content . '</div></center>';
?>
<style>
.selected { border: 3px solid black; }
#color-circle-container {
width: 100%;
display: grid;
grid-template-columns: repeat(16, 1.5rem);
gap: 1rem;
justify-content: center;
}
.color-circle {
display: block;
width: 1.5rem;
height: 1.5rem;
border-radius: 100%;
margin: 0.2rem;
}
@media (max-width:960px) {
#color-circle-container{grid-template-columns:repeat(8,1.5rem);}
}
</style>
<div id="color-circle-container">
<div class="color-circle" style="background-color: #ff0000;" data-color="#ff0000"></div>
<div class="color-circle" style="background-color: #0000ff;" data-color="#0000ff"></div>
<div class="color-circle" style="background-color: #ffff00;" data-color="#ffff00"></div>
<div class="color-circle" style="background-color: #6600cc;" data-color="#6600cc"></div>
<div class="color-circle" style="background-color: #ff99ff;" data-color="#ff99ff"></div>
<div class="color-circle" style="background-color: #00ff00;" data-color="#00ff00"></div>
<div class="color-circle" style="background-color: #339933;" data-color="#339933"></div>
<div class="color-circle" style="background-color: #9999ff;" data-color="#9999ff"></div>
<div class="color-circle" style="background-color: #cc66ff;" data-color="#cc66ff"></div>
<div class="color-circle" style="background-color: #ff9900;" data-color="#ff9900"></div>
<div class="color-circle" style="background-color: #ff6600;" data-color="#ff6600"></div>
<div class="color-circle" style="background-color: #cc0000;" data-color="#cc0000"></div>
<div class="color-circle" style="background-color: #993300;" data-color="#993300"></div>
<div class="color-circle" style="background-color: #663300;" data-color="#663300"></div>
<div class="color-circle" style="background-color: #ffccff;" data-color="#ffccff"></div>
<div class="color-circle" style="background-color: #ffcc99;" data-color="#ffcc99"></div>
<div class="color-circle" style="background-color: #ffffcc;" data-color="#ffffcc"></div>
<div class="color-circle" style="background-color: #ccffcc;" data-color="#ccffcc"></div>
<div class="color-circle" style="background-color: #ccffff;" data-color="#ccffff"></div>
<div class="color-circle" style="background-color: #cc9900;" data-color="#cc9900"></div>
<div class="color-circle" style="background-color: #666633;" data-color="#666633"></div>
<div class="color-circle" style="background-color: #333300;" data-color="#333300"></div>
<div class="color-circle" style="background-color: #4d004d;" data-color="#4d004d"></div>
<div class="color-circle" style="background-color: #ff33cc;" data-color="#ff33cc"></div>
<div class="color-circle" style="background-color: #ffffff;" data-color="#ffffff"></div>
<div class="color-circle" style="background-color: #336699;" data-color="#336699"></div>
<div class="color-circle" style="background-color: #333399;" data-color="#333399"></div>
<div class="color-circle" style="background-color: #99ccff;" data-color="#99ccff"></div>
<div class="color-circle" style="background-color: #999966;" data-color="#999966"></div>
<div class="color-circle" style="background-color: #D3D3D3;" data-color="#D3D3D3"></div>
<div class="color-circle" style="background-color: #808080;" data-color="#808080"></div>
<div class="color-circle" style="background-color: #000000;" data-color="#000000"></div>
</div>
<!-- Скрипт раскраски -->
<script>
let selectedColor="#ff0000";
document.addEventListener('DOMContentLoaded', function() {
const svgContainer = document.getElementById('svgContainer');
const paths = svgContainer.querySelectorAll('path');
paths.forEach(path => {
path.addEventListener('click', function() {
this.style.fill = selectedColor;
});
});
});
const colorCircles = document.querySelectorAll('.color-circle');
colorCircles[0].classList.add('selected');
colorCircles.forEach(circle => {
circle.addEventListener('click', function() {
colorCircles.forEach(c => c.classList.remove('selected'));
this.classList.add('selected');
selectedColor = this.getAttribute('data-color');
});
});
</script>
<!---------------- КОНЕЦ РАСКРАСКИ ------------------>
<!--- ПОЛЬЗОВАТЕЛЬСКАЯ КНОПКА ДОБАВЛЕНИЯ В КОРЗИНУ --->
<button class="custom-ajax-add-to-cart" data-product-id="<?php echo esc_attr( $product->get_id() ); ?>">
Добавить в корзину (пользовательская кнопка)
</button>
<!---- КОНЕЦ ПОЛЬЗОВАТЕЛЬСКОЙ КНОПКИ ДОБАВЛЕНИЯ В КОРЗИНУ --->
<?php
} else {
// Кнопка добавления в корзину
woocommerce_template_single_add_to_cart();
}
?>
custom-ajax-add-to-cart.js:
jQuery(document).ready(function($) {
$('.custom-ajax-add-to-cart').on('click', function(e) {
e.preventDefault(); // Предотвратить стандартное действие
const button = $(this);
button.prop('disabled', true); // Отключить кнопку, чтобы предотвратить множественные клики
var productId = button.data('product-id');
var svgContent = $('#svgContainer').html(); // Захватить содержимое SVG из контейнера
console.log('ID продукта:', productId);
console.log('Данные SVG:', svgContent);
if (productId && svgContent) {
$.ajax({
url: custom_ajax_params.ajax_url,
type: 'POST',
data: {
action: 'add_to_cart',
product_id: productId,
svg_content: svgContent,
nonce: custom_ajax_params.nonce
},
success: function(response) {
console.log('AJAX Ответ:', response);
// При необходимости обновить интерфейс или сообщить пользователю об успешном выполнении здесь
},
error: function(xhr, status, error) {
console.error('AJAX Ошибка:', error);
},
complete: function() {
button.prop('disabled', false); // Снова включить кнопку после завершения AJAX вызова
}
});
} else {
console.error('Отсутствует ID продукта или данные SVG');
button.prop('disabled', false); // Снова включить кнопку, если произошла ошибка
}
});
});
.
Ответ или решение
Инструмент настройки цвета SVG для WooCommerce: Решение проблемы с отображением на странице управления заказами
Вам удалось успешно реализовать множество важных функций для вашего интернет-магазина WooCommerce, связанного с кастомизированным дизайном текстиля. Однако, вы столкнулись с проблемой при отображении цветного SVG на странице просмотра заказа в админ-панели. Давайте подробно разберем предлагаемые решения, чтобы исправить данную ситуацию.
Актуальная Проблема
При сохранении SVG-контента в метаданных заказа через метод $item->update_meta_data('custom_svg_content', $values['custom_svg_content'])
, происходит автоматическая процесс-санитация, в результате чего все теги SVG удаляются. Однако для вашего случая это нежелательно, так как вам нужно сохранить весь SVG для корректного отображения.
Рекомендации по Решению
-
Сохранение SVG в оригинальном формате
При сохранении SVG-контента в метаданных заказа, важно сохранить его без проектирования. Вы можете использовать методwp_kses()
для указания разрешенных тегов и атрибутов, что поможет избежать уязвимостей без полного удаления SVG:$allowed_tags = array( 'svg' => array( 'xmlns' => array(), 'width' => array(), 'height' => array(), 'viewBox' => array(), 'path' => array( 'd' => array(), 'fill' => array(), 'stroke' => array(), // Добавьте дополнительные атрибуты по мере необходимости ), // Разрешите другие теги по мере необходимости ), // Добавьте другие реже используемые теги (например, `g`, `circle`) ); // При сохранении SVG $item->update_meta_data('custom_svg_content', wp_kses($values['custom_svg_content'], $allowed_tags));
-
Отображение на странице Управления Заказами
При выводе SVG на странице управления заказами, используйте функцииhtmlspecialchars
илиhtmlentities
, чтобы избежать потенциальных проблем с выводом:function display_custom_svg_on_order_page($item_id, $item, $order, $plain_text) { $custom_svg = wp_kses_post($item->get_meta('custom_svg_content')); if ($custom_svg) { echo '<div class="custom-svg-content" style="margin-top: 10px;">'; echo $custom_svg; echo '</div>'; } }
-
Безопасность и Уязвимости
Всегда учитывайте безопасность при работе с пользовательским вводом SVG. Использование функцииwp_kses()
позволит вам ступенчато управлять тем, что действительно может быть использовано в SVG. Инструмент Imagick, о котором вы упомянули, хорош для преобразования SVG в другие форматы, такие как PNG, но в этом случае вы теряете возможность редактирования цвета на этапе заказа.
Заключение
Функциональность вашего интернет-магазина Woocommerce может быть значительно улучшена с помощью правильной обработки и отображения SVG. Использование wp_kses()
не только обеспечит защиту, но и позволит надлежащим образом сохранить данные для будущего использования. Убедитесь, что каждый шаг, который вы реализуете, имеет продуманную безопасность, ведь это главное в индустрии электронной коммерции.
Если у вас возникнут дополнительные вопросы или потребуется помощь по интеграции этого решения, не стесняйтесь обращаться за помощью. Успехов в развитии вашего WooCommerce магазина!