PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / trunk
Yoast SEO – Advanced SEO with real-time guidance and built-in AI vtrunk
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/helpscout-beacon.php +104 -38 18.7 → trunk View file →
@@ -5,12 +5,18 @@
5 5 use WPSEO_Addon_Manager;
6 6 use WPSEO_Admin_Asset_Manager;
7 7 use WPSEO_Tracking_Server_Data;
8 8 use WPSEO_Utils;
9 +use Yoast\WP\SEO\Bulk_Editor\User_Interface\Bulk_Editor_Integration;
9 10 use Yoast\WP\SEO\Conditionals\Admin_Conditional;
11 +use Yoast\WP\SEO\Conditionals\User_Can_Manage_Wpseo_Options_Conditional;
10 12 use Yoast\WP\SEO\Config\Migration_Status;
11 13 use Yoast\WP\SEO\Helpers\Options_Helper;
14 +use Yoast\WP\SEO\Integrations\Academy_Integration;
12 15 use Yoast\WP\SEO\Integrations\Integration_Interface;
16 +use Yoast\WP\SEO\Integrations\Settings_Integration;
17 +use Yoast\WP\SEO\Integrations\Support_Integration;
18 +use Yoast\WP\SEO\Plans\User_Interface\Plans_Page_Integration;
13 19
14 20 /**
15 21 * Class WPSEO_HelpScout
16 22 */
@@ -30,16 +36,30 @@
30 36 */
31 37 protected $beacon_id_tracking_users = '6b8e74c5-aa81-4295-b97b-c2a62a13ea7f';
32 38
33 39 /**
40 + * The id for the beacon for Premium users.
41 + *
42 + * @var string
43 + */
44 + protected $beacon_id_premium = '1ae02e91-5865-4f13-b220-7daed946ba25';
45 +
46 + /**
47 + * The id for the beacon for WooCommerce SEO users.
48 + *
49 + * @var string
50 + */
51 + protected $beacon_id_woocommerce = '8535d745-4e80-48b9-b211-087880aa857d';
52 +
53 + /**
34 54 * The products the beacon is loaded for.
35 55 *
36 - * @var array
56 + * @var array<string>
37 57 */
38 58 protected $products = [];
39 59
40 60 /**
41 - * Whether to asks the user's consent before loading in HelpScout.
61 + * Whether to ask the user's consent before loading in HelpScout.
42 62 *
43 63 * @var bool
44 64 */
45 65 protected $ask_consent = true;
@@ -51,11 +71,18 @@
51 71 */
52 72 protected $options;
53 73
54 74 /**
75 + * The addon manager.
76 + *
77 + * @var WPSEO_Addon_Manager
78 + */
79 + protected $addon_manager;
80 +
81 + /**
55 82 * The array of pages we need to show the beacon on with their respective beacon IDs.
56 83 *
57 - * @var array
84 + * @var array<string, string>
58 85 */
59 86 protected $pages_ids;
60 87
61 88 /**
@@ -60,24 +87,27 @@
60 87
61 88 /**
62 89 * The array of pages we need to show the beacon on.
63 90 *
64 - * @var array
91 + * @var array<string>
65 92 */
66 93 protected $base_pages = [
67 94 'wpseo_dashboard',
68 - 'wpseo_titles',
95 + Settings_Integration::PAGE,
96 + Academy_Integration::PAGE,
97 + Support_Integration::PAGE,
69 98 'wpseo_search_console',
70 - 'wpseo_social',
71 99 'wpseo_tools',
72 - 'wpseo_licenses',
100 + Plans_Page_Integration::PAGE,
73 101 'wpseo_workouts',
102 + Integrations_Page::PAGE,
103 + Bulk_Editor_Integration::PAGE,
74 104 ];
75 105
76 106 /**
77 107 * The current admin page
78 108 *
79 - * @var string
109 + * @var string|null
80 110 */
81 111 protected $page;
82 112
83 113 /**
@@ -99,29 +129,35 @@
99 129 *
100 130 * @param Options_Helper $options The options helper.
101 131 * @param WPSEO_Admin_Asset_Manager $asset_manager The asset manager.
102 132 * @param Migration_Status $migration_status The migrations status.
133 + * @param WPSEO_Addon_Manager $addon_manager The addon manager.
103 134 */
104 - public function __construct( Options_Helper $options, WPSEO_Admin_Asset_Manager $asset_manager, Migration_Status $migration_status ) {
105 - $this->options = $options;
106 - $this->asset_manager = $asset_manager;
107 - $this->ask_consent = ! $this->options->get( 'tracking' );
108 - $this->page = \filter_input( \INPUT_GET, 'page', \FILTER_SANITIZE_STRING );
135 + public function __construct( Options_Helper $options, WPSEO_Admin_Asset_Manager $asset_manager, Migration_Status $migration_status, WPSEO_Addon_Manager $addon_manager ) {
136 + $this->options = $options;
137 + $this->asset_manager = $asset_manager;
138 + $this->addon_manager = $addon_manager;
139 + $this->ask_consent = ! $this->options->get( 'tracking' );
140 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: We are not processing form information.
141 + if ( isset( $_GET['page'] ) && \is_string( $_GET['page'] ) ) {
142 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: We are not processing form information.
143 + $this->page = \sanitize_text_field( \wp_unslash( $_GET['page'] ) );
144 + }
145 + else {
146 + $this->page = null;
147 + }
109 148 $this->migration_status = $migration_status;
110 149
150 + $beacon_id = $this->get_beacon_id();
111 151 foreach ( $this->base_pages as $page ) {
112 - if ( $this->ask_consent ) {
113 - // We want to be able to show surveys to people who have tracking on, so we give them a different beacon.
114 - $this->pages_ids[ $page ] = $this->beacon_id_tracking_users;
115 - }
116 - else {
117 - $this->pages_ids[ $page ] = $this->beacon_id;
118 - }
152 + $this->pages_ids[ $page ] = $beacon_id;
119 153 }
120 154 }
121 155
122 156 /**
123 157 * {@inheritDoc}
158 + *
159 + * @return void
124 160 */
125 161 public function register_hooks() {
126 162 \add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_help_scout_script' ] );
127 163 \add_action( 'admin_footer', [ $this, 'output_beacon_js' ] );
@@ -128,8 +164,10 @@
128 164 }
129 165
130 166 /**
131 167 * Enqueues the HelpScout script.
168 + *
169 + * @return void
132 170 */
133 171 public function enqueue_help_scout_script() {
134 172 // Make sure plugins can filter in their "stuff", before we check whether we're outputting a beacon.
135 173 $this->filter_settings();
@@ -141,8 +179,10 @@
141 179 }
142 180
143 181 /**
144 182 * Outputs a small piece of javascript for the beacon.
183 + *
184 + * @return void
145 185 */
146 186 public function output_beacon_js() {
147 187 if ( ! $this->is_beacon_page() ) {
148 188 return;
@@ -152,9 +192,9 @@
152 192 '<script type="text/javascript">window.%1$s(\'%2$s\', %3$s)</script>',
153 193 ( $this->ask_consent ) ? 'wpseoHelpScoutBeaconConsent' : 'wpseoHelpScoutBeacon',
154 194 \esc_html( $this->pages_ids[ $this->page ] ),
155 195 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaping done in format_json_encode.
156 - WPSEO_Utils::format_json_encode( (array) $this->get_session_data() )
196 + WPSEO_Utils::format_json_encode( (array) $this->get_session_data() ),
157 197 );
158 198 }
159 199
160 200 /**
@@ -170,9 +210,9 @@
170 210
171 211 /**
172 212 * Filter: 'wpseo_helpscout_show_beacon' - Allows overriding whether we show the HelpScout beacon.
173 213 *
174 - * @api bool - Whether we show the beacon or not.
214 + * @param bool $show_beacon Whether we show the beacon or not.
175 215 */
176 216 return \apply_filters( 'wpseo_helpscout_show_beacon', $return );
177 217 }
178 218
@@ -204,9 +244,9 @@
204 244 'Active theme' => $this->get_theme_info(),
205 245 'Active plugins' => $this->get_active_plugins(),
206 246 'Must-use and dropins' => $this->get_mustuse_and_dropins(),
207 247 'Indexables status' => $this->get_indexables_status(),
208 - ]
248 + ],
209 249 );
210 250
211 251 if ( ! empty( $this->products ) ) {
212 252 $addon_manager = new WPSEO_Addon_Manager();
@@ -229,9 +269,9 @@
229 269
230 270 /**
231 271 * Returns basic info about the server software.
232 272 *
233 - * @return array
273 + * @return array<string, string>
234 274 */
235 275 private function get_server_info() {
236 276 $server_tracking_data = new WPSEO_Tracking_Server_Data();
237 277 $server_data = $server_tracking_data->get();
@@ -281,9 +321,9 @@
281 321 }
282 322
283 323 $product_info = \sprintf(
284 324 'Expiration date %1$s',
285 - $plugin->expiry_date
325 + $plugin->expiry_date,
286 326 );
287 327
288 328 return $product_info;
289 329 }
@@ -318,9 +358,9 @@
318 358 $theme_info = \sprintf(
319 359 '%1$s (Version %2$s, %3$s)',
320 360 \esc_html( $theme->display( 'Name' ) ),
321 361 \esc_html( $theme->display( 'Version' ) ),
322 - \esc_attr( $theme->display( 'ThemeURI' ) )
362 + \esc_attr( $theme->display( 'ThemeURI' ) ),
323 363 );
324 364
325 365 if ( \is_child_theme() ) {
326 366 $theme_info .= \sprintf( ', this is a child theme of: %1$s', \esc_html( $theme->display( 'Template' ) ) );
@@ -351,9 +391,9 @@
351 391 '%1$s (Version %2$s%3$s, %4$s) | ',
352 392 \esc_html( $plugin_data['Name'] ),
353 393 \esc_html( $plugin_data['Version'] ),
354 394 $plugin_update_available,
355 - \esc_attr( $plugin_data['PluginURI'] )
395 + \esc_attr( $plugin_data['PluginURI'] ),
356 396 );
357 397 }
358 398
359 399 return $active_plugins;
@@ -414,9 +454,9 @@
414 454
415 455 $language_settings = \sprintf(
416 456 'Site locale: %1$s, user locale: %2$s',
417 457 ( \is_string( $site_locale ) ) ? \esc_html( $site_locale ) : 'unknown',
418 - ( \is_string( $user_locale ) ) ? \esc_html( $user_locale ) : 'unknown'
458 + ( \is_string( $user_locale ) ) ? \esc_html( $user_locale ) : 'unknown',
419 459 );
420 460
421 461 return $language_settings;
422 462 }
@@ -423,30 +463,56 @@
423 463
424 464 /**
425 465 * Returns the conditionals based on which this integration should be active.
426 466 *
427 - * @return array The array of conditionals.
467 + * @return array<string> The array of conditionals.
428 468 */
429 469 public static function get_conditionals() {
430 - return [ Admin_Conditional::class ];
470 + return [ Admin_Conditional::class, User_Can_Manage_Wpseo_Options_Conditional::class ];
431 471 }
432 472
433 473 /**
474 + * Get the beacon id to use based on the user's subscription and tracking settings.
475 + *
476 + * @return string The beacon id to use.
477 + */
478 + private function get_beacon_id() {
479 + // Case where the user has a Yoast WooCommerce SEO plan subscription (highest priority).
480 + if ( $this->addon_manager->has_active_addons() && $this->addon_manager->has_valid_subscription( WPSEO_Addon_Manager::WOOCOMMERCE_SLUG ) ) {
481 + return $this->beacon_id_woocommerce;
482 + }
483 +
484 + // Case where the user has a Yoast SEO Premium plan subscription.
485 + if ( $this->addon_manager->has_active_addons() && $this->addon_manager->has_valid_subscription( WPSEO_Addon_Manager::PREMIUM_SLUG ) ) {
486 + return $this->beacon_id_premium;
487 + }
488 +
489 + // Case where the user has no plan active and tracking enabled.
490 + if ( $this->ask_consent ) {
491 + return $this->beacon_id_tracking_users;
492 + }
493 +
494 + // Case where the user has no plan active and tracking disabled.
495 + return $this->beacon_id;
496 + }
497 +
498 + /**
434 499 * Allows filtering of the HelpScout settings. Hooked to admin_head to prevent timing issues, not too early, not too late.
500 + *
501 + * @return void
435 502 */
436 503 protected function filter_settings() {
437 - /**
438 - * Filter: 'wpseo_helpscout_beacon_settings' - Allows overriding the HelpScout beacon settings.
439 - *
440 - * @api string - The HelpScout beacon settings.
441 - */
442 504 $filterable_helpscout_setting = [
443 505 'products' => $this->products,
444 506 'pages_ids' => $this->pages_ids,
445 507 ];
446 508
509 + /**
510 + * Filter: 'wpseo_helpscout_beacon_settings' - Allows overriding the HelpScout beacon settings.
511 + *
512 + * @param string $beacon_settings The HelpScout beacon settings.
513 + */
447 514 $helpscout_settings = \apply_filters( 'wpseo_helpscout_beacon_settings', $filterable_helpscout_setting );
448 -
449 - $this->products = $helpscout_settings['products'];
450 - $this->pages_ids = $helpscout_settings['pages_ids'];
515 + $this->products = $helpscout_settings['products'];
516 + $this->pages_ids = $helpscout_settings['pages_ids'];
451 517 }
452 518 }