404 to 301 - Version 2.1.0

Version Description

(20/12/2015) = New Feature

  • New option to set items per page from error log listing page.
  • New option to show or hide items from listing table (Screen option).

Improvements

  • Improved error listing page table structure.

Bug Fixes

  • Fixed issue - Null value issue when no Referrer or User Agent found.
  • Fixed issue - Clearing errors and redirecting.
Download this release

Release Info

Developer joelcj91
Plugin Icon 128x128 404 to 301
Version 2.1.0
Comparing to
See all releases

Code changes from version 2.0.9 to 2.1.0

404-to-301.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: 404 to 301
4
  * Plugin URI: http://iscode.co/products/404-to-301/
5
  * Description: Automatically redirect all <strong>404 errors</strong> to any page using <strong>301 redirect for SEO</strong>. You can <strong>redirect and log</strong> every 404 errors. No more 404 errors in Webmaster tool.
6
- * Version: 2.0.9
7
  * Author: Joel James
8
  * Author URI: http://iscode.co/
9
  * Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=XUVWY8HUBUXY4
@@ -28,7 +28,7 @@
28
  * @package I4T3
29
  * @category Core
30
  * @author Joel James
31
- * @version 2.0.7
32
  */
33
 
34
  // If this file is called directly, abort.
@@ -52,7 +52,7 @@ if(!defined('I4T3_DB_VERSION')) {
52
  define( 'I4T3_DB_VERSION', '3' );
53
  }
54
  if(!defined('I4T3_VERSION')) {
55
- define( 'I4T3_VERSION', '2.0.9' );
56
  }
57
  // Set who all can access 404 settings. You can change this if you want to give others access.
58
  if(!defined('I4T3_ADMIN_PERMISSION')) {
3
  * Plugin Name: 404 to 301
4
  * Plugin URI: http://iscode.co/products/404-to-301/
5
  * Description: Automatically redirect all <strong>404 errors</strong> to any page using <strong>301 redirect for SEO</strong>. You can <strong>redirect and log</strong> every 404 errors. No more 404 errors in Webmaster tool.
6
+ * Version: 2.1.0
7
  * Author: Joel James
8
  * Author URI: http://iscode.co/
9
  * Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=XUVWY8HUBUXY4
28
  * @package I4T3
29
  * @category Core
30
  * @author Joel James
31
+ * @version 2.1.0
32
  */
33
 
34
  // If this file is called directly, abort.
52
  define( 'I4T3_DB_VERSION', '3' );
53
  }
54
  if(!defined('I4T3_VERSION')) {
55
+ define( 'I4T3_VERSION', '2.1.0' );
56
  }
57
  // Set who all can access 404 settings. You can change this if you want to give others access.
58
  if(!defined('I4T3_ADMIN_PERMISSION')) {
admin/class-404-to-301-admin.php CHANGED
@@ -52,6 +52,15 @@ class _404_To_301_Admin {
52
  * @var string $gnrl_options Get the options saved in db.
53
  */
54
  private $gnrl_options;
 
 
 
 
 
 
 
 
 
55
 
56
  /**
57
  * Initialize the class and set its properties.
@@ -71,7 +80,7 @@ class _404_To_301_Admin {
71
 
72
 
73
  /**
74
- * Register the stylesheets for the Dashboard.
75
  *
76
  * This function is used to register all the required stylesheets for
77
  * dashboard. Styles will be registered only for i4t3 pages for performance.
@@ -160,7 +169,7 @@ class _404_To_301_Admin {
160
  public function i4t3_create_404_to_301_menu(){
161
 
162
  // Error log menu
163
- add_menu_page(
164
  __( '404 Error Logs', '404-to-301' ),
165
  __( '404 Error Logs', '404-to-301' ),
166
  I4T3_ADMIN_PERMISSION,
@@ -169,6 +178,8 @@ class _404_To_301_Admin {
169
  'dashicons-redo',
170
  90
171
  );
 
 
172
 
173
  // 404 to 301 settings menu
174
  add_submenu_page(
@@ -180,7 +191,40 @@ class _404_To_301_Admin {
180
  array( $this, 'i4t3_admin_page' )
181
  );
182
  }
183
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
 
185
 
186
  /**
@@ -192,14 +236,26 @@ class _404_To_301_Admin {
192
  */
193
  public function i4t3_render_list_page(){
194
 
195
- global $i4t3_errorlogtable;
196
- $i4t3_errorlogtable = new _404_To_301_Logs( $this->table );
197
- echo '<div class="wrap"><h2>'. __( '404 Error Logs', '404-to-301' ) .'</h2>';
198
- $i4t3_errorlogtable->prepare_items();
199
- echo '<form method="post">
200
- <input type="hidden" name="page" value="i4t3_logs_list">';
201
- $i4t3_errorlogtable->display();
202
- echo '</form></div>';
 
 
 
 
 
 
 
 
 
 
 
 
203
  }
204
 
205
 
52
  * @var string $gnrl_options Get the options saved in db.
53
  */
54
  private $gnrl_options;
55
+
56
+ /**
57
+ * The options from db.
58
+ *
59
+ * @since 2.1.0
60
+ * @access private
61
+ * @var mixed $list_table Class object for listing table.
62
+ */
63
+ private $list_table;
64
 
65
  /**
66
  * Initialize the class and set its properties.
80
 
81
 
82
  /**
83
+ * Register the stylesheet for the Dashboard.
84
  *
85
  * This function is used to register all the required stylesheets for
86
  * dashboard. Styles will be registered only for i4t3 pages for performance.
169
  public function i4t3_create_404_to_301_menu(){
170
 
171
  // Error log menu
172
+ $hook = add_menu_page(
173
  __( '404 Error Logs', '404-to-301' ),
174
  __( '404 Error Logs', '404-to-301' ),
175
  I4T3_ADMIN_PERMISSION,
178
  'dashicons-redo',
179
  90
180
  );
181
+
182
+ add_action( "load-$hook", array( $this, 'screen_option' ) );
183
 
184
  // 404 to 301 settings menu
185
  add_submenu_page(
191
  array( $this, 'i4t3_admin_page' )
192
  );
193
  }
194
+
195
+
196
+ /**
197
+ * To set the screen of the error listing page.
198
+ *
199
+ * @since 2.1.0
200
+ * @author Joel James.
201
+ */
202
+ public static function set_screen( $status, $option, $value ) {
203
+ return $value;
204
+ }
205
+
206
+ /**
207
+ * To make screen options for 404 to 301 listing.
208
+ *
209
+ * This function is used to show screen options like entries per page,
210
+ * show/hide columns etc.
211
+ *
212
+ * @since 2.1.0
213
+ * @author Joel James.
214
+ */
215
+ public function screen_option() {
216
+
217
+ $option = 'per_page';
218
+ $args = [
219
+ 'label' => __( 'Error Logs', '404-to-301' ),
220
+ 'default' => 5,
221
+ 'option' => 'logs_per_page'
222
+ ];
223
+
224
+ add_screen_option( $option, $args );
225
+
226
+ $this->list_table = new _404_To_301_Logs( $this->table );
227
+ }
228
 
229
 
230
  /**
236
  */
237
  public function i4t3_render_list_page(){
238
 
239
+ ?>
240
+ <div class="wrap">
241
+ <h2><?php _e( '404 Error Logs', '404-to-301' ); ?></h2>
242
+
243
+ <div id="poststuff">
244
+ <div id="post-body" class="metabox-holder">
245
+ <div id="post-body-content">
246
+ <div class="meta-box-sortables ui-sortable">
247
+ <form method="post">
248
+ <?php
249
+ $this->list_table->prepare_items();
250
+ $this->list_table->display(); ?>
251
+ </form>
252
+ </div>
253
+ </div>
254
+ </div>
255
+ <br class="clear">
256
+ </div>
257
+ </div>
258
+ <?php
259
  }
260
 
261
 
admin/class-404-to-301-logs.php CHANGED
@@ -9,7 +9,6 @@ if ( ! defined( 'WPINC' ) ) {
9
  * Details here - https://codex.wordpress.org/Class_Reference/WP_List_Table
10
  * So we have copied this class and using independently to avoid future issues.
11
  */
12
-
13
  if( ! class_exists( 'WP_List_Table_404' ) ) {
14
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/core/class-wp-list-table.php';
15
  }
@@ -28,86 +27,69 @@ if( ! class_exists( 'WP_List_Table_404' ) ) {
28
  */
29
  class _404_To_301_Logs extends WP_List_Table_404 {
30
 
31
- /**
32
  * The table name of this plugin.
33
  *
34
  * @since 2.0.0
35
  * @access private
 
36
  * @var string $table The table name of this plugin in db.
37
  */
38
- private $table;
39
-
40
- /**
41
- * Data to be displayed in table.
42
- *
43
- * @since 2.0.0
44
- * @access private
45
- * @var array $log_data The error log data from db.
46
- */
47
- private $log_data;
48
-
49
-
50
- /**
51
  * Initialize the class and set its properties.
52
  *
53
  * @since 2.0.0
54
- * @var string $table The name of the table of plugin.
55
- * @var array $log_data The error log data from db.
56
- * @var global $status, $page Global variables from WordPress
57
  */
58
- public function __construct( $table ) {
59
 
60
- global $status, $page;
61
- $this->table = $table;
62
- $this->log_data = $this->i4t3_get_log_data();
63
 
64
- parent::__construct( array(
65
- 'singular' => __( 'i4t3_log', __( '404 Log', '404-to-301' ) ), //singular name of the listed records
66
- 'plural' => __( 'i4t3_logs', __( '404 Logs', '404-to-301' ) ), //plural name of the listed records
67
- 'ajax' => false //does this table support ajax?
68
- )
69
- );
70
- }
71
 
72
- /**
 
 
 
73
  * Error log data to be displayed.
74
  *
75
  * Getting the error log data from the database and converts it to
76
  * the required structure.
 
 
 
77
  *
78
  * @since 2.0.0
79
  * @author Joel James.
80
  * @var $wpdb Global variable for db class.
81
  * @uses apply_filters i4t3_log_list_per_page Custom filter to modify per page view.
82
- * @return array $error_data Array of error log data.
83
  */
84
- public function i4t3_get_log_data() {
85
 
86
- global $wpdb;
87
- // Let us hide sql query errors
88
- $wpdb->hide_errors();
89
-
90
- // Per page filter
91
- $per_page = apply_filters( 'i4t3_log_list_per_page', 10 );
92
-
93
- $current_page = $this->get_pagenum();
94
- $limit = ( $current_page-1 )* $per_page;
95
-
96
- // If no sort, default to title
97
- $orderby = ( isset( $_GET['orderby'] ) ) ? $this->i4t3_get_sort_column_filtered( $_GET['orderby'] ) : 'date';
98
- // If no order, default to asc
99
- $order = ( isset($_GET['order'] ) && 'desc' == $_GET['order'] ) ? 'DESC' : 'ASC';
100
-
101
- $log_data = $wpdb->get_results( $wpdb->prepare( "SELECT SQL_CALC_FOUND_ROWS id as ID,date,url,ref,ip,ua FROM $this->table ORDER BY $orderby $order LIMIT %d,%d", array( $limit, $per_page) ), ARRAY_A );
102
 
103
- $error_data = array();
104
- foreach ($log_data as $key) {
105
- $error_data[] = $key;
106
- }
107
-
108
- return $error_data;
109
- }
 
 
110
 
 
 
 
 
111
  /**
112
  * Filter the sorting parameters.
113
  *
@@ -121,7 +103,7 @@ class _404_To_301_Logs extends WP_List_Table_404 {
121
  * @var $filtered_column Value aftet filtering.
122
  * @return string $filtered_column.
123
  */
124
- public function i4t3_get_sort_column_filtered( $column ) {
125
 
126
  $allowed_columns = array( 'date','url','ref','ip' );
127
 
@@ -134,7 +116,61 @@ class _404_To_301_Logs extends WP_List_Table_404 {
134
  }
135
 
136
 
137
- /**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  * Empty record text.
139
  *
140
  * Custom text to display where there is nothing to display in error
@@ -144,13 +180,12 @@ class _404_To_301_Logs extends WP_List_Table_404 {
144
  * @author Joel James.
145
  * @return void
146
  */
147
- public function no_items() {
148
-
149
- _e( 'Ulta pulta..! Seems like you had no errors to log.' );
150
- }
151
 
152
 
153
- /**
154
  * Default columns in list table.
155
  *
156
  * To show columns in error log list table. If there is nothing
@@ -158,90 +193,38 @@ class _404_To_301_Logs extends WP_List_Table_404 {
158
  *
159
  * @since 2.0.0
160
  * @author Joel James.
161
- * @uses switch To switch between colums.
162
  */
163
- public function column_default( $item, $column_name ) {
164
-
165
- switch( $column_name ) {
166
- case 'date':
167
  case 'url':
168
  case 'ref':
169
  case 'ip':
170
  case 'ua':
171
- return $item[ $column_name ];
172
- default:
173
- return print_r( $item, true ) ; //Show the whole array for troubleshooting purposes
174
- }
175
- }
176
-
177
 
178
- /**
179
- * Make colums sortable
180
  *
181
- * To make our custom columns in list table sortable. We have included
182
- * 4 columns except 'User Agent' column here.
183
  *
184
- * @since 2.0.0
185
  * @author Joel James.
186
- * @return array $sortable_columns Array of columns to enable sorting.
187
- */
188
- public function get_sortable_columns() {
189
-
190
- $sortable_columns = array(
191
- 'date' => array('date',false),
192
- 'url' => array('url',false),
193
- 'ref' => array('ref',false),
194
- 'ip' => array('ip',false)
195
- );
196
-
197
- return $sortable_columns;
198
- }
199
-
200
-
201
- /**
202
- * Column titles
203
- *
204
- * Custom column titles to be displayed in listing table. You can change this to anything
205
- *
206
- * @since 2.0.0
207
- * @author Joel James.
208
- * @return array $columns Array of cloumn titles.
209
- */
210
- public function get_columns() {
211
-
212
- $columns = array(
213
- 'date'=> __( 'Date and Time', '404-to-301' ),
214
- 'url' => __( '404 Path', '404-to-301' ),
215
- 'ref' => __( 'Came From', '404-to-301' ), // referer
216
- 'ip' => __( 'IP Address', '404-to-301' ),
217
- 'ua' => __( 'User Agent', '404-to-301' )
218
- );
219
-
220
- return $columns;
221
- }
222
-
223
-
224
- /**
225
- * Bulk actions drop down
226
- *
227
- * Options to be added to the bulk actions drop down for users
228
- * to select. We have added 'clear log' action.
229
- *
230
- * @since 2.0.0
231
- * @author Joel James.
232
- * @return array $actions Options to be added to the action select box.
233
  */
234
- public function get_bulk_actions() {
235
-
236
- $actions = array(
237
- 'clear' => __( 'Clear Logs', '404-to-301' )
238
- );
239
-
240
- return $actions;
241
- }
242
 
243
 
244
- /**
245
  * To modify the date column data
246
  *
247
  * This function is used to modify the column data for date in listing table.
@@ -251,16 +234,21 @@ class _404_To_301_Logs extends WP_List_Table_404 {
251
  * @author Joel James.
252
  * @return string $date_data Date column text data.
253
  */
254
- public function column_date( $item ) {
255
-
256
- // Apply filter - i4t3_log_list_date_column
257
- $date_data = apply_filters( 'i4t3_log_list_date_column', date("j M Y, g:i a", strtotime($item['date'])) );
258
 
259
- return $date_data;
260
- }
261
-
262
-
263
- /**
 
 
 
 
 
 
 
 
264
  * To modify the url column data
265
  *
266
  * This function is used to modify the column data for url in listing table.
@@ -273,13 +261,13 @@ class _404_To_301_Logs extends WP_List_Table_404 {
273
  public function column_url( $item ) {
274
 
275
  // Apply filter - i4t3_log_list_url_column
276
- $url_data = apply_filters( 'i4t3_log_list_url_column', '<p class="i4t3-url-p">'.$item['url'].'</p>' );
277
 
278
  return $url_data;
279
  }
280
-
281
-
282
- /**
283
  * To modify the ref column data
284
  *
285
  * This function is used to modify the column data for ref in listing table.
@@ -292,13 +280,119 @@ class _404_To_301_Logs extends WP_List_Table_404 {
292
  public function column_ref( $item ) {
293
 
294
  // Apply filter - i4t3_log_list_ref_column
295
- $ref_data = apply_filters( 'i4t3_log_list_ref_column', '<a href="'.$item['ref'].'">'.$item['ref'].'</a>' );
296
 
297
  return $ref_data;
298
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
299
 
300
 
301
- /**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
302
  * Main function to output the listing table using WP_List_Table class
303
  *
304
  * As name says, this function is used to prepare the lsting table based
@@ -313,55 +407,73 @@ class _404_To_301_Logs extends WP_List_Table_404 {
313
  * @uses $wpdb The global variable for WordPress database operations.
314
  * @uses hide_errors() To hide if there are SQL query errors.
315
  */
316
- public function prepare_items() {
317
-
318
- global $wpdb;
319
- // Let us hide sql query errors
320
- $wpdb->hide_errors();
321
-
322
- $columns = $this->get_columns();
323
- $hidden = array();
324
- $sortable = $this->get_sortable_columns();
325
- $this->_column_headers = array( $columns, $hidden, $sortable );
326
-
327
- $current_page = $this->get_pagenum();
328
 
329
- // Per page filter
330
- $per_page = apply_filters( 'i4t3_log_list_per_page', 10 );
331
-
332
- $total = $wpdb->get_var( "SELECT count(id) as ID FROM $this->table" );
333
-
334
- if( $total ) {
335
- $total_items = $total;
336
- } else {
337
- $total_items = count( $this->log_data );
338
- }
339
 
340
- // only ncessary because we have sample data
341
- $this->set_pagination_args( array(
342
- 'total_items' => $total_items, //WE have to calculate the total number of items
343
- 'per_page' => $per_page //WE have to determine how many items to show on a page
344
- )
345
- );
346
 
347
- $this->items = $this->log_data;
348
- $this->process_bulk_action(); // To perform bulk delete action
349
- }
350
 
 
 
 
 
351
 
352
- /**
 
 
 
 
353
  * To perform bulk actions.
354
  *
355
  * This function is used to check if bulk action is set in post.
356
  * If set it will call the required functions to perform the task.
357
  *
358
- * @since 2.0.0
359
  * @author Joel James.
360
  * @uses wp_verify_nonce To verify if the request is from WordPress.
361
  */
362
- public function process_bulk_action() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
363
 
364
- if( isset($_POST['_wpnonce'])) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
 
366
  $nonce = '';
367
  $action = '';
@@ -372,16 +484,54 @@ class _404_To_301_Logs extends WP_List_Table_404 {
372
  $action = 'bulk-' . $this->_args['plural'];
373
  }
374
 
375
- if ( ! wp_verify_nonce( $nonce, $action ) )
376
- wp_die( 'Nope! Security check failed!' );
 
 
 
 
 
 
 
377
 
378
- else if( 'clear' === $this->current_action() ) {
379
- global $wpdb;
380
- // Let us hide sql query errors if any
381
- $wpdb->hide_errors();
382
- $total = $wpdb->query( "DELETE FROM $this->table" );
 
 
 
383
  }
384
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
385
 
386
- }
387
  }
9
  * Details here - https://codex.wordpress.org/Class_Reference/WP_List_Table
10
  * So we have copied this class and using independently to avoid future issues.
11
  */
 
12
  if( ! class_exists( 'WP_List_Table_404' ) ) {
13
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/core/class-wp-list-table.php';
14
  }
27
  */
28
  class _404_To_301_Logs extends WP_List_Table_404 {
29
 
30
+ /**
31
  * The table name of this plugin.
32
  *
33
  * @since 2.0.0
34
  * @access private
35
+ * @author Joel James.
36
  * @var string $table The table name of this plugin in db.
37
  */
38
+ private static $table;
39
+
40
+ /**
 
 
 
 
 
 
 
 
 
 
41
  * Initialize the class and set its properties.
42
  *
43
  * @since 2.0.0
44
+ * @author Joel James.
45
+ * @var string $table The name of the table of plugin.
 
46
  */
47
+ public function __construct( $table ) {
48
 
49
+ self::$table = $table;
 
 
50
 
51
+ parent::__construct( [
52
+ 'singular' => __( '404 Error Log', '404-to-301' ), //singular name of the listed records
53
+ 'plural' => __( '404 Error Logs', '404-to-301' ), //plural name of the listed records
54
+ 'ajax' => false //does this table support ajax?
55
+ ] );
 
 
56
 
57
+ }
58
+
59
+
60
+ /**
61
  * Error log data to be displayed.
62
  *
63
  * Getting the error log data from the database and converts it to
64
  * the required structure.
65
+ *
66
+ * @param int $per_page
67
+ * @param int $page_number
68
  *
69
  * @since 2.0.0
70
  * @author Joel James.
71
  * @var $wpdb Global variable for db class.
72
  * @uses apply_filters i4t3_log_list_per_page Custom filter to modify per page view.
73
+ * @return mixed $error_data Array of error log data.
74
  */
75
+ public static function i4t3_get_log_data( $per_page = 5, $page_number = 1 ) {
76
 
77
+ global $wpdb;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
+ $offset = ( $page_number - 1 ) * $per_page;
80
+
81
+ // If no sort, default to title
82
+ $orderby = ( isset( $_REQUEST['orderby'] ) ) ? self::i4t3_get_sort_column_filtered( $_REQUEST['orderby'] ) : 'date';
83
+
84
+ // If no order, default to asc
85
+ $order = ( isset( $_REQUEST['order'] ) && 'desc' == $_REQUEST['order'] ) ? 'DESC' : 'ASC';
86
+
87
+ $result = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM ".self::$table." ORDER BY $orderby $order LIMIT %d OFFSET %d", array( $per_page, $offset) ), 'ARRAY_A' );
88
 
89
+ return $result;
90
+ }
91
+
92
+
93
  /**
94
  * Filter the sorting parameters.
95
  *
103
  * @var $filtered_column Value aftet filtering.
104
  * @return string $filtered_column.
105
  */
106
+ public static function i4t3_get_sort_column_filtered( $column ) {
107
 
108
  $allowed_columns = array( 'date','url','ref','ip' );
109
 
116
  }
117
 
118
 
119
+ /**
120
+ * Delete a single record from table.
121
+ *
122
+ * This function is used to clear the selected errors
123
+ * from error logs table.
124
+ *
125
+ * @since 2.1.0
126
+ * @author Joel James.
127
+ * @param int $id ID
128
+ */
129
+ public static function delete_error_logs( $id ) {
130
+ global $wpdb;
131
+
132
+ $wpdb->delete(
133
+ self::$table,
134
+ [ 'id' => $id ],
135
+ [ '%d' ]
136
+ );
137
+ }
138
+
139
+
140
+ /**
141
+ * Delete all records at once from database.
142
+ *
143
+ * This function is used to clear the error logs table.
144
+ *
145
+ * @since 2.1.0
146
+ * @author Joel James.
147
+ */
148
+ public static function delete_error_all_logs() {
149
+
150
+ global $wpdb;
151
+
152
+ $wpdb->query( "DELETE FROM ".self::$table."" );
153
+ }
154
+
155
+
156
+ /**
157
+ * Get the count of total records in table.
158
+ *
159
+ * @since 2.1.0
160
+ * @author Joel James.
161
+ * @return null|string
162
+ */
163
+ public static function record_count() {
164
+
165
+ global $wpdb;
166
+
167
+ $sql = "SELECT COUNT(id) FROM ".self::$table;
168
+
169
+ return $wpdb->get_var( $sql );
170
+ }
171
+
172
+
173
+ /**
174
  * Empty record text.
175
  *
176
  * Custom text to display where there is nothing to display in error
180
  * @author Joel James.
181
  * @return void
182
  */
183
+ public function no_items() {
184
+ _e( 'Ulta pulta..! Seems like you had no errors to log.', '404-to-301' );
185
+ }
 
186
 
187
 
188
+ /**
189
  * Default columns in list table.
190
  *
191
  * To show columns in error log list table. If there is nothing
193
  *
194
  * @since 2.0.0
195
  * @author Joel James.
196
+ * @uses switch To switch between columns.
197
  */
198
+ public function column_default( $item, $column_name ) {
199
+ switch ( $column_name ) {
200
+ case 'date':
 
201
  case 'url':
202
  case 'ref':
203
  case 'ip':
204
  case 'ua':
205
+ return $item[ $column_name ];
206
+ default:
207
+ return print_r( $item, true ); //Show the whole array for troubleshooting purposes
208
+ }
209
+ }
 
210
 
211
+ /**
212
+ * To output checkbox for bulk actions.
213
  *
214
+ * This function is used to add new checkbox for all entries in
215
+ * the listing table. We use this checkbox to perform bulk actions.
216
  *
217
+ * @since 2.1.0
218
  * @author Joel James.
219
+ * @return string Checkbox.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  */
221
+ function column_cb( $item ) {
222
+
223
+ return sprintf( '<input type="checkbox" name="bulk-delete[]" value="%s"/>', $item['id'] );
224
+ }
 
 
 
 
225
 
226
 
227
+ /**
228
  * To modify the date column data
229
  *
230
  * This function is used to modify the column data for date in listing table.
234
  * @author Joel James.
235
  * @return string $date_data Date column text data.
236
  */
237
+ function column_date( $item ) {
 
 
 
238
 
239
+ $delete_nonce = wp_create_nonce( 'i4t3_delete_log' );
240
+
241
+ $title = apply_filters( 'i4t3_log_list_date_column', date("j M Y, g:i a", strtotime($item['date'])) );
242
+ $confirm = __( 'Are you sure you want to delete this item?', '404-to-301' );
243
+ $actions = [
244
+ 'delete' => sprintf( '<a href="?page=%s&action=%s&log=%s&_wpnonce=%s" onclick="return confirm(\'%s\');">'. __( 'Delete', '404-to-301' ) .'</a>', esc_attr( $_REQUEST['page'] ), 'delete', absint( $item['id'] ), $delete_nonce, $confirm )
245
+ ];
246
+
247
+ return $title . $this->row_actions( $actions );
248
+ }
249
+
250
+
251
+ /**
252
  * To modify the url column data
253
  *
254
  * This function is used to modify the column data for url in listing table.
261
  public function column_url( $item ) {
262
 
263
  // Apply filter - i4t3_log_list_url_column
264
+ $url_data = apply_filters( 'i4t3_log_list_url_column', $this->get_empty_text( '<p class="i4t3-url-p">'.$item['url'].'</p>', $item['url'] ) );
265
 
266
  return $url_data;
267
  }
268
+
269
+
270
+ /**
271
  * To modify the ref column data
272
  *
273
  * This function is used to modify the column data for ref in listing table.
280
  public function column_ref( $item ) {
281
 
282
  // Apply filter - i4t3_log_list_ref_column
283
+ $ref_data = apply_filters( 'i4t3_log_list_ref_column', $this->get_empty_text( '<a href="'.$item['ref'].'">'.$item['ref'].'</a>', $item['ref'] ) );
284
 
285
  return $ref_data;
286
  }
287
+
288
+
289
+ /**
290
+ * To modify the user agent column data
291
+ *
292
+ * This function is used to modify the column data for user agent in listing table.
293
+ * We can change styles, texts etc. using this function.
294
+ *
295
+ * @since 2.0.9.1
296
+ * @author Joel James.
297
+ * @return string $ua_data Ref column text data.
298
+ */
299
+ public function column_ua( $item ) {
300
+
301
+ // Apply filter - i4t3_log_list_ref_column
302
+ $ua_data = apply_filters( 'i4t3_log_list_ua_column', $this->get_empty_text( $item['ua'], $item['ua'] ) );
303
+
304
+ return $ua_data;
305
+ }
306
+
307
+
308
+ /**
309
+ * To modify the ip column data
310
+ *
311
+ * This function is used to modify the column data for ip in listing table.
312
+ * We can change styles, texts etc. using this function.
313
+ *
314
+ * @since 2.0.9.1
315
+ * @author Joel James.
316
+ * @return string $ip Ref column text data.
317
+ */
318
+ public function column_ip( $item ) {
319
+
320
+ // Apply filter - i4t3_log_list_ref_column
321
+ $ip = apply_filters( 'i4t3_log_list_ip_column', $this->get_empty_text( $item['ip'], $item['ip'] ) );
322
+
323
+ return $ip;
324
+ }
325
 
326
 
327
+ /**
328
+ * Column titles
329
+ *
330
+ * Custom column titles to be displayed in listing table. You can change this to anything
331
+ *
332
+ * @since 2.0.0
333
+ * @author Joel James.
334
+ * @return array $columns Array of cloumn titles.
335
+ */
336
+ function get_columns() {
337
+
338
+ $columns = [
339
+ 'cb' => '<input type="checkbox" style="width: 5%;" />',
340
+ 'date'=> __( 'Date and Time', '404-to-301' ),
341
+ 'url' => __( '404 Path', '404-to-301' ),
342
+ 'ref' => __( 'Came From', '404-to-301' ), // referer
343
+ 'ip' => __( 'IP Address', '404-to-301' ),
344
+ 'ua' => __( 'User Agent', '404-to-301' )
345
+ ];
346
+
347
+ return $columns;
348
+ }
349
+
350
+
351
+ /**
352
+ * Make columns sortable
353
+ *
354
+ * To make our custom columns in list table sortable. We have included
355
+ * 4 columns except 'User Agent' column here.
356
+ *
357
+ * @since 2.0.0
358
+ * @author Joel James.
359
+ * @return array $sortable_columns Array of columns to enable sorting.
360
+ */
361
+ public function get_sortable_columns() {
362
+
363
+ $sortable_columns = array(
364
+ 'date' => array( 'date', true ),
365
+ 'url' => array('url',false),
366
+ 'ref' => array('ref',false),
367
+ 'ip' => array('ip',false)
368
+ );
369
+
370
+ return $sortable_columns;
371
+ }
372
+
373
+ /**
374
+ * Bulk actions drop down
375
+ *
376
+ * Options to be added to the bulk actions drop down for users
377
+ * to select. We have added 'Delete' actions.
378
+ *
379
+ * @since 2.0.0
380
+ * @modified 2.1.0
381
+ * @author Joel James.
382
+ * @return array $actions Options to be added to the action select box.
383
+ */
384
+ public function get_bulk_actions() {
385
+
386
+ $actions = [
387
+ 'bulk-delete' => __('Delete Selected', '404-to-301' ),
388
+ 'bulk-all-delete' => __( 'Delete All', '404-to-301' )
389
+ ];
390
+
391
+ return $actions;
392
+ }
393
+
394
+
395
+ /**
396
  * Main function to output the listing table using WP_List_Table class
397
  *
398
  * As name says, this function is used to prepare the lsting table based
407
  * @uses $wpdb The global variable for WordPress database operations.
408
  * @uses hide_errors() To hide if there are SQL query errors.
409
  */
410
+ public function prepare_items() {
 
 
 
 
 
 
 
 
 
 
 
411
 
412
+ $this->_column_headers = $this->get_column_info();
 
 
 
 
 
 
 
 
 
413
 
414
+ /** Process bulk action */
415
+ $this->process_bulk_action();
 
 
 
 
416
 
417
+ $per_page = $this->get_items_per_page( 'logs_per_page', 5 );
418
+ $current_page = $this->get_pagenum();
419
+ $total_items = self::record_count();
420
 
421
+ $this->set_pagination_args( [
422
+ 'total_items' => $total_items, //WE have to calculate the total number of items
423
+ 'per_page' => $per_page //WE have to determine how many items to show on a page
424
+ ] );
425
 
426
+ $this->items = self::i4t3_get_log_data( $per_page, $current_page );
427
+ }
428
+
429
+
430
+ /**
431
  * To perform bulk actions.
432
  *
433
  * This function is used to check if bulk action is set in post.
434
  * If set it will call the required functions to perform the task.
435
  *
436
+ * @since 2.1.0
437
  * @author Joel James.
438
  * @uses wp_verify_nonce To verify if the request is from WordPress.
439
  */
440
+ public function process_bulk_action() {
441
+
442
+ //Detect when a bulk action is being triggered...
443
+ if ( 'delete' === $this->current_action() ) {
444
+
445
+ // In our file that handles the request, verify the nonce.
446
+ $nonce = esc_attr( $_REQUEST['_wpnonce'] );
447
+
448
+ if ( ! wp_verify_nonce( $nonce, 'i4t3_delete_log' ) ) {
449
+ wp_die( 'Go get a life script kiddies' );
450
+ } else {
451
+
452
+ self::delete_error_logs( absint( $_GET['log'] ) );
453
+ wp_redirect( esc_url( add_query_arg() ) );
454
+ exit;
455
+ }
456
+
457
+ }
458
 
459
+ $this->bulk_delete_actions();
460
+ }
461
+
462
+
463
+ /**
464
+ * To perform bulk delete actions.
465
+ *
466
+ * This function is used to perform the bulk delete
467
+ * actions. Selected data delete and whole data delete
468
+ * is being performed here.
469
+ *
470
+ * @since 2.1.0
471
+ * @author Joel James.
472
+ * @uses wp_verify_nonce To verify if the request is from WordPress.
473
+ */
474
+ public function bulk_delete_actions() {
475
+
476
+ if( isset($_POST['_wpnonce'])) {
477
 
478
  $nonce = '';
479
  $action = '';
484
  $action = 'bulk-' . $this->_args['plural'];
485
  }
486
 
487
+ if ( ! wp_verify_nonce( $nonce, $action ) ) {
488
+ wp_die( 'Go get a life script kiddies' );
489
+ }
490
+
491
+ // If the delete bulk action is triggered
492
+ else if ( ( isset( $_POST['action'] ) && $_POST['action'] == 'bulk-delete' )
493
+ || ( isset( $_POST['action2'] ) && $_POST['action2'] == 'bulk-delete' ) ) {
494
+
495
+ $delete_ids = esc_sql( $_POST['bulk-delete'] );
496
 
497
+ // loop over the array of record IDs and delete them
498
+ foreach ( $delete_ids as $id ) {
499
+ self::delete_error_logs( $id );
500
+
501
+ }
502
+
503
+ wp_redirect( esc_url( add_query_arg() ) );
504
+ exit;
505
  }
506
+
507
+ // If the delete all bulk action is triggered
508
+ else if ( ( isset( $_POST['action'] ) && $_POST['action'] == 'bulk-all-delete' )
509
+ || ( isset( $_POST['action2'] ) && $_POST['action2'] == 'bulk-all-delete' ) ) {
510
+
511
+ self::delete_error_all_logs();
512
+ wp_redirect( esc_url( add_query_arg() ) );
513
+ exit;
514
+ }
515
+ }
516
+ }
517
+
518
+
519
+ /**
520
+ * To make clear error text if value is N/A.
521
+ *
522
+ * This function is used to show the N/A text in red colour if the field value
523
+ * is not available.
524
+ *
525
+ * @since 2.1.0
526
+ * @author Joel James.
527
+ */
528
+ public function get_empty_text( $data, $na = 'N/A' ) {
529
+
530
+ if( $na == 'N/A' ) {
531
+ return '<p class="i4t3-url-p">'. __( 'N/A', '404-to-301' ) .'</p>';
532
+ }
533
+
534
+ return $data;
535
+ }
536
 
 
537
  }
admin/core/class-wp-list-table.php CHANGED
@@ -1,67 +1,71 @@
1
  <?php
 
 
 
 
 
 
 
 
2
  /**
3
  * Base class for displaying a list of items in an ajaxified HTML table.
4
- * We are not using this class from core WordPress since it is not
5
- * recommended by WordPress itself.
6
  *
7
  * @since 3.1.0
8
  * @access private
9
- *
10
- * @package I4T3
11
- * @subpackage I4T3/List_Table
12
  */
13
  class WP_List_Table_404 {
14
 
15
  /**
16
- * The current list of items
17
  *
18
  * @since 3.1.0
19
- * @var array
20
  * @access public
 
21
  */
22
  public $items;
23
 
24
  /**
25
- * Various information about the current table
26
  *
27
  * @since 3.1.0
28
- * @var array
29
  * @access protected
 
30
  */
31
  protected $_args;
32
 
33
  /**
34
- * Various information needed for displaying the pagination
35
  *
36
  * @since 3.1.0
 
37
  * @var array
38
  */
39
  protected $_pagination_args = array();
40
 
41
  /**
42
- * The current screen
43
  *
44
  * @since 3.1.0
45
- * @var object
46
  * @access protected
 
47
  */
48
  protected $screen;
49
 
50
  /**
51
- * Cached bulk actions
52
  *
53
  * @since 3.1.0
54
- * @var array
55
  * @access private
 
56
  */
57
  private $_actions;
58
 
59
  /**
60
- * Cached pagination output
61
  *
62
  * @since 3.1.0
63
- * @var string
64
  * @access private
 
65
  */
66
  private $_pagination;
67
 
@@ -69,20 +73,34 @@ class WP_List_Table_404 {
69
  * The view switcher modes.
70
  *
71
  * @since 4.1.0
72
- * @var array
73
  * @access protected
 
74
  */
75
  protected $modes = array();
76
 
77
  /**
78
- * Stores the value returned by ->get_column_info()
79
  *
 
 
80
  * @var array
81
  */
82
  protected $_column_headers;
83
 
 
 
 
 
 
 
84
  protected $compat_fields = array( '_args', '_pagination_args', 'screen', '_actions', '_pagination' );
85
 
 
 
 
 
 
 
86
  protected $compat_methods = array( 'set_pagination_args', 'get_views', 'get_bulk_actions', 'bulk_actions',
87
  'row_actions', 'months_dropdown', 'view_switcher', 'comments_bubble', 'get_items_per_page', 'pagination',
88
  'get_sortable_columns', 'get_column_info', 'get_table_classes', 'display_tablenav', 'extra_tablenav',
@@ -141,8 +159,8 @@ class WP_List_Table_404 {
141
 
142
  if ( empty( $this->modes ) ) {
143
  $this->modes = array(
144
- 'list' => __( 'List View', '404-to-301' ),
145
- 'excerpt' => __( 'Excerpt View', '404-to-301' )
146
  );
147
  }
148
  }
@@ -250,8 +268,10 @@ class WP_List_Table_404 {
250
  /**
251
  * An internal method that sets all the necessary pagination arguments
252
  *
253
- * @param array $args An associative array with information about the pagination
254
  * @access protected
 
 
255
  */
256
  protected function set_pagination_args( $args ) {
257
  $args = wp_parse_args( $args, array(
@@ -283,11 +303,13 @@ class WP_List_Table_404 {
283
  * @return int Number of items that correspond to the given pagination argument.
284
  */
285
  public function get_pagination_arg( $key ) {
286
- if ( 'page' == $key )
287
  return $this->get_pagenum();
 
288
 
289
- if ( isset( $this->_pagination_args[$key] ) )
290
  return $this->_pagination_args[$key];
 
291
  }
292
 
293
  /**
@@ -380,6 +402,8 @@ class WP_List_Table_404 {
380
  if ( empty( $views ) )
381
  return;
382
 
 
 
383
  echo "<ul class='subsubsub'>\n";
384
  foreach ( $views as $class => $view ) {
385
  $views[ $class ] = "\t<li class='$class'>$view";
@@ -435,19 +459,19 @@ class WP_List_Table_404 {
435
  if ( empty( $this->_actions ) )
436
  return;
437
 
438
- echo "<label for='bulk-action-selector-" . esc_attr( $which ) . "' class='screen-reader-text'>" . __( 'Select bulk action', '404-to-301' ) . "</label>";
439
- echo "<select name='action$two' id='bulk-action-selector-" . esc_attr( $which ) . "'>\n";
440
- echo "<option value='-1' selected='selected'>" . __( 'Bulk Actions', '404-to-301' ) . "</option>\n";
441
 
442
  foreach ( $this->_actions as $name => $title ) {
443
- $class = 'edit' == $name ? ' class="hide-if-no-js"' : '';
444
 
445
- echo "\t<option value='$name'$class>$title</option>\n";
446
  }
447
 
448
  echo "</select>\n";
449
 
450
- submit_button( __( 'Apply', '404-to-301' ), 'action', '', false, array( 'id' => "doaction$two" ) );
451
  echo "\n";
452
  }
453
 
@@ -457,7 +481,7 @@ class WP_List_Table_404 {
457
  * @since 3.1.0
458
  * @access public
459
  *
460
- * @return string|bool The action name or False if no action was selected
461
  */
462
  public function current_action() {
463
  if ( isset( $_REQUEST['filter_action'] ) && ! empty( $_REQUEST['filter_action'] ) )
@@ -497,6 +521,8 @@ class WP_List_Table_404 {
497
  }
498
  $out .= '</div>';
499
 
 
 
500
  return $out;
501
  }
502
 
@@ -506,6 +532,9 @@ class WP_List_Table_404 {
506
  * @since 3.1.0
507
  * @access protected
508
  *
 
 
 
509
  * @param string $post_type
510
  */
511
  protected function months_dropdown( $post_type ) {
@@ -523,10 +552,18 @@ class WP_List_Table_404 {
523
  return;
524
  }
525
 
 
 
 
 
 
 
 
526
  $months = $wpdb->get_results( $wpdb->prepare( "
527
  SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
528
  FROM $wpdb->posts
529
  WHERE post_type = %s
 
530
  ORDER BY post_date DESC
531
  ", $post_type ) );
532
 
@@ -562,7 +599,7 @@ class WP_List_Table_404 {
562
  selected( $m, $year . $month, false ),
563
  esc_attr( $arc_row->year . $month ),
564
  /* translators: 1: month name, 2: 4-digit year */
565
- sprintf( __( '%1$s %2$d', '404-to-301' ), $wp_locale->get_month( $month ), $year )
566
  );
567
  }
568
  ?>
@@ -585,7 +622,7 @@ class WP_List_Table_404 {
585
  <?php
586
  foreach ( $this->modes as $mode => $title ) {
587
  $classes = array( 'view-' . $mode );
588
- if ( $current_mode == $mode )
589
  $classes[] = 'current';
590
  printf(
591
  "<a href='%s' class='%s' id='view-switch-$mode'><span class='screen-reader-text'>%s</span></a>\n",
@@ -609,15 +646,46 @@ class WP_List_Table_404 {
609
  * @param int $pending_comments Number of pending comments.
610
  */
611
  protected function comments_bubble( $post_id, $pending_comments ) {
612
- $pending_phrase = sprintf( __( '%s pending', '404-to-301' ), number_format( $pending_comments ) );
613
 
614
- if ( $pending_comments )
615
- echo '<strong>';
616
 
617
- echo "<a href='" . esc_url( add_query_arg( 'p', $post_id, admin_url( 'edit-comments.php' ) ) ) . "' title='" . esc_attr( $pending_phrase ) . "' class='post-com-count'><span class='comment-count'>" . number_format_i18n( get_comments_number() ) . "</span></a>";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
618
 
619
- if ( $pending_comments )
620
- echo '</strong>';
 
 
 
 
 
 
 
 
 
 
621
  }
622
 
623
  /**
@@ -631,7 +699,7 @@ class WP_List_Table_404 {
631
  public function get_pagenum() {
632
  $pagenum = isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 0;
633
 
634
- if( isset( $this->_pagination_args['total_pages'] ) && $pagenum > $this->_pagination_args['total_pages'] )
635
  $pagenum = $this->_pagination_args['total_pages'];
636
 
637
  return max( 1, $pagenum );
@@ -688,7 +756,11 @@ class WP_List_Table_404 {
688
  $infinite_scroll = $this->_pagination_args['infinite_scroll'];
689
  }
690
 
691
- $output = '<span class="displaying-num">' . sprintf( _n( '1 item', '%s items', $total_items ), number_format_i18n( $total_items ) ) . '</span>';
 
 
 
 
692
 
693
  $current = $this->get_pagenum();
694
 
@@ -698,53 +770,78 @@ class WP_List_Table_404 {
698
 
699
  $page_links = array();
700
 
701
- $disable_first = $disable_last = '';
702
- if ( $current == 1 ) {
703
- $disable_first = ' disabled';
 
 
 
 
 
 
 
 
704
  }
705
- if ( $current == $total_pages ) {
706
- $disable_last = ' disabled';
 
 
 
 
707
  }
708
- $page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
709
- 'first-page' . $disable_first,
710
- esc_attr__( 'Go to the first page', '404-to-301' ),
711
- esc_url( remove_query_arg( 'paged', $current_url ) ),
712
- '&laquo;'
713
- );
714
 
715
- $page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
716
- 'prev-page' . $disable_first,
717
- esc_attr__( 'Go to the previous page', '404-to-301' ),
718
- esc_url( add_query_arg( 'paged', max( 1, $current-1 ), $current_url ) ),
719
- '&lsaquo;'
720
- );
 
 
 
721
 
722
- if ( 'bottom' == $which ) {
723
- $html_current_page = $current;
724
  } else {
725
- $html_current_page = sprintf( "%s<input class='current-page' id='current-page-selector' title='%s' type='text' name='paged' value='%s' size='%d' />",
726
- '<label for="current-page-selector" class="screen-reader-text">' . __( 'Select Page', '404-to-301' ) . '</label>',
727
- esc_attr__( 'Current page', '404-to-301' ),
 
 
 
 
 
 
 
 
 
 
728
  $current,
729
  strlen( $total_pages )
730
  );
731
  }
732
  $html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $total_pages ) );
733
- $page_links[] = '<span class="paging-input">' . sprintf( _x( '%1$s of %2$s', 'paging' ), $html_current_page, $html_total_pages ) . '</span>';
734
 
735
- $page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
736
- 'next-page' . $disable_last,
737
- esc_attr__( 'Go to the next page', '404-to-301' ),
738
- esc_url( add_query_arg( 'paged', min( $total_pages, $current+1 ), $current_url ) ),
739
- '&rsaquo;'
740
- );
 
 
 
741
 
742
- $page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
743
- 'last-page' . $disable_last,
744
- esc_attr__( 'Go to the last page', '404-to-301' ),
745
- esc_url( add_query_arg( 'paged', $total_pages, $current_url ) ),
746
- '&raquo;'
747
- );
 
 
 
748
 
749
  $pagination_links_class = 'pagination-links';
750
  if ( ! empty( $infinite_scroll ) ) {
@@ -793,6 +890,83 @@ class WP_List_Table_404 {
793
  return array();
794
  }
795
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
796
  /**
797
  * Get a list of all, hidden and sortable columns, with filter applied
798
  *
@@ -802,8 +976,17 @@ class WP_List_Table_404 {
802
  * @return array
803
  */
804
  protected function get_column_info() {
805
- if ( isset( $this->_column_headers ) )
806
- return $this->_column_headers;
 
 
 
 
 
 
 
 
 
807
 
808
  $columns = get_column_headers( $this->screen );
809
  $hidden = get_hidden_columns( $this->screen );
@@ -833,7 +1016,8 @@ class WP_List_Table_404 {
833
  $sortable[$id] = $data;
834
  }
835
 
836
- $this->_column_headers = array( $columns, $hidden, $sortable );
 
837
 
838
  return $this->_column_headers;
839
  }
@@ -858,27 +1042,31 @@ class WP_List_Table_404 {
858
  * @since 3.1.0
859
  * @access public
860
  *
 
 
861
  * @param bool $with_id Whether to set the id attribute or not
862
  */
863
  public function print_column_headers( $with_id = true ) {
864
- list( $columns, $hidden, $sortable ) = $this->get_column_info();
865
 
866
  $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
867
  $current_url = remove_query_arg( 'paged', $current_url );
868
 
869
- if ( isset( $_GET['orderby'] ) )
870
  $current_orderby = $_GET['orderby'];
871
- else
872
  $current_orderby = '';
 
873
 
874
- if ( isset( $_GET['order'] ) && 'desc' == $_GET['order'] )
875
  $current_order = 'desc';
876
- else
877
  $current_order = 'asc';
 
878
 
879
  if ( ! empty( $columns['cb'] ) ) {
880
  static $cb_counter = 1;
881
- $columns['cb'] = '<label class="screen-reader-text" for="cb-select-all-' . $cb_counter . '">' . __( 'Select All', '404-to-301' ) . '</label>'
882
  . '<input id="cb-select-all-' . $cb_counter . '" type="checkbox" />';
883
  $cb_counter++;
884
  }
@@ -886,22 +1074,24 @@ class WP_List_Table_404 {
886
  foreach ( $columns as $column_key => $column_display_name ) {
887
  $class = array( 'manage-column', "column-$column_key" );
888
 
889
- $style = '';
890
- if ( in_array( $column_key, $hidden ) )
891
- $style = 'display:none;';
892
-
893
- $style = ' style="' . $style . '"';
894
 
895
- if ( 'cb' == $column_key )
896
  $class[] = 'check-column';
897
  elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ) ) )
898
  $class[] = 'num';
899
 
 
 
 
 
900
  if ( isset( $sortable[$column_key] ) ) {
901
  list( $orderby, $desc_first ) = $sortable[$column_key];
902
 
903
- if ( $current_orderby == $orderby ) {
904
- $order = 'asc' == $current_order ? 'desc' : 'asc';
905
  $class[] = 'sorted';
906
  $class[] = $current_order;
907
  } else {
@@ -913,12 +1103,14 @@ class WP_List_Table_404 {
913
  $column_display_name = '<a href="' . esc_url( add_query_arg( compact( 'orderby', 'order' ), $current_url ) ) . '"><span>' . $column_display_name . '</span><span class="sorting-indicator"></span></a>';
914
  }
915
 
 
 
916
  $id = $with_id ? "id='$column_key'" : '';
917
 
918
  if ( !empty( $class ) )
919
  $class = "class='" . join( ' ', $class ) . "'";
920
 
921
- echo "<th scope='col' $id $class $style>$column_display_name</th>";
922
  }
923
  }
924
 
@@ -933,6 +1125,7 @@ class WP_List_Table_404 {
933
 
934
  $this->display_tablenav( 'top' );
935
 
 
936
  ?>
937
  <table class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>">
938
  <thead>
@@ -979,15 +1172,17 @@ class WP_List_Table_404 {
979
  * @param string $which
980
  */
981
  protected function display_tablenav( $which ) {
982
- if ( 'top' == $which )
983
  wp_nonce_field( 'bulk-' . $this->_args['plural'] );
984
- ?>
 
985
  <div class="tablenav <?php echo esc_attr( $which ); ?>">
986
 
 
987
  <div class="alignleft actions bulkactions">
988
  <?php $this->bulk_actions( $which ); ?>
989
  </div>
990
- <?php
991
  $this->extra_tablenav( $which );
992
  $this->pagination( $which );
993
  ?>
@@ -1048,8 +1243,17 @@ class WP_List_Table_404 {
1048
  echo '</tr>';
1049
  }
1050
 
 
 
 
 
 
1051
  protected function column_default( $item, $column_name ) {}
1052
 
 
 
 
 
1053
  protected function column_cb( $item ) {}
1054
 
1055
  /**
@@ -1061,35 +1265,65 @@ class WP_List_Table_404 {
1061
  * @param object $item The current item
1062
  */
1063
  protected function single_row_columns( $item ) {
1064
- list( $columns, $hidden ) = $this->get_column_info();
1065
 
1066
  foreach ( $columns as $column_name => $column_display_name ) {
1067
- $class = "class='$column_name column-$column_name'";
 
 
 
 
 
 
 
1068
 
1069
- $style = '';
1070
- if ( in_array( $column_name, $hidden ) )
1071
- $style = ' style="display:none;"';
1072
 
1073
- $attributes = "$class$style";
1074
 
1075
- if ( 'cb' == $column_name ) {
1076
  echo '<th scope="row" class="check-column">';
1077
  echo $this->column_cb( $item );
1078
  echo '</th>';
1079
- }
1080
- elseif ( method_exists( $this, 'column_' . $column_name ) ) {
 
 
 
 
 
 
 
1081
  echo "<td $attributes>";
1082
  echo call_user_func( array( $this, 'column_' . $column_name ), $item );
 
1083
  echo "</td>";
1084
- }
1085
- else {
1086
  echo "<td $attributes>";
1087
  echo $this->column_default( $item, $column_name );
 
1088
  echo "</td>";
1089
  }
1090
  }
1091
  }
1092
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1093
  /**
1094
  * Handle an incoming ajax request (called from admin-ajax.php)
1095
  *
@@ -1112,7 +1346,7 @@ class WP_List_Table_404 {
1112
 
1113
  if ( isset( $this->_pagination_args['total_items'] ) ) {
1114
  $response['total_items_i18n'] = sprintf(
1115
- _n( '1 item', '%s items', $this->_pagination_args['total_items'] ),
1116
  number_format_i18n( $this->_pagination_args['total_items'] )
1117
  );
1118
  }
1
  <?php
2
+ /**
3
+ * Administration API: WP_List_Table class
4
+ *
5
+ * @package WordPress
6
+ * @subpackage List_Table
7
+ * @since 3.1.0
8
+ */
9
+
10
  /**
11
  * Base class for displaying a list of items in an ajaxified HTML table.
 
 
12
  *
13
  * @since 3.1.0
14
  * @access private
 
 
 
15
  */
16
  class WP_List_Table_404 {
17
 
18
  /**
19
+ * The current list of items.
20
  *
21
  * @since 3.1.0
 
22
  * @access public
23
+ * @var array
24
  */
25
  public $items;
26
 
27
  /**
28
+ * Various information about the current table.
29
  *
30
  * @since 3.1.0
 
31
  * @access protected
32
+ * @var array
33
  */
34
  protected $_args;
35
 
36
  /**
37
+ * Various information needed for displaying the pagination.
38
  *
39
  * @since 3.1.0
40
+ * @access protected
41
  * @var array
42
  */
43
  protected $_pagination_args = array();
44
 
45
  /**
46
+ * The current screen.
47
  *
48
  * @since 3.1.0
 
49
  * @access protected
50
+ * @var object
51
  */
52
  protected $screen;
53
 
54
  /**
55
+ * Cached bulk actions.
56
  *
57
  * @since 3.1.0
 
58
  * @access private
59
+ * @var array
60
  */
61
  private $_actions;
62
 
63
  /**
64
+ * Cached pagination output.
65
  *
66
  * @since 3.1.0
 
67
  * @access private
68
+ * @var string
69
  */
70
  private $_pagination;
71
 
73
  * The view switcher modes.
74
  *
75
  * @since 4.1.0
 
76
  * @access protected
77
+ * @var array
78
  */
79
  protected $modes = array();
80
 
81
  /**
82
+ * Stores the value returned by ->get_column_info().
83
  *
84
+ * @since 4.1.0
85
+ * @access protected
86
  * @var array
87
  */
88
  protected $_column_headers;
89
 
90
+ /**
91
+ * {@internal Missing Summary}
92
+ *
93
+ * @access protected
94
+ * @var array
95
+ */
96
  protected $compat_fields = array( '_args', '_pagination_args', 'screen', '_actions', '_pagination' );
97
 
98
+ /**
99
+ * {@internal Missing Summary}
100
+ *
101
+ * @access protected
102
+ * @var array
103
+ */
104
  protected $compat_methods = array( 'set_pagination_args', 'get_views', 'get_bulk_actions', 'bulk_actions',
105
  'row_actions', 'months_dropdown', 'view_switcher', 'comments_bubble', 'get_items_per_page', 'pagination',
106
  'get_sortable_columns', 'get_column_info', 'get_table_classes', 'display_tablenav', 'extra_tablenav',
159
 
160
  if ( empty( $this->modes ) ) {
161
  $this->modes = array(
162
+ 'list' => __( 'List View' ),
163
+ 'excerpt' => __( 'Excerpt View' )
164
  );
165
  }
166
  }
268
  /**
269
  * An internal method that sets all the necessary pagination arguments
270
  *
271
+ * @since 3.1.0
272
  * @access protected
273
+ *
274
+ * @param array|string $args Array or string of arguments with information about the pagination.
275
  */
276
  protected function set_pagination_args( $args ) {
277
  $args = wp_parse_args( $args, array(
303
  * @return int Number of items that correspond to the given pagination argument.
304
  */
305
  public function get_pagination_arg( $key ) {
306
+ if ( 'page' === $key ) {
307
  return $this->get_pagenum();
308
+ }
309
 
310
+ if ( isset( $this->_pagination_args[$key] ) ) {
311
  return $this->_pagination_args[$key];
312
+ }
313
  }
314
 
315
  /**
402
  if ( empty( $views ) )
403
  return;
404
 
405
+ $this->screen->render_screen_reader_content( 'heading_views' );
406
+
407
  echo "<ul class='subsubsub'>\n";
408
  foreach ( $views as $class => $view ) {
409
  $views[ $class ] = "\t<li class='$class'>$view";
459
  if ( empty( $this->_actions ) )
460
  return;
461
 
462
+ echo '<label for="bulk-action-selector-' . esc_attr( $which ) . '" class="screen-reader-text">' . __( 'Select bulk action' ) . '</label>';
463
+ echo '<select name="action' . $two . '" id="bulk-action-selector-' . esc_attr( $which ) . "\">\n";
464
+ echo '<option value="-1">' . __( 'Bulk Actions' ) . "</option>\n";
465
 
466
  foreach ( $this->_actions as $name => $title ) {
467
+ $class = 'edit' === $name ? ' class="hide-if-no-js"' : '';
468
 
469
+ echo "\t" . '<option value="' . $name . '"' . $class . '>' . $title . "</option>\n";
470
  }
471
 
472
  echo "</select>\n";
473
 
474
+ submit_button( __( 'Apply' ), 'action', '', false, array( 'id' => "doaction$two" ) );
475
  echo "\n";
476
  }
477
 
481
  * @since 3.1.0
482
  * @access public
483
  *
484
+ * @return string|false The action name or False if no action was selected
485
  */
486
  public function current_action() {
487
  if ( isset( $_REQUEST['filter_action'] ) && ! empty( $_REQUEST['filter_action'] ) )
521
  }
522
  $out .= '</div>';
523
 
524
+ $out .= '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details' ) . '</span></button>';
525
+
526
  return $out;
527
  }
528
 
532
  * @since 3.1.0
533
  * @access protected
534
  *
535
+ * @global wpdb $wpdb
536
+ * @global WP_Locale $wp_locale
537
+ *
538
  * @param string $post_type
539
  */
540
  protected function months_dropdown( $post_type ) {
552
  return;
553
  }
554
 
555
+ $extra_checks = "AND post_status != 'auto-draft'";
556
+ if ( ! isset( $_GET['post_status'] ) || 'trash' !== $_GET['post_status'] ) {
557
+ $extra_checks .= " AND post_status != 'trash'";
558
+ } elseif ( isset( $_GET['post_status'] ) ) {
559
+ $extra_checks = $wpdb->prepare( ' AND post_status = %s', $_GET['post_status'] );
560
+ }
561
+
562
  $months = $wpdb->get_results( $wpdb->prepare( "
563
  SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
564
  FROM $wpdb->posts
565
  WHERE post_type = %s
566
+ $extra_checks
567
  ORDER BY post_date DESC
568
  ", $post_type ) );
569
 
599
  selected( $m, $year . $month, false ),
600
  esc_attr( $arc_row->year . $month ),
601
  /* translators: 1: month name, 2: 4-digit year */
602
+ sprintf( __( '%1$s %2$d' ), $wp_locale->get_month( $month ), $year )
603
  );
604
  }
605
  ?>
622
  <?php
623
  foreach ( $this->modes as $mode => $title ) {
624
  $classes = array( 'view-' . $mode );
625
+ if ( $current_mode === $mode )
626
  $classes[] = 'current';
627
  printf(
628
  "<a href='%s' class='%s' id='view-switch-$mode'><span class='screen-reader-text'>%s</span></a>\n",
646
  * @param int $pending_comments Number of pending comments.
647
  */
648
  protected function comments_bubble( $post_id, $pending_comments ) {
649
+ $approved_comments = get_comments_number();
650
 
651
+ $approved_comments_number = number_format_i18n( $approved_comments );
652
+ $pending_comments_number = number_format_i18n( $pending_comments );
653
 
654
+ $approved_only_phrase = sprintf( _n( '%s comment', '%s comments', $approved_comments ), $approved_comments_number );
655
+ $approved_phrase = sprintf( _n( '%s approved comment', '%s approved comments', $approved_comments ), $approved_comments_number );
656
+ $pending_phrase = sprintf( _n( '%s pending comment', '%s pending comments', $pending_comments ), $pending_comments_number );
657
+
658
+ // No comments at all.
659
+ if ( ! $approved_comments && ! $pending_comments ) {
660
+ printf( '<span aria-hidden="true">—</span><span class="screen-reader-text">%s</span>',
661
+ __( 'No comments' )
662
+ );
663
+ // Approved comments have different display depending on some conditions.
664
+ } elseif ( $approved_comments ) {
665
+ printf( '<a href="%s" class="post-com-count post-com-count-approved"><span class="comment-count-approved" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></a>',
666
+ esc_url( add_query_arg( array( 'p' => $post_id, 'comment_status' => 'approved' ), admin_url( 'edit-comments.php' ) ) ),
667
+ $approved_comments_number,
668
+ $pending_comments ? $approved_phrase : $approved_only_phrase
669
+ );
670
+ } else {
671
+ printf( '<span class="post-com-count post-com-count-no-comments"><span class="comment-count comment-count-no-comments" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></span>',
672
+ $approved_comments_number,
673
+ $pending_comments ? __( 'No approved comments' ) : __( 'No comments' )
674
+ );
675
+ }
676
 
677
+ if ( $pending_comments ) {
678
+ printf( '<a href="%s" class="post-com-count post-com-count-pending"><span class="comment-count-pending" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></a>',
679
+ esc_url( add_query_arg( array( 'p' => $post_id, 'comment_status' => 'moderated' ), admin_url( 'edit-comments.php' ) ) ),
680
+ $pending_comments_number,
681
+ $pending_phrase
682
+ );
683
+ } else {
684
+ printf( '<span class="post-com-count post-com-count-pending post-com-count-no-pending"><span class="comment-count comment-count-no-pending" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></span>',
685
+ $pending_comments_number,
686
+ $approved_comments ? __( 'No pending comments' ) : __( 'No comments' )
687
+ );
688
+ }
689
  }
690
 
691
  /**
699
  public function get_pagenum() {
700
  $pagenum = isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 0;
701
 
702
+ if ( isset( $this->_pagination_args['total_pages'] ) && $pagenum > $this->_pagination_args['total_pages'] )
703
  $pagenum = $this->_pagination_args['total_pages'];
704
 
705
  return max( 1, $pagenum );
756
  $infinite_scroll = $this->_pagination_args['infinite_scroll'];
757
  }
758
 
759
+ if ( 'top' === $which && $total_pages > 1 ) {
760
+ $this->screen->render_screen_reader_content( 'heading_pagination' );
761
+ }
762
+
763
+ $output = '<span class="displaying-num">' . sprintf( _n( '%s item', '%s items', $total_items ), number_format_i18n( $total_items ) ) . '</span>';
764
 
765
  $current = $this->get_pagenum();
766
 
770
 
771
  $page_links = array();
772
 
773
+ $total_pages_before = '<span class="paging-input">';
774
+ $total_pages_after = '</span>';
775
+
776
+ $disable_first = $disable_last = $disable_prev = $disable_next = false;
777
+
778
+ if ( $current == 1 ) {
779
+ $disable_first = true;
780
+ $disable_prev = true;
781
+ }
782
+ if ( $current == 2 ) {
783
+ $disable_first = true;
784
  }
785
+ if ( $current == $total_pages ) {
786
+ $disable_last = true;
787
+ $disable_next = true;
788
+ }
789
+ if ( $current == $total_pages - 1 ) {
790
+ $disable_last = true;
791
  }
 
 
 
 
 
 
792
 
793
+ if ( $disable_first ) {
794
+ $page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&laquo;</span>';
795
+ } else {
796
+ $page_links[] = sprintf( "<a class='first-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
797
+ esc_url( remove_query_arg( 'paged', $current_url ) ),
798
+ __( 'First page' ),
799
+ '&laquo;'
800
+ );
801
+ }
802
 
803
+ if ( $disable_prev ) {
804
+ $page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&lsaquo;</span>';
805
  } else {
806
+ $page_links[] = sprintf( "<a class='prev-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
807
+ esc_url( add_query_arg( 'paged', max( 1, $current-1 ), $current_url ) ),
808
+ __( 'Previous page' ),
809
+ '&lsaquo;'
810
+ );
811
+ }
812
+
813
+ if ( 'bottom' === $which ) {
814
+ $html_current_page = $current;
815
+ $total_pages_before = '<span class="screen-reader-text">' . __( 'Current Page' ) . '</span><span id="table-paging" class="paging-input">';
816
+ } else {
817
+ $html_current_page = sprintf( "%s<input class='current-page' id='current-page-selector' type='text' name='paged' value='%s' size='%d' aria-describedby='table-paging' />",
818
+ '<label for="current-page-selector" class="screen-reader-text">' . __( 'Current Page' ) . '</label>',
819
  $current,
820
  strlen( $total_pages )
821
  );
822
  }
823
  $html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $total_pages ) );
824
+ $page_links[] = $total_pages_before . sprintf( _x( '%1$s of %2$s', 'paging' ), $html_current_page, $html_total_pages ) . $total_pages_after;
825
 
826
+ if ( $disable_next ) {
827
+ $page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&rsaquo;</span>';
828
+ } else {
829
+ $page_links[] = sprintf( "<a class='next-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
830
+ esc_url( add_query_arg( 'paged', min( $total_pages, $current+1 ), $current_url ) ),
831
+ __( 'Next page' ),
832
+ '&rsaquo;'
833
+ );
834
+ }
835
 
836
+ if ( $disable_last ) {
837
+ $page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&raquo;</span>';
838
+ } else {
839
+ $page_links[] = sprintf( "<a class='last-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
840
+ esc_url( add_query_arg( 'paged', $total_pages, $current_url ) ),
841
+ __( 'Last page' ),
842
+ '&raquo;'
843
+ );
844
+ }
845
 
846
  $pagination_links_class = 'pagination-links';
847
  if ( ! empty( $infinite_scroll ) ) {
890
  return array();
891
  }
892
 
893
+ /**
894
+ * Gets the name of the default primary column.
895
+ *
896
+ * @since 4.3.0
897
+ * @access protected
898
+ *
899
+ * @return string Name of the default primary column, in this case, an empty string.
900
+ */
901
+ protected function get_default_primary_column_name() {
902
+ $columns = $this->get_columns();
903
+ $column = '';
904
+
905
+ if ( empty( $columns ) ) {
906
+ return $column;
907
+ }
908
+
909
+ // We need a primary defined so responsive views show something,
910
+ // so let's fall back to the first non-checkbox column.
911
+ foreach ( $columns as $col => $column_name ) {
912
+ if ( 'cb' === $col ) {
913
+ continue;
914
+ }
915
+
916
+ $column = $col;
917
+ break;
918
+ }
919
+
920
+ return $column;
921
+ }
922
+
923
+ /**
924
+ * Public wrapper for WP_List_Table::get_default_primary_column_name().
925
+ *
926
+ * @since 4.4.0
927
+ * @access public
928
+ *
929
+ * @return string Name of the default primary column.
930
+ */
931
+ public function get_primary_column() {
932
+ return $this->get_primary_column_name();
933
+ }
934
+
935
+ /**
936
+ * Gets the name of the primary column.
937
+ *
938
+ * @since 4.3.0
939
+ * @access protected
940
+ *
941
+ * @return string The name of the primary column.
942
+ */
943
+ protected function get_primary_column_name() {
944
+ $columns = get_column_headers( $this->screen );
945
+ $default = $this->get_default_primary_column_name();
946
+
947
+ // If the primary column doesn't exist fall back to the
948
+ // first non-checkbox column.
949
+ if ( ! isset( $columns[ $default ] ) ) {
950
+ $default = WP_List_Table::get_default_primary_column_name();
951
+ }
952
+
953
+ /**
954
+ * Filter the name of the primary column for the current list table.
955
+ *
956
+ * @since 4.3.0
957
+ *
958
+ * @param string $default Column name default for the specific list table, e.g. 'name'.
959
+ * @param string $context Screen ID for specific list table, e.g. 'plugins'.
960
+ */
961
+ $column = apply_filters( 'list_table_primary_column', $default, $this->screen->id );
962
+
963
+ if ( empty( $column ) || ! isset( $columns[ $column ] ) ) {
964
+ $column = $default;
965
+ }
966
+
967
+ return $column;
968
+ }
969
+
970
  /**
971
  * Get a list of all, hidden and sortable columns, with filter applied
972
  *
976
  * @return array
977
  */
978
  protected function get_column_info() {
979
+ // $_column_headers is already set / cached
980
+ if ( isset( $this->_column_headers ) && is_array( $this->_column_headers ) ) {
981
+ // Back-compat for list tables that have been manually setting $_column_headers for horse reasons.
982
+ // In 4.3, we added a fourth argument for primary column.
983
+ $column_headers = array( array(), array(), array(), $this->get_primary_column_name() );
984
+ foreach ( $this->_column_headers as $key => $value ) {
985
+ $column_headers[ $key ] = $value;
986
+ }
987
+
988
+ return $column_headers;
989
+ }
990
 
991
  $columns = get_column_headers( $this->screen );
992
  $hidden = get_hidden_columns( $this->screen );
1016
  $sortable[$id] = $data;
1017
  }
1018
 
1019
+ $primary = $this->get_primary_column_name();
1020
+ $this->_column_headers = array( $columns, $hidden, $sortable, $primary );
1021
 
1022
  return $this->_column_headers;
1023
  }
1042
  * @since 3.1.0
1043
  * @access public
1044
  *
1045
+ * @staticvar int $cb_counter
1046
+ *
1047
  * @param bool $with_id Whether to set the id attribute or not
1048
  */
1049
  public function print_column_headers( $with_id = true ) {
1050
+ list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
1051
 
1052
  $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
1053
  $current_url = remove_query_arg( 'paged', $current_url );
1054
 
1055
+ if ( isset( $_GET['orderby'] ) ) {
1056
  $current_orderby = $_GET['orderby'];
1057
+ } else {
1058
  $current_orderby = '';
1059
+ }
1060
 
1061
+ if ( isset( $_GET['order'] ) && 'desc' === $_GET['order'] ) {
1062
  $current_order = 'desc';
1063
+ } else {
1064
  $current_order = 'asc';
1065
+ }
1066
 
1067
  if ( ! empty( $columns['cb'] ) ) {
1068
  static $cb_counter = 1;
1069
+ $columns['cb'] = '<label class="screen-reader-text" for="cb-select-all-' . $cb_counter . '">' . __( 'Select All' ) . '</label>'
1070
  . '<input id="cb-select-all-' . $cb_counter . '" type="checkbox" />';
1071
  $cb_counter++;
1072
  }
1074
  foreach ( $columns as $column_key => $column_display_name ) {
1075
  $class = array( 'manage-column', "column-$column_key" );
1076
 
1077
+ if ( in_array( $column_key, $hidden ) ) {
1078
+ $class[] = 'hidden';
1079
+ }
 
 
1080
 
1081
+ if ( 'cb' === $column_key )
1082
  $class[] = 'check-column';
1083
  elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ) ) )
1084
  $class[] = 'num';
1085
 
1086
+ if ( $column_key === $primary ) {
1087
+ $class[] = 'column-primary';
1088
+ }
1089
+
1090
  if ( isset( $sortable[$column_key] ) ) {
1091
  list( $orderby, $desc_first ) = $sortable[$column_key];
1092
 
1093
+ if ( $current_orderby === $orderby ) {
1094
+ $order = 'asc' === $current_order ? 'desc' : 'asc';
1095
  $class[] = 'sorted';
1096
  $class[] = $current_order;
1097
  } else {
1103
  $column_display_name = '<a href="' . esc_url( add_query_arg( compact( 'orderby', 'order' ), $current_url ) ) . '"><span>' . $column_display_name . '</span><span class="sorting-indicator"></span></a>';
1104
  }
1105
 
1106
+ $tag = ( 'cb' === $column_key ) ? 'td' : 'th';
1107
+ $scope = ( 'th' === $tag ) ? 'scope="col"' : '';
1108
  $id = $with_id ? "id='$column_key'" : '';
1109
 
1110
  if ( !empty( $class ) )
1111
  $class = "class='" . join( ' ', $class ) . "'";
1112
 
1113
+ echo "<$tag $scope $id $class>$column_display_name</$tag>";
1114
  }
1115
  }
1116
 
1125
 
1126
  $this->display_tablenav( 'top' );
1127
 
1128
+ $this->screen->render_screen_reader_content( 'heading_list' );
1129
  ?>
1130
  <table class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>">
1131
  <thead>
1172
  * @param string $which
1173
  */
1174
  protected function display_tablenav( $which ) {
1175
+ if ( 'top' === $which ) {
1176
  wp_nonce_field( 'bulk-' . $this->_args['plural'] );
1177
+ }
1178
+ ?>
1179
  <div class="tablenav <?php echo esc_attr( $which ); ?>">
1180
 
1181
+ <?php if ( $this->has_items() ): ?>
1182
  <div class="alignleft actions bulkactions">
1183
  <?php $this->bulk_actions( $which ); ?>
1184
  </div>
1185
+ <?php endif;
1186
  $this->extra_tablenav( $which );
1187
  $this->pagination( $which );
1188
  ?>
1243
  echo '</tr>';
1244
  }
1245
 
1246
+ /**
1247
+ *
1248
+ * @param object $item
1249
+ * @param string $column_name
1250
+ */
1251
  protected function column_default( $item, $column_name ) {}
1252
 
1253
+ /**
1254
+ *
1255
+ * @param object $item
1256
+ */
1257
  protected function column_cb( $item ) {}
1258
 
1259
  /**
1265
  * @param object $item The current item
1266
  */
1267
  protected function single_row_columns( $item ) {
1268
+ list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
1269
 
1270
  foreach ( $columns as $column_name => $column_display_name ) {
1271
+ $classes = "$column_name column-$column_name";
1272
+ if ( $primary === $column_name ) {
1273
+ $classes .= ' has-row-actions column-primary';
1274
+ }
1275
+
1276
+ if ( in_array( $column_name, $hidden ) ) {
1277
+ $classes .= ' hidden';
1278
+ }
1279
 
1280
+ // Comments column uses HTML in the display name with screen reader text.
1281
+ // Instead of using esc_attr(), we strip tags to get closer to a user-friendly string.
1282
+ $data = 'data-colname="' . wp_strip_all_tags( $column_display_name ) . '"';
1283
 
1284
+ $attributes = "class='$classes' $data";
1285
 
1286
+ if ( 'cb' === $column_name ) {
1287
  echo '<th scope="row" class="check-column">';
1288
  echo $this->column_cb( $item );
1289
  echo '</th>';
1290
+ } elseif ( method_exists( $this, '_column_' . $column_name ) ) {
1291
+ echo call_user_func(
1292
+ array( $this, '_column_' . $column_name ),
1293
+ $item,
1294
+ $classes,
1295
+ $data,
1296
+ $primary
1297
+ );
1298
+ } elseif ( method_exists( $this, 'column_' . $column_name ) ) {
1299
  echo "<td $attributes>";
1300
  echo call_user_func( array( $this, 'column_' . $column_name ), $item );
1301
+ echo $this->handle_row_actions( $item, $column_name, $primary );
1302
  echo "</td>";
1303
+ } else {
 
1304
  echo "<td $attributes>";
1305
  echo $this->column_default( $item, $column_name );
1306
+ echo $this->handle_row_actions( $item, $column_name, $primary );
1307
  echo "</td>";
1308
  }
1309
  }
1310
  }
1311
 
1312
+ /**
1313
+ * Generates and display row actions links for the list table.
1314
+ *
1315
+ * @since 4.3.0
1316
+ * @access protected
1317
+ *
1318
+ * @param object $item The item being acted upon.
1319
+ * @param string $column_name Current column name.
1320
+ * @param string $primary Primary column name.
1321
+ * @return string The row actions HTML, or an empty string if the current column is the primary column.
1322
+ */
1323
+ protected function handle_row_actions( $item, $column_name, $primary ) {
1324
+ return $column_name === $primary ? '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details' ) . '</span></button>' : '';
1325
+ }
1326
+
1327
  /**
1328
  * Handle an incoming ajax request (called from admin-ajax.php)
1329
  *
1346
 
1347
  if ( isset( $this->_pagination_args['total_items'] ) ) {
1348
  $response['total_items_i18n'] = sprintf(
1349
+ _n( '%s item', '%s items', $this->_pagination_args['total_items'] ),
1350
  number_format_i18n( $this->_pagination_args['total_items'] )
1351
  );
1352
  }
includes/class-404-to-301.php CHANGED
@@ -67,7 +67,7 @@ class _404_To_301 {
67
  public function __construct() {
68
 
69
  $this->plugin_name = '404-to-301';
70
- $this->version = '2.0.9';
71
  $this->table = $GLOBALS['wpdb']->prefix . '404_to_301';
72
  $this->load_dependencies();
73
  $this->set_locale();
@@ -141,6 +141,7 @@ class _404_To_301 {
141
  $this->loader->add_filter( 'plugin_action_links', $plugin_admin, 'i4t3_plugin_action_links', 10, 5 );
142
  $this->loader->add_action( 'plugins_loaded', $plugin_admin, 'i4t3_upgrade_if_new' );
143
  $this->loader->add_filter( 'i4t3_notify_admin_email_address', $plugin_admin, 'i4t3_change_notify_email' );
 
144
  }
145
 
146
 
67
  public function __construct() {
68
 
69
  $this->plugin_name = '404-to-301';
70
+ $this->version = '2.1.0';
71
  $this->table = $GLOBALS['wpdb']->prefix . '404_to_301';
72
  $this->load_dependencies();
73
  $this->set_locale();
141
  $this->loader->add_filter( 'plugin_action_links', $plugin_admin, 'i4t3_plugin_action_links', 10, 5 );
142
  $this->loader->add_action( 'plugins_loaded', $plugin_admin, 'i4t3_upgrade_if_new' );
143
  $this->loader->add_filter( 'i4t3_notify_admin_email_address', $plugin_admin, 'i4t3_change_notify_email' );
144
+ $this->loader->add_filter( 'set-screen-option', $plugin_admin, 'set_screen', 10, 3 );
145
  }
146
 
147
 
public/class-404-to-301-public.php CHANGED
@@ -132,17 +132,17 @@ class _404_To_301_Public {
132
  global $wpdb;
133
  $data = array(
134
  'date' => current_time('mysql'),
135
- 'url' => $_SERVER['REQUEST_URI']
136
  );
137
  if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
138
- $data['ip'] = $_SERVER['HTTP_CLIENT_IP'];
139
  } else if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
140
- $data['ip'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
141
  } else {
142
- $data['ip'] = $_SERVER['REMOTE_ADDR'];
143
  }
144
- $data['ref'] = $_SERVER['HTTP_REFERER'];
145
- $data['ua'] = $_SERVER['HTTP_USER_AGENT'];
146
  // trim stuff
147
  foreach( array( 'url', 'ref', 'ua' ) as $k )
148
  if( isset( $data[$k] ) )
@@ -255,5 +255,17 @@ class _404_To_301_Public {
255
  }
256
  return false;
257
  }
 
 
 
 
 
 
 
 
 
 
 
 
258
 
259
  }
132
  global $wpdb;
133
  $data = array(
134
  'date' => current_time('mysql'),
135
+ 'url' => $this->get_clear_empty( $_SERVER['REQUEST_URI'] )
136
  );
137
  if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
138
+ $data['ip'] = $this->get_clear_empty( $_SERVER['HTTP_CLIENT_IP'] );
139
  } else if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
140
+ $data['ip'] = $this->get_clear_empty( $_SERVER['HTTP_X_FORWARDED_FOR'] );
141
  } else {
142
+ $data['ip'] = $this->get_clear_empty( $_SERVER['REMOTE_ADDR'] );
143
  }
144
+ $data['ref'] = $this->get_clear_empty( $_SERVER['HTTP_REFERER'] );
145
+ $data['ua'] = $this->get_clear_empty( $_SERVER['HTTP_USER_AGENT'] );
146
  // trim stuff
147
  foreach( array( 'url', 'ref', 'ua' ) as $k )
148
  if( isset( $data[$k] ) )
255
  }
256
  return false;
257
  }
258
+
259
+
260
+ /**
261
+ * Check if value is empty before trying to insert.
262
+ *
263
+ * @since 2.0.9.1
264
+ * @author Joel James
265
+ */
266
+ public function get_clear_empty( $data = null ) {
267
+
268
+ return ( $data == null || empty($data) ) ? 'N/A' : $data;
269
+ }
270
 
271
  }
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: joelcj91,is_code
3
  Tags: 404, 301, 302, 307, not found, 404 redirect, 404 to 301, 301 redirect, seo redirect, error redirect, 404 seo, custom 404 page
4
  Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=XUVWY8HUBUXY4
5
  Requires at least: 3.0
6
- Tested up to: 4.3.1
7
- Stable tag: 2.0.9
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -112,6 +112,21 @@ Bug reports for 404 to 301 are always welcome. [Report here](http://iscode.co/bu
112
 
113
  == Changelog ==
114
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  = 2.0.9 (2/11/2015) =
116
  **Bug Fixes**
117
 
@@ -214,5 +229,16 @@ Bug reports for 404 to 301 are always welcome. [Report here](http://iscode.co/bu
214
 
215
  == Upgrade Notice ==
216
 
217
- = 2.0.9 =
218
- - Fixed issue - Empty needle issue after 2.0.8 update.
 
 
 
 
 
 
 
 
 
 
 
3
  Tags: 404, 301, 302, 307, not found, 404 redirect, 404 to 301, 301 redirect, seo redirect, error redirect, 404 seo, custom 404 page
4
  Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=XUVWY8HUBUXY4
5
  Requires at least: 3.0
6
+ Tested up to: 4.4
7
+ Stable tag: 2.1.0
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
112
 
113
  == Changelog ==
114
 
115
+ = 2.1.0 (20/12/2015) =
116
+ **New Feature**
117
+
118
+ - New option to set items per page from error log listing page.
119
+ - New option to show or hide items from listing table (Screen option).
120
+
121
+ **Improvements**
122
+
123
+ - Improved error listing page table structure.
124
+
125
+ **Bug Fixes**
126
+
127
+ - Fixed issue - Null value issue when no Referrer or User Agent found.
128
+ - Fixed issue - Clearing errors and redirecting.
129
+
130
  = 2.0.9 (2/11/2015) =
131
  **Bug Fixes**
132
 
229
 
230
  == Upgrade Notice ==
231
 
232
+ = 2.1.0 =
233
+ **New Feature**
234
+
235
+ - New option to set items per page from error log listing page.
236
+ - New option to show or hide items from listing table (Screen option).
237
+
238
+ **Improvements**
239
+
240
+ - Improved error listing page table structure.
241
+
242
+ **Bug Fixes**
243
+
244
+ - Fixed issue - Null value issue when no Referrer or User Agent found.