Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f1bc9ac
Media: Add a settings dialog to the Media Library toolbar.
t-hamano Aug 7, 2026
a98eea4
Adjust search input width
joedolson Aug 9, 2026
9251623
Switch label from implicit to explicit
joedolson Aug 9, 2026
b0bb18a
Adjust paragraph alignment & and cover narrow viewports
joedolson Aug 9, 2026
2b58600
Cast media_library_infinite_scrolling filter result to boolean
t-hamano Aug 10, 2026
a10841e
Tests: Add coverage for the Media Library settings Ajax handler
t-hamano Aug 10, 2026
3aac1c6
Tests: Follow the ajax test docblock conventions for the Media Librar…
t-hamano Aug 10, 2026
d280e56
Media: Make the infinite scrolling checkbox label state the resulting…
t-hamano Aug 10, 2026
837d3b4
Media: Scope the search field max-width to the grid mode toolbar
t-hamano Aug 10, 2026
ee61aef
Media: Drop the redundant comment on the library settings media data
t-hamano Aug 10, 2026
5421a07
Media: Send the library settings data only to users who can upload files
t-hamano Aug 10, 2026
d22db3c
Media: Let the library settings Ajax error messages reach the dialog
t-hamano Aug 10, 2026
382cdfe
Docs: Correct the Media Library settings since tags to 7.1.0
t-hamano Aug 10, 2026
e70b2c5
Media: Sync the library settings dialog with the stored value on each…
t-hamano Aug 10, 2026
f407c53
Media: Show the library settings toggle regardless of the infinite sc…
t-hamano Aug 10, 2026
49ba43d
Media: Move the library settings dialog out of the toolbar and into t…
t-hamano Aug 10, 2026
961d5b7
Docs: Trim the Media Library settings view docblocks to their summaries
t-hamano Aug 10, 2026
b67cddb
Media: Adjust the Media Library settings toggle and dialog styles
t-hamano Aug 10, 2026
dd4fe91
Media: Use Boolean() in the library settings filter check to satisfy …
t-hamano Aug 10, 2026
eb9a031
Media: Drop the redundant comment on the library settings user meta u…
t-hamano Aug 10, 2026
739c979
Media: Restore the library settings status min-height to keep the dia…
t-hamano Aug 10, 2026
2b23278
Improve button alignment on sub 782px viewport
joedolson Aug 10, 2026
c8617bc
Fix button sizing between 782 and 900 px
joedolson Aug 10, 2026
2ca898f
Media: Adjust search field and settings toggle placement in the media…
t-hamano Aug 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -1403,6 +1403,7 @@ module.exports = function(grunt) {
'src/wp-includes/js/media/views/iframe.js' : 'src/js/media/views/iframe.js',
'src/wp-includes/js/media/views/image-details.js' : 'src/js/media/views/image-details.js',
'src/wp-includes/js/media/views/label.js' : 'src/js/media/views/label.js',
'src/wp-includes/js/media/views/library-settings.js' : 'src/js/media/views/library-settings.js',
'src/wp-includes/js/media/views/media-details.js' : 'src/js/media/views/media-details.js',
'src/wp-includes/js/media/views/media-frame.js' : 'src/js/media/views/media-frame.js',
'src/wp-includes/js/media/views/menu-item.js' : 'src/js/media/views/menu-item.js',
Expand Down
1 change: 1 addition & 0 deletions src/js/_enqueues/wp/media/views.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ media.view.AttachmentFilters = require( '../../../media/views/attachment-filters
media.view.DateFilter = require( '../../../media/views/attachment-filters/date.js' );
media.view.AttachmentFilters.Uploaded = require( '../../../media/views/attachment-filters/uploaded.js' );
media.view.AttachmentFilters.All = require( '../../../media/views/attachment-filters/all.js' );
media.view.LibrarySettings = require( '../../../media/views/library-settings.js' );
media.view.AttachmentsBrowser = require( '../../../media/views/attachments/browser.js' );
media.view.Selection = require( '../../../media/views/selection.js' );
media.view.Attachment.Selection = require( '../../../media/views/attachment/selection.js' );
Expand Down
38 changes: 31 additions & 7 deletions src/js/media/views/attachments.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
var View = wp.media.View,
$ = jQuery,
Attachments,
infiniteScrolling = wp.media.view.settings.infiniteScrolling;
Attachments;

Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{
tagName: 'ul',
Expand Down Expand Up @@ -54,7 +53,7 @@ Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{
* calculating the total number of columns.
*/
_.defaults( this.options, {
infiniteScrolling: infiniteScrolling || false,
infiniteScrolling: !! wp.media.view.settings.infiniteScrolling,
refreshSensitivity: wp.media.isTouchDevice ? 300 : 200,
refreshThreshold: 3,
AttachmentView: wp.media.view.Attachment,
Expand Down Expand Up @@ -90,11 +89,12 @@ Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{

this.controller.on( 'library:selection:add', this.attachmentFocus, this );

if ( this.options.infiniteScrolling ) {
// Throttle the scroll handler and bind this.
this.scroll = _.chain( this.scroll ).bind( this ).throttle( this.options.refreshSensitivity ).value();
// Throttle the scroll handler and bind this. Done even when infinite
// scrolling is off, since it can be turned on at any time.
this.scroll = _.chain( this.scroll ).bind( this ).throttle( this.options.refreshSensitivity ).value();
this.options.scrollElement = this.options.scrollElement || this.el;

this.options.scrollElement = this.options.scrollElement || this.el;
if ( this.options.infiniteScrolling ) {
$( this.options.scrollElement ).on( 'scroll', this.scroll );
}

Expand All @@ -114,6 +114,28 @@ Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{
}
},

/**
* Turns infinite scrolling on or off after the view has been created.
*
* @since 7.1.0
*
* @param {boolean} enabled Whether to load more attachments on scroll.
*
* @return {void}
*/
setInfiniteScrolling: function( enabled ) {
this.options.infiniteScrolling = enabled;

$( this.options.scrollElement ).off( 'scroll', this.scroll );

if ( enabled ) {
$( this.options.scrollElement ).on( 'scroll', this.scroll );

// The list may already be scrolled past the point where more are loaded.
this.scroll();
}
},

/**
* Listens to the resizeEvent on the window.
*
Expand Down Expand Up @@ -231,6 +253,8 @@ Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{
*/
dispose: function() {
this.collection.props.off( null, null, this );
$( this.options.scrollElement ).off( 'scroll', this.scroll );

if ( this.options.resize ) {
this.$window.off( this.resizeEvent );
}
Expand Down
49 changes: 47 additions & 2 deletions src/js/media/views/attachments/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ var View = wp.media.View,
l10n = wp.media.view.l10n,
$ = jQuery,
AttachmentsBrowser,
infiniteScrolling = wp.media.view.settings.infiniteScrolling,
settings = wp.media.view.settings,
librarySettings = wp.media.view.settings.librarySettings,
__ = wp.i18n.__,
sprintf = wp.i18n.sprintf;

Expand Down Expand Up @@ -34,6 +35,8 @@ AttachmentsBrowser = View.extend(/** @lends wp.media.view.AttachmentsBrowser.pro
className: 'attachments-browser',

initialize: function() {
var infiniteScrolling = !! settings.infiniteScrolling;

_.defaults( this.options, {
filters: false,
search: true,
Expand All @@ -45,6 +48,7 @@ AttachmentsBrowser = View.extend(/** @lends wp.media.view.AttachmentsBrowser.pro

this.controller.on( 'toggle:upload:attachment', this.toggleUploader, this );
this.controller.on( 'edit:selection', this.editSelection );
this.controller.on( 'library:infinite-scrolling', this.setInfiniteScrolling, this );

// In the Media Library, the sidebar is used to display errors before the attachments grid.
if ( this.options.sidebar && 'errors' === this.options.sidebar ) {
Expand Down Expand Up @@ -111,6 +115,39 @@ AttachmentsBrowser = View.extend(/** @lends wp.media.view.AttachmentsBrowser.pro
this.collection.on( 'attachments:received', this.announceSearchResults, this );
},

/**
* Switches between infinite scrolling and the Load more button in place.
*
* The Load more view is created on demand and then kept, hidden by the
* `has-load-more` class, so that switching back and forth is cheap.
*
* @since 7.1.0
*
* @param {boolean} enabled Whether to load more attachments on scroll.
*
* @return {void}
*/
setInfiniteScrolling: function( enabled ) {
if ( enabled === Boolean( this.attachments.options.infiniteScrolling ) ) {
return;
}

this.attachments.setInfiniteScrolling( enabled );
this.$el.toggleClass( 'has-load-more', ! enabled );

if ( enabled ) {
this.collection.off( 'add remove reset', this.updateLoadMoreView, this );
return;
}

if ( ! this.loadMoreWrapper ) {
this.createLoadMoreView();
}

this.collection.on( 'add remove reset', this.updateLoadMoreView, this );
this.updateLoadMoreView();
},

/**
* Updates the `wp.a11y.speak()` ARIA live region with a message to communicate
* the number of search results to screen reader users. This function is
Expand All @@ -125,7 +162,7 @@ AttachmentsBrowser = View.extend(/** @lends wp.media.view.AttachmentsBrowser.pro
/* translators: Accessibility text. %d: Number of attachments found in a search. */
mediaFoundHasMoreResultsMessage = __( 'Number of media items displayed: %d. Click load more for more results.' );

if ( infiniteScrolling ) {
if ( this.attachments.options.infiniteScrolling ) {
/* translators: Accessibility text. %d: Number of attachments found in a search. */
mediaFoundHasMoreResultsMessage = __( 'Number of media items displayed: %d. Scroll the page for more results.' );
}
Expand Down Expand Up @@ -393,6 +430,14 @@ AttachmentsBrowser = View.extend(/** @lends wp.media.view.AttachmentsBrowser.pro
model: this.collection.props,
priority: 60
}).render() );

// Only for users allowed to save the preference, see `wp_enqueue_media()`.
if ( librarySettings ) {
this.toolbar.set( 'librarySettings', new wp.media.view.LibrarySettings({
controller: this.controller,
priority: 70
}).render() );
}
}

if ( this.options.dragInfo ) {
Expand Down
181 changes: 181 additions & 0 deletions src/js/media/views/library-settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
var View = wp.media.View,
settings = wp.media.view.settings,
$ = jQuery,
__ = wp.i18n.__,
LibrarySettings;

/**
* wp.media.view.LibrarySettings
*
* A toolbar control opening a modal dialog with the personal options for the
* Media Library.
*
* @since 7.1.0
*
* @memberOf wp.media.view
*
* @class
* @augments wp.media.View
* @augments wp.Backbone.View
* @augments Backbone.View
*/
LibrarySettings = View.extend(/** @lends wp.media.view.LibrarySettings.prototype */{
tagName: 'button',
className: 'button button-compact media-library-settings__toggle',
template: wp.template( 'media-library-settings-toggle' ),

attributes: {
type: 'button',
'aria-haspopup': 'dialog'
},

events: {
'click': 'open'
},

/**
* Identifies the most recent request.
*
* @type {number}
*/
requestId: 0,

initialize: function() {
// Several media frames can be attached at once, so IDs are per instance.
this.uid = _.uniqueId( 'media-library-settings-' );
},

prepare: function() {
return {
titleId: this.uid + '-title',
infiniteScrollingId: this.uid + '-infinite-scrolling'
};
},

/**
* Removes the dialog along with the view.
*
* @return {wp.media.view.LibrarySettings} Returns itself to allow chaining.
*/
dispose: function() {
if ( this.dialog ) {
$( this.dialog ).remove();
}

return View.prototype.dispose.apply( this, arguments );
},

/**
* Inserts the dialog into the frame.
*
* @return {void}
*/
createDialog: function() {
var $dialog = $( wp.template( 'media-library-settings-dialog' )( this.prepare() ) );

this.controller.$el.append( $dialog );

this.dialog = $dialog[0];
this.status = $dialog.find( '.media-library-settings__status' )[0];
this.checkbox = $dialog.find( '.media-library-settings__checkbox' )[0];

$dialog.on( 'change', '.media-library-settings__checkbox', _.bind( this.updateInfiniteScrolling, this ) );

/*
* In the media modal, `wp.media.view.Modal` closes on Escape and
* `wp.media.view.FocusManager` constrains Tab. Neither must run while the
* dialog is open: it handles both itself, and the rest of the modal is inert.
*/
$dialog.on( 'keydown', function( event ) {
event.stopPropagation();
} );
},

/**
* Opens the dialog.
*
* @return {void}
*/
open: function() {
if ( ! this.dialog ) {
this.createDialog();
}

this.checkbox.checked = !! settings.librarySettings.infiniteScrolling;

this.setStatus( '' );
this.dialog.showModal();
},

/**
* Whether a `media_library_infinite_scrolling` filter callback overrides the
* personal option.
*
* @type {boolean}
*/
isFiltered: !! settings.librarySettings &&
Boolean( settings.infiniteScrolling ) !== Boolean( settings.librarySettings.infiniteScrolling ),

/**
* Saves the "Infinite scrolling" personal option for the current user.
*
* @param {Event} event The change event of the checkbox.
* @return {void}
*/
updateInfiniteScrolling: function( event ) {
var view = this,
checkbox = event.target,
enabled = checkbox.checked,
requestId = ++this.requestId;

this.setStatus( __( 'Saving…' ) );

wp.ajax.post( 'set-media-library-settings', {
_ajax_nonce: settings.librarySettings.nonce,
infinite_scrolling: enabled ? 'true' : 'false'
} ).done( function() {
if ( requestId !== view.requestId ) {
return;
}

settings.librarySettings.infiniteScrolling = enabled ? 1 : 0;

/*
* A filter callback takes precedence over the preference, so the Media
* Library keeps the filtered behavior. Otherwise the browser this toggle
* belongs to is updated without a reload.
*/
if ( ! view.isFiltered ) {
settings.infiniteScrolling = enabled ? 1 : 0;

view.controller.trigger( 'library:infinite-scrolling', enabled );
}

view.setStatus( enabled ?
__( 'Infinite scrolling is on.' ) :
__( 'Infinite scrolling is off.' )
);
} ).fail( function( response ) {
if ( requestId !== view.requestId ) {
return;
}

// Put the checkbox back in sync with the stored value.
checkbox.checked = ! enabled;

view.setStatus( ( response && response.message ) || __( 'The setting could not be saved.' ) );
} );
},

/**
* Updates the message below the controls.
*
* @param {string} message The message to display. An empty string clears it.
* @return {void}
*/
setStatus: function( message ) {
this.status.textContent = message;
}
});

module.exports = LibrarySettings;
1 change: 1 addition & 0 deletions src/wp-admin/admin-ajax.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
'closed-postboxes',
'hidden-columns',
'update-welcome-panel',
'set-media-library-settings',
'menu-get-metabox',
'wp-link-ajax',
'menu-locations-save',
Expand Down
7 changes: 2 additions & 5 deletions src/wp-admin/css/common.css
Original file line number Diff line number Diff line change
Expand Up @@ -1121,17 +1121,14 @@ th.action-links {
.wp-filter .search-form input[type="search"] {
width: 280px;
max-width: 100%;
min-height: 32px;
padding: 0 8px;
}

.wp-filter .search-form select {
margin: 0;
}

.wp-filter .search-form input[type="search"] {
min-height: 32px;
padding: 0 8px;
}

.wp-filter .search-form select,
.wp-filter .filter-items select {
min-height: 32px;
Expand Down
Loading
Loading