Add AIBI free trial promotion modal and Plans page changes#23104
Add AIBI free trial promotion modal and Plans page changes#23104leonidasmi merged 3 commits intotrunkfrom
Conversation
…introduction flow - Introduced a new modal component for the AI Brand Insights free trial. - Updated the introduction initialization to include the new component. - Enhanced the AI Plus card to display a badge and link for the free trial when applicable. - Updated the AI Brand Insights post-launch logic to check for premium status. - Added unit tests for the new free trial introduction class and updated tests for the post-launch class.
Pull Request Test Coverage Report for Build 9bb88cc73145d515f8cd150542428abcee0cad9eWarning: This coverage report may be inaccurate.This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.
Details
💛 - Coveralls |
There was a problem hiding this comment.
Pull request overview
Promotes the Yoast AI Brand Insights (AIBI) free trial to Premium users inside the Yoast SEO plugin by adding a new introduction modal and enhancing the Plans page AI+ card, while restricting the existing post-launch AIBI modal to free users.
Changes:
- Added a new
ai-brand-insights-free-trialintroduction (PHP + React modal) that shows only to Premium users on Yoast admin pages. - Updated
ai-brand-insights-post-launchintroduction to show only to non-Premium users. - Updated the Plans page AI+ card to show a “Free trial available” badge and a “Start your free trial” outbound CTA for Premium users.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Unit/Introductions/Application/AI_Brand_Insights_Post_Launch_Test.php | Updates unit tests for new Premium-gating logic and injected Product_Helper. |
| tests/Unit/Introductions/Application/AI_Brand_Insights_Free_Trial_Test.php | Adds unit tests for the new free-trial introduction. |
| src/introductions/application/ai-brand-insights-post-launch.php | Gates the post-launch intro to free users via ! Product_Helper::is_premium(). |
| src/introductions/application/ai-brand-insights-free-trial.php | Adds new introduction gated to Premium users via Product_Helper::is_premium(). |
| packages/js/src/plans/components/cards/ai-plus-card.js | Adds Premium-only “Free trial available” badge + outbound CTA on the AI+ card. |
| packages/js/src/introductions/initialize.js | Registers the new free-trial modal component under its introduction ID. |
| packages/js/src/introductions/components/modals/ai-brand-insights-free-trial.js | Implements the new free-trial promotion modal UI and CTA. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <div className="yst-mt-6 yst-text-xs yst-font-medium yst-flex yst-flex-col yst-items-center"> | ||
| <span className="yst-introduction-modal-uppercase yst-flex yst-gap-2 yst-items-center"> | ||
| <span className="yst-ai-insights-icon" { ...svgAriaProps } /> | ||
| { "Yoast AI Brand Insights" } |
There was a problem hiding this comment.
The product label "Yoast AI Brand Insights" is hard-coded and won’t be picked up for translation. Wrap it in __() (or similar) so the modal content is fully localizable (even if the product name itself stays a proper noun).
| { "Yoast AI Brand Insights" } | |
| { __( "Yoast AI Brand Insights", "wordpress-seo" ) } |
There was a problem hiding this comment.
Maybe we should re-consider our strategy in translating this? We had it untranslatable before, because it was a product name (as per this) but maybe the specs for this case are different? I would ask Product
packages/js/src/introductions/components/modals/ai-brand-insights-free-trial.js
Show resolved
Hide resolved
- Wrap "Yoast AI Brand Insights" in __() for i18n - Add rel="noopener noreferrer" to external link button
leonidasmi
left a comment
There was a problem hiding this comment.
Some minor comments below for CR/Acceptance, but once those are addressed, a small smoke test of the instructions is enough.
On top of the comments left inline, also:
- If a user has Premium and sees the new
Free Trialmodal, if they ever uninstall Premium, they will be greeted by the similarUpgrade to Yoast SEO AI+modal- I bet that's ok, but let's double check with Product
| <div className="yst-mt-6 yst-text-xs yst-font-medium yst-flex yst-flex-col yst-items-center"> | ||
| <span className="yst-introduction-modal-uppercase yst-flex yst-gap-2 yst-items-center"> | ||
| <span className="yst-ai-insights-icon" { ...svgAriaProps } /> | ||
| { "Yoast AI Brand Insights" } |
There was a problem hiding this comment.
Maybe we should re-consider our strategy in translating this? We had it untranslatable before, because it was a product name (as per this) but maybe the specs for this case are different? I would ask Product
| return { | ||
| isPremiumActive: plansSelect.selectAddOnIsActive( ADD_ONS.premium ), | ||
| learnMoreLink: plansSelect.selectLink( "https://yoa.st/plans-ai-plus-learn-more" ), | ||
| freeTrialLink: plansSelect.selectLink( "https://yoa.st/plans-ai-plus-free-trial/" ), |
There was a problem hiding this comment.
Is this the right link? If so, can we put it in the Test Instructions, to treat it as the source of truth?
There was a problem hiding this comment.
Yes, forgot to link the 🧵 in the test instructions. I'll add it.
| </div> | ||
| </div> | ||
| <div className="yst-w-full yst-flex yst-mt-6"> | ||
| <Button |
There was a problem hiding this comment.
I think this only happens when you are on the Dashboard page, but that's not the case with the buttons of the previous modals, so I think we should fix it
There was a problem hiding this comment.
If the same used to happen before, it's not a blocker for us now. But let's create a task to deal with this properly in the future :)
| export const AiBrandInsightsFreeTrial = () => { | ||
| const imageLink = useSelect( select => select( STORE_NAME_INTRODUCTIONS ).selectImageLink( "ai-brand-insights-pre-launch.png" ), [] ); | ||
| const buttonLink = useSelect( select => select( STORE_NAME_INTRODUCTIONS ) | ||
| .selectLink( "https://yoa.st/ai-free-trial-modal/" ), [] ); |
There was a problem hiding this comment.
Is this the right link? If so, can we put it in the Test Instructions, to treat it as the source of truth?
There was a problem hiding this comment.
Hm, I see a different link in the test instructions and the relevant thread 🤔 (https://yoa.st/aibi-introduction-free-trial)


Context
Promote the Yoast AI Brand Insights (AIBI) free trial to premium users directly from within the Yoast SEO plugin, so they can discover and activate the trial without needing to find it independently on my.yoast.com.
Summary
This PR can be summarized in the following changelog entry:
Relevant technical choices:
ai-brand-insights-free-trial): A new PHP introduction class and React modal component that shows to premium users only on Yoast SEO pages. Uses the existing introduction infrastructure (priority 20, same as other AIBI modals).ai-brand-insights-post-launchmodal is now restricted to free users only (addedProduct_Helperdependency to checkis_premium()).CardLinkwithExternalLinkIcon) for premium users. ExtractedAiPlusCardBadgeandAiPlusCardActionssub-components to keep complexity under the ESLint threshold.UiModal.Title(wraps HeadlessUI'sDialog.Title) for properaria-labelledbyon the dialog, so screen readers announce the modal as a dialog with its title.useSvgAriahook on all SVG/icon elements (sparkle icon, external link icon) for consistentrole="img"andaria-hidden="true".https://yoa.st/aibi-introduction-free-trial(modal CTA) andhttps://yoa.st/aibi-plans-free-trial(Plans page button) — to be updated with final URLs (see request).Test instructions
Test instructions for the acceptance test before the PR gets merged
This PR can be acceptance tested by following these steps:
Modal (Premium users):
_yoast_wpseo_introductionsfrom usermeta to reset seen introductionshttps://yoa.st/aibi-introduction-free-trial(see 🧵thread along with the link parameters we usually add.Modal (Free users):
_yoast_wpseo_introductionsfrom usermetaFree vs Premium modal exclusivity:
_yoast_wpseo_introductions→ go to a Yoast page → confirm you see only the free trial modal (not the post-launch modal)_yoast_wpseo_introductions→ go to a Yoast page → confirm you see only the post-launch modal (not the free trial modal)Black Friday modal priority:
src/promotions/domain/black-friday-promotion.php, temporarily adjust theTime_Intervalto include the current date)_yoast_wpseo_introductionsfrom usermetaPlans page (Premium users):
wp-admin/admin.php?page=wpseo_licenses)https://yoa.st/aibi-plans-free-trial(see request) 🧵 along with the link parameters we usually add.Plans page (Free users):
Accessibility (screen reader):
Relevant test scenarios
Test instructions for QA when the code is in the RC
Impact check
This PR affects the following parts of the plugin, which may require extra testing:
UI changes
Other environments
Documentation
Quality assurance
Innovation
innovationlabel.Fixes #1112