Статьи

Вложение файлов в ваши сообщения с помощью пользовательских мета-боксов WordPress, часть 2

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


Если вы следовали вместе с кодом в первом посте, то у вас должна быть функциональная демонстрация того, как работает прикрепление PDF к посту (или странице) WordPress; однако общая презентация выглядит не очень хорошо:

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

Во-первых, давайте переместим ссылку для скачивания в более логичное место. Если вы следили за первым постом, вы помните, что мы поместили ссылку для скачивания в файл single.php, который находится в корне каталога темы. Откройте файл и найдите блок кода, который выглядит следующим образом:

1
2
get_template_part( ‘content’, ‘single’ );
$doc = get_post_meta(get_the_ID(), ‘wp_custom_attachment’, true);
1
2
3
<a href=» <?php echo $doc[‘url’]; ?>»>
Download PDF Here
</a>

Скопируйте все, кроме первой строки кода, и удалите его из файла. Это должно оставить только вызов get_template_part .

Затем найдите custom-single.php. Это файл шаблона, расположенный в корне каталога темы. Найдите вызов the_content () и вставьте код, который вы только что скопировали, прямо под ним. Это должно привести к следующему блоку кода:

1
2
3
4
5
the_content();
$doc = get_post_meta(get_the_ID(), ‘wp_custom_attachment’, true);
    <a href=» <?php echo $doc[‘url’]; ?>»>
    Download PDF Here
    </a>

Теперь давайте обернем ссылку в контейнер, чтобы мы могли легко ее стилизовать. Я даю своему контейнеру идентификатор «wp_custom_attachment». Не стесняйтесь использовать все, что вам нравится, просто не забудьте правильно сослаться на это в вашей таблице стилей.

Вот моя разметка:

1
2
3
4
5
6
7
the_content();
$doc = get_post_meta(get_the_ID(), ‘wp_custom_attachment’, true);
<div id=»wp_custom_attachment»>
    <a href=»<?php echo $doc[‘url’]; ?>»>
        Download PDF Here
    </a>
</div><!— #wp_custom_attachment —>

И вот мой CSS:

1
2
3
4
5
6
7
8
.wp_custom_attachment {
    margin: 8px 0 8px 0;
    border: 1px solid #DDD;
    background: #EEE;
    padding: 8px;
    text-align: center;
    border-radius: 4px;
}

Если вы правильно все написали, ссылка для скачивания теперь должна выглядеть так:

Намного лучше, верно? Теперь он стилизован так, что выглядит более тесно интегрированным с темой. Не забудьте также внести соответствующие изменения в page.php (учитывая, что мы поддерживаем вложения файлов на постах и ​​страницах).


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

В идеале, мы хотим отображать ссылку на скачивание только тогда, когда есть файл для загрузки. Таким образом, нам понадобится условие. В частности, нам нужно получить соответствующие метаданные публикации, определить, есть ли фактический URL-адрес для вложения файла. Если так, мы покажем ссылку; в противном случае мы не будем.

В блоке кода, который мы только что добавили в content-single.php, поместите открывающий оператор if чуть выше открывающего тега wp_custom_attachment и закройте оператор чуть ниже закрывающего тега контейнера. Прямо сейчас код должен выглядеть примерно так:

1
2
3
4
5
6
7
8
9
the_content();
$doc = get_post_meta(get_the_ID(), ‘wp_custom_attachment’, true);
if() {
    <div id=»wp_custom_attachment»>
        <a href=»<?php echo $doc[‘url’]; ?>»>
            Download PDF Here
        </a>
    </div><!— #wp_custom_attachment —>
} // end if

Нам нужно проверить наличие URL документа. Есть несколько способов сделать это, но я обычно проверяю, посмотрев на его атрибут URL. Результирующий блок кода:

1
2
3
4
5
6
7
8
9
the_content();
$doc = get_post_meta(get_the_ID(), ‘wp_custom_attachment’, true);
if(strlen(trim($doc[‘url’])) > 0) {
    <div id=»wp_custom_attachment»>
        <a href=»<?php echo $doc[‘url’]; ?>»>
            Download PDF Here
        </a>
    </div><!— #wp_custom_attachment —>
} // end if

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


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

Вспомните из последнего поста, что когда пользователь пытается загрузить файл, у нас есть функция сериализации, которая запускает функцию записи файла на диск. Для справки, это происходит в save_custom_meta_data.

Чтобы правильно удалить файл, нам нужно отследить местоположение существующего файла и узнать, действительно ли пользователь действительно запросил удаление файла. Мы сделаем это с помощью комбинации поля ввода и якоря.

Сначала найдите функцию ‘wp_custom_attachment’, которую мы создали в последнем посте. Здесь мы добавили элемент ввода файла. Чуть ниже элемента ввода добавьте следующий код (полная функция будет представлена ​​ниже):

1
2
// Create the input box and set the file’s URL as the text element’s value
$html .= ‘<input type=»text» id=»wp_custom_attachment_url» name=»wp_custom_attachment_url» value=» ‘ . $doc[‘url’] . ‘» size=»30″ />’;

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

1
$html .= ‘<a href=»javascript:;»

Обратите внимание: мы дали якору уникальный идентификатор. Это будет необходимо, когда мы начнем подключать область администрирования для обработки пользовательских событий. Если вы не дадите своему якорю этот идентификатор, запишите все, что вы назначаете.

Мы еще не закончили. Помните, как мы настраивали отдельные сообщения и просмотры страниц для условного отображения ссылки на скачивание? Мы должны сделать то же самое для ссылки удаления. В частности, нам нужно показывать ссылку для удаления, только если документ существует. Таким же образом, оберните якорь в условный оператор, который проверяет наличие URL документа:

1
2
3
4
// Display the ‘Delete’ option if a URL to a file exists
if(strlen(trim($doc[‘url’])) > 0) {
    $html .= ‘<a href=»javascript:;»
} // end if

Ничего слишком тяжелого, верно? Чтобы быть полным, вот полная функция в ее нынешнем виде:

1
function wp_custom_attachment() { wp_nonce_field(plugin_basename(__FILE__), ‘wp_custom_attachment_nonce’);

Мы вернемся к этой функции немного позже, но позже в уроке, но пока протестируем ее. Сначала перейдите к сообщению, которое не имеет вложений. Вы должны увидеть поле ввода файла и пустое поле ввода. После загрузки файла вы должны увидеть в поле ввода URL-адрес файла, а затем ссылку для удаления файла.

Но мы еще не закончили. В конце концов, ссылка для удаления на самом деле ничего не делает.

Затем найдите каталог ‘js’ в корне темы. Добавьте новый файл с именем custom_attachment.js. Мы напишем код для этого на мгновение, но целью файла будет то, что позволяет нам фактически удалить PDF, который мы прикрепили к сообщению.

После этого откройте файл functions.php и добавьте следующую функцию в конец файла:

1
2
3
4
5
6
7
function add_custom_attachment_script() {
 
    wp_register_script(‘custom-attachment-script’, get_stylesheet_directory_uri() . ‘/js/custom_attachment.js’);
    wp_enqueue_script(‘custom-attachment-script’);
 
} // end add_custom_attachment_script
add_action(‘admin_enqueue_scripts’, ‘add_custom_attachment_script’);

Эта функция будет читать только что созданный нами файл JavaScript и включать его на любую административную страницу в бэкэнде WordPress. Постановка в очередь и регистрация сценариев выходят за рамки данного руководства, но я рекомендую ознакомиться с ним .

Далее давайте вернемся к файлу JavaScript. Вообще говоря, код должен делать следующие вещи:

  • Определите, есть ли ссылка для удаления
  • Если ссылка присутствует, присоедините пользовательский обработчик событий, который очищает текстовый ввод, содержащий URL-адрес файла.
  • Скрыть ссылку после того, как файл был помечен для удаления

Исходный код приведен ниже, и он полностью прокомментирован, чтобы помочь объяснить, что делает каждая строка:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
jQuery(function($) {
 
    // Check to see if the ‘Delete File’ link exists on the page…
    if($(‘a#wp_custom_attachment_delete’).length === 1) {
 
        // Since the link exists, we need to handle the case when the user clicks on it…
        $(‘#wp_custom_attachment_delete’).click(function(evt) {
         
            // We don’t want the link to remove us from the current page
            // so we’re going to stop it’s normal behavior.
            evt.preventDefault();
             
            // Find the text input element that stores the path to the file
            // and clear it’s value.
            $(‘#wp_custom_attachment_url’).val(»);
             
            // Hide this link so users can’t click on it multiple times
            $(this).hide();
         
        });
     
    } // end if
 
});

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

После нажатия на ссылку «Удалить ссылку» пользовательское мета-поле должно выглядеть следующим образом:

Если нет, дважды проверьте консоль отладки, чтобы убедиться, что у вас нет ошибок JavaScript.


На данный момент мы сделали почти все, но фактически удалили файл. Для этого нам нужно обновить функцию save_custom_meta_data, которую мы написали в первом посте. Напомним, что функционал включает в себя условную проверку содержимого коллекции $ _FILES, поступающей из запроса POST. Если коллекция заполнена, то мы сериализуем файл.

Поскольку мы пытаемся удалить файл, коллекция $ _FILES не должна содержать никаких данных, поэтому весь наш код должен будет содержаться в предложении else. Полный исходный код функции будет предоставлен ниже, но вот как функционал должен работать:

  • Проверьте, есть ли документ, связанный с сообщением
  • Проверьте, является ли текстовое поле, используемое для отслеживания URL-адреса файла, пустым
  • Если файл существует и текстовое поле пусто, удалите файл и обновите связанные метаданные

Это должно быть просто: мы дали каждому сообщению текстовый элемент, который содержит URL-адрес файла. Если URL-адрес файла пуст, это означает, что пользователь нажал на ссылку «Удалить файл» и запрашивает удаление файла. Вот как мы можем достичь этого:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
// Grab a reference to the file associated with this post
$doc = get_post_meta($id, ‘wp_custom_attachment’, true);
 
// Grab the value for the URL to the file stored in the text element
$delete_flag = get_post_meta($id, ‘wp_custom_attachment_url’, true);
 
// Determine if a file is associated with this post and if the delete flag has been set (by clearing out the input box)
if(strlen(trim($doc[‘url’])) > 0 && strlen(trim($delete_flag)) == 0) {
 
    // Attempt to remove the file.
    if(unlink($doc[‘file’])) {
         
        // Delete succeeded so reset the WordPress meta data
        update_post_meta($id, ‘wp_custom_attachment’, null);
        update_post_meta($id, ‘wp_custom_attachment_url’, »);
         
    } else {
        wp_die(‘There was an error trying to delete your file.’);
    } // end if/el;se
     
} // end if

Как только файл будет удален, обратите внимание, что мы также должны обновить метаданные публикации, опустошив значение вложения, а также значение URL вложения. В нечетном случае, когда файл не удаляется, мы отображаем простое сообщение об ошибке. Расширенная обработка ошибок выходит за рамки этого поста.

Как и было обещано, вот полная функция сериализации:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
function save_custom_meta_data($id) {
 
    /* — security verification — */
    if(!wp_verify_nonce($_POST[‘wp_custom_attachment_nonce’], plugin_basename(__FILE__))) {
      return $id;
    } // end if
       
    if(defined(‘DOING_AUTOSAVE’) && DOING_AUTOSAVE) {
      return $id;
    } // end if
       
    if(!current_user_can(‘edit_page’, $id)) {
        return $id;
    } // end if
    /* — end security verification — */
     
    // Make sure the file array isn’t empty
    if(!empty($_FILES[‘wp_custom_attachment’][‘name’])) {
         
        // Setup the array of supported file types.
        $supported_types = array(‘application/pdf’);
         
        // Get the file type of the upload
        $arr_file_type = wp_check_filetype(basename($_FILES[‘wp_custom_attachment’][‘name’]));
        $uploaded_type = $arr_file_type[‘type’];
         
        // Check if the type is supported.
        if(in_array($uploaded_type, $supported_types)) {
 
            // Use the WordPress API to upload the file
            $upload = wp_upload_bits($_FILES[‘wp_custom_attachment’][‘name’], null, file_get_contents($_FILES[‘wp_custom_attachment’][‘tmp_name’]));
     
            if(isset($upload[‘error’]) && $upload[‘error’] != 0) {
                wp_die(‘There was an error uploading your file. The error is: ‘ . $upload[‘error’]);
            } else {
                add_post_meta($id, ‘wp_custom_attachment’, $upload);
                update_post_meta($id, ‘wp_custom_attachment’, $upload);
            } // end if/else
 
        } else {
            wp_die(«The file type that you’ve uploaded is not a PDF.»);
        } // end if/else
         
    } else {
 
        // Grab a reference to the file associated with this post
        $doc = get_post_meta($id, ‘wp_custom_attachment’, true);
         
        // Grab the value for the URL to the file stored in the text element
        $delete_flag = get_post_meta($id, ‘wp_custom_attachment_url’, true);
         
        // Determine if a file is associated with this post and if the delete flag has been set (by clearing out the input box)
        if(strlen(trim($doc[‘url’])) > 0 && strlen(trim($delete_flag)) == 0) {
         
            // Attempt to remove the file.
            if(unlink($doc[‘file’])) {
                 
                // Delete succeeded so reset the WordPress meta data
                update_post_meta($id, ‘wp_custom_attachment’, null);
                update_post_meta($id, ‘wp_custom_attachment_url’, »);
                 
            } else {
                wp_die(‘There was an error trying to delete your file.’);
            } // end if/el;se
             
        } // end if
 
    } // end if/else
     
} // end save_custom_meta_data
add_action(‘save_post’, ‘save_custom_meta_data’);

К настоящему времени у вас есть полностью работающий пользовательский метабокс. Попробуйте.


У нас есть последнее небольшое изменение, которое нужно сделать, чтобы завершить наш пользовательский интерфейс. Помните ввод текста, который мы добавили ранее в руководстве, который отвечает за поддержку URL файла? Мы можем пометить это как скрытое — нет причин, по которым пользователю нужно это видеть. Источник JavaScript по-прежнему будет правильно его использовать, и его значение будет считано в функции сериализации.

Финальная функция wp_custom_attachment должна выглядеть так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function wp_custom_attachment() {
 
    wp_nonce_field(plugin_basename(__FILE__), ‘wp_custom_attachment_nonce’);
     
    $html = ‘<p class=»description»>’;
        $html .= ‘Upload your PDF here.’;
    $html .= ‘</p>’;
    $html .= ‘<input type=»file» id=»wp_custom_attachment» name=»wp_custom_attachment» value=»» size=»25″ />’;
     
    // Grab the array of file information currently associated with the post
    $doc = get_post_meta(get_the_ID(), ‘wp_custom_attachment’, true);
     
    // Create the input box and set the file’s URL as the text element’s value
    $html .= ‘<input type=»hidden» id=»wp_custom_attachment_url» name=»wp_custom_attachment_url» value=» ‘ . $doc[‘url’] . ‘» size=»30″ />’;
     
    // Display the ‘Delete’ option if a URL to a file exists
    if(strlen(trim($doc[‘url’])) > 0) {
        $html .= ‘<a href=»javascript:;»
    } // end if
     
    echo $html;
 
} // end wp_custom_attachment

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

Кроме того, если вы работаете с WordPress профессионально, важно понимать API. Надеюсь, что эта серия помогла продемонстрировать многое из того, что можно сделать, используя основные функции WordPress.