Идея

  • Необходимо добавить метабокс (MetaBox) на страницу редактирования записи, который будет отображать поле для указания файла на жёстком диске. (<input type="file">)
  • При сохранении записи загруженный файл необходимо сохранить на сервере как «прикреплённый файл» к этой записи.

Код

По умолчанию форма для редактирования записей не имеет атрибут enctype="multipart/form-data", который необходим для загрузки файлов. К счастью, существует действие (Action), которое позволяет добавлять пользовательские атрибуты в форму редактирования записей. Следующий код показывает как это сделать.

add_action('post_edit_form_tag', 'post_edit_form_tag');
function post_edit_form_tag() {
    echo ' enctype="multipart/form-data"';
}

Следующим шагом необходимо создать метабокс (MetaBox), который будет выводить поле для указания файла. Делается это с помощью функции add_meta_box. Следующий код — это функция, которая используется для нашего метабокса.

function custom_field_document_upload() {
    global $post;

    $custom         = get_post_custom($post->ID);
    $download_id    = get_post_meta($post->ID, 'document_file_id', true);

    echo '<p><label for="document_file">Загрузить файл:</label><br />';
    echo '<input type="file" name="document_file" id="document_file" /></p>';
    echo '</p>';

    if(!empty($download_id) && $download_id != '0') {
        echo '<p><a href="' . wp_get_attachment_url($download_id) . '">
            Просмотр файла</a></p>';
    }
}

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

add_action('save_post', 'custom_field_document_update');
function custom_field_document_update($post_id) {
    global $post;

    if(strtolower($_POST['post_type']) === 'page') {
        if(!current_user_can('edit_page', $post_id)) {
            return $post_id;
        }
    }
    else {
        if(!current_user_can('edit_post', $post_id)) {
            return $post_id;
        }
    }

    if(!empty($_FILES['document_file'])) {
        $file   = $_FILES['document_file'];
        $upload = wp_handle_upload($file, array('test_form' => false));
        if(!isset($upload['error']) && isset($upload['file'])) {
            $filetype   = wp_check_filetype(basename($upload['file']), null);
            $title      = $file['name'];
            $ext        = strrchr($title, '.');
            $title      = ($ext !== false) ? substr($title, 0, -strlen($ext)) : $title;
            $attachment = array(
                'post_mime_type'    => $wp_filetype['type'],
                'post_title'        => addslashes($title),
                'post_content'      => '',
                'post_status'       => 'inherit',
                'post_parent'       => $post->ID
            );

            $attach_key = 'document_file_id';
            $attach_id  = wp_insert_attachment($attachment, $upload['file']);
            $existing_download = (int) get_post_meta($post->ID, $attach_key, true);

            if(is_numeric($existing_download)) {
                wp_delete_attachment($existing_download);
            }

            update_post_meta($post->ID, $attach_key, $attach_id);
        }
    }
}

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