Conversation
Detect QM 4.0+ via the QM_VERSION constant and load the collector-based integration. Fall back to the existing HTML output override for QM 3.x.
23cbf68 to
7755e17
Compare
Register a custom QM collector that extracts SQLite queries from $wpdb->queries, re-indexed to match QM's rendered row order, and a client-side HTML outputter that emits the inline JS module used by the QM 4.0 shadow DOM integration. QM auto-serializes the collector data into window.QueryMonitorData.data.sqlite.
691a188 to
ab2e2ea
Compare
Inject <details> elements into QM 4.0's Preact-rendered DB queries panel inside the shadow DOM. Waits for DOMContentLoaded so QM has attached the shadow root, then uses a debounced MutationObserver to re-inject after panel switches and re-renders.
Add separate test cases for QM 3.x (server-side HTML) and QM 4.0+ (Preact shadow DOM). Each test auto-skips when the other QM version is detected.
plugin.php → qm3.php (QM 3.x server-side HTML override) collector.php → qm4.php (QM 4.0+ collector and JS injection)
ab2e2ea to
567490f
Compare
ashfame
left a comment
There was a problem hiding this comment.
Clean and well-architected PR. The QM 3.x/4.0 split is sound, the SQL-text-based matching is a smart approach for surviving Preact re-renders, and the E2E tests are thorough. Left a few minor notes inline — nothing blocking.
| $mapped[ $sql ] = array_column( $query['sqlite_queries'], 'sql' ); | ||
| } | ||
| } | ||
| $this->data->queries = $mapped; |
There was a problem hiding this comment.
Nit: Setting ->queries dynamically on $this->data could trigger a PHP 8.2+ "Creation of dynamic property" deprecation if QM 4.0's base data object isn't a plain stdClass. It may be worth defining a small SQLite_QM_Data extends QM_Data class with a typed $queries property to be safe.
| new MutationObserver( () => { | ||
| clearTimeout( timer ); | ||
| timer = setTimeout( () => inject( shadowRoot, sqliteData ), 100 ); | ||
| } ).observe( shadowRoot, { childList: true, subtree: true } ); |
There was a problem hiding this comment.
Minor: The observer watches the entire shadow root subtree, so any QM panel interaction (not just DB queries) triggers a re-injection cycle. Since inject() early-exits when #qm-db_queries isn't found the overhead is minimal, but if the panel element is stable in the DOM, scoping the observer to it would cut down on unnecessary callbacks.
There was a problem hiding this comment.
The observer needs to watch the full shadow root because #qm-db_queries doesn't exist until the user navigates to the Database Queries tab — scoping to it would miss its creation. The early-exit in inject() keeps the overhead negligible.
| }; | ||
| } ); | ||
| expect( counts.rows ).toBeGreaterThan( 0 ); | ||
| expect( counts.details ).toBe( counts.rows ); |
There was a problem hiding this comment.
Nit: This asserts that every visible row after the get_option filter has an SQLite <details> element. It holds today because all DB queries on SQLite carry sqlite_queries metadata, but it could become fragile if QM ever injects synthetic/internal rows into the table. Low risk — just flagging for awareness.
Define SQLite_QM_Data with a typed $queries property instead of relying on dynamic property assignment on QM_Data_Fallback. This aligns with QM 4.0's QM_DataCollector pattern and avoids depending on #[AllowDynamicProperties].
Summary
Query Monitor 4.0 switched from server-side PHP rendering to client-side Preact rendering inside a shadow DOM. This broke the existing SQLite query display integration, which overrides
output_query_row()— a method that QM 4.0 no longer calls.This PR adds QM 4.0 support while maintaining backward compatibility with QM 3.x:
boot.phpusingQM_VERSIONto choose between QM 3.x and 4.0+ integration paths.qm4.php) that extracts SQLite queries from$wpdb->queries. With$client_side_rendered = true, QM auto-serializes the collector data intowindow.QueryMonitorData.data.sqlite, so the outputter's only job is to emit an inline JS module.query-monitor-sqlite.js) that reads fromQueryMonitorDataand injects<details>elements into the DB queries panel. It runs onDOMContentLoaded(after QM attaches the shadow root) and uses a debouncedMutationObserverto re-inject after Preact re-renders (panel switches, filters, etc.). Each injected element tracks its SQL key to handle Preact's DOM recycling on filter/sort changes.Fixes the CI failure introduced by QM 4.0 release.
Test Plan
<details>elements appear in shadow DOM, SQLite queries display correctly