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