*/ protected $tabs = []; /** * Hints for tabs. * * @var array Index is tab id, value is html code. */ protected $tab_hints = []; /** * Constructor * * @param array $args Initial options. */ public function __construct( $args = [] ) { $this->tabs = $this::get_tab_names(); // phpcs:disable WordPress.CSRF.NonceVerification.NoNonceVerification,WordPress.VIP.SuperGlobalInputUsage.AccessDetected,WordPress.Security.NonceVerification.Recommended -- we create tables on content audit page and load GET parameters, it must work even without nonce. // fill from request. $this->date = isset( $_REQUEST['m'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['m'] ) ) : ''; $this->cat_value_raw = isset( $_REQUEST['cat'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['cat'] ) ) : ''; $this->tab = isset( $_REQUEST['tab'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['tab'] ) ) : self::DEFAULT_TAB; $this->keywords = isset( $_REQUEST['keywords'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['keywords'] ) ) : ''; $this->reason = isset( $_REQUEST['reason'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['reason'] ) ) : ''; $this->author = isset( $_REQUEST['author'] ) ? absint( $_REQUEST['author'] ) : 0; // phpcs:enable WordPress.CSRF.NonceVerification.NoNonceVerification,WordPress.VIP.SuperGlobalInputUsage.AccessDetected,WordPress.Security.NonceVerification.Recommended if ( ! isset( $this->tabs[ $this->tab ] ) ) { $this->tab = self::DEFAULT_TAB; } // need to fill tab property before parent constructor call. parent::__construct( [ 'plural' => 'backlinks', 'screen' => is_array( $args ) && isset( $args['screen'] ) ? $args['screen'] : null, 'ajax' => true, ] ); $this->tab_hints = [ 'dropped' => $this->prepare_hint( __( 'These pages used to rank in the top 3 for your target keyword but no longer are (as of last audit)', 'ahrefs-seo' ) ), 'well-performing' => $this->prepare_hint( __( 'These pages are ranking in the top 3 for your target keyword', 'ahrefs-seo' ) ), 'under-performing' => $this->prepare_hint( __( 'These pages have a significant number of backlinks, but are not ranking in the top 3 for your target keyword', 'ahrefs-seo' ) ), 'non-performing' => $this->prepare_hint( __( 'These pages are ranking below the top 20 for your target keyword', 'ahrefs-seo' ) ), 'excluded' => sprintf( ' ', // both substituted strings must not have double quote char, because it will break the title="..." content. $this->prepare_quotes( __( 'These pages do not participate in the content audit. Automatically excluded pages are:', 'ahrefs-seo' ) ), $this->prepare_quotes( implode( '
  • ', [ __( 'Noindex page', 'ahrefs-seo' ), __( 'Non-canonical page', 'ahrefs-seo' ), __( 'Redirected page', 'ahrefs-seo' ), __( 'Out of scope', 'ahrefs-seo' ), __( 'Newly published', 'ahrefs-seo' ), __( 'Added since last audit', 'ahrefs-seo' ), __( 'Error analyzing', 'ahrefs-seo' ) ] ) ), $this->prepare_quotes( sprintf( "%s %s", // html code must not contain double quotes. $this->prepare_quotes( esc_html__( 'You can also manually exclude pages from the audit.', 'ahrefs-seo' ) ), 'https://help.ahrefs.com/en/articles/3901720-how-does-the-ahrefs-seo-wordpress-plugin-work', // no double quotes! __( 'Learn more', 'ahrefs-seo' ) ) ) ), ]; $this->content = Ahrefs_Seo_Data_Content::get(); $name = ''; $value = $this->cat_value_raw; // parse cat_value at "cat-id", "page-id" or "0" - for all categories. if ( false !== strpos( $this->cat_value_raw, Ahrefs_Seo_Data_Content::CAT_FILTER_DIVIDER ) ) { list($name, $value) = explode( Ahrefs_Seo_Data_Content::CAT_FILTER_DIVIDER, $this->cat_value_raw, 2 ); } switch ( $name ) { case 'cat': $this->post_type = 'post'; // "cat-0". if ( ! empty( $value ) ) { $this->category = $value; // "cat-xx". } else { $this->post_type = 'post'; // "cat-0". } break; case 'page': if ( ! empty( $value ) ) { $this->page_id = absint( $value ); // "page-xx". } else { $this->post_type = 'page'; // "page-0". } break; case 'product': $this->post_type = 'product'; // "product-0". if ( ! empty( $value ) ) { $this->category = $value; // "product-xx". } break; default: if ( 0 === strpos( $name, 'tax:' ) ) { // possible values: 'tax:', 'tax:category' or 'tax:product_cat'. $this->taxonomy = substr( $name, 4 ); } else { $this->post_type = $name; } } add_filter( 'hidden_columns', [ $this, 'hidden_columns_filter' ], 10, 3 ); } /** * Get id and title for all tabs. * * @since 0.9.4 * * @return array Array [ tab name => tab title ]. */ public static function get_tab_names() { return [ '' => _x( 'All analyzed', 'Title of tab and chart legend', 'ahrefs-seo' ), 'dropped' => _x( 'No longer well-performing', 'Title of tab', 'ahrefs-seo' ), 'well-performing' => _x( 'Well-performing', 'Title of tab and chart legend', 'ahrefs-seo' ), 'under-performing' => _x( 'Under-performing', 'Title of tab and chart legend', 'ahrefs-seo' ), 'non-performing' => _x( 'Non-performing', 'Title of tab and chart legend', 'ahrefs-seo' ), 'excluded' => _x( 'Excluded', 'Title of tab and chart legend', 'ahrefs-seo' ), ]; } /** * Prepare simple tooltip content * * @since 0.8.6 * * @param string $text Source text string. * @return string Escaped string. */ private function prepare_hint( $text ) { return sprintf( ' ', esc_attr( $text ) ); } /** * Replace quotes in html string * * @since 0.8.6 * * @param string $html Source HTML string. * @return string Resulting string, not escaped. */ public function prepare_quotes( $html ) { return str_replace( '"', '"', // so replace possible double quote with html entity. $html ); } /** * Filter for default columns visibility. * * @param string[] $hidden An array of hidden columns. * @param \WP_Screen $screen WP_Screen object of the current screen. * @param bool $use_defaults Whether to show the default columns. * @return string[] */ public function hidden_columns_filter( $hidden, $screen, $use_defaults = false ) { // do not define parameter types for filter function. if ( $use_defaults ) { if ( $this->screen->id === $screen->id ) { $hidden[] = 'categories'; // do not show categories by default. $hidden[] = 'author'; // do not show author by default. } } return $hidden; } /** * Get sortable columns * * @return array> */ protected function get_sortable_columns() { return array( 'title' => array( 'title', false ), 'keyword' => array( 'keyword', false ), 'position' => array( 'position', false ), 'total' => array( 'total', false ), 'organic' => array( 'organic', false ), 'backlinks' => array( 'backlinks', false ), 'refdomains' => array( 'refdomains', false ), 'date' => array( 'created', false ), 'last_well_date' => array( 'last_well_date', false ), 'action' => array( 'action', false ), ); } /** * Get columns * * @return array */ public function get_columns() { $settings_content = Links::settings( Ahrefs_Seo_Screen_Settings::TAB_CONTENT ); $waiting_text = $this->content->get_waiting_as_text(); $country_code = ( new Snapshot() )->get_country_code( $this->content->snapshot_context_get() ); $columns = [ 'cb' => '', 'title' => _x( 'Title', 'Table column title', 'ahrefs-seo' ), 'author' => _x( 'Author', 'Table column title', 'ahrefs-seo' ), 'keyword' => _x( 'Target Keywords', 'Table column title', 'ahrefs-seo' ), 'categories' => _x( 'Categories', 'Table column title', 'ahrefs-seo' ), 'position' => sprintf( '%s', esc_attr__( 'The average position of this page in search results for a target keyword over the last 3 months. It is retrieved from your Google Search Console account.', 'ahrefs-seo' ), '' === $country_code ? esc_html_x( 'Position', 'Table column title', 'ahrefs-seo' ) : sprintf( esc_html_x( 'Position in %s', 'Table column title', 'ahrefs-seo' ), $country_code ) ), 'total' => sprintf( '%s', sprintf( /* Translators: %s: number of weeks or months: "12 weeks" or "3 months" */ esc_attr__( 'This metric is retrieved from your Google Analytics account. It is the monthly average traffic from all sources to this page, acquired in the last %s.', 'ahrefs-seo' ), $waiting_text ), esc_html_x( 'Total traffic', 'Table column title', 'ahrefs-seo' ) ), 'organic' => sprintf( '%s', sprintf( /* Translators: %s: number of weeks or months: "12 weeks" or "3 months" */ esc_attr__( 'This metric is retrieved from your Google Analytics account. It includes only monthly average traffic from organic search to this page, acquired in the last %s.', 'ahrefs-seo' ), $waiting_text ), esc_html_x( 'Organic traffic', 'Table column title', 'ahrefs-seo' ) ), 'backlinks' => sprintf( '%s', esc_attr__( 'How many links point to your target in total. Not to be confused with the number of pages linking to your target, as a single page can give multiple backlinks.', 'ahrefs-seo' ), esc_html_x( 'Backlinks', 'Table column title', 'ahrefs-seo' ) ), 'refdomains' => sprintf( '%s', esc_attr__( 'Number of domains containing at least one backlink that links to the target.', 'ahrefs-seo' ), esc_html_x( 'Ref. domains', 'Table column title', 'ahrefs-seo' ) ), 'date' => _x( 'Date', 'Table column title', 'ahrefs-seo' ), 'last_well_date' => _x( 'Last well done', 'Table column title', 'ahrefs-seo' ), 'action' => 'excluded' !== $this->tab ? sprintf( '%s', esc_attr( sprintf( /* Translators: %s: expanded to "content audit settings" with a link */ __( 'Recommended based on the traffic, backlinks & waiting time thresholds you’ve set in the %s.', 'ahrefs-seo' ), sprintf( "%s", esc_attr( $settings_content ), esc_html__( 'content audit settings', 'ahrefs-seo' ) ) ) ), _x( 'Suggestion', 'Table column title', 'ahrefs-seo' ) ) : sprintf( '%s', esc_attr__( 'The reason for post being excluded or not analyzed.', 'ahrefs-seo' ), esc_html_x( 'Reasons', 'Table column title', 'ahrefs-seo' ) ), ]; if ( Ahrefs_Seo_Data_Content::STATUS4_DROPPED !== $this->tab ) { unset( $columns['last_well_date'] ); } return $columns; } /** * Generates content for a single row of the table * * @param stdClass $item The current item. * @return void */ public function single_row( $item ) { // Note: can not define type of parameters, because not defined in parent class. $item->post_tax = Post_Tax::create_from_string( (string) $item->id ); ?> single_row_columns( $item ); ?> ', esc_attr( $item->id ), esc_attr( $item->id ), intval( $item->ver ), isset( $item->post_tax ) ? disabled( ! $item->post_tax->user_can_manage(), true, false ) : false ); } /** * Display title column * * @param stdClass $item Item. */ protected function column_title( stdClass $item ) { $title = $item->title ?: __( '(no title)', 'ahrefs-seo' ); $url_edit = ''; $post_tax = isset( $item->post_tax ) ? $item->post_tax : Post_Tax::create_from_string( (string) $item->id ); if ( $post_tax->user_can_edit() ) { $url_edit = $post_tax->get_url_edit(); // post edit link, may be empty. } // term edit link. if ( ! empty( $url_edit ) ) { printf( '%s', esc_attr( $url_edit ), /* translators: %s: Post title. */ esc_attr( sprintf( __( '“%s” (Edit)', 'ahrefs-seo' ), $title ) ), esc_html( $title ) ); } else { // just a title. echo esc_html( $title ); } } /** * Display author column * * @param stdClass $item Item. */ protected function column_author( stdClass $item ) { if ( $item->author ) { $link = add_query_arg( [ 'author' => get_the_author_meta( 'ID', $item->author ), 'keywords' => $this->keywords, ], Links::content_audit( $this->tab ) ); $link = Helper_Content::get()->update_link( $link ); ?> author ) ); ?>
    keyword ) || '' === $item->keyword ) { $this::some_empty_message(); } else { echo esc_html( $item->keyword ); } ?>
    keyword, $item->is_approved_keyword, $item->kw_low, $item->kw_source ); } /** * Print badge for keyword based on couple of parameters. * * @since 0.9.4 * * @param string|null $keyword Keyword. * @param string|null $is_approved_keyword Is keyword approved, field as string, directly from DB. * @param string|null $kw_low Does article have low words for TF-IDF analysis, field as string, directly from DB. * @param string|null $kw_source Source of keyword if any. * @return void */ public static function print_keyword_source_badge( $keyword = null, $is_approved_keyword = null, $kw_low = null, $kw_source = null ) { if ( Sources::SOURCE_YOASTSEO === $kw_source ) { ?> ✓ ✓ ✓ ✓ categories ) ) { sort( $item->categories ); echo implode( ', ', $item->categories ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $item->categories contains html links. } $badge = $this::get_post_type_badge( $item->badge ); $post_tax = isset( $item->post_tax ) ? $item->post_tax : Post_Tax::create_from_string( (string) $item->id ); $edit_link = $post_tax->user_can_edit() ? $post_tax->get_url_edit() : $post_tax->get_url(); if ( $edit_link ) { ?> created ) && '' !== str_replace( [ '0', '-' ], '', $item->created ) ) { $date = date_create_from_format( 'Y-m-d', (string) $item->created ); if ( false !== $date ) { echo esc_html( date_format( $date, 'j M Y' ) ); return; } } $this::some_empty_message(); } /** * Display 'last well done' date column * * @param stdClass $item Item. */ protected function column_last_well_date( stdClass $item ) { if ( ! empty( $item->last_well_date ) && '' !== str_replace( [ '0', '-' ], '', $item->last_well_date ) ) { echo esc_html( (string) $item->last_well_date ); } else { $this::some_empty_message(); } } /** * Display total traffic column * * @param stdClass $item Item. */ protected function column_total( stdClass $item ) { if ( ! is_null( $item->total ) ) { if ( intval( $item->total ) >= 0 ) { if ( defined( 'AHREFS_SEO_NO_GA' ) && AHREFS_SEO_NO_GA ) { $this::some_empty_message(); } else { echo esc_html( $item->total ); } } else { $this::some_error_message(); } } else { $this::some_empty_message(); } } /** * Display Position column * * @param stdClass $item Item. */ protected function column_position( stdClass $item ) { $this::print_position( is_null( $item->position ) ? null : floatval( $item->position ) ); } /** * Display Organic traffic column * * @param stdClass $item Item. */ protected function column_organic( stdClass $item ) { if ( ! is_null( $item->organic ) ) { if ( intval( $item->organic ) >= 0 ) { if ( defined( 'AHREFS_SEO_NO_GA' ) && AHREFS_SEO_NO_GA ) { $this::some_empty_message(); } else { echo esc_html( $item->organic ); } } else { $this::some_error_message(); } } else { $this::some_empty_message(); } } /** * Display Backlinks column * * @param stdClass $item Item. */ protected function column_backlinks( stdClass $item ) { if ( ! is_null( $item->backlinks ) ) { if ( intval( $item->backlinks ) >= 0 ) { echo esc_html( $item->backlinks ); } else { $this::some_error_message(); } } else { $this::some_empty_message(); } } /** * Display Ref.domains column * * @since 0.9.8 * * @param stdClass $item Item. */ protected function column_refdomains( stdClass $item ) { if ( ! is_null( $item->refdomains ) ) { if ( intval( $item->refdomains ) >= 0 ) { echo esc_html( $item->refdomains ); } else { $this::some_error_message(); } } else { $this::some_empty_message(); } } /** * Display Suggested action column * * @param stdClass $item Item. */ protected function column_action( stdClass $item ) { $action = isset( $item->action ) ? $item->action : Ahrefs_Seo_Data_Content::ACTION4_ADDED_SINCE_LAST; // Items never added (action is null) to content audit will have ACTION4_ADDED_SINCE_LAST. $title = $this::get_action_title( (string) $action ); ?> content-more-button button" href="#"> ? — = 0 ) { if ( $position < Ahrefs_Seo_Data_Content::POSITION_MAX - 1 ) { $value = round( 10 * $position ) / 10; echo esc_html( sprintf( '%.1f', $value ) ); } else { // position not found. self::some_empty_message(); } } else { self::some_error_message(); } } else { self::some_empty_message(); } } /** * Fill current table page with items * * @return array */ protected function fill_items() { if ( count( $this->ids ) ) { return $this->content->data_get_by_ids( $this->ids ); } $page = $this->get_pagenum(); $start = ( $page - 1 ) * (int) $this->per_page; $filters = [ 'cat' => $this->category, 'taxonomy' => $this->taxonomy, 'post_type' => $this->post_type, 'page_id' => $this->page_id, 's' => $this->search_string, 'ids' => $this->ids, ]; if ( ! empty( $this->author ) ) { $filters['author'] = $this->author; } if ( '' !== $this->keywords ) { $filters['keywords'] = $this->keywords; } if ( '' !== $this->reason ) { $filters['reason'] = $this->reason; } return $this->content->data_get_clear( $this->tab, $this->date, $filters, $start, $this->per_page, $this->orderby, $this->order ); } /** * Return count of items using current filters * * @return int */ private function count_data() { if ( count( $this->ids ) ) { return count( $this->ids ); } $filters = [ 'cat' => $this->category, 'taxonomy' => $this->taxonomy, 'post_type' => $this->post_type, 'page_id' => $this->page_id, 's' => $this->search_string, ]; if ( ! empty( $this->author ) ) { $filters['author'] = $this->author; } if ( '' !== $this->keywords ) { $filters['keywords'] = $this->keywords; } if ( '' !== $this->reason ) { $filters['reason'] = $this->reason; } return $this->content->data_get_clear_count( $this->tab, $this->date, $filters ); } /** * Prepares the list of items for displaying */ public function prepare_items() { $columns = $this->get_columns(); $hidden = get_hidden_columns( ! empty( get_current_screen() ) ? get_current_screen() : $this->screen ); $sortable = $this->get_sortable_columns(); $this->_column_headers = array( $columns, $hidden, $sortable ); $this->items = $this->fill_items(); $total_items = $this->count_data(); $this->set_pagination_args( [ 'total_items' => $total_items, 'per_page' => $this->per_page, 'total_pages' => intval( ceil( $total_items / $this->per_page ) ), 'orderby' => $this->orderby, 'order' => $this->order, ] ); } /** * Display a table. * * Note: we will not have there any query vars from page url until we added it as parameter at the content.display() JS function. */ public function display() { // Adds field order and orderby. // Note: nonce field already added before. ?> taxonomy}" ); ?>" /> tab && $tip_expand_suggestion->need_to_show() ) { $tip_expand_suggestion->hide(); // show only once at main tab after each Content audit. ?> Associative array ( action id => title ) */ protected function get_bulk_actions() { return array( 'stop' => __( 'Exclude from analysis', 'ahrefs-seo' ), 'start' => __( 'Include in analysis', 'ahrefs-seo' ), ); } /** * Generates and displays row action links. * * @param stdClass $item Item being acted upon. * @param string $column_name Current column name. * @param string $primary Primary column name. * @return string Row actions output for posts. */ protected function handle_row_actions( $item, $column_name, $primary ) { // Note: can not define type of parameters, because not defined in parent class. if ( $primary === $column_name ) { $url_edit = ''; $post_id = absint( $item->post_id ); $title = $item->title ?: __( '(no title)', 'ahrefs-seo' ); $actions = []; // Note: we are working only with posts & pages already filtered by post_status 'publish' here. // So we can skip related checks in row handlers logic. $post_tax = isset( $item->post_tax ) ? $item->post_tax : Post_Tax::create_from_string( (string) $item->id ); if ( $post_tax->user_can_edit() ) { $url_edit = $post_tax->get_url_edit(); // post edit link, may be empty. } $url_view = $post_tax->get_url(); if ( '' !== $url_edit ) { $actions['edit'] = sprintf( '%s', $url_edit, /* translators: %s: post title */ esc_attr( sprintf( __( 'Edit “%s”', 'ahrefs-seo' ), $title ) ), __( 'Edit', 'ahrefs-seo' ) ); } if ( '' !== $url_view ) { $actions['view'] = sprintf( '%s', $url_view, /* translators: %s: post title */ esc_attr( sprintf( __( 'View “%s”', 'ahrefs-seo' ), $title ) ), __( 'View', 'ahrefs-seo' ) ); } if ( $post_tax->user_can_manage() ) { // Exclude from audit / Include to audit row action. $action = isset( $item->action ) ? $item->action : Ahrefs_Seo_Data_Content::ACTION4_ADDED_SINCE_LAST; if ( in_array( $action, [ Ahrefs_Seo_Data_Content::ACTION4_ADDED_SINCE_LAST ], true ) ) { $actions['include'] = sprintf( '%s', '#', $item->id, esc_attr__( 'Run audit', 'ahrefs-seo' ), __( 'Run audit', 'ahrefs-seo' ) ); } elseif ( in_array( $action, [ Ahrefs_Seo_Data_Content::ACTION4_ERROR_ANALYZING ], true ) ) { $actions['include'] = sprintf( '%s', '#', $item->id, esc_attr__( 'Analyze page again', 'ahrefs-seo' ), __( 'Analyze page again', 'ahrefs-seo' ) ); } elseif ( in_array( $action, [ Ahrefs_Seo_Data_Content::ACTION4_NOINDEX_PAGE, Ahrefs_Seo_Data_Content::ACTION4_NONCANONICAL, Ahrefs_Seo_Data_Content::ACTION4_REDIRECTED ], true ) ) { $actions['recheck'] = sprintf( '%s', '#', $item->id, esc_attr__( 'Recheck status', 'ahrefs-seo' ), __( 'Recheck status', 'ahrefs-seo' ) ); $actions['include'] = sprintf( '%s', '#', $item->id, esc_attr__( 'Include to audit', 'ahrefs-seo' ), __( 'Include to audit', 'ahrefs-seo' ) ); } elseif ( in_array( $action, [ Ahrefs_Seo_Data_Content::ACTION4_MANUALLY_EXCLUDED, Ahrefs_Seo_Data_Content::ACTION4_OUT_OF_SCOPE, Ahrefs_Seo_Data_Content::ACTION4_NEWLY_PUBLISHED ], true ) ) { $actions['include'] = sprintf( '%s', '#', $item->id, esc_attr__( 'Include to audit', 'ahrefs-seo' ), __( 'Include to audit', 'ahrefs-seo' ) ); } elseif ( in_array( $action, [ Ahrefs_Seo_Data_Content::ACTION4_DO_NOTHING, Ahrefs_Seo_Data_Content::ACTION4_UPDATE_YELLOW, Ahrefs_Seo_Data_Content::ACTION4_MERGE, Ahrefs_Seo_Data_Content::ACTION4_EXCLUDE, Ahrefs_Seo_Data_Content::ACTION4_UPDATE_ORANGE, Ahrefs_Seo_Data_Content::ACTION4_REWRITE, Ahrefs_Seo_Data_Content::ACTION4_ANALYZING, Ahrefs_Seo_Data_Content::ACTION4_OUT_OF_SCOPE_ANALYZING ], true ) ) { $actions['exclude'] = sprintf( '%s', '#', $item->id, esc_attr__( 'Exclude from audit', 'ahrefs-seo' ), __( 'Exclude from audit', 'ahrefs-seo' ) ); } // additional "Exclude" row action. if ( in_array( $action, [ Ahrefs_Seo_Data_Content::ACTION4_NEWLY_PUBLISHED, Ahrefs_Seo_Data_Content::ACTION4_ADDED_SINCE_LAST ], true ) ) { $actions['exclude'] = sprintf( '%s', '#', $item->id, esc_attr__( 'Exclude from audit', 'ahrefs-seo' ), __( 'Exclude from audit', 'ahrefs-seo' ) ); } } return $this->row_actions( $actions ); } elseif ( 'keyword' === $column_name ) { $post_tax = isset( $item->post_tax ) ? $item->post_tax : Post_Tax::create_from_string( (string) $item->id ); if ( $post_tax->user_can_manage() ) { $actions = []; $title = $item->title ?: __( '(no title)', 'ahrefs-seo' ); if ( $post_tax->user_can_manage() ) { // can user manage this item in a plugin? if ( ! is_null( $item->keyword ) && '' !== $item->keyword && ! (bool) $item->is_approved_keyword && ! Sources::is_source_imported( $item->kw_source ) ) { $actions['approve-keyword'] = sprintf( '✓ %s', $item->id, /* translators: %s: post title */ esc_attr( sprintf( __( 'Approve keyword for “%s”', 'ahrefs-seo' ), $title ) ), __( 'Approve', 'ahrefs-seo' ) ); } $actions['change-keyword'] = sprintf( '%s', $item->id, /* translators: %s: post title */ esc_attr( sprintf( __( 'Change keyword for “%s”', 'ahrefs-seo' ), $title ) ), __( 'Change', 'ahrefs-seo' ) ); } return $this->row_actions( $actions ); } } elseif ( 'backlinks' === $column_name ) { $actions = []; $post_id = absint( $item->post_id ); $url = Post_Tax::create_from_string( (string) $item->id )->get_url(); if ( '' !== $url ) { $link = 'https://app.ahrefs.com/v2-site-explorer/backlinks/exact?target=' . rawurlencode( apply_filters( 'ahrefs_seo_search_traffic_url', $url ) ); if ( ! is_null( $item->backlinks ) ) { if ( intval( $item->backlinks ) > 0 ) { $actions['ahrefs-open-link'] = sprintf( '%s', esc_attr( $link ), esc_attr( "{$post_id}" ), esc_attr( $url ), /* translators: view info for post in Ahrefs */ esc_attr__( 'View in Ahrefs', 'ahrefs-seo' ), __( 'View in Ahrefs', 'ahrefs-seo' ), esc_attr( AHREFS_SEO_IMAGES_URL . 'link-open.svg' ) ); } } } return $this->row_actions( $actions ); } elseif ( 'refdomains' === $column_name ) { $actions = []; $post_id = absint( $item->post_id ); $url = Post_Tax::create_from_string( (string) $item->id )->get_url(); if ( '' !== $url ) { $link = 'https://app.ahrefs.com/v2-site-explorer/refdomains/exact?target=' . rawurlencode( apply_filters( 'ahrefs_seo_search_traffic_url', $url ) ); if ( ! is_null( $item->refdomains ) ) { if ( intval( $item->refdomains ) > 0 ) { $actions['ahrefs-open-link'] = sprintf( '%s', esc_attr( $link ), esc_attr( "{$post_id}" ), esc_attr( $url ), /* translators: view info for post in Ahrefs */ esc_attr__( 'View in Ahrefs', 'ahrefs-seo' ), __( 'View in Ahrefs', 'ahrefs-seo' ), esc_attr( AHREFS_SEO_IMAGES_URL . 'link-open.svg' ) ); } } } return $this->row_actions( $actions ); } return ''; } /** * Display a monthly dropdown for filtering items * * @global \WP_Locale $wp_locale * @return void */ protected function months_dropdown_content() { global $wp_locale; $months = Ahrefs_Seo_Db_Helper::content_data_get_clear_months( $this->content->snapshot_context_get(), $this->search_string ); $month_count = count( $months ); if ( ! $month_count || 1 === $month_count && 0 === $months[0]->month ) { return; } $m = $this->date; ?> categories_dropdown( $this->post_type, $this->category, $this->cat_value_raw, $this->is_lang_used ); } /** * Displays an authors drop-down for filtering on the Posts list table. */ protected function authors_dropdown_content() { $list = ( new Content_Db() )->get_all_authors(); ?>
    months_dropdown_content(); $this->categories_dropdown_content(); $this->authors_dropdown_content(); if ( 'excluded' !== $this->tab ) { $this->keywords_dropdown_content(); } else { $this->reasons_dropdown_content(); } submit_button( __( 'Filter', 'ahrefs-seo' ), '', 'filter_action', false, array( 'id' => 'group-filter-submit' ) ); } ?>
    link ) with the list * of views available on this table. * * @return array */ protected function get_views() { $result = []; $counts = $this->content->data_get_count_by_status(); // Called from admin-ajax.php content, need to use correct base link. $base_url = Links::content_audit(); foreach ( $this->tabs as $id => $title ) { $url = '' === $id ? remove_query_arg( 'tab', $base_url ) : add_query_arg( 'tab', $id, $base_url ); $url = Helper_Content::get()->update_link( $url ); $count = isset( $counts[ $id ] ) ? $counts[ $id ] : 0; $tab_hint = isset( $this->tab_hints[ $id ] ) ? $this->tab_hints[ $id ] : ''; // html code of hint. $result[ $title ] = sprintf( '%s %s (%d)', esc_attr( $url ), esc_attr( $id ), $id === $this->tab ? 'current' : '', esc_html( $title ), $tab_hint, $count ); } return $result; } /** * Replace top navigations by search box and Analysis setting button * * @param string $which Top or bottom. * @phpstan-param 'bottom'|'top' $which Top or bottom. * @return void */ protected function pagination( $which ) { // Note: can not define type of parameters, because not defined in parent class. if ( 'top' === $which ) { ?>
    search_box( __( 'Search', 'ahrefs-seo' ), 'search_to_url' ); ?>
    $additional_fields Additional fields. * @return void */ public function ajax_response_updated( array $ids, array $additional_fields ) { if ( ! empty( $ids ) ) { $this->ids = $ids; $this->prepare_items(); ob_start(); $this->display_rows(); $rows = ob_get_clean(); } ob_start(); $this->views(); $tabs = ob_get_clean(); $response = [ 'tabs' => $tabs ]; if ( ! empty( $rows ) ) { $response['updated'] = $rows; } if ( ! empty( $additional_fields ) ) { $response = array_merge( $response, $additional_fields ); } wp_send_json_success( $response ); } /** * Get default orderby * * @since 0.8.4 * @return string */ protected function get_default_orderby() { return Ahrefs_Seo_Data_Content::STATUS4_DROPPED === $this->tab ? 'last_well_date' : $this->default_orderby; } /** * Get current tab * * @since 0.9.4 * * @return string Tab ID. */ public function get_current_tab() { return $this->tab; } }