[PARKED] Upgrade block apiVersion from 2 to 3#118
Draft
gsarig wants to merge 16 commits into
Draft
Conversation
* Register ability category for Abilities API compliance * Remove unintended Kratt-specific meta block from ability registration * Add description to ability category registration * Fire wp_abilities_api_categories_init before abilities in test * Clarify lat/lng and markers descriptions to prevent misuse by ability consumers
* Add unit tests for createMapboxStyleUrl and wire up test:unit script * Add Playwright test for Mapbox tile loading * Wire up MAPBOX_ACCESS_TOKEN for local .env and CI secret * Fix playwright target to source .env before running setup * Fix URL host check in Mapbox test to use hostname comparison * Add test:unit to CI and disable Playwright traces to prevent token leaking
- Include src/block/block.json in the artifact-playwright version
consistency check so all four version locations are validated
- Use ${RSYNC_EXCLUDE:+"$RSYNC_EXCLUDE"} in build-zip.sh to prevent
word splitting if the variable contains spaces
* Harden OpenAI REST endpoint validation and error handling
* Add prompt length constraints and rename response body variable
- Add minLength/maxLength to the prompt REST arg schema to reject empty or
overly-large inputs before the callback runs
- Rename $body to $response_body when retrieving the AI API response to
avoid shadowing the outbound request payload variable
* Use get_param() for validated prompt arg and check upstream HTTP status
- Replace get_json_params()['prompt'] with get_param('prompt') so the
validated/sanitized route arg is used regardless of how the client
encodes the request body
- Check wp_remote_retrieve_response_code() before decoding the response
so non-2xx upstream errors are returned as WP_Error 502 rather than
silently forwarded as 200 OK
* Fix JS error handling, race condition, and edge cases - Add .catch() and response.ok check to both SearchBox fetch calls - Wrap renderMap in try/catch so one corrupt map doesn't break the page - Return fetch promise from openai findMarkers to fix race condition - Fix centerMap returning [undefined, undefined] for empty markers - Replace for...in with findIndex in getMarkerIndex * Normalize parsed AI response to array before mapping JSON.parse(resultsRaw) may return a non-array value if the AI provider returns an unexpected shape. Guard against this so .map() never throws and Promise.all always receives a valid array. * Guard Promise.all cleanup against empty results and marker fetch errors * Skip remaining marker tasks once a fetch error has occurred Once markerError is set, already-scheduled timeout callbacks can still call findMarkers and have addMarker overwrite the error state with 'working'. Guard each task callback so it resolves immediately when markerError is true, preventing later successful markers from clobbering the error UI before its 3-second timeout fires. * Guard addMarker against in-flight responses after a marker error The markerError check before each task prevents new fetches from starting, but a concurrent in-flight request can still resolve and call addMarker after markerError is set. Skip addMarker when markerError is already true so a racing success can't overwrite the error UI state. * Guard addMarker against empty Nominatim responses Nominatim can return an empty array for an unknown place, which would pass undefined to addMarker and either throw or silently produce a broken marker. Only call addMarker when data is a non-empty array. * Clear error state after JSON parse failure The catch block for JSON.parse errors set openAImode to 'error' but never scheduled a reset, leaving the error alert stuck indefinitely. Add the same 3-second timeout cleanup used by the other error branches.
* Start: Consolidate Dependabot dependency bumps into a single PR * Consolidate 14 Dependabot dependency bumps into a single PR - npm: flatted 3.4.1→3.4.2, yaml 1.10.2→1.10.3, picomatch 2.3.1→2.3.2 (4.0.3→4.0.4 in nested jest/tinyglobby entries) - composer: phpstan/phpstan 2.1.40→2.1.44 - All other bumps (braces, form-data, tar-fs, on-headers, compression, playwright, js-yaml, preact, diff, lodash, lodash-es) were already at or above the Dependabot target versions after merging release/2.12.0
* Start: Add WordPress Playground blueprint * Add WordPress Playground blueprint for live plugin preview Adds .wordpress-org/blueprints/blueprint.json so the WordPress.org plugin page shows a "Preview" button that launches a Playground instance with the plugin installed and a demo map page open in the block editor. The blueprint installs the plugin, then writes and navigates to a PHP setup script that creates an "OpenStreetMap Demo" page with three pre-configured markers (Athens, Thessaloniki, Heraklion) at zoom 7, then redirects directly into the block editor. The setup script mirrors save.js precisely — plugin_dir_url(), the same JSON encoding flags, and the getBoundsCenter arithmetic — so the block passes editor validation without a recovery prompt. * Remove invalid activate property from installPlugin step * Fix marker shape: use text/textRaw instead of title/content/icon * Add blueprint lint: schema property check and PHP syntax validation * Add blueprint validation to js-build CI job * Skip PHP lint in validate-blueprint.js when php is not in PATH
…rt search (#117) * Start: WordPress 7.0 compatibility + WordPress AI Client integration for smart search * Add WordPress 7.0 compatibility and WP AI Client integration for smart search - Bump "Tested up to" to 7.0 in readme.txt - Route smart search through wp_ai_client_prompt() when available and no plugin API key is set; plugin key always wins (backward compat) - Show a settings notice when a site-level AI connector is detected - Add PHPStan stub for wp_ai_client_prompt() so static analysis passes * Add integration tests for OpenAI callback routing and WP AI Client notice * Update documentation to mention WP 7.0 site-level AI connector * Differentiate connector notice when plugin API key is also set * Fix missing HTTP status in openai_error and pass through upstream status from WP AI Client errors * Add rules for REST WP_Error status and Copilot filter callback false positive * Fix stub detection and add priority-3 test with process isolation * Add Copilot rule: Tested up to belongs only in readme.txt, not plugin PHP header * Wrap pre_http_request filter in try/finally to prevent test pollution on assertion failure
- Bump apiVersion from 2 to 3 in block.json
- Add referrerPolicy="origin" to TileLayer to fix 403 Referer errors on
OSM tiles when the block renders inside Gutenberg's editor iframe
(blob: URLs carry no Referer header by default)
- Add useEffect in MapEvents.js to handle three apiVersion 3 iframe quirks:
1. HTML5 DnD: useBlockProps sets draggable="true" on the block wrapper;
cancel dragstart in capture phase before Gutenberg's block-drag handler
can reposition the DOM
2. Coordinate mismatch: Gutenberg's useBubbleEvents translates forwarded
mousemove coords from iframe-relative to parent-relative; Leaflet's
_startPoint is captured from the native mousedown in iframe coords;
correct _startPoint after Leaflet's _onDown runs so both coordinate
systems match
3. mouseup not forwarded: forward mouseup from iframeDoc to parent document
so Leaflet's drag _onUp handler fires correctly
- Remove non-functional referrerPolicy=origin from TileProvider.js (Leaflet ignores this prop; it is not applied to the img elements TileLayer creates, so it was silently doing nothing) - Fix block-editor.spec.ts for apiVersion 3: the editor canvas is now rendered inside an iframe, so block-content locators must go through frameLocator(); also update beforeEach to check a parent-document element instead of .block-editor-writing-flow which is inside the iframe Made-with: Cursor
The button label changed between WP 6.6 (Toggle block inserter) and WP 7.0+ (Block Inserter). Use the same dual-selector already used in the insertBlock helper so the beforeEach check passes on both versions. Made-with: Cursor
In apiVersion 3 the block editor canvas is a blob: URL iframe. Tile images are inserted into that iframe's DOM, so the browser uses the iframe document URL when determining the Referer header for tile requests. Blob: URLs carry no Referer by default, causing OSM tile servers to return 403. Inject <meta name=referrer content=origin> into the iframe head so the browser sends the page's real origin (https://example.com) as the Referer. On localhost the origin is http://localhost which OSM also rejects — that is an OSM policy limitation, not a code issue. Made-with: Cursor
Add an Architecture Notes entry to CLAUDE.md explaining the OSM tile 403 on localhost: cause, the meta referrer fix, why production works, and why localhost will always 403 (OSM policy). Add a matching Known local limitations section to docs/tests/README.md for developers running the editor locally. Made-with: Cursor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Upgrades the block's apiVersion from 2 to 3 in block.json.
Status: Parked — not targeting 2.12.0
This PR is complete and all tests pass, but has been deliberately parked and is not being merged into release/2.12.0. See the decision rationale below.
Brief
apiVersion 3 was introduced in WordPress 6.3. The key difference: the block editor canvas is now rendered inside a blob: URL iframe. The block's JavaScript (including Leaflet and React) continues to run in the parent frame's execution context — not inside the iframe.
For this block, three regressions were introduced and fixed:
HTML5 DnD hijack — useBlockProps sets draggable="true" on the block wrapper in the iframe DOM. Fixed by cancelling dragstart in capture phase before Gutenberg's block-drag handler.
Coordinate mismatch (drag jump) — Gutenberg's useBubbleEvents adds the iframe's getBoundingClientRect() offset to forwarded mousemove events, but Leaflet's _startPoint is captured from the native mousedown in iframe-relative coords. Fixed by correcting _startPoint after Leaflet's _onDown runs.
mouseup not forwarded — Gutenberg's useBubbleEvents does not forward mouseup. Fixed by manually forwarding it from the iframe document to the parent document so Leaflet's drag _onUp handler fires.
Additionally: tile
elements are inserted into the iframe DOM, so the browser sends no Referer for tile requests (blob: URL context). Fixed by injecting into the iframe . This resolves the 403 on production; on localhost, OSM's own policy blocks localhost origins regardless.
Why it is parked
The fix for regression #2 accesses Leaflet's private internal API:
map.dragging._draggable._startPoint.x += rect.left;
This is a documented fragile point: any Leaflet version that renames or restructures _draggable._startPoint would silently reintroduce the drag-jump regression with no error. The coordinate correction is also coupled to exactly how Gutenberg's useBubbleEvents translates mouse coordinates — a change in that mechanism would require revisiting the fix.
Meanwhile, apiVersion 2 has no announced deprecation timeline. WordPress's backward compatibility commitments are strong and apiVersion 2 blocks are expected to keep working for the foreseeable future.
Forcing functions to revisit
Pick this up when one of the following occurs:
The pending react-leaflet upgrade (currently blocked by @wordpress/scripts Node constraints) lands — at that point, verify _draggable._startPoint still exists at that path in the new Leaflet version and merge together
WordPress announces a deprecation notice for apiVersion 2 (editor warnings, etc.)
A future WordPress release changes useBubbleEvents in a way that breaks the current fixes anyway
What is on the branch
src/block/block.json — "apiVersion": 2 → 3
src/block/Elements/MapEvents.js — iframe drag fixes + referrer meta tag injection
src/block/Elements/TileProvider.js — removed non-functional referrerPolicy="origin" prop (Leaflet ignores it)
tests/playwright/block-editor.spec.ts — new editor E2E tests, updated for apiVersion 3 iframe architecture
CLAUDE.md + docs/tests/README.md — documented the localhost OSM tile 403 limitation
All tests pass: lint ✓ · PHPUnit ✓ · Playwright 6/7 ✓ (1 skipped: Mapbox, no key)
Old Brief
What
enables the latest block lifecycle guarantees; needs its own PR with a targeted regression test run against saved block content
Brief
Source: current
src/block/block.jsonhas"apiVersion": 2apiVersion 3 was introduced in WordPress 6.3. The key difference: the block wrapper
element (
<div class="wp-block-…">) is now rendered by the editor automatically viauseBlockProps, so thesavefunction should not add the outer element itself. Forblocks with
render_callback(server-side rendering), thesavefunction alreadyreturns
null— which means the wrapper is currently not in saved post content and theupgrade path is simpler than for static-save blocks.
Rough scope:
"apiVersion": 2to"apiVersion": 3inblock.jsoneditfunction usesuseBlockPropscorrectly (it should already)savefunction returnsnull(server-rendered block — it should)block editor behaviour
Known risk: If any legacy saved blocks have a wrapper div written by the
savefunctionfrom a prior version, upgrading apiVersion can cause block validation failures on those
posts. Check the save function history to determine whether this has ever not been
null.This is a contained change if the save function is confirmed as
null. Give it its ownPR so the diff is reviewable in isolation.
Risk: Low if save returns
null(server-rendered). Medium if any static-save era existsin the block's history — snapshot tests and a manual editor check will surface this.
Planning proposal: 2026-03-28 · Task 8