Skip to content

Podcast: gate the Episodes dashboard tab on Premium product access (PODS-145)#48704

Open
robertbpugh wants to merge 10 commits into
trunkfrom
pods-145-gate-episode-dashboard-tab-on-premium-product-access
Open

Podcast: gate the Episodes dashboard tab on Premium product access (PODS-145)#48704
robertbpugh wants to merge 10 commits into
trunkfrom
pods-145-gate-episode-dashboard-tab-on-premium-product-access

Conversation

@robertbpugh
Copy link
Copy Markdown
Contributor

@robertbpugh robertbpugh commented May 11, 2026

Fixes PODS-145.

Blocked on #48700 (adds PODCASTING to WPCOM_Features::FEATURES_MAP). Until that lands, Current_Plan::supports('podcasting') returns false for Simple-site Premium users and the Episodes tab shows the upsell instead of episodes. Merge order: #48700#48702 → this PR.

Proposed changes

  • class-admin-page.php adds a jetpack_admin_js_script_data filter that injects podcast.has_product_access into window.JetpackScriptData. The hook fires from maybe_load_wp_build(), so it only runs on the podcast admin request.
  • dashboard/index.tsx reads the flag via getScriptData() and branches the Episodes tab content only. Settings and Distribution render normally. Welcome onboarding stays the same.
  • dashboard/upsell/index.tsx (new): uses UpsellBanner from @automattic/jetpack-components and getProductCheckoutUrl for the CTA target.
  • dashboard/declarations.d.ts (new): module-augments JetpackScriptData with the podcast field, so the helper is typed without a cast.
  • Fail-open: a missing flag means access-granted, so a deploy race never locks grandfathered users out.

Related product discussion/links

  • Linear: PODS-145.
  • The gate helper lives on PODS-141 (PR #48702). This branch is based on that one and will rebase to trunk after PODS-141 merges.
  • Hold the merge until PODS-144 backfill has run in production.

Does this pull request change what data or activity we track or use?

No.

Testing instructions

On a site with jetpack_podcast_untangle filtered to true and the podcast package built:

  1. Free, no grandfather sticker. Visit Jetpack > Podcast > Episodes. Expect the upsell banner with an "Upgrade to Premium" CTA that links to wordpress.com/checkout/<your-site>/premium?redirect_to=<episodes-url>&site=<your-site>.
  2. Premium. Upgrade the test site. Episodes tab shows the episode list (unchanged from PODS-141).
  3. Free, grandfather-stickered. Add the podcasting-grandfathered sticker to the blog. Episodes tab shows the episode list.
  4. In every state, Settings and Distribution tabs render normally.
  5. Smoke fail-open. Comment out the add_filter line in maybe_load_wp_build(). Episodes still renders (no upsell), since a missing flag means access-granted.

Codex and simplify review notes

I ran Codex review and the simplify skill before opening. Three findings applied in the second commit:

  • Replaced the hand-rolled Card + VStack + Button upsell with UpsellBanner from @automattic/jetpack-components (already a workspace dep).
  • Swapped the hand-built checkout URL for getProductCheckoutUrl, which adds redirect_to and site query params.
  • Added declarations.d.ts so JetpackScriptData carries the podcast field, removing the as unknown as cast.

🤖 Generated with Claude Code

robertbpugh and others added 8 commits May 11, 2026 13:51
Adds `Podcast_Gate::has_product_access()` as the single entry point downstream
gates (dashboard tab, stats endpoint, episode block, AI shownotes) will call.
Two ways to pass: the `podcasting-grandfathered` blog sticker, or
`Current_Plan::supports( 'podcasting' )` — which short-circuits to
`wpcom_site_has_feature` on Simple/Atomic and falls through to cached plan
data on self-hosted Jetpack, so the same helper is correct on every host.
* Drop @phan-suppress-next-line PhanUndeclaredClassMethod on the two
  Atomic-only branches in class-tracks (Current_Plan::get,
  Tracking::tracks_record_event). Adding automattic/jetpack-plans to
  the package require pulls in the connection package transitively,
  so phan now resolves both classes and the suppressions are unused.
* Regenerate the three plugin composer.locks (jetpack, mu-wpcom-plugin,
  wpcomsh) that reference automattic/jetpack-podcast, picking up the
  new jetpack-plans dep.
Matches sibling changelog entries in projects/packages/podcast/changelog
(add-podcast-tracks, add-podcast-settings, add-podcast-package) which all
use `minor` for new added surface area.
Required by the pre-push changelog check now that the previous commit
touched jetpack/mu-wpcom-plugin/wpcomsh composer.lock files.
Inject `podcast.has_product_access` via `jetpack_admin_js_script_data`
and branch the Episodes tab on it. Treat a missing flag as
access-granted so a deploy race never locks grandfathered users out.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
AGENTS.md says not to prefix changelog text with the package name.
Switch to "Dashboard:" to match `add-podcast-ui` convention.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Replace the hand-rolled upsell card with `UpsellBanner` from
  `@automattic/jetpack-components`.
- Build the checkout URL with `getProductCheckoutUrl`, which adds
  `redirect_to`, `unlinked`, and `site` query params for free.
- Add `dashboard/declarations.d.ts` so `JetpackScriptData` carries
  the `podcast.has_product_access` field, removing the `as unknown as`
  cast on `getScriptData()`.
- Rename the helper to `hasProductAccess`; the flag is product-level,
  not Episodes-tab-specific.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@robertbpugh robertbpugh self-assigned this May 11, 2026
@robertbpugh robertbpugh requested a review from arcangelini May 11, 2026 19:23
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 11, 2026

Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.

  • To test on WoA, go to the Plugins menu on a WoA dev site. Click on the "Upload" button and follow the upgrade flow to be able to upload, install, and activate the Jetpack Beta plugin. Once the plugin is active, go to Jetpack > Jetpack Beta, select your plugin (Jetpack or WordPress.com Site Helper), and enable the pods-145-gate-episode-dashboard-tab-on-premium-product-access branch.
  • To test on Simple, run the following command on your sandbox:
bin/jetpack-downloader test jetpack pods-145-gate-episode-dashboard-tab-on-premium-product-access
bin/jetpack-downloader test jetpack-mu-wpcom-plugin pods-145-gate-episode-dashboard-tab-on-premium-product-access

Interested in more tips and information?

  • In your local development environment, use the jetpack rsync command to sync your changes to a WoA dev blog.
  • Read more about our development workflow here: PCYsg-eg0-p2
  • Figure out when your changes will be shipped to customers here: PCYsg-eg5-p2

@github-actions github-actions Bot added [Package] Podcast [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ [Plugin] mu wpcom jetpack-mu-wpcom plugin [Plugin] Wpcomsh [Status] In Progress [Tests] Includes Tests labels May 11, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 11, 2026

Thank you for your PR!

When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:

  • ✅ Include a description of your PR changes.
  • ✅ Add a "[Status]" label (In Progress, Needs Review, ...).
  • ✅ Add testing instructions.
  • ✅ Specify whether this PR includes any changes to data or privacy.
  • ✅ Add changelog entries to affected projects

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 🤖


Follow this PR Review Process:

  1. Ensure all required checks appearing at the bottom of this PR are passing.
  2. Make sure to test your changes on all platforms that it applies to. You're responsible for the quality of the code you ship.
  3. You can use GitHub's Reviewers functionality to request a review.
  4. When it's reviewed and merged, you will be pinged in Slack to deploy the changes to WordPress.com simple once the build is done.

If you have questions about anything, reach out in #jetpack-developers for guidance!


Jetpack plugin:

The Jetpack plugin has different release cadences depending on the platform:

  • WordPress.com Simple releases happen as soon as you deploy your changes after merging this PR (PCYsg-Jjm-p2).
  • WoA releases happen weekly.
  • Releases to self-hosted sites happen monthly:
    • Scheduled release: June 2, 2026
    • Code freeze: June 1, 2026

If you have any questions about the release process, please ask in the #jetpack-releases channel on Slack.


Mu Wpcom plugin:

  • Next scheduled release: WordPress.com Simple releases happen semi-continuously (PCYsg-Jjm-p2)

If you have any questions about the release process, please ask in the #jetpack-releases channel on Slack.


Wpcomsh plugin:

  • Next scheduled release: Atomic deploys happen twice daily on weekdays (p9o2xV-2EN-p2)

If you have any questions about the release process, please ask in the #jetpack-releases channel on Slack.

@github-actions github-actions Bot added the [Status] Needs Author Reply We need more details from you. This label will be auto-added until the PR meets all requirements. label May 11, 2026
@robertbpugh robertbpugh marked this pull request as ready for review May 11, 2026 19:27
Copilot AI review requested due to automatic review settings May 11, 2026 19:27
@jp-launch-control
Copy link
Copy Markdown

jp-launch-control Bot commented May 11, 2026

Code Coverage Summary

This PR did not change code coverage!

That could be good or bad, depending on the situation. Everything covered before, and still is? Great! Nothing was covered before? Not so great. 🤷

Full summary · PHP report · JS report

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 introduces a Premium-access gate for the Jetpack Podcast “Episodes” dashboard tab by surfacing a server-computed access flag into JetpackScriptData and rendering an upsell experience when access is denied.

Changes:

  • Add Podcast_Gate::has_product_access() (with PHPUnit coverage) and wire it into admin script data as JetpackScriptData.podcast.has_product_access.
  • Gate the Episodes tab UI: show the existing Episodes experience when allowed, otherwise show a new UpsellBanner with a Premium checkout CTA.
  • Add jetpack-plans as a dependency (and update downstream composer.lock files) to support plan-based gating.

Reviewed changes

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

Show a summary per file
File Description
projects/plugins/wpcomsh/composer.lock Updates locked deps for the podcast package to include jetpack-plans.
projects/plugins/wpcomsh/changelog/pods-141-add-gate Notes the lockfile update for wpcomsh.
projects/plugins/mu-wpcom-plugin/composer.lock Updates locked deps for the podcast package to include jetpack-plans.
projects/plugins/mu-wpcom-plugin/changelog/pods-141-add-gate Notes the lockfile update for mu-wpcom-plugin.
projects/plugins/jetpack/composer.lock Updates locked deps for the podcast package to include jetpack-plans.
projects/plugins/jetpack/changelog/pods-141-add-gate Adds a Jetpack plugin changelog entry indicating no plugin-level behavior change.
projects/packages/podcast/tests/php/Podcast_Gate_Test.php Adds unit tests for the product-access gate logic.
projects/packages/podcast/tests/php/bootstrap.php Adds a test stub for wpcom_has_blog_sticker used by the gate.
projects/packages/podcast/src/dashboard/upsell/index.tsx Introduces the upsell UI using UpsellBanner and getProductCheckoutUrl.
projects/packages/podcast/src/dashboard/index.tsx Reads JetpackScriptData.podcast.has_product_access and conditionally renders Episodes vs upsell.
projects/packages/podcast/src/dashboard/declarations.d.ts Module-augments JetpackScriptData typing to include podcast.has_product_access.
projects/packages/podcast/src/class-tracks.php Removes now-unneeded Phan suppressions around plan/tracks calls.
projects/packages/podcast/src/class-podcast-gate.php Adds the Podcast_Gate helper implementing sticker/plan access checks.
projects/packages/podcast/src/class-admin-page.php Injects podcast.has_product_access into jetpack_admin_js_script_data for the podcast admin request.
projects/packages/podcast/composer.json Adds automattic/jetpack-plans dependency.
projects/packages/podcast/changelog/pods-145-gate-episode-dashboard-tab-on-premium-product-access Adds a changelog entry for gating Episodes tab UI.
projects/packages/podcast/changelog/pods-141-add-gate Adds a changelog entry for introducing the product-access gate helper.

Comment thread projects/plugins/jetpack/changelog/pods-141-add-gate Outdated
Comment thread projects/plugins/wpcomsh/changelog/pods-141-add-gate Outdated
Comment thread projects/plugins/mu-wpcom-plugin/changelog/pods-141-add-gate Outdated
@robertbpugh
Copy link
Copy Markdown
Contributor Author

@copilot apply changes based on the comments in this thread

Agent-Logs-Url: https://github.com/Automattic/jetpack/sessions/f2e086e7-020d-48a9-94d8-a7e9094cb83d

Co-authored-by: robertbpugh <52668747+robertbpugh@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented May 11, 2026

@copilot apply changes based on the comments in this thread

Applied the requested review-thread fixes in 53bac59: moved the Jetpack changelog Comment: line into the header block and updated both lockfile changelog entries to imperative mood (Update ...). No UI files changed in this follow-up, so there’s no UI screenshot to share.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/134921bfca9b02d8f374c48381451da1d98402f9
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/90f41072d220e5c40df6e8635f5dafba2d9d4d04
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/comparator/zipball/c769009dee98f494e0edc3fd4f4087501688f11e
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/complexity/zipball/bad4316aba5303d0221f43f8cee37eb58d384bbb
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/environment/zipball/b121608b28a13f721e76ffbbd386d08eff58f3f6
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/exporter/zipball/016951ae10980765e4e7aee491eb288c64e505b7
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/global-state/zipball/ef1377171613d09edd25b7816f05be8313f9115d
    • Triggering command: /usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/glVALU /usr/bin/composer update --quiet (http block)
  • https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/97ffee3bcfb5805568d6af7f0f893678fc076d2f
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1effe8e9b8e068e9ae228e542d5d11b5d16db894
    • Triggering command: /usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/glVALU /usr/bin/composer update --quiet (http block)
  • https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/4bfa827c969c98be1e527abd576533293c634f6a
    • Triggering command: /usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/glVALU /usr/bin/composer update --quiet (http block)
  • https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/876099a072646c7745f673d7aeab5382c4439691
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3d1cd096ef6bea4bf2762ba586e35dbd317cbfd5
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/12b54e689b07a25a9b41e57736dfab6ec9ae5406
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/e1367a453f0eda562eedb4f659e13aa900d66c53
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/php-timer/zipball/f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d75dd30597caa80e72fad2ef7904601a30ef1046
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/0b01998a7d5b1f122911a66bebcb8d46f0c82d8c
    • Triggering command: /usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/glVALU /usr/bin/composer update --quiet (http block)
  • https://api.github.com/repos/sebastianbergmann/type/zipball/e549163b9760b8f71f191651d22acf32d56d6d4d
    • Triggering command: /usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/glVALU /usr/bin/composer update --quiet (http block)
  • https://api.github.com/repos/sebastianbergmann/version/zipball/3e6ccf7657d4f0a59200564b08cead899313b53c
    • Triggering command: /usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/glVALU /usr/bin/composer update --quiet (http block)
  • https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163
    • Triggering command: /usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/glVALU /usr/bin/composer update --quiet (http block)
  • https://api.github.com/repos/symfony/console/zipball/d7d2b64a45a89d607865927b176fa51c33ddbb58
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/symfony/deprecation-contracts/zipball/50f59d1f3ca46d41ac911f97a78626b6756af35b
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/symfony/polyfill-ctype/zipball/141046a8f9477948ff284fa65be2095baafb94f2
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/4864388bfbd3001ce88e234fab652acd91fdc57e
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6a21eb99c6973357967f6ce3708cd55a6bec6315
    • Triggering command: /usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/glVALU /usr/bin/composer update --quiet (http block)
  • https://api.github.com/repos/symfony/process/zipball/60f19cd3badc8de688421e21e4305eba50f8089a
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/symfony/service-contracts/zipball/d25d82433a80eba6aa0e6c24b61d7370d99e444a
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/symfony/string/zipball/114ac57257d75df748eda23dd003878080b8e688
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/theseer/tokenizer/zipball/7989e43bf381af0eac72e4f0ca5bcbfa81658be4
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/wikimedia/testing-access-wrapper/zipball/7b4ddeb6242c175156538221b451a3ec981b5be9
    • Triggering command: REDACTED, pid is -1 (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Per AGENTS.md, changelog entries within a package should not repeat
the package name. Restored sub-area label.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@robertbpugh robertbpugh marked this pull request as draft May 11, 2026 20:24
@robertbpugh robertbpugh marked this pull request as ready for review May 11, 2026 21:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Package] Podcast [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ [Plugin] mu wpcom jetpack-mu-wpcom plugin [Plugin] Wpcomsh [Status] In Progress [Status] Needs Author Reply We need more details from you. This label will be auto-added until the PR meets all requirements. [Tests] Includes Tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants