В этом уроке я покажу вам два способа, как можно создать поле с возможностью загрузки изображений, и мы сразу добавим его в метабокс и на страницу настроек кстати. В первом способе мы всё сделаем ручками, а во втором – воспользуемся плагином (Carbon Fields).
Давайте же посмотрим, что мы будем создавать!
Создание поля
1. JavaScript код медиазагрузчика wp.media
Если быть точным, то jQuery. Почему мы не используем чистый JS для этой цели? Да потому что в этом нет большого смысла в админке WordPress, там jQuery и так подключается и поэтому даже правильнее будет использовать его.
jQuery(function($){ /* * действие при нажатии на кнопку загрузки изображения * вы также можете привязать это действие к клику по самому изображению */ $('.upload_image_button').click(function( event ){ event.preventDefault(); const button = $(this); const customUploader = wp.media({ title: 'Выберите изображение плз', library : { // uploadedTo : wp.media.view.settings.post.id, // если для метобокса и хотим прилепить к текущему посту type : 'image' }, button: { text: 'Выбрать изображение' // текст кнопки, по умолчанию "Вставить в запись" }, multiple: false }); // добавляем событие выбора изображения customUploader.on('select', function() { const image = customUploader.state().get('selection').first().toJSON(); button.parent().prev().attr( 'src', image.url ); button.prev().val( image.id ); }); // и открываем модальное окно с выбором изображения customUploader.open(); }); /* * удаляем значение произвольного поля * если быть точным, то мы просто удаляем value у <input type="hidden"> */ $('.remove_image_button').click(function( event){ event.preventDefault(); if ( true == confirm( "Уверены?" ) ) { const src = $(this).parent().prev().data('src'); $(this).parent().prev().attr('src', src); $(this).prev().prev().val(''); } }); });
Хотел бы прояснить несколько моментов по этому коду:
2. Подключаем скрипты в админку через wp_enqueue_script() и wp_enqueue_media()
add_action( 'admin_enqueue_scripts', 'true_include_myuploadscript' ); function true_include_myuploadscript( $hook ) { // у вас в админке уже должен быть подключен jQuery, если нет - раскомментируйте следующую строку: // wp_enqueue_script('jquery'); // дальше у нас идут скрипты и стили загрузчика изображений WordPress if ( ! did_action( 'wp_enqueue_media' ) ) { wp_enqueue_media(); } // само собой - меняем admin.js на название своего файла wp_enqueue_script( 'myuploadscript', get_stylesheet_directory_uri() . '/admin.js', array('jquery'), null, false ); }
Немного прокомментирую код выше.
3. Функция для вывода поля загрузки изображения
Эта функция в первозданном виде тоже отправляется в файл functions.php
(предполагая, что мы работаем с темой WordPress), единственное только вы можете поменять URL изображения, которое будет отображаться по умолчанию (вторая строка, переменная $default
).
function true_image_uploader_field( $args ) { // следующая строчка нужна только для использования на страницах настроек $value = get_option( $args[ 'name' ] ); // следующая строчка нужна только для использования в мета боксах $value = $args[ 'value' ]; $default = get_stylesheet_directory_uri() . '/placeholder.png'; if( $value && ( $image_attributes = wp_get_attachment_image_src( $value, array( 150, 110 ) ) ) ) { $src = $image_attributes[0]; } else { $src = $default; } echo ' <div> <img data-src="' . $default . '" src="' . $src . '" width="150" /> <div> <input type="hidden" name="' . $args[ 'name' ] . '" id="' . $args[ 'name' ] . '" value="' . $value . '" /> <button type="submit" class="upload_image_button button">Загрузить</button> <button type="submit" class="remove_image_button button">×</button> </div> </div> '; }
Вы можете подумать, что это абсолютно произвольная функция, но не спешите себя радовать – я не случайно использовал всего лишь один аргумент $args
и передавал параметры в неё в виде массива, почему было принято такое решение, вы узнаете в главе про создание страницы настроек ниже.
Также тут важен порядок элементов всех HTML элементов <div>
,<img>
, <button>
, и <input type="hidden" />
, потому что ещё в первой главе, в JavaScript-коде я перемещаюсь по дереву DOM методами prev()
и parent()
. Это тоже не случайно! Мы не можем использовать классы для каждого элемента, потому что если вдруг на одной странице у нас будет несколько таких загрузчиков, то работать будет только первый из них!
Использование в метабоксах
Код добавления метабокса — я максимально упростил его, для того, чтобы была понятна суть, но очень рекомендую ознакомиться с руководством по метабоксам на моём сайте.
Прежде, чем использовать представленный ниже код, убедитесь, что у вас выполнены все шаги.
/* * Добавляем метабокс */ add_action( 'add_meta_boxes', 'true_meta_boxes_u' ); function true_meta_boxes_u() { add_meta_box( 'truediv', 'Настройки', 'true_print_box_u', 'post', 'normal', 'high' ); } /* * Заполняем метабокс */ function true_print_box_u( $post ) { if( function_exists( 'true_image_uploader_field' ) ) { true_image_uploader_field( array( 'name' => 'uploader_custom', 'value' => get_post_meta( $post->ID, 'uploader_custom', true ), ) ); } } /* * Сохраняем данные произвольного поля */ add_action('save_post', 'true_save_box_data_u'); function true_save_box_data_u( $post_id ) { // ... тут различные проверки на права пользователя, на тип поста, на то, что не автосохранение и т д if( isset( $_POST[ 'uploader_custom' ] ) ) { update_post_meta( $post_id, 'uploader_custom', absint( $_POST[ 'uploader_custom' ] ) ); } return $post_id; }
В результате у меня получился вот такой метабокс:
Использование на странице настроек
В этой главе вас ждёт готовый код, который вы можете вставить либо в functions.php текущей темы, либо читайте здесь, куда.
Также у меня есть подробнейший урок про создание страниц настроек в WordPress.
class trueOptionsPage{ public $page_slug; public $option_group; function __construct() { // это у нас используется много где, поэтому давайте вынесем как отдельное свойство $this->page_slug = 'true_image'; $this->option_group = 'true_image_settings'; add_action( 'admin_menu', array( $this, 'add' ), 25 ); add_action( 'admin_init', array( $this, 'settings' ) ); add_action( 'admin_notices', array( $this, 'notice' ) ); } function add(){ add_menu_page( 'Настройки изображения', 'Изображение', 'manage_options', $this->page_slug, array( $this, 'display' ), 'dashicons-format-image', 20 ); } function display() { echo '<div class="wrap"> <h1>' . get_admin_page_title() . '</h1> <form method="post" action="options.php">'; settings_fields( $this->option_group ); do_settings_sections( $this->page_slug ); submit_button( 'Сохранить изображение' ); echo '</form></div>'; } function settings(){ register_setting( $this->option_group, 'true_image_field_id', 'absint' ); add_settings_section( 'image_settings_section_id', '', '', $this->page_slug ); add_settings_field( 'true_image_field_id', 'Изображение', 'true_image_uploader_field', // а вот эта наша функция кстати! $this->page_slug, 'image_settings_section_id', array( 'name' => 'true_image_field_id' ) ); } function notice() { if( isset( $_GET[ 'page' ] ) && $this->page_slug == $_GET[ 'page' ] && isset( $_GET[ 'settings-updated' ] ) && true == $_GET[ 'settings-updated' ] ) { echo '<div class="notice notice-success is-dismissible"><p>Настройки изображения сохранены!</p></div>'; } } } new trueOptionsPage();
Пожалуй самое интересное, на что тут можно обратить внимание, это использование функции add_settings_field()
на строчках 43-50, потому что 3-м аргументом мы передаём в неё название функции, которую мы создавали в шаге 3, а последним параметром – массив $args
, являющийся единственным аргументом этой функции!
Окей, результат вы уже знаете, но почему бы не показать вам его ещё один раз:
Делаем то же самое при помощи плагина Carbon Fields
О, а сейчас вас ждёт мега-прикол!
Вы по сути поймёте, почему сейчас редко кто пилит метабоксы и страницы настроек вручную.
Сначала давайте взглянем на то, как создать поле изображения при помощи Carbon Fields для метабокса. И да, вот ссылка на подробное руководство по Carbon Fields.
Container::make( 'post_meta', 'Настройки' ) ->where( 'post_type', '=', 'post' ) ->add_fields( array( Field::make( 'image', 'true_image', 'Изображение' ) ) );
Результат:
А теперь готовый готовый код, как сделать это для страницы настроек.
Container::make( 'theme_options', 'Настройки изображения' ) ->set_icon( 'dashicons-format-image' ) ->set_page_menu_title( 'Изображение' ) ->set_page_menu_position( 20 ) ->add_fields( array( Field::make( 'image', 'true_image', 'Изображение' ) ) );