Как сделать архив и загрузить в него рандом файлы wordpress?
Сайт на woordpress с woocommere
Привет, пока писал маркет по продаже аккаунтов возникла проблема
В кратце:
Есть цифровой товар и у него есть некое количество файлов, при условии, если человек при покупке выбрал один файл, то, он и получает один файл на странице "спасибо" (первый в списке файлов)
но, если он выбирает несколько товаров, то, они должны архивироваться в архив и выводится ссылкой на странице "спасибо"
Проблема в том, что архив постоянно получается пустым и повреждённым :(
У меня не получается нормально создать архив, и закинуть в него рандом файлы
У меня есть код в functions.php и archive-function.php, первый ведёт во второй
нужный кусок из файла functions.php :
include_once('archive-function.php'); add_action('woocommerce_thankyou', 'customize_thank_you_page'); function customize_thank_you_page($order_id) { // Получение текущего заказа $order = wc_get_order($order_id); // Получение списка товаров в заказе $items = $order->get_items(); // Получение общего количества товаров в заказе $total_quantity = 0; // Вычисляем общее количество товаров foreach ($items as $item) { $total_quantity += $item->get_quantity(); } // Выводим информацию о товарах echo '<p>'; if ($total_quantity === 1) { echo 'Спасибо за ваш заказ! Вы можете скачать ваш файл, перейдя по следующей ссылке:'; } else { echo 'Спасибо за ваш заказ! Вы выбрали ' . $total_quantity . ' товаров. '; generate_archive_link($items); // Вызываем функцию для создания ссылки на архив } echo '</p>'; // Выводим количество товаров echo '<p>Количество товаров: ' . $total_quantity . '</p>'; // Получение случайного товара $random_item = reset($items); // Получение товара $product = $random_item->get_product(); // Получение файлов для товара $files = $product->get_files(); // Если есть файлы, создаем ссылку для скачивания if ($files) { $file_data = reset($files); $file_url = esc_url($file_data['file']); $file_name = sanitize_file_name($file_data['name']); // Корректное имя файла if ($total_quantity === 1) { echo '<a id="download-link" href="' . $file_url . '" download="' . $file_name . '">' . $file_name . '</a>'; } // Добавим JavaScript для отслеживания клика и отправки AJAX запроса echo '<script> var countdown; var downloadLink = document.getElementById("download-link"); downloadLink.addEventListener("click", function() { countdown = 10; // Устанавливаем время таймера updateCountdown(); // Отправка AJAX запроса после клика var xhr = new XMLHttpRequest(); xhr.open("POST", "' . admin_url('admin-ajax.php') . '", true); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.send("action=update_downloadable_files&product_id=' . $product->get_id() . '&file_key=' . key($files) . '"); }); function updateCountdown() { if (countdown > 0) { downloadLink.innerHTML = "Файл будет загружен. Перенаправление на главную страницу через " + countdown + " секунд."; countdown--; setTimeout(updateCountdown, 1000); } else { window.location.href = "' . esc_url(home_url('/')) . '"; } } </script>'; } } // AJAX обработчик для обновления списка файлов add_action('wp_ajax_update_downloadable_files', 'update_downloadable_files'); function update_downloadable_files() { if (isset($_POST['product_id']) && isset($_POST['file_key'])) { $product_id = intval($_POST['product_id']); $file_key = sanitize_text_field($_POST['file_key']); // Получаем файлы для товара $product = wc_get_product($product_id); $files = $product->get_files(); // Удаляем скачанный файл из списка unset($files[$file_key]); // Обновляем мета-данные товара update_post_meta($product_id, '_downloadable_files', $files); } wp_die(); } |
include_once('archive-function.php'); add_action('woocommerce_thankyou', 'customize_thank_you_page'); function customize_thank_you_page($order_id) { // Получение текущего заказа $order = wc_get_order($order_id); // Получение списка товаров в заказе $items = $order->get_items(); // Получение общего количества товаров в заказе $total_quantity = 0; // Вычисляем общее количество товаров foreach ($items as $item) { $total_quantity += $item->get_quantity(); } // Выводим информацию о товарах echo '<p>'; if ($total_quantity === 1) { echo 'Спасибо за ваш заказ! Вы можете скачать ваш файл, перейдя по следующей ссылке:'; } else { echo 'Спасибо за ваш заказ! Вы выбрали ' . $total_quantity . ' товаров. '; generate_archive_link($items); // Вызываем функцию для создания ссылки на архив } echo '</p>'; // Выводим количество товаров echo '<p>Количество товаров: ' . $total_quantity . '</p>'; // Получение случайного товара $random_item = reset($items); // Получение товара $product = $random_item->get_product(); // Получение файлов для товара $files = $product->get_files(); // Если есть файлы, создаем ссылку для скачивания if ($files) { $file_data = reset($files); $file_url = esc_url($file_data['file']); $file_name = sanitize_file_name($file_data['name']); // Корректное имя файла if ($total_quantity === 1) { echo '<a id="download-link" href="' . $file_url . '" download="' . $file_name . '">' . $file_name . '</a>'; } // Добавим JavaScript для отслеживания клика и отправки AJAX запроса echo '<script> var countdown; var downloadLink = document.getElementById("download-link"); downloadLink.addEventListener("click", function() { countdown = 10; // Устанавливаем время таймера updateCountdown(); // Отправка AJAX запроса после клика var xhr = new XMLHttpRequest(); xhr.open("POST", "' . admin_url('admin-ajax.php') . '", true); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.send("action=update_downloadable_files&product_id=' . $product->get_id() . '&file_key=' . key($files) . '"); }); function updateCountdown() { if (countdown > 0) { downloadLink.innerHTML = "Файл будет загружен. Перенаправление на главную страницу через " + countdown + " секунд."; countdown--; setTimeout(updateCountdown, 1000); } else { window.location.href = "' . esc_url(home_url('/')) . '"; } } </script>'; } } // AJAX обработчик для обновления списка файлов add_action('wp_ajax_update_downloadable_files', 'update_downloadable_files'); function update_downloadable_files() { if (isset($_POST['product_id']) && isset($_POST['file_key'])) { $product_id = intval($_POST['product_id']); $file_key = sanitize_text_field($_POST['file_key']); // Получаем файлы для товара $product = wc_get_product($product_id); $files = $product->get_files(); // Удаляем скачанный файл из списка unset($files[$file_key]); // Обновляем мета-данные товара update_post_meta($product_id, '_downloadable_files', $files); } wp_die(); }
Код из файла archive-function.php:
<?php // Функция для создания ссылки на архив function generate_archive_link($items) { // Получение случайного товара $random_item = reset($items); // Получение товара $product = $random_item->get_product(); // Получение файлов для товара $files = $product->get_files(); // Если есть файлы, создаем ссылку на архив if ($files && count($files) > 1) { $archive_url = admin_url('admin-ajax.php?action=generate_download_archive&product_id=' . $product->get_id()); echo '<p>Для удобства, вы можете <a href="' . esc_url($archive_url) . '">скачать все файлы в одном архиве</a>.</p>'; } } // AJAX обработчик для создания архива add_action('wp_ajax_generate_download_archive', 'generate_download_archive'); function generate_download_archive() { if (isset($_GET['product_id'])) { $product_id = intval($_GET['product_id']); $product = wc_get_product($product_id); $files = $product->get_files(); if ($files) { $zip = new ZipArchive(); $zip_filename = 'download_archive_' . $product_id . '.zip'; if ($zip->open($zip_filename, ZipArchive::CREATE)) { foreach ($files as $file_key => $file_data) { $file_url = WP_CONTENT_DIR . '/uploads/' . $file_data['file']; $zip->addFile($file_url, $file_data['name']); } $zip->close(); header('Content-Type: application/zip'); header('Content-Disposition: attachment; filename=' . $zip_filename); header('Content-Length: ' . filesize($zip_filename)); readfile($zip_filename); // Удаляем архив после отправки unlink($zip_filename); exit(); } } } wp_die(); } ?> |
<?php // Функция для создания ссылки на архив function generate_archive_link($items) { // Получение случайного товара $random_item = reset($items); // Получение товара $product = $random_item->get_product(); // Получение файлов для товара $files = $product->get_files(); // Если есть файлы, создаем ссылку на архив if ($files && count($files) > 1) { $archive_url = admin_url('admin-ajax.php?action=generate_download_archive&product_id=' . $product->get_id()); echo '<p>Для удобства, вы можете <a href="' . esc_url($archive_url) . '">скачать все файлы в одном архиве</a>.</p>'; } } // AJAX обработчик для создания архива add_action('wp_ajax_generate_download_archive', 'generate_download_archive'); function generate_download_archive() { if (isset($_GET['product_id'])) { $product_id = intval($_GET['product_id']); $product = wc_get_product($product_id); $files = $product->get_files(); if ($files) { $zip = new ZipArchive(); $zip_filename = 'download_archive_' . $product_id . '.zip'; if ($zip->open($zip_filename, ZipArchive::CREATE)) { foreach ($files as $file_key => $file_data) { $file_url = WP_CONTENT_DIR . '/uploads/' . $file_data['file']; $zip->addFile($file_url, $file_data['name']); } $zip->close(); header('Content-Type: application/zip'); header('Content-Disposition: attachment; filename=' . $zip_filename); header('Content-Length: ' . filesize($zip_filename)); readfile($zip_filename); // Удаляем архив после отправки unlink($zip_filename); exit(); } } } wp_die(); } ?>
Помогите пожалуйста
Вот сайт на котором я это и делаю: https://atq-store.com/
Нажимайте на сам товар, а не на кнопку купить
Дополнительно:
Для начала оформите код через кнопку на форме </>
Включите вывод ошибок, может у вас zip расширение не стоит или ещё чего
Для отладки закоментируйте эти строки
header('Content-Type: application/zip'); header('Content-Disposition: attachment; filename=' . $zip_filename); header('Content-Length: ' . filesize($zip_filename)); readfile($zip_filename); // Удаляем архив после отправки unlink($zip_filename); exit(); |
header('Content-Type: application/zip'); header('Content-Disposition: attachment; filename=' . $zip_filename); header('Content-Length: ' . filesize($zip_filename)); readfile($zip_filename); // Удаляем архив после отправки unlink($zip_filename); exit();
Посмотрите архив. Если он весит мало, откройте его как текстовый и почитайте текст ошибки
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
Пустой или повреждённый ZIP в WooCommerce чаще всего получается из-за неправильных путей к файлам, создания архива до того, как файлы реально найдены, отсутствия прав на запись или вывода лишнего HTML/пробелов в поток скачивания. Для цифровых товаров лучше сначала собрать реальные абсолютные пути к файлам, проверить их через
file_exists(), а уже потом добавлять вZipArchive.Базовая схема:
$upload = wp_upload_dir(); $zip_dir = trailingslashit($upload['basedir']) . 'order-zips/'; wp_mkdir_p($zip_dir); $zip_path = $zip_dir . 'order-' . absint($order_id) . '.zip'; $zip = new ZipArchive(); if ($zip->open($zip_path, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) { return; } foreach ($files as $file_path) { if (!file_exists($file_path)) { continue; } $zip->addFile($file_path, basename($file_path)); } $zip->close();
После
close()проверьте размер:if (!file_exists($zip_path) || filesize($zip_path) === 0) { // логировать ошибку }
Не используйте URL файла там, где нужен путь на диске.
ZipArchive::addFile()принимает именно локальный путь вроде/home/site/public_html/wp-content/uploads/file.txt, а неhttps://site.ru/wp-content/uploads/file.txt.Если архив создаётся на странице “Спасибо”, не выводите его напрямую в этот же момент. Лучше создать ZIP, сохранить его во временную папку uploads и вывести ссылку. Для безопасности ссылку нужно ограничить: проверять order key, пользователя или использовать signed URL.
Итог: проверьте абсолютные пути, права на папку, результат
$zip->open(), количество добавленных файлов и размер архива после закрытия. Почти всегда ошибка находится именно там.