PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 28.5
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v28.5
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/integrations/admin/workouts-integration.php +31 -202 18.028.5 View file →
@@ -3,11 +3,9 @@
3 3 namespace Yoast\WP\SEO\Integrations\Admin;
4 4
5 5 use WPSEO_Addon_Manager;
6 6 use WPSEO_Admin_Asset_Manager;
7 -use WPSEO_Admin_Asset_Yoast_Components_L10n;
8 7 use Yoast\WP\SEO\Conditionals\Admin_Conditional;
9 -use Yoast\WP\SEO\Helpers\Indexing_Helper;
10 8 use Yoast\WP\SEO\Helpers\Options_Helper;
11 9 use Yoast\WP\SEO\Helpers\Product_Helper;
12 10 use Yoast\WP\SEO\Integrations\Integration_Interface;
13 11 use Yoast\WP\SEO\Presenters\Admin\Notice_Presenter;
@@ -45,15 +43,8 @@
45 43 */
46 44 private $product_helper;
47 45
48 46 /**
49 - * The indexing helper.
50 - *
51 - * @var Indexing_Helper
52 - */
53 - private $indexing_helper;
54 -
55 - /**
56 47 * {@inheritDoc}
57 48 */
58 49 public static function get_conditionals() {
59 50 return [ Admin_Conditional::class ];
@@ -65,22 +56,19 @@
65 56 * @param WPSEO_Addon_Manager $addon_manager The addon manager.
66 57 * @param WPSEO_Admin_Asset_Manager $admin_asset_manager The admin asset manager.
67 58 * @param Options_Helper $options_helper The options helper.
68 59 * @param Product_Helper $product_helper The product helper.
69 - * @param Indexing_Helper $indexing_helper The indexing helper.
70 60 */
71 61 public function __construct(
72 62 WPSEO_Addon_Manager $addon_manager,
73 63 WPSEO_Admin_Asset_Manager $admin_asset_manager,
74 64 Options_Helper $options_helper,
75 - Product_Helper $product_helper,
76 - Indexing_Helper $indexing_helper
65 + Product_Helper $product_helper
77 66 ) {
78 67 $this->addon_manager = $addon_manager;
79 68 $this->admin_asset_manager = $admin_asset_manager;
80 69 $this->options_helper = $options_helper;
81 70 $this->product_helper = $product_helper;
82 - $this->indexing_helper = $indexing_helper;
83 71 }
84 72
85 73 /**
86 74 * {@inheritDoc}
@@ -88,9 +76,8 @@
88 76 public function register_hooks() {
89 77 \add_filter( 'wpseo_submenu_pages', [ $this, 'add_submenu_page' ], 8 );
90 78 \add_filter( 'wpseo_submenu_pages', [ $this, 'remove_old_submenu_page' ], 10 );
91 79 \add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ], 11 );
92 - \add_action( 'admin_notices', [ $this, 'configuration_workout_notice' ] );
93 80 }
94 81
95 82 /**
96 83 * Adds the workouts submenu page.
@@ -102,9 +89,9 @@
102 89 public function add_submenu_page( $submenu_pages ) {
103 90 $submenu_pages[] = [
104 91 'wpseo_dashboard',
105 92 '',
106 - \__( 'Workouts', 'wordpress-seo' ),
93 + \__( 'Workouts', 'wordpress-seo' ) . ' <span class="yoast-badge yoast-premium-badge"></span>',
107 94 'edit_others_posts',
108 95 'wpseo_workouts',
109 96 [ $this, 'render_target' ],
110 97 ];
@@ -140,8 +127,10 @@
140 127 }
141 128
142 129 /**
143 130 * Enqueue the workouts app.
131 + *
132 + * @return void
144 133 */
145 134 public function enqueue_assets() {
146 135 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Date is not processed or saved.
147 136 if ( ! isset( $_GET['page'] ) || $_GET['page'] !== 'wpseo_workouts' ) {
@@ -154,12 +143,10 @@
154 143
155 144 $this->admin_asset_manager->enqueue_style( 'workouts' );
156 145
157 146 $workouts_option = $this->get_workouts_option();
147 + $ftc_url = \esc_url( \admin_url( 'admin.php?page=wpseo_dashboard#/first-time-configuration' ) );
158 148
159 - $yoast_components_l10n = new WPSEO_Admin_Asset_Yoast_Components_L10n();
160 - $yoast_components_l10n->localize_script( 'workouts' );
161 -
162 149 $this->admin_asset_manager->enqueue_script( 'workouts' );
163 150 $this->admin_asset_manager->localize_script(
164 151 'workouts',
165 152 'wpseoWorkoutsData',
@@ -165,23 +152,23 @@
165 152 'wpseoWorkoutsData',
166 153 [
167 154 'workouts' => $workouts_option,
168 155 'homeUrl' => \home_url(),
169 - 'pluginUrl' => \esc_url( \plugins_url( '', WPSEO_FILE ) ),
156 + 'pluginUrl' => \esc_url( \plugins_url( '', \WPSEO_FILE ) ),
170 157 'toolsPageUrl' => \esc_url( \admin_url( 'admin.php?page=wpseo_tools' ) ),
171 158 'usersPageUrl' => \esc_url( \admin_url( 'users.php' ) ),
159 + 'firstTimeConfigurationUrl' => $ftc_url,
172 160 'isPremium' => $this->product_helper->is_premium(),
173 - 'shouldUpdatePremium' => $this->should_update_premium(),
174 161 'upsellText' => $this->get_upsell_text(),
175 162 'upsellLink' => $this->get_upsell_link(),
176 - 'canDoConfigurationWorkout' => $this->user_can_do_configuration_workout(),
177 - 'canEditWordPressOptions' => $this->user_can_edit_wordpress_options(),
178 - ]
163 + ],
179 164 );
180 165 }
181 166
182 167 /**
183 168 * Renders the target for the React to mount to.
169 + *
170 + * @return void
184 171 */
185 172 public function render_target() {
186 173 if ( $this->should_update_premium() ) {
187 174 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output escaped in get_update_premium_notice.
@@ -191,87 +178,8 @@
191 178 echo '<div id="wpseo-workouts-container-free" class="yoast"></div>';
192 179 }
193 180
194 181 /**
195 - * Determines whether and where the "First-time SEO Configuration workout" admin notice should be displayed.
196 - *
197 - * @return bool Whether the "First-time SEO Configuration workout" admin notice should be displayed.
198 - */
199 - public function should_display_configuration_workout_notice() {
200 - if ( ! $this->options_helper->get( 'dismiss_configuration_workout_notice', false ) === false ) {
201 - return false;
202 - }
203 -
204 - if ( ! $this->user_can_do_configuration_workout() ) {
205 - return false;
206 - }
207 -
208 - if ( ! $this->on_wpseo_admin_page_or_dashboard() ) {
209 - return false;
210 - }
211 -
212 - if ( $this->is_configuration_workout_finished() ) {
213 - return false;
214 - }
215 -
216 - if ( $this->options_helper->get( 'first_time_install', false ) === false ) {
217 - return false;
218 - }
219 -
220 - return ! $this->are_site_representation_name_and_logo_set() || $this->indexing_helper->get_unindexed_count() > 0;
221 - }
222 -
223 - /**
224 - * Displays an admin notice when the configuration workout has not been finished yet.
225 - *
226 - * @return void
227 - */
228 - public function configuration_workout_notice() {
229 - if ( ! $this->should_display_configuration_workout_notice() ) {
230 - return;
231 - }
232 -
233 - $this->admin_asset_manager->enqueue_style( 'monorepo' );
234 -
235 - $notice = new Notice_Presenter(
236 - \__( 'First-time SEO configuration', 'wordpress-seo' ),
237 - \sprintf(
238 - /* translators: 1: Link start tag to the configuration workout, 2: Yoast SEO, 3: Link closing tag. */
239 - __( 'Get started quickly with the %1$s%2$s Configuration workout%3$s and configure Yoast SEO with the optimal SEO settings for your site!', 'wordpress-seo' ),
240 - '<a href="' . \esc_url( \self_admin_url( 'admin.php?page=wpseo_workouts' ) ) . '">',
241 - 'Yoast SEO',
242 - '</a>'
243 - ),
244 - 'mirrored_fit_bubble_woman_1_optim.svg',
245 - null,
246 - true,
247 - 'yoast-configuration-workout-notice'
248 - );
249 -
250 - //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output from present() is considered safe.
251 - echo $notice->present();
252 -
253 - // Enable permanently dismissing the notice.
254 - echo "<script>
255 - function dismiss_configuration_workout_notice(){
256 - var data = {
257 - 'action': 'dismiss_configuration_workout_notice',
258 - };
259 -
260 - jQuery.post( ajaxurl, data, function( response ) {
261 - jQuery( '#yoast-configuration-workout-notice' ).hide();
262 - });
263 - }
264 -
265 - jQuery( document ).ready( function() {
266 - jQuery( 'body' ).on( 'click', '#yoast-configuration-workout-notice .notice-dismiss', function() {
267 - dismiss_configuration_workout_notice();
268 - } );
269 - } );
270 - </script>";
271 - }
272 -
273 - /**
274 182 * Gets the workouts option.
275 183 *
276 184 * @return mixed|null Returns workouts option if found, null if not.
277 185 */
@@ -296,14 +204,15 @@
296 204 $copy = \sprintf(
297 205 /* translators: %s: expands to 'Yoast SEO Premium'. */
298 206 \esc_html__(
299 207 'Accessing the latest workouts requires an updated version of %s (at least 17.7), but it looks like your subscription has expired. Please renew your subscription to update and gain access to all the latest features.',
300 - 'wordpress-seo'
208 + 'wordpress-seo',
301 209 ),
302 - 'Yoast SEO Premium'
210 + 'Yoast SEO Premium',
303 211 );
304 212 $button = '<a class="yoast-button yoast-button-upsell yoast-button--small" href="' . \esc_url( $url ) . '" target="_blank">'
305 213 . \esc_html__( 'Renew your subscription', 'wordpress-seo' )
214 + /* translators: Hidden accessibility text. */
306 215 . '<span class="screen-reader-text">' . \__( '(Opens in a new browser tab)', 'wordpress-seo' ) . '</span>'
307 216 . '<span aria-hidden="true" class="yoast-button-upsell__caret"></span>'
308 217 . '</a>';
309 218 }
@@ -314,9 +223,9 @@
314 223 /* translators: 1: expands to 'Yoast SEO Premium', 2: Link start tag to the page to update Premium, 3: Link closing tag. */
315 224 \esc_html__( 'It looks like you\'re running an outdated version of %1$s, please %2$supdate to the latest version (at least 17.7)%3$s to gain access to our updated workouts section.', 'wordpress-seo' ),
316 225 'Yoast SEO Premium',
317 226 '<a href="' . \esc_url( $url ) . '">',
318 - '</a>'
227 + '</a>',
319 228 );
320 229 $button = null;
321 230 }
322 231 else {
@@ -327,13 +236,14 @@
327 236 /* translators: 1: expands to 'Yoast SEO Premium', 2: Link start tag to the page to update Premium, 3: Link closing tag. */
328 237 \esc_html__( 'It looks like you’re running an outdated and unactivated version of %1$s, please activate your subscription in %2$sMyYoast%3$s and update to the latest version (at least 17.7) to gain access to our updated workouts section.', 'wordpress-seo' ),
329 238 'Yoast SEO Premium',
330 239 '<a href="' . \esc_url( $url ) . '">',
331 - '</a>'
240 + '</a>',
332 241 );
333 242 $button = '<a class="yoast-button yoast-button--primary yoast-button--small" href="' . \esc_url( $url_button ) . '" target="_blank">'
334 - . esc_html__( 'Get help activating your subscription', 'wordpress-seo' )
335 - . '<span class="screen-reader-text">' . __( '(Opens in a new browser tab)', 'wordpress-seo' ) . '</span>'
243 + . \esc_html__( 'Get help activating your subscription', 'wordpress-seo' )
244 + /* translators: Hidden accessibility text. */
245 + . '<span class="screen-reader-text">' . \__( '(Opens in a new browser tab)', 'wordpress-seo' ) . '</span>'
336 246 . '</a>';
337 247 }
338 248
339 249 $notice = new Notice_Presenter(
@@ -338,10 +248,10 @@
338 248
339 249 $notice = new Notice_Presenter(
340 250 $title,
341 251 $copy,
342 - 'Assistent_Time_bubble_500x570.png',
343 - $button
252 + null,
253 + $button,
344 254 );
345 255
346 256 return $notice->present();
347 257 }
@@ -352,9 +262,9 @@
352 262 * @return bool Returns true when Premium is enabled and the version is below 17.7.
353 263 */
354 264 private function should_update_premium() {
355 265 $premium_version = $this->product_helper->get_premium_version();
356 - return $premium_version !== null && version_compare( $premium_version, '17.7-RC1', '<' );
266 + return $premium_version !== null && \version_compare( $premium_version, '17.7-RC1', '<' );
357 267 }
358 268
359 269 /**
360 270 * Check whether the Premium subscription has expired.
@@ -363,9 +273,9 @@
363 273 */
364 274 private function has_premium_subscription_expired() {
365 275 $subscription = $this->addon_manager->get_subscription( WPSEO_Addon_Manager::PREMIUM_SLUG );
366 276
367 - return ( isset( $subscription->expiry_date ) && ( strtotime( $subscription->expiry_date ) - time() ) < 0 );
277 + return ( isset( $subscription->expiry_date ) && ( \strtotime( $subscription->expiry_date ) - \time() ) < 0 );
368 278 }
369 279
370 280 /**
371 281 * Check whether the Premium subscription is activated.
@@ -386,25 +296,25 @@
386 296 // Use the default defined in the component.
387 297 return '';
388 298 }
389 299 if ( $this->has_premium_subscription_expired() ) {
390 - return sprintf(
300 + return \sprintf(
391 301 /* translators: %s: expands to 'Yoast SEO Premium'. */
392 - __( 'Renew %s', 'wordpress-seo' ),
393 - 'Yoast SEO Premium'
302 + \__( 'Renew %s', 'wordpress-seo' ),
303 + 'Yoast SEO Premium',
394 304 );
395 305 }
396 306 if ( $this->has_premium_subscription_activated() ) {
397 - return sprintf(
307 + return \sprintf(
398 308 /* translators: %s: expands to 'Yoast SEO Premium'. */
399 - __( 'Update %s', 'wordpress-seo' ),
400 - 'Yoast SEO Premium'
309 + \__( 'Update %s', 'wordpress-seo' ),
310 + 'Yoast SEO Premium',
401 311 );
402 312 }
403 - return sprintf(
313 + return \sprintf(
404 314 /* translators: %s: expands to 'Yoast SEO Premium'. */
405 - __( 'Activate %s', 'wordpress-seo' ),
406 - 'Yoast SEO Premium'
315 + \__( 'Activate %s', 'wordpress-seo' ),
316 + 'Yoast SEO Premium',
407 317 );
408 318 }
409 319
410 320 /**
@@ -423,87 +333,6 @@
423 333 if ( $this->has_premium_subscription_activated() ) {
424 334 return \wp_nonce_url( \self_admin_url( 'update.php?action=upgrade-plugin&plugin=wordpress-seo-premium/wp-seo-premium.php' ), 'upgrade-plugin_wordpress-seo-premium/wp-seo-premium.php' );
425 335 }
426 336 return 'https://yoa.st/workouts-activate-notice-myyoast';
427 - }
428 -
429 - /**
430 - * Whether the user can do the configuration workout.
431 - *
432 - * @return bool Whether the current user can do the configuration workout.
433 - */
434 - private function user_can_do_configuration_workout() {
435 - return \current_user_can( 'wpseo_manage_options' );
436 - }
437 -
438 - /**
439 - * Whether the user can edit WordPress options.
440 - *
441 - * @return bool Whether the current user can edit WordPress options.
442 - */
443 - private function user_can_edit_wordpress_options() {
444 - return \current_user_can( 'manage_options' );
445 - }
446 -
447 - /**
448 - * Whether the user is currently visiting one of our admin pages or the WordPress dashboard.
449 - *
450 - * @return bool Whether the current page is a Yoast SEO admin page
451 - */
452 - private function on_wpseo_admin_page_or_dashboard() {
453 - $pagenow = $GLOBALS['pagenow'];
454 -
455 - // Show on the WP Dashboard.
456 - if ( $pagenow === 'index.php' ) {
457 - return true;
458 - }
459 -
460 - $page_from_get = filter_input( INPUT_GET, 'page' );
461 -
462 - // Show on Yoast SEO pages, with some exceptions.
463 - if ( $pagenow === 'admin.php' && strpos( $page_from_get, 'wpseo' ) === 0 ) {
464 - $exceptions = [
465 - 'wpseo_workouts',
466 - 'wpseo_installation_successful',
467 - 'wpseo_installation_successful_free',
468 - ];
469 -
470 - if ( ! \in_array( $page_from_get, $exceptions, true ) ) {
471 - return true;
472 - }
473 - }
474 -
475 - return false;
476 - }
477 -
478 - /**
479 - * Whether all steps of the configuration workout have been finished.
480 - *
481 - * @return bool Whether the configuration workout has been finished.
482 - */
483 - private function is_configuration_workout_finished() {
484 - $workouts_option = $this->options_helper->get( 'workouts_data', [] );
485 -
486 - return count( $workouts_option['configuration']['finishedSteps'] ) === 5;
487 - }
488 -
489 - /**
490 - * Whether the site representation name and logo have been set.
491 - *
492 - * @return bool Whether the site representation name and logo have been set.
493 - */
494 - private function are_site_representation_name_and_logo_set() {
495 - $company_or_person = $this->options_helper->get( 'company_or_person', '' );
496 -
497 - if ( $company_or_person === '' ) {
498 - return false;
499 - }
500 -
501 - if ( $company_or_person === 'company' ) {
502 - return ! empty( $this->options_helper->get( 'company_name' ) )
503 - && ! empty( $this->options_helper->get( 'company_logo', '' ) );
504 - }
505 -
506 - return ! empty( $this->options_helper->get( 'company_or_person_user_id' ) )
507 - && ! empty( $this->options_helper->get( 'person_logo', '' ) );
508 337 }
509 338 }