I'm the developer of the Advanced Custom Fields plugin and am hoping you can help me out with an issue I am facing.

I have a button where you can edit an image. This button will launch a WP 3.5 media modal via the wp_media() function.

The problem is that I want to pre-select an image so that it's details are loaded in the sidebar panel.

Currently I am hooking into the 'open' callback and running some code which populates this selection, however, it is clunky and in efficient. This is what it looks like:

// _media is an object I am using

_media.frame = wp.media({
    title       :   'title',
    multiple    :   false,
    button      :   { text : 'button' }

// open
_media.frame.on('open',function() {

    // add class
    _media.frame.$el.closest('.media-modal').addClass('acf-media-modal acf-expanded');

    // set selection
    var selection   =   _media.frame.state().get('selection'),
        attachment  =   wp.media.attachment( id );

    selection.add( attachment );


// Finally, open the modal

This is working fine, until the user opens another modal window, selects the upload tab, then uses the edit button which I have created. Now the code fails completely becuase my code relies on the modal being in the 'browse' mode.

I found some code which will swap the frame over to the browse mode, it looks like this:


This works some of the time, but then the following code fails. Like it needs some time to render before the attachment can be added to the selection....

Surely there is a better way.

Thanks for your help. Elliot


1 Answer 1


Here is the script:

I’m using the function loadImages in following script to load the existing attached images via AJAX and then just pass the function with the IDs of images and it opens up a pre-populated modal.

var frame,
selection = loadImages(images);

$('#stag_images_upload').on('click', function(e) {

var options = {
    title: '<?php _e("Create Featured Gallery", "stag"); ?>',
    state: 'gallery-edit',
    frame: 'post',
    selection: selection

frame = wp.media(options).open();

frame.menu.get('view').get('gallery-edit').el.innerHTML = '<?php _e("Edit Featured Gallery", "stag"); ?>';
frame.content.get('view').sidebar.unset('gallery'); // Hide Gallery Settings in sidebar

// when editing a gallery
frame.on( 'toolbar:render:gallery-edit', function() {

frame.on( 'content:render:browse', function( browser ) {
    if ( !browser ) return;
    // Hide Gallery Settings in sidebar
    browser.sidebar.on('ready', function(){

    // Hide filter/search as they don't work
    browser.toolbar.on('ready', function(){
        if(browser.toolbar.controller._state == 'gallery-library'){

// All images removed
frame.state().get('library').on( 'remove', function() {
    var models = frame.state().get('library');
    if(models.length == 0){
        selection = false;
        $.post(ajaxurl, { ids: '', action: 'stag_save_images', post_id: stag_ajax.post_id, nonce: stag_ajax.nonce });

function overrideGalleryInsert(){
        insert: {
            style: 'primary',
            text: '<?php _e("Save Featured Gallery", "stag"); ?>',
            click: function(){
                var models = frame.state().get('library'),
                    ids = '';

                models.each( function( attachment ) {
                    ids += attachment.id + ','

                this.el.innerHTML = '<?php _e("Saving...", "stag"); ?>';

                    type: 'POST',
                    url: ajaxurl,
                    data: { 
                        ids: ids, 
                        action: 'stag_save_images', 
                        post_id: stag_ajax.post_id, 
                        nonce: stag_ajax.nonce 
                    success: function(){
                        selection = loadImages(ids);
                        $('#_stag_image_ids').val( ids );
                    dataType: 'html'
                }).done( function( data ) {
                    $('.stag-gallery-thumbs').html( data );

function loadImages(images){
    if (images){
        var shortcode = new wp.shortcode({
            tag:      'gallery',
            attrs:    { ids: images },
            type:     'single'

        var attachments = wp.media.gallery.attachments( shortcode );

        var selection = new wp.media.model.Selection( attachments.models, {
            props:    attachments.props.toJSON(),
            multiple: true

        selection.gallery = attachments.gallery;

        selection.more().done( function() {
            // Break ties with the query.
            selection.props.set({ query: false });

        return selection;
    return false;


And here is the php function that handles the AJAX request:

function stag_save_images(){
    if( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ){

    if ( !isset($_POST['ids']) || !isset($_POST['nonce']) || !wp_verify_nonce( $_POST['nonce'], 'stag-ajax' ) ){

    if ( !current_user_can( 'edit_posts' ) ) return;

    $ids = strip_tags(rtrim($_POST['ids'], ','));
    update_post_meta($_POST['post_id'], '_stag_image_ids', $ids);

    $thumbs = explode(',', $ids);
    $thumbs_output = '';
    foreach( $thumbs as $thumb ) {
        $thumbs_output .= '<li>' . wp_get_attachment_image( $thumb, array(75,75) ) . '</li>';

    echo $thumbs_output;

add_action( 'wp_ajax_stag_save_images', 'stag_save_images' );

function stag_metabox_scripts(){
    global $post;
    if( isset($post) ) {
        wp_localize_script( 'jquery', 'stag_ajax', array(
            'post_id' => $post->ID,
            'nonce' => wp_create_nonce( 'stag-ajax' )
        ) );

add_action( 'admin_enqueue_scripts', 'stag_metabox_scripts' );

I just copied the snippet from my WordPress framework, hope it makes sense.

  • What does "state 'gallery-edit'" do?
    – Daniel
    Commented Jul 8, 2020 at 20:25

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.