Multiple images upload Theme Customizer control – 03

In my earlier post I’ve added a very basic control to the Theme Customizer.
It’s time to actually make that multiple image selector take care of those selected images.

I’ve spent quite some time trying to figure out how the Theme Customizer will actually know I’ve set some values and will save and restore them: the magic (I mean it) is Backbone-driven and the way it works is actually quite simple. Once I understood it.
The current control method flow starts from here

public function render_content()
{
    // get the set values if any
    $imageSrcs = explode(',', $this->value());
    if (!is_array($imageSrcs)) {
        $imageSrcs = array();
    }
    $this->theTitle();
    $this->theButtons();
    $this->theUploadedImages($imageSrcs);
}

and, sparing the theTitle method which is trivial in its markup, the theButtons methods reads like

public function theButtons()
{
    ?>
    <div>
        <input type="hidden" value="<?php echo $this->value(); ?>" <?php $this->link(); ?>/>
        <a href="#" class="button-secondary multi-images-upload">
            <?php echo 'Upload'; ?>
        </a>
        <a href="#" class="button-secondary multi-images-remove">
         <?php echo 'Remove images'; ?>
     </a>
 </div>
 <?php
}

aside for the evil thing that is that much mixing of PHP and HTML the method contains the first component that will allow a user to select multiple images: the hidden input field will, in fact, store the comma separated urls the media manager will provide.
The $this->link() method call will output markup like

<input type="hidden" value="" data-customize-setting-link="some_plugin[some_setting]">

and that’s what will make the current value be saved to the database under the some_plugin option in the database. The option will be an array and some_setting will be one of its keys.

Calling the media manager

Via evil ways I will print the following JavaScript code to the page

jQuery(document).ready(function($) {
    "use strict";
    var file_frame;

    // bind to click event for each upload button on the page
    jQuery('.multi-images-upload').live('click',
        function(event) {

            event.preventDefault();

            // file frame already created, return
            if (file_frame) {
                file_frame.open();
                return;
            }

            var root = $(this).parent();
            // create the file frame
            file_frame = wp.media.frames.file_frame = wp.media({
                title: jQuery(this).data('uploader_title'),
                button: jQuery(this).data('uploader_button_text'),
                multiple: true,
                library: {
                    type: 'image'
                }
            });

            // get the selected attachments
            file_frame.on('select', function() {
                var selected = file_frame.state().get('selection').toJSON(),
                    urls = [];

                // store each image url in an hidden text field
                for (var i = selected.length - 1; i >= 0; i--) {
                    var url = selected[i].url;
                    urls.push(url);
                }
                // get the input field that will store the image sources
                var store = root.find('input[type=hidden]');
                // store the new values and trigger a change
                store.val(urls).trigger('change');
            });

            // open the just created file frame
            file_frame.open();
        });
});

Which is a blatant copy of the scripts found in Mike Jolley article save for the part where the selected images urls are saved in the hidden input field value attribute and trigger the save action that will turn the Save $ Publish button on and actually save the selected urls in a comma-separated list in the database.

Show those images

I’ve gone further and the MultiImageControl::theUploadedImages will take care, via evil inline style, of showing the selected images on the page

 public function theUploadedImages($srcs = array())
 {
    $imageStyle = array('width:25%', 'height:auto;', 'padding:2px', 'box-sizing:border-box', 'float:left');
    ?>
    <div class="customize-control-content">
        <div class="thumbnails">
            <?php if (is_array($srcs)): ?>
                <?php foreach ($srcs as $src): ?>
                    <img src="<?php echo $src; ?>" style="<?php echo implode(';', $imageStyle) . ';'; ?>" alt="the imag"> 
                <?php endforeach; ?> 
            <?php endif; ?>
        </div>
    </div>
    <?php
}

This is the current output [caption id=“attachment_768” align=“aligncenter” width=“603”]Not very nice. The cats. Not very nice. The cats.[/caption]

What’s badly missing and I will implement next

Right now the control responsiveness is very 90’s meaning that once the theme user has selected some images he will need to actually reload the whole Theme Customizer, hence re-fire the PHP part of it, to see the new images in place.
I will implement the control responsiveness next to make it at least enter the 2000’s.