PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 28.4
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v28.4
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
wordpress-seo / src / ai / generator / user-interface / get-usage-route.php

get-usage-route.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 28.4, at src/ai/generator/user-interface/get-usage-route.php

164 lines 5.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong -- Needed in the folder structure.
4 namespace Yoast\WP\SEO\AI\Generator\User_Interface;
5
6 use WP_REST_Response;
7 use WPSEO_Addon_Manager;
8 use Yoast\WP\SEO\AI\Authentication\Application\AI_Request_Sender_Factory;
9 use Yoast\WP\SEO\AI\Consent\Application\Consent_Handler;
10 use Yoast\WP\SEO\AI\Generator\Domain\Usage_Parameters;
11 use Yoast\WP\SEO\AI\HTTP_Request\Domain\Exceptions\Forbidden_Exception;
12 use Yoast\WP\SEO\AI\HTTP_Request\Domain\Exceptions\Insufficient_Scope_Exception;
13 use Yoast\WP\SEO\AI\HTTP_Request\Domain\Exceptions\Remote_Request_Exception;
14 use Yoast\WP\SEO\AI\HTTP_Request\Domain\Exceptions\Too_Many_Requests_Exception;
15 use Yoast\WP\SEO\AI\HTTP_Request\Domain\Exceptions\WP_Request_Exception;
16 use Yoast\WP\SEO\Conditionals\AI_Conditional;
17 use Yoast\WP\SEO\Main;
18 use Yoast\WP\SEO\Routes\Route_Interface;
19
20 /**
21 * Registers a route to get suggestions from the AI API
22 *
23 * @makePublic
24 *
25 * @phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded
26 */
27 class Get_Usage_Route implements Route_Interface {
28
29 use Route_Permission_Trait;
30
31 /**
32 * The namespace for this route.
33 *
34 * @var string
35 */
36 public const ROUTE_NAMESPACE = Main::API_V1_NAMESPACE;
37
38 /**
39 * The prefix for this route.
40 *
41 * @var string
42 */
43 public const ROUTE_PREFIX = '/ai_generator/get_usage';
44
45 /**
46 * The auth strategy factory.
47 *
48 * @var AI_Request_Sender_Factory
49 */
50 private $ai_request_sender_factory;
51
52 /**
53 * The consent handler instance.
54 *
55 * @var Consent_Handler
56 */
57 private $consent_handler;
58
59 /**
60 * Represents the add-on manager.
61 *
62 * @var WPSEO_Addon_Manager
63 */
64 private $addon_manager;
65
66 /**
67 * Returns the conditionals based in which this loadable should be active.
68 *
69 * @return array<string> The conditionals.
70 */
71 public static function get_conditionals() {
72 return [ AI_Conditional::class ];
73 }
74
75 /**
76 * Class constructor.
77 *
78 * @param AI_Request_Sender_Factory $ai_request_sender_factory The auth strategy factory.
79 * @param Consent_Handler $consent_handler The consent handler instance.
80 * @param WPSEO_Addon_Manager $addon_manager The add-on manager instance.
81 */
82 public function __construct( AI_Request_Sender_Factory $ai_request_sender_factory, Consent_Handler $consent_handler, WPSEO_Addon_Manager $addon_manager ) {
83 $this->addon_manager = $addon_manager;
84 $this->ai_request_sender_factory = $ai_request_sender_factory;
85 $this->consent_handler = $consent_handler;
86 }
87
88 /**
89 * Registers routes with WordPress.
90 *
91 * @return void
92 */
93 public function register_routes() {
94 \register_rest_route(
95 self::ROUTE_NAMESPACE,
96 self::ROUTE_PREFIX,
97 [
98 'methods' => 'POST',
99 'args' => [
100 'is_woo_product_entity' => [
101 'type' => 'boolean',
102 'default' => false,
103 ],
104 ],
105 'callback' => [ $this, 'get_usage' ],
106 'permission_callback' => [ $this, 'check_permissions' ],
107 ],
108 );
109 }
110
111 /**
112 * Runs the callback that gets the monthly usage of the user.
113 *
114 * @param WP_REST_Request $request The request object.
115 *
116 * @return WP_REST_Response The response of the callback action.
117 */
118 public function get_usage( $request ): WP_REST_Response {
119 $is_woo_product_entity = $request->get_param( 'is_woo_product_entity' );
120 $user = \wp_get_current_user();
121 try {
122 $parameters = new Usage_Parameters( $user, $this->is_free( $is_woo_product_entity ), \gmdate( 'Y-m' ) );
123 $sender = $this->ai_request_sender_factory->create( $user );
124 $response = $sender->get_usage( $parameters );
125 $data = \json_decode( $response->get_body() );
126 } catch ( Remote_Request_Exception |WP_Request_Exception $e ) {
127 if ( $e instanceof Forbidden_Exception && ! $e instanceof Insufficient_Scope_Exception ) {
128 $this->consent_handler->revoke_consent( $user->ID );
129 }
130 $message = [
131 'errorMessage' => $e->getMessage(),
132 'errorIdentifier' => $e->get_error_identifier(),
133 'errorCode' => $e->getCode(),
134 ];
135 if ( $e instanceof Too_Many_Requests_Exception ) {
136 $message['missingLicenses'] = $e->get_missing_licenses();
137 }
138 return new WP_REST_Response(
139 $message,
140 $e->getCode(),
141 );
142 }
143
144 return new WP_REST_Response( $data );
145 }
146
147 /**
148 * Whether the current request should read the time-unbound free-usage bucket.
149 *
150 * A user without the relevant paid subscription is on the free tier, whose usage is tracked in
151 * the free-usage bucket rather than per period.
152 *
153 * @param bool $is_woo_product_entity Whether the request is for a WooCommerce product entity.
154 *
155 * @return bool True when the user is on the free tier for this request type.
156 */
157 public function is_free( $is_woo_product_entity = false ): bool {
158 if ( $is_woo_product_entity ) {
159 return ! $this->addon_manager->has_valid_subscription( WPSEO_Addon_Manager::WOOCOMMERCE_SLUG );
160 }
161 return ! $this->addon_manager->has_valid_subscription( WPSEO_Addon_Manager::PREMIUM_SLUG );
162 }
163 }
164