WordPress. Загрузка файлов. Часть 3 из 3
Хорошо, теперь мы умеем загружать файлы как в панели управления, так и в публичной части. Но делаем это с перезагрузкой страницы, что выглядит совсем уж архаично. Давайте доработаем наш плагин так, чтобы он умел отправлять файлы с использованием объекта XmlHttpRequest. Изменения будут небольшие — нам надо подключить к странице js-файл, который будет отправлять ajax-запросы. И подправить php-код в файле плагина, который отвечает за загрузку файлов.
Загрузка файлов в публичной части (AJAX)
Простая загрузка одного файла
Итак, создаем в директории плагина файл script.php
и добавляем в него следующий код:
jQuery(document).ready(function($) { // скрываем блок, где будут результаты, чтобы потом красиво показать $('.tokmakov-upload-file .response').hide(); /* * Подписываемся на событие submit, отменяем обычную отправку формы */ $('.tokmakov-upload-file form').on('submit', function(e) { e.preventDefault(); var $form = $(this); $response = $form.siblings('.response'); // передаем форму не объектом jQuery, а как DOM-элемент var data = new FormData($form[0]); $.ajax({ url: tokmakov_upload_file.handler, type: $form.attr('method'), contentType: false, // убираем форматирование данных по умолчанию processData: false, // убираем преобразование строк по умолчанию data: data, dataType: 'text', success: function(response) { $('<p>').appendTo($response).text(response); $response .slideDown(500) .delay(2000) .slideUp(500, function () { $(this).empty(); }); $form.children('input[type="file"]').val(''); } }); }); });
Вносим изменения в файл tokmakov-upload-file.php
. Обработать POST-данные мы можем при наступлении следующих событий:
admin_post_tokmakov_upload_file
— когда происходит обычная отправка данных формыwp_ajax_tokmakov_upload_file
— когда данные отправляются с использованием AJAX
И в первом и во втором случае обрабатывать POST-данные будет функция tokmakov_upload_file()
. Просто внутри функции мы будем проверять — это обычный POST-запрос или это AJAX-запрос?
<?php /* * Plugin name: Загрузка файлов * Description: Пример загрузки файлов в публичной части */ register_activation_hook(__FILE__, function() { // проверяем права пользователя на активацию плагинов if (!current_user_can('activate_plugins')) { return; } // для загрузки файлов из публичной части у всех // пользователей должны быть права на это $subscriber = get_role('subscriber'); if (!$subscriber->has_cap('upload_files')) { $subscriber->add_cap('upload_files'); } }); register_deactivation_hook(__FILE__, function() { // проверяем права пользователя на деактивацию плагинов if (!current_user_can('deactivate_plugins')) { return; } // удаляем права на загрузку файлов, которую // предоставили на этапе активации плагина $subscriber = get_role('subscriber'); if ($subscriber->has_cap('upload_files')) { $subscriber->remove_cap('upload_files'); } }); /* * Загрузка файлов при использовании XmlHttpRequest (AJAX) */ if (wp_doing_ajax()) { add_action('wp_ajax_tokmakov_upload_file', 'tokmakov_upload_file'); // когда пришел ajax-запрос на загрузку файлов, больше ничего // делать не надо, так что прерываем работу плагина и выходим return; } /* * Регистрируем шорткод [tokmakov-upload-file], который позволит * вставить форму загрузки файлов на страницу или запись блога */ add_shortcode('tokmakov-upload-file', function () { if (!is_user_logged_in()) { return ''; } ob_start(); ?> <div class="tokmakov-upload-file"> <div class="response"> <?php if (isset($_SESSION['tokmakov_upload_file'])): ?> <p><?= $_SESSION['tokmakov_upload_file']; ?></p> <?php unset($_SESSION['tokmakov_upload_file']); ?> <?php endif; ?> </div> <form action="<?= admin_url('admin-post.php'); ?>" method="post" enctype="multipart/form-data"> <?php wp_nonce_field('tokmakov_upload_file'); ?> <input type="hidden" name="action" value="tokmakov_upload_file" /> <input type="hidden" name="redirect" value="<?= get_permalink(); ?>" /> <input type="file" name="tokmakov_upload_file" required /> <input type="submit" value="Загрузить файл" /> </form> </div> <?php return ob_get_clean(); }); /* * Подключаем js и css файлы, необходимые для работы плагина */ add_action('wp_enqueue_scripts', function () { if (is_user_logged_in()) { wp_enqueue_script( 'tokmakov-upload-file-js', plugin_dir_url(__FILE__) . 'script.js', ['jquery'], null, true ); // определяем глобальную js-переменную, которая будет // содержать URL, куда отправлять ajax-запросы wp_localize_script( 'tokmakov-upload-file-js', 'tokmakov_upload_file', ['handler' => admin_url('admin-ajax.php')] ); wp_enqueue_style( 'tokmakov-upload-file-css', plugin_dir_url(__FILE__) . 'style.css' ); } }); /* * Запускаем сессию, чтобы передавать сообщение о результате * обработки файла после перезагрузки страницы */ add_action('init', function () { if (session_id() == '') { session_start(); } }); /* * Обрабатываем данные формы, загружаем файл(ы). Сообщение о результате * записываем в сесиию, чтобы показать пользователю на странице с формой. */ add_action('admin_post_tokmakov_upload_file', 'tokmakov_upload_file'); /* * Функция загружает файлы в директорию wp-content/uploads */ function tokmakov_upload_file() { // подключаем файл с функцией wp_handle_upload() require_once ABSPATH . 'wp-admin/includes/file.php'; // проверяем защиту nonce и права пользователя $check1 = wp_verify_nonce( $_POST['_wpnonce'], 'tokmakov_upload_file' ); $check2 = current_user_can('upload_files'); if ($check1 && $check2) { // проверка пройдена, можно загружать файл $overrides = ['test_form' => false]; $result = wp_handle_upload( $_FILES['tokmakov_upload_file'], $overrides ); // показываем результаты загрузки файла if (isset($result['error'])) { $message = 'Ошибка при загрузке файла'; } else { $message = 'Файл был успешно загружен'; } } else { $message = 'Проверка не пройдена, файл не загружен'; } if (!wp_doing_ajax()) { $_SESSION['tokmakov_upload_file'] = $message; // после отправки формы делаем редирект, чтобы предотвратить // повторную отправку, если пользователь обновит страницу $redirect = home_url(); if (isset($_POST['redirect'])) { $redirect = $_POST['redirect']; $redirect = wp_validate_redirect($redirect, home_url()); } wp_redirect($redirect); } else { echo $message; } die(); }
Загрузка одного вложения (attachment)
Мы уже знаем, что для загрузки вложения нужно использовать функцию media_handle_upload()
. И умеем отправлять данные формы с использованием объекта XmlHttpRequest. Наш js-код остается без изменений, а в php-код вносим небольшие изменения.
jQuery(document).ready(function($) { // скрываем блок, где будут результаты, чтобы потом красиво показать $('.tokmakov-upload-file .response').hide(); /* * Подписываемся на событие submit, отменяем обычную отправку формы */ $('.tokmakov-upload-file form').on('submit', function(e) { e.preventDefault(); var $form = $(this); $response = $form.siblings('.response'); // передаем форму не объектом jQuery, а как DOM-элемент var data = new FormData($form[0]); $.ajax({ url: tokmakov_upload_file.handler, type: $form.attr('method'), contentType: false, // убираем форматирование данных по умолчанию processData: false, // убираем преобразование строк по умолчанию data: data, dataType: 'text', success: function(response) { $('<p>').appendTo($response).text(response); $response .slideDown(500) .delay(2000) .slideUp(500, function () { $(this).empty(); }); $form.children('input[type="file"]').val(''); } }); }); });
<?php /* * Plugin name: Загрузка файлов * Description: Пример загрузки файлов в публичной части */ register_activation_hook(__FILE__, function() { /*...*/ }); register_deactivation_hook(__FILE__, function() { /*...*/ }); /* * Загрузка файлов при использовании XmlHttpRequest (AJAX) */ if (wp_doing_ajax()) { add_action('wp_ajax_tokmakov_upload_file', 'tokmakov_upload_file'); // когда пришел ajax-запрос на загрузку файлов, больше ничего // делать не надо, так что прерываем работу плагина и выходим return; } /* * Регистрируем шорткод [tokmakov-upload-file], который позволит * вставить форму загрузки файлов на страницу или запись блога */ add_shortcode('tokmakov-upload-file', function () { if (!is_user_logged_in()) { return ''; } ob_start(); ?> <div class="tokmakov-upload-file"> <div class="response"> <?php if (isset($_SESSION['tokmakov_upload_file'])): ?> <p><?= $_SESSION['tokmakov_upload_file']; ?></p> <?php unset($_SESSION['tokmakov_upload_file']); ?> <?php endif; ?> </div> <form action="<?= admin_url('admin-post.php'); ?>" method="post" enctype="multipart/form-data"> <?php wp_nonce_field('tokmakov_upload_file'); ?> <input type="hidden" name="action" value="tokmakov_upload_file" /> <input type="hidden" name="redirect" value="<?= get_permalink(); ?>" /> <input type="file" name="tokmakov_upload_file" required /> <input type="submit" value="Загрузить файл" /> </form> </div> <?php return ob_get_clean(); }); /* * Подключаем js и css файлы, необходимые для работы плагина */ add_action('wp_enqueue_scripts', function () { if (is_user_logged_in()) { wp_enqueue_script( 'tokmakov-upload-file-js', plugin_dir_url(__FILE__) . 'script.js', ['jquery'], null, true ); // определяем глобальную js-переменную, которая будет // содержать URL, куда отправлять ajax-запросы wp_localize_script( 'tokmakov-upload-file-js', 'tokmakov_upload_file', ['handler' => admin_url('admin-ajax.php')] ); wp_enqueue_style( 'tokmakov-upload-file-css', plugin_dir_url(__FILE__) . 'style.css' ); } }); /* * Запускаем сессию, чтобы передавать сообщение о результате * обработки файла после перезагрузки страницы */ add_action('init', function () { if (session_id() == '') { session_start(); } }); /* * Обрабатываем данные формы, загружаем файл(ы). Сообщение о результате * записываем в сесиию, чтобы показать пользователю на странице с формой. */ add_action('admin_post_tokmakov_upload_file', 'tokmakov_upload_file'); /* * Функция загружает файлы в директорию wp-content/uploads */ function tokmakov_upload_file() { // подключаем все файлы, которые нужны для загрузки require_once ABSPATH . 'wp-admin/includes/image.php'; require_once ABSPATH . 'wp-admin/includes/file.php'; require_once ABSPATH . 'wp-admin/includes/media.php'; // проверяем защиту nonce и права пользователя $check1 = wp_verify_nonce( $_POST['_wpnonce'], 'tokmakov_upload_file' ); $check2 = current_user_can('upload_files'); if ($check1 && $check2) { // проверка пройдена, можно загружать файл $result = media_handle_upload('tokmakov_upload_file', 0); if (is_wp_error($result)) { $message = 'Ошибка при загрузке файла'; } else { $message = 'Файл был успешно загружен'; } } else { $message = 'Проверка не пройдена, файл не загружен'; } if (!wp_doing_ajax()) { $_SESSION['tokmakov_upload_file'] = $message; // после отправки формы делаем редирект, чтобы предотвратить // повторную отправку, если пользователь обновит страницу $redirect = home_url(); if (isset($_POST['redirect'])) { $redirect = $_POST['redirect']; $redirect = wp_validate_redirect($redirect, home_url()); } wp_redirect($redirect); } else { echo $message; } die(); }
Простая загрузка нескольких файлов
Для загрузки используем функцию wp_handle_upload()
, «скармливая» ей файлы по одному. Ответ сервера будет содержать массив результатов, который мы преобразуем в json-формат с помощью функции wp_send_json()
. На стороне клиента из этого массива создадим список и покажем пользователю.
jQuery(document).ready(function($) { // скрываем блок, где будут результаты, чтобы потом красиво показать $('.tokmakov-upload-file .response').hide(); /* * Подписываемся на событие submit, отменяем обычную отправку формы */ $('.tokmakov-upload-file form').on('submit', function(e) { e.preventDefault(); var $form = $(this); var $response = $form.siblings('.response'); // передаем форму не объектом jQuery, а как DOM-элемент var data = new FormData($form[0]); $.ajax({ url: tokmakov_upload_file.handler, type: $form.attr('method'), contentType: false, // убираем форматирование данных по умолчанию processData: false, // убираем преобразование строк по умолчанию data: data, dataType: 'json', success: function(response) { var messages = $('<ul>').appendTo($response); response.forEach(function(item) { $('<li>').text(item).appendTo(messages); }); $response .slideDown(500) .delay(2000) .slideUp(500, function () { $(this).empty(); }); $form.children('input[type="file"]').val(''); } }); }); });
<?php /* * Plugin name: Загрузка файлов * Description: Пример загрузки файлов в публичной части */ register_activation_hook(__FILE__, function() { /*...*/ }); register_deactivation_hook(__FILE__, function() { /*...*/ }); /* * Загрузка файлов при использовании XmlHttpRequest (AJAX) */ if (wp_doing_ajax()) { add_action('wp_ajax_tokmakov_upload_file', 'tokmakov_upload_file'); // когда пришел ajax-запрос на загрузку файлов, больше ничего // делать не надо, так что прерываем работу плагина и выходим return; } /* * Регистрируем шорткод [tokmakov-upload-file], который позволит * вставить форму загрузки файлов на страницу или запись блога */ add_shortcode('tokmakov-upload-file', function () { if (!is_user_logged_in()) { return ''; } ob_start(); ?> <div class="tokmakov-upload-file"> <div class="response"> <?php if (isset($_SESSION['tokmakov_upload_file'])): ?> <ul> <?php foreach ($_SESSION['tokmakov_upload_file'] as $message): ?> <li><?= $message; ?></li> <?php endforeach; ?> </ul> <?php unset($_SESSION['tokmakov_upload_file']); ?> <?php endif; ?> </div> <form action="<?= admin_url('admin-post.php'); ?>" method="post" enctype="multipart/form-data"> <?php wp_nonce_field('tokmakov_upload_file'); ?> <input type="hidden" name="action" value="tokmakov_upload_file" /> <input type="hidden" name="redirect" value="<?= get_permalink(); ?>" /> <input type="file" name="tokmakov_upload_file[]" required multiple /> <input type="submit" value="Загрузить файл" /> </form> </div> <?php return ob_get_clean(); }); /* * Подключаем js и css файлы, необходимые для работы плагина */ add_action('wp_enqueue_scripts', function () { if (is_user_logged_in()) { wp_enqueue_script( 'tokmakov-upload-file-js', plugin_dir_url(__FILE__) . 'script.js', ['jquery'], null, true ); // определяем глобальную js-переменную, которая будет // содержать URL, куда отправлять ajax-запросы wp_localize_script( 'tokmakov-upload-file-js', 'tokmakov_upload_file', ['handler' => admin_url('admin-ajax.php')] ); wp_enqueue_style( 'tokmakov-upload-file-css', plugin_dir_url(__FILE__) . 'style.css' ); } }); /* * Запускаем сессию, чтобы передавать сообщение о результате * обработки файла после перезагрузки страницы */ add_action('init', function () { if (session_id() == '') { session_start(); } }); /* * Обрабатываем данные формы, загружаем файл(ы). Сообщение о результате * записываем в сесиию, чтобы показать пользователю на странице с формой. */ add_action('admin_post_tokmakov_upload_file', 'tokmakov_upload_file'); /* * Функция загружает файлы в директорию wp-content/uploads */ function tokmakov_upload_file() { // подключаем файл с функцией wp_handle_upload() require_once ABSPATH . 'wp-admin/includes/file.php'; // проверяем защиту nonce и права пользователя $check1 = wp_verify_nonce( $_POST['_wpnonce'], 'tokmakov_upload_file' ); $check2 = current_user_can('upload_files'); if ($check1 && $check2) { // проверка пройдена, можно загружать файлы $messages = []; // перебираем все файлы в цикле и загружаем по одному $overrides = ['test_form' => false]; foreach ($_FILES['tokmakov_upload_file']['name'] as $i => $v) { $file = [ 'name' => $_FILES['tokmakov_upload_file']['name'][$i], 'type' => $_FILES['tokmakov_upload_file']['type'][$i], 'tmp_name' => $_FILES['tokmakov_upload_file']['tmp_name'][$i], 'error' => $_FILES['tokmakov_upload_file']['error'][$i], 'size' => $_FILES['tokmakov_upload_file']['size'][$i], ]; // загружаем очередной файл в директорию uploads $result = wp_handle_upload($file, $overrides); if (isset($result['error'])) { $messages[] = 'Ошибка при загрузке файла ' . $file['name']; } else { $messages[] = 'Файл ' . $file['name'] . ' успешно загружен'; } } } else { $messages[] = 'Проверка не пройдена, файл не загружен'; } if (!wp_doing_ajax()) { $_SESSION['tokmakov_upload_file'] = $messages; // после отправки формы делаем редирект, чтобы предотвратить // повторную отправку, если пользователь обновит страницу $redirect = home_url(); if (isset($_POST['redirect'])) { $redirect = $_POST['redirect']; $redirect = wp_validate_redirect($redirect, home_url()); } wp_redirect($redirect); die(); } else { wp_send_json($messages); } }
Загрузка нескольких вложений (attachments)
Здесь объяснять нечего, мы проделываем это уже много раз. Так что только js и php код для полноты картины.
jQuery(document).ready(function($) { // скрываем блок, где будут результаты, чтобы потом красиво показать $('.tokmakov-upload-file .response').hide(); /* * Подписываемся на событие submit, отменяем обычную отправку формы */ $('.tokmakov-upload-file form').on('submit', function(e) { e.preventDefault(); var $form = $(this); var $response = $form.siblings('.response'); // передаем форму не объектом jQuery, а как DOM-элемент var data = new FormData($form[0]); $.ajax({ url: tokmakov_upload_file.handler, type: $form.attr('method'), contentType: false, // убираем форматирование данных по умолчанию processData: false, // убираем преобразование строк по умолчанию data: data, dataType: 'json', success: function(response) { var messages = $('<ul>').appendTo($response); response.forEach(function(item) { $('<li>').text(item).appendTo(messages); }); $response .slideDown(500) .delay(2000) .slideUp(500, function () { $(this).empty(); }); $form.children('input[type="file"]').val(''); } }); }); });
<?php /* * Plugin name: Загрузка файлов * Description: Пример загрузки файлов в публичной части */ register_activation_hook(__FILE__, function() { /*...*/ }); register_deactivation_hook(__FILE__, function() { /*...*/ }); /* * Загрузка файлов при использовании XmlHttpRequest (AJAX) */ if (wp_doing_ajax()) { add_action('wp_ajax_tokmakov_upload_file', 'tokmakov_upload_file'); // когда пришел ajax-запрос на загрузку файлов, больше ничего // делать не надо, так что прерываем работу плагина и выходим return; } /* * Регистрируем шорткод [tokmakov-upload-file], который позволит * вставить форму загрузки файлов на страницу или запись блога */ add_shortcode('tokmakov-upload-file', function () { if (!is_user_logged_in()) { return ''; } ob_start(); ?> <div class="tokmakov-upload-file"> <div class="response"> <?php if (isset($_SESSION['tokmakov_upload_file'])): ?> <ul> <?php foreach ($_SESSION['tokmakov_upload_file'] as $message): ?> <li><?= $message; ?></li> <?php endforeach; ?> </ul> <?php unset($_SESSION['tokmakov_upload_file']); ?> <?php endif; ?> </div> <form action="<?= admin_url('admin-post.php'); ?>" method="post" enctype="multipart/form-data"> <?php wp_nonce_field('tokmakov_upload_file'); ?> <input type="hidden" name="action" value="tokmakov_upload_file" /> <input type="hidden" name="redirect" value="<?= get_permalink(); ?>" /> <input type="file" name="tokmakov_upload_file[]" required multiple /> <input type="submit" value="Загрузить файл" /> </form> </div> <?php return ob_get_clean(); }); /* * Подключаем js и css файлы, необходимые для работы плагина */ add_action('wp_enqueue_scripts', function () { if (is_user_logged_in()) { wp_enqueue_script( 'tokmakov-upload-file-js', plugin_dir_url(__FILE__) . 'script.js', ['jquery'], null, true ); // определяем глобальную js-переменную, которая будет // содержать URL, куда отправлять ajax-запросы wp_localize_script( 'tokmakov-upload-file-js', 'tokmakov_upload_file', ['handler' => admin_url('admin-ajax.php')] ); wp_enqueue_style( 'tokmakov-upload-file-css', plugin_dir_url(__FILE__) . 'style.css' ); } }); /* * Запускаем сессию, чтобы передавать сообщение о результате * обработки файла после перезагрузки страницы */ add_action('init', function () { if (session_id() == '') { session_start(); } }); /* * Обрабатываем данные формы, загружаем файл(ы). Сообщение о результате * записываем в сесиию, чтобы показать пользователю на странице с формой. */ add_action('admin_post_tokmakov_upload_file', 'tokmakov_upload_file'); /* * Функция загружает файлы в директорию wp-content/uploads */ function tokmakov_upload_file() { // подключаем все файлы, которые нужны для загрузки require_once ABSPATH . 'wp-admin/includes/image.php'; require_once ABSPATH . 'wp-admin/includes/file.php'; require_once ABSPATH . 'wp-admin/includes/media.php'; // проверяем защиту nonce и права пользователя $check1 = wp_verify_nonce( $_POST['_wpnonce'], 'tokmakov_upload_file' ); $check2 = current_user_can('upload_files'); if ($check1 && $check2) { // проверка пройдена, можно загружать файлы $messages = []; // перебираем все файлы в цикле и загружаем по одному foreach ($_FILES['tokmakov_upload_file']['name'] as $i => $v) { $file = [ 'name' => $_FILES['tokmakov_upload_file']['name'][$i], 'type' => $_FILES['tokmakov_upload_file']['type'][$i], 'tmp_name' => $_FILES['tokmakov_upload_file']['tmp_name'][$i], 'error' => $_FILES['tokmakov_upload_file']['error'][$i], 'size' => $_FILES['tokmakov_upload_file']['size'][$i], ]; // загружаем очередной файл в директорию uploads $result = media_handle_sideload($file, 0); if (is_wp_error($result)) { $messages[] = 'Ошибка при загрузке файла ' . $file['name']; } else { $messages[] = 'Файл ' . $file['name'] . ' успешно загружен'; } } } else { $messages[] = 'Проверка не пройдена, файл не загружен'; } if (!wp_doing_ajax()) { $_SESSION['tokmakov_upload_file'] = $messages; // после отправки формы делаем редирект, чтобы предотвратить // повторную отправку, если пользователь обновит страницу $redirect = home_url(); if (isset($_POST['redirect'])) { $redirect = $_POST['redirect']; $redirect = wp_validate_redirect($redirect, home_url()); } wp_redirect($redirect); die(); } else { wp_send_json($messages); } }
Поиск: AJAX • CMS • JSON • POST • Web-разработка • WordPress • Файл • Форма • Загрузка • Upload • File