PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 18.2
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v18.2
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 / helpscout-beacon.php

helpscout-beacon.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 18.2, at src/integrations/admin/helpscout-beacon.php

352 lines 9.3 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_Tracking_Server_Data;
8 use WPSEO_Utils;
9 use Yoast\WP\SEO\Conditionals\Admin_Conditional;
10 use Yoast\WP\SEO\Helpers\Options_Helper;
11 use Yoast\WP\SEO\Integrations\Integration_Interface;
12
13 /**
14 * Class WPSEO_HelpScout
15 */
16 class HelpScout_Beacon implements Integration_Interface {
17
18 /**
19 * The id for the beacon.
20 *
21 * @var string
22 */
23 protected $beacon_id = '2496aba6-0292-489c-8f5d-1c0fba417c2f';
24
25 /**
26 * The id for the beacon for users that have tracking on.
27 *
28 * @var string
29 */
30 protected $beacon_id_tracking_users = '6b8e74c5-aa81-4295-b97b-c2a62a13ea7f';
31
32 /**
33 * The products the beacon is loaded for.
34 *
35 * @var array
36 */
37 protected $products = [];
38
39 /**
40 * Whether to asks the user's consent before loading in HelpScout.
41 *
42 * @var bool
43 */
44 protected $ask_consent = true;
45
46 /**
47 * The options helper.
48 *
49 * @var Options_Helper
50 */
51 protected $options;
52
53 /**
54 * The array of pages we need to show the beacon on with their respective beacon IDs.
55 *
56 * @var array
57 */
58 protected $pages_ids;
59
60 /**
61 * The array of pages we need to show the beacon on.
62 *
63 * @var array
64 */
65 protected $base_pages = [
66 'wpseo_dashboard',
67 'wpseo_titles',
68 'wpseo_search_console',
69 'wpseo_social',
70 'wpseo_tools',
71 'wpseo_licenses',
72 'wpseo_workouts',
73 ];
74
75 /**
76 * The current admin page
77 *
78 * @var string
79 */
80 protected $page;
81
82 /**
83 * The asset manager.
84 *
85 * @var WPSEO_Admin_Asset_Manager
86 */
87 protected $asset_manager;
88
89 /**
90 * Headless_Rest_Endpoints_Enabled_Conditional constructor.
91 *
92 * @param Options_Helper $options The options helper.
93 * @param WPSEO_Admin_Asset_Manager $asset_manager The asset manager.
94 */
95 public function __construct( Options_Helper $options, WPSEO_Admin_Asset_Manager $asset_manager ) {
96 $this->options = $options;
97 $this->asset_manager = $asset_manager;
98 $this->ask_consent = ! $this->options->get( 'tracking' );
99 $this->page = \filter_input( \INPUT_GET, 'page', \FILTER_SANITIZE_STRING );
100
101 foreach ( $this->base_pages as $page ) {
102 if ( $this->ask_consent ) {
103 // We want to be able to show surveys to people who have tracking on, so we give them a different beacon.
104 $this->pages_ids[ $page ] = $this->beacon_id_tracking_users;
105 }
106 else {
107 $this->pages_ids[ $page ] = $this->beacon_id;
108 }
109 }
110 }
111
112 /**
113 * {@inheritDoc}
114 */
115 public function register_hooks() {
116 \add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_help_scout_script' ] );
117 \add_action( 'admin_footer', [ $this, 'output_beacon_js' ] );
118 }
119
120 /**
121 * Enqueues the HelpScout script.
122 */
123 public function enqueue_help_scout_script() {
124 // Make sure plugins can filter in their "stuff", before we check whether we're outputting a beacon.
125 $this->filter_settings();
126 if ( ! $this->is_beacon_page() ) {
127 return;
128 }
129
130 $this->asset_manager->enqueue_script( 'help-scout-beacon' );
131 }
132
133 /**
134 * Outputs a small piece of javascript for the beacon.
135 */
136 public function output_beacon_js() {
137 if ( ! $this->is_beacon_page() ) {
138 return;
139 }
140
141 \printf(
142 '<script type="text/javascript">window.%1$s(\'%2$s\', %3$s)</script>',
143 ( $this->ask_consent ) ? 'wpseoHelpScoutBeaconConsent' : 'wpseoHelpScoutBeacon',
144 \esc_html( $this->pages_ids[ $this->page ] ),
145 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaping done in format_json_encode.
146 WPSEO_Utils::format_json_encode( (array) $this->get_session_data() )
147 );
148 }
149
150 /**
151 * Checks if the current page is a page containing the beacon.
152 *
153 * @return bool
154 */
155 private function is_beacon_page() {
156 $return = false;
157 if ( ! empty( $this->page ) && $GLOBALS['pagenow'] === 'admin.php' && isset( $this->pages_ids[ $this->page ] ) ) {
158 $return = true;
159 }
160
161 /**
162 * Filter: 'wpseo_helpscout_show_beacon' - Allows overriding whether we show the HelpScout beacon.
163 *
164 * @api bool - Whether we show the beacon or not.
165 */
166 return \apply_filters( 'wpseo_helpscout_show_beacon', $return );
167 }
168
169 /**
170 * Retrieves the identifying data.
171 *
172 * @return string The data to pass as identifying data.
173 */
174 protected function get_session_data() {
175 $current_user = \wp_get_current_user();
176
177 // Do not make these strings translatable! They are for our support agents, the user won't see them!
178 $data = [
179 'name' => \trim( $current_user->user_firstname . ' ' . $current_user->user_lastname ),
180 'email' => $current_user->user_email,
181 'WordPress Version' => $this->get_wordpress_version(),
182 'Server' => $this->get_server_info(),
183 '<a href="' . \admin_url( 'themes.php' ) . '">Theme</a>' => $this->get_theme_info(),
184 '<a href="' . \admin_url( 'plugins.php' ) . '">Plugins</a>' => $this->get_active_plugins(),
185 ];
186
187 if ( ! empty( $this->products ) ) {
188 $addon_manager = new WPSEO_Addon_Manager();
189 foreach ( $this->products as $product ) {
190 $subscription = $addon_manager->get_subscription( $product );
191
192 if ( ! $subscription ) {
193 continue;
194 }
195
196 $data[ $subscription->product->name ] = $this->get_product_info( $subscription );
197 }
198 }
199
200 return WPSEO_Utils::format_json_encode( $data );
201 }
202
203 /**
204 * Returns basic info about the server software.
205 *
206 * @return string
207 */
208 private function get_server_info() {
209 $server_tracking_data = new WPSEO_Tracking_Server_Data();
210 $server_data = $server_tracking_data->get();
211 $server_data = $server_data['server'];
212
213 $fields_to_use = [
214 'IP' => 'ip',
215 'Hostname' => 'Hostname',
216 'OS' => 'os',
217 'PHP' => 'PhpVersion',
218 'CURL' => 'CurlVersion',
219 ];
220
221 $server_data['CurlVersion'] = $server_data['CurlVersion']['version'] . '(SSL Support' . $server_data['CurlVersion']['sslSupport'] . ')';
222
223 $server_info = '<table>';
224
225 foreach ( $fields_to_use as $label => $field_to_use ) {
226 if ( isset( $server_data[ $field_to_use ] ) ) {
227 $server_info .= \sprintf( '<tr><td>%1$s</td><td>%2$s</td></tr>', \esc_html( $label ), \esc_html( $server_data[ $field_to_use ] ) );
228 }
229 }
230
231 $server_info .= '</table>';
232
233 return $server_info;
234 }
235
236 /**
237 * Returns info about the Yoast SEO plugin version and license.
238 *
239 * @param object $plugin The plugin.
240 *
241 * @return string The product info.
242 */
243 private function get_product_info( $plugin ) {
244 if ( empty( $plugin ) ) {
245 return '';
246 }
247
248 $product_info = '<table>';
249 $product_info .= '<tr><td>Version</td><td>' . $plugin->product->version . '</td></tr>';
250 $product_info .= '<tr><td>Expiration date</td><td>' . $plugin->expiry_date . '</td></tr>';
251 $product_info .= '</table>';
252
253 return $product_info;
254 }
255
256 /**
257 * Returns the WordPress version + a suffix if current WP is multi site.
258 *
259 * @return string The WordPress version string.
260 */
261 private function get_wordpress_version() {
262 global $wp_version;
263
264 $wordpress_version = $wp_version;
265 if ( \is_multisite() ) {
266 $wordpress_version .= ' MULTI-SITE';
267 }
268
269 return $wordpress_version;
270 }
271
272 /**
273 * Returns a formatted HTML string for the current theme.
274 *
275 * @return string The theme info as string.
276 */
277 private function get_theme_info() {
278 $theme = \wp_get_theme();
279
280 $theme_info = \sprintf(
281 '<a href="%1$s">%2$s</a> v%3$s by %4$s',
282 \esc_attr( $theme->display( 'ThemeURI' ) ),
283 \esc_html( $theme->display( 'Name' ) ),
284 \esc_html( $theme->display( 'Version' ) ),
285 \esc_html( $theme->display( 'Author' ) )
286 );
287
288 if ( \is_child_theme() ) {
289 $theme_info .= \sprintf( '<br />Child theme of: %1$s', \esc_html( $theme->display( 'Template' ) ) );
290 }
291
292 return $theme_info;
293 }
294
295 /**
296 * Returns a formatted HTML list of all active plugins.
297 *
298 * @return string The active plugins.
299 */
300 private function get_active_plugins() {
301 $updates_available = \get_site_transient( 'update_plugins' );
302
303 $active_plugins = '';
304 foreach ( \wp_get_active_and_valid_plugins() as $plugin ) {
305 $plugin_data = \get_plugin_data( $plugin );
306 $plugin_file = \str_replace( \trailingslashit( \WP_PLUGIN_DIR ), '', $plugin );
307
308 if ( isset( $updates_available->response[ $plugin_file ] ) ) {
309 $active_plugins .= '<i class="icon-close1"></i> ';
310 }
311
312 $active_plugins .= \sprintf(
313 '<a href="%1$s">%2$s</a> v%3$s',
314 \esc_attr( $plugin_data['PluginURI'] ),
315 \esc_html( $plugin_data['Name'] ),
316 \esc_html( $plugin_data['Version'] )
317 );
318 }
319
320 return $active_plugins;
321 }
322
323 /**
324 * Returns the conditionals based on which this integration should be active.
325 *
326 * @return array The array of conditionals.
327 */
328 public static function get_conditionals() {
329 return [ Admin_Conditional::class ];
330 }
331
332 /**
333 * Allows filtering of the HelpScout settings. Hooked to admin_head to prevent timing issues, not too early, not too late.
334 */
335 protected function filter_settings() {
336 /**
337 * Filter: 'wpseo_helpscout_beacon_settings' - Allows overriding the HelpScout beacon settings.
338 *
339 * @api string - The HelpScout beacon settings.
340 */
341 $filterable_helpscout_setting = [
342 'products' => $this->products,
343 'pages_ids' => $this->pages_ids,
344 ];
345
346 $helpscout_settings = \apply_filters( 'wpseo_helpscout_beacon_settings', $filterable_helpscout_setting );
347
348 $this->products = $helpscout_settings['products'];
349 $this->pages_ids = $helpscout_settings['pages_ids'];
350 }
351 }
352