PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 19.0
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v19.0
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 / integrations / admin / first-time-configuration-integration.php

first-time-configuration-integration.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 19.0, at src/integrations/admin/first-time-configuration-integration.php

455 lines 12.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Yoast\WP\SEO\Integrations\Admin;
4
5 use WPSEO_Addon_Manager;
6 use WPSEO_Admin_Asset_Manager;
7 use WPSEO_Shortlinker;
8 use WPSEO_Utils;
9 use WPSEO_Option_Tab;
10
11 use Yoast\WP\SEO\Conditionals\Admin_Conditional;
12 use Yoast\WP\SEO\Helpers\Options_Helper;
13 use Yoast\WP\SEO\Helpers\Product_Helper;
14 use Yoast\WP\SEO\Integrations\Integration_Interface;
15 use Yoast\WP\SEO\Integrations\Admin\Social_Profiles_Helper;
16 use Yoast\WP\SEO\Routes\Indexing_Route;
17
18 // phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded -- First time configuration simply has a lot of words.
19 /**
20 * First_Time_Configuration_Integration class
21 */
22 class First_Time_Configuration_Integration implements Integration_Interface {
23
24 /**
25 * The admin asset manager.
26 *
27 * @var WPSEO_Admin_Asset_Manager
28 */
29 private $admin_asset_manager;
30
31 /**
32 * The addon manager.
33 *
34 * @var WPSEO_Addon_Manager
35 */
36 private $addon_manager;
37
38 /**
39 * The shortlinker.
40 *
41 * @var WPSEO_Shortlinker
42 */
43 private $shortlinker;
44
45 /**
46 * The options' helper.
47 *
48 * @var Options_Helper
49 */
50 private $options_helper;
51
52 /**
53 * The social profiles helper.
54 *
55 * @var Social_Profiles_Helper
56 */
57 private $social_profiles_helper;
58
59 /**
60 * The product helper.
61 *
62 * @var Product_Helper
63 */
64 private $product_helper;
65
66 /**
67 * {@inheritDoc}
68 */
69 public static function get_conditionals() {
70 return [ Admin_Conditional::class ];
71 }
72
73 /**
74 * Configuration_Workout_Integration constructor.
75 *
76 * @param WPSEO_Admin_Asset_Manager $admin_asset_manager The admin asset manager.
77 * @param WPSEO_Addon_Manager $addon_manager The addon manager.
78 * @param WPSEO_Shortlinker $shortlinker The shortlinker.
79 * @param Options_Helper $options_helper The options helper.
80 * @param Social_Profiles_Helper $social_profiles_helper The social profile helper.
81 * @param Product_Helper $product_helper The product helper.
82 */
83 public function __construct(
84 WPSEO_Admin_Asset_Manager $admin_asset_manager,
85 WPSEO_Addon_Manager $addon_manager,
86 WPSEO_Shortlinker $shortlinker,
87 Options_Helper $options_helper,
88 Social_Profiles_Helper $social_profiles_helper,
89 Product_Helper $product_helper
90 ) {
91 $this->admin_asset_manager = $admin_asset_manager;
92 $this->addon_manager = $addon_manager;
93 $this->shortlinker = $shortlinker;
94 $this->options_helper = $options_helper;
95 $this->social_profiles_helper = $social_profiles_helper;
96 $this->product_helper = $product_helper;
97 }
98
99 /**
100 * {@inheritDoc}
101 */
102 public function register_hooks() {
103 \add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
104 \add_action( 'wpseo_settings_tabs_dashboard', [ $this, 'add_first_time_configuration_tab' ] );
105 }
106
107 /**
108 * Adds a dedicated tab in the General sub-page.
109 *
110 * @param WPSEO_Options_Tabs $dashboard_tabs Object representing the tabs of the General sub-page.
111 */
112 public function add_first_time_configuration_tab( $dashboard_tabs ) {
113 $dashboard_tabs->add_tab(
114 new WPSEO_Option_Tab(
115 'first-time-configuration',
116 __( 'First-time configuration', 'wordpress-seo' ),
117 [ 'save_button' => false ]
118 )
119 );
120 }
121
122 /**
123 * Adds the data for the first-time configuration to the wpseoFirstTimeConfigurationData object.
124 */
125 public function enqueue_assets() {
126 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Date is not processed or saved.
127 if ( ! isset( $_GET['page'] ) || $_GET['page'] !== 'wpseo_dashboard' || \is_network_admin() ) {
128 return;
129 }
130
131 $this->admin_asset_manager->enqueue_script( 'indexation' );
132 $this->admin_asset_manager->enqueue_script( 'first-time-configuration' );
133 $this->admin_asset_manager->enqueue_style( 'admin-css' );
134 $this->admin_asset_manager->enqueue_style( 'tailwind' );
135 $this->admin_asset_manager->enqueue_style( 'monorepo' );
136
137 $data = [
138 'disabled' => ! \YoastSEO()->helpers->indexable->should_index_indexables(),
139 'amount' => \YoastSEO()->helpers->indexing->get_filtered_unindexed_count(),
140 'firstTime' => ( \YoastSEO()->helpers->indexing->is_initial_indexing() === true ),
141 'errorMessage' => '',
142 'restApi' => [
143 'root' => \esc_url_raw( \rest_url() ),
144 'indexing_endpoints' => $this->get_endpoints(),
145 'nonce' => \wp_create_nonce( 'wp_rest' ),
146 ],
147 ];
148
149 /**
150 * Filter: 'wpseo_indexing_data' Filter to adapt the data used in the indexing process.
151 *
152 * @param array $data The indexing data to adapt.
153 */
154 $data = \apply_filters( 'wpseo_indexing_data', $data );
155
156 $this->admin_asset_manager->localize_script( 'indexation', 'yoastIndexingData', $data );
157
158 $person_id = $this->get_person_id();
159 $social_profiles = $this->get_social_profiles();
160
161 // This filter is documented in admin/views/tabs/metas/paper-content/general/knowledge-graph.php.
162 $knowledge_graph_message = \apply_filters( 'wpseo_knowledge_graph_setting_msg', '' );
163
164 $finished_steps = $this->get_finished_steps();
165 $options = $this->get_company_or_person_options();
166 $selected_option_label = '';
167 $filtered_options = \array_filter(
168 $options,
169 function ( $item ) {
170 return $item['value'] === $this->is_company_or_person();
171 }
172 );
173 $selected_option = \reset( $filtered_options );
174 if ( \is_array( $selected_option ) ) {
175 $selected_option_label = $selected_option['label'];
176 }
177
178 $this->admin_asset_manager->add_inline_script(
179 'first-time-configuration',
180 \sprintf(
181 'window.wpseoFirstTimeConfigurationData = {
182 "canEditUser": %d,
183 "companyOrPerson": "%s",
184 "companyOrPersonLabel": "%s",
185 "companyName": "%s",
186 "companyLogo": "%s",
187 "companyLogoId": %d,
188 "finishedSteps": %s,
189 "personId": %d,
190 "personName": "%s",
191 "personLogo": "%s",
192 "personLogoId": %d,
193 "siteTagline": "%s",
194 "socialProfiles": {
195 "facebookUrl": "%s",
196 "twitterUsername": "%s",
197 "otherSocialUrls": %s,
198 },
199 "isPremium": %d,
200 "tracking": %d,
201 "isTrackingAllowedMultisite": %d,
202 "isMainSite": %d,
203 "companyOrPersonOptions": %s,
204 "shouldForceCompany": %d,
205 "knowledgeGraphMessage": "%s",
206 "shortlinks": {
207 "gdpr": "%s",
208 "configIndexables": "%s",
209 "configIndexablesBenefits": "%s",
210 },
211 };',
212 $this->social_profiles_helper->can_edit_profile( $person_id ),
213 $this->is_company_or_person(),
214 $selected_option_label,
215 $this->get_company_name(),
216 $this->get_company_logo(),
217 $this->get_company_logo_id(),
218 WPSEO_Utils::format_json_encode( $finished_steps ),
219 $person_id,
220 $this->get_person_name(),
221 $this->get_person_logo(),
222 $this->get_person_logo_id(),
223 $this->get_site_tagline(),
224 $social_profiles['facebook_url'],
225 $social_profiles['twitter_username'],
226 WPSEO_Utils::format_json_encode( $social_profiles['other_social_urls'] ),
227 $this->product_helper->is_premium(),
228 $this->has_tracking_enabled(),
229 $this->is_tracking_enabled_multisite(),
230 $this->is_main_site(),
231 WPSEO_Utils::format_json_encode( $options ),
232 $this->should_force_company(),
233 $knowledge_graph_message,
234 $this->shortlinker->build_shortlink( 'https://yoa.st/gdpr-config-workout' ),
235 $this->shortlinker->build_shortlink( 'https://yoa.st/config-indexables' ),
236 $this->shortlinker->build_shortlink( 'https://yoa.st/config-indexables-benefits' )
237 ),
238 'before'
239 );
240 }
241
242 /**
243 * Retrieves a list of the endpoints to use.
244 *
245 * @return array The endpoints.
246 */
247 protected function get_endpoints() {
248 $endpoints = [
249 'prepare' => Indexing_Route::FULL_PREPARE_ROUTE,
250 'terms' => Indexing_Route::FULL_TERMS_ROUTE,
251 'posts' => Indexing_Route::FULL_POSTS_ROUTE,
252 'archives' => Indexing_Route::FULL_POST_TYPE_ARCHIVES_ROUTE,
253 'general' => Indexing_Route::FULL_GENERAL_ROUTE,
254 'indexablesComplete' => Indexing_Route::FULL_INDEXABLES_COMPLETE_ROUTE,
255 'post_link' => Indexing_Route::FULL_POST_LINKS_INDEXING_ROUTE,
256 'term_link' => Indexing_Route::FULL_TERM_LINKS_INDEXING_ROUTE,
257 ];
258
259 $endpoints = \apply_filters( 'wpseo_indexing_endpoints', $endpoints );
260
261 $endpoints['complete'] = Indexing_Route::FULL_COMPLETE_ROUTE;
262
263 return $endpoints;
264 }
265
266 // ** Private functions ** //
267
268 /**
269 * Returns the finished steps array.
270 *
271 * @return array An array with the finished steps.
272 */
273 private function get_finished_steps() {
274 return $this->options_helper->get( 'configuration_finished_steps', [] );
275 }
276
277 /**
278 * Returns the entity represented by the site.
279 *
280 * @return string The entity represented by the site.
281 */
282 private function is_company_or_person() {
283 return $this->options_helper->get( 'company_or_person', '' );
284 }
285
286 /**
287 * Gets the company name from the option in the database.
288 *
289 * @return string The company name.
290 */
291 private function get_company_name() {
292 return $this->options_helper->get( 'company_name', '' );
293 }
294
295 /**
296 * Gets the company logo from the option in the database.
297 *
298 * @return string The company logo.
299 */
300 private function get_company_logo() {
301 return $this->options_helper->get( 'company_logo', '' );
302 }
303
304 /**
305 * Gets the company logo id from the option in the database.
306 *
307 * @return string The company logo id.
308 */
309 private function get_company_logo_id() {
310 return $this->options_helper->get( 'company_logo_id', '' );
311 }
312
313 /**
314 * Gets the person id from the option in the database.
315 *
316 * @return int|null The person id, null if empty.
317 */
318 private function get_person_id() {
319 return $this->options_helper->get( 'company_or_person_user_id' );
320 }
321
322 /**
323 * Gets the person id from the option in the database.
324 *
325 * @return int|null The person id, null if empty.
326 */
327 private function get_person_name() {
328 $user = \get_userdata( $this->get_person_id() );
329 if ( $user instanceof \WP_User ) {
330 return $user->get( 'display_name' );
331 }
332 return '';
333 }
334
335 /**
336 * Gets the person avatar from the option in the database.
337 *
338 * @return string The person logo.
339 */
340 private function get_person_logo() {
341 return $this->options_helper->get( 'person_logo', '' );
342 }
343
344 /**
345 * Gets the person logo id from the option in the database.
346 *
347 * @return string The person logo id.
348 */
349 private function get_person_logo_id() {
350 return $this->options_helper->get( 'person_logo_id', '' );
351 }
352
353 /**
354 * Gets the site tagline.
355 *
356 * @return string The site tagline.
357 */
358 private function get_site_tagline() {
359 return \get_bloginfo( 'description' );
360 }
361
362 /**
363 * Gets the social profiles stored in the database.
364 *
365 * @return string[] The social profiles.
366 */
367 private function get_social_profiles() {
368 return [
369 'facebook_url' => $this->options_helper->get( 'facebook_site', '' ),
370 'twitter_username' => $this->options_helper->get( 'twitter_site', '' ),
371 'other_social_urls' => $this->options_helper->get( 'other_social_urls', [] ),
372 ];
373 }
374
375 /**
376 * Checks whether tracking is enabled.
377 *
378 * @return bool True if tracking is enabled, false otherwise, null if in Free and conf. workout step not finished.
379 */
380 private function has_tracking_enabled() {
381 $default = false;
382
383 if ( $this->product_helper->is_premium() ) {
384 $default = true;
385 }
386
387 return $this->options_helper->get( 'tracking', $default );
388 }
389
390 /**
391 * Checks whether tracking option is allowed at network level.
392 *
393 * @return bool True if option change is allowed, false otherwise.
394 */
395 private function is_tracking_enabled_multisite() {
396 $default = true;
397
398 if ( ! \is_multisite() ) {
399 return $default;
400 }
401
402 return $this->options_helper->get( 'allow_tracking', $default );
403 }
404
405 /**
406 * Checks whether we are in a main site.
407 *
408 * @return bool True if it's the main site or a single site, false if it's a subsite.
409 */
410 private function is_main_site() {
411 return \is_main_site();
412 }
413
414 /**
415 * Gets the options for the Company or Person select.
416 * Returns only the company option if it is forced (by Local SEO), otherwise returns company and person option.
417 *
418 * @return array The options for the company-or-person select.
419 */
420 private function get_company_or_person_options() {
421 $options = [
422 [
423 'label' => \__( 'Organization', 'wordpress-seo' ),
424 'value' => 'company',
425 'id' => 'company',
426 ],
427 [
428 'label' => \__( 'Person', 'wordpress-seo' ),
429 'value' => 'person',
430 'id' => 'person',
431 ],
432 ];
433 if ( $this->should_force_company() ) {
434 $options = [
435 [
436 'label' => \__( 'Organization', 'wordpress-seo' ),
437 'value' => 'company',
438 'id' => 'company',
439 ],
440 ];
441 }
442
443 return $options;
444 }
445
446 /**
447 * Checks whether we should force "Organization".
448 *
449 * @return bool
450 */
451 private function should_force_company() {
452 return $this->addon_manager->is_installed( WPSEO_Addon_Manager::LOCAL_SLUG );
453 }
454 }
455