Skip to content

fix: Chrome <111 titlebars + duplicate-placement REST 500s (#167)#172

Merged
epeicher merged 2 commits into
trunkfrom
fix/chrome-109-and-duplicate-placements
May 12, 2026
Merged

fix: Chrome <111 titlebars + duplicate-placement REST 500s (#167)#172
epeicher merged 2 commits into
trunkfrom
fix/chrome-109-and-duplicate-placements

Conversation

@epeicher
Copy link
Copy Markdown
Collaborator

@epeicher epeicher commented May 12, 2026

Summary

Closes #167. Three independent issues, fixed in one PR because they were all reported together.

1. Window control buttons invisible on Chrome <111

assets/css/variables.css declared every focused titlebar background through color-mix(in srgb, ...). Chromium shipped color-mix() in 111; on older browsers the declaration is invalid at computed-value time, the custom property is left at the light unfocused fallback, and the white close/min/max glyphs disappear into it.

The mix inputs were all static literals, so the calls were just compile-time arithmetic dressed up as runtime CSS. Replaced each with the precomputed sRGB hex (pixel-identical on modern Chrome, works on Chrome <111). Kept the original color-mix(...) expression as an inline comment per scheme for traceability.

2. desktop_mode_files_insert_failed 500 on URL / folder creation

Schema v5 added UNIQUE KEY (user_id, parent_id, file_type, file_ref) without filtering on trashed_at_ms. Two reported flows hit the duplicate-key path:

  • Link tile recreation. User trashes www.google.com, recreates it, INSERT collides with the still-present trashed row.
  • Folder placement race. POST /folders returns, the client fires POST /placements, but a concurrent GET /placements?folder=0 triggers desktop_mode_files_auto_place_orphans which places the folder first. The client's POST then collides.

desktop_mode_files_place() now disambiguates the generic false from $wpdb->insert: looks up the colliding row by the unique-key tuple, restores it if trashed, applies the caller's coords / meta via desktop_mode_files_move. Real DB failures still surface as the original WP_Error because the lookup returns null in that case.

3. Restored tile only appeared after refresh

Tile state was correct server-side, but with WP_DEBUG_DISPLAY on, wpdb prints a <div class=\"wpdberror\">...</div> block when the INSERT collides. That HTML was getting prepended to the REST JSON response, so await resp.json() threw on the client and upsertPlacement never ran. Wrapped the INSERT in $wpdb->suppress_errors() so the deliberate, recovered duplicate-key stays silent. Genuine DB failures still hit $wpdb->last_error and error_log.

Tooling

.wp-env.json now sets port: 8890 and testsPort: 8891 so the standalone npm run test:php script coexists with a wordpress-develop checkout on 8889. AGENTS.md updated to drop the prior "do not run test:php" warning.

Test plan

  • npm run build
  • npm run lint
  • ./node_modules/.bin/tsc --noEmit
  • npm run test:js (1109 passing)
  • npm run test:php (654 passing)
  • Reproduced Issue 2 via Chrome DevTools against a local dev WP, confirmed real-time tile creation after the suppress_errors fix
  • Verify Chrome 109 still renders the focused titlebar with visible control buttons (depends on access to a real Chrome 109 build)
Open WordPress Playground Preview
Three independent bugs surfaced in Issue #167:

1. Window control buttons invisible on Chrome 109. assets/css/variables.css
   declared every focused titlebar background through `color-mix(in srgb, ...)`,
   which Chromium shipped in 111. On older browsers the declaration is
   invalid-at-computed-value-time, the custom property falls back to the
   light unfocused surface, and the white close/min/max glyphs vanish into
   it. The mix inputs were all static literals anyway, so the calls were
   only ever doing compile-time arithmetic. Replaced with the precomputed
   sRGB hex per scheme (visually identical on modern Chrome, just works
   on Chrome <111). Each line keeps the original color-mix() in a comment
   for traceability.

2. "Failed to write placement" (REST 500) when creating a URL tile whose
   string matches a soft-trashed one, or when the orphan auto-placer
   raced a folder-creation. Schema v5 added a UNIQUE key on
   (user_id, parent_id, file_type, file_ref) without filtering on
   trashed_at_ms, so both flows hit the same wpdb duplicate-key path.
   desktop_mode_files_place() now disambiguates the generic `false` from
   $wpdb->insert: looks up the colliding row, restores it if trashed,
   then applies the caller's coords / meta. Real DB failures still
   surface as the original WP_Error because the lookup returns null.

3. After fix 2 the row state was correct but the new tile only appeared
   after a refresh. Root cause was unrelated to the fix logic: with
   WP_DEBUG_DISPLAY on, wpdb prints a `<div class="wpdberror">...</div>`
   block to stdout when the INSERT collides, which gets prepended to
   the REST JSON response. The client's `await resp.json()` then throws
   and upsertPlacement is never called. Wrapped the INSERT in
   $wpdb->suppress_errors() so the deliberate, recovered failure stays
   silent. The error still lands in $wpdb->last_error and error_log.

Tooling: .wp-env.json now sets port=8890 / testsPort=8891 so the
standalone `npm run test:php` script coexists with the user's
wordpress-develop checkout on 8889. AGENTS.md updated to reflect that
`npm run test:php` is the supported path again.

Verified: npm run build, npm run lint, tsc --noEmit, npm run test:js
(1109 ok), npm run test:php (654 ok). Manual repro of issues 1 and 2
in Chrome via DevTools confirmed real-time tile creation.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 12, 2026

✅ WordPress Plugin Check Report

✅ Status: Passed

📊 Report

All checks passed! No errors or warnings found.


🤖 Generated by WordPress Plugin Check Action • Learn more about Plugin Check

`bin/sync-to-wp-develop.sh` resolves the destination plugin folder in
three steps now, instead of just two:

  1. `WPDM_SYNC_DEST` env var, used verbatim if set.
  2. Inspect running containers for a mount whose Destination is
     exactly `/var/www` and whose host Source looks like a wordpress-
     develop checkout (has `src/wp-content/plugins/` and
     `wp-tests-config-sample.php`). Append `desktop-mode` to land at
     the plugin folder.
  3. Fall back to `$HOME/github/wordpress-develop/...` (the historical
     default), with a hint to set `WPDM_SYNC_DEST` or start the
     container.

The /var/www-Destination check distinguishes wordpress-develop from
wp-env, which mounts to /var/www/html. Another developer with their
wordpress-develop checkout at `~/repos/wordpress-develop` (or anywhere
else) now gets the right sync target automatically, as long as the
container is running. The fallback keeps the script useful before the
container is started for the first time.

Each branch prints which path resolved, so the destination is visible
in the sync log.
@epeicher epeicher enabled auto-merge (squash) May 12, 2026 09:36
@epeicher epeicher merged commit ef73ac3 into trunk May 12, 2026
5 checks passed
@epeicher epeicher deleted the fix/chrome-109-and-duplicate-placements branch May 12, 2026 09:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant