30

I have written a plugin in which you have a small chat icon in the bottom right corner, however I want the user to be able to choose an image as the icon from the Media Library. How can I do this with the Wordpress API? The image is a setting in the plugin (only changable by the admin)

1
  • 2
    You should include the wp.media to allow custom uploads, select of a media file for this requirement. WPSE have a lot of examples, but maybe this posts helps you jeroensormani.com/… Also you find on github examples, especially from ocean90 - github.com/ocean90/media-modal-demo
    – bueltge
    Commented Aug 17, 2016 at 12:24

6 Answers 6

47
+50

You should use wp.media to use the WordPress Media Manager dialog.

First, you need to enqueue the scritps:

// As you are dealing with plugin settings,
// I assume you are in admin side
add_action( 'admin_enqueue_scripts', 'load_wp_media_files' );
function load_wp_media_files( $page ) {
  // change to the $page where you want to enqueue the script
  if( $page == 'options-general.php' ) {
    // Enqueue WordPress media scripts
    wp_enqueue_media();
    // Enqueue custom script that will interact with wp.media
    wp_enqueue_script( 'myprefix_script', plugins_url( '/js/myscript.js' , __FILE__ ), array('jquery'), '0.1' );
  }
}

Your HTML could be something like this (note my code use attachment ID in the plugin setting instead of image url as you did in your answer, I think it is much better. For example, using ID allows you to get different images sizes when you need them):

$image_id = get_option( 'myprefix_image_id' );
if( intval( $image_id ) > 0 ) {
    // Change with the image size you want to use
    $image = wp_get_attachment_image( $image_id, 'medium', false, array( 'id' => 'myprefix-preview-image' ) );
} else {
    // Some default image
    $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( 'Select a image', '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();
             }
             // Define image_frame as wp.media object
             image_frame = wp.media({
                           title: 'Select Media',
                           multiple : false,
                           library : {
                                type : 'image',
                            }
                       });

                       image_frame.on('close',function() {
                          // On close, get selections and save to the hidden input
                          // plus other AJAX stuff to refresh the image preview
                          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;//if closed withput selecting an image
                          jQuery('input#myprefix_image_id').val(ids);
                          Refresh_Image(ids);
                       });

                      image_frame.on('open',function() {
                        // On open, get the id from the hidden input
                        // and select the appropiate images in the media manager
                        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 request to refresh the image preview
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 );
            }
        });
}

And the Ajax action to refresh the image preview:

// Ajax action to refresh the user image
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();
    }
}

PD: it is a quick sample written here based on other answer. Not tested because you didn't provide enough information about the exact context the code will be used or the exact problems you have.

2
  • 3
    The get_image ajax call is not necessary. The selection.models[0].attributes.url holds the selected image url on image_frame close. If you want to use a certain size, you'll need the ajax call.
    – Bjorn
    Commented Apr 17, 2020 at 17:48
  • Thanks! Small adjustment, I think on "close" it should not do any changes to the selected image, but only on "select".
    – Nikolay
    Commented Jun 14, 2022 at 12:48
8

Easy for use just only copy paste the code in your required place

<?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( 'Upload image' ); ?>" />
        <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="Save" 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( $ ) {
            // Uploading files
            var file_frame;
            var wp_media_post_id = wp.media.model.settings.post.id; // Store the old id
            var set_to_post_id = <?php echo $my_saved_attachment_post_id; ?>; // Set this
            jQuery('#upload_image_button').on('click', function( event ){
                event.preventDefault();
                // If the media frame already exists, reopen it.
                if ( file_frame ) {
                    // Set the post ID to what we want
                    file_frame.uploader.uploader.param( 'post_id', set_to_post_id );
                    // Open frame
                    file_frame.open();
                    return;
                } else {
                    // Set the wp.media post id so the uploader grabs the ID we want when initialised
                    wp.media.model.settings.post.id = set_to_post_id;
                }
                // Create the media frame.
                file_frame = wp.media.frames.file_frame = wp.media({
                    title: 'Select a image to upload',
                    button: {
                        text: 'Use this image',
                    },
                    multiple: false // Set to true to allow multiple files to be selected
                });
                // When an image is selected, run a callback.
                file_frame.on( 'select', function() {
                    // We set multiple to false so only get one image from the uploader
                    attachment = file_frame.state().get('selection').first().toJSON();
                    // Do something with attachment.id and/or attachment.url here
                    $( '#image-preview' ).attr( 'src', attachment.url ).css( 'width', 'auto' );
                    $( '#image_attachment_id' ).val( attachment.id );
                    // Restore the main post ID
                    wp.media.model.settings.post.id = wp_media_post_id;
                });
                    // Finally, open the modal
                    file_frame.open();
            });
            // Restore the main ID when the add media button is pressed
            jQuery( 'a.add_media' ).on( 'click', function() {
                wp.media.model.settings.post.id = wp_media_post_id;
            });
        });
    </script>
3
  • You saved my life ! :) Thank you Commented Jun 23, 2020 at 7:20
  • @LawrenceCherone can you see my code, I have updated Commented Jan 14, 2021 at 6:49
  • This works well. Is there a way to pass a category to the Media Library selector?
    – TARKUS
    Commented Aug 27, 2022 at 18:05
5

So this answer worked perfectly. But in order to make it reusable, I converted the code to a function. So, to use this, you have to first check this out to enqueue the script. And then declare wpOpenGallery like this:

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

            // Predefined settings
            const defaultOptions = {
                title: 'Select Media',
                fileType: 'image',
                multiple: false,
                currentValue: '',
            };

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

            let image_frame;

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

            // Define image_frame as wp.media object
            image_frame = wp.media({
                title: opt.title,
                multiple : opt.multiple,
                library : {
                    type : opt.fileType,
                }
            });

            image_frame.on('open',function() {
                // On open, get the id from the hidden input
                // and select the appropiate images in the media manager
                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() {
                // On close, get selections and save to the hidden input
                // plus other AJAX stuff to refresh the image preview
                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));

And call it like this:

wpOpenGallery(null, function(data) {
    console.log(data);
});
2

Use wordpress-settings-api-class by Tareq Hasan, Url: https://github.com/tareq1988/wordpress-settings-api-class

1
  • 2
    I think a solution without additional libraries is better, solid; like the wp.media control.
    – bueltge
    Commented Aug 17, 2016 at 12:27
1

Since you want the icon to be different for every user, you will have to store the image in the user profile. This means you need to add an extra user field:

// create the field
add_action( 'show_user_profile', 'wpse_235406_chaticon' );
add_action( 'edit_user_profile', 'wpse_235406_chaticon' );

function wpse_235406_chaticon ($user) { 
    echo '
    <h3>Chat Icon</h3>
    <table class="form-table">
        <tr>
            <th><label for="chaticon">Chat Icon</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">Please select your chat icon.</span>
            </td>
        </tr>
    </table>';
}

// save the field
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']);
}

Now, this gives you the possibility to upload a file from the user's computer. If you want the user to select the file frome existing images, things become more complicated, because then you need to call the media library in stead of the default file upload. Steven Slack has written an excellent post how to do this, which I don't want to take credit for by copy-pasting his code here.

In your template you must distinguish three possibilities: user not logged in, user logged in but has no icon, user logged in and has icon. Roughly, include this:

$current_user = wp_get_current_user();
if ( 0 == $current_user->ID ) {
  ... do what you want to do for not logged in users ...
  }
else {
  $icon = get_user_meta ($current_user->ID, 'chaticon');
  if (empty($icon)) {
    ... default icon with link to upload possibility ...
    }
  else {
     ... display $icon ...
     }
5
  • no, I'd like it to be a plugin setting
    – Thomas
    Commented Aug 15, 2016 at 11:20
  • You mean only the admin of the site should be able to change the icon and it will be the same for every visitor/user?
    – cjbj
    Commented Aug 15, 2016 at 11:24
  • 2
    That would be pretty trivial. Here's a tutorial for that: mikejolley.com/2012/12/21/…
    – cjbj
    Commented Aug 15, 2016 at 11:28
  • yeah, it customizes the look (image) of a button
    – Thomas
    Commented Aug 15, 2016 at 11:28
  • I tried the tutorial, but it doesn't work for me (obsolete?) becauses frames is not part of the js object
    – Thomas
    Commented Aug 16, 2016 at 7:08
0

I used this solution (without using the Media Library itself):

Using image-picker-lib inside a modal that set a hidden input's value, which is posted to the options. By getting all the media and echoing it as options I can let the user select an img.

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">
    change
</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">Choose</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();
 +        });
7
  • 1
    I think a solution without additional libraries is better, solid; like the wp.media control.
    – bueltge
    Commented Aug 17, 2016 at 12:26
  • @bueltge I agree, but nobody gave a straight answer and I was in need of time. So if someone gives a great answer, they get the bounty!
    – Thomas
    Commented Aug 17, 2016 at 12:40
  • I see your answer also as solution, but not the best way. Now it is a part of the question author, you ;) to make the decision.
    – bueltge
    Commented Aug 17, 2016 at 12:42
  • This solution can quickly become a problem as the number of images increase. "nobody gave a straight answer" is not a excuse; your question is very poor, so you get poor answers. You don't show us any effort, research or code you has tried, just "I want to do this, give a ready-to-use solution", which is the same that "do the job for me". Search for wp.media as bueltge suggested; there are hundreds of examples here in WPSE. If you have problems using it, post a new question about it.
    – cybmeta
    Commented Aug 18, 2016 at 10:19
  • @cybmeta I did try and this is my best attemp, so don't be an ass about it. If you don't like it, propose a better solution.
    – Thomas
    Commented Aug 18, 2016 at 10:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.