WordPress. Загрузка медиа-файлов

27.07.2019

Теги: AJAXFormDataWeb-разработкаWordPressПлагинФайлФорма

Давайте создадим плагин, который позволит зарегистрированным пользователям загружать медиа файлы. Чтобы не создавать свой загрузчик файлов, будем использовать файл async-upload.php, расположенный в папке wp-admin. Это стандартный скрипт WordPress для AJAX-загрузки медиа файлов, в нем есть все необходимые проверки прав доступа, так что нам не придется делать это самостоятельно.

Для использования файла async-upload.php, нам нужно выполнить следующие условия:

  • Установить значение атрибута name поля для загрузки файла в значение async-upload
  • В post-запросе отправить ключ _wpnonce со значением, которе возвращает функция wp_create_nonce() с аргументом media-form
  • В post-запросе отправить ключ action со значением upload-attachment, чтобы была вызвана функция wp_ajax_upload_attachment()

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

Плагин загрузки медиа-файлов

Итак, создаем директорию tokmakov-upload-media, а внутри нее — три файла: tokmakov-upload-media.php, script.js и style.js.

Файл tokmakov-upload-media.php

<?php
/*
Plugin Name: Загрузка файлов
Plugin URI: https://tokmakov.msk.ru
Description: Позволяет загружать файлы зарегистрированным пользователям.
Version: 1.0
Author: Евгений Токмаков
Author URI: https://tokmakov.msk.ru
*/

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');
    }
});

Предоставляя всем зарегистрированным пользователям возможность загрузки файлов, мы тем самым предоставляем доступ к медиабиблиотеке — пользователи смогут загружать файлы в админ-панели сайта. А мы добавим возможность загрузки файлов в публичной части сайта — там, где будет размещен шорткод.

Смысла в этом плагине немного, это скорее исследование возможностей WordPress. Но можно доработать плагин, чтобы он стал реально полезен. Например, прикреплять загруженные файлы к той записи, где размещен шорткод, объединять их в галерею и показывать на странице и т.п. Потому как неприкрепленные вложения будут только захламлять медиабиблиотеку.

/*
 * Подключаем js-файл, который будет загружать файлы с использованием AJAX
 */
add_action('wp_enqueue_scripts', function () {
    wp_enqueue_script(
        'tokmakov-upload-media-js',  // будет зарегистрирован под этим именем
        plugin_dir_url( __FILE__ ) . 'script.js',
        ['jquery'],  // должен быть подключен после jquery
        null, // версии нет, поэтому null
        true // подключаем перед закрывающим тегом body
    );
    // передаем на сторону клиента объект tokmakov_upload_media,
    // который содержит все необходимое для работы js-кода
    $config = array(
        'upload_url'    => admin_url('async-upload.php'),
        'ajax_url'      => admin_url('admin-ajax.php'),
        'nonce_upload'  => wp_create_nonce('media-form'),
        'nonce_remove'  => wp_create_nonce('remove-media'),
        'nonce_message' => wp_create_nonce('admin-message'),
    );
    wp_localize_script(
        'tokmakov-upload-media-js',
        'tokmakov_upload_media',
        $config
    );
    // подключаем файл стилей, чтобы красиво оформить наш блок загрузки
    wp_enqueue_style(
        'tokmakov-upload-media-css', // будет зарегистрирован под этим именем
        plugin_dir_url(__FILE__) . 'style.css'
    );
});
/*
 * Регистрируем шорткод [tokmakov-upload-media], который позволит вставить форму
 * загрузки файлов в любое место
 */
add_shortcode('tokmakov-upload-media', function () {
    $html = '';
    if (is_user_logged_in()) {
        $html =
<<<HTML
    <div class="tokmakov-upload-media">
        <span class="loader"></span>
        <span class="result"></span>
        <span class="preview"></span>
        <span class="upload">
            <input type="file" accept="image/*,audio/*,video/*">
            <button>Загрузить</button>
        </span>
    </div>
HTML;
    }
    return $html;
});
/*
 * Удаляем ранее загруженный файл, если пользователь передумал
 */
add_action('wp_ajax_tokmakov_remove_media', function () {
    check_ajax_referer('remove-media');
    $file_id = filter_var($_POST['file_id'], FILTER_VALIDATE_INT);
    if (!$file_id) {
        wp_send_json_error(
            ['message' => 'Некорректный идентификатор файла']
        );
    }
    if (false === wp_delete_attachment($file_id, true)) {
        wp_send_json_error(
            ['message' => 'Ошибка при удалении']
        );
    } else {
        wp_send_json_success(
            ['message' => 'Файл успешно удален']
        );
    }
});
/*
 * Отправляем почтовое сообщение администратору о загрузке файла
 */
add_action('wp_ajax_tokmakov_upload_media', function () {
    check_ajax_referer('admin-message');
    $file_id = filter_var($_POST['file_id'], FILTER_VALIDATE_INT);
    $author_id = filter_var($_POST['author_id'], FILTER_VALIDATE_INT);
    if ( ! ($file_id && $author_id)) {
        wp_send_json_error(
            ['message' => 'Некорректные данные файла или пользователя']
        );
    }

    $email= get_option('admin_email');
    $subject = 'Загружен новый файл';
    $user = get_user_by('id', $author_id);
    $user_name = $user->data->user_nicename;
    $user_mail = $user->data->user_email;
    $message = sprintf(
        'Загружен новый файл пользователем %s (%s). Ссылка на файл: %s',
        $user_name,
        $user_mail,
        wp_get_attachment_url($file_id)
    );
    $result = wp_mail($email, $subject, $message);

    if ($result) {
        wp_send_json_success(
            ['message' => 'Сообщение администратору успешно отправлено']
        );
    } else {
        wp_send_json_error(
            ['message' => 'Ошибка при отправке сообщения администратору']
        );
    }
});

В результате работы шорткода на страницу будет добавлен html-код:

<div class="tokmakov-upload-media">
    <span class="loader"></span>
    <span class="result"></span>
    <span class="preview"></span>
    <span class="upload">
        <input type="file" accept="image/*,audio/*,video/*">
        <button>Загрузить</button>
    </span>
</div>

Если медиа-файл был успешно загружен, с сервера будет получен ответ в формате JSON, который будет содержать всю информацию о загруженном файле. Так что на клиенте мы можем предоставить возможность этот файл посмотреть или удалить.

{
    "success":true,
    "data":
        {
            "id":2342,
            "title":"sunrise",
            "filename":"sunrise.jpg",
            "url":"http://www.serever.com/wp-content/uploads/2019/07/sunrise.jpg",
            "link":"http://www.serever.com/sunrise/",
            "alt":"",
            "author":"1",
            "description":"",
            "caption":"",
            "name":"sunrise",
            "status":"inherit",
            "uploadedTo":0,
            "date":1564148014000,
            "modified":1564148014000,
            "menuOrder":0,
            "mime":"image/jpeg",
            "type":"image",
            "subtype":"jpeg",
            "icon":"http://www.serever.com/wp-includes/images/media/default.png",
            "dateFormatted":"26.07.2019",
            "nonces":
                {
                    "update":"3a9155cf5a",
                    "delete":"3c232c8759",
                    "edit":"9153475dbb"
                },
            "editLink":"http://www.serever.com/wp-admin/post.php?post=2342&action=edit",
            "meta":false,
            "authorName":"admin",
            "filesizeInBytes":207875,
            "filesizeHumanReadable":"203 KB",
            "context":"",
            "height":1080,
            "width":1920,
            "orientation":"landscape",
            "sizes":
                {
                    "thumbnail":
                        {
                            "height":150,
                            "width":150,
                            "url":"http://www.serever.com/wp-content\/uploads/2019/07/sunrise-150x150.jpg",
                            "orientation":"landscape"
                        },
                    "medium":
                        {
                            "height":113,
                            "width":200,
                            "url":"http://www.serever.com/wp-content/uploads/2019/07/sunrise-200x113.jpg",
                            "orientation":"landscape"
                        },
                    "large":
                        {
                            "height":563,
                            "width":1000,
                            "url":"http://www.serever.com/wp-content/uploads/2019/07/sunrise-1000x563.jpg",
                            "orientation":"landscape"
                        },
                    "full":
                        {
                            "url":"http://www.serever.com/wp-content/uploads/2019/07/sunrise.jpg",
                            "height":1080,
                            "width":1920,
                            "orientation":"landscape"
                        }
                },
            "compat":
                {
                    "item":"",
                    "meta":""
                }
        }
}

Файл script.js

jQuery(document).ready(function($) {
    // при клике на кнопке отправляем ajax-запрос
    $('.tokmakov-upload-media button').on('click', function() {
        var $button = $(this);
        var $block = $button.parent().parent();
        var $upload = $block.children('span.upload');
        var $input = $upload.children('input[type="file"]');
        var $preview = $block.children('span.preview');
        var $result = $block.children('span.result');
        // очищаем сообщение о предыдущих загрузках
        $result.empty();
        // если файл был выбран — загружаем его на сервер
        if ($input.prop('files').length) {
            // данные, которые будем отправлять на сервер
            var data = new FormData();
            data.append('action', 'upload-attachment');
            data.append('async-upload', $input.prop('files')[0]);
            data.append('_wpnonce', tokmakov_upload_media.nonce_upload);
            // отправляем ajax-запрос
            $.ajax({
                url: tokmakov_upload_media.upload_url,
                type: 'POST',
                data: data,
                processData: false,
                contentType: false,
                dataType: 'json',
                beforeSend: function() {
                    // перед отправкой запроса скрываем поле выбора
                    // файла и кнопку отправки
                    $upload.hide();
                    // показываем сообщение, что идет загрузка; это
                    // нужно для больших файлов
                    $result.html('Загрузка файла &hellip;');
                },
                success: function(response) {
                    if (response.success) {
                        $result.html('Файл успешно загружен');
                        // показываем ссылку для просмотра файла
                        var attr = {href: response.data.url, target: '_blank'};
                        $('<a>', attr).text('Открыть файл').appendTo($preview);
                        $preview.append(' '); // пробел между ссылками
                        // показываем ссылку для удаления файла...
                        var $remove = $('<a>', {href: '#'}).text('Удалить файл').appendTo($preview);
                        // ...и назначаем для нее обработчик события
                        $remove.on('click', function (e) {
                            e.preventDefault();
                            var data = new FormData();
                            data.append('action', 'tokmakov_remove_media');
                            data.append('file_id', response.data.id);
                            data.append('_wpnonce', tokmakov_upload_media.nonce_remove);
                            $.ajax({
                                url: tokmakov_upload_media.ajax_url,
                                type: 'POST',
                                data: data,
                                processData: false,
                                contentType: false,
                                dataType: 'json',
                                success: function(response) {
                                    $result.html(response.data.message);
                                    if (response.success) {
                                        $preview.empty();
                                        // предлагаем загрузить другой файл
                                        $input.val('');
                                        $upload.show();
                                    }
                                }
                            });
                        });
                        // отправляем сообщение администратору о загрузке файла
                        var data = new FormData();
                        data.append('action', 'tokmakov_upload_media');
                        data.append('file_id', response.data.id);
                        data.append('author_id', response.data.author);
                        data.append('_wpnonce', tokmakov_upload_media.nonce_message);
                        $.ajax({
                            url: tokmakov_upload_media.ajax_url,
                            type: 'POST',
                            data: data,
                            processData: false,
                            contentType: false,
                            dataType: 'json',
                        });
                    } else {
                        $result.html('Ошибка при загрузке файла');
                        // предлагаем загрузить еще раз
                        $input.val('');
                        $upload.show();
                    }
                },
                error: function () {
                    $result.html('Обратитесь к администратору');
                }
            });
        } else {
            $result.text('Выберите файл для загрузки');
        }
    });
});

Файл style.css

.tokmakov-upload-media {
    padding: 10px;
    margin: 10px 0;
    background-color: #f5f5f5;
    border: 1px solid #e3e3e3;
}
    .tokmakov-upload-media input, .tokmakov-upload-media button {
        display: inline-block;
        padding: 5px;
        background-color: #e3e3e3;
        border: none;
    }

Поиск: AJAX • FormData • Web-разработка • WordPress • Плагин • Файл • Форма • Загрузка • Upload

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.