options = $options;
$this->asset_manager = $asset_manager;
$this->ask_consent = ! $this->options->get( 'tracking' );
$this->page = \filter_input( \INPUT_GET, 'page', \FILTER_SANITIZE_STRING );
foreach ( $this->base_pages as $page ) {
if ( $this->ask_consent ) {
// We want to be able to show surveys to people who have tracking on, so we give them a different beacon.
$this->pages_ids[ $page ] = $this->beacon_id_tracking_users;
}
else {
$this->pages_ids[ $page ] = $this->beacon_id;
}
}
}
/**
* {@inheritDoc}
*/
public function register_hooks() {
\add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_help_scout_script' ] );
\add_action( 'admin_footer', [ $this, 'output_beacon_js' ] );
}
/**
* Enqueues the HelpScout script.
*/
public function enqueue_help_scout_script() {
// Make sure plugins can filter in their "stuff", before we check whether we're outputting a beacon.
$this->filter_settings();
if ( ! $this->is_beacon_page() ) {
return;
}
$this->asset_manager->enqueue_script( 'help-scout-beacon' );
}
/**
* Outputs a small piece of javascript for the beacon.
*/
public function output_beacon_js() {
if ( ! $this->is_beacon_page() ) {
return;
}
\printf(
'',
( $this->ask_consent ) ? 'wpseoHelpScoutBeaconConsent' : 'wpseoHelpScoutBeacon',
\esc_html( $this->pages_ids[ $this->page ] ),
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaping done in format_json_encode.
WPSEO_Utils::format_json_encode( (array) $this->get_session_data() )
);
}
/**
* Checks if the current page is a page containing the beacon.
*
* @return bool
*/
private function is_beacon_page() {
$return = false;
if ( ! empty( $this->page ) && $GLOBALS['pagenow'] === 'admin.php' && isset( $this->pages_ids[ $this->page ] ) ) {
$return = true;
}
/**
* Filter: 'wpseo_helpscout_show_beacon' - Allows overriding whether we show the HelpScout beacon.
*
* @api bool - Whether we show the beacon or not.
*/
return \apply_filters( 'wpseo_helpscout_show_beacon', $return );
}
/**
* Retrieves the identifying data.
*
* @return string The data to pass as identifying data.
*/
protected function get_session_data() {
$current_user = \wp_get_current_user();
// Do not make these strings translatable! They are for our support agents, the user won't see them!
$data = [
'name' => \trim( $current_user->user_firstname . ' ' . $current_user->user_lastname ),
'email' => $current_user->user_email,
'WordPress Version' => $this->get_wordpress_version(),
'Server' => $this->get_server_info(),
'Theme' => $this->get_theme_info(),
'Plugins' => $this->get_active_plugins(),
];
if ( ! empty( $this->products ) ) {
$addon_manager = new WPSEO_Addon_Manager();
foreach ( $this->products as $product ) {
$subscription = $addon_manager->get_subscription( $product );
if ( ! $subscription ) {
continue;
}
$data[ $subscription->product->name ] = $this->get_product_info( $subscription );
}
}
return WPSEO_Utils::format_json_encode( $data );
}
/**
* Returns basic info about the server software.
*
* @return string
*/
private function get_server_info() {
$server_tracking_data = new WPSEO_Tracking_Server_Data();
$server_data = $server_tracking_data->get();
$server_data = $server_data['server'];
$fields_to_use = [
'IP' => 'ip',
'Hostname' => 'Hostname',
'OS' => 'os',
'PHP' => 'PhpVersion',
'CURL' => 'CurlVersion',
];
$server_data['CurlVersion'] = $server_data['CurlVersion']['version'] . '(SSL Support' . $server_data['CurlVersion']['sslSupport'] . ')';
$server_info = '
';
foreach ( $fields_to_use as $label => $field_to_use ) {
if ( isset( $server_data[ $field_to_use ] ) ) {
$server_info .= \sprintf( '%1$s | %2$s |
', \esc_html( $label ), \esc_html( $server_data[ $field_to_use ] ) );
}
}
$server_info .= '
';
return $server_info;
}
/**
* Returns info about the Yoast SEO plugin version and license.
*
* @param object $plugin The plugin.
*
* @return string The product info.
*/
private function get_product_info( $plugin ) {
if ( empty( $plugin ) ) {
return '';
}
$product_info = '';
$product_info .= 'Version | ' . $plugin->product->version . ' |
';
$product_info .= 'Expiration date | ' . $plugin->expiry_date . ' |
';
$product_info .= '
';
return $product_info;
}
/**
* Returns the WordPress version + a suffix if current WP is multi site.
*
* @return string The WordPress version string.
*/
private function get_wordpress_version() {
global $wp_version;
$wordpress_version = $wp_version;
if ( \is_multisite() ) {
$wordpress_version .= ' MULTI-SITE';
}
return $wordpress_version;
}
/**
* Returns a formatted HTML string for the current theme.
*
* @return string The theme info as string.
*/
private function get_theme_info() {
$theme = \wp_get_theme();
$theme_info = \sprintf(
'%2$s v%3$s by %4$s',
\esc_attr( $theme->display( 'ThemeURI' ) ),
\esc_html( $theme->display( 'Name' ) ),
\esc_html( $theme->display( 'Version' ) ),
\esc_html( $theme->display( 'Author' ) )
);
if ( \is_child_theme() ) {
$theme_info .= \sprintf( '
Child theme of: %1$s', \esc_html( $theme->display( 'Template' ) ) );
}
return $theme_info;
}
/**
* Returns a formatted HTML list of all active plugins.
*
* @return string The active plugins.
*/
private function get_active_plugins() {
$updates_available = \get_site_transient( 'update_plugins' );
$active_plugins = '';
foreach ( \wp_get_active_and_valid_plugins() as $plugin ) {
$plugin_data = \get_plugin_data( $plugin );
$plugin_file = \str_replace( \trailingslashit( \WP_PLUGIN_DIR ), '', $plugin );
if ( isset( $updates_available->response[ $plugin_file ] ) ) {
$active_plugins .= ' ';
}
$active_plugins .= \sprintf(
'%2$s v%3$s',
\esc_attr( $plugin_data['PluginURI'] ),
\esc_html( $plugin_data['Name'] ),
\esc_html( $plugin_data['Version'] )
);
}
return $active_plugins;
}
/**
* Returns the conditionals based on which this integration should be active.
*
* @return array The array of conditionals.
*/
public static function get_conditionals() {
return [ Admin_Conditional::class ];
}
/**
* Allows filtering of the HelpScout settings. Hooked to admin_head to prevent timing issues, not too early, not too late.
*/
protected function filter_settings() {
/**
* Filter: 'wpseo_helpscout_beacon_settings' - Allows overriding the HelpScout beacon settings.
*
* @api string - The HelpScout beacon settings.
*/
$filterable_helpscout_setting = [
'products' => $this->products,
'pages_ids' => $this->pages_ids,
];
$helpscout_settings = \apply_filters( 'wpseo_helpscout_beacon_settings', $filterable_helpscout_setting );
$this->products = $helpscout_settings['products'];
$this->pages_ids = $helpscout_settings['pages_ids'];
}
}