Commit 707d545
Podcast: add episode block (#48546)
* Add Podcast Episode block
* Podcast Episode: split ternary __() calls so i18n extractor can read string literals
* Podcast Episode: post-bound alternate (one source of truth for title/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>
* Podcast Episode: use block context, reuse convertSecondsToTimeCode, restore 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>
* Podcast Episode: read post via block context, defer mejs lookup, tighten 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>
* Podcast Episode: episode cover art override, drop excerpt/GUID UI
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.
* Podcast Episode: fix CI lint/phpcs/phan/build errors
- 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.
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Address PR review comments: coverArt guard, TRANSCRIPT_TYPE_OPTIONS i18n, 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>
* Podcast Episode: use get_block_wrapper_attributes for class+style output
* Podcast Episode: drop get_block_wrapper_attributes, fix PHPCS alignment
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.
* Podcast Episode: use null coalescing for $original_post (Phan)
* Podcast Episode: ship from jetpack-podcast package, gate behind untangle filter
* Podcast Episode: drop inline-data global, get_block_wrapper_attributes, TSX migration
* Podcast Episode: review nits (drop unused const, _x context, echo wrapper attrs)
* Podcast Episode: migrate remaining block utils + icons to TypeScript
* Podcast Episode: refresh wpcomsh composer.lock for new podcast deps
* Podcast Episode: address review feedback + mixed-content fix
- Drop unused mediaSize attribute from block.json, edit.tsx
- Richer author microdata (Schema.org Person with nested name)
- Include explicit flag in meta-line gate (was missing in PHP, matched JSX)
- Remove get_block_wrapper_attributes test-fallback; tests prime WP_Block_Supports::$block_to_render instead
- Add happy-path render tests: title/author/date, video vs audio, trailer/bonus/explicit badges, people list, transcript/chapters/location/license links
- Force admin scheme on the editor script URL to avoid mixed-content blocks on WPCOM sites whose mapped custom domain returns http via home_url()
* Podcast Episode: revert media-player-control hardening
The podcast package keeps the lazy-mejs lookup in its own local util/time-code.ts
copy, so this PR no longer needs to touch the Jetpack plugin's shared util.
Slim the Jetpack changelog to describe only the extensions/index.json
registration.
* Podcast Episode: mark dist/ as production-include in podcast package
Without this flag, jetpack rsync and CI mirror builds were skipping the
package's compiled editor JS (`dist/blocks/podcast-episode/editor.js`)
because dist/ is gitignored. Also production-exclude the source TS/SCSS
since the compiled versions are what ships.
* Podcast Episode: use script_loader_src filter for admin-scheme rewrite
* Refresh composer.lock for jetpack + mu-wpcom-plugin after podcast deps
* mu-wpcom-plugin: add changelog for podcast package bump
* Podcast Episode: add soundbite + alternateEnclosure attrs; slim local util copies
* Podcast Episode: render soundbites at startTime=0 (skip on missing key, not on zero)
* Podcast Episode: ship frontend CSS, inline chapters, cover-art picker refresh
- Split style.scss into its own webpack entry so the block's shared CSS
ships on the public post page; register the frontend style handle via
Assets::register_script and hand it to register_block_type via the
`style` arg.
- Move script_loader_src filter registration into load_editor_scripts so
it no longer fires on every front-end script load.
- Add is_array($person) guard in the people render loop to match the
soundbites / alternateEnclosures patterns.
- Replace chaptersUrl (string) with a chapters array of
{ startTime, title } objects; add a ChaptersEditor in the Inspector,
render an ordered chapter list (sorted by startTime) on the frontend,
and remove the legacy "View chapters" link.
- Refresh the cover-art picker into a featured-image-style full-width
clickable preview with Replace / Remove actions and an empty-state
dashed button.
- Reorganize the Inspector: Audio panel hosts transcript + chapters,
third panel renames to Metadata.
- Block_Test: construct a real WP_Block in block_ctx() so phan stops
complaining about \stdClass vs \WP_Block at the render_block call
sites; add a chapter render test and drop the obsolete chaptersUrl
assertion.
* Podcast Episode: use schema.org contributor for people (not actor)
---------
Co-authored-by: Tony Arcangelini <tony@arcangelini.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>1 parent 32b9c67 commit 707d545
30 files changed
Lines changed: 2304 additions & 29 deletions
File tree
- projects
- packages/podcast
- changelog
- src
- blocks/podcast-episode
- icons
- util
- tests/php/blocks
- plugins
- jetpack
- changelog
- extensions
- mu-wpcom-plugin
- changelog
- wpcomsh
- changelog
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
| 8 | + | |
| 9 | + | |
9 | 10 | | |
10 | 11 | | |
11 | 12 | | |
12 | | - | |
13 | | - | |
14 | | - | |
15 | | - | |
16 | | - | |
17 | | - | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
5 | 6 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
Lines changed: 4 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
| 9 | + | |
8 | 10 | | |
9 | 11 | | |
10 | 12 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
19 | | - | |
| 19 | + | |
| 20 | + | |
20 | 21 | | |
21 | 22 | | |
22 | | - | |
23 | | - | |
24 | | - | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
25 | 27 | | |
26 | 28 | | |
27 | 29 | | |
28 | 30 | | |
29 | 31 | | |
| 32 | + | |
30 | 33 | | |
31 | 34 | | |
32 | 35 | | |
33 | 36 | | |
| 37 | + | |
| 38 | + | |
34 | 39 | | |
35 | 40 | | |
| 41 | + | |
| 42 | + | |
36 | 43 | | |
37 | 44 | | |
38 | 45 | | |
39 | 46 | | |
40 | 47 | | |
| 48 | + | |
| 49 | + | |
41 | 50 | | |
| 51 | + | |
42 | 52 | | |
43 | 53 | | |
44 | 54 | | |
45 | 55 | | |
46 | 56 | | |
| 57 | + | |
47 | 58 | | |
48 | 59 | | |
49 | 60 | | |
50 | | - | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
51 | 68 | | |
52 | 69 | | |
53 | 70 | | |
| |||
60 | 77 | | |
61 | 78 | | |
62 | 79 | | |
63 | | - | |
64 | | - | |
65 | | - | |
66 | | - | |
67 | | - | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
68 | 84 | | |
69 | 85 | | |
70 | 86 | | |
| |||
Lines changed: 112 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
0 commit comments