class-wpseo-admin-bar-menu.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  1. <?php
  2. /**
  3. * WPSEO plugin file.
  4. *
  5. * @package WPSEO
  6. */
  7. /**
  8. * Class for the Yoast SEO admin bar menu.
  9. */
  10. class WPSEO_Admin_Bar_Menu implements WPSEO_WordPress_Integration {
  11. /**
  12. * The identifier used for the menu.
  13. *
  14. * @var string
  15. */
  16. const MENU_IDENTIFIER = 'wpseo-menu';
  17. /**
  18. * The identifier used for the Keyword Research submenu.
  19. *
  20. * @var string
  21. */
  22. const KEYWORD_RESEARCH_SUBMENU_IDENTIFIER = 'wpseo-kwresearch';
  23. /**
  24. * The identifier used for the Analysis submenu.
  25. *
  26. * @var string
  27. */
  28. const ANALYSIS_SUBMENU_IDENTIFIER = 'wpseo-analysis';
  29. /**
  30. * The identifier used for the Settings submenu.
  31. *
  32. * @var string
  33. */
  34. const SETTINGS_SUBMENU_IDENTIFIER = 'wpseo-settings';
  35. /**
  36. * The identifier used for the Network Settings submenu.
  37. *
  38. * @var string
  39. */
  40. const NETWORK_SETTINGS_SUBMENU_IDENTIFIER = 'wpseo-network-settings';
  41. /**
  42. * Asset manager instance.
  43. *
  44. * @var WPSEO_Admin_Asset_Manager
  45. */
  46. protected $asset_manager;
  47. /**
  48. * Constructor.
  49. *
  50. * Sets the asset manager to use.
  51. *
  52. * @param WPSEO_Admin_Asset_Manager $asset_manager Optional. Asset manager to use.
  53. */
  54. public function __construct( WPSEO_Admin_Asset_Manager $asset_manager = null ) {
  55. if ( ! $asset_manager ) {
  56. $asset_manager = new WPSEO_Admin_Asset_Manager();
  57. }
  58. $this->asset_manager = $asset_manager;
  59. }
  60. /**
  61. * Adds the admin bar menu.
  62. *
  63. * @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
  64. *
  65. * @return void
  66. */
  67. public function add_menu( WP_Admin_Bar $wp_admin_bar ) {
  68. // If the current user can't write posts, this is all of no use, so let's not output an admin menu.
  69. if ( ! current_user_can( 'edit_posts' ) ) {
  70. return;
  71. }
  72. $this->add_root_menu( $wp_admin_bar );
  73. $this->add_keyword_research_submenu( $wp_admin_bar );
  74. if ( ! is_admin() ) {
  75. $this->add_analysis_submenu( $wp_admin_bar );
  76. }
  77. if ( ! is_admin() || is_blog_admin() ) {
  78. $this->add_settings_submenu( $wp_admin_bar );
  79. }
  80. elseif ( is_network_admin() ) {
  81. $this->add_network_settings_submenu( $wp_admin_bar );
  82. }
  83. }
  84. /**
  85. * Enqueues admin bar assets.
  86. *
  87. * @return void
  88. */
  89. public function enqueue_assets() {
  90. if ( ! is_admin_bar_showing() ) {
  91. return;
  92. }
  93. // If the current user can't write posts, this is all of no use, so let's not output an admin menu.
  94. if ( ! current_user_can( 'edit_posts' ) ) {
  95. return;
  96. }
  97. $this->asset_manager->register_assets();
  98. $this->asset_manager->enqueue_style( 'adminbar' );
  99. }
  100. /**
  101. * Registers the hooks.
  102. *
  103. * @return void
  104. */
  105. public function register_hooks() {
  106. if ( ! $this->meets_requirements() ) {
  107. return;
  108. }
  109. add_action( 'admin_bar_menu', [ $this, 'add_menu' ], 95 );
  110. add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_assets' ] );
  111. add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
  112. }
  113. /**
  114. * Checks whether the requirements to use this class are met.
  115. *
  116. * @return bool True if requirements are met, false otherwise.
  117. */
  118. public function meets_requirements() {
  119. if ( is_network_admin() ) {
  120. return WPSEO_Utils::is_plugin_network_active();
  121. }
  122. if ( WPSEO_Options::get( 'enable_admin_bar_menu' ) !== true ) {
  123. return false;
  124. }
  125. return ! is_admin() || is_blog_admin();
  126. }
  127. /**
  128. * Adds the admin bar root menu.
  129. *
  130. * @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
  131. *
  132. * @return void
  133. */
  134. protected function add_root_menu( WP_Admin_Bar $wp_admin_bar ) {
  135. $title = $this->get_title();
  136. $score = '';
  137. $settings_url = '';
  138. $counter = '';
  139. $alert_popup = '';
  140. $post = $this->get_singular_post();
  141. if ( $post ) {
  142. $score = $this->get_post_score( $post );
  143. }
  144. $term = $this->get_singular_term();
  145. if ( $term ) {
  146. $score = $this->get_term_score( $term );
  147. }
  148. $can_manage_options = $this->can_manage_options();
  149. if ( $can_manage_options ) {
  150. $settings_url = $this->get_settings_page_url();
  151. }
  152. if ( empty( $score ) && ! is_network_admin() && $can_manage_options ) {
  153. $counter = $this->get_notification_counter();
  154. $alert_popup = $this->get_notification_alert_popup();
  155. }
  156. $admin_bar_menu_args = [
  157. 'id' => self::MENU_IDENTIFIER,
  158. 'title' => $title . $score . $counter . $alert_popup,
  159. 'href' => $settings_url,
  160. 'meta' => [ 'tabindex' => ! empty( $settings_url ) ? false : '0' ],
  161. ];
  162. $wp_admin_bar->add_menu( $admin_bar_menu_args );
  163. if ( ! empty( $counter ) ) {
  164. $admin_bar_menu_args = [
  165. 'parent' => self::MENU_IDENTIFIER,
  166. 'id' => 'wpseo-notifications',
  167. 'title' => __( 'Notifications', 'wordpress-seo' ) . $counter,
  168. 'href' => $settings_url,
  169. 'meta' => [ 'tabindex' => ! empty( $settings_url ) ? false : '0' ],
  170. ];
  171. $wp_admin_bar->add_menu( $admin_bar_menu_args );
  172. }
  173. if ( ! is_network_admin() && $can_manage_options ) {
  174. $admin_bar_menu_args = [
  175. 'parent' => self::MENU_IDENTIFIER,
  176. 'id' => 'wpseo-configuration-wizard',
  177. 'title' => __( 'Configuration Wizard', 'wordpress-seo' ),
  178. 'href' => admin_url( 'admin.php?page=' . WPSEO_Configuration_Page::PAGE_IDENTIFIER ),
  179. ];
  180. $wp_admin_bar->add_menu( $admin_bar_menu_args );
  181. }
  182. }
  183. /**
  184. * Adds the admin bar keyword research submenu.
  185. *
  186. * @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
  187. *
  188. * @return void
  189. */
  190. protected function add_keyword_research_submenu( WP_Admin_Bar $wp_admin_bar ) {
  191. $adwords_url = 'https://yoa.st/keywordplanner';
  192. $trends_url = 'https://yoa.st/google-trends';
  193. $post = $this->get_singular_post();
  194. if ( $post ) {
  195. $focus_keyword = $this->get_post_focus_keyword( $post );
  196. if ( ! empty( $focus_keyword ) ) {
  197. $trends_url .= '#q=' . urlencode( $focus_keyword );
  198. }
  199. }
  200. $menu_args = [
  201. 'parent' => self::MENU_IDENTIFIER,
  202. 'id' => self::KEYWORD_RESEARCH_SUBMENU_IDENTIFIER,
  203. 'title' => __( 'Keyword Research', 'wordpress-seo' ),
  204. 'meta' => [ 'tabindex' => '0' ],
  205. ];
  206. $wp_admin_bar->add_menu( $menu_args );
  207. $submenu_items = [
  208. [
  209. 'id' => 'wpseo-kwresearchtraining',
  210. 'title' => __( 'Keyword research training', 'wordpress-seo' ),
  211. 'href' => WPSEO_Shortlinker::get( 'https://yoa.st/wp-admin-bar' ),
  212. ],
  213. [
  214. 'id' => 'wpseo-adwordsexternal',
  215. 'title' => __( 'Google Ads', 'wordpress-seo' ),
  216. 'href' => $adwords_url,
  217. ],
  218. [
  219. 'id' => 'wpseo-googleinsights',
  220. 'title' => __( 'Google Trends', 'wordpress-seo' ),
  221. 'href' => $trends_url,
  222. ],
  223. ];
  224. foreach ( $submenu_items as $menu_item ) {
  225. $menu_args = [
  226. 'parent' => self::KEYWORD_RESEARCH_SUBMENU_IDENTIFIER,
  227. 'id' => $menu_item['id'],
  228. 'title' => $menu_item['title'],
  229. 'href' => $menu_item['href'],
  230. 'meta' => [ 'target' => '_blank' ],
  231. ];
  232. $wp_admin_bar->add_menu( $menu_args );
  233. }
  234. }
  235. /**
  236. * Adds the admin bar analysis submenu.
  237. *
  238. * @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
  239. *
  240. * @return void
  241. */
  242. protected function add_analysis_submenu( WP_Admin_Bar $wp_admin_bar ) {
  243. $url = WPSEO_Frontend::get_instance()->canonical( false );
  244. $focus_keyword = '';
  245. if ( ! $url ) {
  246. return;
  247. }
  248. $post = $this->get_singular_post();
  249. if ( $post ) {
  250. $focus_keyword = $this->get_post_focus_keyword( $post );
  251. }
  252. $menu_args = [
  253. 'parent' => self::MENU_IDENTIFIER,
  254. 'id' => self::ANALYSIS_SUBMENU_IDENTIFIER,
  255. 'title' => __( 'Analyze this page', 'wordpress-seo' ),
  256. 'meta' => [ 'tabindex' => '0' ],
  257. ];
  258. $wp_admin_bar->add_menu( $menu_args );
  259. $encoded_url = urlencode( $url );
  260. $submenu_items = [
  261. [
  262. 'id' => 'wpseo-inlinks',
  263. 'title' => __( 'Check links to this URL', 'wordpress-seo' ),
  264. 'href' => 'https://search.google.com/search-console/links/drilldown?resource_id=' . urlencode( get_option( 'siteurl' ) ) . '&type=EXTERNAL&target=' . $encoded_url . '&domain=',
  265. ],
  266. [
  267. 'id' => 'wpseo-kwdensity',
  268. 'title' => __( 'Check Keyphrase Density', 'wordpress-seo' ),
  269. // HTTPS not available.
  270. 'href' => 'http://www.zippy.co.uk/keyworddensity/index.php?url=' . $encoded_url . '&keyword=' . urlencode( $focus_keyword ),
  271. ],
  272. [
  273. 'id' => 'wpseo-cache',
  274. 'title' => __( 'Check Google Cache', 'wordpress-seo' ),
  275. 'href' => '//webcache.googleusercontent.com/search?strip=1&q=cache:' . $encoded_url,
  276. ],
  277. [
  278. 'id' => 'wpseo-header',
  279. 'title' => __( 'Check Headers', 'wordpress-seo' ),
  280. 'href' => '//quixapp.com/headers/?r=' . urlencode( $url ),
  281. ],
  282. [
  283. 'id' => 'wpseo-structureddata',
  284. 'title' => __( 'Google Structured Data Test', 'wordpress-seo' ),
  285. 'href' => 'https://search.google.com/structured-data/testing-tool#url=' . $encoded_url,
  286. ],
  287. [
  288. 'id' => 'wpseo-facebookdebug',
  289. 'title' => __( 'Facebook Debugger', 'wordpress-seo' ),
  290. 'href' => '//developers.facebook.com/tools/debug/og/object?q=' . $encoded_url,
  291. ],
  292. [
  293. 'id' => 'wpseo-pinterestvalidator',
  294. 'title' => __( 'Pinterest Rich Pins Validator', 'wordpress-seo' ),
  295. 'href' => 'https://developers.pinterest.com/tools/url-debugger/?link=' . $encoded_url,
  296. ],
  297. [
  298. 'id' => 'wpseo-htmlvalidation',
  299. 'title' => __( 'HTML Validator', 'wordpress-seo' ),
  300. 'href' => '//validator.w3.org/check?uri=' . $encoded_url,
  301. ],
  302. [
  303. 'id' => 'wpseo-cssvalidation',
  304. 'title' => __( 'CSS Validator', 'wordpress-seo' ),
  305. 'href' => '//jigsaw.w3.org/css-validator/validator?uri=' . $encoded_url,
  306. ],
  307. [
  308. 'id' => 'wpseo-pagespeed',
  309. 'title' => __( 'Google Page Speed Test', 'wordpress-seo' ),
  310. 'href' => '//developers.google.com/speed/pagespeed/insights/?url=' . $encoded_url,
  311. ],
  312. [
  313. 'id' => 'wpseo-google-mobile-friendly',
  314. 'title' => __( 'Mobile-Friendly Test', 'wordpress-seo' ),
  315. 'href' => 'https://www.google.com/webmasters/tools/mobile-friendly/?url=' . $encoded_url,
  316. ],
  317. ];
  318. foreach ( $submenu_items as $menu_item ) {
  319. $menu_args = [
  320. 'parent' => self::ANALYSIS_SUBMENU_IDENTIFIER,
  321. 'id' => $menu_item['id'],
  322. 'title' => $menu_item['title'],
  323. 'href' => $menu_item['href'],
  324. 'meta' => [ 'target' => '_blank' ],
  325. ];
  326. $wp_admin_bar->add_menu( $menu_args );
  327. }
  328. }
  329. /**
  330. * Adds the admin bar settings submenu.
  331. *
  332. * @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
  333. *
  334. * @return void
  335. */
  336. protected function add_settings_submenu( WP_Admin_Bar $wp_admin_bar ) {
  337. if ( ! $this->can_manage_options() ) {
  338. return;
  339. }
  340. $admin_menu = new WPSEO_Admin_Menu( new WPSEO_Menu() );
  341. $submenu_pages = $admin_menu->get_submenu_pages();
  342. $menu_args = [
  343. 'parent' => self::MENU_IDENTIFIER,
  344. 'id' => self::SETTINGS_SUBMENU_IDENTIFIER,
  345. 'title' => __( 'SEO Settings', 'wordpress-seo' ),
  346. 'meta' => [ 'tabindex' => '0' ],
  347. ];
  348. $wp_admin_bar->add_menu( $menu_args );
  349. foreach ( $submenu_pages as $submenu_page ) {
  350. if ( ! current_user_can( $submenu_page[3] ) ) {
  351. continue;
  352. }
  353. $id = 'wpseo-' . str_replace( '_', '-', str_replace( 'wpseo_', '', $submenu_page[4] ) );
  354. if ( $id === 'wpseo-dashboard' ) {
  355. $id = 'wpseo-general';
  356. }
  357. $menu_args = [
  358. 'parent' => self::SETTINGS_SUBMENU_IDENTIFIER,
  359. 'id' => $id,
  360. 'title' => $submenu_page[2],
  361. 'href' => admin_url( 'admin.php?page=' . urlencode( $submenu_page[4] ) ),
  362. ];
  363. $wp_admin_bar->add_menu( $menu_args );
  364. }
  365. }
  366. /**
  367. * Adds the admin bar network settings submenu.
  368. *
  369. * @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
  370. *
  371. * @return void
  372. */
  373. protected function add_network_settings_submenu( WP_Admin_Bar $wp_admin_bar ) {
  374. if ( ! $this->can_manage_options() ) {
  375. return;
  376. }
  377. $network_admin_menu = new WPSEO_Network_Admin_Menu( new WPSEO_Menu() );
  378. $submenu_pages = $network_admin_menu->get_submenu_pages();
  379. $menu_args = [
  380. 'parent' => self::MENU_IDENTIFIER,
  381. 'id' => self::NETWORK_SETTINGS_SUBMENU_IDENTIFIER,
  382. 'title' => __( 'SEO Settings', 'wordpress-seo' ),
  383. 'meta' => [ 'tabindex' => '0' ],
  384. ];
  385. $wp_admin_bar->add_menu( $menu_args );
  386. foreach ( $submenu_pages as $submenu_page ) {
  387. if ( ! current_user_can( $submenu_page[3] ) ) {
  388. continue;
  389. }
  390. $id = 'wpseo-' . str_replace( '_', '-', str_replace( 'wpseo_', '', $submenu_page[4] ) );
  391. if ( $id === 'wpseo-dashboard' ) {
  392. $id = 'wpseo-general';
  393. }
  394. $menu_args = [
  395. 'parent' => self::NETWORK_SETTINGS_SUBMENU_IDENTIFIER,
  396. 'id' => $id,
  397. 'title' => $submenu_page[2],
  398. 'href' => network_admin_url( 'admin.php?page=' . urlencode( $submenu_page[4] ) ),
  399. ];
  400. $wp_admin_bar->add_menu( $menu_args );
  401. }
  402. }
  403. /**
  404. * Gets the menu title markup.
  405. *
  406. * @return string Admin bar title markup.
  407. */
  408. protected function get_title() {
  409. return '<div id="yoast-ab-icon" class="ab-item yoast-logo svg"><span class="screen-reader-text">' . __( 'SEO', 'wordpress-seo' ) . '</span></div>';
  410. }
  411. /**
  412. * Gets the current post if in a singular post context.
  413. *
  414. * @global string $pagenow Current page identifier.
  415. * @global WP_Post|null $post Current post object, or null if none available.
  416. *
  417. * @return WP_Post|null Post object, or null if not in singular context.
  418. */
  419. protected function get_singular_post() {
  420. global $pagenow, $post;
  421. if ( ! is_singular() && ( ! is_blog_admin() || ! WPSEO_Metabox::is_post_edit( $pagenow ) ) ) {
  422. return null;
  423. }
  424. if ( ! isset( $post ) || ! is_object( $post ) || ! $post instanceof WP_Post ) {
  425. return null;
  426. }
  427. return $post;
  428. }
  429. /**
  430. * Gets the focus keyword for a given post.
  431. *
  432. * @param WP_Post $post Post object to get its focus keyword.
  433. *
  434. * @return string Focus keyword, or empty string if none available.
  435. */
  436. protected function get_post_focus_keyword( $post ) {
  437. if ( ! is_object( $post ) || ! property_exists( $post, 'ID' ) ) {
  438. return '';
  439. }
  440. /**
  441. * Filter: 'wpseo_use_page_analysis' Determines if the analysis should be enabled.
  442. *
  443. * @api bool Determines if the analysis should be enabled.
  444. */
  445. if ( apply_filters( 'wpseo_use_page_analysis', true ) !== true ) {
  446. return '';
  447. }
  448. return WPSEO_Meta::get_value( 'focuskw', $post->ID );
  449. }
  450. /**
  451. * Gets the score for a given post.
  452. *
  453. * @param WP_Post $post Post object to get its score.
  454. *
  455. * @return string Score markup, or empty string if none available.
  456. */
  457. protected function get_post_score( $post ) {
  458. if ( ! is_object( $post ) || ! property_exists( $post, 'ID' ) ) {
  459. return '';
  460. }
  461. if ( apply_filters( 'wpseo_use_page_analysis', true ) !== true ) {
  462. return '';
  463. }
  464. $analysis_seo = new WPSEO_Metabox_Analysis_SEO();
  465. $analysis_readability = new WPSEO_Metabox_Analysis_Readability();
  466. if ( $analysis_seo->is_enabled() ) {
  467. return $this->get_score( WPSEO_Meta::get_value( 'linkdex', $post->ID ) );
  468. }
  469. if ( $analysis_readability->is_enabled() ) {
  470. return $this->get_score( WPSEO_Meta::get_value( 'content_score', $post->ID ) );
  471. }
  472. return '';
  473. }
  474. /**
  475. * Gets the current term if in a singular term context.
  476. *
  477. * @global string $pagenow Current page identifier.
  478. * @global WP_Query $wp_query Current query object.
  479. * @global WP_Term|null $tag Current term object, or null if none available.
  480. *
  481. * @return WP_Term|null Term object, or null if not in singular context.
  482. */
  483. protected function get_singular_term() {
  484. global $pagenow, $wp_query, $tag;
  485. if ( is_category() || is_tag() || is_tax() ) {
  486. return $wp_query->get_queried_object();
  487. }
  488. if ( WPSEO_Taxonomy::is_term_edit( $pagenow ) && ! WPSEO_Taxonomy::is_term_overview( $pagenow ) && isset( $tag ) && is_object( $tag ) && ! is_wp_error( $tag ) ) {
  489. return get_term( $tag->term_id );
  490. }
  491. return null;
  492. }
  493. /**
  494. * Gets the score for a given term.
  495. *
  496. * @param WP_Term $term Term object to get its score.
  497. *
  498. * @return string Score markup, or empty string if none available.
  499. */
  500. protected function get_term_score( $term ) {
  501. if ( ! is_object( $term ) || ! property_exists( $term, 'term_id' ) || ! property_exists( $term, 'taxonomy' ) ) {
  502. return '';
  503. }
  504. $analysis_seo = new WPSEO_Metabox_Analysis_SEO();
  505. $analysis_readability = new WPSEO_Metabox_Analysis_Readability();
  506. if ( $analysis_seo->is_enabled() ) {
  507. return $this->get_score( WPSEO_Taxonomy_Meta::get_term_meta( $term->term_id, $term->taxonomy, 'linkdex' ) );
  508. }
  509. if ( $analysis_readability->is_enabled() ) {
  510. return $this->get_score( WPSEO_Taxonomy_Meta::get_term_meta( $term->term_id, $term->taxonomy, 'content_score' ) );
  511. }
  512. return '';
  513. }
  514. /**
  515. * Takes the SEO score and makes the score icon for the admin bar for it.
  516. *
  517. * @param int $score The 0-100 rating of the score. Can be either SEO score or content score.
  518. *
  519. * @return string Score markup.
  520. */
  521. protected function get_score( $score ) {
  522. $score_class = WPSEO_Utils::translate_score( $score );
  523. $translated_score = WPSEO_Utils::translate_score( $score, false );
  524. /* translators: %s expands to the SEO score. */
  525. $screen_reader_text = sprintf( __( 'SEO score: %s', 'wordpress-seo' ), $translated_score );
  526. $score_adminbar_element = '<div class="wpseo-score-icon adminbar-seo-score ' . $score_class . '"><span class="adminbar-seo-score-text screen-reader-text">' . $screen_reader_text . '</span></div>';
  527. return $score_adminbar_element;
  528. }
  529. /**
  530. * Gets the URL to the main admin settings page.
  531. *
  532. * @return string Admin settings page URL.
  533. */
  534. protected function get_settings_page_url() {
  535. return self_admin_url( 'admin.php?page=' . WPSEO_Admin::PAGE_IDENTIFIER );
  536. }
  537. /**
  538. * Gets the notification counter if in a valid context.
  539. *
  540. * @return string Notification counter markup, or empty string if not available.
  541. */
  542. protected function get_notification_counter() {
  543. $notification_center = Yoast_Notification_Center::get();
  544. $notification_count = $notification_center->get_notification_count();
  545. if ( ! $notification_count ) {
  546. return '';
  547. }
  548. /* translators: %s: number of notifications */
  549. $counter_screen_reader_text = sprintf( _n( '%s notification', '%s notifications', $notification_count, 'wordpress-seo' ), number_format_i18n( $notification_count ) );
  550. return sprintf( ' <div class="wp-core-ui wp-ui-notification yoast-issue-counter"><span aria-hidden="true">%d</span><span class="screen-reader-text">%s</span></div>', $notification_count, $counter_screen_reader_text );
  551. }
  552. /**
  553. * Gets the notification alert popup if in a valid context.
  554. *
  555. * @return string Notification alert popup markup, or empty string if not available.
  556. */
  557. protected function get_notification_alert_popup() {
  558. $notification_center = Yoast_Notification_Center::get();
  559. $new_notifications = $notification_center->get_new_notifications();
  560. $new_notifications_count = count( $new_notifications );
  561. if ( ! $new_notifications_count ) {
  562. return '';
  563. }
  564. $notification = sprintf(
  565. _n(
  566. 'There is a new notification.',
  567. 'There are new notifications.',
  568. $new_notifications_count,
  569. 'wordpress-seo'
  570. ),
  571. $new_notifications_count
  572. );
  573. return '<div class="yoast-issue-added">' . $notification . '</div>';
  574. }
  575. /**
  576. * Checks whether the current user can manage options in the current context.
  577. *
  578. * @return bool True if capabilities are sufficient, false otherwise.
  579. */
  580. protected function can_manage_options() {
  581. return is_network_admin() && current_user_can( 'wpseo_manage_network_options' ) || ! is_network_admin() && WPSEO_Capability_Utils::current_user_can( 'wpseo_manage_options' );
  582. }
  583. }