| 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">—</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">—</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::BAD ); |
| 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 |
|