WPSEO_Meta_Columns

Class WPSEO_Meta_Columns.

Defined (1)

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

/admin/class-meta-columns.php  
  1. class WPSEO_Meta_Columns { 
  2.  
  3. /** 
  4. * @var WPSEO_Metabox_Analysis_SEO 
  5. */ 
  6. private $analysis_seo; 
  7.  
  8. /** 
  9. * @var WPSEO_Metabox_Analysis_Readability 
  10. */ 
  11. private $analysis_readability; 
  12.  
  13. /** 
  14. * When page analysis is enabled, just initialize the hooks 
  15. */ 
  16. public function __construct() { 
  17. if ( apply_filters( 'wpseo_use_page_analysis', true ) === true ) { 
  18. add_action( 'admin_init', array( $this, 'setup_hooks' ) ); 
  19.  
  20. $this->analysis_seo = new WPSEO_Metabox_Analysis_SEO(); 
  21. $this->analysis_readability = new WPSEO_Metabox_Analysis_Readability(); 
  22.  
  23. /** 
  24. * Setting up the hooks 
  25. */ 
  26. public function setup_hooks() { 
  27. $this->set_post_type_hooks(); 
  28.  
  29. if ( $this->analysis_seo->is_enabled() ) { 
  30. add_action( 'restrict_manage_posts', array( $this, 'posts_filter_dropdown' ) ); 
  31.  
  32. add_filter( 'request', array( $this, 'column_sort_orderby' ) ); 
  33.  
  34. /** 
  35. * Adds the column headings for the SEO plugin for edit posts / pages overview 
  36. * @param array $columns Already existing columns. 
  37. * @return array 
  38. */ 
  39. public function column_heading( $columns ) { 
  40. if ( $this->is_metabox_hidden() === true ) { 
  41. return $columns; 
  42.  
  43. $added_columns = array(); 
  44.  
  45. if ( $this->analysis_seo->is_enabled() ) { 
  46. $added_columns['wpseo-score'] = __( 'SEO', 'wordpress-seo' ); 
  47. if ( $this->analysis_readability->is_enabled() ) { 
  48. $added_columns['wpseo-score-readability'] = __( 'Readability', 'wordpress-seo' ); 
  49. $added_columns['wpseo-title'] = __( 'SEO Title', 'wordpress-seo' ); 
  50. $added_columns['wpseo-metadesc'] = __( 'Meta Desc.', 'wordpress-seo' ); 
  51.  
  52. if ( $this->analysis_seo->is_enabled() ) { 
  53. $added_columns['wpseo-focuskw'] = __( 'Focus KW', 'wordpress-seo' ); 
  54.  
  55. return array_merge( $columns, $added_columns ); 
  56.  
  57. /** 
  58. * Display the column content for the given column 
  59. * @param string $column_name Column to display the content for. 
  60. * @param int $post_id Post to display the column content for. 
  61. */ 
  62. public function column_content( $column_name, $post_id ) { 
  63. if ( $this->is_metabox_hidden() === true ) { 
  64. return; 
  65.  
  66. switch ( $column_name ) { 
  67. case 'wpseo-score' : 
  68. echo $this->parse_column_score( $post_id ); 
  69. break; 
  70. case 'wpseo-score-readability': 
  71. echo $this->parse_column_score_readability( $post_id ); 
  72. break; 
  73. case 'wpseo-title' : 
  74. echo esc_html( apply_filters( 'wpseo_title', wpseo_replace_vars( $this->page_title( $post_id ), get_post( $post_id, ARRAY_A ) ) ) ); 
  75. break; 
  76. case 'wpseo-metadesc' : 
  77. $metadesc_val = apply_filters( 'wpseo_metadesc', wpseo_replace_vars( WPSEO_Meta::get_value( 'metadesc', $post_id ), get_post( $post_id, ARRAY_A ) ) ); 
  78. $metadesc = ( '' === $metadesc_val ) ? '<span aria-hidden="true">—</span><span class="screen-reader-text">' . __( 'Meta description not set.', 'wordpress-seo' ) . '</span>' : esc_html( $metadesc_val ); 
  79. echo $metadesc; 
  80. break; 
  81. case 'wpseo-focuskw' : 
  82. $focuskw_val = WPSEO_Meta::get_value( 'focuskw', $post_id ); 
  83. $focuskw = ( '' === $focuskw_val ) ? '<span aria-hidden="true">—</span><span class="screen-reader-text">' . __( 'Focus keyword not set.', 'wordpress-seo' ) . '</span>' : esc_html( $focuskw_val ); 
  84. echo $focuskw; 
  85. break; 
  86.  
  87. /** 
  88. * Indicate which of the SEO columns are sortable. 
  89. * @param array $columns appended with their orderby variable. 
  90. * @return array 
  91. */ 
  92. public function column_sort( $columns ) { 
  93. if ( $this->is_metabox_hidden() === true ) { 
  94. return $columns; 
  95.  
  96. $columns['wpseo-metadesc'] = 'wpseo-metadesc'; 
  97.  
  98. if ( $this->analysis_seo->is_enabled() ) { 
  99. $columns['wpseo-focuskw'] = 'wpseo-focuskw'; 
  100.  
  101. return $columns; 
  102.  
  103. /** 
  104. * Hide the SEO Title, Meta Desc and Focus KW columns if the user hasn't chosen which columns to hide 
  105. * @param array|false $result The hidden columns. 
  106. * @param string $option The option name used to set which columns should be hidden. 
  107. * @param WP_User $user The User. 
  108. * @return array|false $result 
  109. */ 
  110. public function column_hidden( $result, $option, $user ) { 
  111. global $wpdb; 
  112.  
  113. $prefix = $wpdb->get_blog_prefix(); 
  114. if ( ! $user->has_prop( $prefix . $option ) && ! $user->has_prop( $option ) ) { 
  115.  
  116. if ( ! is_array( $result ) ) { 
  117. $result = array(); 
  118.  
  119. array_push( $result, 'wpseo-title', 'wpseo-metadesc' ); 
  120.  
  121. if ( $this->analysis_seo->is_enabled() ) { 
  122. array_push( $result, 'wpseo-focuskw' ); 
  123.  
  124. return $result; 
  125.  
  126. /** 
  127. * Adds a dropdown that allows filtering on the posts SEO Quality. 
  128. * @return void 
  129. */ 
  130. public function posts_filter_dropdown() { 
  131. if ( $GLOBALS['pagenow'] === 'upload.php' || $this->is_metabox_hidden() === true ) { 
  132. return; 
  133.  
  134. $ranks = WPSEO_Rank::get_all_ranks(); 
  135. $current_seo_filter = filter_input( INPUT_GET, 'seo_filter' ); 
  136.  
  137. echo ' 
  138. <label class="screen-reader-text" for="wpseo-filter">' . __( 'Filter by SEO Score', 'wordpress-seo' ) . '</label> 
  139. <select name="seo_filter" id="wpseo-filter"> 
  140. <option value="">', __( 'All SEO Scores', 'wordpress-seo' ), '</option>'; 
  141. foreach ( $ranks as $rank ) { 
  142. $sel = selected( $current_seo_filter, $rank->get_rank(), false ); 
  143. echo ' 
  144. <option ', $sel, 'value="', $rank->get_rank(), '">', $rank->get_drop_down_label(), '</option>'; 
  145. echo ' 
  146. </select>'; 
  147.  
  148. /** 
  149. * Modify the query based on the seo_filter variable in $_GET 
  150. * @param array $vars Query variables. 
  151. * @return array 
  152. */ 
  153. public function column_sort_orderby( $vars ) { 
  154. if ( $seo_filter = filter_input( INPUT_GET, 'seo_filter' ) ) { 
  155. $rank = new WPSEO_Rank( $seo_filter ); 
  156.  
  157. if ( WPSEO_Rank::NO_FOCUS === $seo_filter || WPSEO_Rank::NO_INDEX === $seo_filter ) { 
  158. $vars = $this->filter_other( $vars, $seo_filter ); 
  159. else { 
  160. $vars = array_merge( $vars, $this->filter_scored( $rank->get_starting_score(), $rank->get_end_score() ) ); 
  161.  
  162. if ( $seo_kw_filter = filter_input( INPUT_GET, 'seo_kw_filter' ) ) { 
  163. $vars = array_merge( 
  164. $vars, array( 
  165. 'post_type' => get_query_var( 'post_type', 'post' ),  
  166. 'meta_key' => WPSEO_Meta::$meta_prefix . 'focuskw',  
  167. 'meta_value' => sanitize_text_field( $seo_kw_filter ),  
  168. ); 
  169.  
  170. if ( isset( $vars['orderby'] ) ) { 
  171. $vars = array_merge( $vars, $this->filter_order_by( $vars['orderby'] ) ); 
  172.  
  173. return $vars; 
  174.  
  175. /** 
  176. * When there is a score just return this meta query array 
  177. * @param string $low The lowest number in the score range. 
  178. * @param string $high The highest number in the score range. 
  179. * @return array 
  180. */ 
  181. private function filter_scored( $low, $high ) { 
  182. /** 
  183. * @internal DON'T touch the order of these without double-checking/adjusting the seo_score_posts_where() method below! 
  184. */ 
  185. return array( 
  186. 'meta_query' => array( 
  187. 'relation' => 'AND',  
  188. array( 
  189. 'key' => WPSEO_Meta::$meta_prefix . 'linkdex',  
  190. 'value' => array( $low, $high ),  
  191. 'type' => 'numeric',  
  192. 'compare' => 'BETWEEN',  
  193. ),  
  194. array( 
  195. 'relation' => 'OR',  
  196. array( 
  197. 'key' => WPSEO_Meta::$meta_prefix . 'meta-robots-noindex',  
  198. 'compare' => 'NOT EXISTS',  
  199. ),  
  200. array( 
  201. 'key' => WPSEO_Meta::$meta_prefix . 'meta-robots-noindex',  
  202. 'value' => '1',  
  203. 'compare' => '!=',  
  204. ),  
  205. ),  
  206. ),  
  207. ); 
  208.  
  209. /** 
  210. * Get vars for noindex or na filters 
  211. * @param array $vars The unmerged vars. 
  212. * @param string $seo_filter The SEO filter. 
  213. * @return array 
  214. */ 
  215. private function filter_other( $vars, $seo_filter ) { 
  216. switch ( $seo_filter ) { 
  217. case 'noindex': 
  218. $vars = array_merge( 
  219. $vars,  
  220. array( 
  221. 'meta_query' => array( 
  222. array( 
  223. 'key' => WPSEO_Meta::$meta_prefix . 'meta-robots-noindex',  
  224. 'value' => '1',  
  225. 'compare' => '=',  
  226. ),  
  227. ),  
  228. ); 
  229. break; 
  230. case 'na': 
  231. $vars = array_merge( 
  232. $vars,  
  233. array( 
  234. 'meta_query' => array( 
  235. 'relation' => 'AND',  
  236. array( 
  237. 'key' => WPSEO_Meta::$meta_prefix . 'meta-robots-noindex',  
  238. 'value' => 'needs-a-value-anyway',  
  239. 'compare' => 'NOT EXISTS',  
  240. ),  
  241. array( 
  242. 'key' => WPSEO_Meta::$meta_prefix . 'linkdex',  
  243. 'value' => 'needs-a-value-anyway',  
  244. 'compare' => 'NOT EXISTS',  
  245. ),  
  246. ); 
  247. break; 
  248.  
  249. return $vars; 
  250.  
  251. /** 
  252. * Returning filters when $order_by is matched in the if-statement 
  253. * @param string $order_by The ID of the column by which to order the posts. 
  254. * @return array 
  255. */ 
  256. private function filter_order_by( $order_by ) { 
  257. switch ( $order_by ) { 
  258. case 'wpseo-metadesc' : 
  259. return array( 
  260. 'meta_key' => WPSEO_Meta::$meta_prefix . 'metadesc',  
  261. 'orderby' => 'meta_value',  
  262. ); 
  263. break; 
  264. case 'wpseo-focuskw' : 
  265. return array( 
  266. 'meta_key' => WPSEO_Meta::$meta_prefix . 'focuskw',  
  267. 'orderby' => 'meta_value',  
  268. ); 
  269. break; 
  270.  
  271. return array(); 
  272.  
  273. /** 
  274. * Parsing the score column 
  275. * @param integer $post_id The ID of the post for which to show the score. 
  276. * @return string The HTML for the SEO score indicator. 
  277. */ 
  278. private function parse_column_score( $post_id ) { 
  279. if ( '1' === WPSEO_Meta::get_value( 'meta-robots-noindex', $post_id ) ) { 
  280. $rank = new WPSEO_Rank( WPSEO_Rank::NO_INDEX ); 
  281. $title = __( 'Post is set to noindex.', 'wordpress-seo' ); 
  282. WPSEO_Meta::set_value( 'linkdex', 0, $post_id ); 
  283. elseif ( '' === WPSEO_Meta::get_value( 'focuskw', $post_id ) ) { 
  284. $rank = new WPSEO_Rank( WPSEO_Rank::NO_FOCUS ); 
  285. $title = __( 'Focus keyword not set.', 'wordpress-seo' ); 
  286. else { 
  287. $score = (int) WPSEO_Meta::get_value( 'linkdex', $post_id ); 
  288. $rank = WPSEO_Rank::from_numeric_score( $score ); 
  289. $title = $rank->get_label(); 
  290.  
  291. return $this->render_score_indicator( $rank, $title ); 
  292.  
  293. /** 
  294. * Parsing the readability score column. 
  295. * @param int $post_id The ID of the post for which to show the readability score. 
  296. * @return string The HTML for the readability score indicator. 
  297. */ 
  298. private function parse_column_score_readability( $post_id ) { 
  299. $score = (int) WPSEO_Meta::get_value( 'content_score', $post_id ); 
  300. $rank = WPSEO_Rank::from_numeric_score( $score ); 
  301.  
  302. return $this->render_score_indicator( $rank ); 
  303.  
  304. /** 
  305. * Setting the hooks for the post_types 
  306. */ 
  307. private function set_post_type_hooks() { 
  308. $post_types = get_post_types( array( 'public' => true ), 'names' ); 
  309.  
  310. if ( is_array( $post_types ) && $post_types !== array() ) { 
  311. foreach ( $post_types as $pt ) { 
  312. if ( $this->is_metabox_hidden( $pt ) === false ) { 
  313. add_filter( 'manage_' . $pt . '_posts_columns', array( $this, 'column_heading' ), 10, 1 ); 
  314. add_action( 'manage_' . $pt . '_posts_custom_column', array( 
  315. $this,  
  316. 'column_content',  
  317. ), 10, 2 ); 
  318. add_action( 'manage_edit-' . $pt . '_sortable_columns', array( 
  319. $this,  
  320. 'column_sort',  
  321. ), 10, 2 ); 
  322.  
  323. /** 
  324. * Use the `get_user_option_{$option}` filter to change the output of the get_user_option 
  325. * function for the `manage{$screen}columnshidden` option, which is based on the current 
  326. * admin screen. The admin screen we want to target is the `edit-{$post_type}` screen. 
  327. */ 
  328. $filter = sprintf( 'get_user_option_%s', sprintf( 'manage%scolumnshidden', 'edit-' . $pt ) ); 
  329. add_filter( $filter, array( $this, 'column_hidden' ), 10, 3 ); 
  330. unset( $pt ); 
  331.  
  332. /** 
  333. * Test whether the metabox should be hidden either by choice of the admin or because 
  334. * the post type is not a public post type 
  335. * @since 1.5.0 
  336. * @param string $post_type (optional) The post type to test, defaults to the current post post_type. 
  337. * @return bool Whether or not the meta box (and associated columns etc) should be hidden 
  338. */ 
  339. private function is_metabox_hidden( $post_type = null ) { 
  340. if ( ! isset( $post_type ) && $get_post_type = filter_input( INPUT_GET, 'post_type' ) ) { 
  341. $post_type = sanitize_text_field( $get_post_type ); 
  342.  
  343. if ( isset( $post_type ) ) { 
  344. // Don't make static as post_types may still be added during the run. 
  345. $cpts = get_post_types( array( 'public' => true ), 'names' ); 
  346. $options = get_option( 'wpseo_titles' ); 
  347.  
  348. return ( ( isset( $options[ 'hideeditbox-' . $post_type ] ) && $options[ 'hideeditbox-' . $post_type ] === true ) || in_array( $post_type, $cpts ) === false ); 
  349.  
  350. return false; 
  351.  
  352. /** 
  353. * Retrieve the page title. 
  354. * @param int $post_id Post to retrieve the title for. 
  355. * @return string 
  356. */ 
  357. private function page_title( $post_id ) { 
  358. $fixed_title = WPSEO_Meta::get_value( 'title', $post_id ); 
  359. if ( $fixed_title !== '' ) { 
  360. return $fixed_title; 
  361.  
  362. $post = get_post( $post_id ); 
  363. $options = WPSEO_Options::get_option( 'wpseo_titles' ); 
  364. if ( is_object( $post ) && ( isset( $options[ 'title-' . $post->post_type ] ) && $options[ 'title-' . $post->post_type ] !== '' ) ) { 
  365. $title_template = $options[ 'title-' . $post->post_type ]; 
  366. $title_template = str_replace( ' %%page%% ', ' ', $title_template ); 
  367.  
  368. return wpseo_replace_vars( $title_template, $post ); 
  369.  
  370. return wpseo_replace_vars( '%%title%%', $post ); 
  371.  
  372. /** 
  373. * @param WPSEO_Rank $rank The rank this indicator should have. 
  374. * @param string $title Optional. The title for this rank, defaults to the title of the rank. 
  375. * @return string The HTML for a score indicator. 
  376. */ 
  377. private function render_score_indicator( $rank, $title = '' ) { 
  378. if ( empty( $title ) ) { 
  379. $title = $rank->get_label(); 
  380.  
  381. return '<div aria-hidden="true" title="' . esc_attr( $title ) . '" class="wpseo-score-icon ' . esc_attr( $rank->get_css_class() ) . '"></div><span class="screen-reader-text">' . $title . '</span>'; 
  382.  
  383. /** 
  384. * Hacky way to get round the limitation that you can only have AND *or* OR relationship between 
  385. * meta key clauses and not a combination - which is what we need. 
  386. * @deprecated 3.5 Unnecessary with nested meta queries in core. 
  387. * @codeCoverageIgnore 
  388. * @param string $where Where clause. 
  389. * @return string 
  390. */ 
  391. public function seo_score_posts_where( $where ) { 
  392.  
  393. _deprecated_function( __METHOD__, '3.5' ); 
  394.  
  395. global $wpdb; 
  396.  
  397. /** Find the two mutually exclusive noindex clauses which should be changed from AND to OR relation */ 
  398. $find = '`([\s]+AND[\s]+)((?:' . $wpdb->prefix . 'postmeta|mt[0-9]|mt1)\.post_id IS NULL[\s]+)AND([\s]+\([\s]*(?:' . $wpdb->prefix . 'postmeta|mt[0-9])\.meta_key = \'' . WPSEO_Meta::$meta_prefix . 'meta-robots-noindex\' AND CAST\([^\)]+\)[^\)]+\))`'; 
  399.  
  400. $replace = '$1( $2OR$3 )'; 
  401.  
  402. $new_where = preg_replace( $find, $replace, $where ); 
  403.  
  404. if ( $new_where ) { 
  405. return $new_where; 
  406. return $where;