Skip to content

Conversation

pls78
Copy link
Member

@pls78 pls78 commented Sep 6, 2025

Context

Summary

This PR can be summarized in the following changelog entry:

  • Adds an introduction which would show after 14 days of the plugin activation or update.

Relevant technical choices:

  • This PR changes the way introductions that have been seen by a user are stored in the user meta: previously we were storing an array of the form [ 'introduction_name' => bool ] which would flag if that introduction has been seen. Now, introductions that has been seen are represented as an array of the form [ 'is_seen' => bool, 'seen_on' => timestamp ].

Test instructions

Test instructions for the acceptance test before the PR gets merged

This PR can be acceptance tested by following these steps:

  • Make sure you don't have Premium activated
  • Start with a fresh installation of this RC/PR
  • Don't visit any Yoast SEO page yet
Test introductions user meta is correctly updated
  • With a MySQL client look for the wp_options table
    • Copy the value in the option_value column where option_name = wpseo
    • Unserialize it and verify you have a first_activated_on timestamp with an integer value
  • Now look for the wp_usermeta table
    • Find the row where meta_key = _yoast_wpseo_introductions and edit the value of the meta_value column by copy-pasting the following:
    a:2:{s:25:"ai-fix-assessments-upsell";b:0;s:42:"ai-generate-titles-and-descriptions-upsell";b:1;}
    
  • Visit a Yoast SEO page
    • Verify you see the AI Brand Insights pre-launch introduction
  • Go back to the wp_usermeta table, same row where meta_key = _yoast_wpseo_introductions
    • Check that the value in the meta_value column is now:
    a:3:{s:25:"ai-fix-assessments-upsell";a:2:{s:7:"is_seen";b:0;s:7:"seen_on";i:0;}s:42:"ai-generate-titles-and-descriptions-upsell";a:2:{s:7:"is_seen";b:1;s:7:"seen_on";i:1757419869;}s:28:"ai-brand-insights-pre-launch";a:2:{s:7:"is_seen";b:1;s:7:"seen_on";i:1757419869;}}
    
    That is:
    • the ai-fix-assessments-upsell intrduction is marked as not seen with a timestamp of 0
    • the ai-generate-titles-and-descriptions-upsell introduction has the timestamp added
    • the ai-brand-insights-pre-launch introduction has been added with a timestamp
  • Copy this value and store it somewere as this is going to be your baseline value for the tests
Test the introduction is shown when the user has activated the plugin more than two weeks ago but only if another introduction has not been seen in the last week
  • Edit the value in the option_value column where option_name = wpseo: change the first_activated_on timestamp to something more than two weeks ago (use this site to manipulate time stamps), for example "first_activated_on":i:1755326382; for August 16th 2025
    • Visit a Yoast SEO page
    • Verify you still don't see the introduction
    • Edit the wp_usermeta table where meta_key = _yoast_wpseo_introductions: change all the time stamps to something more than a week ago
    • Refresh the page and verify you now get the introduction
    • Verify the introductions conforms to the design (it's the one under Upsell / Admin / Timed)
Test the introduction is shown when the user has updated the plugin more than two weeks ago but only if another introduction has not been seen in the last week
  • Restore the baseline value in of the wp_usermeta table where meta_key = _yoast_wpseo_introductions column
  • Edit the value in the option_value column where option_name = wpseo (you will need to unserialize->edit->serialize again to save a proper value)
    • change the last_updated_on timestamp to something more than two weeks ago (use this site to manipulate time stamps)
    • change also the previous_version value to 25.8, like this: "previous_version":s:4:"25.8";
    • Visit a Yoast SEO page
    • Verify you still don't see the introduction
    • Edit the wp_usermeta table where meta_key = _yoast_wpseo_introductions: change all the time stamps to something more than a week ago
    • Refresh the page and verify you now get the introduction
Test the introduction is not shown in the `First Time Configuration` page
  • Restore the baseline value in of the wp_usermeta table where meta_key = _yoast_wpseo_introductions column
  • Make sure you're in conditions of seeing the delayed upsell: edit src/introductions/application/delayed-premium-upsell.php, change line 103 from return $this->should_show_after_delay(); to return true;
  • Visit http://YOU_BLOG_URL/wp-admin/admin.php?page=wpseo_dashboard#/first-time-configuration
    • Verify you don't see the introduction
    • Go to the wp_usermeta table, same row where meta_key = _yoast_wpseo_introductions
      • Check that the value in the meta_value now contains the substring s:22:"delayed-premium-upsell";a:2:{s:7:"is_seen";b:0;s:7:"seen_on";i:0;}
  • Visit another Yoast SEO page and verify you do see the introduction
Smoke test having the BF modal active too
  • Edit src\promotions\domain\black-friday-promotion.php to make sure BF is active: new Time_Interval( \gmmktime( 10, 00, 00, 11, 28, 2024 ), \gmmktime( 10, 00, 00, 12, 3, 2026 ) )
  • In a fresh site, or a recently updated one
  • Visit a yoast page and confirm that you get the BF ad
  • Refresh the page and confirm that you gt the AI insight ad
  • Refresh the page and confirm that you dont get any other ad
  • Using the instructions above, make sure you set that you installed or upgraded Yoast over 2 weeks ago
  • Refresh the page and confirm that you dont get any other ad
  • Using the instructions above, make sure you set that you saw the BF modal over 1 week ago
  • Refresh the page and confirm that you dont get any other ad
  • Using the instructions above, make sure you set that you saw the AI insight modal over 1 week ago
  • Refresh the page and confirm that you now DO get the delayed upsell modal

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:

  • The introductions framework has been changed to take into account the new format with timestamps: please perform a regression test for the introduction feature.

Other environments

  • This PR also affects Shopify. I have added a changelog entry starting with [shopify-seo], added test instructions for Shopify and attached the Shopify label to this PR.

Documentation

  • I have written documentation for this change. For example, comments in the Relevant technical choices, comments in the code, documentation on Confluence / shared Google Drive / Yoast developer portal, or other.

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 #762

@coveralls
Copy link

coveralls commented Sep 6, 2025

Pull Request Test Coverage Report for Build aaea12fe12c7195d02e0f7ea5fe67d379d3e3227

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

  • 15 of 89 (16.85%) changed or added relevant lines in 10 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall first build on add-delayed-premium-upsell at 41.602%

Changes Missing Coverage Covered Lines Changed/Added Lines %
inc/class-upgrade.php 0 1 0.0%
packages/js/src/introductions/components/modal.js 0 1 0.0%
src/introductions/application/introductions-collector.php 1 2 50.0%
packages/js/src/introductions/components/features/features-data.js 0 2 0.0%
packages/js/src/introductions/components/features/feature.js 0 3 0.0%
src/introductions/infrastructure/introductions-seen-repository.php 10 13 76.92%
packages/js/src/introductions/components/modals/delayed-premium-upsell.js 0 9 0.0%
src/introductions/user-interface/introductions-integration.php 3 12 25.0%
src/introductions/application/delayed-premium-upsell.php 0 45 0.0%
Totals Coverage Status
Change from base Build 6a9988bdde4a038d2d2dacdfff3f05948c180746: 41.6%
Covered Lines: 22173
Relevant Lines: 49829

💛 - Coveralls

@pls78 pls78 added the changelog: other Needs to be included in the 'Other' category in the changelog label Sep 8, 2025
@pls78 pls78 changed the base branch from trunk to release/26.0 September 9, 2025 13:16
@pls78 pls78 added this to the 26.0 milestone Sep 9, 2025
@pls78 pls78 marked this pull request as ready for review September 9, 2025 13:22
Copy link
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: 🚧

Also, there are some visual differences in the modal, like

  • the background that looks much more red in the implementation than the design
  • Yoast SEO Premium is in color in the intro copy of the design
  • the perks are in bold in the design

so let's involve UX in this at some point.

public function enqueue_assets() {
$user_id = $this->user_helper->get_current_user_id();
$user_id = $this->user_helper->get_current_user_id();
$this->introductions_collector->update_metadata_for( $user_id );
Copy link
Contributor

Choose a reason for hiding this comment

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

In theory this has the potential to run an extra SELECT and an extra UPDATE query on every admin page load, since it always runs.

However:

  • WP caching makes it so that there's no extra SELECT as long as there has been a prior wp_get_current_user() call, which it's always the case (as wp_get_current_user() is being called from a lot of WP functions that we already use in admin calls)
  • The internal logic of WP's update_metadata() is smart enough to check the old value of the metadata and as long as it's a single value and it's the same with what we're about to update it with, it returns early with no UPDATE queries
    which means that there will be no extra queries on admin page loads, except the first time that we need to update the meta.

Which means that this is a no-issue, but wanted to leave this comment here for future reference.

@leonidasmi
Copy link
Contributor

CR: ✅

@leonidasmi
Copy link
Contributor

One issue discovered at acceptance testing, things don't work 100% properly on new installs and we're dependent on not having other introductions for the delayed upsell to be delayed.

Steps to reproduce:

  • Let's first make it so that we don't have any other introduction lined up to be shown (because at some point, our product requirements might dictate so). Edit AI_Brand_Insights_Pre_Launch::should_show() to always return false
  • Install Yoast SEO in a new site (so, not update, fresh install)
  • Go to one of the Yoast pages without waiting 2 weeks from the time you installed.
  • See that the upsell is shown, even though it should be shown only after two weeks.

The problem lies on the should_show_after_delay() function and specifically in the

		if ( $previous_version === '' && ( $current_time - $first_activated_on ) >= $delay ) {
			return $this->is_last_introduction_seen_older_than_a_week();
		}

chunk. Basically, if the second condition is false, we should probably return early with false, not continue with the other code of the function.

@leonidasmi
Copy link
Contributor

There's another issue I discovered, although it exists in the production versions, sort of. It all starts with the old requirement that no introduction should be shown in the FTC. From this PR on, we do that by sending a REST request setting the introductions to not seen again, when on the FTC.

If:

  • a user goes to the FTC without ever visiting any other Yoast page (which can be a common flow, considering that we guide people to the FTC once they install the plugin)
  • we have more than one introduction set to be seen in Yoast pages

then:

  • the introduction with the highest priority will never be shown to that user.

because:

  • there's a race condition from firing multiple REST requests and the second one overwrites the first one, thus setting the highest priority introduction as seen again.

We already have that problem in the released versions, but because we have no multiple introductions yet (not until Black Friday comes - until then we only have the AI insights one), it's never triggered. If we release a fix before Black Friday, no user will be affected (unless there's a user that has Yoast installed already, has never visited a Yoast page and goes straight to the FTC during BF, which is a highly unlikely scenario).

After careful consideration with @pls78 we think this is not a blocker for this PR either, because the only way we trigger this problem is to have multiple introductions set to be seen but prevented in the FTC. That's unlikely to happen here too because

  • The user that installs this version might go straight to the FTC but at that point this delayed upsell is not set to be seen yet for another two weeks.
  • A different admin that didnt install this version but went into the admin area two weeks after the install, will probably never go straight into the FTC without going through other Yoast pages

@leonidasmi
Copy link
Contributor

Acceptance check is ✅

@leonidasmi leonidasmi merged commit 9fc928f into release/26.0 Sep 12, 2025
38 checks passed
@leonidasmi leonidasmi deleted the add-delayed-premium-upsell branch September 12, 2025 11:08
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.

3 participants