Как загрузить изображение с помощью простой формы?
Я разрабатываю плагин для страницы профиля и хочу создать возможность загрузки через кнопку 'Обзор' и поле 'Директория', которые будут загружать и возвращать URL изображения. При этом я не хочу использовать media-upload.
Я читал Установка изображения записи через форму на фронтенде, но я не понимаю код. Помогите решить эту проблему?

Существует несколько частей.
Вам нужно добавить атрибут enctype
в форму профиля.
function edit_form_type_wpse_98375() {
echo ' enctype="multipart/form-data"';
}
add_action('user_edit_form_tag','edit_form_type_wpse_98375');
Затем добавить поле в форму.
function user_fields_wpse_98375($profileuser) {
$_profile_photo = get_user_meta($profileuser->data->ID,'_profile_photo',true);
echo '<h3>'.__('Дополнительные данные пользователя',THEME_TEXTDOMAIN).'</h3>';
echo '<tr class="show-admin-bar">';
echo '<th scope="row">'.__('Фото профиля', THEME_TEXTDOMAIN).'</th>';
echo '<td'.$tspan.'>';
echo '<fieldset>';
echo '<legend class="screen-reader-text"><span>'.__('Фото профиля', THEME_TEXTDOMAIN).'</span></legend>';
echo '<label for="profile_photo">';
echo '<input name="profile_photo" type="file" id="profile_photo" value="" />';
echo '</label><br />';
echo '</fieldset>';
echo '</td>';
echo '</tr>';
echo '</table>';
}
add_action('show_user_profile', 'user_fields_wpse_98375');
add_action('edit_user_profile', 'user_fields_wpse_98375');
И затем сохранить данные.
function save_user_custom($id=false) {
global $_FILES,$_POST;
if (false === $id) return false;
// сохраняем изображение
if (isset($_FILES)) {
if (isset($_FILES['profile_photo'])){
if (0 === $_FILES['profile_photo']['error']) {
// Здесь вы сохраняете файл
// Можно использовать wp_handle_upload
// Или Filesystem API
// не уверен, что именно вы хотите сделать
}
}
unset($up);
}
}
add_action('personal_options_update','save_user_custom');
add_action('edit_user_profile_update','save_user_custom');
wp_handle_upload
вероятно самый простой вариант. Из Codex:
if ( ! function_exists( 'wp_handle_upload' ) )
require_once( ABSPATH . 'wp-admin/includes/file.php' );
$uploadedfile = $_FILES['file'];
$upload_overrides = array( 'test_form' => false );
$movefile = wp_handle_upload( $uploadedfile, $upload_overrides );
if ( $movefile ) {
echo "Файл корректен и был успешно загружен.\n";
var_dump( $movefile);
} else {
echo "Возможная атака при загрузке файла!\n";
}
Поле ввода типа file
работает (в основном) как любое другое поле формы. Если вы дадите ему имя вроде my_uploads['profile_photo']
вместо просто profile_photo
, вы получите массив. Это отразится в переменной $_FILES
при обработке отправки формы. Вы можете добавить столько полей file
, сколько захотите, создавая этот массив или просто давая им разные имена. Что касается динамического добавления полей file
, это довольно простая задача для JavaScript.
Ссылки
http://codex.wordpress.org/Function_Reference/wp_handle_upload
http://codex.wordpress.org/Filesystem_API

Спасибо s_ha_dum ^_^ и вот пример, который мне действительно нужен http://i165.photobucket.com/albums/u56/zectdropper/Capture_zpsea5fdfc7.png Пояснение -> поле загрузки может добавлять или удалять больше одного файла. Я думаю, они должны сохраняться как массив. Как я могу записать и сохранить их в WordPress?

И если вам нужно тестировать ошибки, вы можете использовать этот хук: user_profile_update_errors

Я предполагаю, что вы не очень опытны в работе с PHP и загрузкой файлов. Поэтому начну с основ и закончу простым классом.
Если вы еще не читали основы загрузки файлов с помощью PHP, сделайте это сейчас. Никто не будет объяснять это здесь, это не по теме.
Начнем с базовой HTML формы:
if( empty( $_FILES ) ) {
global $pagenow;
$url = admin_url( $pagenow );
?>
<!-- Тип кодирования данных enctype ДОЛЖЕН быть указан как ниже -->
<form enctype="multipart/form-data" action="<?php echo $url; ?>" method="POST">
<!-- MAX_FILE_SIZE должен предшествовать полю ввода файла -->
<input type="hidden" name="MAX_FILE_SIZE" value="30000" />
<!-- Имя элемента input определяет имя в массиве $_FILES -->
Отправить этот файл: <input name="userfile" type="file" />
<input type="submit" value="Отправить файл" />
</form>
<?php
} else {
$imageupload = new File_Upload();
$attachment_id = $imageupload->create_attachment();
var_dump( $attachment_id );
}
Это довольно просто. Если суперглобальный массив $_FILES
пуст, это значит, что файл не был загружен — отображаем форму загрузки. Если он не пуст — обрабатываем загрузку. Я использую admin_url()
и переменную $pagenow
для создания URL действия. Если вы используете форму загрузки на фронтенде, вам нужно использовать home_url()
или что-то подобное.
После отправки файла через HTML вам нужно обработать загруженные файлы. Это будет сделано в классе File_Upload
.
class File_Upload
{
/**
* Ключ индекса из формы загрузки
* @var string
*/
public $index_key = '';
/**
* Копия суперглобального массива $_FILES
* @var array
*/
public $files = array();
/**
* Конструктор
* Настраивает массив файлов и угадывает ключ индекса
*/
public function __construct(){
if ( isset( $_FILES ) && ! empty( $_FILES ) ) {
$this->files = $_FILES;
$this->guess_index_key();
}
}
/**
* Устанавливает/перезаписывает ключ индекса
* Преобразует $name с приведением типа (string)
*
* @param string $name Имя ключа индекса
* @return string ::name Имя сохраненного ключа индекса
*/
public function set_field_name_for_file( $name = '' ) {
$this->index_key = ( ! empty( $name ) ) ? (string) $name : '';
return $this->index_key;
}
/**
* Преобразует загруженный файл в вложение WordPress
*
* @return boolean Был ли создан вложение (true) или нет (false)
*/
public function create_attachment(){
// перемещаем загруженный файл из временной папки и создаем базовые данные
$imagedata = $this->handle_uploaded_file();
// если перемещение не удалось, останавливаемся здесь
/*
* Для продакшена
* Установите и верните объект ошибки с WP_Error()
*/
if ( empty( $imagedata ) )
return false;
/*
* Для продакшена
* Проверьте, содержит ли $imagedata ожидаемые (и необходимые)
* значения. Каждый метод может завершиться неудачей и вернуть вредоносные данные!!
*/
$filename = $imagedata['filename'];
// создаем массив данных вложения
$attachment = array(
'guid' => $imagedata['url'] . '/' . $filename,
'post_mime_type' => $imagedata['type'],
'post_title' => preg_replace('/\.[^.]+$/', '', $filename ),
'post_content' => '',
'post_status' => 'inherit'
);
// вставляем вложение (тип записи attachment)
$attach_id = wp_insert_attachment( $attachment, $filename );
// сначала нужно подключить файл image.php
// для работы функции wp_generate_attachment_metadata()
require_once( ABSPATH . 'wp-admin/includes/image.php' );
/*
* Для продакшена
* Проверьте $attach_data, wp_generate_attachment_metadata() может завершиться неудачей
* Проверьте, если wp_update_attachment_metadata() завершится неудачей (вернет false),
* верните объект ошибки с WP_Error()
*/
$attach_data = wp_generate_attachment_metadata( $attach_id, $filename );
wp_update_attachment_metadata( $attach_id, $attach_data );
return $attach_id;
}
/**
* Обрабатывает загрузку
*
* @return array $return_data Массив с информацией о загруженном файле
*/
protected function handle_uploaded_file() {
// получаем базовые данные
$return_data = wp_upload_dir();
// получаем временный путь к файлу и имя файла из $_FILES ($this->files)
$tmp_file = ( isset( $this->files[$this->index_key] ) && ! empty( $this->files[$this->index_key] ) ) ?
(string) $this->files[$this->index_key]['tmp_name'] : '';
$tmp_name = ( isset( $this->files[$this->index_key] ) && ! empty( $this->files[$this->index_key] ) ) ?
(string) $this->files[$this->index_key]['name'] : '';
// останавливаемся, если что-то пошло не так
if ( empty( $tmp_file ) )
return false;
// устанавливаем путь к файлу
$filepath = $return_data['filepath'] = $return_data['path'] . '/' . basename( $tmp_name );
// перемещаем загруженный файл из временной директории в директорию загрузки
move_uploaded_file( $tmp_file , $filepath );
// устанавливаем имя файла
$filename = $return_data['filename'] = basename( $filepath );
// устанавливаем тип файла
/*
* Для продакшена
* Вы ДОЛЖНЫ действительно проверять расширение файла и тип файла
* при КАЖДОЙ загрузке. Если вы этого не сделаете, возможно загрузить
* ЛЮБОЙ вид файла, включая вредоносный код.
*/
$type = wp_check_filetype( $filename, null );
$return_data['file_ext'] = ( isset( $type['ext'] ) && ! empty( $type['ext'] ) ) ?
$type['ext'] : '';
$return_data['type'] = ( isset( $type['type'] ) && ! empty( $type['type'] ) ) ?
$type['type'] : '';
// возвращаем результаты
return $return_data;
}
/**
* Пытается получить первый индекс из $_FILES
*
* @return boolean Был ли найден ключ или нет
*/
protected function guess_index_key() {
$keys = array_keys( $_FILES );
if ( ! empty( $keys ) ) {
$this->index_key = $keys[0];
return true;
}
return false;
}
}
Это базовый класс и не для продакшена! Загрузка файлов — очень чувствительная тема, вы должны самостоятельно проверять и очищать все данные. В противном случае возможно, что кто-то загрузит вредоносный код и взломает ваш сервер/блог/сайт!
Теперь шаг за шагом о том, что происходит, где и когда.
При создании экземпляра класса класс пытается создать копию суперглобального массива $_FILES
. Если вы работаете с суперглобальными массивами, не трогайте их! Возможно, другим частям кода (плагинам или темам) также нужны данные внутри них. Следующее, что происходит в конструкторе — это попытка угадать ключ индекса. Как вы знаете, мы можем передать больше, чем один файл, и $_FILES
может содержать данные для всех загруженных файлов. Если вам нужно обработать больше одного файла, пройдитесь циклом по $_FILES
и установите ключ индекса с помощью set_field_name_for_file()
// получаем индексы из $_FILES
$keys = array_keys( $_FILES );
$upload_processor = new File_Upload();
foreach ( $keys as $key ) {
$upload_processor->set_field_name_for_file( $key );
$upload_processor->create_attachment();
}
set_field_name_for_file()
также необходим, если вы хотите выбрать конкретное поле из вашей HTML формы, в противном случае класс использует первый найденный индекс.
Следующий шаг — обработка загруженного файла. Метод create_attachment()
вызывает защищенный метод handle_uploaded_file()
, вам не нужно делать это вручную. Метод handle_uploaded_file()
просто собирает и устанавливает некоторые необходимые пути и имена файлов.
Последний шаг — создание вложения. create_attachment()
установит все необходимые данные и создаст для вас вложение. Метод возвращает ID вложения, так что вы можете получить доступ ко всем данным вложения с помощью get_post( [id] )
$imageupload = new File_Upload();
$attachment_id = $imageupload->create_attachment();
[некоторый другой код]
$attachment = get_post( $attachment_id );
$image_url = $attachment->guid;
printf( '<p><img src="%s"></p>', $image_url );
Несколько слов об обработке ошибок
Я написал несколько подсказок в коде класса для продакшена. Как я упоминал выше, загрузка файлов — очень чувствительная тема. Вы должны проверять, валидировать и очищать абсолютно все. В WordPress есть встроенная обработка ошибок с помощью WP_Error()
. Используйте ее! И проверяйте, была ли загрузка успешной, с помощью is_wp_error()
.
PHP может установить некоторые сообщения об ошибках, если загрузка не удалась. Но PHP не возвращает сообщения в виде текста, он возвращает коды ошибок. Метод для преобразования этих кодов в понятный текст может выглядеть так:
protected function guess_upload_error( $err = 0 ) {
$errcodes = array(
'Неизвестная ошибка',
'Загружаемый файл превышает директиву upload_max_filesize в php.ini.',
'Загружаемый файл превышает директиву MAX_FILE_SIZE, указанную в HTML форме.',
'Загружаемый файл был загружен только частично.',
'Файл не был загружен.',
'Отсутствует временная папка.',
'Не удалось записать файл на диск.',
'Расширение PHP остановило загрузку файла. PHP не предоставляет способа определить, какое расширение вызвало остановку загрузки файла; просмотр списка загруженных расширений с помощью phpinfo() может помочь.'
);
return ( isset( $errcodes[$err] ) ) ?
$errcodes[$err] : 'Неизвестная ошибка';
}
Вы должны проверить, была ли загрузка успешной, это может выглядеть так (в методе handle_upload_file()
):
// останавливаемся, если что-то пошло не так
if ( empty( $tmp_file ) ) {
$code = ( isset( $this->files[$this->index_key]['error'] ) ) ?
$this->files[$this->index_key]['error'] : 0;
$msg = $this->guess_upload_error( $code );
return new WP_Error( 'uploaderror', 'Ошибка загрузки с сообщением: ' . $msg );
}
И тогда вам нужно обработать ошибку при вызове класса:
if ( empty( $_FILES ) ) {
global $pagenow;
$url = admin_url( $pagenow );
?>
<!-- HTML форма -->
<?php
} else {
$imageupload = new File_Upload();
$attachment_id = $imageupload->create_attachment();
if ( is_wp_error( $attachment_id ) ) {
echo '<ol>';
foreach ( $attachment_id->get_error_messages() as $err )
printf( '<li>%s</li>', $err );
echo '</ol>';
} else {
// делаем что-то с созданным вложением
$attachment = get_post( $attachment_id );
$image_url = $attachment->guid;
printf( '<p><img src="%s"></p>', $image_url );
}
}
Всегда помните: Никогда не оставляйте неудачную загрузку без обработки!

Добавьте код в файл функций
add_action('wp_ajax_custom_action', 'custom_action');
add_action('wp_ajax_nopriv_custom_action', 'custom_action');
function custom_action() {
$post_id =12;
//print_r($_FILES); exit;
global $wpdb;
//$response = array();
if( $_FILES['uploadedfiles']) {
$file = $_FILES['uploadedfiles'];
require_once( ABSPATH . 'wp-admin/includes/admin.php' );
$file_return = wp_handle_upload( $file, array('test_form' => false ) );
if( isset( $file_return['error'] ) || isset( $file_return['upload_error_handler'] ) ) {
return false;
} else {
$filename = $file_return['file'];
$attachment = array(
'post_mime_type' => $file_return['type'],
'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $filename ) ),
'post_content' => '',
'post_status' => 'inherit',
'guid' => $file_return['url']
);
$attachment_id = wp_insert_attachment( $attachment, $file_return['url'] );
require_once(ABSPATH . 'wp-admin/includes/image.php');
$attachment_data = wp_generate_attachment_metadata( $attachment_id, $filename );
wp_update_attachment_metadata( $attachment_id, $attachment_data );
update_post_meta($post_id, '_thumbnail_id', $attachment_id);
if( 0 < intval( $attachment_id ) ) {
return $attachment_id;
}
}
return false;
}
//$response['message'] = 'Изображение загружено!!!';
//echo json_encode($response);
wp_die();
}
