*/ namespace RankMath\Admin; use RankMath\Helper; use RankMath\Helpers\Str; use RankMath\Helpers\Param; use RankMath\Runner; use RankMath\Traits\Hooker; use RankMath\Admin\Database\Database; defined( 'ABSPATH' ) || exit; /** * Post_Columns class. */ class Post_Columns implements Runner { use Hooker; /** * SEO data. * * @var array */ private $data = []; /** * Register hooks. */ public function hooks() { $this->action( 'admin_init', 'init' ); } /** * Intialize. */ public function init() { if ( ! Helper::has_cap( 'onpage_general' ) ) { return; } $this->register_post_columns(); $this->register_media_columns(); $this->register_taxonomy_columns(); // Column Content. $this->filter( 'rank_math_title', 'get_column_title', 5, 2 ); $this->filter( 'rank_math_description', 'get_column_description', 5, 2 ); $this->filter( 'rank_math_seo_details', 'get_column_seo_details', 5 ); } /** * Register post column hooks. */ private function register_post_columns() { $post_types = Helper::get_allowed_post_types(); foreach ( $post_types as $post_type ) { $this->filter( 'edd_download_columns', 'add_columns', 11 ); $this->filter( "manage_{$post_type}_posts_columns", 'add_columns', 11 ); $this->action( "manage_{$post_type}_posts_custom_column", 'columns_contents', 11, 2 ); $this->filter( "manage_edit-{$post_type}_sortable_columns", 'sortable_columns', 11 ); // Also make them hidden by default. $user_id = get_current_user_id(); $columns_hidden = (array) get_user_meta( $user_id, "manageedit-{$post_type}columnshidden", true ); $maybe_hidden = get_user_meta( $user_id, "manageedit-{$post_type}columnshidden_default", true ); // Continue if default is already set. if ( $maybe_hidden ) { continue; } // Set it to hidden by default. $columns_hidden = array_unique( array_merge( $columns_hidden, [ 'rank_math_title', 'rank_math_description' ] ) ); update_user_meta( $user_id, "manageedit-{$post_type}columnshidden", $columns_hidden ); update_user_meta( $user_id, "manageedit-{$post_type}columnshidden_default", '1' ); } } /** * Register media column hooks. */ private function register_media_columns() { if ( ! Helper::get_settings( 'titles.pt_attachment_bulk_editing' ) ) { return; } $this->filter( 'manage_media_columns', 'add_media_columns', 11 ); $this->action( 'manage_media_custom_column', 'media_contents', 11, 2 ); } /** * Register taxonomy columns hooks. * * @return void */ private function register_taxonomy_columns() { $taxonomies = Helper::get_allowed_taxonomies(); foreach ( $taxonomies as $taxonomy ) { $this->filter( "manage_edit-{$taxonomy}_columns", 'add_taxonomy_columns', 9 ); $this->filter( "manage_{$taxonomy}_custom_column", 'taxonomy_columns_contents', 10, 3 ); } } /** * Add new columns for SEO title, description and focus keywords. * * @param array $columns Array of column names. * * @return array */ public function add_columns( $columns ) { global $post_type; $current_pt = $post_type; if ( ! $post_type && 'inline-save' === Param::post( 'action' ) ) { $post_id = Param::post( 'post_ID', 0, FILTER_VALIDATE_INT ); $current_pt = get_post_type( $post_id ); } $columns['rank_math_seo_details'] = esc_html__( 'SEO Details', 'rank-math' ); if ( Helper::get_settings( 'titles.pt_' . $current_pt . '_bulk_editing', true ) ) { $columns['rank_math_title'] = esc_html__( 'SEO Title', 'rank-math' ); $columns['rank_math_description'] = esc_html__( 'SEO Desc', 'rank-math' ); } return $columns; } /** * Make the SEO Score column sortable. * * @param array $columns Array of column names. * * @return array */ public function sortable_columns( $columns ) { $columns['rank_math_seo_details'] = 'rank_math_seo_score'; return $columns; } /** * Add new columns for Media Alt & Title. * * @param array $columns Array of column names. * * @return array */ public function add_media_columns( $columns ) { $columns['rank_math_image_title'] = esc_html__( 'Title', 'rank-math' ); $columns['rank_math_image_alt'] = esc_html__( 'Alternative Text', 'rank-math' ); return $columns; } /** * Adds custom columns to taxonomy list view. * * @param array $columns Columns belonging to current taxonomy. * * @return array */ public function add_taxonomy_columns( $columns ) { $screen = get_current_screen(); if ( Helper::get_settings( 'titles.tax_' . $screen->taxonomy . '_bulk_editing', false ) ) { $columns['rank_math_title'] = esc_html__( 'SEO Title', 'rank-math' ); $columns['rank_math_description'] = esc_html__( 'SEO Desc', 'rank-math' ); } return $columns; } /** * Add content for custom column. * * @param string $column_name The name of the column to display. * @param int $post_id The current post ID. */ public function columns_contents( $column_name, $post_id ) { if ( Str::starts_with( 'rank_math', $column_name ) ) { do_action( $column_name, $post_id ); } } /** * Generate content of custom columns. * * @param string $content The content of the current column. * @param string $column_name The column name. * @param int $term_id The unique ID of the current term. * * @return string */ public function taxonomy_columns_contents( $content, $column_name, $term_id ) { if ( Str::starts_with( 'rank_math_', $column_name ) ) { do_action( $column_name, $term_id, 'term' ); } return $content; } /** * Add content for title column. * * @param int $object_id The current Object ID. * @param string $object_type The current Object type. */ public function get_column_title( $object_id, $object_type = 'post' ) { if ( empty( $this->data ) ) { $method = "get_{$object_type}_seo_data"; $this->$method( $object_type ); } $title = ! empty( $this->data[ $object_id ]['rank_math_title'] ) ? $this->data[ $object_id ]['rank_math_title'] : ''; if ( ! $title ) { $title = $this->get_default_title( $object_id, $object_type ); } ?>
data[ $object_id ]['rank_math_description'] ) ? $this->data[ $object_id ]['rank_math_description'] : ''; if ( ! $description ) { $description = $this->get_default_description( $object_id, $object_type ); } ?>
data ) ) { $this->get_post_seo_data(); } $data = isset( $this->data[ $post_id ] ) ? $this->data[ $post_id ] : []; if ( ! self::is_post_indexable( $post_id ) ) { echo 'N/A'; echo '' . esc_html__( 'No Index', 'rank-math' ) . ''; $this->do_action( 'post/column/seo_details', $post_id, $data, $this->data ); return; } $keyword = ! empty( $data['rank_math_focus_keyword'] ) ? $data['rank_math_focus_keyword'] : ''; $keyword = explode( ',', $keyword )[0]; $is_pillar = ! empty( $data['rank_math_pillar_content'] ) && 'on' === $data['rank_math_pillar_content'] ? true : false; $score = empty( $keyword ) ? false : $this->get_seo_score( $data ); $class = ! $score ? 'no-score' : $this->get_seo_score_class( $score ); $score = $score ? $score . ' / 100' : 'N/A'; ?> <?php esc_html_e( 'Is Pillar', 'rank-math' ); ?> : do_filter( 'post/column/seo_details/focus_keyword', $keyword ) ) : esc_html__( 'Not Set', 'rank-math' ); ?> do_action( 'post/column/seo_details', $post_id, $data, $this->data ); ?>
taxonomy}_title" ); } $post_type = get_post_type( $object_id ); return Helper::get_settings( "titles.pt_{$post_type}_title" ); } /** * Get Default description for the object type. * * @param int $object_id The current Object ID. * @param string $object_type The current Object type. */ private function get_default_description( $object_id, $object_type ) { if ( $object_type === 'term' ) { $term = get_term( $object_id ); return Helper::get_settings( "titles.tax_{$term->taxonomy}_description" ); } $post_type = get_post_type( $object_id ); $description = has_excerpt( $object_id ) ? '%excerpt%' : Helper::get_settings( "titles.pt_{$post_type}_description" ); } /** * Get Terms SEO data. */ private function get_term_seo_data() { $wp_list_table = _get_list_table( 'WP_Terms_List_Table' ); $wp_list_table->prepare_items(); $items = $wp_list_table->items; if ( empty( $items ) ) { return false; } $term_ids = array_filter( array_map( function ( $item ) { return isset( $item->term_id ) ? $item->term_id : ''; }, $items ) ); $results = Database::table( 'termmeta' )->select( [ 'term_id', 'meta_key', 'meta_value' ] )->whereIn( 'term_id', $term_ids )->whereLike( 'meta_key', 'rank_math' )->get( ARRAY_A ); if ( empty( $results ) ) { return false; } foreach ( $results as $result ) { $this->data[ $result['term_id'] ][ $result['meta_key'] ] = $result['meta_value']; } } /** * Get Post SEO data. */ private function get_post_seo_data() { $post_ids = []; $post_ids = array_filter( $this->get_post_ids() ); $post_id = (int) Param::post( 'post_ID' ); if ( $post_id ) { $post_ids[] = $post_id; } if ( empty( $post_ids ) ) { return false; } $results = Database::table( 'postmeta' )->select( [ 'post_id', 'meta_key', 'meta_value' ] )->whereIn( 'post_id', $post_ids )->whereLike( 'meta_key', 'rank_math' )->get( ARRAY_A ); if ( empty( $results ) ) { return false; } foreach ( $results as $result ) { $this->data[ $result['post_id'] ][ $result['meta_key'] ] = $result['meta_value']; } } /** * Get Post IDs dispalyed on the Post lists page. */ private function get_post_ids() { global $wp_query, $per_page; if ( empty( $wp_query->posts ) ) { return []; } $pages = $wp_query->posts; if ( ! is_post_type_hierarchical( Param::get( 'post_type' ) ) || 'menu_order title' !== $wp_query->query['orderby'] ) { return array_map( function ( $post ) { return isset( $post->ID ) ? $post->ID : ''; }, $pages ); } $children_pages = []; if ( empty( Param::request( 's' ) ) ) { $top_level_pages = []; foreach ( $pages as $page ) { if ( $page->post_parent > 0 ) { $children_pages[ $page->post_parent ][] = $page; } else { $top_level_pages[] = $page; } } $pages = &$top_level_pages; } $pagenum = max( 1, Param::request( 'paged', 0 ) ); $count = 0; $start = ( $pagenum - 1 ) * $per_page; $end = $start + $per_page; $ids = []; foreach ( $pages as $page ) { if ( $count >= $end ) { break; } if ( $count >= $start ) { $ids[] = $page->ID; } ++$count; $this->add_child_page_ids( $children_pages, $page->ID, $ids, $count ); } return $ids; } /** * Add the child page IDs to the list of IDs to be processed. * * @param array $children_pages Child Pages. * @param int $id Current page ID. * @param array $ids IDs to be processed. * @param int $count Counter. */ private function add_child_page_ids( $children_pages, $id, &$ids, &$count ) { if ( empty( $children_pages ) || empty( $children_pages[ $id ] ) ) { return; } foreach ( $children_pages[ $id ] as $child_page ) { $id = $child_page->ID; $ids[] = $child_page->ID; ++$count; $this->add_child_page_ids( $children_pages, $id, $ids, $count ); } } /** * Get SEO score. * * @param array $data SEO data of current post. * * @return string */ private function get_seo_score( $data ) { if ( ! isset( $data['rank_math_seo_score'] ) ) { return false; } if ( ! Helper::is_score_enabled() ) { return false; } return $data['rank_math_seo_score'] ? $data['rank_math_seo_score'] : 0; } /** * Get SEO score rating string: great/good/bad. * * @param int $score Score. * * @return string */ private function get_seo_score_class( $score ) { if ( $score > 80 ) { return 'great'; } if ( $score > 50 && $score < 81 ) { return 'good'; } return 'bad'; } /** * Check post indexable status. * * @param int $post_id Post ID. */ public static function is_post_indexable( $post_id ) { $robots = Param::post( 'rank_math_robots', false, FILTER_DEFAULT, FILTER_REQUIRE_ARRAY ); $robots = apply_filters( 'rank_math/admin/robots', $robots, $post_id ); if ( ! empty( $robots ) ) { return in_array( 'index', $robots, true ) ? true : false; } return Helper::is_post_indexable( $post_id ); } }