11

When I click the Add Media button on a Post/Page, I have the option to Add Media. After selecting media, I click Insert Into Post, and the images are inserted. However, there is another option, which is on the left sidebar. I can click Create Gallery. The image selecting process is the same, but when I click Create New Gallery, it goes to a new frame which allows me to edit the order of the images.

This second window is what I am after. I am calling the frame from a metabox, and I have gotten it successfully to allow me to grab single or multiple images and save the ID's as a string, as well as insert thumbnails live into a preview box. I cannot find anything about calling the Gallery frame.

My current code is as follows:

jQuery('#fg_select').on('click', function(event){

    event.preventDefault();

    // If the media frame already exists, reopen it.
    if ( file_frame ) {
        file_frame.open();
        return;
    }

    // Create the media frame.
    file_frame = wp.media.frame = wp.media({
        title: "Select Images For Gallery",
        button: {text: "Select",},
        library : { type : 'image'},
        multiple: true // Set to true to allow multiple files to be selected
    });

    file_frame.on('open', function() {
        var selection = file_frame.state().get('selection');
        ids = jQuery('#fg_metadata').val().split(',');
        ids.forEach(function(id) {
            attachment = wp.media.attachment(id);
            attachment.fetch();
            selection.add( attachment ? [ attachment ] : [] );
        });
    });

    file_frame.on('ready', function() {
        // Here we can add a custom class to our media modal.
        // .media-modal doesn't exists before the frame is
        // completly initialised.
        $( '.media-modal' ).addClass( 'no-sidebar' );
    });

    // When an image is selected, run a callback.
    file_frame.on('select', function() {
        var imageIDArray = [];
        var imageHTML = '';
        var metadataString = '';
        images = file_frame.state().get('selection');
        images.each(function(image) {
            imageIDArray.push(image.attributes.id);
            imageHTML += '<li><button></button><img id="'+image.attributes.id+'" src="'+image.attributes.url+'"></li>';
        });
        metadataString = imageIDArray.join(",");
        if(metadataString){
            jQuery("#fg_metadata").val(metadataString);
            jQuery("#featuredgallerydiv ul").html(imageHTML);
            jQuery('#fg_select').text('Edit Selection');
            jQuery('#fg_removeall').addClass('visible');
        }
    });

    // Finally, open the modal
    file_frame.open();

});

Any ideas?

EDIT:

I've gotten it to the point where it calls the gallery directly, without any sidebars, etc. However, it now ignores the on('select') call. I guess galleries send a different call when selecting the image?

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

// Uploading files
var file_frame;

jQuery('#fg_select').on('click', function(event){

    event.preventDefault();

    // If the media frame already exists, reopen it.
    if ( file_frame ) {
        file_frame.open();
        return;
    }

    // Create the media frame.
    file_frame = wp.media.frame = wp.media({
        frame: "post",
        state: "featured-gallery",
        library : { type : 'image'},
        button: {text: "Edit Image Order"},
        multiple: true
    });

    file_frame.states.add([
        new wp.media.controller.Library({
            id:         'featured-gallery',
            title:      'Select Images for Gallery',
            priority:   20,
            toolbar:    'main-gallery',
            filterable: 'uploaded',
            library:    wp.media.query( file_frame.options.library ),
            multiple:   file_frame.options.multiple ? 'reset' : false,
            editable:   true,
            allowLocalEdits: true,
            displaySettings: true,
            displayUserSettings: true
        }),
    ]);

    file_frame.on('open', function() {
        var selection = file_frame.state().get('selection');
        ids = jQuery('#fg_metadata').val().split(',');
        if (!empty(ids)) {
            ids.forEach(function(id) {
                attachment = wp.media.attachment(id);
                attachment.fetch();
                selection.add( attachment ? [ attachment ] : [] );
            });
        }
    });

    file_frame.on('ready', function() {
        // Here we can add a custom class to our media modal.
        // .media-modal doesn't exists before the frame is
        // completly initialised.
        $( '.media-modal' ).addClass( 'no-sidebar' );
    });

    file_frame.on('change', function() {
        // Here we can add a custom class to our media modal.
        // .media-modal doesn't exists before the frame is
        // completly initialised.
        setTimeout(function(){
            $('.media-menu a:first-child').text('← Edit Selection').addClass('button').addClass('button-large').addClass('button-primary');
        },0);
    });

    // When an image is selected, run a callback.
    file_frame.on('set', function() {
        alert('test');
    });

    // Finally, open the modal
    file_frame.open();

});

EDIT 2:

Okay, so I've gotten everything to fire correctly. But I can't decipher the outputted gallery code.

        // When an image is selected, run a callback.
    file_frame.on('update', function() {
        var imageIDArray = [];
        var imageHTML = '';
        var metadataString = '';
        images = file_frame.state().get('selection');
        images.each(function(image) {
            imageIDArray.push(image.attributes.id);
            imageHTML += '<li><button></button><img id="'+image.attributes.id+'" src="'+image.attributes.url+'"></li>';
        });
        metadataString = imageIDArray.join(",");
        if (metadataString) {
            jQuery("#fg_metadata").val(metadataString);
            jQuery("#featuredgallerydiv ul").html(imageHTML);
            jQuery('#fg_select').text('Edit Selection');
            jQuery('#fg_removeall').addClass('visible');
        }
    });

Nothing is coming out for $imageArray, or $imageHTML. $image is something, it's an [object object].

EDIT 3: As mentioned below in comment, the main problem with the code from Edit 2 is that when using Gallery, you have to call 'library' instead of 'selection'.

    // Uploading files
var file_frame;

jQuery('#fg_select').on('click', function(event){

    event.preventDefault();

    // If the media frame already exists, reopen it.
    if ( file_frame ) {
        file_frame.open();
        return;
    }

    // Create the media frame.
    file_frame = wp.media.frame = wp.media({
        frame: "post",
        state: "gallery",
        library : { type : 'image'},
        button: {text: "Edit Image Order"},
        multiple: true
    });

    file_frame.on('open', function() {
        var selection = file_frame.state().get('selection');
        var ids = jQuery('#fg_metadata').val();
        if (ids) {
            idsArray = ids.split(',');
            idsArray.forEach(function(id) {
                attachment = wp.media.attachment(id);
                attachment.fetch();
                selection.add( attachment ? [ attachment ] : [] );
            });
        }
    });

    // When an image is selected, run a callback.
    file_frame.on('update', function() {
        var imageIDArray = [];
        var imageHTML = '';
        var metadataString = '';
        images = file_frame.state().get('library');
        images.each(function(attachment) {
            imageIDArray.push(attachment.attributes.id);
            imageHTML += '<li><button></button><img id="'+attachment.attributes.id+'" src="'+attachment.attributes.url+'"></li>';
        });
        metadataString = imageIDArray.join(",");
        if (metadataString) {
            jQuery("#fg_metadata").val(metadataString);
            jQuery("#featuredgallerydiv ul").html(imageHTML);
            jQuery('#fg_select').text('Edit Selection');
            jQuery('#fg_removeall').addClass('visible');
        }
    });

    // Finally, open the modal
    file_frame.open();

});

The main thing here I'm having difficulty with now is that I can't get it to open to gallery-edit with a selection. I can get it to open there, but there are no images selected. I'm looking into that. I'm also looking into re-opening instead of creating a new view and sending a pre-selection. If I go to the selection window, then the order window, but click the X to close, I can re-open to the order window. So there should be a way.

EDIT 4

As per code from answer below, I've changed the pre-selection code to:

    file_frame.on('open', function() {
        var library = file_frame.state().get('library');
        var ids = jQuery('#fg_perm_metadata').val();
        if (ids) {
            idsArray = ids.split(',');
            idsArray.forEach(function(id) {
                attachment = wp.media.attachment(id);
                attachment.fetch();
                library.add( attachment ? [ attachment ] : [] );
            });
        }
    });

This allows me to re-open directly to the gallery-edit state and have images pre-selected. However, when I open directly to this state, I cannot click Cancel Gallery (return to image selection state). Clicking that button/link just closes the frame. I tried pre-filling both the library and the selection, but that doesn't work either. The following is from media-views.js, and seems to be what controls that button. Instead of changing the state to a specific state, it changes it to the previous state. Since we are opening directly to gallery-edit, there is no past state. I'm wondering if it's possible to open to gallery, and then on open, change to gallery-edit. Do it instantly so that the user doesn't see, but so that it gets the past state into the system.

    galleryMenu: function( view ) {
    var lastState = this.lastState(),
        previous = lastState && lastState.id,
        frame = this;

EDIT 5:

Finally figured it all out. I couldn't get the above to work at all, I'm not sure why. So, there may be a better way to do this, involving that code. If so, I'd love to know.

    file_frame.on('open', function() {
        var selection = file_frame.state().get('selection');
        var library = file_frame.state('gallery-edit').get('library');
        var ids = jQuery('#fg_perm_metadata').val();
        if (ids) {
            idsArray = ids.split(',');
            idsArray.forEach(function(id) {
                attachment = wp.media.attachment(id);
                attachment.fetch();
                selection.add( attachment ? [ attachment ] : [] );
            });
            file_frame.setState('gallery-edit');
            idsArray.forEach(function(id) {
                attachment = wp.media.attachment(id);
                attachment.fetch();
                library.add( attachment ? [ attachment ] : [] );
            });
        }
    });

FINAL EDIT

My code is now working entirely, and I appreciate the help! If you'd like to see it in action, check out http://wordpress.org/plugins/featured-galleries/

Kelderic
  • 6,502
  • 8
  • 46
  • 85

1 Answers1

7

I'm relatively new to WP. In fact, I'm building my first WP theme and I'm stuck on the same question as you. Thank to your code, I can get to the Gallery page. And luckily, I've got the images saved. Here's my code:

// when click Insert Gallery, run callback
wp_media_frame.on('update', function(){
    var library = wp_media_frame.state().get('library');
    var images  = [];
    var image_ids = [];
    thumb_wraper.html('');

    library.map( function( image ) {
        image = image.toJSON();
        images.push(image.url);
        image_ids.push(image.id);
        thumb_wraper.append('<img src="' + image.url + '" alt="" />');
    });
});

What I have found is you should get 'library' instead of get 'selection'.

Edit: I've figured out how to go back to gallery-edit. Here is my full code:

    $( '#btn_upload' ).on( 'click', function( event ) {
    event.preventDefault();

    var images = $( '#image_ids' ).val();
    var gallery_state = images ? 'gallery-edit' : 'gallery-library';

    // create new media frame
    // You have to create new frame every time to control the Library state as well as selected images
    var wp_media_frame = wp.media.frames.wp_media_frame = wp.media( {
        title: 'My Gallery', // it has no effect but I really want to change the title
        frame: "post",
        toolbar: 'main-gallery',
        state: gallery_state,
        library: {
            type: 'image'
        },
        multiple: true
    } );

    // when open media frame, add the selected image to Gallery
    wp_media_frame.on( 'open', function() {
        var images = $( '#image_ids' ).val();
        if ( !images )
            return;

        var image_ids = images.split( ',' );
        var library = wp_media_frame.state().get( 'library' );
        image_ids.forEach( function( id ) {
            attachment = wp.media.attachment( id );
            attachment.fetch();
            library.add( attachment ? [ attachment ] : [] );
        } );
    } );

    // when click Insert Gallery, run callback
    wp_media_frame.on( 'update', function() {

        var thumb_wrapper = $( '#thumb-wrapper' );
        thumb_wraper.html( '' );
        var image_urls = [];
        var image_ids = [];

        var library = wp_media_frame.state().get( 'library' );

        library.map( function( image ) {
            image = image.toJSON();
            image_urls.push( image.url );
            image_ids.push( image.id );
            thumb_wrapper.append( '<img src="' + image.url + '" alt="" />' );
        } );
    } );
} );

I figured that if you re-open the existed frame, it'll always keep the initial state, in your case it's 'gallery'. You'll have to create new frame every time and check if there's images to open 'gallery-edit' Also, I prefer 'gallery-library' than 'gallery' because I want user to focus on my gallery.

Kan Nguyen
  • 199
  • 1
  • 4
  • Thanks for the response, first I've gotten! Yep, I figured out that it was library from perusing the media-views.js. My current code is able to open to the Gallery, change to Gallery-edit, then send me the code. I'm also able to reopen with images selected. What I have not been able to figure out is how to re-open to the gallery-edit state. I'll post full updated code above. – Kelderic Feb 24 '14 at 13:14
  • @AndyM: I added my full code. You'll have to create new frame every time, and check if there's images to set the state to 'gallery-edit'. It's silly but I can't find another way. – Kan Nguyen Feb 25 '14 at 08:43
  • Though I figured out to change selection to library when grabbing it, I forgot to change selection to library in my pre-selection code. It's frustrating that there are two different terms used here. Thanks for the help! – Kelderic Feb 25 '14 at 14:20
  • Actually there still seems to be an issue, see main code for description. – Kelderic Feb 25 '14 at 14:31
  • As you can see in my code, when start media frame the first time, I use state: 'gallery-library' instead of 'gallery' like yours. It means that, my frame only open "Add to Gallery" or "Edit Gallery" and it's always close the frame when click "Cancel Gallery". I prefer it that way so I stopped at my current code. If you want to fix the newest issue, you should dig deeper into media-views.js. Btw, have you removed the code for checking existed frame. I'm curious if you can open gallery-edit without creating new frame every time. – Kan Nguyen Feb 25 '14 at 15:18
  • Near the beginning, it checks to see if the frame exists. If it does, it just reopens and doesn't do anything else. You could slip in a .setState('gallery-edit'); there if you wanted. – Kelderic Feb 25 '14 at 16:10
  • I've already tried that, there's no effect. My gallery has button Upload, if there's images the button change to Edit. If there's no images the first time the frame is create, it'll always open the "Add to Gallery" even if I reset the state to gallery-edit. It's the reason I have to remove the code for checking existed frame. – Kan Nguyen Feb 26 '14 at 01:48
  • Sounds kind of like what I'm working on, which is a featured gallery plugin. I handle the Button text via the metabox php code, which checks to see if there is stored metadata (in the text box that the media uploader code will be stored), and either says Select Images, or Edit Selection. Then in the JS, I never look to see if a frame exists. Whenever the selection is changed, I have the JS look at my text input and see if it is blank or not. – Kelderic Feb 26 '14 at 13:36
  • @KanNguyen hi there ... can you tell me what is `#image_ids` and `#thumb-wrapper` – deemi-D-nadeem Feb 20 '17 at 10:47
  • @KanNguyen ... I want to add gallery shortcode in my meta field ... so please can you guide me how can i do that ... I try your code its working to create gallery but ... did'nt get any shortcode – deemi-D-nadeem Feb 20 '17 at 11:10
  • 1
    @deemi `#image_ids` and `#thumb-wrapper` are ids of the input file and the div that show your uploaded's thumbnails. For example, this HTML code will work: `
    `
    – Kan Nguyen Mar 21 '17 at 06:58
  • 1
    @deemi My code above helps upload images and stores on post meta. If you want to use the default gallery shortcode, try this on your theme's template file: `echo do_shortcode( '[gallery ids="IMAGE_IDS"]' );` – Kan Nguyen Mar 21 '17 at 07:01
  • @KanNguyen ... thanx a lot bro ...but my issue is fixed by asking this question => `http://stackoverflow.com/questions/42344340/how-to-get-shortcode-of-wp-gallery-on-creating-gallery-in-meta-field` – deemi-D-nadeem Mar 21 '17 at 07:27
  • @KanNguyen its works fine, maybe you can say how to get attachment by url instead of id `attachment = wp.media.attachment( id );` – Tigran Babajanyan Jan 23 '18 at 05:22