PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / trunk
Yoast SEO – Advanced SEO with real-time guidance and built-in AI vtrunk
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 All 129 releases
← All changes | src/ai/content-planner/application/content-outline-command-handler.php +33 -59 27.7 → trunk View file →
@@ -2,17 +2,17 @@
2 2 // phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong -- Needed in the folder structure.
3 3
4 4 namespace Yoast\WP\SEO\AI\Content_Planner\Application;
5 5
6 -use Yoast\WP\SEO\AI\Authorization\Application\Token_Manager;
6 +use Yoast\WP\SEO\AI\Authentication\Application\AI_Request_Sender_Factory;
7 7 use Yoast\WP\SEO\AI\Consent\Application\Consent_Handler;
8 +use Yoast\WP\SEO\AI\Content_Planner\Domain\Content_Outline_Parameters;
8 9 use Yoast\WP\SEO\AI\Content_Planner\Domain\Section;
9 10 use Yoast\WP\SEO\AI\Content_Planner\Domain\Section_List;
10 11 use Yoast\WP\SEO\AI\Content_Planner\Infrastructure\Recent_Content\Recent_Content_Collector;
11 -use Yoast\WP\SEO\AI\HTTP_Request\Application\Request_Handler;
12 12 use Yoast\WP\SEO\AI\HTTP_Request\Domain\Exceptions\Forbidden_Exception;
13 +use Yoast\WP\SEO\AI\HTTP_Request\Domain\Exceptions\Insufficient_Scope_Exception;
13 14 use Yoast\WP\SEO\AI\HTTP_Request\Domain\Exceptions\Unauthorized_Exception;
14 -use Yoast\WP\SEO\AI\HTTP_Request\Domain\Request;
15 15 use Yoast\WP\SEO\AI\HTTP_Request\Domain\Response;
16 16
17 17 /**
18 18 * Handles the content outline command.
@@ -26,22 +26,15 @@
26 26 */
27 27 private $recent_content_collector;
28 28
29 29 /**
30 - * The token manager.
30 + * The auth strategy factory.
31 31 *
32 - * @var Token_Manager
32 + * @var AI_Request_Sender_Factory
33 33 */
34 - private $token_manager;
34 + private $ai_request_sender_factory;
35 35
36 36 /**
37 - * The request handler.
38 - *
39 - * @var Request_Handler
40 - */
41 - private $request_handler;
42 -
43 - /**
44 37 * The consent handler.
45 38 *
46 39 * @var Consent_Handler
47 40 */
@@ -49,44 +42,38 @@
49 42
50 43 /**
51 44 * The constructor.
52 45 *
53 - * @param Recent_Content_Collector $recent_content_collector The recent content collector.
54 - * @param Token_Manager $token_manager The token manager.
55 - * @param Request_Handler $request_handler The request handler.
56 - * @param Consent_Handler $consent_handler The consent handler.
46 + * @param Recent_Content_Collector $recent_content_collector The recent content collector.
47 + * @param AI_Request_Sender_Factory $ai_request_sender_factory The auth strategy factory.
48 + * @param Consent_Handler $consent_handler The consent handler.
57 49 */
58 50 public function __construct(
59 51 Recent_Content_Collector $recent_content_collector,
60 - Token_Manager $token_manager,
61 - Request_Handler $request_handler,
52 + AI_Request_Sender_Factory $ai_request_sender_factory,
62 53 Consent_Handler $consent_handler
63 54 ) {
64 - $this->recent_content_collector = $recent_content_collector;
65 - $this->token_manager = $token_manager;
66 - $this->request_handler = $request_handler;
67 - $this->consent_handler = $consent_handler;
55 + $this->recent_content_collector = $recent_content_collector;
56 + $this->ai_request_sender_factory = $ai_request_sender_factory;
57 + $this->consent_handler = $consent_handler;
68 58 }
69 59
60 + // phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber -- PHPCS doesn't track exceptions thrown by called services.
61 +
70 62 /**
71 63 * Handles the content outline command by collecting recent content and requesting an outline from the AI API.
72 64 *
73 - * @param Content_Outline_Command $command The content outline command.
74 - * @param bool $retry_on_unauthorized Whether to retry on unauthorized response.
65 + * @param Content_Outline_Command $command The content outline command.
75 66 *
76 - * @throws Unauthorized_Exception When the API returns an unauthorized response and retry is exhausted.
77 - * @throws Forbidden_Exception When consent has been revoked.
67 + * @throws Unauthorized_Exception When the API returns an unauthorized response and retry is exhausted.
68 + * @throws Forbidden_Exception When consent has been revoked.
69 + * @throws Insufficient_Scope_Exception When the OAuth path's token is missing the required scope.
78 70 *
79 71 * @return Section_List A list of outline sections.
80 72 */
81 - public function handle(
82 - Content_Outline_Command $command,
83 - bool $retry_on_unauthorized = true
84 - ): Section_List {
85 - $recent_content = $this->recent_content_collector->collect( $command->get_post_type() );
73 + public function handle( Content_Outline_Command $command ): Section_List {
74 + $recent_content = $command->get_recent_content();
86 75 $about_page = $this->recent_content_collector->collect_about_page( $command->get_post_type() );
87 - $token = $this->token_manager->get_or_request_access_token( $command->get_user() );
88 - $recent_content = $recent_content->to_array();
89 76
90 77 $existing_posts = \array_map(
91 78 static function ( $post ) {
92 79 return [
@@ -111,38 +98,25 @@
111 98 if ( $about_page ) {
112 99 $content['about_page'] = $about_page;
113 100 }
114 101
115 - $request_body = [
116 - 'subject' => [
117 - 'language' => $command->get_language(),
118 - 'content' => $content,
119 - ],
120 - ];
102 + $parameters = new Content_Outline_Parameters(
103 + $command->get_user(),
104 + $command->get_language(),
105 + $content,
106 + $command->get_editor(),
107 + );
121 108
122 - $request_headers = [
123 - 'Authorization' => "Bearer $token",
124 - 'X-Yst-Cohort' => $command->get_editor(),
125 - ];
126 -
127 109 try {
128 - $response = $this->request_handler->handle( new Request( '/content-planner/next-post-outline', $request_body, $request_headers ) );
129 - } catch ( Unauthorized_Exception $exception ) {
130 - // Delete the stored JWT tokens, as they appear to be no longer valid.
131 - $this->token_manager->clear_tokens( (string) $command->get_user()->ID );
132 -
133 - if ( ! $retry_on_unauthorized ) {
134 - throw $exception;
135 - }
136 -
137 - // Try again once more by fetching a new set of tokens and trying the outline endpoint again.
138 - return $this->handle( $command, false );
110 + $sender = $this->ai_request_sender_factory->create( $command->get_user() );
111 + $response = $sender->get_content_outline_suggestions( $parameters );
112 + } catch ( Insufficient_Scope_Exception $exception ) {
113 + throw $exception;
139 114 } catch ( Forbidden_Exception $exception ) {
140 - // Follow the API in the consent being revoked (Use case: user sent an e-mail to revoke?).
141 - // phpcs:disable WordPress.Security.EscapeOutput.ExceptionNotEscaped -- false positive.
142 115 $this->consent_handler->revoke_consent( $command->get_user()->ID );
116 + // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
143 117 throw new Forbidden_Exception( 'CONSENT_REVOKED', $exception->getCode() );
144 - // phpcs:enable WordPress.Security.EscapeOutput.ExceptionNotEscaped
118 +
145 119 }
146 120
147 121 return $this->build_outline( $response );
148 122 }