PluginProbe ʕ •ᴥ•ʔ
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 18.0
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v18.0
27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 19.1 19.10 19.11 19.12 19.13 19.14 19.2 19.3 19.4 19.5 19.5.1 19.6 19.6.1 19.7 19.7.1 19.7.2 19.8 19.9 20.0 20.1 20.10 20.11 20.12 20.13 20.2 20.2.1 20.3 20.4 20.5 20.6 20.7 20.8 20.9 21.0 21.1 21.2 21.3 21.4 21.5 21.6 21.7 21.8 21.8.1 21.9 21.9.1 22.0 22.1 22.2 22.3 22.4 22.5 22.6 22.7 22.8 22.9 23.0 23.1 23.2 23.3 23.4 23.5 23.6 23.7 23.8 23.9 24.0 24.1 24.2 24.3 24.4 24.5 24.6 24.7 24.8 24.8.1 24.9 25.0 25.1 25.2 25.3 25.3.1 25.4 25.5 25.6 25.7 25.8 25.9 26.0 26.1 26.1.1 26.2 26.3 26.4 26.5 26.6 26.7 26.8 26.9 27.0 27.1 27.1.1 27.2 27.3 27.4
wordpress-seo / admin / class-meta-columns.php
wordpress-seo / admin Last commit date
ajax 5 years ago capabilities 4 years ago endpoints 5 years ago exceptions 7 years ago filters 4 years ago formatter 4 years ago google_search_console 5 years ago import 4 years ago listeners 8 years ago menu 4 years ago metabox 4 years ago notifiers 4 years ago pages 4 years ago roles 5 years ago ryte 5 years ago services 5 years ago statistics 5 years ago taxonomy 4 years ago tracking 4 years ago views 4 years ago watchers 5 years ago admin-settings-changed-listener.php 5 years ago ajax.php 4 years ago class-admin-asset-analysis-worker-location.php 5 years ago class-admin-asset-dev-server-location.php 5 years ago class-admin-asset-location.php 8 years ago class-admin-asset-manager.php 4 years ago class-admin-asset-seo-location.php 4 years ago class-admin-asset-yoast-components-l10n.php 5 years ago class-admin-editor-specific-replace-vars.php 5 years ago class-admin-gutenberg-compatibility-notification.php 5 years ago class-admin-help-panel.php 5 years ago class-admin-init.php 4 years ago class-admin-recommended-replace-vars.php 6 years ago class-admin-user-profile.php 6 years ago class-admin-utils.php 5 years ago class-admin.php 4 years ago class-asset.php 5 years ago class-bulk-description-editor-list-table.php 5 years ago class-bulk-editor-list-table.php 4 years ago class-bulk-title-editor-list-table.php 6 years ago class-collector.php 6 years ago class-config.php 4 years ago class-customizer.php 5 years ago class-database-proxy.php 5 years ago class-export.php 5 years ago class-expose-shortlinks.php 4 years ago class-gutenberg-compatibility.php 4 years ago class-helpscout.php 5 years ago class-meta-columns.php 5 years ago class-my-yoast-proxy.php 5 years ago class-option-tab.php 4 years ago class-option-tabs-formatter.php 5 years ago class-option-tabs.php 5 years ago class-paper-presenter.php 5 years ago class-plugin-availability.php 5 years ago class-plugin-conflict.php 4 years ago class-premium-popup.php 5 years ago class-premium-upsell-admin-block.php 4 years ago class-primary-term-admin.php 5 years ago class-product-upsell-notice.php 5 years ago class-remote-request.php 5 years ago class-schema-person-upgrade-notification.php 4 years ago class-suggested-plugins.php 4 years ago class-yoast-columns.php 5 years ago class-yoast-dashboard-widget.php 4 years ago class-yoast-form.php 4 years ago class-yoast-input-validation.php 5 years ago class-yoast-network-admin.php 5 years ago class-yoast-network-settings-api.php 4 years ago class-yoast-notification-center.php 4 years ago class-yoast-notification.php 5 years ago class-yoast-notifications.php 5 years ago class-yoast-plugin-conflict.php 4 years ago index.php 10 years ago interface-collection.php 7 years ago interface-installable.php 8 years ago
class-meta-columns.php
752 lines
1 <?php
2 /**
3 * WPSEO plugin file.
4 *
5 * @package WPSEO\Admin
6 */
7
8 use Yoast\WP\SEO\Context\Meta_Tags_Context;
9 use Yoast\WP\SEO\Integrations\Admin\Admin_Columns_Cache_Integration;
10 use Yoast\WP\SEO\Surfaces\Values\Meta;
11
12 /**
13 * Class WPSEO_Meta_Columns.
14 */
15 class WPSEO_Meta_Columns {
16
17 /**
18 * Holds the context objects for each indexable.
19 *
20 * @var Meta_Tags_Context[]
21 */
22 protected $context = [];
23
24 /**
25 * Holds the SEO analysis.
26 *
27 * @var WPSEO_Metabox_Analysis_SEO
28 */
29 private $analysis_seo;
30
31 /**
32 * Holds the readability analysis.
33 *
34 * @var WPSEO_Metabox_Analysis_Readability
35 */
36 private $analysis_readability;
37
38 /**
39 * Admin columns cache.
40 *
41 * @var Admin_Columns_Cache_Integration
42 */
43 private $admin_columns_cache;
44
45 /**
46 * When page analysis is enabled, just initialize the hooks.
47 */
48 public function __construct() {
49 if ( apply_filters( 'wpseo_use_page_analysis', true ) === true ) {
50 add_action( 'admin_init', [ $this, 'setup_hooks' ] );
51 }
52
53 $this->analysis_seo = new WPSEO_Metabox_Analysis_SEO();
54 $this->analysis_readability = new WPSEO_Metabox_Analysis_Readability();
55 $this->admin_columns_cache = YoastSEO()->classes->get( Admin_Columns_Cache_Integration::class );
56 }
57
58 /**
59 * Sets up up the hooks.
60 */
61 public function setup_hooks() {
62 $this->set_post_type_hooks();
63
64 if ( $this->analysis_seo->is_enabled() ) {
65 add_action( 'restrict_manage_posts', [ $this, 'posts_filter_dropdown' ] );
66 }
67
68 if ( $this->analysis_readability->is_enabled() ) {
69 add_action( 'restrict_manage_posts', [ $this, 'posts_filter_dropdown_readability' ] );
70 }
71
72 add_filter( 'request', [ $this, 'column_sort_orderby' ] );
73 add_filter( 'default_hidden_columns', [ $this, 'column_hidden' ], 10, 1 );
74 }
75
76 /**
77 * Adds the column headings for the SEO plugin for edit posts / pages overview.
78 *
79 * @param array $columns Already existing columns.
80 *
81 * @return array Array containing the column headings.
82 */
83 public function column_heading( $columns ) {
84 if ( $this->display_metabox() === false ) {
85 return $columns;
86 }
87
88 $added_columns = [];
89
90 if ( $this->analysis_seo->is_enabled() ) {
91 $added_columns['wpseo-score'] = '<span class="yoast-tooltip yoast-tooltip-n yoast-tooltip-alt" data-label="' . esc_attr__( 'SEO score', 'wordpress-seo' ) . '"><span class="yoast-column-seo-score yoast-column-header-has-tooltip"><span class="screen-reader-text">' . __( 'SEO score', 'wordpress-seo' ) . '</span></span></span>';
92 }
93
94 if ( $this->analysis_readability->is_enabled() ) {
95 $added_columns['wpseo-score-readability'] = '<span class="yoast-tooltip yoast-tooltip-n yoast-tooltip-alt" data-label="' . esc_attr__( 'Readability score', 'wordpress-seo' ) . '"><span class="yoast-column-readability yoast-column-header-has-tooltip"><span class="screen-reader-text">' . __( 'Readability score', 'wordpress-seo' ) . '</span></span></span>';
96 }
97
98 $added_columns['wpseo-title'] = __( 'SEO Title', 'wordpress-seo' );
99 $added_columns['wpseo-metadesc'] = __( 'Meta Desc.', 'wordpress-seo' );
100
101 if ( $this->analysis_seo->is_enabled() ) {
102 $added_columns['wpseo-focuskw'] = __( 'Keyphrase', 'wordpress-seo' );
103 }
104
105 return array_merge( $columns, $added_columns );
106 }
107
108 /**
109 * Displays the column content for the given column.
110 *
111 * @param string $column_name Column to display the content for.
112 * @param int $post_id Post to display the column content for.
113 */
114 public function column_content( $column_name, $post_id ) {
115 if ( $this->display_metabox() === false ) {
116 return;
117 }
118
119 switch ( $column_name ) {
120 case 'wpseo-score':
121 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Correctly escaped in render_score_indicator() method.
122 echo $this->parse_column_score( $post_id );
123 return;
124
125 case 'wpseo-score-readability':
126 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Correctly escaped in render_score_indicator() method.
127 echo $this->parse_column_score_readability( $post_id );
128 return;
129
130 case 'wpseo-title':
131 echo esc_html( $this->get_meta( $post_id )->title );
132 return;
133
134 case 'wpseo-metadesc':
135 $metadesc_val = $this->get_meta( $post_id )->meta_description;
136
137 if ( $metadesc_val === '' ) {
138 echo '<span aria-hidden="true">&#8212;</span><span class="screen-reader-text">',
139 esc_html__( 'Meta description not set.', 'wordpress-seo' ),
140 '</span>';
141 return;
142 }
143
144 echo esc_html( $metadesc_val );
145 return;
146
147 case 'wpseo-focuskw':
148 $focuskw_val = WPSEO_Meta::get_value( 'focuskw', $post_id );
149
150 if ( $focuskw_val === '' ) {
151 echo '<span aria-hidden="true">&#8212;</span><span class="screen-reader-text">',
152 esc_html__( 'Focus keyphrase not set.', 'wordpress-seo' ),
153 '</span>';
154 return;
155 }
156
157 echo esc_html( $focuskw_val );
158 return;
159 }
160 }
161
162 /**
163 * Indicates which of the SEO columns are sortable.
164 *
165 * @param array $columns Appended with their orderby variable.
166 *
167 * @return array Array containing the sortable columns.
168 */
169 public function column_sort( $columns ) {
170 if ( $this->display_metabox() === false ) {
171 return $columns;
172 }
173
174 $columns['wpseo-metadesc'] = 'wpseo-metadesc';
175
176 if ( $this->analysis_seo->is_enabled() ) {
177 $columns['wpseo-focuskw'] = 'wpseo-focuskw';
178 }
179
180 return $columns;
181 }
182
183 /**
184 * Hides the SEO title, meta description and focus keyword columns if the user hasn't chosen which columns to hide.
185 *
186 * @param array $hidden The hidden columns.
187 *
188 * @return array Array containing the columns to hide.
189 */
190 public function column_hidden( $hidden ) {
191 if ( ! is_array( $hidden ) ) {
192 $hidden = [];
193 }
194
195 array_push( $hidden, 'wpseo-title', 'wpseo-metadesc' );
196
197 if ( $this->analysis_seo->is_enabled() ) {
198 $hidden[] = 'wpseo-focuskw';
199 }
200
201 return $hidden;
202 }
203
204 /**
205 * Adds a dropdown that allows filtering on the posts SEO Quality.
206 */
207 public function posts_filter_dropdown() {
208 if ( ! $this->can_display_filter() ) {
209 return;
210 }
211
212 $ranks = WPSEO_Rank::get_all_ranks();
213
214 echo '<label class="screen-reader-text" for="wpseo-filter">' . esc_html__( 'Filter by SEO Score', 'wordpress-seo' ) . '</label>';
215 echo '<select name="seo_filter" id="wpseo-filter">';
216
217 // phpcs:ignore WordPress.Security.EscapeOutput -- Output is correctly escaped in the generate_option() method.
218 echo $this->generate_option( '', __( 'All SEO Scores', 'wordpress-seo' ) );
219
220 foreach ( $ranks as $rank ) {
221 $selected = selected( $this->get_current_seo_filter(), $rank->get_rank(), false );
222
223 // phpcs:ignore WordPress.Security.EscapeOutput -- Output is correctly escaped in the generate_option() method.
224 echo $this->generate_option( $rank->get_rank(), $rank->get_drop_down_label(), $selected );
225 }
226
227 echo '</select>';
228 }
229
230 /**
231 * Adds a dropdown that allows filtering on the posts Readability Quality.
232 *
233 * @return void
234 */
235 public function posts_filter_dropdown_readability() {
236 if ( ! $this->can_display_filter() ) {
237 return;
238 }
239
240 $ranks = WPSEO_Rank::get_all_readability_ranks();
241
242 echo '<label class="screen-reader-text" for="wpseo-readability-filter">' . esc_html__( 'Filter by Readability Score', 'wordpress-seo' ) . '</label>';
243 echo '<select name="readability_filter" id="wpseo-readability-filter">';
244
245 // phpcs:ignore WordPress.Security.EscapeOutput -- Output is correctly escaped in the generate_option() method.
246 echo $this->generate_option( '', __( 'All Readability Scores', 'wordpress-seo' ) );
247
248 foreach ( $ranks as $rank ) {
249 $selected = selected( $this->get_current_readability_filter(), $rank->get_rank(), false );
250
251 // phpcs:ignore WordPress.Security.EscapeOutput -- Output is correctly escaped in the generate_option() method.
252 echo $this->generate_option( $rank->get_rank(), $rank->get_drop_down_readability_labels(), $selected );
253 }
254
255 echo '</select>';
256 }
257
258 /**
259 * Generates an <option> element.
260 *
261 * @param string $value The option's value.
262 * @param string $label The option's label.
263 * @param string $selected HTML selected attribute for an option.
264 *
265 * @return string The generated <option> element.
266 */
267 protected function generate_option( $value, $label, $selected = '' ) {
268 return '<option ' . $selected . ' value="' . esc_attr( $value ) . '">' . esc_html( $label ) . '</option>';
269 }
270
271 /**
272 * Returns the meta object for a given post ID.
273 *
274 * @param int $post_id The post ID.
275 *
276 * @return Meta The meta object.
277 */
278 protected function get_meta( $post_id ) {
279 $indexable = $this->admin_columns_cache->get_indexable( $post_id );
280
281 return YoastSEO()->meta->for_indexable( $indexable, 'Post_Type' );
282 }
283
284 /**
285 * Determines the SEO score filter to be later used in the meta query, based on the passed SEO filter.
286 *
287 * @param string $seo_filter The SEO filter to use to determine what further filter to apply.
288 *
289 * @return array The SEO score filter.
290 */
291 protected function determine_seo_filters( $seo_filter ) {
292 if ( $seo_filter === WPSEO_Rank::NO_FOCUS ) {
293 return $this->create_no_focus_keyword_filter();
294 }
295
296 if ( $seo_filter === WPSEO_Rank::NO_INDEX ) {
297 return $this->create_no_index_filter();
298 }
299
300 $rank = new WPSEO_Rank( $seo_filter );
301
302 return $this->create_seo_score_filter( $rank->get_starting_score(), $rank->get_end_score() );
303 }
304
305 /**
306 * Determines the Readability score filter to the meta query, based on the passed Readability filter.
307 *
308 * @param string $readability_filter The Readability filter to use to determine what further filter to apply.
309 *
310 * @return array The Readability score filter.
311 */
312 protected function determine_readability_filters( $readability_filter ) {
313 $rank = new WPSEO_Rank( $readability_filter );
314
315 return $this->create_readability_score_filter( $rank->get_starting_score(), $rank->get_end_score() );
316 }
317
318 /**
319 * Creates a keyword filter for the meta query, based on the passed Keyword filter.
320 *
321 * @param string $keyword_filter The keyword filter to use.
322 *
323 * @return array The keyword filter.
324 */
325 protected function get_keyword_filter( $keyword_filter ) {
326 return [
327 'post_type' => get_query_var( 'post_type', 'post' ),
328 'key' => WPSEO_Meta::$meta_prefix . 'focuskw',
329 'value' => sanitize_text_field( $keyword_filter ),
330 ];
331 }
332
333 /**
334 * Determines whether the passed filter is considered to be valid.
335 *
336 * @param mixed $filter The filter to check against.
337 *
338 * @return bool Whether or not the filter is considered valid.
339 */
340 protected function is_valid_filter( $filter ) {
341 return ! empty( $filter ) && is_string( $filter );
342 }
343
344 /**
345 * Collects the filters and merges them into a single array.
346 *
347 * @return array Array containing all the applicable filters.
348 */
349 protected function collect_filters() {
350 $active_filters = [];
351
352 $seo_filter = $this->get_current_seo_filter();
353 $readability_filter = $this->get_current_readability_filter();
354 $current_keyword_filter = $this->get_current_keyword_filter();
355
356 if ( $this->is_valid_filter( $seo_filter ) ) {
357 $active_filters = array_merge(
358 $active_filters,
359 $this->determine_seo_filters( $seo_filter )
360 );
361 }
362
363 if ( $this->is_valid_filter( $readability_filter ) ) {
364 $active_filters = array_merge(
365 $active_filters,
366 $this->determine_readability_filters( $readability_filter )
367 );
368 }
369
370 if ( $this->is_valid_filter( $current_keyword_filter ) ) {
371 $active_filters = array_merge(
372 $active_filters,
373 $this->get_keyword_filter( $current_keyword_filter )
374 );
375 }
376
377 return $active_filters;
378 }
379
380 /**
381 * Modify the query based on the filters that are being passed.
382 *
383 * @param array $vars Query variables that need to be modified based on the filters.
384 *
385 * @return array Array containing the meta query to use for filtering the posts overview.
386 */
387 public function column_sort_orderby( $vars ) {
388 $collected_filters = $this->collect_filters();
389
390 if ( isset( $vars['orderby'] ) ) {
391 $vars = array_merge( $vars, $this->filter_order_by( $vars['orderby'] ) );
392 }
393
394 return $this->build_filter_query( $vars, $collected_filters );
395 }
396
397 /**
398 * Retrieves the meta robots query values to be used within the meta query.
399 *
400 * @return array Array containing the query parameters regarding meta robots.
401 */
402 protected function get_meta_robots_query_values() {
403 return [
404 'relation' => 'OR',
405 [
406 'key' => WPSEO_Meta::$meta_prefix . 'meta-robots-noindex',
407 'compare' => 'NOT EXISTS',
408 ],
409 [
410 'key' => WPSEO_Meta::$meta_prefix . 'meta-robots-noindex',
411 'value' => '1',
412 'compare' => '!=',
413 ],
414 ];
415 }
416
417 /**
418 * Determines the score filters to be used. If more than one is passed, it created an AND statement for the query.
419 *
420 * @param array $score_filters Array containing the score filters.
421 *
422 * @return array Array containing the score filters that need to be applied to the meta query.
423 */
424 protected function determine_score_filters( $score_filters ) {
425 if ( count( $score_filters ) > 1 ) {
426 return array_merge( [ 'relation' => 'AND' ], $score_filters );
427 }
428
429 return $score_filters;
430 }
431
432 /**
433 * Retrieves the post type from the $_GET variable.
434 *
435 * @return string The current post type.
436 */
437 public function get_current_post_type() {
438 return filter_input( INPUT_GET, 'post_type' );
439 }
440
441 /**
442 * Retrieves the SEO filter from the $_GET variable.
443 *
444 * @return string The current post type.
445 */
446 public function get_current_seo_filter() {
447 return filter_input( INPUT_GET, 'seo_filter' );
448 }
449
450 /**
451 * Retrieves the Readability filter from the $_GET variable.
452 *
453 * @return string The current post type.
454 */
455 public function get_current_readability_filter() {
456 return filter_input( INPUT_GET, 'readability_filter' );
457 }
458
459 /**
460 * Retrieves the keyword filter from the $_GET variable.
461 *
462 * @return string The current post type.
463 */
464 public function get_current_keyword_filter() {
465 return filter_input( INPUT_GET, 'seo_kw_filter' );
466 }
467
468 /**
469 * Uses the vars to create a complete filter query that can later be executed to filter out posts.
470 *
471 * @param array $vars Array containing the variables that will be used in the meta query.
472 * @param array $filters Array containing the filters that we need to apply in the meta query.
473 *
474 * @return array Array containing the complete filter query.
475 */
476 protected function build_filter_query( $vars, $filters ) {
477 // If no filters were applied, just return everything.
478 if ( count( $filters ) === 0 ) {
479 return $vars;
480 }
481
482 $result = [ 'meta_query' => [] ];
483 $result['meta_query'] = array_merge( $result['meta_query'], [ $this->determine_score_filters( $filters ) ] );
484
485 $current_seo_filter = $this->get_current_seo_filter();
486
487 // This only applies for the SEO score filter because it can because the SEO score can be altered by the no-index option.
488 if ( $this->is_valid_filter( $current_seo_filter ) && ! in_array( $current_seo_filter, [ WPSEO_Rank::NO_INDEX, WPSEO_Rank::NO_FOCUS ], true ) ) {
489 $result['meta_query'] = array_merge( $result['meta_query'], [ $this->get_meta_robots_query_values() ] );
490 }
491
492 return array_merge( $vars, $result );
493 }
494
495 /**
496 * Creates a Readability score filter.
497 *
498 * @param number $low The lower boundary of the score.
499 * @param number $high The higher boundary of the score.
500 *
501 * @return array The Readability Score filter.
502 */
503 protected function create_readability_score_filter( $low, $high ) {
504 return [
505 [
506 'key' => WPSEO_Meta::$meta_prefix . 'content_score',
507 'value' => [ $low, $high ],
508 'type' => 'numeric',
509 'compare' => 'BETWEEN',
510 ],
511 ];
512 }
513
514 /**
515 * Creates an SEO score filter.
516 *
517 * @param number $low The lower boundary of the score.
518 * @param number $high The higher boundary of the score.
519 *
520 * @return array The SEO score filter.
521 */
522 protected function create_seo_score_filter( $low, $high ) {
523 return [
524 [
525 'key' => WPSEO_Meta::$meta_prefix . 'linkdex',
526 'value' => [ $low, $high ],
527 'type' => 'numeric',
528 'compare' => 'BETWEEN',
529 ],
530 ];
531 }
532
533 /**
534 * Creates a filter to retrieve posts that were set to no-index.
535 *
536 * @return array Array containin the no-index filter.
537 */
538 protected function create_no_index_filter() {
539 return [
540 [
541 'key' => WPSEO_Meta::$meta_prefix . 'meta-robots-noindex',
542 'value' => '1',
543 'compare' => '=',
544 ],
545 ];
546 }
547
548 /**
549 * Creates a filter to retrieve posts that have no keyword set.
550 *
551 * @return array Array containing the no focus keyword filter.
552 */
553 protected function create_no_focus_keyword_filter() {
554 return [
555 [
556 'key' => WPSEO_Meta::$meta_prefix . 'meta-robots-noindex',
557 'value' => 'needs-a-value-anyway',
558 'compare' => 'NOT EXISTS',
559 ],
560 [
561 'key' => WPSEO_Meta::$meta_prefix . 'linkdex',
562 'value' => 'needs-a-value-anyway',
563 'compare' => 'NOT EXISTS',
564 ],
565 ];
566 }
567
568 /**
569 * Determines whether a particular post_id is of an indexable post type.
570 *
571 * @param string $post_id The post ID to check.
572 *
573 * @return bool Whether or not it is indexable.
574 */
575 protected function is_indexable( $post_id ) {
576 if ( ! empty( $post_id ) && ! $this->uses_default_indexing( $post_id ) ) {
577 return WPSEO_Meta::get_value( 'meta-robots-noindex', $post_id ) === '2';
578 }
579
580 $post = get_post( $post_id );
581
582 if ( is_object( $post ) ) {
583 // If the option is false, this means we want to index it.
584 return WPSEO_Options::get( 'noindex-' . $post->post_type, false ) === false;
585 }
586
587 return true;
588 }
589
590 /**
591 * Determines whether the given post ID uses the default indexing settings.
592 *
593 * @param int $post_id The post ID to check.
594 *
595 * @return bool Whether or not the default indexing is being used for the post.
596 */
597 protected function uses_default_indexing( $post_id ) {
598 return WPSEO_Meta::get_value( 'meta-robots-noindex', $post_id ) === '0';
599 }
600
601 /**
602 * Returns filters when $order_by is matched in the if-statement.
603 *
604 * @param string $order_by The ID of the column by which to order the posts.
605 *
606 * @return array Array containing the order filters.
607 */
608 private function filter_order_by( $order_by ) {
609 switch ( $order_by ) {
610 case 'wpseo-metadesc':
611 return [
612 'meta_key' => WPSEO_Meta::$meta_prefix . 'metadesc',
613 'orderby' => 'meta_value',
614 ];
615
616 case 'wpseo-focuskw':
617 return [
618 'meta_key' => WPSEO_Meta::$meta_prefix . 'focuskw',
619 'orderby' => 'meta_value',
620 ];
621 }
622
623 return [];
624 }
625
626 /**
627 * Parses the score column.
628 *
629 * @param int $post_id The ID of the post for which to show the score.
630 *
631 * @return string The HTML for the SEO score indicator.
632 */
633 private function parse_column_score( $post_id ) {
634 if ( ! $this->is_indexable( $post_id ) ) {
635 $rank = new WPSEO_Rank( WPSEO_Rank::NO_INDEX );
636 $title = __( 'Post is set to noindex.', 'wordpress-seo' );
637
638 WPSEO_Meta::set_value( 'linkdex', 0, $post_id );
639
640 return $this->render_score_indicator( $rank, $title );
641 }
642
643 if ( WPSEO_Meta::get_value( 'focuskw', $post_id ) === '' ) {
644 $rank = new WPSEO_Rank( WPSEO_Rank::NO_FOCUS );
645 $title = __( 'Focus keyphrase not set.', 'wordpress-seo' );
646
647 return $this->render_score_indicator( $rank, $title );
648 }
649
650 $score = (int) WPSEO_Meta::get_value( 'linkdex', $post_id );
651 $rank = WPSEO_Rank::from_numeric_score( $score );
652 $title = $rank->get_label();
653
654 return $this->render_score_indicator( $rank, $title );
655 }
656
657 /**
658 * Parsing the readability score column.
659 *
660 * @param int $post_id The ID of the post for which to show the readability score.
661 *
662 * @return string The HTML for the readability score indicator.
663 */
664 private function parse_column_score_readability( $post_id ) {
665 $score = (int) WPSEO_Meta::get_value( 'content_score', $post_id );
666 $rank = WPSEO_Rank::from_numeric_score( $score );
667
668 return $this->render_score_indicator( $rank );
669 }
670
671 /**
672 * Sets up the hooks for the post_types.
673 */
674 private function set_post_type_hooks() {
675 $post_types = WPSEO_Post_Type::get_accessible_post_types();
676
677 if ( ! is_array( $post_types ) || $post_types === [] ) {
678 return;
679 }
680
681 foreach ( $post_types as $post_type ) {
682 if ( $this->display_metabox( $post_type ) === false ) {
683 continue;
684 }
685
686 add_filter( 'manage_' . $post_type . '_posts_columns', [ $this, 'column_heading' ], 10, 1 );
687 add_action( 'manage_' . $post_type . '_posts_custom_column', [ $this, 'column_content' ], 10, 2 );
688 add_action( 'manage_edit-' . $post_type . '_sortable_columns', [ $this, 'column_sort' ], 10, 2 );
689 }
690
691 unset( $post_type );
692 }
693
694 /**
695 * Wraps the WPSEO_Metabox check to determine whether the metabox should be displayed either by
696 * choice of the admin or because the post type is not a public post type.
697 *
698 * @since 7.0
699 *
700 * @param string|null $post_type Optional. The post type to test, defaults to the current post post_type.
701 *
702 * @return bool Whether or not the meta box (and associated columns etc) should be hidden.
703 */
704 private function display_metabox( $post_type = null ) {
705 $current_post_type = sanitize_text_field( $this->get_current_post_type() );
706
707 if ( ! isset( $post_type ) && ! empty( $current_post_type ) ) {
708 $post_type = $current_post_type;
709 }
710
711 return WPSEO_Utils::is_metabox_active( $post_type, 'post_type' );
712 }
713
714 /**
715 * Renders the score indicator.
716 *
717 * @param WPSEO_Rank $rank The rank this indicator should have.
718 * @param string $title Optional. The title for this rank, defaults to the title of the rank.
719 *
720 * @return string The HTML for a score indicator.
721 */
722 private function render_score_indicator( $rank, $title = '' ) {
723 if ( empty( $title ) ) {
724 $title = $rank->get_label();
725 }
726
727 return '<div aria-hidden="true" title="' . esc_attr( $title ) . '" class="' . esc_attr( 'wpseo-score-icon ' . $rank->get_css_class() ) . '"></div><span class="screen-reader-text wpseo-score-text">' . esc_html( $title ) . '</span>';
728 }
729
730 /**
731 * Determines whether or not filter dropdowns should be displayed.
732 *
733 * @return bool Whether or the current page can display the filter drop downs.
734 */
735 public function can_display_filter() {
736 if ( $GLOBALS['pagenow'] === 'upload.php' ) {
737 return false;
738 }
739
740 if ( $this->display_metabox() === false ) {
741 return false;
742 }
743
744 $screen = get_current_screen();
745 if ( $screen === null ) {
746 return false;
747 }
748
749 return WPSEO_Post_Type::is_post_type_accessible( $screen->post_type );
750 }
751 }
752