Skip to content

fix(loops): resolve custom media fields to URLs in loops - #300

Open
shadysamir wants to merge 1 commit into
CoreBunch:mainfrom
shadysamir:fix/loop-media-field-resolution
Open

fix(loops): resolve custom media fields to URLs in loops#300
shadysamir wants to merge 1 commit into
CoreBunch:mainfrom
shadysamir:fix/loop-media-field-resolution

Conversation

@shadysamir

@shadysamir shadysamir commented Jul 28, 2026

Copy link
Copy Markdown

Summary

A loop over a data table only exposed the built-in featuredMedia and firstImage fields as resolved media URLs. Any user-defined media field (for example a Client logo) was spread through raw, so a {currentEntry.<field>} binding on an img src emitted the stored media id instead of a URL. The browser then resolved that bare id against the current path, so the image never loaded, both on the editor canvas and on the published site.

The format:"media" hint written into the binding at authoring time had no consumer at render time: id → URL dereferencing ran only for the two hardcoded built-in fields in the loop source.

This fix makes the loop source resolve every type:"media" cell to its public path generically, replacing the featuredMedia-only special case:

  • Both page-slice queries (post-type published-version join and data-kind direct read) now select data_tables.fields_json to learn which fields are media-typed.
  • collectMediaIds gathers the featured id plus every custom media id into the existing single batched resolve, so no extra queries are issued.
  • resolvedMediaOverlay overwrites each media cell with its resolved public path in both row projections, spread right after the raw cells.
  • Multi-value media fields (allowMultiple) flatten to the first element for a scalar binding; a dangling id resolves to null rather than leaking the raw id.

Resolving media in the loop source runs before both token paths, so resolveBindingValue and interpolateTokens need no changes: by the time they read the field, it is already a URL. A new shared reader readMediaCellIds (in src/core/data/cells.ts) tolerates both cell shapes (single id string, or string[]).

Scope is single-value resolution plus first-element flatten for multi-value. Rendering every element of a multi-value field is a separate nested-loop concern and is intentionally out of scope here.

Relates to #224 (same root limitation from the plugin-API side: resolveMediaIdsToPaths was hardcoded to built-in media fields).

Verification

  • bun run build
  • bun test (6302 pass, 0 fail; includes 5 new tests in dataRowsFetch.test.ts)
  • bun run lint
  • Docker/deployment check, if relevant

Checklist

  • Tests cover behavior changes.
  • Docs were updated when behavior, config, deployment, or public surfaces changed. (No documented behavior changed; the fix restores the documented format:"media" contract.)
  • No compatibility shim was added for old pre-release behavior.
  • No secrets, local databases, uploads, or generated artifacts are included.

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings July 28, 2026 18:24
A loop over a data table exposed only the built-in `featuredMedia` and
`firstImage` fields as resolved media URLs. Any user-defined `media`
field (e.g. a Client `logo`) was spread through raw, so a
`{currentEntry.<field>}` binding on an `img src` emitted the stored
media id instead of a URL. The browser then resolved that bare id
against the current path, so the image never loaded, on the canvas and
on the published site.

The loop source now resolves every `type:"media"` cell to its public
path generically, replacing the `featuredMedia`-only special case:

- Both page-slice queries select `data_tables.fields_json` to identify
  which fields are media-typed.
- `collectMediaIds` gathers featured + all custom media ids into the
  existing single batched resolve (no extra queries).
- `resolvedMediaOverlay` overwrites each media cell with its resolved
  path in both row projections, applied right after the raw cells.
- Multi-value media fields (`allowMultiple`) flatten to the first
  element for a scalar binding; a dangling id resolves to null instead
  of the raw id.

Resolving media in the loop source runs before both token paths, so the
binding and string-token resolvers need no changes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@shadysamir
shadysamir force-pushed the fix/loop-media-field-resolution branch from 9170a2a to 5a1dba6 Compare July 28, 2026 18:26

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes data.rows loop rendering so all media-typed table fields (not just the built-in featuredMedia / firstImage) are resolved from stored media asset IDs to public URLs before bindings are evaluated. This aligns loop output with the authoring-time format: "media" hint so {currentEntry.<field>} can be used directly in img src on both the editor canvas and published output.

Changes:

  • Fetch data_tables.fields_json in both post-type and data-kind row queries to identify which fields are type: "media".
  • Batch-resolve media IDs for featured media + all custom media fields, then overlay resolved URLs onto the row’s fields map.
  • Add readMediaCellIds helper and new tests covering single, multi-value (flatten-first), empty, and dangling-ID behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/core/loops/sources/dataRows.ts Generalizes loop-source media resolution by discovering media fields from fields_json, batch-resolving IDs, and overlaying URLs into LoopItem.fields.
src/core/data/cells.ts Adds readMediaCellIds to tolerate both single-id and multi-id media cell shapes (string vs string[]).
src/tests/loops/dataRowsFetch.test.ts Adds coverage to lock in URL resolution for custom media fields across both loop projections (data-kind + post-type).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings July 28, 2026 18:27

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

@shadysamir
shadysamir marked this pull request as ready for review July 28, 2026 18:39
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.

2 participants