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 / workouts-integration.php

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

354 lines 11.7 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 Yoast\WP\SEO\Conditionals\Admin_Conditional;
8 use Yoast\WP\SEO\Helpers\Indexing_Helper;
9 use Yoast\WP\SEO\Helpers\Options_Helper;
10 use Yoast\WP\SEO\Helpers\Product_Helper;
11 use Yoast\WP\SEO\Integrations\Integration_Interface;
12 use Yoast\WP\SEO\Presenters\Admin\Notice_Presenter;
13
14 /**
15 * WorkoutsIntegration class
16 */
17 class Workouts_Integration implements Integration_Interface {
18
19 /**
20 * The admin asset manager.
21 *
22 * @var WPSEO_Admin_Asset_Manager
23 */
24 private $admin_asset_manager;
25
26 /**
27 * The addon manager.
28 *
29 * @var WPSEO_Addon_Manager
30 */
31 private $addon_manager;
32
33 /**
34 * The options helper.
35 *
36 * @var Options_Helper
37 */
38 private $options_helper;
39
40 /**
41 * The product helper.
42 *
43 * @var Product_Helper
44 */
45 private $product_helper;
46
47 /**
48 * {@inheritDoc}
49 */
50 public static function get_conditionals() {
51 return [ Admin_Conditional::class ];
52 }
53
54 /**
55 * Workouts_Integration constructor.
56 *
57 * @param WPSEO_Addon_Manager $addon_manager The addon manager.
58 * @param WPSEO_Admin_Asset_Manager $admin_asset_manager The admin asset manager.
59 * @param Options_Helper $options_helper The options helper.
60 * @param Product_Helper $product_helper The product helper.
61 */
62 public function __construct(
63 WPSEO_Addon_Manager $addon_manager,
64 WPSEO_Admin_Asset_Manager $admin_asset_manager,
65 Options_Helper $options_helper,
66 Product_Helper $product_helper
67 ) {
68 $this->addon_manager = $addon_manager;
69 $this->admin_asset_manager = $admin_asset_manager;
70 $this->options_helper = $options_helper;
71 $this->product_helper = $product_helper;
72 }
73
74 /**
75 * {@inheritDoc}
76 */
77 public function register_hooks() {
78 \add_filter( 'wpseo_submenu_pages', [ $this, 'add_submenu_page' ], 8 );
79 \add_filter( 'wpseo_submenu_pages', [ $this, 'remove_old_submenu_page' ], 10 );
80 \add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ], 11 );
81 }
82
83 /**
84 * Adds the workouts submenu page.
85 *
86 * @param array $submenu_pages The Yoast SEO submenu pages.
87 *
88 * @return array The filtered submenu pages.
89 */
90 public function add_submenu_page( $submenu_pages ) {
91 $submenu_pages[] = [
92 'wpseo_dashboard',
93 '',
94 \__( 'Workouts', 'wordpress-seo' ) . ' <span class="yoast-badge yoast-premium-badge"></span>',
95 'edit_others_posts',
96 'wpseo_workouts',
97 [ $this, 'render_target' ],
98 ];
99
100 return $submenu_pages;
101 }
102
103 /**
104 * Removes the workouts submenu page from older Premium versions
105 *
106 * @param array $submenu_pages The Yoast SEO submenu pages.
107 *
108 * @return array The filtered submenu pages.
109 */
110 public function remove_old_submenu_page( $submenu_pages ) {
111 if ( ! $this->should_update_premium() ) {
112 return $submenu_pages;
113 }
114
115 // Copy only the Workouts page item that comes first in the array.
116 $result_submenu_pages = [];
117 $workouts_page_encountered = false;
118 foreach ( $submenu_pages as $item ) {
119 if ( $item[4] !== 'wpseo_workouts' || ! $workouts_page_encountered ) {
120 $result_submenu_pages[] = $item;
121 }
122 if ( $item[4] === 'wpseo_workouts' ) {
123 $workouts_page_encountered = true;
124 }
125 }
126
127 return $result_submenu_pages;
128 }
129
130 /**
131 * Enqueue the workouts app.
132 */
133 public function enqueue_assets() {
134 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Date is not processed or saved.
135 if ( ! isset( $_GET['page'] ) || $_GET['page'] !== 'wpseo_workouts' ) {
136 return;
137 }
138
139 if ( $this->should_update_premium() ) {
140 \wp_dequeue_script( 'yoast-seo-premium-workouts' );
141 }
142
143 $this->admin_asset_manager->enqueue_style( 'workouts' );
144
145 $workouts_option = $this->get_workouts_option();
146
147 $this->admin_asset_manager->enqueue_script( 'workouts' );
148 $this->admin_asset_manager->localize_script(
149 'workouts',
150 'wpseoWorkoutsData',
151 [
152 'workouts' => $workouts_option,
153 'homeUrl' => \home_url(),
154 'pluginUrl' => \esc_url( \plugins_url( '', \WPSEO_FILE ) ),
155 'toolsPageUrl' => \esc_url( \admin_url( 'admin.php?page=wpseo_tools' ) ),
156 'usersPageUrl' => \esc_url( \admin_url( 'users.php' ) ),
157 'firsttimeConfigurationUrl' => \esc_url( \admin_url( 'admin.php?page=wpseo_dashboard#top#first-time-configuration' ) ),
158 'isPremium' => $this->product_helper->is_premium(),
159 'shouldUpdatePremium' => $this->should_update_premium(),
160 'upsellText' => $this->get_upsell_text(),
161 'upsellLink' => $this->get_upsell_link(),
162 'canDoConfigurationWorkout' => $this->user_can_do_configuration_workout(),
163 'canEditWordPressOptions' => $this->user_can_edit_wordpress_options(),
164 ]
165 );
166 }
167
168 /**
169 * Renders the target for the React to mount to.
170 */
171 public function render_target() {
172 if ( $this->should_update_premium() ) {
173 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output escaped in get_update_premium_notice.
174 echo $this->get_update_premium_notice();
175 }
176
177 echo '<div id="wpseo-workouts-container-free" class="yoast"></div>';
178 }
179
180 /**
181 * Gets the workouts option.
182 *
183 * @return mixed|null Returns workouts option if found, null if not.
184 */
185 private function get_workouts_option() {
186 $workouts_option = $this->options_helper->get( 'workouts_data' );
187
188 // This filter is documented in src/routes/workouts-route.php.
189 return \apply_filters( 'Yoast\WP\SEO\workouts_options', $workouts_option );
190 }
191
192 /**
193 * Returns the notification to show when Premium needs to be updated.
194 *
195 * @return string The notification to update Premium.
196 */
197 private function get_update_premium_notice() {
198 $url = $this->get_upsell_link();
199
200 if ( $this->has_premium_subscription_expired() ) {
201 /* translators: %s: expands to 'Yoast SEO Premium'. */
202 $title = \sprintf( \__( 'Renew your subscription of %s', 'wordpress-seo' ), 'Yoast SEO Premium' );
203 $copy = \sprintf(
204 /* translators: %s: expands to 'Yoast SEO Premium'. */
205 \esc_html__(
206 '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.',
207 'wordpress-seo'
208 ),
209 'Yoast SEO Premium'
210 );
211 $button = '<a class="yoast-button yoast-button-upsell yoast-button--small" href="' . \esc_url( $url ) . '" target="_blank">'
212 . \esc_html__( 'Renew your subscription', 'wordpress-seo' )
213 . '<span class="screen-reader-text">' . \__( '(Opens in a new browser tab)', 'wordpress-seo' ) . '</span>'
214 . '<span aria-hidden="true" class="yoast-button-upsell__caret"></span>'
215 . '</a>';
216 }
217 elseif ( $this->has_premium_subscription_activated() ) {
218 /* translators: %s: expands to 'Yoast SEO Premium'. */
219 $title = \sprintf( \__( 'Update to the latest version of %s', 'wordpress-seo' ), 'Yoast SEO Premium' );
220 $copy = \sprintf(
221 /* translators: 1: expands to 'Yoast SEO Premium', 2: Link start tag to the page to update Premium, 3: Link closing tag. */
222 \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' ),
223 'Yoast SEO Premium',
224 '<a href="' . \esc_url( $url ) . '">',
225 '</a>'
226 );
227 $button = null;
228 }
229 else {
230 /* translators: %s: expands to 'Yoast SEO Premium'. */
231 $title = \sprintf( \__( 'Activate your subscription of %s', 'wordpress-seo' ), 'Yoast SEO Premium' );
232 $url_button = 'https://yoa.st/workouts-activate-notice-help';
233 $copy = \sprintf(
234 /* translators: 1: expands to 'Yoast SEO Premium', 2: Link start tag to the page to update Premium, 3: Link closing tag. */
235 \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' ),
236 'Yoast SEO Premium',
237 '<a href="' . \esc_url( $url ) . '">',
238 '</a>'
239 );
240 $button = '<a class="yoast-button yoast-button--primary yoast-button--small" href="' . \esc_url( $url_button ) . '" target="_blank">'
241 . \esc_html__( 'Get help activating your subscription', 'wordpress-seo' )
242 . '<span class="screen-reader-text">' . \__( '(Opens in a new browser tab)', 'wordpress-seo' ) . '</span>'
243 . '</a>';
244 }
245
246 $notice = new Notice_Presenter(
247 $title,
248 $copy,
249 'Assistent_Time_bubble_500x570.png',
250 $button
251 );
252
253 return $notice->present();
254 }
255
256 /**
257 * Check whether Premium should be updated.
258 *
259 * @return bool Returns true when Premium is enabled and the version is below 17.7.
260 */
261 private function should_update_premium() {
262 $premium_version = $this->product_helper->get_premium_version();
263 return $premium_version !== null && \version_compare( $premium_version, '17.7-RC1', '<' );
264 }
265
266 /**
267 * Check whether the Premium subscription has expired.
268 *
269 * @return bool Returns true when Premium subscription has expired.
270 */
271 private function has_premium_subscription_expired() {
272 $subscription = $this->addon_manager->get_subscription( WPSEO_Addon_Manager::PREMIUM_SLUG );
273
274 return ( isset( $subscription->expiry_date ) && ( \strtotime( $subscription->expiry_date ) - \time() ) < 0 );
275 }
276
277 /**
278 * Check whether the Premium subscription is activated.
279 *
280 * @return bool Returns true when Premium subscription is activated.
281 */
282 private function has_premium_subscription_activated() {
283 return $this->addon_manager->has_valid_subscription( WPSEO_Addon_Manager::PREMIUM_SLUG );
284 }
285
286 /**
287 * Returns the upsell/update copy to show in the card buttons.
288 *
289 * @return string Returns a string with the upsell/update copy for the card buttons.
290 */
291 private function get_upsell_text() {
292 if ( ! $this->product_helper->is_premium() || ! $this->should_update_premium() ) {
293 // Use the default defined in the component.
294 return '';
295 }
296 if ( $this->has_premium_subscription_expired() ) {
297 return \sprintf(
298 /* translators: %s: expands to 'Yoast SEO Premium'. */
299 \__( 'Renew %s', 'wordpress-seo' ),
300 'Yoast SEO Premium'
301 );
302 }
303 if ( $this->has_premium_subscription_activated() ) {
304 return \sprintf(
305 /* translators: %s: expands to 'Yoast SEO Premium'. */
306 \__( 'Update %s', 'wordpress-seo' ),
307 'Yoast SEO Premium'
308 );
309 }
310 return \sprintf(
311 /* translators: %s: expands to 'Yoast SEO Premium'. */
312 \__( 'Activate %s', 'wordpress-seo' ),
313 'Yoast SEO Premium'
314 );
315 }
316
317 /**
318 * Returns the upsell/update link to show in the card buttons.
319 *
320 * @return string Returns a string with the upsell/update link for the card buttons.
321 */
322 private function get_upsell_link() {
323 if ( ! $this->product_helper->is_premium() || ! $this->should_update_premium() ) {
324 // Use the default defined in the component.
325 return '';
326 }
327 if ( $this->has_premium_subscription_expired() ) {
328 return 'https://yoa.st/workout-renew-notice';
329 }
330 if ( $this->has_premium_subscription_activated() ) {
331 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' );
332 }
333 return 'https://yoa.st/workouts-activate-notice-myyoast';
334 }
335
336 /**
337 * Whether the user can do the configuration workout.
338 *
339 * @return bool Whether the current user can do the configuration workout.
340 */
341 private function user_can_do_configuration_workout() {
342 return \current_user_can( 'wpseo_manage_options' );
343 }
344
345 /**
346 * Whether the user can edit WordPress options.
347 *
348 * @return bool Whether the current user can edit WordPress options.
349 */
350 private function user_can_edit_wordpress_options() {
351 return \current_user_can( 'manage_options' );
352 }
353 }
354