Skip to content

Add AIBI free trial promotion modal and Plans page changes#23104

Merged
leonidasmi merged 3 commits intotrunkfrom
jpv/promote-aibi-free-trial-in-plugin
Mar 30, 2026
Merged

Add AIBI free trial promotion modal and Plans page changes#23104
leonidasmi merged 3 commits intotrunkfrom
jpv/promote-aibi-free-trial-in-plugin

Conversation

@JorPV
Copy link
Copy Markdown
Contributor

@JorPV JorPV commented Mar 26, 2026

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:

  • Adds an AIBI free trial promotion modal for premium users and a "Free trial available" badge with CTA on the Plans page AI+ card.

Relevant technical choices:

  • New introduction modal (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).
  • Post-launch modal restricted: The existing ai-brand-insights-post-launch modal is now restricted to free users only (added Product_Helper dependency to check is_premium()).
  • Plans page AI+ card: Added a "Free trial available" badge and "Start your free trial" button (using CardLink with ExternalLinkIcon) for premium users. Extracted AiPlusCardBadge and AiPlusCardActions sub-components to keep complexity under the ESLint threshold.
  • Accessibility improvements:
    • Uses UiModal.Title (wraps HeadlessUI's Dialog.Title) for proper aria-labelledby on the dialog, so screen readers announce the modal as a dialog with its title.
    • Uses useSvgAria hook on all SVG/icon elements (sparkle icon, external link icon) for consistent role="img" and aria-hidden="true".
    • Screen-reader-only text for external link buttons ("Opens in a new browser tab").
  • Placeholder shortlinks: https://yoa.st/aibi-introduction-free-trial (modal CTA) and https://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):

  • Enable Premium on a test site
  • Delete _yoast_wpseo_introductions from usermeta to reset seen introductions
  • Go to any Yoast admin page → confirm you see the new free trial modal with (compare it with the designs)
    • "YOAST AI BRAND INSIGHTS" label with sparkle icon
    • "Your first brand analysis is free!" title
    • "As a Yoast customer, you can run your first brand analysis for free." description
    • "Start your free trial" button with gradient background and external link icon
    • Confirm that the link is https://yoa.st/aibi-introduction-free-trial (see 🧵thread along with the link parameters we usually add.
    • "Close" button
image
  • Close the modal.
  • Close the modal, refresh → confirm it does not reappear
  • Confirm the shortlink includes the expected link parameters

Modal (Free users):

  • Disable Premium
  • Delete _yoast_wpseo_introductions from usermeta
  • Go to any Yoast admin page → confirm you see the existing post-launch modal ("Discover Brand Insights now"), NOT the free trial modal
image

Free vs Premium modal exclusivity:

  • With Premium enabled, delete _yoast_wpseo_introductions → go to a Yoast page → confirm you see only the free trial modal (not the post-launch modal)
  • With Premium disabled, delete _yoast_wpseo_introductions → go to a Yoast page → confirm you see only the post-launch modal (not the free trial modal)
  • With Premium enabled, after dismissing the free trial modal, disable Premium and delete usermeta → confirm you now see the post-launch modal

Black Friday modal priority:

  • Without Premium, make the Black Friday promotion active (in src/promotions/domain/black-friday-promotion.php, temporarily adjust the Time_Interval to include the current date)
  • Delete _yoast_wpseo_introductions from usermeta
  • Go to any Yoast page → confirm you see the Black Friday modal first
image
  • Refresh → confirm the post-launch modal now appears on the next visit
  • Reset the Black Friday promotion dates

Plans page (Premium users):

  • Enable Premium
  • Go to Plans page (wp-admin/admin.php?page=wpseo_licenses)
  • Confirm the AI+ card shows as per the design:
    • "Free trial available" badge at the top
    • "Start your free trial" primary button with external link icon
    • Confirm that the link is https://yoa.st/aibi-plans-free-trial (see request) 🧵 along with the link parameters we usually add.
    • "Learn more →" link below it

Plans page (Free users):

  • Disable Premium
  • Go to Plans page → confirm the AI+ card shows only the "Learn more" button (no badge, no trial button)

Accessibility (screen reader):

  • Open the free trial modal with a screen reader (e.g. VoiceOver on macOS)
  • Confirm the screen reader announces it as a dialog (not web content) with the title "Your first brand analysis is free!"
  • Confirm the sparkle icon and external link icon are hidden from the screen reader (decorative)
  • Confirm the "Start your free trial" button announces "(Opens in a new browser tab)" for screen reader users

Relevant test scenarios

  • Changes should be tested with the browser console open
  • Changes should be tested on different posts/pages/taxonomies/custom post types/custom taxonomies
  • Changes should be tested on different editors (Default Block/Gutenberg/Classic/Elementor/other)
  • Changes should be tested on different browsers
  • Changes should be tested on multisite

Test instructions for QA when the code is in the RC

  • QA should use the same steps as above.

Impact check

This PR affects the following parts of the plugin, which may require extra testing:

  • Introduction modals system (new modal added, post-launch modal visibility changed)
  • Plans page AI+ card (new badge and button for premium users)
  • Let's make sure that Free users that have seen the AI+ introduction modal with the previous plugin versions, will not see it again.

UI changes

  • This PR changes the UI in the plugin. I have added the 'UI change' label to this PR.

Other environments

  • This PR also affects Shopify.

Documentation

  • I have written documentation for this change.

Quality assurance

  • I have tested this code to the best of my abilities.
  • During testing, I had activated all plugins that Yoast SEO provides integrations for.
  • I have added unit tests to verify the code works as intended.
  • If any part of the code is behind a feature flag, my test instructions also cover cases where the feature flag is switched off.
  • I have written this PR in accordance with my team's definition of done.
  • I have checked that the base branch is correctly set.

Innovation

  • No innovation project is applicable for this PR.
  • This PR falls under an innovation project. I have attached the innovation label.
  • I have added my hours to the WBSO document.

Fixes #1112

…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.
@JorPV JorPV added the changelog: other Needs to be included in the 'Other' category in the changelog label Mar 26, 2026
@coveralls
Copy link
Copy Markdown

coveralls commented Mar 26, 2026

Pull Request Test Coverage Report for Build 9bb88cc73145d515f8cd150542428abcee0cad9e

Warning: 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

  • 12 of 32 (37.5%) changed or added relevant lines in 4 files are covered.
  • 4 unchanged lines in 1 file lost coverage.
  • Overall coverage decreased (-0.02%) to 53.458%

Changes Missing Coverage Covered Lines Changed/Added Lines %
packages/js/src/introductions/components/modals/ai-brand-insights-free-trial.js 0 9 0.0%
packages/js/src/plans/components/cards/ai-plus-card.js 0 11 0.0%
Files with Coverage Reduction New Missed Lines %
packages/js/src/components/WebinarPromoNotification.js 4 0.0%
Totals Coverage Status
Change from base Build fd50e4f5fcaadc210eba1fae17a91707767b5835: -0.02%
Covered Lines: 34358
Relevant Lines: 64561

💛 - Coveralls

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

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-trial introduction (PHP + React modal) that shows only to Premium users on Yoast admin pages.
  • Updated ai-brand-insights-post-launch introduction 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" }
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

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).

Suggested change
{ "Yoast AI Brand Insights" }
{ __( "Yoast AI Brand Insights", "wordpress-seo" ) }

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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

- Wrap "Yoast AI Brand Insights" in __() for i18n
- Add rel="noopener noreferrer" to external link button
@JorPV JorPV modified the milestones: 27.3, 27.4 Mar 26, 2026
Copy link
Copy Markdown
Contributor

@leonidasmi leonidasmi left a comment

Choose a reason for hiding this comment

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

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 Trial modal, if they ever uninstall Premium, they will be greeted by the similar Upgrade 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" }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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/" ),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this the right link? If so, can we put it in the Test Instructions, to treat it as the source of truth?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

When you hover over the button, you get weird styling because the font changes color:
image

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That is the color for visited links . It's actually a link that looks like a button. The same happens in the post-launch modal (free modal).

image

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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/" ), [] );
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this the right link? If so, can we put it in the Test Instructions, to treat it as the source of truth?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hm, I see a different link in the test instructions and the relevant thread 🤔 (https://yoa.st/aibi-introduction-free-trial)

Copy link
Copy Markdown
Contributor

@leonidasmi leonidasmi left a comment

Choose a reason for hiding this comment

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

CR + Acceptance is ✅

@leonidasmi leonidasmi merged commit bb3b29d into trunk Mar 30, 2026
38 checks passed
@leonidasmi leonidasmi deleted the jpv/promote-aibi-free-trial-in-plugin branch March 30, 2026 08:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog: other Needs to be included in the 'Other' category in the changelog

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants