...
Как добавить загрузку изображений к отзывам в WooCommerce
Уроки

Как добавить загрузку изображений к отзывам в WooCommerce

Главная » Уроки » Как добавить загрузку изображений к отзывам в WooCommerce

Вовлечённость клиентов — ключевой фактор успешного интернет-магазина. Один из лучших способов повысить доверие к товарам — позволить покупателям добавлять фото к своим отзывам. В этой статье я покажу, как реализовать функционал загрузки изображений в отзывах WooCommerce.

В стандартных отзывах о товарах WooCommerce нет возможности загружать фото, а иногда это бывает необходимо.

Реализованный функционал позволяет:
✅ Загружать до 10 изображений к отзыву
✅ Просматривать фото в удобном слайдере
✅ Увеличивать изображения в Lightbox
✅ Управлять фотографиями из админ-панели

Ниже приведено готовое решение, которое вы можете поместить в function.php вашей темы либо как отдельный сниппет в плагине Code Snippets.

Сниппет целиком

// Добавляем поле загрузки изображений в форму отзывов
add_filter('comment_form_field_comment', 'add_image_upload_to_review_form');
function add_image_upload_to_review_form($field) {
    global $post;
    if ($post->post_type === 'product') {
        $field .= '<p class="comment-form-images"><label for="images"><span class="upload-text">' . __('Добавить фото', 'textdomain') . '</span><span class="file-count-badge">0</span></label><input type="file" id="images" name="images[]" multiple="multiple" accept="image/*" /></p>';
    }
    return $field;
}

// Устанавливаем enctype для формы комментариев
add_action('wp_footer', 'set_comment_form_enctype');
function set_comment_form_enctype() {
    global $post;
    if ($post && $post->post_type === 'product') {
        ?>
        <script>
        document.addEventListener('DOMContentLoaded', function() {
            var form = document.getElementById('commentform');
            if (form) {
                form.setAttribute('enctype', 'multipart/form-data');
            }
        });
        </script>
        <?php
    }
}

// Обрабатываем загрузку изображений при отправке отзыва
add_action('comment_post', 'handle_review_image_uploads', 10, 2);
function handle_review_image_uploads($comment_id, $comment_approved) {
    if (isset($_FILES['images']) && !empty($_FILES['images']['name'][0])) {
        $uploaded_images = array();
        $files = $_FILES['images'];
        $max_images = 10;
        $file_count = count($files['name']);
        if ($file_count > $max_images) {
            $file_count = $max_images;
        }
        for ($i = 0; $i < $file_count; $i++) {
            if ($files['name'][$i]) {
                $file = array(
                    'name' => $files['name'][$i],
                    'type' => $files['type'][$i],
                    'tmp_name' => $files['tmp_name'][$i],
                    'error' => $files['error'][$i],
                    'size' => $files['size'][$i]
                );
                $_FILES = array('upload' => $file);
                $upload = wp_handle_upload($file, array('test_form' => false));
                if ($upload && !isset($upload['error'])) {
                    $uploaded_images[] = $upload['url'];
                }
            }
        }
        if (!empty($uploaded_images)) {
            update_comment_meta($comment_id, 'review_images', $uploaded_images);
        }
    }
}

// Отображаем изображения в слайдере над текстом отзыва
add_action('woocommerce_review_before_comment_text', 'display_review_images_slider', 10, 1);
function display_review_images_slider($comment) {
    $images = get_comment_meta($comment->comment_ID, 'review_images', true);
    if ($images && is_array($images)) {
        echo '<div class="review-images-slider">';
        echo '<button class="slider-prev"><span class="dashicons dashicons-arrow-left-alt2"></span></button>';
        echo '<div class="slider-container">';
        foreach ($images as $image) {
            echo '<div><img src="' . esc_url($image) . '" alt="Review Image" /></div>';
        }
        echo '</div>';
        echo '<button class="slider-next"><span class="dashicons dashicons-arrow-right-alt2"></span></button>';
        echo '</div>';
    }
}

// Добавляем стили для слайдера и lightbox
add_action('wp_head', 'add_review_images_styles');
function add_review_images_styles() {
    if (is_product()) {
        ?>
        <style>
        .review-images-slider {
            position: relative;
            margin-bottom: 10px;
            display: flex;
            align-items: center;
        }
        .slider-container {
            display: flex;
            overflow-x: auto;
            scroll-behavior: smooth;
            width: calc(100% - 60px); /* Учитываем ширину кнопок */
            margin: 0 30px; /* Отступы для кнопок */
        }
        .slider-container > div {
            flex: 0 0 auto;
            width: 100px;
            margin-right: 10px;
        }
        .slider-container img {
            cursor: pointer;
        }
        .slider-prev, .slider-next {
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            background-color: rgb(175 138 120);
            color: white;
            border: none;
            cursor: pointer;
            padding: 5px;
            z-index: 1;
			border-radius: 50px;
        }
        .slider-prev {
            left: 0;
        }
        .slider-next {
            right: 0;
        }
        #review-lightbox {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0,0,0,0.8);
            z-index: 9999;
        }
        #lightbox-content {
            position: absolute;
            top: 300px;
            bottom: 300px;
            left: 50%;
            transform: translateX(-50%);
            display: flex;
            justify-content: center;
            align-items: center;
            width: 80%;
        }
        .image-container {
            position: relative;
            display: inline-block;
        }
        #lightbox-image {
            max-width: 100%;
            max-height: 700px;
        }
        #lightbox-close {
            position: absolute;
            top: 10px;
    		right: 10px;
            color: white;
            font-size: 24px;
            cursor: pointer;
            z-index: 1;
        }
        #lightbox-prev, #lightbox-next {
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            background: none;
            border: none;
            color: white;
            font-size: 30px;
            cursor: pointer;
    		z-index: 99;
        }
        #lightbox-prev {
            left: 10px;
        }
        #lightbox-next {
            right: 10px;
        }
        .comment-form-images input[type="file"] {
            display: none;
        }
        .comment-form-images label {
            position: relative;
            display: inline-block;
            background-color: #AF8A78;
            color: white;
            padding: 10px 15px;
            cursor: pointer;
            border-radius: 5px;
        }
        .file-count-badge {
            position: absolute;
            top: -10px;
            right: -10px;
            background-color: #846858;
            color: white;
            border-radius: 50%;
            width: 20px;
            height: 20px;
            text-align: center;
            line-height: 20px;
            font-size: 12px;
            display: none;
        }
        </style>
        <?php
    }
}

// Добавляем JavaScript для слайдера и lightbox
add_action('wp_footer', 'add_review_images_script');
function add_review_images_script() {
    if (is_product()) {
        ?>
        <script>
        document.addEventListener('DOMContentLoaded', function() {
            var fileInput = document.querySelector('input[name="images[]"]');
            var badge = document.querySelector('.file-count-badge');
            fileInput.addEventListener('change', function() {
                var count = this.files.length;
                if (count > 10) {
                    alert('You can upload a maximum of 10 images.');
                    this.value = '';
                    badge.style.display = 'none';
                } else if (count > 0) {
                    badge.textContent = count;
                    badge.style.display = 'block';
                } else {
                    badge.style.display = 'none';
                }
            });

            // Слайдер
            var sliders = document.querySelectorAll('.review-images-slider');
            sliders.forEach(function(slider) {
                var container = slider.querySelector('.slider-container');
                var prev = slider.querySelector('.slider-prev');
                var next = slider.querySelector('.slider-next');
                var scrollAmount = 110; // ширина изображения + отступ
                prev.addEventListener('click', function() {
                    container.scrollLeft -= scrollAmount;
                });
                next.addEventListener('click', function() {
                    container.scrollLeft += scrollAmount;
                });
            });

            // Lightbox
            var lightbox = document.getElementById('review-lightbox');
            var lightboxImage = document.getElementById('lightbox-image');
            var lightboxClose = document.getElementById('lightbox-close');
            var lightboxPrev = document.getElementById('lightbox-prev');
            var lightboxNext = document.getElementById('lightbox-next');
            var currentImages = [];
            var currentIndex = 0;

            document.querySelectorAll('.review-images-slider img').forEach(function(img) {
                img.addEventListener('click', function() {
                    var slider = this.closest('.review-images-slider');
                    currentImages = Array.from(slider.querySelectorAll('img')).map(function(img) { return img.src; });
                    currentIndex = currentImages.indexOf(this.src);
                    lightboxImage.src = this.src;
                    lightbox.style.display = 'block';
                });
            });

            lightboxClose.addEventListener('click', function() {
                lightbox.style.display = 'none';
            });

            lightboxPrev.addEventListener('click', function() {
                if (currentIndex > 0) {
                    currentIndex--;
                    lightboxImage.src = currentImages[currentIndex];
                }
            });

            lightboxNext.addEventListener('click', function() {
                if (currentIndex < currentImages.length - 1) {
                    currentIndex++;
                    lightboxImage.src = currentImages[currentIndex];
                }
            });

            // Закрытие lightbox при клике вне изображения
            lightbox.addEventListener('click', function(e) {
                if (e.target === lightbox) {
                    lightbox.style.display = 'none';
                }
            });
        });
        </script>
        <?php
    }
}

// Добавляем HTML для lightbox
add_action('wp_footer', 'add_lightbox_html');
function add_lightbox_html() {
    if (is_product()) {
        ?>
        <div id="review-lightbox">
            <div id="lightbox-content">
                <button id="lightbox-prev"><span class="dashicons dashicons-arrow-left-alt2"></span></button>
                <div class="image-container">
                    <img id="lightbox-image" src="" />
                    <span id="lightbox-close">×</span>
                </div>
                <button id="lightbox-next"><span class="dashicons dashicons-arrow-right-alt2"></span></button>
            </div>
        </div>
        <?php
    }
}

// Добавляем мета-бокс в админ-панели для отзывов
add_action('add_meta_boxes_comment', 'add_review_images_meta_box');
function add_review_images_meta_box($comment) {
    if ($comment->comment_type === 'review') {
        add_meta_box('review-images', 'Review Images', 'display_review_images_meta_box', 'comment', 'normal', 'high');
    }
}

function display_review_images_meta_box($comment) {
    $images = get_comment_meta($comment->comment_ID, 'review_images', true);
    if ($images && is_array($images)) {
        echo '<div style="display: flex; flex-wrap: wrap;">';
        foreach ($images as $image) {
            echo '<div style="position: relative; margin: 10px;">';
            echo '<img src="' . esc_url($image) . '" style="max-width:100px;" />';
            echo '<span class="delete-review-image" data-image="' . esc_attr($image) . '" data-comment-id="' . $comment->comment_ID . '" style="position: absolute; top: 0; right: 0; cursor: pointer; color: red; font-size: 20px;">×</span>';
            echo '</div>';
        }
        echo '</div>';
    } else {
        echo 'No images uploaded.';
    }
}

// Добавляем скрипт для удаления изображений в админ-панели
add_action('admin_footer', 'add_review_images_admin_script');
function add_review_images_admin_script() {
    if (get_current_screen()->id === 'comment') {
        ?>
        <script>
        jQuery(document).ready(function($) {
            $(document).on('click', '.delete-review-image', function(e) {
                e.preventDefault();
                var image = $(this).data('image');
                var commentId = $(this).data('comment-id');
                if (confirm('Are you sure you want to delete this image?')) {
                    $.ajax({
                        url: '<?php echo admin_url('admin-ajax.php'); ?>',
                        type: 'POST',
                        data: {
                            action: 'delete_review_image',
                            image: image,
                            comment_id: commentId,
                            nonce: '<?php echo wp_create_nonce('delete_review_image'); ?>'
                        },
                        success: function(response) {
                            if (response.success) {
                                $(this).parent().remove();
                            } else {
                                alert('Failed to delete image.');
                            }
                        }.bind(this)
                    });
                }
            });
        });
        </script>
        <?php
    }
}

// Обрабатываем AJAX-запрос для удаления изображения
add_action('wp_ajax_delete_review_image', 'delete_review_image');
function delete_review_image() {
    check_ajax_referer('delete_review_image', 'nonce');
    $comment_id = intval($_POST['comment_id']);
    $image_to_delete = sanitize_text_field($_POST['image']);
    $images = get_comment_meta($comment_id, 'review_images', true);
    if ($images && is_array($images)) {
        $key = array_search($image_to_delete, $images);
        if ($key !== false) {
            unset($images[$key]);
            update_comment_meta($comment_id, 'review_images', array_values($images));
            $upload_dir = wp_upload_dir();
            $file_path = str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $image_to_delete);
            if (file_exists($file_path)) {
                unlink($file_path);
            }
            wp_send_json_success();
        } else {
            wp_send_json_error();
        }
    } else {
        wp_send_json_error();
    }
}

// Подключаем Dashicons на страницах товаров
add_action('wp_enqueue_scripts', 'enqueue_dashicons_for_reviews');
function enqueue_dashicons_for_reviews() {
    if (is_product()) {
        wp_enqueue_style('dashicons');
    }
}

Как это работает

1. Добавляем поле загрузки изображений

С помощью хука comment_form_field_comment добавляем поле для загрузки файлов в форму отзывов:

add_filter('comment_form_field_comment', 'add_image_upload_to_review_form');
function add_image_upload_to_review_form($field) {
    global $post;
    if ($post->post_type === 'product') {
        $field .= '<p class="comment-form-images"><label for="images"><span class="upload-text">' . __('Добавить фото', 'textdomain') . '</span><span class="file-count-badge">0</span></label><input type="file" id="images" name="images[]" multiple="multiple" accept="image/*" /></p>';
    }
    return $field;
}

2. Настраиваем форму для загрузки файлов

Добавляем атрибут enctype="multipart/form-data" к форме комментариев:

add_action('wp_footer', 'set_comment_form_enctype');
function set_comment_form_enctype() {
    global $post;
    if ($post && $post->post_type === 'product') {
        ?>
        <script>
        document.addEventListener('DOMContentLoaded', function() {
            var form = document.getElementById('commentform');
            if (form) {
                form.setAttribute('enctype', 'multipart/form-data');
            }
        });
        </script>
        <?php
    }
}

3. Обрабатываем загруженные изображения

При сохранении комментария обрабатываем загруженные файлы:

add_action('comment_post', 'handle_review_image_uploads', 10, 2);
function handle_review_image_uploads($comment_id, $comment_approved) {
    if (isset($_FILES['images']) && !empty($_FILES['images']['name'][0])) {
        // Код обработки изображений
        // ...
        update_comment_meta($comment_id, 'review_images', $uploaded_images);
    }
}

4. Отображаем изображения в отзывах

Создаём красивый слайдер для просмотра фотографий отзывов:

add_action('woocommerce_review_before_comment_text', 'display_review_images_slider', 10, 1);
function display_review_images_slider($comment) {
    $images = get_comment_meta($comment->comment_ID, 'review_images', true);
    if ($images && is_array($images)) {
        echo '<div class="review-images-slider">';
        // Код слайдера
        echo '</div>';
    }
}

5. Добавляем Lightbox для полноэкранного просмотра

Реализуем удобный просмотр фотографий в модальном окне:

document.querySelectorAll('.review-images-slider img').forEach(function(img) {
    img.addEventListener('click', function() {
        // Код открытия Lightbox
    });
});

Стилизация элементов

Мы добавили CSS для:

  • Красивой кнопки загрузки файлов
  • Адаптивного слайдера изображений
  • Модального окна (Lightbox)
  • Индикатора количества выбранных файлов
.review-images-slider {
    position: relative;
    margin-bottom: 10px;
    display: flex;
    align-items: center;
}
/* Другие стили... */

Управление изображениями в админке

Для удобства модерации добавлен метабокс в админ-панели с возможностью удаления фотографий:

add_action('add_meta_boxes_comment', 'add_review_images_meta_box');
function add_review_images_meta_box($comment) {
    if ($comment->comment_type === 'review') {
        add_meta_box('review-images', 'Review Images', 'display_review_images_meta_box', 'comment', 'normal', 'high');
    }
}

Мы знаем о чём пишем!

Если у вас возникли вопросы по этой теме, пожалуйста, свяжитесь с нами.

Pin It on Pinterest

Поделиться

Пожалуйста, расскажите о нас друзьям.

Серафинит - АкселераторОптимизировано Серафинит - Акселератор
Включает высокую скорость сайта, чтобы быть привлекательным для людей и поисковых систем.