WPSEO_Metabox

This class generates the metabox on the edit post / page as well as contains all page analysis functionality.

Defined (1)

The class is defined in the following location(s).

/admin/metabox/class-metabox.php  
  1. class WPSEO_Metabox extends WPSEO_Meta { 
  2.  
  3. /** 
  4. * @var array 
  5. */ 
  6. private $options; 
  7.  
  8. /** 
  9. * @var WPSEO_Social_Admin 
  10. */ 
  11. protected $social_admin; 
  12.  
  13. /** 
  14. * @var WPSEO_Metabox_Analysis_SEO 
  15. */ 
  16. protected $analysis_seo; 
  17.  
  18. /** 
  19. * @var WPSEO_Metabox_Analysis_Readability 
  20. */ 
  21. protected $analysis_readability; 
  22.  
  23. /** 
  24. * Class constructor 
  25. */ 
  26. public function __construct() { 
  27. add_action( 'add_meta_boxes', array( $this, 'add_meta_box' ) ); 
  28. add_action( 'admin_enqueue_scripts', array( $this, 'enqueue' ) ); 
  29. add_action( 'wp_insert_post', array( $this, 'save_postdata' ) ); 
  30. add_action( 'edit_attachment', array( $this, 'save_postdata' ) ); 
  31. add_action( 'add_attachment', array( $this, 'save_postdata' ) ); 
  32. add_action( 'post_submitbox_start', array( $this, 'publish_box' ) ); 
  33. add_action( 'admin_init', array( $this, 'setup_page_analysis' ) ); 
  34. add_action( 'admin_init', array( $this, 'translate_meta_boxes' ) ); 
  35. add_action( 'admin_footer', array( $this, 'template_keyword_tab' ) ); 
  36. add_action( 'admin_footer', array( $this, 'template_generic_tab' ) ); 
  37.  
  38. $this->options = WPSEO_Options::get_options( array( 'wpseo', 'wpseo_social' ) ); 
  39.  
  40. // Check if one of the social settings is checked in the options, if so, initialize the social_admin object. 
  41. if ( $this->options['opengraph'] === true || $this->options['twitter'] === true ) { 
  42. $this->social_admin = new WPSEO_Social_Admin( $this->options ); 
  43.  
  44. $this->editor = new WPSEO_Metabox_Editor(); 
  45. $this->editor->register_hooks(); 
  46.  
  47. $this->analysis_seo = new WPSEO_Metabox_Analysis_SEO(); 
  48. $this->analysis_readability = new WPSEO_Metabox_Analysis_Readability(); 
  49.  
  50. /** 
  51. * Translate text strings for use in the meta box 
  52. * IMPORTANT: if you want to add a new string (option) somewhere, make sure you add that array key to 
  53. * the main meta box definition array in the class WPSEO_Meta() as well!!!! 
  54. */ 
  55. public static function translate_meta_boxes() { 
  56. self::$meta_fields['general']['snippetpreview']['title'] = __( 'Snippet editor', 'wordpress-seo' ); 
  57. /** translators: 1: link open tag; 2: link close tag. */ 
  58. self::$meta_fields['general']['snippetpreview']['help'] = sprintf( __( 'This is a rendering of what this post might look like in Google\'s search results. %1$sLearn more about the Snippet Preview%2$s.', 'wordpress-seo' ), '<a target="_blank" href="' . WPSEO_Shortlinker::get( 'https://yoa.st/snippet-preview' ) . '">', '</a>' ); 
  59. self::$meta_fields['general']['snippetpreview']['help-button'] = __( 'Show information about the snippet editor', 'wordpress-seo' ); 
  60.  
  61. self::$meta_fields['general']['pageanalysis']['title'] = __( 'Analysis', 'wordpress-seo' ); 
  62. /** translators: 1: link open tag; 2: link close tag. */ 
  63. self::$meta_fields['general']['pageanalysis']['help'] = sprintf( __( 'This is the content analysis, a collection of content checks that analyze the content of your page. %1$sLearn more about the Content Analysis Tool%2$s.', 'wordpress-seo' ), '<a target="_blank" href="' . WPSEO_Shortlinker::get( 'https://yoa.st/content-analysis' ) . '">', '</a>' ); 
  64. self::$meta_fields['general']['pageanalysis']['help-button'] = __( 'Show information about the content analysis', 'wordpress-seo' ); 
  65.  
  66. self::$meta_fields['general']['focuskw_text_input']['title'] = __( 'Focus keyword', 'wordpress-seo' ); 
  67. self::$meta_fields['general']['focuskw_text_input']['label'] = __( 'Enter a focus keyword', 'wordpress-seo' ); 
  68. /** translators: 1: link open tag; 2: link close tag. */ 
  69. self::$meta_fields['general']['focuskw_text_input']['help'] = sprintf( __( 'Pick the main keyword or keyphrase that this post/page is about. %1$sLearn more about the Focus Keyword%2$s.', 'wordpress-seo' ), '<a target="_blank" href="' . WPSEO_Shortlinker::get( 'https://yoa.st/focus-keyword' ) . '">', '</a>' ); 
  70. self::$meta_fields['general']['focuskw_text_input']['help-button'] = __( 'Show information about the focus keyword', 'wordpress-seo' ); 
  71.  
  72. self::$meta_fields['general']['title']['title'] = __( 'SEO title', 'wordpress-seo' ); 
  73.  
  74. self::$meta_fields['general']['metadesc']['title'] = __( 'Meta description', 'wordpress-seo' ); 
  75.  
  76. self::$meta_fields['general']['metakeywords']['title'] = __( 'Meta keywords', 'wordpress-seo' ); 
  77. self::$meta_fields['general']['metakeywords']['label'] = __( 'Enter the meta keywords', 'wordpress-seo' ); 
  78. /** translators: 1: link open tag; 2: link close tag. */ 
  79. self::$meta_fields['general']['metakeywords']['description'] = __( 'If you type something above it will override your %1$smeta keywords template%2$s.', 'wordpress-seo' ); 
  80.  
  81.  
  82. self::$meta_fields['advanced']['meta-robots-noindex']['title'] = __( 'Meta robots index', 'wordpress-seo' ); 
  83. if ( '0' == get_option( 'blog_public' ) ) { 
  84. self::$meta_fields['advanced']['meta-robots-noindex']['description'] = '<p class="error-message">' . __( 'Warning: even though you can set the meta robots setting here, the entire site is set to noindex in the sitewide privacy settings, so these settings won\'t have an effect.', 'wordpress-seo' ) . '</p>'; 
  85. self::$meta_fields['advanced']['meta-robots-noindex']['options']['0'] = __( 'Default for this post type, currently: %s', 'wordpress-seo' ); 
  86. self::$meta_fields['advanced']['meta-robots-noindex']['options']['2'] = 'index'; 
  87. self::$meta_fields['advanced']['meta-robots-noindex']['options']['1'] = 'noindex'; 
  88.  
  89. self::$meta_fields['advanced']['meta-robots-nofollow']['title'] = __( 'Meta robots follow', 'wordpress-seo' ); 
  90. self::$meta_fields['advanced']['meta-robots-nofollow']['options']['0'] = 'follow'; 
  91. self::$meta_fields['advanced']['meta-robots-nofollow']['options']['1'] = 'nofollow'; 
  92.  
  93. self::$meta_fields['advanced']['meta-robots-adv']['title'] = __( 'Meta robots advanced', 'wordpress-seo' ); 
  94. self::$meta_fields['advanced']['meta-robots-adv']['description'] = __( 'Advanced <code>meta</code> robots settings for this page.', 'wordpress-seo' ); 
  95. self::$meta_fields['advanced']['meta-robots-adv']['options']['-'] = __( 'Site-wide default: %s', 'wordpress-seo' ); 
  96. self::$meta_fields['advanced']['meta-robots-adv']['options']['none'] = __( 'None', 'wordpress-seo' ); 
  97. self::$meta_fields['advanced']['meta-robots-adv']['options']['noodp'] = __( 'NO ODP', 'wordpress-seo' ); 
  98. self::$meta_fields['advanced']['meta-robots-adv']['options']['noimageindex'] = __( 'No Image Index', 'wordpress-seo' ); 
  99. self::$meta_fields['advanced']['meta-robots-adv']['options']['noarchive'] = __( 'No Archive', 'wordpress-seo' ); 
  100. self::$meta_fields['advanced']['meta-robots-adv']['options']['nosnippet'] = __( 'No Snippet', 'wordpress-seo' ); 
  101.  
  102. self::$meta_fields['advanced']['bctitle']['title'] = __( 'Breadcrumbs Title', 'wordpress-seo' ); 
  103. self::$meta_fields['advanced']['bctitle']['description'] = __( 'Title to use for this page in breadcrumb paths', 'wordpress-seo' ); 
  104.  
  105. self::$meta_fields['advanced']['canonical']['title'] = __( 'Canonical URL', 'wordpress-seo' ); 
  106. /** translators: 1: link open tag; 2: link close tag. */ 
  107. self::$meta_fields['advanced']['canonical']['description'] = sprintf( __( 'The canonical URL that this page should point to, leave empty to default to permalink. %1$sCross domain canonical%2$s supported too.', 'wordpress-seo' ), '<a target="_blank" href="http://googlewebmastercentral.blogspot.com/2009/12/handling-legitimate-cross-domain.html">', '</a>' ); 
  108.  
  109. self::$meta_fields['advanced']['redirect']['title'] = __( '301 Redirect', 'wordpress-seo' ); 
  110. self::$meta_fields['advanced']['redirect']['description'] = __( 'The URL that this page should redirect to.', 'wordpress-seo' ); 
  111.  
  112. do_action( 'wpseo_tab_translate' ); 
  113.  
  114. /** 
  115. * Test whether the metabox should be hidden either by choice of the admin or because 
  116. * the post type is not a public post type 
  117. * @since 1.5.0 
  118. * @param string $post_type (optional) The post type to test, defaults to the current post post_type. 
  119. * @return bool Whether or not the meta box (and associated columns etc) should be hidden 
  120. */ 
  121. function is_metabox_hidden( $post_type = null ) { 
  122. if ( ! isset( $post_type ) && ( isset( $GLOBALS['post'] ) && ( is_object( $GLOBALS['post'] ) && isset( $GLOBALS['post']->post_type ) ) ) ) { 
  123. $post_type = $GLOBALS['post']->post_type; 
  124.  
  125. if ( isset( $post_type ) ) { 
  126. // Don't make static as post_types may still be added during the run. 
  127. $cpts = get_post_types( array( 'public' => true ), 'names' ); 
  128. $options = get_option( 'wpseo_titles' ); 
  129.  
  130. return ( ( isset( $options[ 'hideeditbox-' . $post_type ] ) && $options[ 'hideeditbox-' . $post_type ] === true ) || in_array( $post_type, $cpts ) === false ); 
  131. return false; 
  132.  
  133. /** 
  134. * Sets up all the functionality related to the prominence of the page analysis functionality. 
  135. */ 
  136. public function setup_page_analysis() { 
  137. if ( apply_filters( 'wpseo_use_page_analysis', true ) === true ) { 
  138. add_action( 'post_submitbox_start', array( $this, 'publish_box' ) ); 
  139.  
  140. /** 
  141. * Outputs the page analysis score in the Publish Box. 
  142. */ 
  143. public function publish_box() { 
  144. if ( $this->is_metabox_hidden() === true ) { 
  145. return; 
  146.  
  147. $post = $this->get_metabox_post(); 
  148. if ( self::get_value( 'meta-robots-noindex', $post->ID ) === '1' ) { 
  149. $score_label = 'noindex'; 
  150. $title = __( 'Post is set to noindex.', 'wordpress-seo' ); 
  151. $score_title = $title; 
  152. else { 
  153. $score = self::get_value( 'linkdex', $post->ID ); 
  154. if ( $score === '' ) { 
  155. $score_label = 'na'; 
  156. $title = __( 'No focus keyword set.', 'wordpress-seo' ); 
  157. else { 
  158. $score_label = WPSEO_Utils::translate_score( $score ); 
  159.  
  160. $score_title = WPSEO_Utils::translate_score( $score, false ); 
  161. if ( ! isset( $title ) ) { 
  162. $title = $score_title; 
  163.  
  164. /** 
  165. * Adds the Yoast SEO meta box to the edit boxes in the edit post, page,  
  166. * attachment, and custom post types pages. 
  167. */ 
  168. public function add_meta_box() { 
  169. $post_types = get_post_types( array( 'public' => true ) ); 
  170.  
  171. if ( is_array( $post_types ) && $post_types !== array() ) { 
  172. foreach ( $post_types as $post_type ) { 
  173. if ( $this->is_metabox_hidden( $post_type ) === false ) { 
  174. $product_title = 'Yoast SEO'; 
  175. if ( file_exists( WPSEO_PATH . 'premium/' ) ) { 
  176. $product_title .= ' Premium'; 
  177.  
  178. if ( null !== get_current_screen() ) { 
  179. $screen_id = get_current_screen()->id; 
  180. add_filter( "postbox_classes_{$screen_id}_wpseo_meta", array( $this, 'wpseo_metabox_class' ) ); 
  181.  
  182. add_meta_box( 'wpseo_meta', $product_title, array( 
  183. $this,  
  184. 'meta_box',  
  185. ), $post_type, 'normal', apply_filters( 'wpseo_metabox_prio', 'high' ) ); 
  186.  
  187. /** 
  188. * Adds CSS classes to the meta box. 
  189. * @param array $classes An array of postbox CSS classes. 
  190. * @return array 
  191. */ 
  192. public function wpseo_metabox_class( $classes ) { 
  193. $classes[] = 'yoast wpseo-metabox'; 
  194. return $classes; 
  195.  
  196. /** 
  197. * Pass variables to js for use with the post-scraper 
  198. * @return array 
  199. */ 
  200. public function localize_post_scraper_script() { 
  201. $post = $this->get_metabox_post(); 
  202. $permalink = ''; 
  203.  
  204. if ( is_object( $post ) ) { 
  205. $permalink = get_sample_permalink( $post->ID ); 
  206. $permalink = $permalink[0]; 
  207.  
  208. $post_formatter = new WPSEO_Metabox_Formatter( 
  209. new WPSEO_Post_Metabox_Formatter( $post, WPSEO_Options::get_option( 'wpseo_titles' ), $permalink ) 
  210. ); 
  211.  
  212. return $post_formatter->get_values(); 
  213.  
  214. /** 
  215. * Pass some variables to js for replacing variables. 
  216. */ 
  217. public function localize_replace_vars_script() { 
  218. return array( 
  219. 'no_parent_text' => __( '(no parent)', 'wordpress-seo' ),  
  220. 'replace_vars' => $this->get_replace_vars(),  
  221. 'scope' => $this->determine_scope(),  
  222. ); 
  223.  
  224. /** 
  225. * Determines the scope based on the post type. 
  226. * This can be used by the replacevar plugin to determine if a replacement needs to be executed. 
  227. * @return string String decribing the current scope. 
  228. */ 
  229. private function determine_scope() { 
  230. $post_type = get_post_type( $this->get_metabox_post() ); 
  231.  
  232. if ( $post_type === 'page' ) { 
  233. return 'page'; 
  234.  
  235. return 'post'; 
  236.  
  237. /** 
  238. * Pass some variables to js for the edit / post page overview, snippet preview, etc. 
  239. * @return array 
  240. */ 
  241. public function localize_shortcode_plugin_script() { 
  242. return array( 
  243. 'wpseo_filter_shortcodes_nonce' => wp_create_nonce( 'wpseo-filter-shortcodes' ),  
  244. 'wpseo_shortcode_tags' => $this->get_valid_shortcode_tags(),  
  245. ); 
  246.  
  247. /** 
  248. * Output a tab in the Yoast SEO Metabox 
  249. * @param string $id CSS ID of the tab. 
  250. * @param string $heading Heading for the tab. 
  251. * @param string $content Content of the tab. This content should be escaped. 
  252. */ 
  253. public function do_tab( $id, $heading, $content ) { 
  254. ?> 
  255. <div id="wpseo_<?php echo esc_attr( $id ) ?>" class="wpseotab <?php echo esc_attr( $id ) ?>"> 
  256. <?php echo $content ?> 
  257. </div> 
  258. <?php 
  259.  
  260. /** 
  261. * Output the meta box 
  262. */ 
  263. public function meta_box() { 
  264. $content_sections = $this->get_content_sections(); 
  265.  
  266. $helpcenter_tab = new WPSEO_Option_Tab( 'metabox', 'Meta box',  
  267. array( 'video_url' => 'https://yoa.st/metabox-screencast' ) ); 
  268.  
  269. $helpcenter = new WPSEO_Help_Center( 'metabox', $helpcenter_tab ); 
  270. $helpcenter->output_help_center(); 
  271.  
  272. if ( ! defined( 'WPSEO_PREMIUM_FILE' ) ) { 
  273. echo $this->get_buy_premium_link(); 
  274.  
  275. echo '<div class="wpseo-metabox-sidebar"><ul>'; 
  276.  
  277. foreach ( $content_sections as $content_section ) { 
  278. if ( $content_section->name === 'premium' ) { 
  279. continue; 
  280.  
  281. $content_section->display_link(); 
  282.  
  283. echo '</ul></div>'; 
  284.  
  285. foreach ( $content_sections as $content_section ) { 
  286. $content_section->display_content(); 
  287.  
  288. /** 
  289. * Returns the relevant metabox sections for the current view. 
  290. * @return WPSEO_Metabox_Section[] 
  291. */ 
  292. private function get_content_sections() { 
  293. $content_sections = array( $this->get_content_meta_section() ); 
  294.  
  295. // Check if social_admin is an instance of WPSEO_Social_Admin. 
  296. if ( $this->social_admin instanceof WPSEO_Social_Admin ) { 
  297. $content_sections[] = $this->social_admin->get_meta_section(); 
  298.  
  299. if ( current_user_can( 'manage_options' ) || $this->options['disableadvanced_meta'] === false ) { 
  300. $content_sections[] = $this->get_advanced_meta_section(); 
  301.  
  302. if ( ! defined( 'WPSEO_PREMIUM_FILE' ) ) { 
  303. $content_sections[] = $this->get_buy_premium_section(); 
  304.  
  305. if ( has_action( 'wpseo_tab_header' ) || has_action( 'wpseo_tab_content' ) ) { 
  306. $content_sections[] = $this->get_addons_meta_section(); 
  307.  
  308. return $content_sections; 
  309.  
  310. /** 
  311. * Returns the metabox section for the content analysis. 
  312. * @return WPSEO_Metabox_Section 
  313. */ 
  314. private function get_content_meta_section() { 
  315. $content = $this->get_tab_content( 'general' ); 
  316.  
  317. $tabs = array(); 
  318.  
  319. $tabs[] = new WPSEO_Metabox_Form_Tab( 
  320. 'content',  
  321. $content,  
  322. '',  
  323. array( 
  324. 'tab_class' => 'yoast-seo__remove-tab',  
  325. ); 
  326.  
  327. $tabs[] = new Metabox_Add_Keyword_Tab(); 
  328.  
  329. return new WPSEO_Metabox_Tab_Section( 
  330. 'content',  
  331. '<span class="screen-reader-text">' . __( 'Content optimization', 'wordpress-seo' ) . '</span><span class="yst-traffic-light-container">' . $this->traffic_light_svg() . '</span>',  
  332. $tabs,  
  333. array( 
  334. 'link_aria_label' => __( 'Content optimization', 'wordpress-seo' ),  
  335. 'link_class' => 'yoast-tooltip yoast-tooltip-e',  
  336. ); 
  337.  
  338. /** 
  339. * Returns the metabox section for the advanced settings. 
  340. * @return WPSEO_Metabox_Section 
  341. */ 
  342. private function get_advanced_meta_section() { 
  343. $content = $this->get_tab_content( 'advanced' ); 
  344.  
  345. $tab = new WPSEO_Metabox_Form_Tab( 
  346. 'advanced',  
  347. $content,  
  348. __( 'Advanced', 'wordpress-seo' ),  
  349. array( 
  350. 'single' => true,  
  351. ); 
  352.  
  353. return new WPSEO_Metabox_Tab_Section( 
  354. 'advanced',  
  355. '<span class="screen-reader-text">' . __( 'Advanced', 'wordpress-seo' ) . '</span><span class="dashicons dashicons-admin-generic"></span>',  
  356. array( $tab ),  
  357. array( 
  358. 'link_aria_label' => __( 'Advanced', 'wordpress-seo' ),  
  359. 'link_class' => 'yoast-tooltip yoast-tooltip-e',  
  360. ); 
  361.  
  362. /** 
  363. * Returns a link to activate the Buy Premium tab. 
  364. * @return string 
  365. */ 
  366. private function get_buy_premium_link() { 
  367. return sprintf( "<div class='%s'><a href='#wpseo-meta-section-premium' class='wpseo-meta-section-link'><span class='dashicons dashicons-star-filled wpseo-buy-premium'></span>%s</a></div>",  
  368. 'wpseo-metabox-buy-premium',  
  369. __( 'Go Premium', 'wordpress-seo' ) 
  370. ); 
  371.  
  372. /** 
  373. * Returns the metabox section for the Premium section. 
  374. * @return WPSEO_Metabox_Section 
  375. */ 
  376. private function get_buy_premium_section() { 
  377. $content = sprintf( "<div class='wpseo-metabox-premium-description'> 
  378. %s 
  379. <ul class='wpseo-metabox-premium-advantages'> 
  380. <li> 
  381. <strong>%s</strong> - %s 
  382. </li> 
  383. <li> 
  384. <strong>%s</strong> - %s 
  385. </li> 
  386. <li> 
  387. <strong>%s</strong> - %s 
  388. </li> 
  389. <li> 
  390. <strong>%s</strong> - %s 
  391. </li> 
  392. </ul> 
  393.  
  394. <a target='_blank' id='wpseo-buy-premium-popup-button' class='button button-buy-premium wpseo-metabox-go-to' href='%s'> 
  395. %s 
  396. </a> 
  397.  
  398. <p><a target='_blank' class='wpseo-metabox-go-to' href='%s'>%s</a></p> 
  399. </div>",  
  400. /** translators: %1$s expands to Yoast SEO Premium. */ 
  401. sprintf( __( 'You\'re not getting the benefits of %1$s yet. If you had %1$s, you could use its awesome features:', 'wordpress-seo' ), 'Yoast SEO Premium' ),  
  402. __( 'Redirect manager', 'wordpress-seo' ),  
  403. __( 'Create and manage redirects within your WordPress install.', 'wordpress-seo' ),  
  404. __( 'Multiple focus keywords', 'wordpress-seo' ),  
  405. __( 'Optimize a single post for up to 5 keywords.', 'wordpress-seo' ),  
  406. __( 'Social Previews', 'wordpress-seo' ),  
  407. __( 'Check what your Facebook or Twitter post will look like.', 'wordpress-seo' ),  
  408. __( 'Premium support', 'wordpress-seo' ),  
  409. __( 'Gain access to our 24/7 support team.', 'wordpress-seo' ),  
  410. WPSEO_Shortlinker::get( 'https://yoa.st/pe-buy-premium' ),  
  411. /** translators: %s expands to Yoast SEO Premium. */ 
  412. sprintf( __( 'Get %s now!', 'wordpress-seo' ), 'Yoast SEO Premium' ),  
  413. WPSEO_Shortlinker::get( 'https://yoa.st/pe-premium-page' ),  
  414. __( 'More info', 'wordpress-seo' ) 
  415. ); 
  416.  
  417. $tab = new WPSEO_Metabox_Form_Tab( 
  418. 'premium',  
  419. $content,  
  420. 'Yoast SEO Premium',  
  421. array( 
  422. 'single' => true,  
  423. ); 
  424.  
  425. return new WPSEO_Metabox_Tab_Section( 
  426. 'premium',  
  427. '<span class="dashicons dashicons-star-filled wpseo-buy-premium"></span>',  
  428. array( $tab ),  
  429. array( 
  430. 'link_aria_label' => 'Yoast SEO Premium',  
  431. 'link_class' => 'yoast-tooltip yoast-tooltip-e',  
  432. ); 
  433.  
  434. /** 
  435. * Returns a metabox section dedicated to hosting metabox tabs that have been added by other plugins through the 
  436. * `wpseo_tab_header` and `wpseo_tab_content` actions. 
  437. * @return WPSEO_Metabox_Section 
  438. */ 
  439. private function get_addons_meta_section() { 
  440. return new WPSEO_Metabox_Addon_Tab_Section( 
  441. 'addons',  
  442. '<span class="screen-reader-text">' . __( 'Add-ons', 'wordpress-seo' ) . '</span><span class="dashicons dashicons-admin-plugins"></span>',  
  443. array(),  
  444. array( 
  445. 'link_aria_label' => __( 'Add-ons', 'wordpress-seo' ),  
  446. 'link_class' => 'yoast-tooltip yoast-tooltip-e',  
  447. ); 
  448.  
  449. /** 
  450. * Gets the contents for the metabox tab. 
  451. * @param string $tab_name Tab for which to retrieve the field definitions. 
  452. * @return string 
  453. */ 
  454. private function get_tab_content( $tab_name ) { 
  455. $content = ''; 
  456. foreach ( $this->get_meta_field_defs( $tab_name ) as $key => $meta_field ) { 
  457. $content .= $this->do_meta_box( $meta_field, $key ); 
  458. unset( $key, $meta_field ); 
  459.  
  460. return $content; 
  461.  
  462. /** 
  463. * Adds a line in the meta box 
  464. * @todo [JRF] check if $class is added appropriately everywhere 
  465. * @param array $meta_field_def Contains the vars based on which output is generated. 
  466. * @param string $key Internal key (without prefix). 
  467. * @return string 
  468. */ 
  469. function do_meta_box( $meta_field_def, $key = '' ) { 
  470. $content = ''; 
  471. $esc_form_key = esc_attr( self::$form_prefix . $key ); 
  472. $meta_value = self::get_value( $key, $this->get_metabox_post()->ID ); 
  473.  
  474. $class = ''; 
  475. if ( isset( $meta_field_def['class'] ) && $meta_field_def['class'] !== '' ) { 
  476. $class = ' ' . $meta_field_def['class']; 
  477.  
  478. $placeholder = ''; 
  479. if ( isset( $meta_field_def['placeholder'] ) && $meta_field_def['placeholder'] !== '' ) { 
  480. $placeholder = $meta_field_def['placeholder']; 
  481.  
  482. $aria_describedby = $description = ''; 
  483. if ( isset( $meta_field_def['description'] ) ) { 
  484. $aria_describedby = ' aria-describedby="' . $esc_form_key . '-desc"'; 
  485. $description = '<p id="' . $esc_form_key . '-desc" class="yoast-metabox__description">' . $meta_field_def['description'] . '</p>'; 
  486.  
  487. switch ( $meta_field_def['type'] ) { 
  488. case 'pageanalysis': 
  489. $content .= '<div id="pageanalysis">'; 
  490. $content .= '<section class="yoast-section" id="wpseo-pageanalysis-section">'; 
  491. $content .= '<h3 class="yoast-section__heading yoast-section__heading-icon yoast-section__heading-icon-list">' . __( 'Analysis', 'wordpress-seo' ) . '</h3>'; 
  492. $content .= '<div id="wpseo-pageanalysis"></div>'; 
  493. $content .= '<div id="yoast-seo-content-analysis"></div>'; 
  494. $content .= '</section>'; 
  495. $content .= '</div>'; 
  496. break; 
  497. case 'snippetpreview': 
  498. $content .= '<div id="wpseosnippet" class="wpseosnippet"></div>'; 
  499. break; 
  500. case 'focuskeyword': 
  501. if ( $placeholder !== '' ) { 
  502. $placeholder = ' placeholder="' . esc_attr( $placeholder ) . '"'; 
  503.  
  504. $content .= '<div id="wpseofocuskeyword">'; 
  505. $content .= '<section class="yoast-section" id="wpseo-focuskeyword-section">'; 
  506. $content .= '<h3 class="yoast-section__heading yoast-section__heading-icon yoast-section__heading-icon-key">' . esc_html( $meta_field_def['title'] ) . '</h3>'; 
  507. $content .= '<label for="' . $esc_form_key . '" class="screen-reader-text">' . esc_html( $meta_field_def['label'] ) . '</label>'; 
  508. $content .= '<input type="text"' . $placeholder . ' id="' . $esc_form_key . '" autocomplete="off" name="' . $esc_form_key . '" value="' . esc_attr( $meta_value ) . '" class="large-text' . $class . '"/>'; 
  509.  
  510. if ( $this->options['enable_cornerstone_content'] ) { 
  511. $cornerstone_field = new WPSEO_Cornerstone_Field(); 
  512.  
  513. $content .= $cornerstone_field->get_html( $this->get_metabox_post() ); 
  514. $content .= '</section>'; 
  515. $content .= '</div>'; 
  516. break; 
  517. case 'metakeywords': 
  518. $content .= '<div id="wpseometakeywords">'; 
  519. $content .= '<section class="yoast-section" id="wpseo-metakeywords-section">'; 
  520. $content .= '<h3 class="yoast-section__heading yoast-section__heading-icon yoast-section__heading-icon-edit">' . esc_html( $meta_field_def['title'] ) . '</h3>'; 
  521. $content .= '<label for="' . $esc_form_key . '" class="screen-reader-text">' . esc_html( $meta_field_def['label'] ) . '</label>'; 
  522. $content .= '<input type="text" id="' . $esc_form_key . '" name="' . $esc_form_key . '" value="' . esc_attr( $meta_value ) . '" class="large-text' . $class . '"' . $aria_describedby . '/>'; 
  523. $content .= $description; 
  524. $content .= '</section>'; 
  525. $content .= '</div>'; 
  526. break; 
  527. case 'text': 
  528. $ac = ''; 
  529. if ( isset( $meta_field_def['autocomplete'] ) && $meta_field_def['autocomplete'] === false ) { 
  530. $ac = 'autocomplete="off" '; 
  531. if ( $placeholder !== '' ) { 
  532. $placeholder = ' placeholder="' . esc_attr( $placeholder ) . '"'; 
  533. $content .= '<input type="text"' . $placeholder . 'id="' . $esc_form_key . '" ' . $ac . 'name="' . $esc_form_key . '" value="' . esc_attr( $meta_value ) . '" class="large-text' . $class . '"' . $aria_describedby . '/>'; 
  534. break; 
  535.  
  536. case 'textarea': 
  537. $rows = 3; 
  538. if ( isset( $meta_field_def['rows'] ) && $meta_field_def['rows'] > 0 ) { 
  539. $rows = $meta_field_def['rows']; 
  540. $content .= '<textarea class="large-text' . $class . '" rows="' . esc_attr( $rows ) . '" id="' . $esc_form_key . '" name="' . $esc_form_key . '"' . $aria_describedby . '>' . esc_textarea( $meta_value ) . '</textarea>'; 
  541. break; 
  542.  
  543. case 'hidden': 
  544. $content .= '<input type="hidden" id="' . $esc_form_key . '" name="' . $esc_form_key . '" value="' . esc_attr( $meta_value ) . '"/>' . "\n"; 
  545. break; 
  546. case 'select': 
  547. if ( isset( $meta_field_def['options'] ) && is_array( $meta_field_def['options'] ) && $meta_field_def['options'] !== array() ) { 
  548. $content .= '<select name="' . $esc_form_key . '" id="' . $esc_form_key . '" class="yoast' . $class . '">'; 
  549. foreach ( $meta_field_def['options'] as $val => $option ) { 
  550. $selected = selected( $meta_value, $val, false ); 
  551. $content .= '<option ' . $selected . ' value="' . esc_attr( $val ) . '">' . esc_html( $option ) . '</option>'; 
  552. unset( $val, $option, $selected ); 
  553. $content .= '</select>'; 
  554. break; 
  555.  
  556. case 'multiselect': 
  557. if ( isset( $meta_field_def['options'] ) && is_array( $meta_field_def['options'] ) && $meta_field_def['options'] !== array() ) { 
  558.  
  559. // Set $meta_value as $selected_arr. 
  560. $selected_arr = $meta_value; 
  561.  
  562. // If the multiselect field is 'meta-robots-adv' we should explode on , . 
  563. if ( 'meta-robots-adv' === $key ) { 
  564. $selected_arr = explode( ', ', $meta_value ); 
  565.  
  566. if ( ! is_array( $selected_arr ) ) { 
  567. $selected_arr = (array) $selected_arr; 
  568.  
  569. $options_count = count( $meta_field_def['options'] ); 
  570.  
  571. // This select now uses Select2. 
  572. $content .= '<select multiple="multiple" size="' . esc_attr( $options_count ) . '" name="' . $esc_form_key . '[]" id="' . $esc_form_key . '" class="yoast' . $class . '"' . $aria_describedby . '>'; 
  573. foreach ( $meta_field_def['options'] as $val => $option ) { 
  574. $selected = ''; 
  575. if ( in_array( $val, $selected_arr ) ) { 
  576. $selected = ' selected="selected"'; 
  577. $content .= '<option ' . $selected . ' value="' . esc_attr( $val ) . '">' . esc_html( $option ) . '</option>'; 
  578. $content .= '</select>'; 
  579. unset( $val, $option, $selected, $selected_arr, $options_count ); 
  580. break; 
  581.  
  582. case 'checkbox': 
  583. $checked = checked( $meta_value, 'on', false ); 
  584. $expl = ( isset( $meta_field_def['expl'] ) ) ? esc_html( $meta_field_def['expl'] ) : ''; 
  585. $content .= '<input type="checkbox" id="' . $esc_form_key . '" name="' . $esc_form_key . '" ' . $checked . ' value="on" class="yoast' . $class . '"' . $aria_describedby . '/> <label for="' . $esc_form_key . '">' . $expl . '</label>'; 
  586. unset( $checked, $expl ); 
  587. break; 
  588.  
  589. case 'radio': 
  590. if ( isset( $meta_field_def['options'] ) && is_array( $meta_field_def['options'] ) && $meta_field_def['options'] !== array() ) { 
  591. foreach ( $meta_field_def['options'] as $val => $option ) { 
  592. $checked = checked( $meta_value, $val, false ); 
  593. $content .= '<input type="radio" ' . $checked . ' id="' . $esc_form_key . '_' . esc_attr( $val ) . '" name="' . $esc_form_key . '" value="' . esc_attr( $val ) . '"/> <label for="' . $esc_form_key . '_' . esc_attr( $val ) . '">' . esc_html( $option ) . '</label> '; 
  594. unset( $val, $option, $checked ); 
  595. break; 
  596.  
  597. case 'upload': 
  598. $content .= '<input id="' . $esc_form_key . '" type="text" size="36" class="' . $class . '" name="' . $esc_form_key . '" value="' . esc_attr( $meta_value ) . '"' . $aria_describedby . ' />'; 
  599. $content .= '<input id="' . $esc_form_key . '_button" class="wpseo_image_upload_button button" type="button" value="' . esc_attr__( 'Upload Image', 'wordpress-seo' ) . '" />'; 
  600. break; 
  601.  
  602. $html = ''; 
  603. if ( $content === '' ) { 
  604. $content = apply_filters( 'wpseo_do_meta_box_field_' . $key, $content, $meta_value, $esc_form_key, $meta_field_def, $key ); 
  605.  
  606. if ( $content !== '' ) { 
  607.  
  608. $title = esc_html( $meta_field_def['title'] ); 
  609.  
  610. // By default, use the field title as a label element. 
  611. $label = '<label for="' . $esc_form_key . '">' . $title . '</label>'; 
  612.  
  613. // Set the inline help and help panel, if any. 
  614. $help_button = $help_panel = ''; 
  615. if ( isset( $meta_field_def['help'] ) && $meta_field_def['help'] !== '' ) { 
  616. $help = new WPSEO_Admin_Help_Panel( $key, $meta_field_def['help-button'], $meta_field_def['help'] ); 
  617. $help_button = $help->get_button_html(); 
  618. $help_panel = $help->get_panel_html(); 
  619.  
  620. // If it's a set of radio buttons, output proper fieldset and legend. 
  621. if ( 'radio' === $meta_field_def['type'] ) { 
  622. return '<fieldset><legend>' . $title . '</legend>' . $help_button . $help_panel . $content . $description . '</fieldset>'; 
  623.  
  624. // If it's a single checkbox, ignore the title. 
  625. if ( 'checkbox' === $meta_field_def['type'] ) { 
  626. $label = ''; 
  627.  
  628. // Special meta box sections such as the Snippet Preview, the Analysis, etc. 
  629. if ( in_array( $meta_field_def['type'], array( 
  630. 'snippetpreview',  
  631. 'pageanalysis',  
  632. 'focuskeyword',  
  633. 'metakeywords',  
  634. ), true ) 
  635. ) { 
  636. return $this->create_content_box( $content, $meta_field_def['type'], $help_button, $help_panel ); 
  637.  
  638. // Other meta box content or form fields. 
  639. if ( $meta_field_def['type'] === 'hidden' ) { 
  640. $html = $content; 
  641. else { 
  642. $html = $label . $help_button . $help_panel . $content . $description; 
  643.  
  644. return $html; 
  645.  
  646. /** 
  647. * Creates a sections specific row. 
  648. * @param string $content The content to show. 
  649. * @param string $hidden_help_name Escaped form key name. 
  650. * @param string $help_button The help button. 
  651. * @param string $help_panel The help text. 
  652. * @return string 
  653. */ 
  654. private function create_content_box( $content, $hidden_help_name, $help_button, $help_panel ) { 
  655. $html = $content; 
  656. $html .= '<div class="wpseo_hidden" id="help-yoast-' . $hidden_help_name . '">' . $help_button . $help_panel . '</div>'; 
  657. return $html; 
  658.  
  659. /** 
  660. * Save the WP SEO metadata for posts. 
  661. * @internal $_POST parameters are validated via sanitize_post_meta() 
  662. * @param int $post_id Post ID. 
  663. * @return bool|void Boolean false if invalid save post request 
  664. */ 
  665. function save_postdata( $post_id ) { 
  666. // Bail if this is a multisite installation and the site has been switched. 
  667. if ( is_multisite() && ms_is_switched() ) { 
  668. return false; 
  669.  
  670. if ( $post_id === null ) { 
  671. return false; 
  672.  
  673. if ( wp_is_post_revision( $post_id ) ) { 
  674. $post_id = wp_is_post_revision( $post_id ); 
  675.  
  676. /** 
  677. * Determine we're not accidentally updating a different post. 
  678. * We can't use filter_input here as the ID isn't available at this point, other than in the $_POST data. 
  679. */ 
  680. if ( ! isset( $_POST['ID'] ) || $post_id !== (int) $_POST['ID'] ) { 
  681. return false; 
  682.  
  683. clean_post_cache( $post_id ); 
  684. $post = get_post( $post_id ); 
  685.  
  686. if ( ! is_object( $post ) ) { 
  687. // Non-existent post. 
  688. return false; 
  689.  
  690. do_action( 'wpseo_save_compare_data', $post ); 
  691.  
  692. $meta_boxes = apply_filters( 'wpseo_save_metaboxes', array() ); 
  693. $meta_boxes = array_merge( $meta_boxes, $this->get_meta_field_defs( 'general', $post->post_type ), $this->get_meta_field_defs( 'advanced' ) ); 
  694.  
  695. foreach ( $meta_boxes as $key => $meta_box ) { 
  696.  
  697. // If analysis is disabled remove that analysis score value from the DB. 
  698. if ( $this->is_meta_value_disabled( $key ) ) { 
  699. self::delete( $key, $post_id ); 
  700. continue; 
  701.  
  702. $data = null; 
  703. if ( 'checkbox' === $meta_box['type'] ) { 
  704. $data = isset( $_POST[ self::$form_prefix . $key ] ) ? 'on' : 'off'; 
  705. else { 
  706. if ( isset( $_POST[ self::$form_prefix . $key ] ) ) { 
  707. $data = $_POST[ self::$form_prefix . $key ]; 
  708. if ( isset( $data ) ) { 
  709. self::set_value( $key, $data, $post_id ); 
  710.  
  711. do_action( 'wpseo_saved_postdata' ); 
  712.  
  713. /** 
  714. * Determines if the given meta value key is disabled 
  715. * @param string $key The key of the meta value. 
  716. * @return bool Whether the given meta value key is disabled. 
  717. */ 
  718. public function is_meta_value_disabled( $key ) { 
  719. if ( 'linkdex' === $key && ! $this->analysis_seo->is_enabled() ) { 
  720. return true; 
  721.  
  722. if ( 'content_score' === $key && ! $this->analysis_readability->is_enabled() ) { 
  723. return true; 
  724.  
  725. return false; 
  726.  
  727. /** 
  728. * Enqueues all the needed JS and CSS. 
  729. * @todo [JRF => whomever] create css/metabox-mp6.css file and add it to the below allowed colors array when done 
  730. */ 
  731. public function enqueue() { 
  732. global $pagenow; 
  733.  
  734. $asset_manager = new WPSEO_Admin_Asset_Manager(); 
  735.  
  736. $is_editor = self::is_post_overview( $pagenow ) || self::is_post_edit( $pagenow ); 
  737.  
  738. /** Filter 'wpseo_always_register_metaboxes_on_admin' documented in wpseo-main.php */ 
  739. if ( ( ! $is_editor && apply_filters( 'wpseo_always_register_metaboxes_on_admin', false ) === false ) || $this->is_metabox_hidden() === true 
  740. ) { 
  741. return; 
  742.  
  743. if ( self::is_post_overview( $pagenow ) ) { 
  744. $asset_manager->enqueue_style( 'edit-page' ); 
  745. else { 
  746.  
  747. if ( 0 != get_queried_object_id() ) { 
  748. wp_enqueue_media( array( 'post' => get_queried_object_id() ) ); // Enqueue files needed for upload functionality. 
  749.  
  750. $asset_manager->enqueue_style( 'metabox-css' ); 
  751. $asset_manager->enqueue_style( 'scoring' ); 
  752. $asset_manager->enqueue_style( 'snippet' ); 
  753. $asset_manager->enqueue_style( 'select2' ); 
  754. $asset_manager->enqueue_style( 'kb-search' ); 
  755.  
  756. $asset_manager->enqueue_script( 'metabox' ); 
  757. $asset_manager->enqueue_script( 'admin-media' ); 
  758.  
  759. $asset_manager->enqueue_script( 'post-scraper' ); 
  760. $asset_manager->enqueue_script( 'replacevar-plugin' ); 
  761. $asset_manager->enqueue_script( 'shortcode-plugin' ); 
  762.  
  763. wp_enqueue_script( 'jquery-ui-autocomplete' ); 
  764.  
  765. wp_localize_script( WPSEO_Admin_Asset_Manager::PREFIX . 'admin-media', 'wpseoMediaL10n', $this->localize_media_script() ); 
  766. wp_localize_script( WPSEO_Admin_Asset_Manager::PREFIX . 'post-scraper', 'wpseoPostScraperL10n', $this->localize_post_scraper_script() ); 
  767. wp_localize_script( WPSEO_Admin_Asset_Manager::PREFIX . 'replacevar-plugin', 'wpseoReplaceVarsL10n', $this->localize_replace_vars_script() ); 
  768. wp_localize_script( WPSEO_Admin_Asset_Manager::PREFIX . 'shortcode-plugin', 'wpseoShortcodePluginL10n', $this->localize_shortcode_plugin_script() ); 
  769.  
  770. wp_localize_script( WPSEO_Admin_Asset_Manager::PREFIX . 'metabox', 'wpseoAdminL10n', WPSEO_Help_Center::get_translated_texts() ); 
  771. wp_localize_script( WPSEO_Admin_Asset_Manager::PREFIX . 'metabox', 'wpseoSelect2Locale', WPSEO_Utils::get_language( WPSEO_Utils::get_user_locale() ) ); 
  772.  
  773. if ( post_type_supports( get_post_type(), 'thumbnail' ) ) { 
  774. $asset_manager->enqueue_style( 'featured-image' ); 
  775.  
  776. $asset_manager->enqueue_script( 'featured-image' ); 
  777.  
  778. $featured_image_l10 = array( 'featured_image_notice' => __( 'SEO issue: The featured image should be at least 200 by 200 pixels to be picked up by Facebook and other social media sites.', 'wordpress-seo' ) ); 
  779. wp_localize_script( WPSEO_Admin_Asset_Manager::PREFIX . 'metabox', 'wpseoFeaturedImageL10n', $featured_image_l10 ); 
  780.  
  781. /** 
  782. * Pass some variables to js for upload module. 
  783. * @return array 
  784. */ 
  785. public function localize_media_script() { 
  786. return array( 
  787. 'choose_image' => __( 'Use Image', 'wordpress-seo' ),  
  788. ); 
  789.  
  790. /** 
  791. * Returns post in metabox context 
  792. * @returns WP_Post|array 
  793. */ 
  794. protected function get_metabox_post() { 
  795. if ( $post = filter_input( INPUT_GET, 'post' ) ) { 
  796. $post_id = (int) WPSEO_Utils::validate_int( $post ); 
  797.  
  798. return get_post( $post_id ); 
  799.  
  800.  
  801. if ( isset( $GLOBALS['post'] ) ) { 
  802. return $GLOBALS['post']; 
  803.  
  804. return array(); 
  805.  
  806.  
  807.  
  808. /** 
  809. * Returns an array with shortcode tags for all registered shortcodes. 
  810. * @return array 
  811. */ 
  812. private function get_valid_shortcode_tags() { 
  813. $shortcode_tags = array(); 
  814.  
  815. foreach ( $GLOBALS['shortcode_tags'] as $tag => $description ) { 
  816. array_push( $shortcode_tags, $tag ); 
  817.  
  818. return $shortcode_tags; 
  819.  
  820. /** 
  821. * Prepares the replace vars for localization. 
  822. * @return array replace vars 
  823. */ 
  824. private function get_replace_vars() { 
  825. $post = $this->get_metabox_post(); 
  826.  
  827. $cached_replacement_vars = array(); 
  828.  
  829. $vars_to_cache = array( 
  830. 'date',  
  831. 'id',  
  832. 'sitename',  
  833. 'sitedesc',  
  834. 'sep',  
  835. 'page',  
  836. 'currenttime',  
  837. 'currentdate',  
  838. 'currentday',  
  839. 'currentmonth',  
  840. 'currentyear',  
  841. ); 
  842.  
  843. foreach ( $vars_to_cache as $var ) { 
  844. $cached_replacement_vars[ $var ] = wpseo_replace_vars( '%%' . $var . '%%', $post ); 
  845.  
  846. // Merge custom replace variables with the WordPress ones. 
  847. return array_merge( $cached_replacement_vars, $this->get_custom_replace_vars( $post ) ); 
  848.  
  849. /** 
  850. * Gets the custom replace variables for custom taxonomies and fields. 
  851. * @param WP_Post $post The post to check for custom taxonomies and fields. 
  852. * @return array Array containing all the replacement variables. 
  853. */ 
  854. private function get_custom_replace_vars( $post ) { 
  855. return array( 
  856. 'custom_fields' => $this->get_custom_fields_replace_vars( $post ),  
  857. 'custom_taxonomies' => $this->get_custom_taxonomies_replace_vars( $post ),  
  858. ); 
  859.  
  860. /** 
  861. * Gets the custom replace variables for custom taxonomies. 
  862. * @param WP_Post $post The post to check for custom taxonomies. 
  863. * @return array Array containing all the replacement variables. 
  864. */ 
  865. private function get_custom_taxonomies_replace_vars( $post ) { 
  866. $taxonomies = get_object_taxonomies( $post, 'objects' ); 
  867. $custom_replace_vars = array(); 
  868.  
  869. foreach ( $taxonomies as $taxonomy_name => $taxonomy ) { 
  870.  
  871. if ( is_string( $taxonomy ) ) { // If attachment, see https://core.trac.wordpress.org/ticket/37368 . 
  872. $taxonomy_name = $taxonomy; 
  873. $taxonomy = get_taxonomy( $taxonomy_name ); 
  874.  
  875. if ( $taxonomy->_builtin && $taxonomy->public ) { 
  876. continue; 
  877.  
  878. $custom_replace_vars[ $taxonomy_name ] = array( 
  879. 'name' => $taxonomy->name,  
  880. 'description' => $taxonomy->description,  
  881. ); 
  882.  
  883. return $custom_replace_vars; 
  884.  
  885. /** 
  886. * Gets the custom replace variables for custom fields. 
  887. * @param WP_Post $post The post to check for custom fields. 
  888. * @return array Array containing all the replacement variables. 
  889. */ 
  890. private function get_custom_fields_replace_vars( $post ) { 
  891. $custom_replace_vars = array(); 
  892.  
  893. // If no post object is passed, return the empty custom_replace_vars array. 
  894. if ( ! is_object( $post ) ) { 
  895. return $custom_replace_vars; 
  896.  
  897. $custom_fields = get_post_custom( $post->ID ); 
  898.  
  899. foreach ( $custom_fields as $custom_field_name => $custom_field ) { 
  900. if ( substr( $custom_field_name, 0, 1 ) === '_' ) { 
  901. continue; 
  902.  
  903. $custom_replace_vars[ $custom_field_name ] = $custom_field[0]; 
  904.  
  905. return $custom_replace_vars; 
  906.  
  907.  
  908. /** 
  909. * Return the SVG for the traffic light in the metabox. 
  910. */ 
  911. public function traffic_light_svg() { 
  912. return <<<SVG 
  913. <svg class="yst-traffic-light init" version="1.1" xmlns:x="&ns_extend;" xmlns:i="&ns_ai;" xmlns:graph="&ns_graphs;" 
  914. xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" 
  915. x="0px" y="0px" viewBox="0 0 30 47" enable-background="new 0 0 30 47" xml:space="preserve"> 
  916. <g id="BG_1_"> 
  917. </g> 
  918. <g id="traffic_light"> 
  919. <g> 
  920. <g> 
  921. <g> 
  922. <path fill="#5B2942" d="M22, 0H8C3.6, 0, 0, 3.6, 0, 7.9v31.1C0, 43.4, 3.6, 47, 8, 47h14c4.4, 0, 8-3.6, 8-7.9V7.9C30, 3.6, 26.4, 0, 22, 0z 
  923. M27.5, 38.8c0, 3.1-2.6, 5.7-5.8, 5.7H8.3c-3.2, 0-5.8-2.5-5.8-5.7V8.3c0-1.5, 0.6-2.9, 1.7-4c1.1-1, 2.5-1.6, 4.1-1.6h13.4 
  924. c1.5, 0, 3, 0.6, 4.1, 1.6c1.1, 1.1, 1.7, 2.5, 1.7, 4V38.8z"/> 
  925. </g> 
  926. <g class="traffic-light-color traffic-light-red"> 
  927. <ellipse fill="#C8C8C8" cx="15" cy="23.5" rx="5.7" ry="5.6"/> 
  928. <ellipse fill="#DC3232" cx="15" cy="10.9" rx="5.7" ry="5.6"/> 
  929. <ellipse fill="#C8C8C8" cx="15" cy="36.1" rx="5.7" ry="5.6"/> 
  930. </g> 
  931. <g class="traffic-light-color traffic-light-orange"> 
  932. <ellipse fill="#F49A00" cx="15" cy="23.5" rx="5.7" ry="5.6"/> 
  933. <ellipse fill="#C8C8C8" cx="15" cy="10.9" rx="5.7" ry="5.6"/> 
  934. <ellipse fill="#C8C8C8" cx="15" cy="36.1" rx="5.7" ry="5.6"/> 
  935. </g> 
  936. <g class="traffic-light-color traffic-light-green"> 
  937. <ellipse fill="#C8C8C8" cx="15" cy="23.5" rx="5.7" ry="5.6"/> 
  938. <ellipse fill="#C8C8C8" cx="15" cy="10.9" rx="5.7" ry="5.6"/> 
  939. <ellipse fill="#63B22B" cx="15" cy="36.1" rx="5.7" ry="5.6"/> 
  940. </g> 
  941. <g class="traffic-light-color traffic-light-empty"> 
  942. <ellipse fill="#C8C8C8" cx="15" cy="23.5" rx="5.7" ry="5.6"/> 
  943. <ellipse fill="#C8C8C8" cx="15" cy="10.9" rx="5.7" ry="5.6"/> 
  944. <ellipse fill="#C8C8C8" cx="15" cy="36.1" rx="5.7" ry="5.6"/> 
  945. </g> 
  946. <g class="traffic-light-color traffic-light-init"> 
  947. <ellipse fill="#5B2942" cx="15" cy="23.5" rx="5.7" ry="5.6"/> 
  948. <ellipse fill="#5B2942" cx="15" cy="10.9" rx="5.7" ry="5.6"/> 
  949. <ellipse fill="#5B2942" cx="15" cy="36.1" rx="5.7" ry="5.6"/> 
  950. </g> 
  951. </g> 
  952. </g> 
  953. </g> 
  954. </svg> 
  955. SVG; 
  956.  
  957.  
  958. /** 
  959. * Generic tab. 
  960. */ 
  961. public function template_generic_tab() { 
  962. // This template belongs to the post scraper so don't echo it if it isn't enqueued. 
  963. if ( ! wp_script_is( WPSEO_Admin_Asset_Manager::PREFIX . 'post-scraper' ) ) { 
  964. return; 
  965.  
  966. echo '<script type="text/html" id="tmpl-generic_tab"> 
  967. <li class="<# if ( data.classes ) { #>{{data.classes}}<# } #><# if ( data.active ) { #> active<# } #>"> 
  968. <a class="wpseo_tablink" href="#wpseo_generic" data-score="{{data.score}}"> 
  969. <span class="wpseo-score-icon {{data.score}}"></span> 
  970. <span class="wpseo-tab-prefix">{{data.prefix}}</span> 
  971. <span class="wpseo-tab-label">{{data.label}}</span> 
  972. <span class="screen-reader-text wpseo-generic-tab-textual-score">{{data.scoreText}}</span> 
  973. </a> 
  974. <# if ( data.hideable ) { #> 
  975. <button type="button" class="remove-tab" aria-label="{{data.removeLabel}}"><span>x</span></button> 
  976. <# } #> 
  977. </li> 
  978. </script>'; 
  979.  
  980. /** 
  981. * Keyword tab for enabling analysis of multiple keywords. 
  982. */ 
  983. public function template_keyword_tab() { 
  984. // This template belongs to the post scraper so don't echo it if it isn't enqueued. 
  985. if ( ! wp_script_is( WPSEO_Admin_Asset_Manager::PREFIX . 'post-scraper' ) ) { 
  986. return; 
  987.  
  988. echo '<script type="text/html" id="tmpl-keyword_tab"> 
  989. <li class="<# if ( data.classes ) { #>{{data.classes}}<# } #><# if ( data.active ) { #> active<# } #>"> 
  990. <a class="wpseo_tablink" href="#wpseo_content" data-keyword="{{data.keyword}}" data-score="{{data.score}}"> 
  991. <span class="wpseo-score-icon {{data.score}}"></span> 
  992. <span class="wpseo-tab-prefix">{{data.prefix}}</span> 
  993. <em class="wpseo-keyword">{{data.label}}</em> 
  994. <span class="screen-reader-text wpseo-keyword-tab-textual-score">{{data.scoreText}}</span> 
  995. </a> 
  996. <# if ( data.hideable ) { #> 
  997. <button type="button" class="remove-keyword" aria-label="{{data.removeLabel}}"><span>x</span></button> 
  998. <# } #> 
  999. </li> 
  1000. </script>'; 
  1001.  
  1002. /** 
  1003. * @param string $page The page to check for the post overview page. 
  1004. * @return bool Whether or not the given page is the post overview page. 
  1005. */ 
  1006. public static function is_post_overview( $page ) { 
  1007. return 'edit.php' === $page; 
  1008.  
  1009. /** 
  1010. * @param string $page The page to check for the post edit page. 
  1011. * @return bool Whether or not the given page is the post edit page. 
  1012. */ 
  1013. public static function is_post_edit( $page ) { 
  1014. return 'post.php' === $page 
  1015. || 'post-new.php' === $page; 
  1016.  
  1017. /********************** DEPRECATED METHODS **********************/ 
  1018.  
  1019. // @codeCoverageIgnoreStart 
  1020. /** 
  1021. * Adds the Yoast SEO box 
  1022. * @deprecated 1.4.24 
  1023. * @deprecated use WPSEO_Metabox::add_meta_box() 
  1024. * @see WPSEO_Meta::add_meta_box() 
  1025. */ 
  1026. public function add_custom_box() { 
  1027. _deprecated_function( __METHOD__, 'WPSEO 1.4.24', 'WPSEO_Metabox::add_meta_box()' ); 
  1028. $this->add_meta_box(); 
  1029.  
  1030. /** 
  1031. * Retrieve the meta boxes for the given post type. 
  1032. * @deprecated 1.5.0 
  1033. * @deprecated use WPSEO_Meta::get_meta_field_defs() 
  1034. * @see WPSEO_Meta::get_meta_field_defs() 
  1035. * @param string $post_type The post type for which to get the meta fields. 
  1036. * @return array 
  1037. */ 
  1038. public function get_meta_boxes( $post_type = 'post' ) { 
  1039. _deprecated_function( __METHOD__, 'WPSEO 1.5.0', 'WPSEO_Meta::get_meta_field_defs()' ); 
  1040.  
  1041. return $this->get_meta_field_defs( 'general', $post_type ); 
  1042.  
  1043. /** 
  1044. * Pass some variables to js 
  1045. * @deprecated 1.5.0 
  1046. * @deprecated use WPSEO_Meta::localize_script() 
  1047. * @see WPSEO_Meta::localize_script() 
  1048. */ 
  1049. public function script() { 
  1050. _deprecated_function( __METHOD__, 'WPSEO 1.5.0', 'WPSEO_Meta::localize_script()' ); 
  1051.  
  1052. return $this->localize_script(); 
  1053.  
  1054. /** 
  1055. * @deprecated 3.0 Removed, use javascript functions instead 
  1056. * @param string $string Deprecated. 
  1057. * @return string 
  1058. */ 
  1059. public function strtolower_utf8( $string ) { 
  1060. _deprecated_function( __METHOD__, 'WPSEO 3.0', __( 'Use javascript instead.', 'wordpress-seo' ) ); 
  1061.  
  1062. return $string; 
  1063.  
  1064. /** 
  1065. * @deprecated 3.0 Removed. 
  1066. * @return array 
  1067. */ 
  1068. public function localize_script() { 
  1069. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1070.  
  1071. return array(); 
  1072.  
  1073. /** 
  1074. * @deprecated 3.0 Removed, use javascript functions instead. 
  1075. * @return string 
  1076. */ 
  1077. public function snippet() { 
  1078. _deprecated_function( __METHOD__, 'WPSEO 3.0', __( 'Use javascript instead.', 'wordpress-seo' ) ); 
  1079.  
  1080. return ''; 
  1081.  
  1082. /** 
  1083. * @deprecated 3.0 Use WPSEO_Meta_Columns::posts_filter_dropdown instead. 
  1084. */ 
  1085. public function posts_filter_dropdown() { 
  1086. _deprecated_function( __METHOD__, 'WPSEO 3.0', 'WPSEO_Metabox_Columns::posts_filter_dropdown' ); 
  1087.  
  1088. /** @var WPSEO_Meta_Columns $meta_columns */ 
  1089. $meta_columns = $GLOBALS['wpseo_meta_columns']; 
  1090. $meta_columns->posts_filter_dropdown(); 
  1091.  
  1092. /** 
  1093. * @deprecated 3.0 Use WPSEO_Meta_Columns::column_heading instead. 
  1094. * @param array $columns Already existing columns. 
  1095. * @return array 
  1096. */ 
  1097. public function column_heading( $columns ) { 
  1098. _deprecated_function( __METHOD__, 'WPSEO 3.0', 'WPSEO_Metabox_Columns::column_heading' ); 
  1099.  
  1100. /** @var WPSEO_Meta_Columns $meta_columns */ 
  1101. $meta_columns = $GLOBALS['wpseo_meta_columns']; 
  1102. return $meta_columns->column_heading( $columns ); 
  1103.  
  1104. /** 
  1105. * @deprecated 3.0 Use WPSEO_Meta_Columns::column_content instead. 
  1106. * @param string $column_name Column to display the content for. 
  1107. * @param int $post_id Post to display the column content for. 
  1108. */ 
  1109. public function column_content( $column_name, $post_id ) { 
  1110. _deprecated_function( __METHOD__, 'WPSEO 3.0', 'WPSEO_Metabox_Columns::column_content' ); 
  1111.  
  1112. /** @var WPSEO_Meta_Columns $meta_columns */ 
  1113. $meta_columns = $GLOBALS['wpseo_meta_columns']; 
  1114. $meta_columns->column_content( $column_name, $post_id ); 
  1115.  
  1116. /** 
  1117. * @deprecated 3.0 Use WPSEO_Meta_Columns::column_sort instead. 
  1118. * @param array $columns appended with their orderby variable. 
  1119. * @return array 
  1120. */ 
  1121. public function column_sort( $columns ) { 
  1122. _deprecated_function( __METHOD__, 'WPSEO 3.0', 'WPSEO_Metabox_Columns::column_sort' ); 
  1123.  
  1124. /** @var WPSEO_Meta_Columns $meta_columns */ 
  1125. $meta_columns = $GLOBALS['wpseo_meta_columns']; 
  1126. return $meta_columns->column_sort( $columns ); 
  1127.  
  1128. /** 
  1129. * @deprecated 3.0 Use WPSEO_Meta_Columns::column_sort_orderby instead. 
  1130. * @param array $vars Query variables. 
  1131. * @return array 
  1132. */ 
  1133. public function column_sort_orderby( $vars ) { 
  1134. _deprecated_function( __METHOD__, 'WPSEO 3.0', 'WPSEO_Metabox_Columns::column_sort_orderby' ); 
  1135.  
  1136. /** @var WPSEO_Meta_Columns $meta_columns */ 
  1137. $meta_columns = $GLOBALS['wpseo_meta_columns']; 
  1138. return $meta_columns->column_sort_orderby( $vars ); 
  1139.  
  1140. /** 
  1141. * @deprecated 3.0 Use WPSEO_Meta_Columns::column_hidden instead. 
  1142. * @param array|false $result The hidden columns. 
  1143. * @param string $option The option name used to set which columns should be hidden. 
  1144. * @param WP_User $user The User. 
  1145. * @return array|false $result 
  1146. */ 
  1147. public function column_hidden( $result, $option, $user ) { 
  1148. _deprecated_function( __METHOD__, 'WPSEO 3.0', 'WPSEO_Metabox_Columns::column_hidden' ); 
  1149.  
  1150. /** @var WPSEO_Meta_Columns $meta_columns */ 
  1151. $meta_columns = $GLOBALS['wpseo_meta_columns']; 
  1152. return $meta_columns->column_hidden( $result, $option, $user ); 
  1153.  
  1154. /** 
  1155. * @deprecated 3.0 Use WPSEO_Meta_Columns::seo_score_posts_where instead. 
  1156. * @param string $where Where clause. 
  1157. * @return string 
  1158. */ 
  1159. public function seo_score_posts_where( $where ) { 
  1160. _deprecated_function( __METHOD__, 'WPSEO 3.0', 'WPSEO_Metabox_Columns::seo_score_posts_where' ); 
  1161.  
  1162. /** @var WPSEO_Meta_Columns $meta_columns */ 
  1163. $meta_columns = $GLOBALS['wpseo_meta_columns']; 
  1164. return $meta_columns->seo_score_posts_where( $where ); 
  1165.  
  1166. /** 
  1167. * @deprecated 3.0 Removed. 
  1168. * @param int $post_id Post to retrieve the title for. 
  1169. * @return string 
  1170. */ 
  1171. public function page_title( $post_id ) { 
  1172. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1173.  
  1174. return ''; 
  1175.  
  1176. /** 
  1177. * @deprecated 3.0 
  1178. * @param array $array Array to sort, array is returned sorted. 
  1179. * @param string $key Key to sort array by. 
  1180. */ 
  1181. public function aasort( &$array, $key ) { 
  1182. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1183.  
  1184.  
  1185. /** 
  1186. * @deprecated 3.0 
  1187. * @param object $post Post to output the page analysis results for. 
  1188. * @return string 
  1189. */ 
  1190. public function linkdex_output( $post ) { 
  1191. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1192.  
  1193. return ''; 
  1194.  
  1195.  
  1196. /** 
  1197. * @deprecated 3.0 
  1198. * @param object $post Post to calculate the results for. 
  1199. * @return array|WP_Error 
  1200. */ 
  1201. public function calculate_results( $post ) { 
  1202. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1203.  
  1204. return array(); 
  1205.  
  1206.  
  1207. /** 
  1208. * @deprecated 3.0 
  1209. * @param WP_Post $post Post object instance. 
  1210. * @return array 
  1211. */ 
  1212. public function get_sample_permalink( $post ) { 
  1213. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1214.  
  1215. return array(); 
  1216.  
  1217. /** 
  1218. * @deprecated 3.0 
  1219. * @param array $results The results array used to store results. 
  1220. * @param int $score_value The score value. 
  1221. * @param string $score_message The score message. 
  1222. * @param string $score_label The label of the score to use in the results array. 
  1223. * @param string $raw_score The raw score, to be used by other filters. 
  1224. */ 
  1225. public function save_score_result( &$results, $score_value, $score_message, $score_label, $raw_score = null ) { 
  1226.  
  1227. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1228.  
  1229. /** 
  1230. * @deprecated 3.0 
  1231. * @param string $input_string String to clean up. 
  1232. * @param bool $remove_optional_characters Whether or not to do a cleanup of optional chars too. 
  1233. * @return string 
  1234. */ 
  1235. public function strip_separators_and_fold( $input_string, $remove_optional_characters ) { 
  1236. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1237.  
  1238. return ''; 
  1239.  
  1240. /** 
  1241. * @deprecated 3.0 
  1242. * @param array $job Job data array. 
  1243. * @param array $results Results set by reference. 
  1244. */ 
  1245. public function check_double_focus_keyword( $job, &$results ) { 
  1246. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1247.  
  1248.  
  1249. /** 
  1250. * @deprecated 3.0 
  1251. * @param string $keyword The keyword to check for stopwords. 
  1252. * @param array $results The results array. 
  1253. */ 
  1254. public function score_keyword( $keyword, &$results ) { 
  1255. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1256.  
  1257. /** 
  1258. * @deprecated 3.0 
  1259. * @param array $job The job array holding both the keyword and the URLs. 
  1260. * @param array $results The results array. 
  1261. */ 
  1262. public function score_url( $job, &$results ) { 
  1263. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1264.  
  1265. /** 
  1266. * @deprecated 3.0 
  1267. * @param array $job The job array holding both the keyword versions. 
  1268. * @param array $results The results array. 
  1269. */ 
  1270. public function score_title( $job, &$results ) { 
  1271. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1272.  
  1273. /** 
  1274. * @deprecated 3.0 
  1275. * @param array $job The job array holding both the keyword versions. 
  1276. * @param array $results The results array. 
  1277. * @param array $anchor_texts The array holding all anchors in the document. 
  1278. * @param array $count The number of anchors in the document, grouped by type. 
  1279. */ 
  1280. public function score_anchor_texts( $job, &$results, $anchor_texts, $count ) { 
  1281. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1282.  
  1283. /** 
  1284. * @deprecated 3.0 
  1285. * @param object $xpath An XPATH object of the current document. 
  1286. * @return array 
  1287. */ 
  1288. public function get_anchor_texts( &$xpath ) { 
  1289. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1290.  
  1291. return array(); 
  1292.  
  1293. /** 
  1294. * @deprecated 3.0 
  1295. * @param object $xpath An XPATH object of the current document. 
  1296. * @return array 
  1297. */ 
  1298. public function get_anchor_count( &$xpath ) { 
  1299. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1300.  
  1301. return array(); 
  1302.  
  1303. /** 
  1304. * @deprecated 3.0 
  1305. * @param array $job The job array holding both the keyword versions. 
  1306. * @param array $results The results array. 
  1307. * @param array $imgs The array with images alt texts. 
  1308. */ 
  1309. public function score_images_alt_text( $job, &$results, $imgs ) { 
  1310. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1311.  
  1312. /** 
  1313. * @deprecated 3.0 
  1314. * @param int $post_id The post to find images in. 
  1315. * @param string $body The post content to find images in. 
  1316. * @param array $imgs The array holding the image information. 
  1317. * @return array The updated images array. 
  1318. */ 
  1319. public function get_images_alt_text( $post_id, $body, $imgs ) { 
  1320. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1321.  
  1322. return array(); 
  1323.  
  1324. /** 
  1325. * @deprecated 3.0 
  1326. * @param array $job The array holding the keywords. 
  1327. * @param array $results The results array. 
  1328. * @param array $headings The headings found in the document. 
  1329. */ 
  1330. public function score_headings( $job, &$results, $headings ) { 
  1331. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1332.  
  1333. /** 
  1334. * @deprecated 3.0 
  1335. * @param string $postcontent Post content to find headings in. 
  1336. * @return array Array of heading texts. 
  1337. */ 
  1338. public function get_headings( $postcontent ) { 
  1339. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1340.  
  1341. return array(); 
  1342.  
  1343. /** 
  1344. * @deprecated 3.0 
  1345. * @param array $job The array holding the keywords. 
  1346. * @param array $results The results array. 
  1347. * @param string $description The meta description. 
  1348. * @param int $maxlength The maximum length of the meta description. 
  1349. */ 
  1350. public function score_description( $job, &$results, $description, $maxlength = 155 ) { 
  1351. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1352.  
  1353. /** 
  1354. * @deprecated 3.0 
  1355. * @param array $job The array holding the keywords. 
  1356. * @param array $results The results array. 
  1357. * @param string $body The body. 
  1358. * @param string $firstp The first paragraph. 
  1359. */ 
  1360. public function score_body( $job, &$results, $body, $firstp ) { 
  1361. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1362.  
  1363. /** 
  1364. * @deprecated 3.0 
  1365. * @param object $post The post object. 
  1366. * @return string The post content. 
  1367. */ 
  1368. public function get_body( $post ) { 
  1369. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1370.  
  1371. return ''; 
  1372.  
  1373. /** 
  1374. * @deprecated 3.0 
  1375. * @param string $body The post content to retrieve the first paragraph from. 
  1376. * @return string 
  1377. */ 
  1378. public function get_first_paragraph( $body ) { 
  1379. _deprecated_function( __METHOD__, 'WPSEO 3.0' ); 
  1380.  
  1381. return ''; 
  1382.  
  1383. /** 
  1384. * @deprecated 3.2 
  1385. * Retrieves the title template. 
  1386. * @param object $post metabox post. 
  1387. * @return string 
  1388. */ 
  1389. public static function get_title_template( $post ) { 
  1390. _deprecated_function( __METHOD__, 'WPSEO 3.2', 'WPSEO_Post_Scraper::get_title_template' ); 
  1391.  
  1392. return ''; 
  1393.  
  1394. /** 
  1395. * @deprecated 3.2 
  1396. * Retrieves the metadesc template. 
  1397. * @param object $post metabox post. 
  1398. * @return string 
  1399. */ 
  1400. public static function get_metadesc_template( $post ) { 
  1401. _deprecated_function( __METHOD__, 'WPSEO 3.2', 'WPSEO_Post_Scraper::get_metadesc_template' ); 
  1402. return ''; 
  1403.  
  1404. /** 
  1405. * @deprecated 3.2 
  1406. * Retrieve a post date when post is published, or return current date when it's not. 
  1407. * @param WP_Post $post The post for which to retrieve the post date. 
  1408. * @return string 
  1409. */ 
  1410. public function get_post_date( $post ) { 
  1411. _deprecated_function( __METHOD__, 'WPSEO 3.2', 'WPSEO_Post_Scraper::get_post_date' ); 
  1412.  
  1413. return ''; 
  1414. // @codeCoverageIgnoreEnd