Skip to content

refactor(ai): deprecate legacy ai-* modules in Free#23227

Open
thijsoo wants to merge 3 commits into
trunkfrom
632-re-organize-ai-code-in-free-premium-and-deprecate-the-old-code-in-free
Open

refactor(ai): deprecate legacy ai-* modules in Free#23227
thijsoo wants to merge 3 commits into
trunkfrom
632-re-organize-ai-code-in-free-premium-and-deprecate-the-old-code-in-free

Conversation

@thijsoo
Copy link
Copy Markdown
Contributor

@thijsoo thijsoo commented May 4, 2026

Only merge 3 releases after premium 27.7 is released. So 28.0 for premium.

Context

  • Free shipped two parallel AI codebases: the new src/ai/ tree (canonical, namespaces Yoast\WP\SEO\AI\…) and the legacy src/ai-* tree (namespaces Yoast\WP\SEO\AI_*\…) that existed only to support Premium versions older than 27.5-RC0.

Summary

This PR can be summarized in the following changelog entry:

  • Deprecates the legacy src/ai-* AI modules and the Old_Premium_AI_Conditional / New_Premium_Or_Free_AI_Conditional gating helpers in favour of the reorganized src/ai/ modules.

Relevant technical choices:

  • Dropped New_Premium_Or_Free_AI_Conditional from the get_conditionals() of every active integration/route under src/ai/. With the legacy tree gone, the version gate no longer has a purpose: the new code is the only AI implementation and should load whenever the feature-level conditionals (AI_Conditional, AI_Editor_Conditional) are met.
  • Old Premium installs (< 27.5-RC0) will no longer load AI features from Free as a side-effect — that is the intended consequence of removing the legacy bridge.

Test instructions

Test instructions for the acceptance test before the PR gets merged

This PR can be acceptance tested by following these steps:

  • On a Free-only install (no Premium), open the post editor and confirm the Yoast AI generator panel still appears in the sidebar and works end-to-end (consent, generate suggestions for a title/meta description, usage counter updates).
  • On the same install, open the user profile page and confirm the AI features consent toggle still renders and toggling it succeeds.
  • Hit /wp-json/yoast/v1/ai_generator/get_suggestions, /wp-json/yoast/v1/ai_generator/consent, and /wp-json/yoast/v1/ai/free_sparks from the browser; expect a 401 (or REST cookie rejection) for unauthenticated requests rather than 404 — confirms the new routes still register.
  • On an install with current Premium (≥ 27.5-RC0), repeat the editor and consent flow above and confirm everything still works.
  • Optional: with WP_DEBUG_LOG enabled, exercise the editor flow and confirm wp-content/debug.log does not contain any _deprecated_function notices originating from the AI flows during normal use — they should only fire if something explicitly calls a legacy class.

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.

QA can test this PR by following these steps:

  • Not applicable — this is an internal refactor. The acceptance test above already exercises the only user-visible surface (the AI editor panel and consent toggle), and once the code is in the RC the existing AI test scripts continue to cover it.

Impact check

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

  • The full AI generator flow in the post editor (suggestions, consent, usage counter, free sparks) — covered by the new src/ai/ tree.
  • The AI features consent toggle on the user profile page.
  • Any third-party code that imported the legacy Yoast\WP\SEO\AI_*\… classes or resolved Old_Premium_AI_Conditional / New_Premium_Or_Free_AI_Conditional from the DI container will now see PHP deprecation notices but will continue to work.

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.
  • This PR also affects Yoast SEO for Google Docs. I have added a changelog entry starting with [yoast-doc-extension], added test instructions for Yoast SEO for Google Docs and attached the Google Docs Add-on 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.
  • I have run grunt build:images and committed the results, if my PR introduces or edits images or SVGs.

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.

thijsoo and others added 3 commits May 4, 2026 13:54
Move the five `ai-*` folders from `src/` to `src/deprecated/src/` and decorate
every class with `@deprecated 27.7` + `@codeCoverageIgnore` plus a
`_deprecated_function()` call in each method body. The `src/deprecated/`
directory is excluded from the Symfony loader, so these classes no longer
self-register as integrations or routes; the new `src/ai/` tree is now the
only active AI module in Free.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Remove `New_Premium_Or_Free_AI_Conditional` from the `get_conditionals()`
return of every active integration and route under `src/ai/` and update the
matching unit tests. With the legacy `ai-*` tree deprecated, the version
gate has no remaining purpose: the new code is the only AI implementation
in Free, so it should load whenever the other AI conditionals (e.g.
`AI_Conditional`, `AI_Editor_Conditional`) are met.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Move `Old_Premium_AI_Conditional` and `New_Premium_Or_Free_AI_Conditional`
to `src/deprecated/src/conditionals/`, decorate them with the standard
`@deprecated 27.7` + `_deprecated_function()` pattern, and register both in
`deprecated-classes.php` so any external caller resolving them via the DI
container also gets a Symfony deprecation notice. Their unit tests are
removed because no active code references them anymore.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@thijsoo thijsoo added the changelog: non-user-facing Needs to be included in the 'Non-userfacing' category in the changelog label May 4, 2026
@coveralls
Copy link
Copy Markdown

Coverage Report for CI Build 67351

Coverage increased (+0.5%) to 53.437%

Details

  • Coverage increased (+0.5%) from the base build.
  • Patch coverage: 8 of 8 lines across 8 files are fully covered (100%).
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 64509
Covered Lines: 34513
Line Coverage: 53.5%
Relevant Branches: 16414
Covered Branches: 8730
Branch Coverage: 53.19%
Branches in Coverage %: Yes
Coverage Strength: 46630.51 hits per line

💛 - Coveralls

@thijsoo
Copy link
Copy Markdown
Contributor Author

thijsoo commented May 4, 2026

/build-zip

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 4, 2026

📦 Plugin zip built successfully!

Download it from the workflow run.

Copy link
Copy Markdown
Member

@pls78 pls78 left a comment

Choose a reason for hiding this comment

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

When using the AI features through the UI all is fine, but if I try the REST endpoints I get some unexpected behavior:
1 . https://programmes-hay-eleven-dig.trycloudflare.com/wp-json/yoast/v1/ai/free_sparks is reachable even without the consent granted
2. https://programmes-hay-eleven-dig.trycloudflare.com/wp-json/yoast/v1/ai_generator/get_suggestions returns 403 and not 401

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog: non-user-facing Needs to be included in the 'Non-userfacing' category in the changelog

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants