├── .eslintignore
├── .eslintrc
├── .gitignore
├── .gitmodules
├── .jscsrc
├── .jshintignore
├── .jshintrc
├── .travis.yml
├── README.md
├── css
└── customize-image-gallery-control.css
├── customize-image-gallery-control.php
├── js
└── customize-image-gallery-control.js
├── package.json
├── php
├── class-control.php
└── class-plugin.php
├── phpcs.ruleset.xml
├── tests
├── php
│ ├── test-class-control.php
│ └── test-class-plugin.php
└── test-customize-image-gallery-control.php
└── wp-assets
└── screenshot-1.png
/.eslintignore:
--------------------------------------------------------------------------------
1 | dev-lib/.eslintignore
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | dev-lib/.eslintrc
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "dev-lib"]
2 | path = dev-lib
3 | url = https://github.com/xwp/wp-dev-lib.git
4 |
--------------------------------------------------------------------------------
/.jscsrc:
--------------------------------------------------------------------------------
1 | dev-lib/.jscsrc
--------------------------------------------------------------------------------
/.jshintignore:
--------------------------------------------------------------------------------
1 | **/*.min.js
2 | **/node_modules/**
3 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | dev-lib/.jshintrc
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 |
3 | language:
4 | - php
5 | - node_js
6 |
7 | php:
8 | - 5.4
9 | - 7.0
10 |
11 | env:
12 | - WP_VERSION=latest WP_MULTISITE=0
13 | - WP_VERSION=latest WP_MULTISITE=1
14 | - WP_VERSION=trunk WP_MULTISITE=0
15 | - WP_VERSION=trunk WP_MULTISITE=1
16 |
17 | install:
18 | - export DEV_LIB_PATH=dev-lib
19 | - if [ ! -e "$DEV_LIB_PATH" ] && [ -L .travis.yml ]; then export DEV_LIB_PATH=$( dirname $( readlink .travis.yml ) ); fi
20 | - if [ ! -e "$DEV_LIB_PATH" ]; then git clone https://github.com/xwp/wp-dev-lib.git $DEV_LIB_PATH; fi
21 | - source $DEV_LIB_PATH/travis.install.sh
22 |
23 | script:
24 | - source $DEV_LIB_PATH/travis.script.sh
25 |
26 | after_script:
27 | - source $DEV_LIB_PATH/travis.after_script.sh
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Customize Image Gallery Control
2 |
3 | Adds Customizer support for image gallery control type.
4 |
5 | ## Description ##
6 | Adds new Customizer control type `image_gallery` by extending WP_Customize_Control class. Allows choosing multiple images from Media Library, saves the ID-s as an array.
7 | Displays icons of the images in Customizer.
8 |
9 | Requires PHP 5.3+
10 |
11 | ## Screenshots ##
12 |
13 | 
14 |
--------------------------------------------------------------------------------
/css/customize-image-gallery-control.css:
--------------------------------------------------------------------------------
1 | .image-gallery-attachments {
2 | background: #fff;
3 | float: left;
4 | clear: both;
5 | }
6 |
7 | .image-gallery-thumbnail-wrapper {
8 | float: left;
9 | width: 19%;
10 | height: 45px;
11 | padding: 0.5%;
12 | overflow: hidden;
13 | }
14 |
15 | .image-gallery-thumbnail-wrapper img {
16 | height: auto;
17 | width: 100%;
18 | float: left;
19 | }
20 |
--------------------------------------------------------------------------------
/customize-image-gallery-control.php:
--------------------------------------------------------------------------------
1 | =' ) ) {
16 | require_once __DIR__ . '/php/class-plugin.php';
17 | $class = 'CustomizeImageGalleryControl\\Plugin';
18 | $customize_image_gallery_control_plugin = new $class();
19 | add_action( 'plugins_loaded', array( $customize_image_gallery_control_plugin, 'init' ) );
20 | } else {
21 | if ( defined( 'WP_CLI' ) ) {
22 | WP_CLI::warning( _customize_image_gallery_control_php_version_text() );
23 | } else {
24 | add_action( 'admin_notices', '_customize_image_gallery_control_php_version_error' );
25 | }
26 | }
27 |
28 | /**
29 | * Admin notice for incompatible versions of PHP.
30 | */
31 | function _customize_image_gallery_control_php_version_error() {
32 | printf( '
', esc_html( _customize_image_gallery_control_php_version_text() ) );
33 | }
34 |
35 | /**
36 | * String describing the minimum PHP version.
37 | *
38 | * @return string
39 | */
40 | function _customize_image_gallery_control_php_version_text() {
41 | return __( 'Customize Image Gallery Control plugin error: Your version of PHP is too old to run this plugin. You must be running PHP 5.3 or higher.', 'customize-image-gallery-control' );
42 | }
43 |
--------------------------------------------------------------------------------
/js/customize-image-gallery-control.js:
--------------------------------------------------------------------------------
1 | /* global wp, JSON */
2 | /* eslint consistent-this: [ "error", "control" ] */
3 | /* eslint complexity: ["error", 8] */
4 |
5 | (function( api, $ ) {
6 | 'use strict';
7 |
8 | /**
9 | * An image gallery control.
10 | *
11 | * @class
12 | * @augments wp.customize.Control
13 | * @augments wp.customize.Class
14 | */
15 | api.ImageGalleryControl = api.Control.extend({
16 | initialize: function( id, options ) {
17 | var control = this, args;
18 |
19 | args = options || {};
20 |
21 | if ( ! args.params.file_type ) {
22 | args.params.file_type = 'image';
23 | }
24 |
25 | if ( ! args.params.type ) {
26 | args.params.type = 'image_gallery';
27 | }
28 | if ( ! args.params.content ) {
29 | args.params.content = $( '' );
30 | args.params.content.attr( 'id', 'customize-control-' + id.replace( /]/g, '' ).replace( /\[/g, '-' ) );
31 | args.params.content.attr( 'class', 'customize-control customize-control-' + args.params.type );
32 | }
33 |
34 | if ( ! args.params.attachments ) {
35 | args.params.attachments = [];
36 | }
37 |
38 | api.Control.prototype.initialize.call( control, id, args );
39 | },
40 |
41 | /**
42 | * When the control's DOM structure is ready,
43 | * set up internal event bindings.
44 | */
45 | ready: function() {
46 | var control = this;
47 | // Shortcut so that we don't have to use _.bind every time we add a callback.
48 | _.bindAll( control, 'openFrame', 'select' );
49 |
50 | /**
51 | * Set gallery data and render content.
52 | */
53 | function setGalleryDataAndRenderContent() {
54 |
55 | var value = control.setting.get();
56 | control.setAttachmentsData( value ).done( function() {
57 | control.renderContent();
58 | control.setupSortable();
59 | } );
60 | }
61 |
62 | // Ensure attachment data is initially set.
63 | setGalleryDataAndRenderContent();
64 |
65 | // Update the attachment data and re-render the control when the setting changes.
66 | control.setting.bind( setGalleryDataAndRenderContent );
67 |
68 | // Bind events.
69 | control.container.on( 'click keydown', '.upload-button', control.openFrame );
70 | },
71 |
72 | /**
73 | * Fetch attachment data for rendering in control content.
74 | *
75 | * @param {Array} value Setting value, array of attachment ids.
76 | * @returns {*}
77 | */
78 | setAttachmentsData: function( value ) {
79 | var control = this,
80 | promises = [];
81 |
82 | control.params.attachments = [];
83 |
84 | _.each( value, function( id, index ) {
85 | var hasAttachmentData = new $.Deferred();
86 | wp.media.attachment( id ).fetch().done( function() {
87 | control.params.attachments[ index ] = this.attributes;
88 | hasAttachmentData.resolve();
89 | } );
90 | promises.push( hasAttachmentData );
91 | } );
92 |
93 | return $.when.apply( undefined, promises ).promise();
94 | },
95 |
96 | /**
97 | * Open the media modal.
98 | */
99 | openFrame: function( event ) {
100 | event.preventDefault();
101 |
102 | if ( ! this.frame ) {
103 | this.initFrame();
104 | }
105 |
106 | this.frame.open();
107 | },
108 |
109 | /**
110 | * Initiate the media modal select frame.
111 | * Save it for using later in case needed.
112 | */
113 | initFrame: function() {
114 |
115 | var control = this, preSelectImages;
116 | this.frame = wp.media({
117 |
118 | button: {
119 | text: control.params.button_labels.frame_button
120 | },
121 | states: [
122 | new wp.media.controller.Library({
123 | title: control.params.button_labels.frame_title,
124 | library: wp.media.query({ type: control.params.file_type }),
125 | multiple: 'add'
126 | })
127 | ]
128 | });
129 |
130 | /**
131 | * Pre-select images according to saved settings.
132 | */
133 | preSelectImages = function() {
134 | var selection, ids, attachment, library;
135 |
136 | library = control.frame.state().get( 'library' );
137 | selection = control.frame.state().get( 'selection' );
138 |
139 | ids = control.setting.get();
140 |
141 | // Sort the selected images to top when opening media modal.
142 | library.comparator = function( a, b ) {
143 | var hasA = true === this.mirroring.get( a.cid ),
144 | hasB = true === this.mirroring.get( b.cid );
145 |
146 | if ( ! hasA && hasB ) {
147 | return -1;
148 | } else if ( hasA && ! hasB ) {
149 | return 1;
150 | } else {
151 | return 0;
152 | }
153 | };
154 |
155 | _.each( ids, function( id ) {
156 | attachment = wp.media.attachment( id );
157 | selection.add( attachment ? [ attachment ] : [] );
158 | library.add( attachment ? [ attachment ] : [] );
159 | });
160 | };
161 | control.frame.on( 'open', preSelectImages );
162 | control.frame.on( 'select', control.select );
163 | },
164 |
165 | /**
166 | * Callback for selecting attachments.
167 | */
168 | select: function() {
169 |
170 | var control = this, attachments, attachmentIds;
171 |
172 | attachments = control.frame.state().get( 'selection' ).toJSON();
173 | control.params.attachments = attachments;
174 |
175 | attachmentIds = control.getAttachmentIds( attachments );
176 | control.setSettingValues( attachmentIds );
177 | },
178 |
179 | /**
180 | * Get array of attachment id-s from attachment objects.
181 | *
182 | * @param {Array} attachments Attachments.
183 | * @returns {Array}
184 | */
185 | getAttachmentIds: function( attachments ) {
186 | var ids = [], i;
187 | for ( i in attachments ) {
188 | ids.push( attachments[ i ].id );
189 | }
190 | return ids;
191 | },
192 |
193 | /**
194 | * Set setting values.
195 | *
196 | * @param {Array} values Array of ids.
197 | */
198 | setSettingValues: function( values ) {
199 | var control = this;
200 | control.setting.set( values );
201 | },
202 |
203 | /**
204 | * Setup sortable.
205 | *
206 | * @returns {void}
207 | */
208 | setupSortable: function() {
209 | var control = this,
210 | list = $( '.image-gallery-attachments' );
211 | list.sortable({
212 | items: '.image-gallery-thumbnail-wrapper',
213 | tolerance: 'pointer',
214 | stop: function() {
215 | var selectedValues = [];
216 | list.find( '.image-gallery-thumbnail-wrapper' ).each( function() {
217 | var id;
218 | id = parseInt( $( this ).data( 'postId' ), 10 );
219 | selectedValues.push( id );
220 | } );
221 | control.setSettingValues( selectedValues );
222 | }
223 | });
224 | }
225 |
226 | });
227 |
228 | api.controlConstructor['image_gallery'] = api.ImageGalleryControl;
229 |
230 | })( wp.customize, jQuery );
231 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "customize-image-gallery-control",
3 | "version": "0.1.0",
4 | "description": "",
5 | "scripts": {
6 | "test": "echo \"Error: no test specified\" && exit 1"
7 | },
8 | "repository": {
9 | "type": "git",
10 | "url": "git+https://github.com/xwp/wp-customize-image-gallery-control.git"
11 | },
12 | "bugs": {
13 | "url": "https://github.com/xwp/wp-customize-image-gallery-control/issues"
14 | },
15 | "homepage": "https://github.com/xwp/wp-customize-image-gallery-control#readme",
16 | "devDependencies": {
17 | "eslint": "^2.13.1"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/php/class-control.php:
--------------------------------------------------------------------------------
1 | button_labels = wp_parse_args( $this->button_labels, array(
50 | 'select' => __( 'Select Images', 'customize-image-gallery-control' ),
51 | 'change' => __( 'Modify Gallery', 'customize-image-gallery-control' ),
52 | 'default' => __( 'Default', 'customize-image-gallery-control' ),
53 | 'remove' => __( 'Remove', 'customize-image-gallery-control' ),
54 | 'placeholder' => __( 'No images selected', 'customize-image-gallery-control' ),
55 | 'frame_title' => __( 'Select Gallery Images', 'customize-image-gallery-control' ),
56 | 'frame_button' => __( 'Choose Images', 'customize-image-gallery-control' ),
57 | ) );
58 | }
59 |
60 | /**
61 | * An Underscore (JS) template for this control's content (but not its container).
62 | *
63 | * Class variables for this control class are available in the `data` JS object;
64 | * export custom variables by overriding {@see WP_Customize_Control::to_json()}.
65 | *
66 | * @see WP_Customize_Control::print_template()
67 | */
68 | protected function content_template() {
69 | $data = $this->json();
70 | ?>
71 | <#
72 |
73 | _.defaults( data, );
74 | data.input_id = 'input-' + String( Math.random() );
75 | #>
76 |
77 | <# if ( data.attachments ) { #>
78 |
79 | <# _.each( data.attachments, function( attachment ) { #>
80 |
81 |

82 |
83 | <# } ) #>
84 |
85 | <# } #>
86 |
87 |
88 |
89 |
90 |
91 | json['label'] = html_entity_decode( $this->label, ENT_QUOTES, get_bloginfo( 'charset' ) );
109 | $this->json['file_type'] = $this->file_type;
110 | $this->json['button_labels'] = $this->button_labels;
111 | }
112 |
113 | }
114 |
--------------------------------------------------------------------------------
/php/class-plugin.php:
--------------------------------------------------------------------------------
1 | version = $matches[1];
32 | }
33 | }
34 |
35 | /**
36 | * Initialize.
37 | */
38 | function init() {
39 |
40 | add_action( 'wp_default_styles', array( $this, 'register_styles' ), 100 );
41 | add_action( 'wp_default_scripts', array( $this, 'register_scripts' ), 100 );
42 | add_action( 'customize_register', array( $this, 'customize_register' ), 9 );
43 | add_action( 'customize_controls_enqueue_scripts', array( $this, 'customize_controls_enqueue_scripts' ) );
44 | }
45 |
46 | /**
47 | * Load theme and plugin compatibility classes.
48 | *
49 | * @param \WP_Customize_Manager $wp_customize Manager.
50 | */
51 | function customize_register( \WP_Customize_Manager $wp_customize ) {
52 | require_once __DIR__ . '/class-control.php';
53 | $wp_customize->register_control_type( __NAMESPACE__ . '\\Control' );
54 | }
55 |
56 | /**
57 | * Register styles.
58 | *
59 | * @param \WP_Styles $wp_styles Styles.
60 | */
61 | public function register_styles( \WP_Styles $wp_styles ) {
62 |
63 | $handle = 'customize-image-gallery-control';
64 | $src = plugins_url( 'css/customize-image-gallery-control.css', dirname( __FILE__ ) );
65 | $deps = array( 'customize-controls' );
66 | $wp_styles->add( $handle, $src, $deps, $this->version );
67 | }
68 |
69 | /**
70 | * Register scripts.
71 | *
72 | * @param \WP_Scripts $wp_scripts Scripts.
73 | */
74 | public function register_scripts( \WP_Scripts $wp_scripts ) {
75 | $handle = 'customize-image-gallery-control';
76 | $src = plugins_url( 'js/customize-image-gallery-control.js', dirname( __FILE__ ) );
77 | $deps = array( 'jquery', 'customize-controls' );
78 | $in_footer = 1;
79 | $wp_scripts->add( $handle, $src, $deps, $this->version, $in_footer );
80 | }
81 |
82 | /**
83 | * Enqueue controls scripts.
84 | */
85 | public function customize_controls_enqueue_scripts() {
86 | wp_enqueue_script( 'customize-image-gallery-control' );
87 | wp_enqueue_style( 'customize-image-gallery-control' );
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/phpcs.ruleset.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | 0
13 |
14 |
15 | */dev-lib/*
16 | */node_modules/*
17 |
18 |
--------------------------------------------------------------------------------
/tests/php/test-class-control.php:
--------------------------------------------------------------------------------
1 | wp_customizer = new \WP_Customize_Manager();
38 | $this->plugin = new Plugin();
39 | $this->plugin->customize_register( $this->wp_customizer );
40 | }
41 | /**
42 | * Test constructor
43 | */
44 | public function test_construct() {
45 | $control = new Control( $this->wp_customizer, 'no-setting', array() );
46 | $this->assertTrue( 'image_gallery' === $control->type );
47 | $this->assertTrue( 'image' === $control->file_type );
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/tests/php/test-class-plugin.php:
--------------------------------------------------------------------------------
1 | init();
25 |
26 | $this->assertEquals( 100, has_action( 'wp_default_styles', array( $plugin, 'register_styles' ) ) );
27 | $this->assertEquals( 100, has_action( 'wp_default_scripts', array( $plugin, 'register_scripts' ) ) );
28 | $this->assertEquals( 9, has_action( 'customize_register', array( $plugin, 'customize_register' ) ) );
29 | $this->assertEquals( 10, has_action( 'customize_controls_enqueue_scripts', array( $plugin, 'customize_controls_enqueue_scripts' ) ) );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/test-customize-image-gallery-control.php:
--------------------------------------------------------------------------------
1 | assertContains( '', $buffer );
27 | }
28 |
29 | /**
30 | * Test PHP version error text.
31 | *
32 | * @see customize_snapshots_php_version_text()
33 | */
34 | function test_customize_image_gallery_control_php_version_text() {
35 | $this->assertContains( 'Customize Image Gallery Control plugin error:', _customize_image_gallery_control_php_version_text() );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/wp-assets/screenshot-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xwp/wp-customize-image-gallery-control/edcbdfbb1abfba110868aa34d0cbf4ad4bef77fd/wp-assets/screenshot-1.png
--------------------------------------------------------------------------------