[wp-trac] [WordPress Trac] #64467: Grid view displays attachments in the wrong order when an order query var is present but not normalized
WordPress Trac
noreply at wordpress.org
Sat Jan 3 17:37:18 UTC 2026
#64467: Grid view displays attachments in the wrong order when an order query var
is present but not normalized
-------------------------------------+-------------------------------------
Reporter: trivedikavit | Owner: (none)
Type: defect (bug) | Status: new
Priority: normal | Milestone: 7.0
Component: Media | Version:
Severity: minor | Resolution:
Keywords: has-screenshots | Focuses: javascript,
changes-requested | administration
-------------------------------------+-------------------------------------
Comment (by trivedikavit):
After digging further into the `Query` and `Attachments` models (thanks
@sabernhardt for pointing those out as sources), I think there is a more
fundamental root cause here and a cleaner fix than normalizing order at
individual call sites.
== What changed in my understanding ==
The initial patch (uppercasing order inside `filters.order` /
`comparator`, and defaulting to `DESC` unless `ASC`) is effective, but it
treats the symptom: it fixes only the specific places where those methods
read `this.props.get( 'order' )`.
On closer inspection, the underlying issue is that `this.props` is not
initialized consistently across different collection types / instantiation
paths. As a result, `this.props.get( 'order' )` can contain different
values depending on whether the collection is a `Query` instance or a
plain `Attachments` instance.
== The underlying inconsistency ==
==== `wp.media.model.Query.get( props )` normalizes order ====
In `Query.get()` the code:
* uppercases `props.order`
* validates it against `ASC`/`DESC`
* defaults invalid values back to the default (`DESC`)
So any `Query` created via `Query.get()` ends up with normalized
`props.order`.
{{{
// Normalize the order.
props.order = props.order.toUpperCase();
if ( 'DESC' !== props.order && 'ASC' !== props.order ) {
props.order = defaults.order.toUpperCase();
}
}}}
Reference:
https://core.trac.wordpress.org/browser/trunk/src/js/media/models/query.js?rev=51632&marks=40#L254
This is also done via `_requery` here, where if the collection is a query,
it would create and mirror a `Query` collection:
https://core.trac.wordpress.org/browser/trunk/src/js/media/models/attachments.js?rev=51191&marks=497,514#L443
==== `wp.media.model.Attachments.initialize()` does not normalize order
====
In `Attachments.initialize( models, options )`, `options.props` is applied
directly via:
{{{
this.props.set( _.defaults( options.props || {} ) );
}}}
Reference:
https://core.trac.wordpress.org/browser/trunk/src/js/media/models/attachments.js?rev=51191&marks=497,514#L47
If `options.props.order` is passed in as lowercase (e.g. 'desc') or
invalid, it can remain unnormalized in `this.props`.
Because `Query` inherits from `Attachments`, we end up with different
`this.props` states depending on how the collection is constructed:
* A `Query` instance created via `Query.get()` will have normalized
`this.props.get( 'order' )`
* An `Attachments` instance constructed with raw `options.props.order` may
not have normalized `this.props.get( 'order' )`
**This inconsistency becomes visible as a bug whenever downstream UI logic
performs case-sensitive comparisons against `DESC` / `ASC` (e.g. the
comparator branching on `'DESC' === order`), which can lead to the Grid UI
effectively sorting in the opposite direction from what the server
returned.**
== How I confirmed it ==
I added a temporary log inside the comparator to inspect the instance type
and the order value:
{{{
console.log( 'comparator in', this instanceof wp.media.model.Query ?
'Query' : 'Attachments', 'with order:', order );
}}}
For example, visiting `/wp-
admin/upload.php?mode=grid&orderby=date&order=desc` yields:
{{{
comparator in Query with order: DESC
comparator in Attachments with order: desc
}}}
== Proposed fix: normalize once at initialization ==
Instead of normalizing in every method that consumes `props.order`,
normalize at the point where props are first applied in
`Attachments.initialize()` (i.e. normalize `options.props.order` before
setting it on this.props):
{{{
options.props = options.props || {};
if ( 'string' === typeof options.props.order ) {
options.props.order = options.props.order.toUpperCase();
if ( 'ASC' !== options.props.order && 'DESC' !== options.props.order )
{
options.props.order = 'DESC';
}
}
this.props.set( options.props );
}}}
Reference (replace this line):
https://core.trac.wordpress.org/browser/trunk/src/js/media/models/attachments.js?rev=51191&marks=497,514#L47
== Testing ==
Testing with the fix in place does lead to consistent normalized `order`:
{{{
comparator in Query with order: DESC
comparator in Attachments with order: DESC
}}}
== Why this is better ==
* '''Fixes the root cause''': `this.props` starts out normalized
regardless of whether the collection is `Query` or `Attachments`.
* '''More maintainable''': avoids having to normalize order everywhere
`this.props.get( 'order' )` is referenced.
* '''Inheritance-proof''': subclasses inheriting
`Attachments.initialize()` get consistent normalization automatically.
----
Regarding the `menuOrder`:
This proposed change preserves existing behavior for valid `ASC`/`DESC`
values and improves reliability for `menuOrder` (which already relies on
`ASC` being uppercase). It only changes behavior for previously
unnormalized inputs (e.g. `asc`, `desc`, invalid strings), aligning
`Attachments` initialization with `Query.get()`’s existing
normalization/defaulting.
----
@adamsilverstein Let me know if this looks good.
--
Ticket URL: <https://core.trac.wordpress.org/ticket/64467#comment:5>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list