Как добавить поле загрузки изображения непосредственно в пользовательскую панель записи?

19 нояб. 2010 г., 20:31:26
Просмотры: 114K
Голосов: 67

Я добавил новую страницу в разделе "Страницы" в админ-панели WordPress и добавил несколько пользовательских полей. Я также хотел бы добавить поле для загрузки изображений в редактор страниц - возможно ли это сделать через пользовательские поля (custom fields)?

Или мне нужно использовать другой подход для реализации этой функциональности?

2
Комментарии

проверьте плагин tdo-forms, возможно, это простое решение

bueltge bueltge
19 нояб. 2010 г. 21:07:43

Возможно, этот вопрос связан: http://wordpress.stackexchange.com/questions/4291/how-to-display-category-information-from-a-custom-post

hakre hakre
19 нояб. 2010 г. 23:41:55
Все ответы на вопрос 2
4
112

Для тех, кто хочет узнать больше о загрузке файлов, вот краткое руководство, охватывающее основные темы и проблемные моменты. Это написано с учетом WordPress 3.0 на Linux-системе, и код представляет собой базовый обзор для объяснения концепций. Уверен, что некоторые коллеги здесь могли бы предложить советы по улучшению реализации.

Определите базовый подход

Существует как минимум три способа связать изображения с записями: использование поля post_meta для хранения пути к изображению, использование поля post_meta для хранения ID изображения из медиабиблиотеки (подробнее об этом позже) или назначение изображения записи как вложения. В этом примере мы будем использовать поле post_meta для хранения ID изображения из медиабиблиотеки. Результаты могут отличаться.

Многочастное кодирование

По умолчанию формы создания и редактирования WordPress не имеют атрибута enctype. Если вы хотите загрузить файл, вам нужно добавить "enctype='multipart/form-data'" в тег формы - иначе коллекция $_FILES вообще не будет передана. В WordPress 3.0 для этого есть хук. В некоторых предыдущих версиях (точные детали неизвестны) необходимо использовать замену строки для тега формы.

function xxxx_add_edit_form_multipart_encoding() {
    // Добавляем атрибут многочастного кодирования
    echo ' enctype="multipart/form-data"';
}
add_action('post_edit_form_tag', 'xxxx_add_edit_form_multipart_encoding');

Создание мета-бокса и поля загрузки

Я не буду углубляться в создание мета-боксов, так как большинство из вас, вероятно, уже знает, как это делать. Скажу только, что вам нужен простой мета-бокс с полем для файла. В примере ниже я включил код для поиска существующего изображения и его отображения, если оно существует. Я также добавил простую функциональность обработки ошибок/обратной связи, которая передает ошибки через поле post_meta. Вам следует изменить это для использования класса WP_Error... это только для демонстрации.

function xxxx_render_image_attachment_box($post) {
    // Проверяем, есть ли существующее изображение
    // (Мы связываем изображения с записями, сохраняя 'attachment id' изображения как значение post meta)
    // Кстати, так же вы можете найти любые загруженные файлы для отображения на фронтенде
    $existing_image_id = get_post_meta($post->ID,'_xxxx_attached_image', true);
    if(is_numeric($existing_image_id)) {
        echo '<div>';
            $arr_existing_image = wp_get_attachment_image_src($existing_image_id, 'large');
            $existing_image_url = $arr_existing_image[0];
            echo '<img src="' . $existing_image_url . '" alt="Прикрепленное изображение" title="Прикрепленное изображение" />';
        echo '</div>';
    }

    // Если есть существующее изображение, показываем его
    if($existing_image_id) {
        echo '<div>ID прикрепленного изображения: ' . $existing_image_id . '</div>';
    } 

    echo 'Загрузить изображение: <input type="file" name="xxxx_image" id="xxxx_image" />';

    // Проверяем, есть ли сообщение о статусе
    $status_message = get_post_meta($post->ID,'_xxxx_attached_image_upload_feedback', true);

    // Показываем сообщение об ошибке, если оно есть
    if($status_message) {
        echo '<div class="upload_status_message">';
            echo $status_message;
        echo '</div>';
    }

    // Добавляем скрытый флаг
    echo '<input type="hidden" name="xxxx_manual_save_flag" value="true" />';
}

function xxxx_setup_meta_boxes() {
    // Добавляем бокс на страницу определенного типа контента
    add_meta_box('xxxx_image_box', 'Загрузка изображения', 'xxxx_render_image_attachment_box', 'post', 'normal', 'high');
}
add_action('admin_init','xxxx_setup_meta_boxes');

Обработка загрузки файла

Это самая важная часть - непосредственно обработка загрузки файла путем подключения к действию save_post. Ниже я включил подробно прокомментированную функцию, но хотел бы отметить две ключевые функции WordPress, которые она использует:

wp_handle_upload() выполняет всю магию обработки загрузки. Вы просто передаете ей ссылку на ваше поле в массиве $_FILES и массив опций (не беспокойтесь о них слишком много - единственная важная опция, которую нужно установить, это test_form=false. Поверьте мне). Эта функция, однако, не добавляет загруженный файл в медиабиблиотеку. Она просто выполняет загрузку и возвращает путь к новому файлу (а также, что удобно, полный URL). Если возникает проблема, она возвращает ошибку.

wp_insert_attachment() добавляет изображение в медиабиблиотеку и генерирует все соответствующие миниатюры. Вы просто передаете ей массив опций (заголовок, статус записи и т.д.) и ЛОКАЛЬНЫЙ путь (не URL) к только что загруженному файлу. Отличная особенность помещения изображений в медиабиблиотеку заключается в том, что вы можете легко удалить все файлы позже, вызвав wp_delete_attachment и передав ему ID элемента медиабиблиотеки (что я делаю в функции ниже). С этой функцией вам также нужно будет использовать wp_generate_attachment_metadata() и wp_update_attachment_metadata(), которые делают именно то, что вы ожидаете - генерируют метаданные для медиаэлемента.

function xxxx_update_post($post_id, $post) {
    // Получаем тип записи. Поскольку эта функция будет выполняться для ВСЕХ сохранений записей (независимо от типа),
    // нам нужно это знать. Также важно отметить, что действие save_post может выполняться несколько раз при каждом
    // сохранении записи, поэтому нужно проверить, что тип записи в переданном объекте не "revision"
    $post_type = $post->post_type;

    // Убеждаемся, что наш флаг присутствует, иначе это автосохранение и мы должны прервать выполнение
    if($post_id && isset($_POST['xxxx_manual_save_flag'])) { 

        // Логика для обработки конкретных типов записей
        switch($post_type) {

            // Если это запись. Вы можете изменить этот случай, чтобы отразить ваш пользовательский slug записи
            case 'post':

                // ОБРАБОТКА ЗАГРУЗКИ ФАЙЛА

                // Если в поле загрузки есть файл
                if(isset($_FILES['xxxx_image']) && ($_FILES['xxxx_image']['size'] > 0)) {

                    // Получаем тип загруженного файла. Возвращается как "тип/расширение"
                    $arr_file_type = wp_check_filetype(basename($_FILES['xxxx_image']['name']));
                    $uploaded_file_type = $arr_file_type['type'];

                    // Устанавливаем массив, содержащий список допустимых форматов
                    $allowed_file_types = array('image/jpg','image/jpeg','image/gif','image/png');

                    // Если загруженный файл правильного формата
                    if(in_array($uploaded_file_type, $allowed_file_types)) {

                        // Массив параметров для функции wp_handle_upload
                        $upload_overrides = array( 'test_form' => false ); 

                        // Обрабатываем загрузку с помощью функции wp_handle_upload WordPress
                        $uploaded_file = wp_handle_upload($_FILES['xxxx_image'], $upload_overrides);

                        // Если wp_handle_upload вернул локальный путь для изображения
                        if(isset($uploaded_file['file'])) {

                            // Функции wp_insert_attachment нужен буквальный системный путь
                            $file_name_and_location = $uploaded_file['file'];

                            // Генерируем заголовок для изображения
                            $file_title_for_media_library = 'ваш заголовок здесь';

                            // Настраиваем массив параметров для добавления файла как вложения
                            $attachment = array(
                                'post_mime_type' => $uploaded_file_type,
                                'post_title' => 'Загруженное изображение ' . addslashes($file_title_for_media_library),
                                'post_content' => '',
                                'post_status' => 'inherit'
                            );

                            // Запускаем функцию wp_insert_attachment
                            $attach_id = wp_insert_attachment( $attachment, $file_name_and_location );
                            require_once(ABSPATH . "wp-admin" . '/includes/image.php');
                            $attach_data = wp_generate_attachment_metadata( $attach_id, $file_name_and_location );
                            wp_update_attachment_metadata($attach_id,  $attach_data);

                            // Перед обновлением post meta удаляем любое ранее загруженное изображение для этой записи
                            $existing_uploaded_image = (int) get_post_meta($post_id,'_xxxx_attached_image', true);
                            if(is_numeric($existing_uploaded_image)) {
                                wp_delete_attachment($existing_uploaded_image);
                            }

                            // Обновляем post meta для связи нового изображения с записью
                            update_post_meta($post_id,'_xxxx_attached_image',$attach_id);

                            // Устанавливаем флаг обратной связи в false, так как загрузка прошла успешно
                            $upload_feedback = false;

                        } else { // wp_handle_upload вернул какую-то ошибку

                            $upload_feedback = 'Возникла проблема с вашей загрузкой.';
                            update_post_meta($post_id,'_xxxx_attached_image',$attach_id);

                        }

                    } else { // неверный тип файла

                        $upload_feedback = 'Пожалуйста, загружайте только файлы изображений (jpg, gif или png).';
                        update_post_meta($post_id,'_xxxx_attached_image',$attach_id);

                    }

                } else { // Файл не был передан

                    $upload_feedback = false;

                }

                // Обновляем post meta с любой обратной связью
                update_post_meta($post_id,'_xxxx_attached_image_upload_feedback',$upload_feedback);

            break;

            default:

        } // Конец switch

    return;

} // Конец if manual save flag

    return;

}
add_action('save_post','xxxx_update_post',1,2);

Разрешения, владение и безопасность

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

Во-первых, убедитесь, что ваша папка wp-content/uploads существует и принадлежит apache:apache. Если это так, вы должны иметь возможность установить разрешения на 744, и все должно работать. Владение важно - даже установка прав на 777 иногда не поможет, если директория не имеет правильного владельца.

Вы также должны рассмотреть возможность ограничения типов загружаемых и выполняемых файлов с помощью файла htaccess. Это предотвращает загрузку файлов, которые не являются изображениями, и выполнение скриптов, замаскированных под изображения. Вам стоит поискать в Google более авторитетную информацию об этом, но вы можете сделать простое ограничение типов файлов следующим образом:

<Files ^(*.jpeg|*.jpg|*.png|*.gif)>
order deny,allow
deny from all
</Files>
23 нояб. 2010 г. 02:28:22
Комментарии

Огромное спасибо, MathSmath! Именно то, что мне было нужно. Хотел бы я поставить больше плюсов за этот ответ!

Michal Mau Michal Mau
25 янв. 2011 г. 06:21:30

Отличное объяснение! ЕДИНСТВЕННОЕ, что я бы очень хотел уточнить - как сделать определенные загруженные файлы недоступными для публичного доступа. Другими словами, если нужно создать определенный тип записи, где все загруженные файлы доступны только пользователям с определенными правами. Не могли бы вы подробнее рассказать об этом?

NetConstructor.com NetConstructor.com
25 янв. 2011 г. 13:25:17

Для тех, кто хочет загружать файлы через фронтенд, вам понадобится добавить следующий код, чтобы получить доступ к функции wp_handle_upload(): if ( ! function_exists( 'wp_handle_upload' ) ) require_once( ABSPATH . 'wp-admin/includes/file.php' );

Nick Budden Nick Budden
10 нояб. 2011 г. 19:27:56

@NetConstructor.com Я предлагаю вам создать отдельный вопрос, так как это выходит далеко за рамки данного ответа.

hitautodestruct hitautodestruct
7 мар. 2013 г. 14:51:02
0

Код, предоставленный @MathSmath, правильный. Однако, если вам нужно обрабатывать множество полей загрузки или загружать несколько файлов, то его придется значительно модифицировать.

Кроме того, он не использует медиатеку WordPress для загрузки файлов (которая выполняет всю черновую работу за кулисами).

Я бы рекомендовал вам рассмотреть плагин, например, Meta Box. Этот плагин поддерживает оба способа загрузки файлов:

Он поможет вам сократить усилия по написанию и поддержке кода, особенно когда вам нужно реализовать множественную загрузку файлов.

Отказ от ответственности: я являюсь автором плагина Meta Box.

24 янв. 2018 г. 04:57:44