| 1 |
<?php |
| 2 |
/** |
| 3 |
* OpenStation: Media Library grid query cleanup. |
| 4 |
* |
| 5 |
* The Media Library grid stops live-updating after an upload when the |
| 6 |
* window's `openstation_chromeless=1` flag reaches its media query. |
| 7 |
* |
| 8 |
* `wp-admin/upload.php` seeds the grid from `$_GET`: it runs the whole |
| 9 |
* query string through `wp_edit_attachments_query_vars()`, drops a |
| 10 |
* hardcoded `mode` / `post_type` / `post_status` / `posts_per_page` |
| 11 |
* ignore list, and localizes whatever survives as |
| 12 |
* `_wpMediaGridSettings.queryVars`. Unknown keys pass straight |
| 13 |
* through, so our flag lands in the grid's `wp.media.model.Query` |
| 14 |
* args. |
| 15 |
* |
| 16 |
* That is enough to break uploads. `Query`'s constructor only calls |
| 17 |
* `this.observe( wp.Uploader.queue )` when EVERY arg is in a fixed |
| 18 |
* allowlist (`s`, `order`, `orderby`, `posts_per_page`, |
| 19 |
* `post_mime_type`, `post_parent`, `author`). Anything else means |
| 20 |
* the query has filters the client can't evaluate, so watching the |
| 21 |
* upload queue would show false positives. `openstation_chromeless` |
| 22 |
* is not in that list, the observer is never attached, and a finished |
| 23 |
* upload never enters the collection: the file lands on the server, |
| 24 |
* the grid shows nothing, and the new item only appears once the |
| 25 |
* window is reopened and the collection re-fetches. |
| 26 |
* |
| 27 |
* Core exposes no filter on that array, so the fix re-localizes |
| 28 |
* `_wpMediaGridSettings` after upload.php with our key removed. The |
| 29 |
* later assignment wins in JS, and reading back what core actually |
| 30 |
* produced (rather than recomputing it) keeps this from drifting if |
| 31 |
* core changes the shape. |
| 32 |
* |
| 33 |
* @package OpenStation |
| 34 |
*/ |
| 35 |
|
| 36 |
defined( 'ABSPATH' ) || exit; |
| 37 |
|
| 38 |
/** |
| 39 |
* Strips the chromeless flag from the Media Library grid's query vars. |
| 40 |
* |
| 41 |
* Runs late on `admin_enqueue_scripts` for two reasons: `upload.php` |
| 42 |
* localizes at file scope, before `admin-header.php` fires this hook, |
| 43 |
* and `wp_localize_script()` appends rather than replaces, so the last |
| 44 |
* writer is the one the grid sees. |
| 45 |
* |
| 46 |
* Bails silently whenever the data isn't in the shape we expect. A |
| 47 |
* grid that still doesn't refresh is a lesser failure than a grid that |
| 48 |
* doesn't render. |
| 49 |
* |
| 50 |
* @return void |
| 51 |
*/ |
| 52 |
function openstation_strip_chromeless_flag_from_media_grid() { |
| 53 |
$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; |
| 54 |
if ( ! $screen || 'upload' !== $screen->id ) { |
| 55 |
return; |
| 56 |
} |
| 57 |
|
| 58 |
$scripts = wp_scripts(); |
| 59 |
$data = $scripts->get_data( 'media-grid', 'data' ); |
| 60 |
if ( ! is_string( $data ) || '' === $data ) { |
| 61 |
return; |
| 62 |
} |
| 63 |
|
| 64 |
// `WP_Scripts::localize()` writes one `var <name> = <json>;` |
| 65 |
// statement per call, newline-joined. Take the last one: that's |
| 66 |
// the value currently winning at runtime. |
| 67 |
if ( ! preg_match_all( '/^var _wpMediaGridSettings = (.+);$/m', $data, $matches ) ) { |
| 68 |
return; |
| 69 |
} |
| 70 |
|
| 71 |
// Decoded as objects, not associative arrays. An empty JSON object |
| 72 |
// round-tripped through an array comes back out as `[]`, and the |
| 73 |
// grid reads `queryVars` by key. Decoding to stdClass keeps every |
| 74 |
// nested object an object, however many core grows. |
| 75 |
// |
| 76 |
// `queryVars` is core's key, so the snake_case property sniff has |
| 77 |
// nothing to say about it that we can act on. |
| 78 |
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase |
| 79 |
$settings = json_decode( end( $matches[1] ) ); |
| 80 |
if ( ! $settings instanceof stdClass || ! isset( $settings->queryVars ) || ! $settings->queryVars instanceof stdClass ) { |
| 81 |
return; |
| 82 |
} |
| 83 |
|
| 84 |
if ( ! isset( $settings->queryVars->openstation_chromeless ) ) { |
| 85 |
return; |
| 86 |
} |
| 87 |
|
| 88 |
unset( $settings->queryVars->openstation_chromeless ); |
| 89 |
// phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase |
| 90 |
|
| 91 |
wp_localize_script( 'media-grid', '_wpMediaGridSettings', (array) $settings ); |
| 92 |
} |
| 93 |
add_action( 'admin_enqueue_scripts', 'openstation_strip_chromeless_flag_from_media_grid', 999 ); |
| 94 |
|