[Alternate] Podcast Episode block: post-bound (single source of truth)#48546
[Alternate] Podcast Episode block: post-bound (single source of truth)#48546robertbpugh wants to merge 14 commits intotrunkfrom
Conversation
…cover/excerpt) Alternate model that drops the duplicating attributes (title, summary, description, author, imageId, imageUrl, publishDate) and reads them from the surrounding post instead. - block.json: remove title/summary/description/author/imageId/imageUrl/ publishDate attributes. Block keeps only audio + episode + Podcasting 2.0 metadata. - edit.js: useSelect from core/editor reads post title, excerpt, featured image, author. Sidebar collapses to three panels (Episode, Audio, Podcasting 2.0). Placeholder when block lives outside a post/page. - podcast-episode.php: render_callback uses get_the_title(), get_the_excerpt(), get_the_post_thumbnail_url(), get_the_author(), get_the_date(). Guarded by is_singular() so the block stays inert in sidebars and template parts. - save.js: drop title fallback in the noscript link. Why: previously the block stored its own copy of the post title, featured image, and excerpt. Authors edit the post, the block goes stale; or they edit the block, the post stays out of date. RSS, Reader, the block, and the post page can each show different copy of the same episode. Substack and every episode-centric platform avoids this by treating the post as the episode. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…estore poster size - Read post title/excerpt/featured image/author/date via useEntityProp with usesContext: ['postId', 'postType', 'queryId']. Same pattern as core's post-title/post-excerpt/post-featured-image blocks. Block now works inside Query Loops and site-editor singular templates, not just the post editor. - Replace local formatSeconds() with convertSecondsToTimeCode from extensions/shared/components/media-player-control/utils. - Render publish date in editor preview to match the frontend. - Use medium_large (768px) for the poster image instead of large (1024px); the cover renders at 256-512px CSS. - Hoist person-row inline style to a module const. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.
Interested in more tips and information?
|
|
Thank you for your PR! When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:
This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖 🔴 Action required: Please include detailed testing steps, explaining how to test your change, like so: 🔴 Action required: We would recommend that you add a section to the PR description to specify whether this PR includes any changes to data or privacy, like so: Follow this PR Review Process:
If you have questions about anything, reach out in #jetpack-developers for guidance! Jetpack plugin: No scheduled milestone found for this plugin. If you have any questions about the release process, please ask in the #jetpack-releases channel on Slack. |
Code Coverage SummaryCoverage changed in 1 file.
6 files are newly checked for coverage. Only the first 5 are listed here.
Full summary · PHP report · JS report If appropriate, add one of these labels to override the failing coverage check:
Covered by non-unit tests
|
…ten i18n + a11y
- render_block() now accepts \WP_Block and resolves the backing post from
block context, falling back to the global loop. Drops the is_singular()
guard so the block works inside Query Loops and feeds, and switches all
template tags to post-aware variants (get_the_title($post), etc.) so the
rendered episode matches the loop item, not whatever the global page
query points at.
- utils.js (extensions/shared/components/media-player-control): wrap the
mejs.Utils helpers in arrow functions so the lookup happens at call time.
Reading them at module-evaluation time would throw ReferenceError if the
importing block evaluates before mediaelement loads on the page.
- Editor: switch concatenated Season/Episode strings to
sprintf( __( 'Season %d' ) ) so locales that reorder noun/number can
translate cleanly. Drop `alt={ postTitle }` on the cover-art preview
(the title is rendered immediately after as h3), use BaseControl
.VisualLabel for the People section so the label does not point at a
non-existent input id, gate the placeholder on both postId AND postType,
and drop the redundant useBlockProps className argument.
- Cover-art alt also dropped on the frontend for the same a11y reason.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Cover art now falls back show -> episode override (Apple/Spotify hierarchy). Featured image is no longer reused, so themes don't render the same image twice. Show notes hint replaces the excerpt summary on the player card so authors write notes once, in post content. GUID UI dropped - RSS layer derives it from the permalink.
There was a problem hiding this comment.
Pull request overview
This PR introduces an alternate implementation of the Jetpack Podcast Episode block that treats the post as the single source of truth for episode title/author/date, while keeping per-episode cover art as a block attribute with a show-level fallback.
Changes:
- Adds a new
jetpack/podcast-episodeblock with a post-bound data model (usesContext) and a streamlined inspector (Episode / Audio / Podcasting 2.0). - Implements server-side rendering that pulls title/author/date from the resolved post context and applies a cover art fallback chain (episode override → show setting).
- Reworks the shared media timecode helpers to defer
mejslookup until call time.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| projects/plugins/jetpack/extensions/shared/components/media-player-control/utils.js | Changes timecode helpers to look up mejs.Utils at call time instead of import time. |
| projects/plugins/jetpack/extensions/index.json | Registers the podcast-episode extension. |
| projects/plugins/jetpack/extensions/blocks/podcast-episode/style.scss | Adds shared editor/front-end styling for the episode card layout. |
| projects/plugins/jetpack/extensions/blocks/podcast-episode/save.js | Adds a direct-link fallback saved markup for non-frontend contexts (feeds/email/exports). |
| projects/plugins/jetpack/extensions/blocks/podcast-episode/podcast-episode.php | Registers and renders the block; injects editor data for show cover fallback. |
| projects/plugins/jetpack/extensions/blocks/podcast-episode/icons/microphone.js | Adds the block icon SVG. |
| projects/plugins/jetpack/extensions/blocks/podcast-episode/icons/index.js | Exports the icon(s). |
| projects/plugins/jetpack/extensions/blocks/podcast-episode/editor.scss | Adds editor-only styles for controls (people editor, cover picker, hint text). |
| projects/plugins/jetpack/extensions/blocks/podcast-episode/editor.js | Registers the block from metadata and wires edit/save. |
| projects/plugins/jetpack/extensions/blocks/podcast-episode/edit.js | Implements the editor UI, media selection, and post-bound display fields. |
| projects/plugins/jetpack/extensions/blocks/podcast-episode/block.json | Defines the block metadata/attributes, including coverArt and usesContext. |
| projects/plugins/jetpack/changelog/add-podcast-episode-block | Adds a changelog entry for the new block. |
- Prettier: collapse multi-line help, VisualLabel children, ternary args. - i18n: move translator comments inside sprintf so the rule reads them. - i18n: split __() ternary so the extractor sees literal msgids. - PHPCS: pass JSON encoding flags to wp_json_encode. - Phan: cast post_author to int for get_the_author_meta.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
@copilot apply changes based on the comments in this thread |
…18n, PHPUnit tests Agent-Logs-Url: https://github.com/Automattic/jetpack/sessions/fb9995d0-fe14-48cb-9045-c12c05d7b263 Co-authored-by: robertbpugh <52668747+robertbpugh@users.noreply.github.com>
Applied all unresolved review changes in commit 246b6cf:
|
get_block_wrapper_attributes() depends on WP_Block_Supports::$block_to_render state that is null when render_block is invoked directly from PHPUnit, so the three coverArt-fallback tests crashed with "Trying to access array offset on value of type null". Switch back to a plain class attribute escaped through esc_attr(); production output is identical and the PHPCS escaper rule is satisfied without an ignore comment. Also fix PHPCS MultipleStatementAlignment warnings on the $original_post / $GLOBALS['post'] pair in test_no_post_context_returns_empty_string.
Draft alternate to #48375. The block does the same job, but episode title, author, and date come from the post instead of from block attributes. Walkthrough is in
p1778019506270959-slack-podcast-tools, where Tony also raised a third option: a post-level setting (like Jetpack's paid-content gate) that manages podcast metadata at the post level rather than on the block.Why
Tony's branch stores
title,summary,description,author,imageId,imageUrl, andpublishDateon the block. Every podcast post already has those fields (post_title, post author, post date). When an author edits one copy and forgets the other, Reader, RSS, the player, and the post page can show different versions of the same episode.Substack avoids this by treating the post as the episode: the post title is the episode title, and the show notes go in the post body.
Cover art is the exception, since reusing the featured image renders the same picture twice on a post page (theme banner plus player square). This branch keeps
coverArtas a block attribute and falls back to the show-level cover from Settings → Writing → Podcasting when nothing is set, matching how Apple Podcasts and Spotify resolve cover art.What changes
block.json: dropstitle,summary,description,author,imageId,imageUrl,publishDate,guid. AddscoverArt({ id, url }) andusesContext: [ "postId", "postType", "queryId" ]. Audio metadata, episode metadata, and Podcasting 2.0 fields are unchanged.edit.js: reads post title, author, and date viauseEntityPropwith block context, following core's post-title and post-author-name blocks. Cover art picker falls back towindow.jetpackPodcastEpisodeData.showCoverUrlfor editor preview parity. Sidebar collapses to Episode / Audio / Podcasting 2.0.podcast-episode.php: render callback usesget_the_title(),get_the_author_meta(),get_the_date(),get_permalink(). Cover art falls through episode →podcasting_imageoption → none. Show notes come from post content, so the callback no longer touchespost_excerpt.enqueue_block_editor_assetsexposes the show-level URL viawp_add_inline_script.Comparison
Test plan
<enclosure>,itunes:tags, and Podcasting 2.0 elements land in RSS.cc @arcangelini, treat this as input to the design conversation. Fold whichever pieces work into your branch, or keep the full model if post-bound is the long-term direction.