Как выбрать изображение из Медиа Библиотеки в моём плагине?

9 авг. 2016 г., 10:52:11
Просмотры: 48.9K
Голосов: 31

Я написал плагин, в котором есть маленькая иконка чата в правом нижнем углу, однако я хочу дать пользователю возможность выбирать изображение для этой иконки из Media Library (Медиа Библиотеки). Как это можно реализовать с помощью WordPress API? Изображение является настройкой плагина (изменяемой только администратором)

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

Вам следует подключить wp.media, чтобы разрешить загрузку пользовательских файлов и выбор медиафайла для этой задачи. На WPSE есть множество примеров, но, возможно, вам поможет эта статья: http://jeroensormani.com/how-to-include-the-wordpress-media-selector-in-your-plugin/. Также вы можете найти примеры на GitHub, особенно от ocean90 - https://github.com/ocean90/media-modal-demo

bueltge bueltge
17 авг. 2016 г. 15:24:34
Все ответы на вопрос 6
2
48

Для использования диалогового окна WordPress Media Manager следует использовать wp.media.

Сначала необходимо подключить скрипты:

// Поскольку мы работаем с настройками плагина,
// предполагаем, что находимся в админке
add_action( 'admin_enqueue_scripts', 'load_wp_media_files' );
function load_wp_media_files( $page ) {
  // измените на нужную страницу, где требуется подключить скрипт
  if( $page == 'options-general.php' ) {
    // Подключаем стандартные скрипты WordPress для медиа
    wp_enqueue_media();
    // Подключаем кастомный скрипт для взаимодействия с wp.media
    wp_enqueue_script( 'myprefix_script', plugins_url( '/js/myscript.js' , __FILE__ ), array('jquery'), '0.1' );
  }
}

HTML может выглядеть так (обратите внимание, что в моём коде используется ID вложения в настройках плагина вместо URL изображения, как в вашем ответе - это более правильный подход, так как позволяет получать изображения разных размеров при необходимости):

$image_id = get_option( 'myprefix_image_id' );
if( intval( $image_id ) > 0 ) {
    // Укажите нужный размер изображения
    $image = wp_get_attachment_image( $image_id, 'medium', false, array( 'id' => 'myprefix-preview-image' ) );
} else {
    // Изображение по умолчанию
    $image = '<img id="myprefix-preview-image" src="https://some.default.image.jpg" />';
}

  echo $image; ?>
 <input type="hidden" name="myprefix_image_id" id="myprefix_image_id" value="<?php echo esc_attr( $image_id ); ?>" class="regular-text" />
 <input type='button' class="button-primary" value="<?php esc_attr_e( 'Выбрать изображение', 'mytextdomain' ); ?>" id="myprefix_media_manager"/>

myscript.js

jQuery(document).ready( function($) {

      jQuery('input#myprefix_media_manager').click(function(e) {

             e.preventDefault();
             var image_frame;
             if(image_frame){
                 image_frame.open();
             }
             // Определяем image_frame как объект wp.media
             image_frame = wp.media({
                           title: 'Выбор медиа',
                           multiple : false,
                           library : {
                                type : 'image',
                            }
                       });

                       image_frame.on('close',function() {
                          // При закрытии получаем выбранные элементы и сохраняем в скрытое поле
                          // плюс AJAX-запрос для обновления превью изображения
                          var selection =  image_frame.state().get('selection');
                          var gallery_ids = new Array();
                          var my_index = 0;
                          selection.each(function(attachment) {
                             gallery_ids[my_index] = attachment['id'];
                             my_index++;
                          });
                          var ids = gallery_ids.join(",");
                          if(ids.length === 0) return true;//если закрыто без выбора изображения
                          jQuery('input#myprefix_image_id').val(ids);
                          Refresh_Image(ids);
                       });

                      image_frame.on('open',function() {
                        // При открытии получаем ID из скрытого поля
                        // и выбираем соответствующие изображения в медиабиблиотеке
                        var selection =  image_frame.state().get('selection');
                        var ids = jQuery('input#myprefix_image_id').val().split(',');
                        ids.forEach(function(id) {
                          var attachment = wp.media.attachment(id);
                          attachment.fetch();
                          selection.add( attachment ? [ attachment ] : [] );
                        });

                      });
    
                    image_frame.open();
     });

});

// AJAX-запрос для обновления превью изображения
function Refresh_Image(the_id){
        var data = {
            action: 'myprefix_get_image',
            id: the_id
        };

        jQuery.get(ajaxurl, data, function(response) {

            if(response.success === true) {
                jQuery('#myprefix-preview-image').replaceWith( response.data.image );
            }
        });
}

AJAX-действие для обновления превью изображения:

// AJAX-действие для обновления изображения
add_action( 'wp_ajax_myprefix_get_image', 'myprefix_get_image'   );
function myprefix_get_image() {
    if(isset($_GET['id']) ){
        $image = wp_get_attachment_image( filter_input( INPUT_GET, 'id', FILTER_VALIDATE_INT ), 'medium', false, array( 'id' => 'myprefix-preview-image' ) );
        $data = array(
            'image'    => $image,
        );
        wp_send_json_success( $data );
    } else {
        wp_send_json_error();
    }
}

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

18 авг. 2016 г. 14:29:20
Комментарии

Ajax-вызов get_image не обязателен. selection.models[0].attributes.url содержит URL выбранного изображения при закрытии image_frame. Если вам нужен определенный размер, тогда потребуется ajax-вызов.

Bjorn Bjorn
17 апр. 2020 г. 20:48:30

Спасибо! Небольшая поправка: думаю, при "закрытии" не должно быть изменений выбранного изображения, а только при "выборе".

Nikolay Nikolay
14 июн. 2022 г. 15:48:33
3

Просто скопируйте и вставьте код в нужное место

<?php
if ( isset( $_POST['submit_image_selector'] ) && isset( $_POST['image_attachment_id'] ) ) :
        update_option( 'media_selector_attachment_id', absint( $_POST['image_attachment_id'] ) );
    endif;
    wp_enqueue_media();
    ?><form method='post'>
        <div class='image-preview-wrapper'>
            <img id='image-preview' src='<?php echo wp_get_attachment_url( get_option( 'media_selector_attachment_id' ) ); ?>' width='200'>
        </div>
        <input id="upload_image_button" type="button" class="button" value="<?php _e( 'Загрузить изображение' ); ?>" />
        <input type='hidden' name='image_attachment_id' id='image_attachment_id' value='<?php echo get_option( 'media_selector_attachment_id' ); ?>'>
        <input type="submit" name="submit_image_selector" value="Сохранить" class="button-primary">
    </form>
<?php
$my_saved_attachment_post_id = get_option( 'media_selector_attachment_id', 0 );
    ?><script type='text/javascript'>
        jQuery( document ).ready( function( $ ) {
            // Загрузка файлов
            var file_frame;
            var wp_media_post_id = wp.media.model.settings.post.id; // Сохраняем старый ID
            var set_to_post_id = <?php echo $my_saved_attachment_post_id; ?>; // Устанавливаем этот ID
            jQuery('#upload_image_button').on('click', function( event ){
                event.preventDefault();
                // Если фрейм уже существует, открываем его снова
                if ( file_frame ) {
                    // Устанавливаем нужный post_id
                    file_frame.uploader.uploader.param( 'post_id', set_to_post_id );
                    // Открываем фрейм
                    file_frame.open();
                    return;
                } else {
                    // Устанавливаем post_id для wp.media, чтобы загрузчик использовал нужный ID при инициализации
                    wp.media.model.settings.post.id = set_to_post_id;
                }
                // Создаем медиа-фрейм
                file_frame = wp.media.frames.file_frame = wp.media({
                    title: 'Выберите изображение для загрузки',
                    button: {
                        text: 'Использовать это изображение',
                    },
                    multiple: false // Установите true, чтобы разрешить выбор нескольких файлов
                });
                // При выборе изображения выполняем callback
                file_frame.on( 'select', function() {
                    // Мы установили multiple в false, поэтому получаем только одно изображение
                    attachment = file_frame.state().get('selection').first().toJSON();
                    // Делаем что-то с attachment.id и/или attachment.url
                    $( '#image-preview' ).attr( 'src', attachment.url ).css( 'width', 'auto' );
                    $( '#image_attachment_id' ).val( attachment.id );
                    // Восстанавливаем основной post ID
                    wp.media.model.settings.post.id = wp_media_post_id;
                });
                    // Открываем модальное окно
                    file_frame.open();
            });
            // Восстанавливаем основной ID при нажатии кнопки добавления медиа
            jQuery( 'a.add_media' ).on( 'click', function() {
                wp.media.model.settings.post.id = wp_media_post_id;
            });
        });
    </script>
6 янв. 2018 г. 07:35:32
Комментарии

Вы спасли мне жизнь! :) Спасибо

Freestyle09 Freestyle09
23 июн. 2020 г. 10:20:45

@LawrenceCherone можете посмотреть мой код, я его обновил

Rohit Kaushik Rohit Kaushik
14 янв. 2021 г. 08:49:30

Это отлично работает. Есть ли способ передать категорию в селектор Медиатеки?

TARKUS TARKUS
27 авг. 2022 г. 21:05:39
0

Итак, этот ответ сработал идеально. Но чтобы сделать его переиспользуемым, я преобразовал код в функцию. Таким образом, для использования вам сначала нужно ознакомиться с этим, чтобы enqueue скрипт. Затем объявите wpOpenGallery следующим образом:

(function($) {
    $(document).ready(function() {
        const wpOpenGallery = function(o, callback) {
            const options = (typeof o === 'object') ? o : {};

            // Предустановленные настройки
            const defaultOptions = {
                title: 'Выбрать медиафайл',
                fileType: 'image',
                multiple: false,
                currentValue: '',
            };

            const opt = { ...defaultOptions, ...options };

            let image_frame;

            if(image_frame){
                image_frame.open();
            }

            // Определяем image_frame как объект wp.media
            image_frame = wp.media({
                title: opt.title,
                multiple : opt.multiple,
                library : {
                    type : opt.fileType,
                }
            });

            image_frame.on('open',function() {
                // При открытии получаем ID из скрытого поля
                // и выбираем соответствующие изображения в медиабиблиотеке
                const selection =  image_frame.state().get('selection');
                const ids = opt.currentValue.split(',');

                ids.forEach(function(id) {
                    const attachment = wp.media.attachment(id);
                    attachment.fetch();
                    selection.add( attachment ? [ attachment ] : [] );
                });
            });

            image_frame.on('close',function() {
                // При закрытии получаем выбранные элементы и сохраняем в скрытое поле
                // плюс другие AJAX-действия для обновления превью изображения
                const selection =  image_frame.state().get('selection');
                const files = [];

                selection.each(function(attachment) {
                    files.push({
                        id: attachment.attributes.id,
                        filename: attachment.attributes.filename,
                        url: attachment.attributes.url,
                        type: attachment.attributes.type,
                        subtype: attachment.attributes.subtype,
                        sizes: attachment.attributes.sizes,
                    });
                });

                callback(files);
            });

            image_frame.open();
        }
    })
}(jQuery));

И вызывайте её так:

wpOpenGallery(null, function(data) {
    console.log(data);
});
13 апр. 2020 г. 17:11:58
1

Используйте wordpress-settings-api-class от Tareq Hasan, URL: https://github.com/tareq1988/wordpress-settings-api-class

16 авг. 2016 г. 17:07:15
Комментарии

Я считаю, что решение без дополнительных библиотек лучше, надежнее, например, как wp.media контрол.

bueltge bueltge
17 авг. 2016 г. 15:27:09
5

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

// создаем поле
add_action( 'show_user_profile', 'wpse_235406_chaticon' );
add_action( 'edit_user_profile', 'wpse_235406_chaticon' );

function wpse_235406_chaticon ($user) { 
    echo '
    <h3>Иконка чата</h3>
    <table class="form-table">
        <tr>
            <th><label for="chaticon">Иконка чата</label></th>
            <td>
                <input type="file" name="chaticon" id="chaticon" value="' . esc_attr (get_the_author_meta ('chaticon', $user->ID)) . '" class="file-upload" /><br />
                <span class="description">Пожалуйста, выберите иконку для чата.</span>
            </td>
        </tr>
    </table>';
}

// сохраняем поле
add_action( 'personal_options_update', 'wpse_235406_chaticon_save' );
add_action( 'edit_user_profile_update', 'wpse_235406_chaticon_save' );

function wpse_235406_chaticon_save ($user_id) {
    if (current_user_can ('edit_user', $user_id)) 
        update_usermeta ($user_id, 'chaticon', $_POST['chaticon']);
}

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

В вашем шаблоне нужно учитывать три варианта: пользователь не авторизован, пользователь авторизован, но без иконки, пользователь авторизован и имеет иконку. Вкратце, добавьте следующее:

$current_user = wp_get_current_user();
if ( 0 == $current_user->ID ) {
  ... действия для неавторизованных пользователей ...
  }
else {
  $icon = get_user_meta ($current_user->ID, 'chaticon');
  if (empty($icon)) {
    ... стандартная иконка со ссылкой на возможность загрузки ...
    }
  else {
     ... отображение $icon ...
     }
15 авг. 2016 г. 14:13:14
Комментарии

нет, я хочу, чтобы это было настройкой плагина

Thomas Thomas
15 авг. 2016 г. 14:20:05

Вы имеете в виду, что только администратор сайта сможет изменять иконку, и она будет одинаковой для всех посетителей/пользователей?

cjbj cjbj
15 авг. 2016 г. 14:24:32

Это было бы довольно просто. Вот руководство по этому поводу: https://mikejolley.com/2012/12/21/using-the-new-wordpress-3-5-media-uploader-in-plugins/

cjbj cjbj
15 авг. 2016 г. 14:28:13

да, он настраивает внешний вид (изображение) кнопки

Thomas Thomas
15 авг. 2016 г. 14:28:28

Я попробовал руководство, но у меня не работает (устарело?), потому что frames не является частью js объекта

Thomas Thomas
16 авг. 2016 г. 10:08:50
7

Я использовал это решение (без использования самой Медиатеки):

Используя библиотеку image-picker внутри модального окна, которая устанавливает значение скрытого input, передаваемое в настройки. Получая все медиафайлы и выводя их как варианты, я позволяю пользователю выбрать изображение.

HTML

<input id="image" name="image" class="validate" type="image" src="<?php echo esc_attr(get_option('image_url')); ?>" id="image_url" width="48" height="48" />
<br>
<a href="#imageModal" class="waves-effect waves-light btn modal-trigger">
    изменить
</a>
<input id="image_url" name="image_url" type="text" value="" hidden />

PHP/HTML

<div id="imageModal" class="modal">
    <div class="modal-content">
        <select class="image-picker show-html">
            <option data-img-src="<?php echo CM_PATH . "/img/chat_general.png" ?>"  value="0"></option>
            <?php
            $query_images_args = array(
                'post_type'   => 'attachment',
                'post_mime_type' => 'image',
                'post_status' => 'inherit',
                'posts_per_page' => - 1,
            );

            $query_images = new WP_Query( $query_images_args );
            $i = 1;
            foreach ( $query_images->posts as $image ) {
                ?>
                <option data-img-src="<?php echo wp_get_attachment_url($image->ID); ?>"  value="<?php echo $i; ?>"></option>
                <?php
                $i  ;
            }
            ?>
        </select>
    </div>
    <div class="modal-footer">
        <a class="waves-effect waves-light btn change">Выбрать</a>
    </div>
</div>
</div>
</div>

JS

 $(".change").on("click", function() {
 +            var url = $(".image-picker > option:selected").attr("data-img-src");
 +            $("#image").attr("src", url);
 +            $("#image_url").attr("value", url);
 +            $("#imageModal").closeModal();
 +        });
16 авг. 2016 г. 17:23:29
Комментарии

Я считаю, что решение без дополнительных библиотек лучше, более надежное; например, как элемент управления wp.media.

bueltge bueltge
17 авг. 2016 г. 15:26:54

@bueltge Я согласен, но никто не дал прямого ответа, а у меня был дефицит времени. Так что если кто-то предложит отличное решение — он получит награду!

Thomas Thomas
17 авг. 2016 г. 15:40:01

Я вижу твой ответ тоже как решение, но не самое оптимальное. Теперь автор вопроса (то есть ты) должен принять решение.

bueltge bueltge
17 авг. 2016 г. 15:42:08

Это решение может быстро стать проблемой по мере увеличения количества изображений. "никто не дал прямого ответа" — это не оправдание; ваш вопрос очень слабый, поэтому вы получаете слабые ответы. Вы не показали нам никаких усилий, исследований или кода, который вы пробовали, просто "я хочу сделать это, дайте готовое решение", что равносильно "сделайте работу за меня". Поищите wp.media, как предложил bueltge; здесь, в WPSE, сотни примеров. Если у вас возникнут проблемы с его использованием, задайте новый вопрос об этом.

cybmeta cybmeta
18 авг. 2016 г. 13:19:49

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

Thomas Thomas
18 авг. 2016 г. 13:27:57

wp.media — это лучший вариант, который у вас есть, и именно его я предлагаю; попробуйте использовать его, и если у вас возникнут вопросы, задайте их. Я написал несколько ответов об использовании wp.media, как и другие люди, попробуйте воспользоваться поиском (или Google), попробуйте сами и задавайте вопросы о проблемах, с которыми столкнётесь. Извините, если мои комментарии показались вам грубыми, вы жаловались на отсутствие хороших ответов, я просто попытался объяснить, почему. Честно говоря, я думаю, вам стоит воспринимать мой комментарий без обид и научиться избегать плохих вопросов.

cybmeta cybmeta
18 авг. 2016 г. 13:44:20

Кстати, когда я сказал "вы не показали никаких усилий, исследований или кода, который вы пробовали", я говорил о вашем вопросе. Я думал, что мой комментарий был понятен, возможно, это было не так, и мне следовало оставить этот комментарий под вопросом, а не под ответом. В любом случае, я добавил ответ; надеюсь, он будет полезен для вас.

cybmeta cybmeta
18 авг. 2016 г. 17:49:20
Показать остальные 2 комментариев