feat: hold back the Premium update until matching Free is available - #23373
Open
enricobattocchi wants to merge 1 commit into
Open
feat: hold back the Premium update until matching Free is available#23373enricobattocchi wants to merge 1 commit into
enricobattocchi wants to merge 1 commit into
Conversation
…Free version is available Yoast SEO Premium x.y requires Yoast SEO x.y. When the Premium version offered by the My Yoast licensing API is ahead of the latest Free version the site can currently see, the update is now placed in the no_update bucket instead of response. That hides it from the Updates screen and skips it in the auto-updater, mirroring how WordPress core holds back updates, and it self-corrects per site once the matching Free version is available. Only the major and minor version components are compared, so patch releases are not affected. The check is limited to Premium for now; the seam is isolated in a single helper so other add-ons can be added once their required Free version is known. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VqP5w8YtJBwAPhutDCsPUa
Coverage Report for CI Build 2Coverage decreased (-0.5%) to 53.25%Details
Uncovered Changes
Coverage RegressionsNo coverage regressions found. Coverage Stats💛 - Coveralls |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR prevents Yoast SEO Premium updates from being offered to a site until the matching Yoast SEO (Free) major.minor version is actually available to that site via WordPress.org’s update data, avoiding mismatched Free/Premium pairs during phased rollouts.
Changes:
- Adds a hold-back guard in
WPSEO_Addon_Manager::check_for_updates()to keep Premium updates inno_updatewhen Free’s latest availablenew_versionis behind Premium’s offered major.minor. - Introduces helper methods to compare major.minor versions while ignoring patch/pre-release suffixes.
- Adds unit tests covering the hold-back behavior for Premium vs non-Premium add-ons and patch releases.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
inc/class-addon-manager.php |
Adds the Premium update hold-back decision and version-parsing helpers inside the add-on update flow. |
tests/Unit/Inc/Addon_Manager_Test.php |
Adds unit coverage to ensure Premium updates are hidden/shown based on Free availability and that other add-ons remain unaffected. |
Comment on lines
+428
to
+434
| /** | ||
| * Extracts the major.minor part of a version string, ignoring any patch or pre-release suffix. | ||
| * | ||
| * @param string $version The version string. | ||
| * | ||
| * @return string|null The major.minor version, or null when it cannot be determined. | ||
| */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
Yoast SEO Premium and Yoast SEO (Free) are released together and are built to match: Premium
x.yexpects Freex.yalongside it. They reach sites through different channels at different speeds. Free is distributed by the WordPress.org plugin directory, which rolls a new version out gradually over hours; Premium is downloaded immediately from My Yoast through the customer license. In that gap a site can be offered the Premiumx.yupdate before Freex.yis available to it, and updating Premium then breaks the pairing. This happened with Premium 27.8 and required manually pulling Premium from distribution until Free 27.8 had spread.This PR holds the Premium update back until the matching Free version is available to that specific site. It keys off the real Free availability each site sees, so it self-corrects per site with no fixed timer and no server-side coordination, mirroring how WordPress core silently holds back updates.
Summary
This PR can be summarized in the following changelog entry:
Relevant technical choices:
WPSEO_Addon_Manager::check_for_updates(), the method that already chooses, per add-on, between theresponsebucket (an update is shown and can auto-install) and theno_updatebucket (nothing shown). The new guard keeps a held-back Premium update inno_update.no_updaterather than failing the install mirrors how WordPress core holds back updates: nothing appears on the Updates screen, and the auto-updater skips it too, since it only acts on entries inresponse.x.y.zonly needs Freex.yto be available.new_version); when it is absent the guard fails open, so updates are never hidden on incomplete data.x.y, so it stays out until the required Free version can be provided per product (ideally from the licensing API).YOAST_SEO_CHECK_REQUIRED_VERSIONheader check, which blocks a manually uploaded incompatible add-on. That handles manual installs; this hides the offered and automatic update.Test instructions
Test instructions for the acceptance test before the PR gets merged
This PR can be acceptance tested by following these steps:
The behaviour only occurs when a newer Premium is available while the matching Free version is not yet available to the site, so the scenario has to be simulated. On a site with Free and Premium installed at the same version (for example both
27.7):wp-content/mu-plugins/holdback-test.php. It makes the license report Premium27.8and pins the latest Free the site can see to27.7. Make sure the installed Premium version is lower than the offered one (here, set the Premium plugin's installed version to27.7).27.7.new_versionin the snippet from27.7to27.8(the matching Free is now available), click "Check again", and reload the Plugins screen.27.8update now appears normally.Relevant test scenarios
Test instructions for QA when the code is in the RC
QA can test this PR by following these steps:
Impact check
This PR affects the following parts of the plugin, which may require extra testing:
Other environments
[shopify-seo], added test instructions for Shopify and attached theShopifylabel to this PR.[yoast-doc-extension], added test instructions for Yoast SEO for Google Docs and attached theGoogle Docs Add-onlabel to this PR.Documentation
Quality assurance
grunt build:imagesand committed the results, if my PR introduces or edits images or SVGs.Innovation
innovationlabel.Fixes #23374