run:R W Run
15.41 KB
2026-03-11 16:18:51
R W Run
5.45 KB
2026-03-11 16:18:51
R W Run
4.18 KB
2026-03-11 16:18:51
R W Run
1.41 KB
2026-03-11 16:18:51
R W Run
10.11 KB
2026-03-11 16:18:51
R W Run
3.68 KB
2026-03-11 16:18:51
R W Run
5.34 KB
2026-03-11 16:18:51
R W Run
1.98 KB
2026-03-11 16:18:51
R W Run
6.86 KB
2026-03-11 16:18:51
R W Run
2.64 KB
2026-03-11 16:18:51
R W Run
41.86 KB
2026-03-11 16:18:51
R W Run
13.91 KB
2026-03-11 16:18:51
R W Run
17.63 KB
2026-03-11 16:18:51
R W Run
5.72 KB
2026-03-11 16:18:51
R W Run
error_log
📄media-gallery-widget.js
1/**
2 * @output wp-admin/js/widgets/media-gallery-widget.js
3 */
4
5/* eslint consistent-this: [ "error", "control" ] */
6(function( component ) {
7 'use strict';
8
9 var GalleryWidgetModel, GalleryWidgetControl, GalleryDetailsMediaFrame;
10
11 /**
12 * Custom gallery details frame.
13 *
14 * @since 4.9.0
15 * @class wp.mediaWidgets~GalleryDetailsMediaFrame
16 * @augments wp.media.view.MediaFrame.Post
17 */
18 GalleryDetailsMediaFrame = wp.media.view.MediaFrame.Post.extend(/** @lends wp.mediaWidgets~GalleryDetailsMediaFrame.prototype */{
19
20 /**
21 * Create the default states.
22 *
23 * @since 4.9.0
24 * @return {void}
25 */
26 createStates: function createStates() {
27 this.states.add([
28 new wp.media.controller.Library({
29 id: 'gallery',
30 title: wp.media.view.l10n.createGalleryTitle,
31 priority: 40,
32 toolbar: 'main-gallery',
33 filterable: 'uploaded',
34 multiple: 'add',
35 editable: true,
36
37 library: wp.media.query( _.defaults({
38 type: 'image'
39 }, this.options.library ) )
40 }),
41
42 // Gallery states.
43 new wp.media.controller.GalleryEdit({
44 library: this.options.selection,
45 editing: this.options.editing,
46 menu: 'gallery'
47 }),
48
49 new wp.media.controller.GalleryAdd()
50 ]);
51 }
52 } );
53
54 /**
55 * Gallery widget model.
56 *
57 * See WP_Widget_Gallery::enqueue_admin_scripts() for amending prototype from PHP exports.
58 *
59 * @since 4.9.0
60 *
61 * @class wp.mediaWidgets.modelConstructors.media_gallery
62 * @augments wp.mediaWidgets.MediaWidgetModel
63 */
64 GalleryWidgetModel = component.MediaWidgetModel.extend(/** @lends wp.mediaWidgets.modelConstructors.media_gallery.prototype */{} );
65
66 GalleryWidgetControl = component.MediaWidgetControl.extend(/** @lends wp.mediaWidgets.controlConstructors.media_gallery.prototype */{
67
68 /**
69 * View events.
70 *
71 * @since 4.9.0
72 * @type {object}
73 */
74 events: _.extend( {}, component.MediaWidgetControl.prototype.events, {
75 'click .media-widget-gallery-preview': 'editMedia'
76 } ),
77
78 /**
79 * Gallery widget control.
80 *
81 * See WP_Widget_Gallery::enqueue_admin_scripts() for amending prototype from PHP exports.
82 *
83 * @constructs wp.mediaWidgets.controlConstructors.media_gallery
84 * @augments wp.mediaWidgets.MediaWidgetControl
85 *
86 * @since 4.9.0
87 * @param {Object} options - Options.
88 * @param {Backbone.Model} options.model - Model.
89 * @param {jQuery} options.el - Control field container element.
90 * @param {jQuery} options.syncContainer - Container element where fields are synced for the server.
91 * @return {void}
92 */
93 initialize: function initialize( options ) {
94 var control = this;
95
96 component.MediaWidgetControl.prototype.initialize.call( control, options );
97
98 _.bindAll( control, 'updateSelectedAttachments', 'handleAttachmentDestroy' );
99 control.selectedAttachments = new wp.media.model.Attachments();
100 control.model.on( 'change:ids', control.updateSelectedAttachments );
101 control.selectedAttachments.on( 'change', control.renderPreview );
102 control.selectedAttachments.on( 'reset', control.renderPreview );
103 control.updateSelectedAttachments();
104
105 /*
106 * Refresh a Gallery widget partial when the user modifies one of the selected attachments.
107 * This ensures that when an attachment's caption is updated in the media modal the Gallery
108 * widget in the preview will then be refreshed to show the change. Normally doing this
109 * would not be necessary because all of the state should be contained inside the changeset,
110 * as everything done in the Customizer should not make a change to the site unless the
111 * changeset itself is published. Attachments are a current exception to this rule.
112 * For a proposal to include attachments in the customized state, see #37887.
113 */
114 if ( wp.customize && wp.customize.previewer ) {
115 control.selectedAttachments.on( 'change', function() {
116 wp.customize.previewer.send( 'refresh-widget-partial', control.model.get( 'widget_id' ) );
117 } );
118 }
119 },
120
121 /**
122 * Update the selected attachments if necessary.
123 *
124 * @since 4.9.0
125 * @return {void}
126 */
127 updateSelectedAttachments: function updateSelectedAttachments() {
128 var control = this, newIds, oldIds, removedIds, addedIds, addedQuery;
129
130 newIds = control.model.get( 'ids' );
131 oldIds = _.pluck( control.selectedAttachments.models, 'id' );
132
133 removedIds = _.difference( oldIds, newIds );
134 _.each( removedIds, function( removedId ) {
135 control.selectedAttachments.remove( control.selectedAttachments.get( removedId ) );
136 });
137
138 addedIds = _.difference( newIds, oldIds );
139 if ( addedIds.length ) {
140 addedQuery = wp.media.query({
141 order: 'ASC',
142 orderby: 'post__in',
143 perPage: -1,
144 post__in: newIds,
145 query: true,
146 type: 'image'
147 });
148 addedQuery.more().done( function() {
149 control.selectedAttachments.reset( addedQuery.models );
150 });
151 }
152 },
153
154 /**
155 * Render preview.
156 *
157 * @since 4.9.0
158 * @return {void}
159 */
160 renderPreview: function renderPreview() {
161 var control = this, previewContainer, previewTemplate, data;
162
163 previewContainer = control.$el.find( '.media-widget-preview' );
164 previewTemplate = wp.template( 'wp-media-widget-gallery-preview' );
165
166 data = control.previewTemplateProps.toJSON();
167 data.attachments = {};
168 control.selectedAttachments.each( function( attachment ) {
169 data.attachments[ attachment.id ] = attachment.toJSON();
170 } );
171
172 previewContainer.html( previewTemplate( data ) );
173 },
174
175 /**
176 * Determine whether there are selected attachments.
177 *
178 * @since 4.9.0
179 * @return {boolean} Selected.
180 */
181 isSelected: function isSelected() {
182 var control = this;
183
184 if ( control.model.get( 'error' ) ) {
185 return false;
186 }
187
188 return control.model.get( 'ids' ).length > 0;
189 },
190
191 /**
192 * Open the media select frame to edit images.
193 *
194 * @since 4.9.0
195 * @return {void}
196 */
197 editMedia: function editMedia() {
198 var control = this, selection, mediaFrame, mediaFrameProps;
199
200 selection = new wp.media.model.Selection( control.selectedAttachments.models, {
201 multiple: true
202 });
203
204 mediaFrameProps = control.mapModelToMediaFrameProps( control.model.toJSON() );
205 selection.gallery = new Backbone.Model( mediaFrameProps );
206 if ( mediaFrameProps.size ) {
207 control.displaySettings.set( 'size', mediaFrameProps.size );
208 }
209 mediaFrame = new GalleryDetailsMediaFrame({
210 frame: 'manage',
211 text: control.l10n.add_to_widget,
212 selection: selection,
213 mimeType: control.mime_type,
214 selectedDisplaySettings: control.displaySettings,
215 showDisplaySettings: control.showDisplaySettings,
216 metadata: mediaFrameProps,
217 editing: true,
218 multiple: true,
219 state: 'gallery-edit'
220 });
221 wp.media.frame = mediaFrame; // See wp.media().
222
223 // Handle selection of a media item.
224 mediaFrame.on( 'update', function onUpdate( newSelection ) {
225 var state = mediaFrame.state(), resultSelection;
226
227 resultSelection = newSelection || state.get( 'selection' );
228 if ( ! resultSelection ) {
229 return;
230 }
231
232 // Copy orderby_random from gallery state.
233 if ( resultSelection.gallery ) {
234 control.model.set( control.mapMediaToModelProps( resultSelection.gallery.toJSON() ) );
235 }
236
237 // Directly update selectedAttachments to prevent needing to do additional request.
238 control.selectedAttachments.reset( resultSelection.models );
239
240 // Update models in the widget instance.
241 control.model.set( {
242 ids: _.pluck( resultSelection.models, 'id' )
243 } );
244 } );
245
246 mediaFrame.$el.addClass( 'media-widget' );
247 mediaFrame.open();
248
249 if ( selection ) {
250 selection.on( 'destroy', control.handleAttachmentDestroy );
251 }
252 },
253
254 /**
255 * Open the media select frame to chose an item.
256 *
257 * @since 4.9.0
258 * @return {void}
259 */
260 selectMedia: function selectMedia() {
261 var control = this, selection, mediaFrame, mediaFrameProps;
262 selection = new wp.media.model.Selection( control.selectedAttachments.models, {
263 multiple: true
264 });
265
266 mediaFrameProps = control.mapModelToMediaFrameProps( control.model.toJSON() );
267 if ( mediaFrameProps.size ) {
268 control.displaySettings.set( 'size', mediaFrameProps.size );
269 }
270 mediaFrame = new GalleryDetailsMediaFrame({
271 frame: 'select',
272 text: control.l10n.add_to_widget,
273 selection: selection,
274 mimeType: control.mime_type,
275 selectedDisplaySettings: control.displaySettings,
276 showDisplaySettings: control.showDisplaySettings,
277 metadata: mediaFrameProps,
278 state: 'gallery'
279 });
280 wp.media.frame = mediaFrame; // See wp.media().
281
282 // Handle selection of a media item.
283 mediaFrame.on( 'update', function onUpdate( newSelection ) {
284 var state = mediaFrame.state(), resultSelection;
285
286 resultSelection = newSelection || state.get( 'selection' );
287 if ( ! resultSelection ) {
288 return;
289 }
290
291 // Copy orderby_random from gallery state.
292 if ( resultSelection.gallery ) {
293 control.model.set( control.mapMediaToModelProps( resultSelection.gallery.toJSON() ) );
294 }
295
296 // Directly update selectedAttachments to prevent needing to do additional request.
297 control.selectedAttachments.reset( resultSelection.models );
298
299 // Update widget instance.
300 control.model.set( {
301 ids: _.pluck( resultSelection.models, 'id' )
302 } );
303 } );
304
305 mediaFrame.$el.addClass( 'media-widget' );
306 mediaFrame.open();
307
308 if ( selection ) {
309 selection.on( 'destroy', control.handleAttachmentDestroy );
310 }
311
312 /*
313 * Make sure focus is set inside of modal so that hitting Esc will close
314 * the modal and not inadvertently cause the widget to collapse in the customizer.
315 */
316 mediaFrame.$el.find( ':focusable:first' ).focus();
317 },
318
319 /**
320 * Clear the selected attachment when it is deleted in the media select frame.
321 *
322 * @since 4.9.0
323 * @param {wp.media.models.Attachment} attachment - Attachment.
324 * @return {void}
325 */
326 handleAttachmentDestroy: function handleAttachmentDestroy( attachment ) {
327 var control = this;
328 control.model.set( {
329 ids: _.difference(
330 control.model.get( 'ids' ),
331 [ attachment.id ]
332 )
333 } );
334 }
335 } );
336
337 // Exports.
338 component.controlConstructors.media_gallery = GalleryWidgetControl;
339 component.modelConstructors.media_gallery = GalleryWidgetModel;
340
341})( wp.mediaWidgets );
342