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

Yoast / wordpress-seo / 5066322038

pending completion
5066322038

push

github

GitHub
Merge pull request #20316 from Yoast/JRF/ghactions-run-more-selectively

2550 of 29012 relevant lines covered (8.79%)

0.32 hits per line

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

19.26
/admin/class-meta-columns.php
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\Helpers\Score_Icon_Helper;
10
use Yoast\WP\SEO\Integrations\Admin\Admin_Columns_Cache_Integration;
11
use Yoast\WP\SEO\Surfaces\Values\Meta;
12

13
/**
14
 * Class WPSEO_Meta_Columns.
15
 */
16
class WPSEO_Meta_Columns {
17

18
        /**
19
         * Holds the context objects for each indexable.
20
         *
21
         * @var Meta_Tags_Context[]
22
         */
23
        protected $context = [];
24

25
        /**
26
         * Holds the SEO analysis.
27
         *
28
         * @var WPSEO_Metabox_Analysis_SEO
29
         */
30
        private $analysis_seo;
31

32
        /**
33
         * Holds the readability analysis.
34
         *
35
         * @var WPSEO_Metabox_Analysis_Readability
36
         */
37
        private $analysis_readability;
38

39
        /**
40
         * Admin columns cache.
41
         *
42
         * @var Admin_Columns_Cache_Integration
43
         */
44
        private $admin_columns_cache;
45

46
        /**
47
         * Holds the Score_Icon_Helper.
48
         *
49
         * @var Score_Icon_Helper
50
         */
51
        private $score_icon_helper;
52

53
        /**
54
         * When page analysis is enabled, just initialize the hooks.
55
         */
56
        public function __construct() {
57
                if ( apply_filters( 'wpseo_use_page_analysis', true ) === true ) {
×
58
                        add_action( 'admin_init', [ $this, 'setup_hooks' ] );
×
59
                }
60

61
                $this->analysis_seo         = new WPSEO_Metabox_Analysis_SEO();
×
62
                $this->analysis_readability = new WPSEO_Metabox_Analysis_Readability();
×
63
                $this->admin_columns_cache  = YoastSEO()->classes->get( Admin_Columns_Cache_Integration::class );
×
64
                $this->score_icon_helper    = YoastSEO()->helpers->score_icon;
×
65
        }
66

67
        /**
68
         * Sets up up the hooks.
69
         */
70
        public function setup_hooks() {
71
                $this->set_post_type_hooks();
×
72

73
                if ( $this->analysis_seo->is_enabled() ) {
×
74
                        add_action( 'restrict_manage_posts', [ $this, 'posts_filter_dropdown' ] );
×
75
                }
76

77
                if ( $this->analysis_readability->is_enabled() ) {
×
78
                        add_action( 'restrict_manage_posts', [ $this, 'posts_filter_dropdown_readability' ] );
×
79
                }
80

81
                add_filter( 'request', [ $this, 'column_sort_orderby' ] );
×
82
                add_filter( 'default_hidden_columns', [ $this, 'column_hidden' ], 10, 1 );
×
83
        }
84

85
        /**
86
         * Adds the column headings for the SEO plugin for edit posts / pages overview.
87
         *
88
         * @param array $columns Already existing columns.
89
         *
90
         * @return array Array containing the column headings.
91
         */
92
        public function column_heading( $columns ) {
93
                if ( $this->display_metabox() === false ) {
3✔
94
                        return $columns;
×
95
                }
96

97
                $added_columns = [];
3✔
98

99
                if ( $this->analysis_seo->is_enabled() ) {
3✔
100
                        $added_columns['wpseo-score'] = '<span class="yoast-column-seo-score yoast-column-header-has-tooltip" data-tooltip-text="' . esc_attr__( 'SEO score', 'wordpress-seo' ) . '"><span class="screen-reader-text">' . __( 'SEO score', 'wordpress-seo' ) . '</span></span></span>';
3✔
101
                }
102

103
                if ( $this->analysis_readability->is_enabled() ) {
3✔
104
                        $added_columns['wpseo-score-readability'] = '<span class="yoast-column-readability yoast-column-header-has-tooltip" data-tooltip-text="' . esc_attr__( 'Readability score', 'wordpress-seo' ) . '"><span class="screen-reader-text">' . __( 'Readability score', 'wordpress-seo' ) . '</span></span></span>';
3✔
105
                }
106

107
                $added_columns['wpseo-title']    = __( 'SEO Title', 'wordpress-seo' );
3✔
108
                $added_columns['wpseo-metadesc'] = __( 'Meta Desc.', 'wordpress-seo' );
3✔
109

110
                if ( $this->analysis_seo->is_enabled() ) {
3✔
111
                        $added_columns['wpseo-focuskw'] = __( 'Keyphrase', 'wordpress-seo' );
3✔
112
                }
113

114
                return array_merge( $columns, $added_columns );
3✔
115
        }
116

117
        /**
118
         * Displays the column content for the given column.
119
         *
120
         * @param string $column_name Column to display the content for.
121
         * @param int    $post_id     Post to display the column content for.
122
         */
123
        public function column_content( $column_name, $post_id ) {
124
                if ( $this->display_metabox() === false ) {
×
125
                        return;
×
126
                }
127

128
                switch ( $column_name ) {
129
                        case 'wpseo-score':
×
130
                                // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Correctly escaped in render_score_indicator() method.
131
                                echo $this->parse_column_score( $post_id );
×
132

133
                                return;
×
134

135
                        case 'wpseo-score-readability':
×
136
                                // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Correctly escaped in render_score_indicator() method.
137
                                echo $this->parse_column_score_readability( $post_id );
×
138

139
                                return;
×
140

141
                        case 'wpseo-title':
×
142
                                $meta = $this->get_meta( $post_id );
×
143
                                if ( $meta ) {
×
144
                                        echo esc_html( $meta->title );
×
145
                                }
146

147
                                return;
×
148

149
                        case 'wpseo-metadesc':
×
150
                                $metadesc_val = '';
×
151
                                $meta         = $this->get_meta( $post_id );
×
152
                                if ( $meta ) {
×
153
                                        $metadesc_val = $meta->meta_description;
×
154
                                }
155
                                if ( $metadesc_val === '' ) {
×
156
                                        echo '<span aria-hidden="true">&#8212;</span><span class="screen-reader-text">',
×
157
                                        esc_html__( 'Meta description not set.', 'wordpress-seo' ),
×
158
                                        '</span>';
×
159

160
                                        return;
×
161
                                }
162

163
                                echo esc_html( $metadesc_val );
×
164

165
                                return;
×
166

167
                        case 'wpseo-focuskw':
×
168
                                $focuskw_val = WPSEO_Meta::get_value( 'focuskw', $post_id );
×
169

170
                                if ( $focuskw_val === '' ) {
×
171
                                        echo '<span aria-hidden="true">&#8212;</span><span class="screen-reader-text">',
×
172
                                        esc_html__( 'Focus keyphrase not set.', 'wordpress-seo' ),
×
173
                                        '</span>';
×
174

175
                                        return;
×
176
                                }
177

178
                                echo esc_html( $focuskw_val );
×
179

180
                                return;
×
181
                }
182
        }
183

184
        /**
185
         * Indicates which of the SEO columns are sortable.
186
         *
187
         * @param array $columns Appended with their orderby variable.
188
         *
189
         * @return array Array containing the sortable columns.
190
         */
191
        public function column_sort( $columns ) {
192
                if ( $this->display_metabox() === false ) {
×
193
                        return $columns;
×
194
                }
195

196
                $columns['wpseo-metadesc'] = 'wpseo-metadesc';
×
197

198
                if ( $this->analysis_seo->is_enabled() ) {
×
199
                        $columns['wpseo-focuskw'] = 'wpseo-focuskw';
×
200
                        $columns['wpseo-score']   = 'wpseo-score';
×
201
                }
202

203
                if ( $this->analysis_readability->is_enabled() ) {
×
204
                        $columns['wpseo-score-readability'] = 'wpseo-score-readability';
×
205
                }
206

207
                return $columns;
×
208
        }
209

210
        /**
211
         * Hides the SEO title, meta description and focus keyword columns if the user hasn't chosen which columns to hide.
212
         *
213
         * @param array $hidden The hidden columns.
214
         *
215
         * @return array Array containing the columns to hide.
216
         */
217
        public function column_hidden( $hidden ) {
218
                if ( ! is_array( $hidden ) ) {
3✔
219
                        $hidden = [];
1✔
220
                }
221

222
                array_push( $hidden, 'wpseo-title', 'wpseo-metadesc' );
3✔
223

224
                if ( $this->analysis_seo->is_enabled() ) {
3✔
225
                        $hidden[] = 'wpseo-focuskw';
3✔
226
                }
227

228
                return $hidden;
3✔
229
        }
230

231
        /**
232
         * Adds a dropdown that allows filtering on the posts SEO Quality.
233
         */
234
        public function posts_filter_dropdown() {
235
                if ( ! $this->can_display_filter() ) {
×
236
                        return;
×
237
                }
238

239
                $ranks = WPSEO_Rank::get_all_ranks();
×
240

241
                echo '<label class="screen-reader-text" for="wpseo-filter">' . esc_html__( 'Filter by SEO Score', 'wordpress-seo' ) . '</label>';
×
242
                echo '<select name="seo_filter" id="wpseo-filter">';
×
243

244
                // phpcs:ignore WordPress.Security.EscapeOutput -- Output is correctly escaped in the generate_option() method.
245
                echo $this->generate_option( '', __( 'All SEO Scores', 'wordpress-seo' ) );
×
246

247
                foreach ( $ranks as $rank ) {
×
248
                        $selected = selected( $this->get_current_seo_filter(), $rank->get_rank(), false );
×
249

250
                        // phpcs:ignore WordPress.Security.EscapeOutput -- Output is correctly escaped in the generate_option() method.
251
                        echo $this->generate_option( $rank->get_rank(), $rank->get_drop_down_label(), $selected );
×
252
                }
253

254
                echo '</select>';
×
255
        }
256

257
        /**
258
         * Adds a dropdown that allows filtering on the posts Readability Quality.
259
         *
260
         * @return void
261
         */
262
        public function posts_filter_dropdown_readability() {
263
                if ( ! $this->can_display_filter() ) {
×
264
                        return;
×
265
                }
266

267
                $ranks = WPSEO_Rank::get_all_readability_ranks();
×
268

269
                echo '<label class="screen-reader-text" for="wpseo-readability-filter">' . esc_html__( 'Filter by Readability Score', 'wordpress-seo' ) . '</label>';
×
270
                echo '<select name="readability_filter" id="wpseo-readability-filter">';
×
271

272
                // phpcs:ignore WordPress.Security.EscapeOutput -- Output is correctly escaped in the generate_option() method.
273
                echo $this->generate_option( '', __( 'All Readability Scores', 'wordpress-seo' ) );
×
274

275
                foreach ( $ranks as $rank ) {
×
276
                        $selected = selected( $this->get_current_readability_filter(), $rank->get_rank(), false );
×
277

278
                        // phpcs:ignore WordPress.Security.EscapeOutput -- Output is correctly escaped in the generate_option() method.
279
                        echo $this->generate_option( $rank->get_rank(), $rank->get_drop_down_readability_labels(), $selected );
×
280
                }
281

282
                echo '</select>';
×
283
        }
284

285
        /**
286
         * Generates an <option> element.
287
         *
288
         * @param string $value    The option's value.
289
         * @param string $label    The option's label.
290
         * @param string $selected HTML selected attribute for an option.
291
         *
292
         * @return string The generated <option> element.
293
         */
294
        protected function generate_option( $value, $label, $selected = '' ) {
295
                return '<option ' . $selected . ' value="' . esc_attr( $value ) . '">' . esc_html( $label ) . '</option>';
×
296
        }
297

298
        /**
299
         * Returns the meta object for a given post ID.
300
         *
301
         * @param int $post_id The post ID.
302
         *
303
         * @return Meta The meta object.
304
         */
305
        protected function get_meta( $post_id ) {
306
                $indexable = $this->admin_columns_cache->get_indexable( $post_id );
×
307

308
                return YoastSEO()->meta->for_indexable( $indexable, 'Post_Type' );
×
309
        }
310

311
        /**
312
         * Determines the SEO score filter to be later used in the meta query, based on the passed SEO filter.
313
         *
314
         * @param string $seo_filter The SEO filter to use to determine what further filter to apply.
315
         *
316
         * @return array The SEO score filter.
317
         */
318
        protected function determine_seo_filters( $seo_filter ) {
319
                if ( $seo_filter === WPSEO_Rank::NO_FOCUS ) {
6✔
320
                        return $this->create_no_focus_keyword_filter();
1✔
321
                }
322

323
                if ( $seo_filter === WPSEO_Rank::NO_INDEX ) {
5✔
324
                        return $this->create_no_index_filter();
1✔
325
                }
326

327
                $rank = new WPSEO_Rank( $seo_filter );
4✔
328

329
                return $this->create_seo_score_filter( $rank->get_starting_score(), $rank->get_end_score() );
4✔
330
        }
331

332
        /**
333
         * Determines the Readability score filter to the meta query, based on the passed Readability filter.
334
         *
335
         * @param string $readability_filter The Readability filter to use to determine what further filter to apply.
336
         *
337
         * @return array The Readability score filter.
338
         */
339
        protected function determine_readability_filters( $readability_filter ) {
340
                $rank = new WPSEO_Rank( $readability_filter );
3✔
341

342
                return $this->create_readability_score_filter( $rank->get_starting_score(), $rank->get_end_score() );
3✔
343
        }
344

345
        /**
346
         * Creates a keyword filter for the meta query, based on the passed Keyword filter.
347
         *
348
         * @param string $keyword_filter The keyword filter to use.
349
         *
350
         * @return array The keyword filter.
351
         */
352
        protected function get_keyword_filter( $keyword_filter ) {
353
                return [
×
354
                        'post_type' => get_query_var( 'post_type', 'post' ),
×
355
                        'key'       => WPSEO_Meta::$meta_prefix . 'focuskw',
×
356
                        'value'     => sanitize_text_field( $keyword_filter ),
×
357
                ];
×
358
        }
359

360
        /**
361
         * Determines whether the passed filter is considered to be valid.
362
         *
363
         * @param mixed $filter The filter to check against.
364
         *
365
         * @return bool Whether the filter is considered valid.
366
         */
367
        protected function is_valid_filter( $filter ) {
368
                return ! empty( $filter ) && is_string( $filter );
2✔
369
        }
370

371
        /**
372
         * Collects the filters and merges them into a single array.
373
         *
374
         * @return array Array containing all the applicable filters.
375
         */
376
        protected function collect_filters() {
377
                $active_filters = [];
×
378

379
                $seo_filter             = $this->get_current_seo_filter();
×
380
                $readability_filter     = $this->get_current_readability_filter();
×
381
                $current_keyword_filter = $this->get_current_keyword_filter();
×
382

383
                if ( $this->is_valid_filter( $seo_filter ) ) {
×
384
                        $active_filters = array_merge(
×
385
                                $active_filters,
×
386
                                $this->determine_seo_filters( $seo_filter )
×
387
                        );
×
388
                }
389

390
                if ( $this->is_valid_filter( $readability_filter ) ) {
×
391
                        $active_filters = array_merge(
×
392
                                $active_filters,
×
393
                                $this->determine_readability_filters( $readability_filter )
×
394
                        );
×
395
                }
396

397
                if ( $this->is_valid_filter( $current_keyword_filter ) ) {
×
398
                        /**
399
                         * Adapt the meta query used to filter the post overview on keyphrase.
400
                         *
401
                         * @internal
402
                         *
403
                         * @api array $keyword_filter The current keyword filter.
404
                         *
405
                         * @param array $keyphrase The keyphrase used in the filter.
406
                         */
407
                        $keyphrase_filter = \apply_filters(
×
408
                                'wpseo_change_keyphrase_filter_in_request',
×
409
                                $this->get_keyword_filter( $current_keyword_filter ),
×
410
                                $current_keyword_filter
×
411
                        );
×
412

413
                        if ( \is_array( $keyphrase_filter ) ) {
×
414
                                $active_filters = array_merge(
×
415
                                        $active_filters,
×
416
                                        [ $keyphrase_filter ]
×
417
                                );
×
418
                        }
419
                }
420

421
                /**
422
                 * Adapt the active applicable filters on the posts overview.
423
                 *
424
                 * @internal
425
                 *
426
                 * @param array $active_filters The current applicable filters.
427
                 */
428
                return \apply_filters( 'wpseo_change_applicable_filters', $active_filters );
×
429
        }
430

431
        /**
432
         * Modify the query based on the filters that are being passed.
433
         *
434
         * @param array $vars Query variables that need to be modified based on the filters.
435
         *
436
         * @return array Array containing the meta query to use for filtering the posts overview.
437
         */
438
        public function column_sort_orderby( $vars ) {
439
                $collected_filters = $this->collect_filters();
×
440

441
                $order_by_column = $vars['orderby'];
×
442
                if ( isset( $order_by_column ) ) {
×
443
                        // Based on the selected column, create a meta query.
444
                        $order_by = $this->filter_order_by( $order_by_column );
×
445

446
                        /**
447
                         * Adapt the order by part of the query on the posts overview.
448
                         *
449
                         * @internal
450
                         *
451
                         * @param array  $order_by        The current order by.
452
                         * @param string $order_by_column The current order by column.
453
                         */
454
                        $order_by = \apply_filters( 'wpseo_change_order_by', $order_by, $order_by_column );
×
455

456
                        $vars = array_merge( $vars, $order_by );
×
457
                }
458

459
                return $this->build_filter_query( $vars, $collected_filters );
×
460
        }
461

462
        /**
463
         * Retrieves the meta robots query values to be used within the meta query.
464
         *
465
         * @return array Array containing the query parameters regarding meta robots.
466
         */
467
        protected function get_meta_robots_query_values() {
468
                return [
×
469
                        'relation' => 'OR',
×
470
                        [
×
471
                                'key'     => WPSEO_Meta::$meta_prefix . 'meta-robots-noindex',
×
472
                                'compare' => 'NOT EXISTS',
×
473
                        ],
×
474
                        [
×
475
                                'key'     => WPSEO_Meta::$meta_prefix . 'meta-robots-noindex',
×
476
                                'value'   => '1',
×
477
                                'compare' => '!=',
×
478
                        ],
×
479
                ];
×
480
        }
481

482
        /**
483
         * Determines the score filters to be used. If more than one is passed, it created an AND statement for the query.
484
         *
485
         * @param array $score_filters Array containing the score filters.
486
         *
487
         * @return array Array containing the score filters that need to be applied to the meta query.
488
         */
489
        protected function determine_score_filters( $score_filters ) {
490
                if ( count( $score_filters ) > 1 ) {
×
491
                        return array_merge( [ 'relation' => 'AND' ], $score_filters );
×
492
                }
493

494
                return $score_filters;
×
495
        }
496

497
        /**
498
         * Retrieves the post type from the $_GET variable.
499
         *
500
         * @return string|null The sanitized current post type or null when the variable is not set in $_GET.
501
         */
502
        public function get_current_post_type() {
503
                // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: We are not processing form information.
504
                if ( isset( $_GET['post_type'] ) && is_string( $_GET['post_type'] ) ) {
3✔
505
                        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: We are not processing form information.
506
                        return sanitize_text_field( wp_unslash( $_GET['post_type'] ) );
1✔
507
                }
508
                return null;
2✔
509
        }
510

511
        /**
512
         * Retrieves the SEO filter from the $_GET variable.
513
         *
514
         * @return string|null The sanitized seo filter or null when the variable is not set in $_GET.
515
         */
516
        public function get_current_seo_filter() {
517
                // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: We are not processing form information.
518
                if ( isset( $_GET['seo_filter'] ) && is_string( $_GET['seo_filter'] ) ) {
3✔
519
                        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: We are not processing form information.
520
                        return sanitize_text_field( wp_unslash( $_GET['seo_filter'] ) );
1✔
521
                }
522
                return null;
2✔
523
        }
524

525
        /**
526
         * Retrieves the Readability filter from the $_GET variable.
527
         *
528
         * @return string|null The sanitized readability filter or null when the variable is not set in $_GET.
529
         */
530
        public function get_current_readability_filter() {
531
                // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: We are not processing form information.
532
                if ( isset( $_GET['readability_filter'] ) && is_string( $_GET['readability_filter'] ) ) {
3✔
533
                        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: We are not processing form information.
534
                        return sanitize_text_field( wp_unslash( $_GET['readability_filter'] ) );
1✔
535
                }
536
                return null;
2✔
537
        }
538

539
        /**
540
         * Retrieves the keyword filter from the $_GET variable.
541
         *
542
         * @return string|null The sanitized seo keyword filter or null when the variable is not set in $_GET.
543
         */
544
        public function get_current_keyword_filter() {
545
                // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: We are not processing form information.
546
                if ( isset( $_GET['seo_kw_filter'] ) && is_string( $_GET['seo_kw_filter'] ) ) {
3✔
547
                        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: We are not processing form information.
548
                        return sanitize_text_field( wp_unslash( $_GET['seo_kw_filter'] ) );
1✔
549
                }
550
                return null;
2✔
551
        }
552

553
        /**
554
         * Uses the vars to create a complete filter query that can later be executed to filter out posts.
555
         *
556
         * @param array $vars    Array containing the variables that will be used in the meta query.
557
         * @param array $filters Array containing the filters that we need to apply in the meta query.
558
         *
559
         * @return array Array containing the complete filter query.
560
         */
561
        protected function build_filter_query( $vars, $filters ) {
562
                // If no filters were applied, just return everything.
563
                if ( count( $filters ) === 0 ) {
4✔
564
                        return $vars;
1✔
565
                }
566

567
                $result               = [ 'meta_query' => [] ];
3✔
568
                $result['meta_query'] = array_merge( $result['meta_query'], [ $this->determine_score_filters( $filters ) ] );
3✔
569

570
                $current_seo_filter = $this->get_current_seo_filter();
3✔
571

572
                // This only applies for the SEO score filter because it can because the SEO score can be altered by the no-index option.
573
                if ( $this->is_valid_filter( $current_seo_filter ) && ! in_array( $current_seo_filter, [ WPSEO_Rank::NO_INDEX, WPSEO_Rank::NO_FOCUS ], true ) ) {
3✔
574
                        $result['meta_query'] = array_merge( $result['meta_query'], [ $this->get_meta_robots_query_values() ] );
×
575
                }
576

577
                return array_merge( $vars, $result );
3✔
578
        }
579

580
        /**
581
         * Creates a Readability score filter.
582
         *
583
         * @param number $low  The lower boundary of the score.
584
         * @param number $high The higher boundary of the score.
585
         *
586
         * @return array The Readability Score filter.
587
         */
588
        protected function create_readability_score_filter( $low, $high ) {
589
                return [
×
590
                        [
×
591
                                'key'     => WPSEO_Meta::$meta_prefix . 'content_score',
×
592
                                'value'   => [ $low, $high ],
×
593
                                'type'    => 'numeric',
×
594
                                'compare' => 'BETWEEN',
×
595
                        ],
×
596
                ];
×
597
        }
598

599
        /**
600
         * Creates an SEO score filter.
601
         *
602
         * @param number $low  The lower boundary of the score.
603
         * @param number $high The higher boundary of the score.
604
         *
605
         * @return array The SEO score filter.
606
         */
607
        protected function create_seo_score_filter( $low, $high ) {
608
                return [
×
609
                        [
×
610
                                'key'     => WPSEO_Meta::$meta_prefix . 'linkdex',
×
611
                                'value'   => [ $low, $high ],
×
612
                                'type'    => 'numeric',
×
613
                                'compare' => 'BETWEEN',
×
614
                        ],
×
615
                ];
×
616
        }
617

618
        /**
619
         * Creates a filter to retrieve posts that were set to no-index.
620
         *
621
         * @return array Array containin the no-index filter.
622
         */
623
        protected function create_no_index_filter() {
624
                return [
×
625
                        [
×
626
                                'key'     => WPSEO_Meta::$meta_prefix . 'meta-robots-noindex',
×
627
                                'value'   => '1',
×
628
                                'compare' => '=',
×
629
                        ],
×
630
                ];
×
631
        }
632

633
        /**
634
         * Creates a filter to retrieve posts that have no keyword set.
635
         *
636
         * @return array Array containing the no focus keyword filter.
637
         */
638
        protected function create_no_focus_keyword_filter() {
639
                return [
×
640
                        [
×
641
                                'key'     => WPSEO_Meta::$meta_prefix . 'meta-robots-noindex',
×
642
                                'value'   => 'needs-a-value-anyway',
×
643
                                'compare' => 'NOT EXISTS',
×
644
                        ],
×
645
                        [
×
646
                                'key'     => WPSEO_Meta::$meta_prefix . 'linkdex',
×
647
                                'value'   => 'needs-a-value-anyway',
×
648
                                'compare' => 'NOT EXISTS',
×
649
                        ],
×
650
                ];
×
651
        }
652

653
        /**
654
         * Determines whether a particular post_id is of an indexable post type.
655
         *
656
         * @param string $post_id The post ID to check.
657
         *
658
         * @return bool Whether or not it is indexable.
659
         */
660
        protected function is_indexable( $post_id ) {
661
                if ( ! empty( $post_id ) && ! $this->uses_default_indexing( $post_id ) ) {
4✔
662
                        return WPSEO_Meta::get_value( 'meta-robots-noindex', $post_id ) === '2';
1✔
663
                }
664

665
                $post = get_post( $post_id );
3✔
666

667
                if ( is_object( $post ) ) {
3✔
668
                        // If the option is false, this means we want to index it.
669
                        return WPSEO_Options::get( 'noindex-' . $post->post_type, false ) === false;
2✔
670
                }
671

672
                return true;
1✔
673
        }
674

675
        /**
676
         * Determines whether the given post ID uses the default indexing settings.
677
         *
678
         * @param int $post_id The post ID to check.
679
         *
680
         * @return bool Whether or not the default indexing is being used for the post.
681
         */
682
        protected function uses_default_indexing( $post_id ) {
683
                return WPSEO_Meta::get_value( 'meta-robots-noindex', $post_id ) === '0';
2✔
684
        }
685

686
        /**
687
         * Returns filters when $order_by is matched in the if-statement.
688
         *
689
         * @param string $order_by The ID of the column by which to order the posts.
690
         *
691
         * @return array Array containing the order filters.
692
         */
693
        private function filter_order_by( $order_by ) {
694
                switch ( $order_by ) {
695
                        case 'wpseo-metadesc':
×
696
                                return [
×
697
                                        // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Reason: Only used when user requests sorting.
698
                                        'meta_key' => WPSEO_Meta::$meta_prefix . 'metadesc',
×
699
                                        'orderby'  => 'meta_value',
×
700
                                ];
×
701

702
                        case 'wpseo-focuskw':
×
703
                                return [
×
704
                                        // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Reason: Only used when user requests sorting.
705
                                        'meta_key' => WPSEO_Meta::$meta_prefix . 'focuskw',
×
706
                                        'orderby'  => 'meta_value',
×
707
                                ];
×
708

709
                        case 'wpseo-score':
×
710
                                return [
×
711
                                        // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Reason: Only used when user requests sorting.
712
                                        'meta_key' => WPSEO_Meta::$meta_prefix . 'linkdex',
×
713
                                        'orderby'  => 'meta_value_num',
×
714
                                ];
×
715

716
                        case 'wpseo-score-readability':
×
717
                                return [
×
718
                                        // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Reason: Only used when user requests sorting.
719
                                        'meta_key' => WPSEO_Meta::$meta_prefix . 'content_score',
×
720
                                        'orderby'  => 'meta_value_num',
×
721
                                ];
×
722
                }
723

724
                return [];
×
725
        }
726

727
        /**
728
         * Parses the score column.
729
         *
730
         * @param int $post_id The ID of the post for which to show the score.
731
         *
732
         * @return string The HTML for the SEO score indicator.
733
         */
734
        private function parse_column_score( $post_id ) {
735
                $meta = $this->get_meta( $post_id );
×
736

737
                if ( $meta ) {
×
738
                        return $this->score_icon_helper->for_seo( $meta->indexable, '', __( 'Post is set to noindex.', 'wordpress-seo' ) );
×
739
                }
740
        }
741

742
        /**
743
         * Parsing the readability score column.
744
         *
745
         * @param int $post_id The ID of the post for which to show the readability score.
746
         *
747
         * @return string The HTML for the readability score indicator.
748
         */
749
        private function parse_column_score_readability( $post_id ) {
750
                $meta = $this->get_meta( $post_id );
×
751
                if ( $meta ) {
×
752
                        return $this->score_icon_helper->for_readability( $meta->indexable->readability_score );
×
753
                }
754
        }
755

756
        /**
757
         * Sets up the hooks for the post_types.
758
         */
759
        private function set_post_type_hooks() {
760
                $post_types = WPSEO_Post_Type::get_accessible_post_types();
×
761

762
                if ( ! is_array( $post_types ) || $post_types === [] ) {
×
763
                        return;
×
764
                }
765

766
                foreach ( $post_types as $post_type ) {
×
767
                        if ( $this->display_metabox( $post_type ) === false ) {
×
768
                                continue;
×
769
                        }
770

771
                        add_filter( 'manage_' . $post_type . '_posts_columns', [ $this, 'column_heading' ], 10, 1 );
×
772
                        add_action( 'manage_' . $post_type . '_posts_custom_column', [ $this, 'column_content' ], 10, 2 );
×
773
                        add_action( 'manage_edit-' . $post_type . '_sortable_columns', [ $this, 'column_sort' ], 10, 2 );
×
774
                }
775

776
                unset( $post_type );
×
777
        }
778

779
        /**
780
         * Wraps the WPSEO_Metabox check to determine whether the metabox should be displayed either by
781
         * choice of the admin or because the post type is not a public post type.
782
         *
783
         * @since 7.0
784
         *
785
         * @param string|null $post_type Optional. The post type to test, defaults to the current post post_type.
786
         *
787
         * @return bool Whether or not the meta box (and associated columns etc) should be hidden.
788
         */
789
        private function display_metabox( $post_type = null ) {
790
                $current_post_type = $this->get_current_post_type();
×
791

792
                if ( ! isset( $post_type ) && ! empty( $current_post_type ) ) {
×
793
                        $post_type = $current_post_type;
×
794
                }
795

796
                return WPSEO_Utils::is_metabox_active( $post_type, 'post_type' );
×
797
        }
798

799
        /**
800
         * Determines whether or not filter dropdowns should be displayed.
801
         *
802
         * @return bool Whether or the current page can display the filter drop downs.
803
         */
804
        public function can_display_filter() {
805
                if ( $GLOBALS['pagenow'] === 'upload.php' ) {
×
806
                        return false;
×
807
                }
808

809
                if ( $this->display_metabox() === false ) {
×
810
                        return false;
×
811
                }
812

813
                $screen = get_current_screen();
×
814
                if ( $screen === null ) {
×
815
                        return false;
×
816
                }
817

818
                return WPSEO_Post_Type::is_post_type_accessible( $screen->post_type );
×
819
        }
820
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc