PluginProbe ʕ •ᴥ•ʔ
Rank Math SEO – AI SEO Tools to Dominate SEO Rankings / 1.0.271.1
Rank Math SEO – AI SEO Tools to Dominate SEO Rankings v1.0.271.1
1.0.271 1.0.271.1 1.0.270 1.0.269 trunk 1.0.216 1.0.217 1.0.218 1.0.219 1.0.220 1.0.221 1.0.222 1.0.223 1.0.224 1.0.225 1.0.226 1.0.227 1.0.227.1 1.0.228 1.0.229 1.0.230 1.0.231 1.0.232 1.0.233 1.0.234 1.0.234.1 1.0.235 1.0.236 1.0.237 1.0.238 1.0.239 1.0.240 1.0.241 1.0.242 1.0.243 1.0.244 1.0.245 1.0.246 1.0.247 1.0.248 1.0.249 1.0.250 1.0.251 1.0.251.1 1.0.252 1.0.252.1 1.0.253 1.0.254 1.0.255 1.0.256 1.0.257 1.0.258 1.0.259 1.0.259.1 1.0.260 1.0.261 1.0.262 1.0.263 1.0.264 1.0.264.1 1.0.265 1.0.266 1.0.266.1 1.0.267 1.0.268
seo-by-rank-math / includes / admin / class-post-columns.php
seo-by-rank-math / includes / admin Last commit date
database 5 months ago importers 2 weeks ago metabox 6 days ago notifications 5 months ago views 4 months ago watcher 2 weeks ago wizard 2 weeks ago class-admin-bar-menu.php 2 weeks ago class-admin-breadcrumbs.php 2 weeks ago class-admin-dashboard-nav.php 2 weeks ago class-admin-header.php 2 weeks ago class-admin-helper.php 2 weeks ago class-admin-init.php 8 months ago class-admin-menu.php 2 weeks ago class-admin.php 6 days ago class-api.php 1 year ago class-ask-review.php 2 weeks ago class-assets.php 2 weeks ago class-bulk-actions.php 2 weeks ago class-cmb2-fields.php 2 weeks ago class-cmb2-options.php 2 weeks ago class-dashboard-widget.php 2 weeks ago class-import-export.php 2 weeks ago class-list-table.php 2 weeks ago class-lock-modified-date.php 1 year ago class-notices.php 2 weeks ago class-option-center.php 2 weeks ago class-options.php 2 weeks ago class-page.php 2 weeks ago class-post-columns.php 2 weeks ago class-post-filters.php 2 weeks ago class-pro-notice.php 2 weeks ago class-register-options-page.php 9 months ago class-registration.php 2 weeks ago class-sanitize-settings.php 2 weeks ago class-setup-wizard.php 2 weeks ago index.php 7 years ago
class-post-columns.php
572 lines
1 <?php
2 /**
3 * The admin post columns functionality.
4 *
5 * @since 0.9.0
6 * @package RankMath
7 * @subpackage RankMath\Admin
8 * @author Rank Math <support@rankmath.com>
9 */
10
11 namespace RankMath\Admin;
12
13 use RankMath\Helper;
14 use RankMath\Helpers\Str;
15 use RankMath\Helpers\Param;
16 use RankMath\Runner;
17 use RankMath\Traits\Hooker;
18 use RankMath\Admin\Database\Database;
19
20 defined( 'ABSPATH' ) || exit;
21
22 /**
23 * Post_Columns class.
24 */
25 class Post_Columns implements Runner {
26
27 use Hooker;
28
29 /**
30 * SEO data.
31 *
32 * @var array
33 */
34 private $data = [];
35
36 /**
37 * Register hooks.
38 */
39 public function hooks() {
40 $this->action( 'admin_init', 'init' );
41 }
42
43 /**
44 * Initialize.
45 */
46 public function init() {
47 if ( ! Helper::has_cap( 'onpage_general' ) ) {
48 return;
49 }
50
51 $this->register_post_columns();
52 $this->register_media_columns();
53 $this->register_taxonomy_columns();
54
55 // Column Content.
56 $this->filter( 'rank_math_title', 'get_column_title', 5, 2 );
57 $this->filter( 'rank_math_description', 'get_column_description', 5, 2 );
58 $this->filter( 'rank_math_seo_details', 'get_column_seo_details', 5 );
59 }
60
61 /**
62 * Register post column hooks.
63 */
64 private function register_post_columns() {
65 $post_types = Helper::get_allowed_post_types();
66 foreach ( $post_types as $post_type ) {
67 $this->filter( 'edd_download_columns', 'add_columns', 11 );
68 $this->filter( "manage_{$post_type}_posts_columns", 'add_columns', 11 );
69 $this->action( "manage_{$post_type}_posts_custom_column", 'columns_contents', 11, 2 );
70 $this->filter( "manage_edit-{$post_type}_sortable_columns", 'sortable_columns', 11 );
71
72 // Also make them hidden by default.
73 $user_id = get_current_user_id();
74 $columns_hidden = (array) get_user_meta( $user_id, "manageedit-{$post_type}columnshidden", true );
75 $maybe_hidden = get_user_meta( $user_id, "manageedit-{$post_type}columnshidden_default", true );
76
77 // Continue if default is already set.
78 if ( $maybe_hidden ) {
79 continue;
80 }
81
82 // Set it to hidden by default.
83 $columns_hidden = array_unique( array_merge( $columns_hidden, [ 'rank_math_title', 'rank_math_description' ] ) );
84 update_user_meta( $user_id, "manageedit-{$post_type}columnshidden", $columns_hidden );
85 update_user_meta( $user_id, "manageedit-{$post_type}columnshidden_default", '1' );
86 }
87 }
88
89 /**
90 * Register media column hooks.
91 */
92 private function register_media_columns() {
93 if ( ! Helper::get_settings( 'titles.pt_attachment_bulk_editing' ) ) {
94 return;
95 }
96
97 $this->filter( 'manage_media_columns', 'add_media_columns', 11 );
98 $this->action( 'manage_media_custom_column', 'media_contents', 11, 2 );
99 }
100
101 /**
102 * Register taxonomy columns hooks.
103 *
104 * @return void
105 */
106 private function register_taxonomy_columns() {
107 $taxonomies = Helper::get_allowed_taxonomies();
108 foreach ( $taxonomies as $taxonomy ) {
109 $this->filter( "manage_edit-{$taxonomy}_columns", 'add_taxonomy_columns', 9 );
110 $this->filter( "manage_{$taxonomy}_custom_column", 'taxonomy_columns_contents', 10, 3 );
111 }
112 }
113
114 /**
115 * Add new columns for SEO title, description and focus keywords.
116 *
117 * @param array $columns Array of column names.
118 *
119 * @return array
120 */
121 public function add_columns( $columns ) {
122 global $post_type;
123 $current_pt = $post_type;
124 if ( ! $post_type && 'inline-save' === Param::post( 'action' ) ) {
125 $post_id = Param::post( 'post_ID', 0, FILTER_VALIDATE_INT );
126 $current_pt = get_post_type( $post_id );
127 }
128 $columns['rank_math_seo_details'] = esc_html__( 'SEO Details', 'seo-by-rank-math' );
129
130 if ( Helper::get_settings( 'titles.pt_' . $current_pt . '_bulk_editing', true ) ) {
131 $columns['rank_math_title'] = esc_html__( 'SEO Title', 'seo-by-rank-math' );
132 $columns['rank_math_description'] = esc_html__( 'SEO Desc', 'seo-by-rank-math' );
133 }
134
135 return $columns;
136 }
137
138 /**
139 * Make the SEO Score column sortable.
140 *
141 * @param array $columns Array of column names.
142 *
143 * @return array
144 */
145 public function sortable_columns( $columns ) {
146 $columns['rank_math_seo_details'] = 'rank_math_seo_score';
147
148 return $columns;
149 }
150
151 /**
152 * Add new columns for Media Alt & Title.
153 *
154 * @param array $columns Array of column names.
155 *
156 * @return array
157 */
158 public function add_media_columns( $columns ) {
159 $columns['rank_math_image_title'] = esc_html__( 'Title', 'seo-by-rank-math' );
160 $columns['rank_math_image_alt'] = esc_html__( 'Alternative Text', 'seo-by-rank-math' );
161
162 return $columns;
163 }
164
165 /**
166 * Adds custom columns to taxonomy list view.
167 *
168 * @param array $columns Columns belonging to current taxonomy.
169 *
170 * @return array
171 */
172 public function add_taxonomy_columns( $columns ) {
173 $screen = get_current_screen();
174 if ( Helper::get_settings( 'titles.tax_' . $screen->taxonomy . '_bulk_editing', false ) ) {
175 $columns['rank_math_title'] = esc_html__( 'SEO Title', 'seo-by-rank-math' );
176 $columns['rank_math_description'] = esc_html__( 'SEO Desc', 'seo-by-rank-math' );
177 }
178
179 return $columns;
180 }
181
182 /**
183 * Add content for custom column.
184 *
185 * @param string $column_name The name of the column to display.
186 * @param int $post_id The current post ID.
187 */
188 public function columns_contents( $column_name, $post_id ) {
189 if ( Str::starts_with( 'rank_math', $column_name ) ) {
190 do_action( $column_name, $post_id );
191 }
192 }
193
194 /**
195 * Generate content of custom columns.
196 *
197 * @param string $content The content of the current column.
198 * @param string $column_name The column name.
199 * @param int $term_id The unique ID of the current term.
200 *
201 * @return string
202 */
203 public function taxonomy_columns_contents( $content, $column_name, $term_id ) {
204 if ( Str::starts_with( 'rank_math_', $column_name ) ) {
205 do_action( $column_name, $term_id, 'term' );
206 }
207
208 return $content;
209 }
210
211 /**
212 * Add content for title column.
213 *
214 * @param int $object_id The current Object ID.
215 * @param string $object_type The current Object type.
216 */
217 public function get_column_title( $object_id, $object_type = 'post' ) {
218 if ( empty( $this->data ) ) {
219 $method = "get_{$object_type}_seo_data";
220 $this->$method( $object_type );
221 }
222
223 $title = ! empty( $this->data[ $object_id ]['rank_math_title'] ) ? $this->data[ $object_id ]['rank_math_title'] : '';
224 if ( ! $title ) {
225 $title = $this->get_default_title( $object_id, $object_type );
226 }
227 ?>
228 <span class="rank-math-column-display"><?php echo esc_html( $title ); ?></span>
229 <textarea class="rank-math-column-value" data-field="title" tabindex="11"><?php echo esc_attr( $title ); ?></textarea>
230 <div class="rank-math-column-edit">
231 <a href="#" class="rank-math-column-save"><?php esc_html_e( 'Save', 'seo-by-rank-math' ); ?></a>
232 <a href="#" class="button-link-delete rank-math-column-cancel"><?php esc_html_e( 'Cancel', 'seo-by-rank-math' ); ?></a>
233 </div>
234 <?php
235 }
236
237 /**
238 * Add content for description column.
239 *
240 * @param int $object_id The current Object ID.
241 * @param string $object_type The current Object type.
242 */
243 public function get_column_description( $object_id, $object_type = 'post' ) {
244 $description = ! empty( $this->data[ $object_id ]['rank_math_description'] ) ? $this->data[ $object_id ]['rank_math_description'] : '';
245 if ( ! $description ) {
246 $description = $this->get_default_description( $object_id, $object_type );
247 }
248 ?>
249 <span class="rank-math-column-display"><?php echo esc_html( $description ); ?></span>
250 <textarea class="rank-math-column-value" data-field="description" tabindex="11"><?php echo esc_attr( $description ); ?></textarea>
251 <div class="rank-math-column-edit">
252 <a href="#" class="rank-math-column-save"><?php esc_html_e( 'Save', 'seo-by-rank-math' ); ?></a>
253 <a href="#" class="button-link-delete rank-math-column-cancel"><?php esc_html_e( 'Cancel', 'seo-by-rank-math' ); ?></a>
254 </div>
255 <?php
256 }
257
258 /**
259 * Add content for title column.
260 *
261 * @param int $post_id The current post ID.
262 */
263 public function get_column_seo_details( $post_id ) {
264 if ( empty( $this->data ) ) {
265 $this->get_post_seo_data();
266 }
267
268 $data = isset( $this->data[ $post_id ] ) ? $this->data[ $post_id ] : [];
269 if ( ! self::is_post_indexable( $post_id ) ) {
270 echo '<span class="rank-math-column-display seo-score no-score "><strong>N/A</strong></span>';
271 echo '<strong>' . esc_html__( 'No Index', 'seo-by-rank-math' ) . '</strong>';
272 $this->do_action( 'post/column/seo_details', $post_id, $data, $this->data );
273 return;
274 }
275
276 $keyword = ! empty( $data['rank_math_focus_keyword'] ) ? $data['rank_math_focus_keyword'] : '';
277 $keyword = explode( ',', $keyword )[0];
278 $is_pillar = ! empty( $data['rank_math_pillar_content'] ) && 'on' === $data['rank_math_pillar_content'] ? true : false;
279
280 $score = empty( $keyword ) ? false : $this->get_seo_score( $data );
281 $class = ! $score ? 'no-score' : $this->get_seo_score_class( $score );
282 $score = $score ? $score . ' / 100' : 'N/A';
283
284 ?>
285 <span class="rank-math-column-display seo-score <?php echo esc_attr( $class ); ?> <?php echo ! $score ? 'disabled' : ''; ?>">
286 <strong><?php echo esc_html( $score ); ?></strong>
287 <?php if ( $is_pillar ) { ?>
288 <img class="is-pillar" src="<?php echo esc_url( rank_math()->plugin_url() . 'assets/admin/img/pillar.svg' ); ?>" alt="<?php esc_html_e( 'Is Pillar', 'seo-by-rank-math' ); ?>" title="<?php esc_html_e( 'Is Pillar', 'seo-by-rank-math' ); ?>" width="25" />
289 <?php } ?>
290 </span>
291
292 <label><?php esc_html_e( 'Focus Keyword', 'seo-by-rank-math' ); ?>:</label>
293 <span class="rank-math-column-display">
294 <strong title="Focus Keyword"><?php esc_html_e( 'Keyword', 'seo-by-rank-math' ); ?>:</strong>
295 <span>
296 <?php
297 echo $keyword ? wp_kses_post( $this->do_filter( 'post/column/seo_details/focus_keyword', $keyword ) ) : esc_html__( 'Not Set', 'seo-by-rank-math' );
298 ?>
299 </span>
300 </span>
301
302 <input class="rank-math-column-value" data-field="focus_keyword" tabindex="11" value="<?php echo esc_attr( $keyword ); ?>" />
303
304 <?php $this->do_action( 'post/column/seo_details', $post_id, $data, $this->data ); ?>
305
306 <div class="rank-math-column-edit">
307 <a href="#" class="rank-math-column-save"><?php esc_html_e( 'Save', 'seo-by-rank-math' ); ?></a>
308 <a href="#" class="button-link-delete rank-math-column-cancel"><?php esc_html_e( 'Cancel', 'seo-by-rank-math' ); ?></a>
309 </div>
310
311 <?php
312 }
313
314 /**
315 * Add content for custom media column.
316 *
317 * @param string $column_name The name of the column to display.
318 * @param int $post_id The current post ID.
319 */
320 public function media_contents( $column_name, $post_id ) {
321 if ( 'rank_math_image_title' === $column_name ) {
322 $title = get_the_title( $post_id );
323 ?>
324 <span class="rank-math-column-display"><?php echo esc_html( $title ); ?></span>
325 <input class="rank-math-column-value" data-field="image_title" tabindex="11" value="<?php echo esc_attr( $title ); ?>" />
326 <div class="rank-math-column-edit">
327 <a href="#" class="rank-math-column-save"><?php esc_html_e( 'Save', 'seo-by-rank-math' ); ?></a>
328 <a href="#" class="button-link-delete rank-math-column-cancel"><?php esc_html_e( 'Cancel', 'seo-by-rank-math' ); ?></a>
329 </div>
330 <?php
331 return;
332 }
333
334 if ( 'rank_math_image_alt' === $column_name ) {
335 $alt = get_post_meta( $post_id, '_wp_attachment_image_alt', true );
336 ?>
337 <span class="rank-math-column-display"><?php echo esc_html( $alt ); ?></span>
338 <input class="rank-math-column-value" data-field="image_alt" tabindex="11" value="<?php echo esc_attr( $alt ); ?>" />
339 <div class="rank-math-column-edit">
340 <a href="#" class="rank-math-column-save"><?php esc_html_e( 'Save', 'seo-by-rank-math' ); ?></a>
341 <a href="#" class="button-link-delete rank-math-column-cancel"><?php esc_html_e( 'Cancel', 'seo-by-rank-math' ); ?></a>
342 </div>
343 <?php
344 return;
345 }
346 }
347
348 /**
349 * Get Default title for the object type.
350 *
351 * @param int $object_id The current Object ID.
352 * @param string $object_type The current Object type.
353 */
354 private function get_default_title( $object_id, $object_type ) {
355 if ( $object_type === 'term' ) {
356 $term = get_term( $object_id );
357 return Helper::get_settings( "titles.tax_{$term->taxonomy}_title" );
358 }
359
360 $post_type = get_post_type( $object_id );
361 return Helper::get_settings( "titles.pt_{$post_type}_title" );
362 }
363
364 /**
365 * Get Default description for the object type.
366 *
367 * @param int $object_id The current Object ID.
368 * @param string $object_type The current Object type.
369 */
370 private function get_default_description( $object_id, $object_type ) {
371 if ( $object_type === 'term' ) {
372 $term = get_term( $object_id );
373 return Helper::get_settings( "titles.tax_{$term->taxonomy}_description" );
374 }
375
376 $post_type = get_post_type( $object_id );
377 return has_excerpt( $object_id ) ? '%excerpt%' : Helper::get_settings( "titles.pt_{$post_type}_description" );
378 }
379
380 /**
381 * Get Terms SEO data.
382 */
383 private function get_term_seo_data() {
384 $wp_list_table = _get_list_table( 'WP_Terms_List_Table' );
385 $wp_list_table->prepare_items();
386 $items = $wp_list_table->items;
387 if ( empty( $items ) ) {
388 return false;
389 }
390
391 $term_ids = array_filter(
392 array_map(
393 function ( $item ) {
394 return isset( $item->term_id ) ? $item->term_id : '';
395 },
396 $items
397 )
398 );
399
400 $results = Database::table( 'termmeta' )->select( [ 'term_id', 'meta_key', 'meta_value' ] )->whereIn( 'term_id', $term_ids )->whereLike( 'meta_key', 'rank_math' )->get( ARRAY_A );
401 if ( empty( $results ) ) {
402 return false;
403 }
404
405 foreach ( $results as $result ) {
406 $this->data[ $result['term_id'] ][ $result['meta_key'] ] = $result['meta_value'];
407 }
408 }
409
410 /**
411 * Get Post SEO data.
412 */
413 private function get_post_seo_data() {
414 $post_ids = [];
415
416 $post_ids = array_filter( $this->get_post_ids() );
417 $post_id = (int) Param::post( 'post_ID' );
418 if ( $post_id ) {
419 $post_ids[] = $post_id;
420 }
421
422 if ( empty( $post_ids ) ) {
423 return false;
424 }
425
426 $results = Database::table( 'postmeta' )->select( [ 'post_id', 'meta_key', 'meta_value' ] )->whereIn( 'post_id', $post_ids )->whereLike( 'meta_key', 'rank_math' )->get( ARRAY_A );
427 if ( empty( $results ) ) {
428 return false;
429 }
430
431 foreach ( $results as $result ) {
432 $this->data[ $result['post_id'] ][ $result['meta_key'] ] = $result['meta_value'];
433 }
434 }
435
436 /**
437 * Get Post IDs displayed on the Post lists page.
438 */
439 private function get_post_ids() {
440 global $wp_query, $per_page;
441 if ( empty( $wp_query->posts ) ) {
442 return [];
443 }
444
445 $pages = $wp_query->posts;
446 if (
447 ! is_post_type_hierarchical( Param::get( 'post_type' ) ) ||
448 'menu_order title' !== $wp_query->query['orderby']
449 ) {
450 return array_map(
451 function ( $post ) {
452 return isset( $post->ID ) ? $post->ID : '';
453 },
454 $pages
455 );
456 }
457
458 $children_pages = [];
459 if ( empty( Param::request( 's' ) ) ) {
460 $top_level_pages = [];
461
462 foreach ( $pages as $page ) {
463 if ( $page->post_parent > 0 ) {
464 $children_pages[ $page->post_parent ][] = $page;
465 } else {
466 $top_level_pages[] = $page;
467 }
468 }
469
470 $pages = &$top_level_pages;
471 }
472
473 $pagenum = max( 1, Param::request( 'paged', 0 ) );
474 $count = 0;
475 $start = ( $pagenum - 1 ) * $per_page;
476 $end = $start + $per_page;
477 $ids = [];
478
479 foreach ( $pages as $page ) {
480 if ( $count >= $end ) {
481 break;
482 }
483
484 if ( $count >= $start ) {
485 $ids[] = $page->ID;
486 }
487
488 ++$count;
489
490 $this->add_child_page_ids( $children_pages, $page->ID, $ids, $count );
491 }
492
493 return $ids;
494 }
495
496 /**
497 * Add the child page IDs to the list of IDs to be processed.
498 *
499 * @param array $children_pages Child Pages.
500 * @param int $id Current page ID.
501 * @param array $ids IDs to be processed.
502 * @param int $count Counter.
503 */
504 private function add_child_page_ids( $children_pages, $id, &$ids, &$count ) {
505 if ( empty( $children_pages ) || empty( $children_pages[ $id ] ) ) {
506 return;
507 }
508
509 foreach ( $children_pages[ $id ] as $child_page ) {
510 $id = $child_page->ID;
511 $ids[] = $child_page->ID;
512 ++$count;
513
514 $this->add_child_page_ids( $children_pages, $id, $ids, $count );
515 }
516 }
517
518 /**
519 * Get SEO score.
520 *
521 * @param array $data SEO data of current post.
522 *
523 * @return string
524 */
525 private function get_seo_score( $data ) {
526 if ( ! isset( $data['rank_math_seo_score'] ) ) {
527 return false;
528 }
529
530 if ( ! Helper::is_score_enabled() ) {
531 return false;
532 }
533
534 return $data['rank_math_seo_score'] ? $data['rank_math_seo_score'] : 0;
535 }
536
537 /**
538 * Get SEO score rating string: great/good/bad.
539 *
540 * @param int $score Score.
541 *
542 * @return string
543 */
544 private function get_seo_score_class( $score ) {
545 if ( $score > 80 ) {
546 return 'great';
547 }
548
549 if ( $score > 50 && $score < 81 ) {
550 return 'good';
551 }
552
553 return 'bad';
554 }
555
556 /**
557 * Check post indexable status.
558 *
559 * @param int $post_id Post ID.
560 */
561 public static function is_post_indexable( $post_id ) {
562 $robots = Param::post( 'rank_math_robots', false, FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
563
564 $robots = apply_filters( 'rank_math/admin/robots', $robots, $post_id );
565 if ( ! empty( $robots ) ) {
566 return in_array( 'index', $robots, true ) ? true : false;
567 }
568
569 return Helper::is_post_indexable( $post_id, false );
570 }
571 }
572