• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Yoast / wordpress-seo / 993f259bead15d3b90dcff95657b8a588f66ed76

21 Nov 2025 02:03PM UTC coverage: 52.891% (-0.5%) from 53.366%
993f259bead15d3b90dcff95657b8a588f66ed76

Pull #22743

github

web-flow
Merge 8ea181540 into 530e8fcfb
Pull Request #22743: Redesign ai brand insights button & change behavior of upgrade button

8318 of 15589 branches covered (53.36%)

Branch coverage included in aggregate %.

2 of 46 new or added lines in 4 files covered. (4.35%)

2 existing lines in 2 files now uncovered.

31815 of 60289 relevant lines covered (52.77%)

47826.41 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

8.33
/inc/class-wpseo-admin-bar-menu.php
1
<?php
2
/**
3
 * WPSEO plugin file.
4
 *
5
 * @package WPSEO
6
 */
7

8
use Yoast\WP\SEO\Conditionals\WooCommerce_Conditional;
9
use Yoast\WP\SEO\Helpers\Product_Helper;
10
use Yoast\WP\SEO\Helpers\Score_Icon_Helper;
11
use Yoast\WP\SEO\Integrations\Support_Integration;
12
use Yoast\WP\SEO\Models\Indexable;
13
use Yoast\WP\SEO\Presenters\Admin\Premium_Badge_Presenter;
14
use Yoast\WP\SEO\Promotions\Application\Promotion_Manager;
15
use Yoast\WP\SEO\Repositories\Indexable_Repository;
16

17
/**
18
 * Class for the Yoast SEO admin bar menu.
19
 */
20
class WPSEO_Admin_Bar_Menu implements WPSEO_WordPress_Integration {
21

22
        /**
23
         * The identifier used for the menu.
24
         *
25
         * @var string
26
         */
27
        public const MENU_IDENTIFIER = 'wpseo-menu';
28

29
        /**
30
         * The identifier used for the Keyword Research submenu.
31
         *
32
         * @var string
33
         */
34
        public const KEYWORD_RESEARCH_SUBMENU_IDENTIFIER = 'wpseo-kwresearch';
35

36
        /**
37
         * The identifier used for the Analysis submenu.
38
         *
39
         * @var string
40
         */
41
        public const ANALYSIS_SUBMENU_IDENTIFIER = 'wpseo-analysis';
42

43
        /**
44
         * The identifier used for the Settings submenu.
45
         *
46
         * @var string
47
         */
48
        public const SETTINGS_SUBMENU_IDENTIFIER = 'wpseo-settings';
49

50
        /**
51
         * The identifier used for the Network Settings submenu.
52
         *
53
         * @var string
54
         */
55
        public const NETWORK_SETTINGS_SUBMENU_IDENTIFIER = 'wpseo-network-settings';
56

57
        /**
58
         * Asset manager instance.
59
         *
60
         * @var WPSEO_Admin_Asset_Manager
61
         */
62
        protected $asset_manager;
63

64
        /**
65
         * Holds the Score_Icon_Helper instance.
66
         *
67
         * @var Score_Icon_Helper
68
         */
69
        protected $indexable_repository;
70

71
        /**
72
         * Holds the Score_Icon_Helper instance.
73
         *
74
         * @var Score_Icon_Helper
75
         */
76
        protected $score_icon_helper;
77

78
        /**
79
         * Holds the Product_Helper instance.
80
         *
81
         * @var Product_Helper
82
         */
83
        protected $product_helper;
84

85
        /**
86
         * Holds the shortlinker instance.
87
         *
88
         * @var WPSEO_Shortlinker
89
         */
90
        protected $shortlinker;
91

92
        /**
93
         * Whether SEO Score is enabled.
94
         *
95
         * @var bool|null
96
         */
97
        protected $is_seo_enabled = null;
98

99
        /**
100
         * Whether readability is enabled.
101
         *
102
         * @var bool|null
103
         */
104
        protected $is_readability_enabled = null;
105

106
        /**
107
         * The indexable for the current WordPress page, if found.
108
         *
109
         * @var Indexable|bool|null
110
         */
111
        protected $current_indexable = null;
112

113
        /**
114
         * Constructs the WPSEO_Admin_Bar_Menu.
115
         *
116
         * @param WPSEO_Admin_Asset_Manager|null $asset_manager        Optional. Asset manager to use.
117
         * @param Indexable_Repository|null      $indexable_repository Optional. The Indexable_Repository.
118
         * @param Score_Icon_Helper|null         $score_icon_helper    Optional. The Score_Icon_Helper.
119
         * @param Product_Helper|null            $product_helper       Optional. The product helper.
120
         * @param WPSEO_Shortlinker|null         $shortlinker          The shortlinker.
121
         */
122
        public function __construct(
×
123
                ?WPSEO_Admin_Asset_Manager $asset_manager = null,
124
                ?Indexable_Repository $indexable_repository = null,
125
                ?Score_Icon_Helper $score_icon_helper = null,
126
                ?Product_Helper $product_helper = null,
127
                ?WPSEO_Shortlinker $shortlinker = null
128
        ) {
129
                if ( ! $asset_manager ) {
×
130
                        $asset_manager = new WPSEO_Admin_Asset_Manager();
×
131
                }
132
                if ( ! $indexable_repository ) {
×
133
                        $indexable_repository = YoastSEO()->classes->get( Indexable_Repository::class );
×
134
                }
135
                if ( ! $score_icon_helper ) {
×
136
                        $score_icon_helper = YoastSEO()->helpers->score_icon;
×
137
                }
138
                if ( ! $product_helper ) {
×
139
                        $product_helper = YoastSEO()->helpers->product;
×
140
                }
141
                if ( ! $shortlinker ) {
×
142
                        $shortlinker = new WPSEO_Shortlinker();
×
143
                }
144

145
                $this->product_helper       = $product_helper;
×
146
                $this->asset_manager        = $asset_manager;
×
147
                $this->indexable_repository = $indexable_repository;
×
148
                $this->score_icon_helper    = $score_icon_helper;
×
149
                $this->shortlinker          = $shortlinker;
×
150
        }
151

152
        /**
153
         * Gets whether SEO score is enabled, with cache applied.
154
         *
155
         * @return bool True if SEO score is enabled, false otherwise.
156
         */
157
        protected function get_is_seo_enabled() {
×
158
                if ( $this->is_seo_enabled === null ) {
×
159
                        $this->is_seo_enabled = ( new WPSEO_Metabox_Analysis_SEO() )->is_enabled();
×
160
                }
161

162
                return $this->is_seo_enabled;
×
163
        }
164

165
        /**
166
         * Gets whether readability is enabled, with cache applied.
167
         *
168
         * @return bool True if readability is enabled, false otherwise.
169
         */
170
        protected function get_is_readability_enabled() {
×
171
                if ( $this->is_readability_enabled === null ) {
×
172
                        $this->is_readability_enabled = ( new WPSEO_Metabox_Analysis_Readability() )->is_enabled();
×
173
                }
174

175
                return $this->is_readability_enabled;
×
176
        }
177

178
        /**
179
         * Returns the indexable for the current WordPress page, with cache applied.
180
         *
181
         * @return bool|Indexable The indexable, false if none could be found.
182
         */
183
        protected function get_current_indexable() {
×
184
                if ( $this->current_indexable === null ) {
×
185
                        $this->current_indexable = $this->indexable_repository->for_current_page();
×
186
                }
187

188
                return $this->current_indexable;
×
189
        }
190

191
        /**
192
         * Adds the admin bar menu.
193
         *
194
         * @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
195
         *
196
         * @return void
197
         */
198
        public function add_menu( WP_Admin_Bar $wp_admin_bar ) {
8✔
199
                // On block editor pages, the admin bar only shows on mobile, where having this menu icon is not very helpful.
200
                if ( is_admin() ) {
8✔
201
                        $screen = get_current_screen();
×
202
                        if ( isset( $screen ) && $screen->is_block_editor() ) {
×
203
                                return;
×
204
                        }
205
                }
206

207
                // If the current user can't write posts, this is all of no use, so let's not output an admin menu.
208
                if ( ! current_user_can( 'edit_posts' ) ) {
8✔
209
                        return;
4✔
210
                }
211

212
                $this->add_root_menu( $wp_admin_bar );
4✔
213

214
                /**
215
                 * Adds a submenu item in the top of the adminbar.
216
                 *
217
                 * @param WP_Admin_Bar $wp_admin_bar    Admin bar instance to add the menu to.
218
                 * @param string       $menu_identifier The menu identifier.
219
                 */
220
                do_action( 'wpseo_add_adminbar_submenu', $wp_admin_bar, self::MENU_IDENTIFIER );
4✔
221

222
                if ( ! is_admin() ) {
4✔
223

224
                        if ( is_singular() || is_tag() || is_tax() || is_category() ) {
4✔
225
                                $is_seo_enabled         = $this->get_is_seo_enabled();
×
226
                                $is_readability_enabled = $this->get_is_readability_enabled();
×
227

228
                                $indexable = $this->get_current_indexable();
×
229

230
                                if ( $is_seo_enabled ) {
×
231
                                        $focus_keyword = ( ! is_a( $indexable, 'Yoast\WP\SEO\Models\Indexable' ) || $indexable->primary_focus_keyword === null ) ? __( 'not set', 'wordpress-seo' ) : $indexable->primary_focus_keyword;
×
232

233
                                        $wp_admin_bar->add_menu(
×
234
                                                [
×
235
                                                        'parent' => self::MENU_IDENTIFIER,
×
236
                                                        'id'     => 'wpseo-seo-focus-keyword',
×
237
                                                        'title'  => __( 'Focus keyphrase: ', 'wordpress-seo' ) . '<span class="wpseo-focus-keyword">' . $focus_keyword . '</span>',
×
238
                                                        'meta'   => [ 'tabindex' => '0' ],
×
239
                                                ]
×
240
                                        );
×
241
                                        $wp_admin_bar->add_menu(
×
242
                                                [
×
243
                                                        'parent' => self::MENU_IDENTIFIER,
×
244
                                                        'id'     => 'wpseo-seo-score',
×
245
                                                        'title'  => __( 'SEO score', 'wordpress-seo' ) . ': ' . $this->score_icon_helper->for_seo( $indexable, 'adminbar-sub-menu-score' )
×
246
                                                                        ->present(),
×
247
                                                        'meta'   => [ 'tabindex' => '0' ],
×
248
                                                ]
×
249
                                        );
×
250
                                }
251

252
                                if ( $is_readability_enabled ) {
×
253
                                        $wp_admin_bar->add_menu(
×
254
                                                [
×
255
                                                        'parent' => self::MENU_IDENTIFIER,
×
256
                                                        'id'     => 'wpseo-readability-score',
×
257
                                                        'title'  => __( 'Readability', 'wordpress-seo' ) . ': ' . $this->score_icon_helper->for_readability( $indexable->readability_score, 'adminbar-sub-menu-score' )
×
258
                                                                        ->present(),
×
259
                                                        'meta'   => [ 'tabindex' => '0' ],
×
260
                                                ]
×
261
                                        );
×
262
                                }
263

264
                                if ( ! $this->product_helper->is_premium() ) {
×
265
                                        $wp_admin_bar->add_menu(
×
266
                                                [
×
267
                                                        'parent' => self::MENU_IDENTIFIER,
×
268
                                                        'id'     => 'wpseo-frontend-inspector',
×
269
                                                        'href'   => $this->shortlinker->build_shortlink( 'https://yoa.st/admin-bar-frontend-inspector' ),
×
270
                                                        'title'  => __( 'Front-end SEO inspector', 'wordpress-seo' ) . new Premium_Badge_Presenter( 'wpseo-frontend-inspector-badge' ),
×
271
                                                        'meta'   => [
×
272
                                                                'tabindex' => '0',
×
273
                                                                'target'   => '_blank',
×
274
                                                        ],
×
275
                                                ]
×
276
                                        );
×
277
                                }
278
                        }
279
                        $this->add_analysis_submenu( $wp_admin_bar );
4✔
280
                        $this->add_seo_tools_submenu( $wp_admin_bar );
4✔
281
                        $this->add_how_to_submenu( $wp_admin_bar );
4✔
282
                        $this->add_get_help_submenu( $wp_admin_bar );
4✔
283
                }
284

285
                if ( ! is_admin() || is_blog_admin() ) {
4✔
286
                        $this->add_settings_submenu( $wp_admin_bar );
4✔
287
                }
288
                elseif ( is_network_admin() ) {
×
289
                        $this->add_network_settings_submenu( $wp_admin_bar );
×
290
                }
291

292
                $this->add_premium_link( $wp_admin_bar );
4✔
293
                $this->add_brand_insights_link( $wp_admin_bar );
4✔
294
        }
295

296
        /**
297
         * Enqueues admin bar assets.
298
         *
299
         * @return void
300
         */
301
        public function enqueue_assets() {
8✔
302
                if ( ! is_admin_bar_showing() ) {
8✔
303
                        return;
4✔
304
                }
305

306
                // If the current user can't write posts, this is all of no use, so let's not output an admin menu.
307
                if ( ! current_user_can( 'edit_posts' ) ) {
4✔
308
                        return;
×
309
                }
310

311
                $this->asset_manager->register_assets();
4✔
312
                $this->asset_manager->enqueue_style( 'adminbar' );
4✔
313
        }
314

315
        /**
316
         * Registers the hooks.
317
         *
318
         * @return void
319
         */
320
        public function register_hooks() {
4✔
321
                if ( ! $this->meets_requirements() ) {
4✔
322
                        return;
×
323
                }
324

325
                add_action( 'admin_bar_menu', [ $this, 'add_menu' ], 95 );
4✔
326

327
                add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_assets' ] );
4✔
328
                add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
4✔
329
        }
330

331
        /**
332
         * Checks whether the requirements to use this class are met.
333
         *
334
         * @return bool True if requirements are met, false otherwise.
335
         */
336
        public function meets_requirements() {
4✔
337
                if ( is_network_admin() ) {
4✔
338
                        return WPSEO_Utils::is_plugin_network_active();
×
339
                }
340

341
                if ( WPSEO_Options::get( 'enable_admin_bar_menu' ) !== true ) {
4✔
342
                        return false;
4✔
343
                }
344

345
                return ! is_admin() || is_blog_admin();
4✔
346
        }
347

348
        /**
349
         * Adds the admin bar root menu.
350
         *
351
         * @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
352
         *
353
         * @return void
354
         */
355
        protected function add_root_menu( WP_Admin_Bar $wp_admin_bar ) {
×
356
                $title = $this->get_title();
×
357

358
                $score              = '';
×
359
                $settings_url       = '';
×
360
                $counter            = '';
×
361
                $notification_popup = '';
×
362
                $notification_count = 0;
×
363

364
                $post = $this->get_singular_post();
×
365
                if ( $post ) {
×
366
                        $score = $this->get_post_score( $post );
×
367
                }
368

369
                $term = $this->get_singular_term();
×
370
                if ( $term ) {
×
371
                        $score = $this->get_term_score( $term );
×
372
                }
373

374
                $can_manage_options = $this->can_manage_options();
×
375

376
                if ( $can_manage_options ) {
×
377
                        $settings_url = $this->get_settings_page_url();
×
378
                }
379

380
                if ( empty( $score ) && ! is_network_admin() && $can_manage_options ) {
×
381
                        $notification_center = Yoast_Notification_Center::get();
×
382
                        $notification_count  = $notification_center->get_notification_count();
×
383

384
                        $counter            = $this->get_notification_counter( $notification_count );
×
385
                        $notification_popup = $this->get_notification_popup();
×
386
                }
387

388
                $admin_bar_menu_args = [
×
389
                        'id'    => self::MENU_IDENTIFIER,
×
390
                        'title' => $title . $score . $counter . $notification_popup,
×
391
                        'href'  => $settings_url,
×
392
                        'meta'  => [ 'tabindex' => ! empty( $settings_url ) ? false : '0' ],
×
393
                ];
×
394
                $wp_admin_bar->add_menu( $admin_bar_menu_args );
×
395

396
                if ( $notification_count > 0 ) {
×
397
                        $admin_bar_menu_args = [
×
398
                                'parent' => self::MENU_IDENTIFIER,
×
399
                                'id'     => 'wpseo-notifications',
×
400
                                'title'  => __( 'Notifications', 'wordpress-seo' ) . $counter,
×
401
                                'href'   => empty( $settings_url ) ? '' : $settings_url . '#/alert-center',
×
402
                                'meta'   => [ 'tabindex' => ! empty( $settings_url ) ? false : '0' ],
×
403
                        ];
×
404
                        $wp_admin_bar->add_menu( $admin_bar_menu_args );
×
405
                }
406
        }
407

408
        /**
409
         * Adds the admin bar analysis submenu.
410
         *
411
         * @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
412
         *
413
         * @return void
414
         */
415
        protected function add_analysis_submenu( WP_Admin_Bar $wp_admin_bar ) {
×
416
                try {
417
                        $url = YoastSEO()->meta->for_current_page()->canonical;
×
418
                } catch ( Exception $e ) {
×
419
                        // This is not the type of error we can handle here.
420
                        return;
×
421
                }
422

423
                if ( ! $url ) {
×
424
                        return;
×
425
                }
426

427
                $menu_args = [
×
428
                        'parent' => self::MENU_IDENTIFIER,
×
429
                        'id'     => self::ANALYSIS_SUBMENU_IDENTIFIER,
×
430
                        'title'  => __( 'Analyze this page', 'wordpress-seo' ),
×
431
                        'meta'   => [ 'tabindex' => '0' ],
×
432
                ];
×
433
                $wp_admin_bar->add_menu( $menu_args );
×
434

435
                $encoded_url   = rawurlencode( $url );
×
436
                $submenu_items = [
×
437
                        [
×
438
                                'id'    => 'wpseo-inlinks',
×
439
                                'title' => __( 'Check links to this URL', 'wordpress-seo' ),
×
440
                                'href'  => 'https://search.google.com/search-console/links/drilldown?resource_id=' . rawurlencode( get_option( 'siteurl' ) ) . '&type=EXTERNAL&target=' . $encoded_url . '&domain=',
×
441
                        ],
×
442
                        [
×
443
                                'id'    => 'wpseo-structureddata',
×
444
                                'title' => __( 'Google Rich Results Test', 'wordpress-seo' ),
×
445
                                'href'  => 'https://search.google.com/test/rich-results?url=' . $encoded_url,
×
446
                        ],
×
447
                        [
×
448
                                'id'    => 'wpseo-facebookdebug',
×
449
                                'title' => __( 'Facebook Debugger', 'wordpress-seo' ),
×
450
                                'href'  => '//developers.facebook.com/tools/debug/?q=' . $encoded_url,
×
451
                        ],
×
452
                        [
×
453
                                'id'    => 'wpseo-pagespeed',
×
454
                                'title' => __( 'Google Page Speed Test', 'wordpress-seo' ),
×
455
                                'href'  => '//developers.google.com/speed/pagespeed/insights/?url=' . $encoded_url,
×
456
                        ],
×
457
                ];
×
458

459
                $this->add_submenu_items( $submenu_items, $wp_admin_bar, self::ANALYSIS_SUBMENU_IDENTIFIER );
×
460
        }
461

462
        /**
463
         * Adds the admin bar tools submenu.
464
         *
465
         * @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
466
         *
467
         * @return void
468
         */
469
        protected function add_seo_tools_submenu( WP_Admin_Bar $wp_admin_bar ) {
×
470
                $menu_args = [
×
471
                        'parent' => self::MENU_IDENTIFIER,
×
472
                        'id'     => 'wpseo-sub-tools',
×
473
                        'title'  => __( 'SEO Tools', 'wordpress-seo' ),
×
474
                        'meta'   => [ 'tabindex' => '0' ],
×
475
                ];
×
476
                $wp_admin_bar->add_menu( $menu_args );
×
477

478
                $submenu_items = [
×
479
                        [
×
480
                                'id'    => 'wpseo-semrush',
×
481
                                'title' => 'Semrush',
×
482
                                'href'  => $this->shortlinker->build_shortlink( 'https://yoa.st/admin-bar-semrush' ),
×
483
                        ],
×
484
                        [
×
485
                                'id'    => 'wpseo-wincher',
×
486
                                'title' => 'Wincher',
×
487
                                'href'  => $this->shortlinker->build_shortlink( 'https://yoa.st/admin-bar-wincher' ),
×
488
                        ],
×
489
                        [
×
490
                                'id'    => 'wpseo-google-trends',
×
491
                                'title' => 'Google trends',
×
492
                                'href'  => $this->shortlinker->build_shortlink( 'https://yoa.st/admin-bar-gtrends' ),
×
493
                        ],
×
494
                ];
×
495

496
                $this->add_submenu_items( $submenu_items, $wp_admin_bar, 'wpseo-sub-tools' );
×
497
        }
498

499
        /**
500
         * Adds the admin bar How To submenu.
501
         *
502
         * @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
503
         *
504
         * @return void
505
         */
506
        protected function add_how_to_submenu( WP_Admin_Bar $wp_admin_bar ) {
×
507
                $menu_args = [
×
508
                        'parent' => self::MENU_IDENTIFIER,
×
509
                        'id'     => 'wpseo-sub-howto',
×
510
                        'title'  => __( 'How to', 'wordpress-seo' ),
×
511
                        'meta'   => [ 'tabindex' => '0' ],
×
512
                ];
×
513
                $wp_admin_bar->add_menu( $menu_args );
×
514

515
                $submenu_items = [
×
516
                        [
×
517
                                'id'    => 'wpseo-learn-seo',
×
518
                                'title' => __( 'Learn more SEO', 'wordpress-seo' ),
×
519
                                'href'  => $this->shortlinker->build_shortlink( 'https://yoa.st/admin-bar-learn-more-seo' ),
×
520
                        ],
×
521
                        [
×
522
                                'id'    => 'wpseo-improve-blogpost',
×
523
                                'title' => __( 'Improve your blog post', 'wordpress-seo' ),
×
524
                                'href'  => $this->shortlinker->build_shortlink( 'https://yoa.st/admin-bar-improve-blog-post' ),
×
525
                        ],
×
526
                        [
×
527
                                'id'    => 'wpseo-write-better-content',
×
528
                                'title' => __( 'Write better content', 'wordpress-seo' ),
×
529
                                'href'  => $this->shortlinker->build_shortlink( 'https://yoa.st/admin-bar-write-better' ),
×
530
                        ],
×
531
                ];
×
532

533
                $this->add_submenu_items( $submenu_items, $wp_admin_bar, 'wpseo-sub-howto' );
×
534
        }
535

536
        /**
537
         * Adds the admin bar How To submenu.
538
         *
539
         * @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
540
         *
541
         * @return void
542
         */
543
        protected function add_get_help_submenu( WP_Admin_Bar $wp_admin_bar ) {
×
544
                $menu_args = [
×
545
                        'parent' => self::MENU_IDENTIFIER,
×
546
                        'id'     => 'wpseo-sub-get-help',
×
547
                        'title'  => __( 'Help', 'wordpress-seo' ),
×
548
                        'meta'   => [ 'tabindex' => '0' ],
×
549
                ];
×
550

551
                if ( current_user_can( Support_Integration::CAPABILITY ) ) {
×
552
                        $menu_args['href'] = admin_url( 'admin.php?page=' . Support_Integration::PAGE );
×
553
                        $wp_admin_bar->add_menu( $menu_args );
×
554

555
                        return;
×
556
                }
557
                $wp_admin_bar->add_menu( $menu_args );
×
558

559
                $submenu_items = [
×
560
                        [
×
561
                                'id'    => 'wpseo-yoast-help',
×
562
                                'title' => __( 'Yoast.com help section', 'wordpress-seo' ),
×
563
                                'href'  => $this->shortlinker->build_shortlink( 'https://yoa.st/admin-bar-yoast-help' ),
×
564
                        ],
×
565
                        [
×
566
                                'id'    => 'wpseo-premium-support',
×
567
                                'title' => __( 'Yoast Premium support', 'wordpress-seo' ),
×
568
                                'href'  => $this->shortlinker->build_shortlink( 'https://yoa.st/admin-bar-premium-support' ),
×
569
                        ],
×
570
                        [
×
571
                                'id'    => 'wpseo-wp-support-forums',
×
572
                                'title' => __( 'WordPress.org support forums', 'wordpress-seo' ),
×
573
                                'href'  => $this->shortlinker->build_shortlink( 'https://yoa.st/admin-bar-wp-support-forums' ),
×
574
                        ],
×
575
                        [
×
576
                                'id'    => 'wpseo-learn-seo-2',
×
577
                                'title' => __( 'Learn more SEO', 'wordpress-seo' ),
×
578
                                'href'  => $this->shortlinker->build_shortlink( 'https://yoa.st/admin-bar-learn-more-seo-help' ),
×
579
                        ],
×
580
                ];
×
581

582
                $this->add_submenu_items( $submenu_items, $wp_admin_bar, 'wpseo-sub-get-help' );
×
583
        }
584

585
        /**
586
         * Adds the admin bar How To submenu.
587
         *
588
         * @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
589
         *
590
         * @return void
591
         */
592
        protected function add_premium_link( WP_Admin_Bar $wp_admin_bar ) {
×
NEW
593
                if ( ! function_exists( 'is_plugin_active' ) ) {
×
NEW
594
                        require_once ABSPATH . 'wp-admin/includes/plugin.php';
×
595
                }
596

597
                // Check if the Yoast SEO WooCommerce addon is active.
NEW
598
                $woo_seo_plugin_active = is_plugin_active( 'wpseo-woocommerce/wpseo-woocommerce.php' );
×
599

600
                // Don't show the Upgrade button if Yoast SEO WooCommerce addon is active.
NEW
601
                if ( $woo_seo_plugin_active ) {
×
NEW
602
                        return;
×
603
                }
604

UNCOV
605
                $has_woocommerce = ( new Woocommerce_Conditional() )->is_met();
×
606

607
                // Don't show the Upgrade button if Premium is active without the WooCommerce plugin.
NEW
608
                if ( $this->product_helper->is_premium() && ! $has_woocommerce ) {
×
NEW
609
                        return;
×
610
                }
611

NEW
612
                $link = $this->shortlinker->build_shortlink( 'https://yoa.st/admin-bar-get-premium' );
×
613

NEW
614
                if ( $this->product_helper->is_premium() && $has_woocommerce ) {
×
NEW
615
                        $link = $this->shortlinker->build_shortlink( 'https://yoa.st/admin-bar-get-premium-woocommerce' );
×
616
                }
617
                elseif ( $has_woocommerce ) {
×
618
                        $link = $this->shortlinker->build_shortlink( 'https://yoa.st/admin-bar-get-premium-woocommerce' );
×
619
                }
620

621
                $button_label = esc_html__( 'Upgrade', 'wordpress-seo' );
×
622

623
                if ( YoastSEO()->classes->get( Promotion_Manager::class )->is( 'black-friday-promotion' ) ) {
×
624
                        $button_label = esc_html__( '30% off - BF Sale', 'wordpress-seo' );
×
625
                }
626
                $wp_admin_bar->add_menu(
×
627
                        [
×
628
                                'parent' => self::MENU_IDENTIFIER,
×
629
                                'id'     => 'wpseo-get-premium',
×
630
                                // Circumvent an issue in the WP admin bar API in order to pass `data` attributes. See https://core.trac.wordpress.org/ticket/38636.
631
                                'title'  => sprintf(
×
NEW
632
                                        '<a href="%1$s" target="_blank" data-action="load-nfd-ctb" data-ctb-id="f6a84663-465f-4cb5-8ba5-f7a6d72224b2">%2$s</a>',
×
633
                                        esc_url( $link ),
×
NEW
634
                                        $button_label
×
635
                                ),
×
636
                                'meta'   => [
×
637
                                        'tabindex' => '0',
×
638
                                ],
×
639
                        ]
×
640
                );
×
641
        }
642

643
        /**
644
         * Adds the Brand Insights link to the admin bar.
645
         *
646
         * @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
647
         *
648
         * @return void
649
         */
NEW
650
        protected function add_brand_insights_link( WP_Admin_Bar $wp_admin_bar ) {
×
NEW
651
                $page = $this->product_helper->is_premium() ? 'wpseo_brand_insights_premium' : 'wpseo_brand_insights';
×
652

NEW
653
                $external_link_icon = '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" style="width: 16px; height: 16px; display: inline-block; vertical-align: middle; margin-left: 4px;"><path stroke-linecap="round" stroke-linejoin="round" d="M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25" /></svg>';
×
NEW
654
                $menu_title         = '<span class="yoast-brand-insights-gradient-border"><span class="yoast-brand-insights-content">AI Brand Insights' . $external_link_icon . '</span></span>';
×
655

NEW
656
                $wp_admin_bar->add_menu(
×
NEW
657
                        [
×
NEW
658
                                'parent' => self::MENU_IDENTIFIER,
×
NEW
659
                                'id'     => $page,
×
NEW
660
                                'title'  => $menu_title,
×
NEW
661
                                'href'   => admin_url( 'admin.php?page=' . $page ),
×
NEW
662
                                'meta'   => [
×
NEW
663
                                        'tabindex' => '0',
×
NEW
664
                                        'target'   => '_blank',
×
NEW
665
                                ],
×
NEW
666
                        ]
×
NEW
667
                );
×
668
        }
669

670
        /**
671
         * Adds the admin bar settings submenu.
672
         *
673
         * @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
674
         *
675
         * @return void
676
         */
677
        protected function add_settings_submenu( WP_Admin_Bar $wp_admin_bar ) {
×
678
                if ( ! $this->can_manage_options() ) {
×
679
                        return;
×
680
                }
681

682
                $admin_menu    = new WPSEO_Admin_Menu( new WPSEO_Menu() );
×
683
                $submenu_pages = $admin_menu->get_submenu_pages();
×
684

685
                $menu_args = [
×
686
                        'parent' => self::MENU_IDENTIFIER,
×
687
                        'id'     => self::SETTINGS_SUBMENU_IDENTIFIER,
×
688
                        'title'  => __( 'SEO Settings', 'wordpress-seo' ),
×
689
                        'meta'   => [ 'tabindex' => '0' ],
×
690
                ];
×
691
                $wp_admin_bar->add_menu( $menu_args );
×
692

693
                foreach ( $submenu_pages as $submenu_page ) {
×
694
                        if ( ! current_user_can( $submenu_page[3] ) ) {
×
695
                                continue;
×
696
                        }
697

698
                        // Don't add the Google Search Console menu item.
699
                        if ( $submenu_page[4] === 'wpseo_search_console' ) {
×
700
                                continue;
×
701
                        }
702

703
                        // Don't add the Brand Insights menu items (they're now in the main menu).
NEW
704
                        if ( $submenu_page[4] === 'wpseo_brand_insights' || $submenu_page[4] === 'wpseo_brand_insights_premium' ) {
×
NEW
705
                                continue;
×
706
                        }
707

708
                        $id = 'wpseo-' . str_replace( '_', '-', str_replace( 'wpseo_', '', $submenu_page[4] ) );
×
709
                        if ( $id === 'wpseo-dashboard' ) {
×
710
                                $id = 'wpseo-general';
×
711
                        }
712

713
                        $menu_args = [
×
714
                                'parent' => self::SETTINGS_SUBMENU_IDENTIFIER,
×
715
                                'id'     => $id,
×
716
                                'title'  => $submenu_page[2],
×
717
                                'href'   => admin_url( 'admin.php?page=' . rawurlencode( $submenu_page[4] ) ),
×
718
                        ];
×
719
                        $wp_admin_bar->add_menu( $menu_args );
×
720
                }
721
        }
722

723
        /**
724
         * Adds the admin bar network settings submenu.
725
         *
726
         * @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
727
         *
728
         * @return void
729
         */
730
        protected function add_network_settings_submenu( WP_Admin_Bar $wp_admin_bar ) {
×
731
                if ( ! $this->can_manage_options() ) {
×
732
                        return;
×
733
                }
734

735
                $network_admin_menu = new WPSEO_Network_Admin_Menu( new WPSEO_Menu() );
×
736
                $submenu_pages      = $network_admin_menu->get_submenu_pages();
×
737

738
                $menu_args = [
×
739
                        'parent' => self::MENU_IDENTIFIER,
×
740
                        'id'     => self::NETWORK_SETTINGS_SUBMENU_IDENTIFIER,
×
741
                        'title'  => __( 'SEO Settings', 'wordpress-seo' ),
×
742
                        'meta'   => [ 'tabindex' => '0' ],
×
743
                ];
×
744
                $wp_admin_bar->add_menu( $menu_args );
×
745

746
                foreach ( $submenu_pages as $submenu_page ) {
×
747
                        if ( ! current_user_can( $submenu_page[3] ) ) {
×
748
                                continue;
×
749
                        }
750

751
                        $id = 'wpseo-' . str_replace( '_', '-', str_replace( 'wpseo_', '', $submenu_page[4] ) );
×
752
                        if ( $id === 'wpseo-dashboard' ) {
×
753
                                $id = 'wpseo-general';
×
754
                        }
755

756
                        $menu_args = [
×
757
                                'parent' => self::NETWORK_SETTINGS_SUBMENU_IDENTIFIER,
×
758
                                'id'     => $id,
×
759
                                'title'  => $submenu_page[2],
×
760
                                'href'   => network_admin_url( 'admin.php?page=' . rawurlencode( $submenu_page[4] ) ),
×
761
                        ];
×
762
                        $wp_admin_bar->add_menu( $menu_args );
×
763
                }
764
        }
765

766
        /**
767
         * Gets the menu title markup.
768
         *
769
         * @return string Admin bar title markup.
770
         */
771
        protected function get_title() {
×
772
                return '<div id="yoast-ab-icon" class="ab-item yoast-logo svg"><span class="screen-reader-text">' . __( 'SEO', 'wordpress-seo' ) . '</span></div>';
×
773
        }
774

775
        /**
776
         * Gets the current post if in a singular post context.
777
         *
778
         * @global string       $pagenow Current page identifier.
779
         * @global WP_Post|null $post    Current post object, or null if none available.
780
         *
781
         * @return WP_Post|null Post object, or null if not in singular context.
782
         */
783
        protected function get_singular_post() {
×
784
                global $pagenow, $post;
×
785

786
                if ( ! is_singular() && ( ! is_blog_admin() || ! WPSEO_Metabox::is_post_edit( $pagenow ) ) ) {
×
787
                        return null;
×
788
                }
789

790
                if ( ! isset( $post ) || ! is_object( $post ) || ! $post instanceof WP_Post ) {
×
791
                        return null;
×
792
                }
793

794
                return $post;
×
795
        }
796

797
        /**
798
         * Gets the focus keyword for a given post.
799
         *
800
         * @param WP_Post $post Post object to get its focus keyword.
801
         *
802
         * @return string Focus keyword, or empty string if none available.
803
         */
804
        protected function get_post_focus_keyword( $post ) {
16✔
805
                if ( ! is_object( $post ) || ! property_exists( $post, 'ID' ) ) {
16✔
806
                        return '';
8✔
807
                }
808

809
                /**
810
                 * Filter: 'wpseo_use_page_analysis' Determines if the analysis should be enabled.
811
                 *
812
                 * @param bool $enabled Determines if the analysis should be enabled.
813
                 */
814
                if ( apply_filters( 'wpseo_use_page_analysis', true ) !== true ) {
8✔
815
                        return '';
4✔
816
                }
817

818
                return WPSEO_Meta::get_value( 'focuskw', $post->ID );
4✔
819
        }
820

821
        /**
822
         * Gets the score for a given post.
823
         *
824
         * @param WP_Post $post Post object to get its score.
825
         *
826
         * @return string Score markup, or empty string if none available.
827
         */
828
        protected function get_post_score( $post ) {
×
829
                if ( ! is_object( $post ) || ! property_exists( $post, 'ID' ) ) {
×
830
                        return '';
×
831
                }
832

833
                if ( apply_filters( 'wpseo_use_page_analysis', true ) !== true ) {
×
834
                        return '';
×
835
                }
836

837
                return $this->get_score_icon();
×
838
        }
839

840
        /**
841
         * Gets the current term if in a singular term context.
842
         *
843
         * @global string       $pagenow  Current page identifier.
844
         * @global WP_Query     $wp_query Current query object.
845
         * @global WP_Term|null $tag      Current term object, or null if none available.
846
         *
847
         * @return WP_Term|null Term object, or null if not in singular context.
848
         */
849
        protected function get_singular_term() {
×
850
                global $pagenow, $wp_query, $tag;
×
851

852
                if ( is_category() || is_tag() || is_tax() ) {
×
853
                        return $wp_query->get_queried_object();
×
854
                }
855

856
                if ( WPSEO_Taxonomy::is_term_edit( $pagenow ) && ! WPSEO_Taxonomy::is_term_overview( $pagenow ) && isset( $tag ) && is_object( $tag ) && ! is_wp_error( $tag ) ) {
×
857
                        return get_term( $tag->term_id );
×
858
                }
859

860
                return null;
×
861
        }
862

863
        /**
864
         * Gets the score for a given term.
865
         *
866
         * @param WP_Term $term Term object to get its score.
867
         *
868
         * @return string Score markup, or empty string if none available.
869
         */
870
        protected function get_term_score( $term ) {
×
871
                if ( ! is_object( $term ) || ! property_exists( $term, 'term_id' ) || ! property_exists( $term, 'taxonomy' ) ) {
×
872
                        return '';
×
873
                }
874

875
                return $this->get_score_icon();
×
876
        }
877

878
        /**
879
         * Create the score icon.
880
         *
881
         * @return string The score icon, or empty string.
882
         */
883
        protected function get_score_icon() {
×
884
                $is_seo_enabled         = $this->get_is_seo_enabled();
×
885
                $is_readability_enabled = $this->get_is_readability_enabled();
×
886

887
                $indexable = $this->get_current_indexable();
×
888

889
                if ( $is_seo_enabled ) {
×
890
                        return $this->score_icon_helper->for_seo( $indexable, 'adminbar-seo-score' )->present();
×
891
                }
892

893
                if ( $is_readability_enabled ) {
×
894
                        return $this->score_icon_helper->for_readability( $indexable->readability_score, 'adminbar-seo-score' )
×
895
                                ->present();
×
896
                }
897

898
                return '';
×
899
        }
900

901
        /**
902
         * Gets the URL to the main admin settings page.
903
         *
904
         * @return string Admin settings page URL.
905
         */
906
        protected function get_settings_page_url() {
×
907
                return self_admin_url( 'admin.php?page=' . WPSEO_Admin::PAGE_IDENTIFIER );
×
908
        }
909

910
        /**
911
         * Gets the notification counter if in a valid context.
912
         *
913
         * @param int $notification_count Number of notifications.
914
         *
915
         * @return string Notification counter markup, or empty string if not available.
916
         */
917
        protected function get_notification_counter( $notification_count ) {
×
918
                /* translators: Hidden accessibility text; %s: number of notifications. */
919
                $counter_screen_reader_text = sprintf( _n( '%s notification', '%s notifications', $notification_count, 'wordpress-seo' ), number_format_i18n( $notification_count ) );
×
920

921
                return sprintf(
×
922
                        ' <div class="wp-core-ui wp-ui-notification yoast-issue-counter%s"><span class="yoast-issues-count" aria-hidden="true">%d</span><span class="screen-reader-text">%s</span></div>',
×
923
                        ( $notification_count ) ? '' : ' wpseo-no-adminbar-notifications',
×
924
                        $notification_count,
×
925
                        $counter_screen_reader_text
×
926
                );
×
927
        }
928

929
        /**
930
         * Gets the notification popup if in a valid context.
931
         *
932
         * @return string Notification popup markup, or empty string if not available.
933
         */
934
        protected function get_notification_popup() {
×
935
                $notification_center     = Yoast_Notification_Center::get();
×
936
                $new_notifications       = $notification_center->get_new_notifications();
×
937
                $new_notifications_count = count( $new_notifications );
×
938

939
                if ( ! $new_notifications_count ) {
×
940
                        return '';
×
941
                }
942

943
                $notification = sprintf(
×
944
                        _n(
×
945
                                'There is a new notification.',
×
946
                                'There are new notifications.',
×
947
                                $new_notifications_count,
×
948
                                'wordpress-seo'
×
949
                        ),
×
950
                        $new_notifications_count
×
951
                );
×
952

953
                return '<div class="yoast-issue-added">' . $notification . '</div>';
×
954
        }
955

956
        /**
957
         * Checks whether the current user can manage options in the current context.
958
         *
959
         * @return bool True if capabilities are sufficient, false otherwise.
960
         */
961
        protected function can_manage_options() {
×
962
                return ( is_network_admin() && current_user_can( 'wpseo_manage_network_options' ) )
×
963
                        || ( ! is_network_admin() && WPSEO_Capability_Utils::current_user_can( 'wpseo_manage_options' ) );
×
964
        }
965

966
        /**
967
         * Add submenu items to a menu item.
968
         *
969
         * @param array<array{id: string, title: string, href: string}>  $submenu_items  Submenu items array.
970
         * @param WP_Admin_Bar                                           $wp_admin_bar  Admin bar object.
971
         * @param string                                                 $parent_id     Parent menu item ID.
972
         *
973
         * @return void
974
         */
975
        protected function add_submenu_items( array $submenu_items, WP_Admin_Bar $wp_admin_bar, $parent_id ) {
×
976
                foreach ( $submenu_items as $menu_item ) {
×
977
                        $menu_args = [
×
978
                                'parent' => $parent_id,
×
979
                                'id'     => $menu_item['id'],
×
980
                                'title'  => $menu_item['title'],
×
981
                                'href'   => $menu_item['href'],
×
982
                                'meta'   => [ 'target' => '_blank' ],
×
983
                        ];
×
984
                        $wp_admin_bar->add_menu( $menu_args );
×
985
                }
986
        }
987
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc