PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 27.8
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v27.8
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 / abilities / user-interface / abilities-integration.php

abilities-integration.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 27.8, at src/abilities/user-interface/abilities-integration.php

258 lines 7.9 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\Abilities\User_Interface;
5
6 use Yoast\WP\SEO\Abilities\Application\Score_Retriever;
7 use Yoast\WP\SEO\Conditionals\Abilities_API_Conditional;
8 use Yoast\WP\SEO\Editors\Application\Analysis_Features\Enabled_Analysis_Features_Repository;
9 use Yoast\WP\SEO\Editors\Framework\Inclusive_Language_Analysis;
10 use Yoast\WP\SEO\Editors\Framework\Keyphrase_Analysis;
11 use Yoast\WP\SEO\Editors\Framework\Readability_Analysis;
12 use Yoast\WP\SEO\Helpers\Capability_Helper;
13 use Yoast\WP\SEO\Integrations\Integration_Interface;
14
15 /**
16 * Integration that registers Yoast SEO abilities with the WordPress Abilities API.
17 */
18 class Abilities_Integration implements Integration_Interface {
19
20 /**
21 * The score retriever.
22 *
23 * @var Score_Retriever
24 */
25 private $score_retriever;
26
27 /**
28 * The capability helper.
29 *
30 * @var Capability_Helper
31 */
32 private $capability_helper;
33
34 /**
35 * The enabled analysis features repository.
36 *
37 * @var Enabled_Analysis_Features_Repository
38 */
39 private $enabled_analysis_features_repository;
40
41 /**
42 * Returns the conditionals based on which this loadable should be active.
43 *
44 * @return array<string> The conditionals.
45 */
46 public static function get_conditionals() {
47 return [ Abilities_API_Conditional::class ];
48 }
49
50 /**
51 * Constructor.
52 *
53 * @param Score_Retriever $score_retriever The score retriever.
54 * @param Capability_Helper $capability_helper The capability helper.
55 * @param Enabled_Analysis_Features_Repository $enabled_analysis_features_repository The enabled analysis features repository.
56 */
57 public function __construct(
58 Score_Retriever $score_retriever,
59 Capability_Helper $capability_helper,
60 Enabled_Analysis_Features_Repository $enabled_analysis_features_repository
61 ) {
62 $this->score_retriever = $score_retriever;
63 $this->capability_helper = $capability_helper;
64 $this->enabled_analysis_features_repository = $enabled_analysis_features_repository;
65 }
66
67 /**
68 * Registers hooks with WordPress.
69 *
70 * @return void
71 */
72 public function register_hooks() {
73 \add_action( 'wp_abilities_api_init', [ $this, 'register_abilities' ] );
74 }
75
76 /**
77 * Registers the Yoast SEO abilities.
78 *
79 * @return void
80 */
81 public function register_abilities() {
82 $enabled_features = $this->enabled_analysis_features_repository->get_features_by_keys(
83 [
84 Keyphrase_Analysis::NAME,
85 Readability_Analysis::NAME,
86 Inclusive_Language_Analysis::NAME,
87 ],
88 )->to_array();
89
90 if ( $enabled_features[ Keyphrase_Analysis::NAME ] === true ) {
91 $this->register_seo_scores_ability();
92 }
93
94 if ( $enabled_features[ Readability_Analysis::NAME ] === true ) {
95 $this->register_readability_scores_ability();
96 }
97
98 if ( $enabled_features[ Inclusive_Language_Analysis::NAME ] === true ) {
99 $this->register_inclusive_language_scores_ability();
100 }
101 }
102
103 /**
104 * Checks whether the current user can read scores.
105 *
106 * @return bool Whether the current user can read scores.
107 */
108 public function can_read_scores(): bool {
109 return $this->capability_helper->current_user_can( 'wpseo_manage_options' );
110 }
111
112 /**
113 * Registers the SEO scores ability.
114 *
115 * @return void
116 */
117 private function register_seo_scores_ability(): void {
118 $output_schema = $this->get_score_output_schema();
119 $output_schema['properties']['focus_keyphrase'] = [
120 'type' => [ 'string', 'null' ],
121 'description' => \__( 'The focus keyphrase for the post, or null if not set.', 'wordpress-seo' ),
122 ];
123
124 \wp_register_ability(
125 Ability_Categories_Integration::CATEGORY_SLUG . '/get-seo-scores',
126 $this->get_shared_ability_args(
127 [
128 'label' => \__( 'Get SEO Scores', 'wordpress-seo' ),
129 'description' => \__( 'Get the SEO scores for the most recently modified posts.', 'wordpress-seo' ),
130 'output_schema' => $this->wrap_in_array_schema( $output_schema ),
131 'execute_callback' => [ $this->score_retriever, 'get_seo_scores' ],
132 ],
133 ),
134 );
135 }
136
137 /**
138 * Registers the readability scores ability.
139 *
140 * @return void
141 */
142 private function register_readability_scores_ability(): void {
143 \wp_register_ability(
144 Ability_Categories_Integration::CATEGORY_SLUG . '/get-readability-scores',
145 $this->get_shared_ability_args(
146 [
147 'label' => \__( 'Get Readability Scores', 'wordpress-seo' ),
148 'description' => \__( 'Get the readability scores for the most recently modified posts.', 'wordpress-seo' ),
149 'output_schema' => $this->wrap_in_array_schema( $this->get_score_output_schema() ),
150 'execute_callback' => [ $this->score_retriever, 'get_readability_scores' ],
151 ],
152 ),
153 );
154 }
155
156 /**
157 * Registers the inclusive language scores ability.
158 *
159 * @return void
160 */
161 private function register_inclusive_language_scores_ability(): void {
162 \wp_register_ability(
163 Ability_Categories_Integration::CATEGORY_SLUG . '/get-inclusive-language-scores',
164 $this->get_shared_ability_args(
165 [
166 'label' => \__( 'Get Inclusive Language Scores', 'wordpress-seo' ),
167 'description' => \__( 'Get the inclusive language scores for the most recently modified posts.', 'wordpress-seo' ),
168 'output_schema' => $this->wrap_in_array_schema( $this->get_score_output_schema() ),
169 'execute_callback' => [ $this->score_retriever, 'get_inclusive_language_scores' ],
170 ],
171 ),
172 );
173 }
174
175 // phpcs:disable SlevomatCodingStandard.TypeHints.DisallowMixedTypeHint.DisallowedMixedTypeHint -- Too complicated of a param declaration for this case.
176
177 /**
178 * Returns the shared ability arguments merged with ability-specific arguments.
179 *
180 * @param array<string, mixed> $ability_specific_args The ability-specific arguments.
181 *
182 * @return array<string, mixed> The merged ability arguments.
183 */
184 private function get_shared_ability_args( array $ability_specific_args ): array {
185 // phpcs:enable SlevomatCodingStandard.TypeHints.DisallowMixedTypeHint.DisallowedMixedTypeHint
186 return \array_merge(
187 [
188 'category' => Ability_Categories_Integration::CATEGORY_SLUG,
189 'input_schema' => [
190 'type' => 'object',
191 'properties' => [
192 'number_of_posts' => [
193 'type' => 'integer',
194 'description' => \__( 'The number of recently modified posts to retrieve scores for. Defaults to 10.', 'wordpress-seo' ),
195 'minimum' => 1,
196 'maximum' => 100,
197 'default' => 10,
198 ],
199 ],
200 ],
201 'permission_callback' => [ $this, 'can_read_scores' ],
202 'meta' => [
203 'show_in_rest' => true,
204 'annotations' => [
205 'readonly' => true,
206 'destructive' => false,
207 'idempotent' => true,
208 ],
209 'mcp' => [
210 'public' => true,
211 ],
212 ],
213 ],
214 $ability_specific_args,
215 );
216 }
217
218 /**
219 * Wraps an item schema in an array schema.
220 *
221 * @param array<string, array<string, string>> $item_schema The item schema.
222 *
223 * @return array<string, array<string, string>> The array schema.
224 */
225 private function wrap_in_array_schema( array $item_schema ): array {
226 return [
227 'type' => 'array',
228 'items' => $item_schema,
229 ];
230 }
231
232 /**
233 * Returns the score output schema, including the title property.
234 *
235 * @return array<string, array<string, string>> The score output schema.
236 */
237 private function get_score_output_schema(): array {
238 return [
239 'type' => 'object',
240 'properties' => [
241 'title' => [
242 'type' => 'string',
243 'description' => \__( 'The post title.', 'wordpress-seo' ),
244 ],
245 'score' => [
246 'type' => 'string',
247 'enum' => [ 'na', 'bad', 'ok', 'good' ],
248 'description' => \__( 'The score slug.', 'wordpress-seo' ),
249 ],
250 'label' => [
251 'type' => 'string',
252 'description' => \__( 'A human-readable label for the score.', 'wordpress-seo' ),
253 ],
254 ],
255 ];
256 }
257 }
258