Skip to content

23302 manage user consent through yoast ai#23306

Open
pls78 wants to merge 8 commits into
23301-make-the-token_manager-consent-agnosticfrom
23302-manage-user-consent-through-yoast-ai
Open

23302 manage user consent through yoast ai#23306
pls78 wants to merge 8 commits into
23301-make-the-token_manager-consent-agnosticfrom
23302-manage-user-consent-through-yoast-ai

Conversation

@pls78
Copy link
Copy Markdown
Member

@pls78 pls78 commented May 26, 2026

Context

  • Currently, granting or revoking consent only updates the local user meta; the Yoast AI service has no per-user view of consent. We want it to be informed, so its consent state stays in sync with the local one.

Summary

This PR can be summarized in the following changelog entry:

  • Calls the Yoast AI service when a user grants or revokes consent, keeping the service's per-user consent state in sync with the local user meta.

Relevant technical choices:

  • This PR is stacked on top of 23301 make the token manager consent agnostic #23303: that one should be reviewed and merged first.
  • The first commit refactors Request and API_Client from a bool $is_post flag to a string $http_method (with Request::METHOD_GET/POST/DELETE constants), to accommodate the new
    DELETE /user/consent call.
  • grant_consent() is transactional (any HTTP failure → propagate, local meta untouched: this means the local meta is only written if the remote call succeeded); revoke_consent() is security-first (HTTP failure → log via the PSR-3 logger + swallow, local meta always cleared no matter what).

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 have a working Yoast AI setup (a licensed site URL reachable from the Yoast AI staging service).
  • Execute the following snippet either by creating a mu-plugin at wp-content/mu-plugins/api-calls.php or through a plugin to log every outbound HTTP call to yoa.st in the PHP error log:
  <?php
  add_action( 'http_api_debug', function ( $response, $context, $class, $args, $url ) {
      if ( strpos( $url, 'yoa.st' ) === false ) {
          return;
      }
      error_log( sprintf(
          '[Yoast AI] %s %s -> %s',
          $args['method'] ?? 'POST',
          $url,
          is_wp_error( $response ) ? $response->get_error_message() : wp_remote_retrieve_response_code( $response )
      ) );
  }, 10, 5 );
  • Tail the PHP error log (e.g. tail -f wp-content/debug.log with WP_DEBUG_LOG on).
    • If you're using TasteWP or any other test environment where no console access is available, use any WordPress plugin that lets you inspect WordPress logs

Happy path

  • Visit your WordPress user Profile.
  • If the AI consent button reads Grant consent, click it and confirm in the modal.
    • Verify the AI features become enabled.
    • In the error log, verify you see:
      [Yoast AI] POST https://ai.yoa.st/api/v1/user/consent -> 200
      
  • Now click Revoke consent and confirm in the modal.
    • Verify the AI features get disabled.
    • In the error log, verify you see:
      [Yoast AI] DELETE https://ai.yoa.st/api/v1/user/consent -> 200
      

revoke_consent is security-first

  • Execute the following snippet either by creating a mu-plugin at wp-content/mu-plugins/yoast-ai-failure-sim.php or through a plugin. This pre-empts the DELETE /user/consent call with a synthetic 500 and logs the error with a concrete implementation of our PSR-3 logger
  <?php
  add_filter( 'wpseo_logger', function ( $logger ) {
      return new class extends \YoastSEO_Vendor\Psr\Log\AbstractLogger {
          public function log( $level, $message, array $context = [] ) {
              error_log( sprintf( '[Yoast %s] %s | %s',
                  strtoupper( (string) $level ),
                  (string) $message,
                  wp_json_encode( $context )
              ) );
          }
      };
  } );

  add_filter( 'pre_http_request', function ( $preempt, $args, $url ) {
      if ( ! preg_match( '#/user/consent$#', $url ) ) {
          return $preempt;
      }
      if ( ( $args['method'] ?? '' ) !== 'DELETE' ) {
          return $preempt;
      }
      return [
          'response' => [ 'code' => 500, 'message' => 'Internal Server Error' ],
          'body'     => '{"message":"Simulated AI service failure","status":500}',
          'headers'  => [], 'cookies' => [], 'filename' => null,
      ];
  }, 10, 3 );
  • Grant consent (the POST is not pre-empted).
  • Click Revoke consent.
    • Verify the modal does NOT show an error -> the route returns success.
    • Verify the AI features get disabled.
    • In the error log, verify you see:
      [Yoast WARNING] Failed to revoke consent on the Yoast AI service; clearing local consent anyway. | {"user_id":<your-id>,"exception":"Simulated AI service failure"}
      
    • In wp_usermeta, verify _yoast_wpseo_ai_consent for your user is deleted despite the simulated failure.
  • Remove yoast-ai-failure-sim.php when done with this section.

grant_consent is transactional

  • Re-install the failure-sim mu-plugin, but change 'DELETE' to 'POST' in the method check, so the POST /user/consent call is the one pre-empted.
  • Make sure your user currently has NO consent (revoke first if needed).
  • Click Grant consent.
    • Verify the modal shows an error -> the route returns 500.
    • Verify the AI features stay disabled.
    • In wp_usermeta, verify _yoast_wpseo_ai_consent for your user is not set (local meta untouched on grant failure).
  • Remove the failure-sim mu-plugin when done.

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 HTTP-method refactor of Request / API_Client touches the primitive used by every outbound AI service call. Worth a smoke test of all AI-related features (Generate, Optimize, Summarize, Content Planner, Usage) on top of the consent-specific tests above. Please note https://github.com/Yoast/wordpress-seo-premium/pull/4971 needs to be merged first/checked out to test Premium features with this PR.

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

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

@pls78 pls78 linked an issue May 26, 2026 that may be closed by this pull request
@pls78 pls78 added the changelog: non-user-facing Needs to be included in the 'Non-userfacing' category in the changelog label May 26, 2026
@pls78 pls78 changed the base branch from trunk to 23301-make-the-token_manager-consent-agnostic May 26, 2026 15:13
@coveralls
Copy link
Copy Markdown

coveralls commented May 26, 2026

Coverage Report for CI Build 0

Warning

No base build found for commit 951901d on 23301-make-the-token_manager-consent-agnostic.
Coverage changes can't be calculated without a base build.
If a base build is processing, this comment will update automatically when it completes.

Coverage: 50.322%

Details

  • Patch coverage: 55 uncovered changes across 7 files (38 of 93 lines covered, 40.86%).

Uncovered Changes

File Changed Covered %
src/ai-consent/application/consent-handler.php 27 0 0.0%
src/ai-http-request/infrastructure/api-client.php 13 0 0.0%
src/ai-http-request/domain/request.php 6 0 0.0%
src/ai/http-request/domain/request.php 6 0 0.0%
src/ai-generator/user-interface/get-usage-route.php 1 0 0.0%
src/ai-http-request/application/request-handler.php 1 0 0.0%
src/ai/http-request/infrastructure/api-client.php 10 9 90.0%
Total (10 files) 93 38 40.86%

Coverage Regressions

Requires a base build to compare against. How to fix this →


Coverage Stats

Coverage Status
Relevant Lines: 41519
Covered Lines: 20893
Line Coverage: 50.32%
Coverage Strength: 4.19 hits per line

💛 - Coveralls

@pls78 pls78 marked this pull request as ready for review May 27, 2026 12:26
@pls78 pls78 requested a review from a team as a code owner May 29, 2026 14:32
@pls78 pls78 force-pushed the 23302-manage-user-consent-through-yoast-ai branch from b0f2e6e to 879a3d1 Compare May 29, 2026 20:36
@pls78 pls78 force-pushed the 23302-manage-user-consent-through-yoast-ai branch from 879a3d1 to a2074da Compare May 29, 2026 20:54
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.

Manage user consent through Yoast AI

2 participants