: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
use Yoast\WP\SEO\Helpers\Product_Helper;
use Yoast\WP\SEO\Helpers\Score_Icon_Helper;
use Yoast\WP\SEO\Integrations\Support_Integration;
use Yoast\WP\SEO\Models\Indexable;
use Yoast\WP\SEO\Presenters\Admin\Premium_Badge_Presenter;
use Yoast\WP\SEO\Promotions\Application\Promotion_Manager;
use Yoast\WP\SEO\Repositories\Indexable_Repository;
* Class for the Yoast SEO admin bar menu.
class WPSEO_Admin_Bar_Menu implements WPSEO_WordPress_Integration {
* The identifier used for the menu.
public const MENU_IDENTIFIER = 'wpseo-menu';
* The identifier used for the Keyword Research submenu.
public const KEYWORD_RESEARCH_SUBMENU_IDENTIFIER = 'wpseo-kwresearch';
* The identifier used for the Analysis submenu.
public const ANALYSIS_SUBMENU_IDENTIFIER = 'wpseo-analysis';
* The identifier used for the Settings submenu.
public const SETTINGS_SUBMENU_IDENTIFIER = 'wpseo-settings';
* The identifier used for the Network Settings submenu.
public const NETWORK_SETTINGS_SUBMENU_IDENTIFIER = 'wpseo-network-settings';
* Asset manager instance.
* @var WPSEO_Admin_Asset_Manager
protected $asset_manager;
* Holds the Score_Icon_Helper instance.
protected $indexable_repository;
* Holds the Score_Icon_Helper instance.
protected $score_icon_helper;
* Holds the Product_Helper instance.
protected $product_helper;
* Holds the shortlinker instance.
* Whether SEO Score is enabled.
protected $is_seo_enabled = null;
* Whether readability is enabled.
protected $is_readability_enabled = null;
* The indexable for the current WordPress page, if found.
protected $current_indexable = null;
* Constructs the WPSEO_Admin_Bar_Menu.
* @param WPSEO_Admin_Asset_Manager|null $asset_manager Optional. Asset manager to use.
* @param Indexable_Repository|null $indexable_repository Optional. The Indexable_Repository.
* @param Score_Icon_Helper|null $score_icon_helper Optional. The Score_Icon_Helper.
* @param Product_Helper|null $product_helper Optional. The product helper.
* @param WPSEO_Shortlinker|null $shortlinker The shortlinker.
public function __construct(
?WPSEO_Admin_Asset_Manager $asset_manager = null,
?Indexable_Repository $indexable_repository = null,
?Score_Icon_Helper $score_icon_helper = null,
?Product_Helper $product_helper = null,
?WPSEO_Shortlinker $shortlinker = null
if ( ! $asset_manager ) {
$asset_manager = new WPSEO_Admin_Asset_Manager();
if ( ! $indexable_repository ) {
$indexable_repository = YoastSEO()->classes->get( Indexable_Repository::class );
if ( ! $score_icon_helper ) {
$score_icon_helper = YoastSEO()->helpers->score_icon;
if ( ! $product_helper ) {
$product_helper = YoastSEO()->helpers->product;
$shortlinker = new WPSEO_Shortlinker();
$this->product_helper = $product_helper;
$this->asset_manager = $asset_manager;
$this->indexable_repository = $indexable_repository;
$this->score_icon_helper = $score_icon_helper;
$this->shortlinker = $shortlinker;
* Gets whether SEO score is enabled, with cache applied.
* @return bool True if SEO score is enabled, false otherwise.
protected function get_is_seo_enabled() {
if ( is_null( $this->is_seo_enabled ) ) {
$this->is_seo_enabled = ( new WPSEO_Metabox_Analysis_SEO() )->is_enabled();
return $this->is_seo_enabled;
* Gets whether readability is enabled, with cache applied.
* @return bool True if readability is enabled, false otherwise.
protected function get_is_readability_enabled() {
if ( is_null( $this->is_readability_enabled ) ) {
$this->is_readability_enabled = ( new WPSEO_Metabox_Analysis_Readability() )->is_enabled();
return $this->is_readability_enabled;
* Returns the indexable for the current WordPress page, with cache applied.
* @return bool|Indexable The indexable, false if none could be found.
protected function get_current_indexable() {
if ( is_null( $this->current_indexable ) ) {
$this->current_indexable = $this->indexable_repository->for_current_page();
return $this->current_indexable;
* Adds the admin bar menu.
* @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
public function add_menu( WP_Admin_Bar $wp_admin_bar ) {
// On block editor pages, the admin bar only shows on mobile, where having this menu icon is not very helpful.
$screen = get_current_screen();
if ( isset( $screen ) && $screen->is_block_editor() ) {
// If the current user can't write posts, this is all of no use, so let's not output an admin menu.
if ( ! current_user_can( 'edit_posts' ) ) {
$this->add_root_menu( $wp_admin_bar );
* Adds a submenu item in the top of the adminbar.
* @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
* @param string $menu_identifier The menu identifier.
do_action( 'wpseo_add_adminbar_submenu', $wp_admin_bar, self::MENU_IDENTIFIER );
if ( is_singular() || is_tag() || is_tax() || is_category() ) {
$is_seo_enabled = $this->get_is_seo_enabled();
$is_readability_enabled = $this->get_is_readability_enabled();
$indexable = $this->get_current_indexable();
$focus_keyword = ( ! is_a( $indexable, 'Yoast\WP\SEO\Models\Indexable' ) || is_null( $indexable->primary_focus_keyword ) ) ? __( 'not set', 'wordpress-seo' ) : $indexable->primary_focus_keyword;
'parent' => self::MENU_IDENTIFIER,
'id' => 'wpseo-seo-focus-keyword',
'title' => __( 'Focus keyphrase: ', 'wordpress-seo' ) . '<span class="wpseo-focus-keyword">' . $focus_keyword . '</span>',
'meta' => [ 'tabindex' => '0' ],
'parent' => self::MENU_IDENTIFIER,
'id' => 'wpseo-seo-score',
'title' => __( 'SEO score', 'wordpress-seo' ) . ': ' . $this->score_icon_helper->for_seo( $indexable, 'adminbar-sub-menu-score' )
'meta' => [ 'tabindex' => '0' ],
if ( $is_readability_enabled ) {
'parent' => self::MENU_IDENTIFIER,
'id' => 'wpseo-readability-score',
'title' => __( 'Readability', 'wordpress-seo' ) . ': ' . $this->score_icon_helper->for_readability( $indexable->readability_score, 'adminbar-sub-menu-score' )
'meta' => [ 'tabindex' => '0' ],
if ( ! $this->product_helper->is_premium() ) {
'parent' => self::MENU_IDENTIFIER,
'id' => 'wpseo-frontend-inspector',
'href' => $this->shortlinker->build_shortlink( 'https://yoa.st/admin-bar-frontend-inspector' ),
'title' => __( 'Front-end SEO inspector', 'wordpress-seo' ) . new Premium_Badge_Presenter( 'wpseo-frontend-inspector-badge' ),
$this->add_analysis_submenu( $wp_admin_bar );
$this->add_seo_tools_submenu( $wp_admin_bar );
$this->add_how_to_submenu( $wp_admin_bar );
$this->add_get_help_submenu( $wp_admin_bar );
if ( ! is_admin() || is_blog_admin() ) {
$this->add_settings_submenu( $wp_admin_bar );
elseif ( is_network_admin() ) {
$this->add_network_settings_submenu( $wp_admin_bar );
if ( ! $this->product_helper->is_premium() ) {
$this->add_premium_link( $wp_admin_bar );
* Enqueues admin bar assets.
public function enqueue_assets() {
if ( ! is_admin_bar_showing() ) {
// If the current user can't write posts, this is all of no use, so let's not output an admin menu.
if ( ! current_user_can( 'edit_posts' ) ) {
$this->asset_manager->register_assets();
$this->asset_manager->enqueue_style( 'adminbar' );
public function register_hooks() {
if ( ! $this->meets_requirements() ) {
add_action( 'admin_bar_menu', [ $this, 'add_menu' ], 95 );
add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_assets' ] );
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
* Checks whether the requirements to use this class are met.
* @return bool True if requirements are met, false otherwise.
public function meets_requirements() {
if ( is_network_admin() ) {
return WPSEO_Utils::is_plugin_network_active();
if ( WPSEO_Options::get( 'enable_admin_bar_menu' ) !== true ) {
return ! is_admin() || is_blog_admin();
* Adds the admin bar root menu.
* @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
protected function add_root_menu( WP_Admin_Bar $wp_admin_bar ) {
$title = $this->get_title();
$notification_popup = '';
$post = $this->get_singular_post();
$score = $this->get_post_score( $post );
$term = $this->get_singular_term();
$score = $this->get_term_score( $term );
$can_manage_options = $this->can_manage_options();
if ( $can_manage_options ) {
$settings_url = $this->get_settings_page_url();
if ( empty( $score ) && ! is_network_admin() && $can_manage_options ) {
$counter = $this->get_notification_counter();
$notification_popup = $this->get_notification_popup();
'id' => self::MENU_IDENTIFIER,
'title' => $title . $score . $counter . $notification_popup,
'meta' => [ 'tabindex' => ! empty( $settings_url ) ? false : '0' ],
$wp_admin_bar->add_menu( $admin_bar_menu_args );
if ( ! empty( $counter ) ) {
'parent' => self::MENU_IDENTIFIER,
'id' => 'wpseo-notifications',
'title' => __( 'Notifications', 'wordpress-seo' ) . $counter,
'meta' => [ 'tabindex' => ! empty( $settings_url ) ? false : '0' ],
$wp_admin_bar->add_menu( $admin_bar_menu_args );
* Adds the admin bar analysis submenu.
* @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
protected function add_analysis_submenu( WP_Admin_Bar $wp_admin_bar ) {
$url = YoastSEO()->meta->for_current_page()->canonical;
} catch ( Exception $e ) {
// This is not the type of error we can handle here.
'parent' => self::MENU_IDENTIFIER,
'id' => self::ANALYSIS_SUBMENU_IDENTIFIER,
'title' => __( 'Analyze this page', 'wordpress-seo' ),
'meta' => [ 'tabindex' => '0' ],
$wp_admin_bar->add_menu( $menu_args );
$encoded_url = rawurlencode( $url );
'title' => __( 'Check links to this URL', 'wordpress-seo' ),
'href' => 'https://search.google.com/search-console/links/drilldown?resource_id=' . rawurlencode( get_option( 'siteurl' ) ) . '&type=EXTERNAL&target=' . $encoded_url . '&domain=',
'id' => 'wpseo-structureddata',
'title' => __( 'Google Rich Results Test', 'wordpress-seo' ),
'href' => 'https://search.google.com/test/rich-results?url=' . $encoded_url,
'id' => 'wpseo-facebookdebug',
'title' => __( 'Facebook Debugger', 'wordpress-seo' ),
'href' => '//developers.facebook.com/tools/debug/?q=' . $encoded_url,
'id' => 'wpseo-pagespeed',
'title' => __( 'Google Page Speed Test', 'wordpress-seo' ),
'href' => '//developers.google.com/speed/pagespeed/insights/?url=' . $encoded_url,
$this->add_submenu_items( $submenu_items, $wp_admin_bar, self::ANALYSIS_SUBMENU_IDENTIFIER );
* Adds the admin bar tools submenu.
* @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
protected function add_seo_tools_submenu( WP_Admin_Bar $wp_admin_bar ) {
'parent' => self::MENU_IDENTIFIER,
'id' => 'wpseo-sub-tools',
'title' => __( 'SEO Tools', 'wordpress-seo' ),
'meta' => [ 'tabindex' => '0' ],
$wp_admin_bar->add_menu( $menu_args );
'href' => $this->shortlinker->build_shortlink( 'https://yoa.st/admin-bar-semrush' ),
'href' => $this->shortlinker->build_shortlink( 'https://yoa.st/admin-bar-wincher' ),
'id' => 'wpseo-google-trends',
'title' => 'Google trends',
'href' => $this->shortlinker->build_shortlink( 'https://yoa.st/admin-bar-gtrends' ),
$this->add_submenu_items( $submenu_items, $wp_admin_bar, 'wpseo-sub-tools' );
* Adds the admin bar How To submenu.
* @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.