Skip to content

Refactor My WordPress to use <wpd-tile> + add post status ribbons#233

Merged
AllTerrainDeveloper merged 4 commits into
trunkfrom
refactor-my-wordpress-with-wpd-tiles
May 17, 2026
Merged

Refactor My WordPress to use <wpd-tile> + add post status ribbons#233
AllTerrainDeveloper merged 4 commits into
trunkfrom
refactor-my-wordpress-with-wpd-tiles

Conversation

@AllTerrainDeveloper
Copy link
Copy Markdown
Collaborator

@AllTerrainDeveloper AllTerrainDeveloper commented May 17, 2026

Summary

Consolidates every tile renderer in the shell behind a single canonical
<wpd-tile> web component, lifts the desktop-files tile builder onto a
generic TileSpec adapter, and surfaces unpublished post status
(Draft / Pending / Private / Scheduled) as a diagonal corner
ribbon on My WordPress tiles. Also lands a server-side
post→attachment resolver so the Media drill-in view catches references
that the previous client-side regex missed.

What changed

New <wpd-tile> component (src/ui/components/wpd-tile/)

The canonical tile element used everywhere a tile shows up — desktop
wallpaper, folder windows, every My WordPress section (Posts, Pages,
Users, Media, drill-in usage), and any plugin surface that wants the
same chrome. Light-DOM by design so existing modifier classes
(__media-tile, __tile--user, __tile--usage) keep working from
external CSS. The host element IS the tile — data-placement-id,
style.left/top, and document.querySelector('.desktop-mode-file-tile')
all keep pointing at the same node.

The component owns icon-vs-thumbnail rendering, the status ribbon
(<wpd-ribbon> placement, gated by the per-user
showPostStatusRibbons OS setting), the lock badge for access-gated
items, drag-out wiring, and keyboard activation (Enter / Space).

Generic TileSpec renderer (src/desktop-files/tile-spec.ts)

buildTileFromSpec(spec) instantiates a <wpd-tile> and reflects spec
fields onto attributes. attachTileDragOut(tile, payload) factors out
the standard pointerdown → DragManager dance so no builder duplicates
it any more.

file-tile.ts is now a thin placement → spec adapter on top of
buildTileFromSpec, plus the desktop-files-specific behavior
(double-click → openFile, access-gated toast, share-folder badge
hook). The placement-shaped desktop-mode.files.tile-* plugin hook
surface is preserved unchanged.

My WordPress migrated to <wpd-tile>

index.ts, media-list.ts, media-detail.ts all drop their bespoke
buildXxxTile() DOM construction in favor of buildTileFromSpec +
attachTileDragOut. Net effect: same DOM contract, one tile renderer,
free status-ribbon + drag-out plumbing.

Post status ribbons

  • New per-user OS setting showPostStatusRibbons (default ON) with a
    checkbox in OS Settings → Features.
  • fetchEntityList / fetchEntityDetail carry post status in the
    REST response; EntityListItem / EntityDetail gained the field.
  • Non-publish posts surface a diagonal corner ribbon in the tile
    (tone varies by status: draft=warning, pending=info, private=danger,
    scheduled=primary). Rendered via the existing <wpd-ribbon>
    component — no hand-rolled corner CSS.

Server-side attached-media resolver

New includes/my-wordpress/attached-media.php registers
desktop_mode_attached_media on every public post type. Resolves
attachment ids from the post in four passes — featured image +
wp-image-N block class + [caption id="attachment_N"] shortcodes +
data-id / data-attachment-id attributes + raw <img src> URLs via
attachment_url_to_postid() (with in-request caching and
-scaled.jpg ↔ original URL variants).

Filterable via desktop_mode_my_wordpress_attached_media so ACF /
page-builder / post-meta gallery plugins can append their own refs.

media-usage.php also gains the same -scaled variant handling so
the reverse lookup ("which posts use this attachment?") catches the
same cases.

Hook surface

  • Preserved (Stable): desktop-mode.files.tile-class,
    desktop-mode.files.tile-element, desktop-mode.files.tile-rendered,
    desktop-mode.files.grid-rendered.
  • New (Experimental, 0.21.0): desktop-mode.tile.class +
    desktop-mode.tile.rendered — fire on every <wpd-tile> paint
    anywhere in the shell, so plugins can decorate tiles across all
    surfaces, not just desktop files.
  • New (Experimental, 0.21.0): desktop_mode_my_wordpress_attached_media
    PHP filter + desktop_mode_attached_media REST field on all public
    post types.

Docs

  • docs/files-on-desktop.md — documents the new generic
    desktop-mode.tile.* pair alongside the preserved placement-shaped
    filters; calls out stability for each.
  • docs/hooks-reference.md — full entry for
    desktop_mode_my_wordpress_attached_media with REST field shape
    and sanitization notes.

Test plan

  • npm run lint
  • ./node_modules/.bin/tsc --noEmit
  • npm run test:js (150 files / 1366 tests)
  • npm run build (deterministic — no bundle diffs after rebuild)
  • php -l on every changed PHP file
  • Manual: toggle showPostStatusRibbons in OS Settings → Features,
    confirm ribbons appear/disappear on My WordPress Posts grid
  • Manual: drag a tile from My WordPress Media to the desktop —
    verify it lands as a shortcut placement
  • Manual: open Media drill-in for an attachment used via a raw
    <img src> (no wp-image-N class) — verify it shows in
    "Used in"
  • Manual: smoke-test the desktop wallpaper and a folder window —
    verify tile selection, drag-rearrange, share-folder badge,
    access-gated lock all still work
  • Regression: verify a plugin using desktop-mode.files.tile-class
    or desktop-mode.files.tile-element still receives the filter
Open WordPress Playground Preview

- Updated the fetchEntityList and fetchEntityDetail functions to include the post status in the API responses.
- Enhanced EntityListItem and EntityDetail interfaces to support the new status field.
- Introduced a new setting to toggle the visibility of post status ribbons in the user interface.
- Implemented a checkbox in the settings to allow users to enable or disable the display of post status ribbons.
- Created a new WpdTile component to represent tiles in the My WordPress interface, including status ribbons for non-published posts.
- Added tests for the new WpdTile component and its behavior regarding status ribbons and drag-and-drop functionality.
@AllTerrainDeveloper AllTerrainDeveloper changed the title Refactor my wordpress with wpd tiles Refactor My WordPress to use <wpd-tile> + add post status ribbons May 17, 2026
@AllTerrainDeveloper
Copy link
Copy Markdown
Collaborator Author

@claude can you review this pr please?

@claude
Copy link
Copy Markdown

claude Bot commented May 17, 2026

Claude finished @AllTerrainDeveloper's task in 2m 21s —— View job


PR Review: Refactor My WordPress to use <wpd-tile> + add post status ribbons

Tasks:

  • Understand the request
  • Read <wpd-tile> component (src/ui/components/wpd-tile/)
  • Read tile-spec.ts and file-tile.ts changes
  • Read My WordPress module changes (index.ts, media-list.ts, media-detail.ts)
  • Read PHP changes (attached-media.php, media-usage.php, os-settings.php)
  • Read settings changes
  • Read CSS changes
  • Read docs changes
  • Read tests
  • Post comprehensive review

This is a well-structured refactor with strong test coverage and good docs hygiene. One functional bug, two maintainability concerns, and a few minor notes below.


Bug — selectTile bypasses attribute-based state management

File: src/my-wordpress/media-list.ts:159–163

if ( ctx.selectedTile ) {
    ctx.selectedTile.classList.remove( 'desktop-mode-file-tile--selected' );
}
tile.classList.add( 'desktop-mode-file-tile--selected' );

<wpd-tile>'s _paint() method drives the --selected class exclusively from the selected attribute (this.hasAttribute('selected')). On every _paint() call, it first strips all owned classes including --selected, then re-applies them from attributes. This means any subsequent attribute change on the tile (e.g. a thumbnail URL update, a label change, or even a hover tooltip toggle) will silently remove the manually-added class.

The fix is to use the attribute instead of the class directly:

if ( ctx.selectedTile ) {
    ctx.selectedTile.removeAttribute( 'selected' );
}
tile.setAttribute( 'selected', '' );

Fix this →


Design — getDragManager() duplicated across two files

src/desktop-files/tile-spec.ts:223–227 and src/ui/components/wpd-tile/wpd-tile.ts:70–75 both define an identical getDragManager() function. This is the exact quiet-drift pattern the whole refactor was designed to prevent — the two copies are already functionally identical but will diverge if one is updated without the other.

tile-spec.ts already imports wpd-tile for side effects. The cleanest fix is to export getDragManager from tile-spec.ts (or a shared drag-utils leaf) and import it into wpd-tile.ts. Alternatively, since <wpd-tile> also handles drag-out internally via drag-kind attributes, the attachTileDragOut path in tile-spec.ts and the attribute-driven path in wpd-tile.ts could share a single utility.

Fix this →


Design — TILE_CLASS defined in two places

src/desktop-files/tile-spec.ts:32 and src/ui/components/wpd-tile/wpd-tile.ts:45 both declare export const TILE_CLASS = 'desktop-mode-file-tile'. The tile-spec file already imports wpd-tile for side effects — it should import TILE_CLASS from there instead of re-declaring it, making wpd-tile.ts the single source of truth for the canonical class name.

Fix this →


Minor — cache invalidation gap in media-usage.php

The bust_for_post function (includes/my-wordpress/media-usage.php:468) extracts only wp-image-N class and _thumbnail_id references to determine which attachment caches to invalidate. But attached-media.php now also resolves raw <img src> URL embeds. If a post is edited to add or remove a raw URL embed, the media-usage cache for the affected attachment won't be busted until TTL (5 min) expires.

Not critical (short TTL, read-only), but worth noting as a known gap for future work.


Minor — typographic apostrophe in title comparison (wpd-tile.ts:240)

if ( this.title.startsWith( 'You don’t have permission' ) ) {

The string at line 236 (assignment) and line 240 (comparison) both use a right single quotation mark (') rather than an apostrophe ('). This works as long as both sides match, but it's unusual and could surprise a reader doing a text search for "don't". Worth a comment or normalizing to a straight apostrophe.


Positive observations

  • <wpd-tile> design is solid: light-DOM by design preserves the existing .desktop-mode-file-tile CSS contract, the ownedClasses pattern correctly distinguishes framework-owned modifiers from consumer-appended modifier classes, and the connectedCallback / disconnectedCallback pairing is leak-free.
  • PHP attached-media resolver is thorough — the four-pass scan (block class, id="attachment_N", data attributes, raw URL) plus the -scaled.jpg ↔ original swap covers the major cases the client regex missed. The in-request URL cache prevents repeated SQL hits for repeated embeds.
  • Cache architecture in media-usage.php is well thought out: pre-save snapshot + post-save union ensures both added and removed references bust the right cache entries.
  • Settings propagation (showPostStatusRibbons) is correctly threaded — PHP default, TypeScript DEFAULTS, _parseRaw sanitization, and OsSettingsState type all agree.
  • Test coverage is strong: both wpd-tile.test.ts and tile-spec.test.ts cover the reactive attribute contract, status-ribbon gating, and drag-out behavior.
  • Back-compat hooks (desktop-mode.files.tile-class, .tile-element, .tile-rendered) are preserved — the new generic pair sits alongside without replacing.

Summary: One real bug (selection state management), two easy cleanups (duplicated getDragManager and TILE_CLASS), and a couple of minor notes. The architecture is solid and the refactor is well-executed.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 17, 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

@AllTerrainDeveloper AllTerrainDeveloper enabled auto-merge (squash) May 17, 2026 19:15
@AllTerrainDeveloper AllTerrainDeveloper merged commit 62b1f2b into trunk May 17, 2026
5 checks passed
@AllTerrainDeveloper AllTerrainDeveloper deleted the refactor-my-wordpress-with-wpd-tiles branch May 17, 2026 19:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant