3 * @package WPSEO\Admin|Google_Search_Console
6 if ( ! class_exists( 'WP_List_Table' ) ) {
7 require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
11 * Class WPSEO_GSC_Table
13 class WPSEO_GSC_Table extends WP_List_Table {
18 private $search_string;
23 protected $_column_headers;
26 * The category that is displayed
30 private $current_view;
35 private $per_page = 50;
40 private $current_page = 1;
45 private $modal_heights = array(
48 'already_exists' => 150,
54 * @param string $platform
55 * @param string $category
58 public function __construct( $platform, $category, array $items ) {
59 parent::__construct();
61 // Adding the thickbox.
65 if ( ( $search_string = filter_input( INPUT_GET, 's' ) ) != '' ) {
66 $this->search_string = $search_string;
69 $this->current_view = $category;
71 // Set the crawl issue source.
72 $this->show_fields( $platform );
74 $this->items = $items;
78 * Getting the screen id from this table
82 public function get_screen_id() {
83 return $this->screen->id;
87 * Setup the table variables, fetch the items from the database, search, sort and format the items.
89 public function prepare_items() {
90 // Get variables needed for pagination.
91 $this->per_page = $this->get_items_per_page( 'errors_per_page', $this->per_page );
92 $this->current_page = intval( ( $paged = filter_input( INPUT_GET, 'paged' ) ) ? $paged : 1 );
94 $this->setup_columns();
100 * Set the table columns
104 public function get_columns() {
106 'cb' => '<input type="checkbox" />',
107 'url' => __( 'URL', 'wordpress-seo' ),
108 'last_crawled' => __( 'Last crawled', 'wordpress-seo' ),
109 'first_detected' => __( 'First detected', 'wordpress-seo' ),
110 'response_code' => __( 'Response code', 'wordpress-seo' ),
117 * Return the columns that are sortable
121 protected function get_sortable_columns() {
122 $sortable_columns = array(
123 'url' => array( 'url', false ),
124 'last_crawled' => array( 'last_crawled', false ),
125 'first_detected' => array( 'first_detected', false ),
126 'response_code' => array( 'response_code', false ),
129 return $sortable_columns;
133 * Return available bulk actions
137 protected function get_bulk_actions() {
139 'mark_as_fixed' => __( 'Mark as fixed', 'wordpress-seo' ),
144 * Default method to display a column
147 * @param string $column_name
151 protected function column_default( $item, $column_name ) {
152 return $item[ $column_name ];
162 protected function column_cb( $item ) {
164 '<input type="checkbox" name="wpseo_crawl_issues[]" value="%s" />', $item['url']
169 * Formatting the output of the column last crawled into a dateformat
175 protected function column_last_crawled( $item ) {
176 return date_i18n( get_option( 'date_format' ), strtotime( $item['last_crawled'] ) );
180 * Formatting the output of the column first detected into a dateformat
186 protected function column_first_detected( $item ) {
187 return date_i18n( get_option( 'date_format' ), strtotime( $item['first_detected'] ) );
197 protected function column_url( $item ) {
200 if ( $this->can_create_redirect() ) {
204 $modal_height = $this->modal_box( $item['url'] );
206 $actions['create_redirect'] = '<a title="' . __( 'Create a redirect', 'wordpress-seo' ) . '" href="#TB_inline?width=600&height=' . $this->modal_heights[ $modal_height ] . '&inlineId=redirect-' . md5( $item['url'] ) . '" class="thickbox">' . __( 'Create redirect', 'wordpress-seo' ) . '</a>';
209 $actions['view'] = '<a href="' . $item['url'] . '" target="_blank">' . __( 'View', 'wordpress-seo' ) . '</a>';
210 $actions['markasfixed'] = '<a href="javascript:wpseo_mark_as_fixed(\'' . urlencode( $item['url'] ) . '\');">' . __( 'Mark as fixed', 'wordpress-seo' ) . '</a>';
213 '<span class="value">%1$s</span> %2$s',
215 $this->row_actions( $actions )
220 * Running the setup of the columns
222 private function setup_columns() {
223 $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
227 * Check if the current category allow creating redirects
230 private function can_create_redirect() {
231 return in_array( $this->current_view, array( 'soft_404', 'not_found', 'access_denied' ) );
235 * Setting the table navigation
237 * @param int $total_items
238 * @param int $posts_per_page
240 private function set_pagination( $total_items, $posts_per_page ) {
241 $this->set_pagination_args( array(
242 'total_items' => $total_items,
243 'total_pages' => ceil( ( $total_items / $posts_per_page ) ),
244 'per_page' => $posts_per_page,
251 private function parse_items() {
252 if ( is_array( $this->items ) && count( $this->items ) > 0 ) {
253 if ( ! empty( $this->search_string ) ) {
257 $this->set_pagination( count( $this->items ), $this->per_page );
260 $this->paginate_items();
265 * Search through the items
267 private function do_search() {
270 foreach ( $this->items as $item ) {
271 foreach ( $item as $value ) {
272 if ( stristr( $value, $this->search_string ) !== false ) {
279 $this->items = $results;
283 * Running the pagination
285 private function paginate_items() {
286 // Setting the starting point. If starting point is below 1, overwrite it with value 0, otherwise it will be sliced of at the back.
287 $slice_start = ( $this->current_page - 1 );
288 if ( $slice_start < 0 ) {
292 // Apply 'pagination'.
293 $this->items = array_slice( $this->items, ( $slice_start * $this->per_page ), $this->per_page );
297 * Sort the items by callback
299 private function sort_items() {
301 usort( $this->items, array( $this, 'do_reorder' ) );
305 * Doing the sorting of the issues
312 private function do_reorder( $a, $b ) {
313 // If no sort, default to title.
314 $orderby = ( $orderby = filter_input( INPUT_GET, 'orderby' ) ) ? $orderby : 'url';
316 // If no order, default to asc.
317 $order = ( $order = filter_input( INPUT_GET, 'order' ) ) ? $order : 'asc';
319 // When there is a raw field of it, sort by this field.
320 if ( array_key_exists( $orderby . '_raw', $a ) && array_key_exists( $orderby . '_raw', $b ) ) {
321 $orderby = $orderby . '_raw';
324 // Determine sort order.
325 $result = strcmp( $a[ $orderby ], $b[ $orderby ] );
327 // Send final sort direction to usort.
328 return ( $order === 'asc' ) ? $result : ( - $result );
338 private function modal_box( $url ) {
339 $current_redirect = false;
340 $view_type = $this->modal_box_type( $url, $current_redirect );
342 require WPSEO_PATH . '/admin/google_search_console/views/gsc-create-redirect.php';
348 * Determine which model box type should be rendered
351 * @param string $current_redirect
355 private function modal_box_type( $url, &$current_redirect ) {
356 if ( defined( 'WPSEO_PREMIUM_FILE' ) && class_exists( 'WPSEO_URL_Redirect_Manager' ) ) {
357 static $redirect_manager;
359 if ( ! $redirect_manager ) {
360 $redirect_manager = new WPSEO_URL_Redirect_Manager();
363 if ( $current_redirect = $redirect_manager->search_url( $url ) ) {
364 return 'already_exists';
375 * Showing the hidden fields used by the AJAX requests
377 * @param string $platform
379 private function show_fields( $platform ) {
380 echo "<input type='hidden' name='wpseo_gsc_nonce' value='" . wp_create_nonce( 'wpseo_gsc_nonce' ) . "' />";
381 echo "<input id='field_platform' type='hidden' name='platform' value='{$platform}' />";
382 echo "<input id='field_category' type='hidden' name='category' value='{$this->current_view}' />";