Отзывы с фотографиями — эффективный способ повысить доверие посетителей к вашему сайту. В этой статье мы подробно разберём, как создать функционал отзывов с прикреплением фотографий в WordPress, используя кастомные типы записей, метаполя и AJAX-загрузку изображений. Такой подход позволит пользователям удобно оставлять отзывы, а вам — управлять ими из админки.
Создание кастомного типа записи «Отзывы»
Для начала создадим собственный тип записи, чтобы отзывы были отделены от обычных постов и страниц. Это удобно для организации и вывода на сайте.
function wpvip_register_reviews_cpt() {
$labels = [
'name' => 'Отзывы',
'singular_name' => 'Отзыв',
'add_new' => 'Добавить отзыв',
'add_new_item' => 'Добавить новый отзыв',
'edit_item' => 'Редактировать отзыв',
'new_item' => 'Новый отзыв',
'all_items' => 'Все отзывы',
'view_item' => 'Просмотреть отзыв',
'search_items' => 'Поиск отзывов',
'not_found' => 'Отзывы не найдены',
'not_found_in_trash' => 'В корзине отзывов не найдено',
'menu_name' => 'Отзывы'
];
$args = [
'labels' => $labels,
'public' => true,
'has_archive' => true,
'menu_icon' => 'dashicons-testimonial',
'supports' => ['title', 'editor', 'thumbnail'],
'show_in_rest' => true,
];
register_post_type('wpvip_review', $args);
}
add_action('init', 'wpvip_register_reviews_cpt');
Этот код добавит тип записи wpvip_review с поддержкой заголовка, контента и миниатюры (фотографии). Для отзывов миниатюра — это одна из фотографий пользователя.
Добавление пользовательских полей для загрузки нескольких фотографий
Чтобы пользователь мог добавить несколько фотографий к отзыву, создадим метаполе для хранения ID загруженных изображений. Используем для этого REST API и AJAX-загрузку, чтобы не перегружать интерфейс.
Регистрация метаполя с REST API поддержкой
function wpvip_register_review_images_meta() {
register_post_meta('wpvip_review', 'wpvip_review_images', [
'type' => 'array',
'description' => 'Фотографии отзывов',
'single' => true,
'show_in_rest' => true,
'default' => []
]);
}
add_action('init', 'wpvip_register_review_images_meta');
Теперь поле wpvip_review_images доступно через REST API и хранит массив ID вложений.
AJAX обработчик загрузки изображений
Создадим AJAX-обработчик, который позволит загружать фотографии из формы отзыва без перезагрузки страницы.
function wpvip_ajax_upload_review_image() {
if (!current_user_can('upload_files')) {
wp_send_json_error('Нет прав для загрузки файлов.');
}
if (empty($_FILES['review_image'])) {
wp_send_json_error('Файл не передан.');
}
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/media.php';
require_once ABSPATH . 'wp-admin/includes/image.php';
$file = $_FILES['review_image'];
$attachment_id = media_handle_upload('review_image', 0);
if (is_wp_error($attachment_id)) {
wp_send_json_error($attachment_id->get_error_message());
}
$image_url = wp_get_attachment_url($attachment_id);
wp_send_json_success(['attachment_id' => $attachment_id, 'url' => $image_url]);
}
add_action('wp_ajax_wpvip_upload_review_image', 'wpvip_ajax_upload_review_image');
add_action('wp_ajax_nopriv_wpvip_upload_review_image', 'wpvip_ajax_upload_review_image');
Этот код обрабатывает файл из формы по ключу review_image, загружает его в медиа-библиотеку и возвращает ID и URL файла.
Создание формы для добавления отзыва с фотографиями на фронтенде
Теперь соберём форму, позволяющую пользователю оставить отзыв с несколькими фотографиями. Для удобства загрузку реализуем через JavaScript.
HTML и JavaScript формы
<form id="wpvip-review-form" enctype="multipart/form-data">
<label>Ваше имя:</label>
<input type="text" name="reviewer_name" required />
<label>Отзыв:</label>
<textarea name="review_text" required></textarea>
<label>Фотографии:</label>
<input type="file" id="wpvip-review-images" multiple accept="image/*" />
<div id="wpvip-uploaded-images"></div>
<button type="submit">Отправить отзыв</button>
</form>
<script>
const form = document.getElementById('wpvip-review-form');
const imagesInput = document.getElementById('wpvip-review-images');
const uploadedImagesContainer = document.getElementById('wpvip-uploaded-images');
let uploadedImageIDs = [];
imagesInput.addEventListener('change', () => {
const files = imagesInput.files;
for (let i = 0; i < files.length; i++) {
const file = files[i];
const formData = new FormData();
formData.append('action', 'wpvip_upload_review_image');
formData.append('review_image', file);
formData.append('_wpnonce', wpvip_ajax_obj.nonce);
fetch(wpvip_ajax_obj.ajax_url, {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if(data.success) {
uploadedImageIDs.push(data.data.attachment_id);
const img = document.createElement('img');
img.src = data.data.url;
img.style.maxWidth = '100px';
img.style.marginRight = '10px';
uploadedImagesContainer.appendChild(img);
} else {
alert('Ошибка загрузки: ' + data.data);
}
})
.catch(() => alert('Ошибка загрузки изображения'));
}
imagesInput.value = '';
});
form.addEventListener('submit', (e) => {
e.preventDefault();
const name = form.reviewer_name.value.trim();
const text = form.review_text.value.trim();
if (!name || !text) {
alert('Заполните все обязательные поля');
return;
}
const postData = {
action: 'wpvip_submit_review',
reviewer_name: name,
review_text: text,
images: uploadedImageIDs,
_wpnonce: wpvip_ajax_obj.nonce
};
fetch(wpvip_ajax_obj.ajax_url, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(postData)
})
.then(response => response.json())
.then(data => {
if(data.success) {
alert('Спасибо за отзыв!');
form.reset();
uploadedImagesContainer.innerHTML = '';
uploadedImageIDs = [];
} else {
alert('Ошибка при добавлении отзыва: ' + data.data);
}
})
.catch(() => alert('Ошибка отправки отзыва'));
});
</script>
Для работы скрипта нужно локализовать переменную wpvip_ajax_obj с параметрами AJAX в вашем шаблоне или плагине.
Обработка отправки отзыва на сервере и сохранение данных
Теперь добавим обработчик AJAX, который примет данные формы, создаст новый отзыв и сохранит ID фотографий в метаполе.
function wpvip_ajax_submit_review() {
check_ajax_referer('wpvip_nonce', '_wpnonce');
$name = sanitize_text_field($_POST['reviewer_name'] ?? '');
$text = sanitize_textarea_field($_POST['review_text'] ?? '');
$images = isset($_POST['images']) && is_array($_POST['images']) ? array_map('intval', $_POST['images']) : [];
if (empty($name) || empty($text)) {
wp_send_json_error('Заполните все обязательные поля');
}
$post_id = wp_insert_post([
'post_type' => 'wpvip_review',
'post_title' => $name,
'post_content'=> $text,
'post_status' => 'pending'
]);
if (is_wp_error($post_id) || !$post_id) {
wp_send_json_error('Ошибка при сохранении отзыва');
}
update_post_meta($post_id, 'wpvip_review_images', $images);
// Если есть изображения, укажем первую как миниатюру
if (!empty($images)) {
set_post_thumbnail($post_id, $images[0]);
}
wp_send_json_success('Отзыв успешно добавлен');
}
add_action('wp_ajax_wpvip_submit_review', 'wpvip_ajax_submit_review');
add_action('wp_ajax_nopriv_wpvip_submit_review', 'wpvip_ajax_submit_review');
Вывод отзывов с фотографиями на сайте
Чтобы показать отзывы с фотографиями, создадим WP_Query и выведем отзывы с миниатюрой и содержимым.
$args = [
'post_type' => 'wpvip_review',
'post_status' => 'publish',
'posts_per_page' => 10
];
$reviews = new WP_Query($args);
if ($reviews->have_posts()) {
echo '<div class="wpvip-reviews">';
while ($reviews->have_posts()) {
$reviews->the_post();
$images = get_post_meta(get_the_ID(), 'wpvip_review_images', true);
echo '<div class="wpvip-review-item">';
if (has_post_thumbnail()) {
echo get_the_post_thumbnail(null, 'thumbnail');
}
echo '<h3>' . get_the_title() . '</h3>';
echo '<div class="wpvip-review-content">' . get_the_content() . '</div>';
if (!empty($images) && is_array($images)) {
echo '<div class="wpvip-review-images">';
foreach ($images as $img_id) {
echo wp_get_attachment_image($img_id, 'medium');
}
echo '</div>';
}
echo '</div>';
}
echo '</div>';
wp_reset_postdata();
} else {
echo 'Отзывы не найдены';
}
Рекомендации по безопасности и оптимизации
Важно проверять права доступа при загрузке файлов, использовать nonce для AJAX-запросов и фильтровать входящие данные. Для ускорения загрузки изображений применяйте lazy loading и оптимизацию изображений через плагины.
Полезные плагины для отзывов с фото
- Expert Review — мощный плагин для создания отзывов с оценками и фото.
- My Popup — позволяет показывать отзывы в всплывающих окнах.
- Clearfy Pro — оптимизация и безопасность, чтобы отзывы загружались быстро и без сбоев.
Используя описанный подход, вы сможете создать удобный и функциональный раздел отзывов с поддержкой фотографий, который повысит доверие пользователей и улучшит конверсию сайта.