Version Description
Download this release
Release Info
Developer | maxchirkov |
Plugin | Simple Login Log |
Version | 0.2 |
Comparing to | |
See all releases |
Version 0.2
- readme.txt +30 -0
- screenshot-1.jpg +0 -0
- screenshot-2.jpg +0 -0
- simple-login-log.php +476 -0
readme.txt
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
=== Plugin Name ===
|
2 |
+
Contributors: Max Chirkov
|
3 |
+
Donate link: http://www.ibsteam.net/donate
|
4 |
+
Tags: login, log, users
|
5 |
+
Requires at least: 3.0
|
6 |
+
Tested up to: 3.2.1
|
7 |
+
Stable tag: 0.2
|
8 |
+
|
9 |
+
This plugin keeps a log of WordPress user logins. Offers user and date filtering, and export features.
|
10 |
+
|
11 |
+
== Description ==
|
12 |
+
|
13 |
+
Simple log of user logins. Tracks username, time of login, IP address and browser user agent.
|
14 |
+
|
15 |
+
**Features include:**
|
16 |
+
|
17 |
+
1. ability to filter by username, month and year;
|
18 |
+
2. export into CSV file;
|
19 |
+
3. log auto-truncation.
|
20 |
+
|
21 |
+
== Installation ==
|
22 |
+
|
23 |
+
1. Install and activate like any other basic plugin.
|
24 |
+
2. If you wish to set log trancation, go to Settings => General. Scroll down to Simple Login Log.
|
25 |
+
3. To view login log, go to Users => Login Log. You can export the log to CVS file form the same page.
|
26 |
+
|
27 |
+
== Screenshots ==
|
28 |
+
|
29 |
+
1. Simple Login Log Settings.
|
30 |
+
2. Login Log Management Screen.
|
screenshot-1.jpg
ADDED
Binary file
|
screenshot-2.jpg
ADDED
Binary file
|
simple-login-log.php
ADDED
@@ -0,0 +1,476 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
Plugin Name: Simple Login Log
|
4 |
+
Plugin URI: http://simplerealtytheme.com
|
5 |
+
Description: This plugin keeps a log of WordPress user logins. Offers user filtering and export features.
|
6 |
+
Author: Max Chirkov
|
7 |
+
Version: 0.2
|
8 |
+
Author URI: http://SimpleRealtyTheme.com
|
9 |
+
*/
|
10 |
+
|
11 |
+
|
12 |
+
//TODO: add cleanup method on uninstall
|
13 |
+
|
14 |
+
if( !class_exists( 'SimpleLoginLog' ) )
|
15 |
+
{
|
16 |
+
class SimpleLoginLog {
|
17 |
+
private $table = 'simple_login_log';
|
18 |
+
private $log_duration = null; //days
|
19 |
+
private $opt_name = 'simple_login_log';
|
20 |
+
private $opt = false;
|
21 |
+
|
22 |
+
function __construct()
|
23 |
+
{
|
24 |
+
global $wpdb;
|
25 |
+
$this->table = $wpdb->prefix . $this->table;
|
26 |
+
$this->opt = get_option($this->opt_name);
|
27 |
+
|
28 |
+
if(isset($_GET['download-login-log']))
|
29 |
+
{
|
30 |
+
$this->export_to_CSV();
|
31 |
+
}
|
32 |
+
|
33 |
+
|
34 |
+
add_action( 'admin_menu', array(&$this, 'sll_admin_menu') );
|
35 |
+
add_action('admin_init', array(&$this, 'settings_api_init') );
|
36 |
+
|
37 |
+
//Action on successfull loging
|
38 |
+
add_action( 'wp_login', array(&$this, 'login_success') );
|
39 |
+
|
40 |
+
//Style the log table
|
41 |
+
add_action( 'admin_head', array(&$this, 'admin_header') );
|
42 |
+
|
43 |
+
//Initialize scheduled events
|
44 |
+
add_action( 'wp', array(&$this, 'init_scheduled_events') );
|
45 |
+
}
|
46 |
+
|
47 |
+
function init_scheduled_events()
|
48 |
+
{
|
49 |
+
if ( $this->opt['log_duration'] && !wp_next_scheduled( 'truncate_log' ) )
|
50 |
+
{
|
51 |
+
wp_schedule_event(time(), 'daily', 'truncate_log');
|
52 |
+
}elseif( !$this->opt['log_duration'] || 0 == $this->opt['log_duration'])
|
53 |
+
{
|
54 |
+
$timestamp = wp_next_scheduled( 'truncate_log' );
|
55 |
+
(!$timestamp) ? false : wp_unschedule_event($timestamp, 'truncate_log');
|
56 |
+
|
57 |
+
}
|
58 |
+
}
|
59 |
+
|
60 |
+
function truncate_log()
|
61 |
+
{
|
62 |
+
global $wpdb;
|
63 |
+
|
64 |
+
if( 0 < (int) $this->opt['log_duration'] ){
|
65 |
+
$sql = $wpdb->prepare( "DELETE FROM {$this->table} WHERE time < DATE_SUB(CURDATE(),INTERVAL %d DAY)", array($this->opt['log_duration']));
|
66 |
+
$wpdb->query($sql);
|
67 |
+
}
|
68 |
+
}
|
69 |
+
|
70 |
+
function install()
|
71 |
+
{
|
72 |
+
global $wpdb;
|
73 |
+
|
74 |
+
$sql = "CREATE TABLE " . $this->table . "
|
75 |
+
(
|
76 |
+
id INT( 11 ) NOT NULL AUTO_INCREMENT ,
|
77 |
+
uid INT( 11 ) NOT NULL ,
|
78 |
+
user_login VARCHAR( 60 ) NOT NULL ,
|
79 |
+
time DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL ,
|
80 |
+
ip VARCHAR( 100 ) NOT NULL ,
|
81 |
+
data LONGTEXT NOT NULL ,
|
82 |
+
PRIMARY KEY ( id ) ,
|
83 |
+
INDEX ( uid, ip )
|
84 |
+
);";
|
85 |
+
|
86 |
+
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
|
87 |
+
dbDelta($sql);
|
88 |
+
}
|
89 |
+
|
90 |
+
//Initializing Settings
|
91 |
+
function settings_api_init()
|
92 |
+
{
|
93 |
+
add_settings_section('simple_login_log', 'Simple Login Log', array(&$this, 'sll_settings'), 'general');
|
94 |
+
add_settings_field('field_log_duration', 'Truncate Log Entries', array(&$this, 'field_log_duration'), 'general', 'simple_login_log');
|
95 |
+
register_setting( 'general', 'simple_login_log' );
|
96 |
+
}
|
97 |
+
|
98 |
+
function sll_admin_menu()
|
99 |
+
{
|
100 |
+
add_submenu_page( 'users.php', __('Simple Login Log', 'sll'), __('Login Log', 'sll'), 'edit_users', 'login_log', array(&$this, 'log_manager') );
|
101 |
+
}
|
102 |
+
|
103 |
+
function sll_settings()
|
104 |
+
{
|
105 |
+
//content that goes before the fields output
|
106 |
+
}
|
107 |
+
|
108 |
+
function field_log_duration()
|
109 |
+
{
|
110 |
+
$duration = (null !== $this->opt['log_duration']) ? $this->opt['log_duration'] : $this->log_duration;
|
111 |
+
$output = '<input type="text" value="' . $duration . '" name="simple_login_log[log_duration]" size="10" class="code" /> days and older.';
|
112 |
+
echo $output;
|
113 |
+
echo "<p>Leave empty or enter 0 if you don't want the log to be truncated.</p>";
|
114 |
+
}
|
115 |
+
|
116 |
+
function admin_header()
|
117 |
+
{
|
118 |
+
if($_GET['page'] != 'login_log')
|
119 |
+
return;
|
120 |
+
|
121 |
+
echo '<style type="text/css">';
|
122 |
+
echo '.wp-list-table .column-id { width: 5%; }';
|
123 |
+
echo '.wp-list-table .column-uid { width: 10%; }';
|
124 |
+
echo '.wp-list-table .column-user_login { width: 10%; }';
|
125 |
+
echo '.wp-list-table .column-name { width: 15%; }';
|
126 |
+
echo '.wp-list-table .column-time { width: 15%; }';
|
127 |
+
echo '.wp-list-table .column-ip { width: 10%; }';
|
128 |
+
echo '</style>';
|
129 |
+
}
|
130 |
+
|
131 |
+
//Catch messages on successful login
|
132 |
+
function login_success($user_login){
|
133 |
+
|
134 |
+
$userdata = get_user_by('login', $user_login);
|
135 |
+
|
136 |
+
$uid = ($userdata->ID) ? $userdata->ID : 0;
|
137 |
+
|
138 |
+
//Stop if login form wasn't submitted
|
139 |
+
if( !$_REQUEST['wp-submit'] )
|
140 |
+
return;
|
141 |
+
|
142 |
+
if ( isset( $_REQUEST['redirect_to'] ) ) { $data['Login Redirect'] = $_REQUEST['redirect_to']; }
|
143 |
+
$data['User Agent'] = $_SERVER['HTTP_USER_AGENT'];
|
144 |
+
|
145 |
+
$serialized_data = serialize($data);
|
146 |
+
|
147 |
+
$values = array(
|
148 |
+
'uid' => $uid,
|
149 |
+
'user_login' => $user_login,
|
150 |
+
'time' => current_time('mysql'),
|
151 |
+
'ip' => $_SERVER['REMOTE_ADDR'],
|
152 |
+
'data' => $serialized_data,
|
153 |
+
);
|
154 |
+
|
155 |
+
$format = array('%d', '%s', '%s', '%s', '%s');
|
156 |
+
|
157 |
+
$this->save_data($values, $format);
|
158 |
+
}
|
159 |
+
|
160 |
+
function save_data($values, $format){
|
161 |
+
global $wpdb;
|
162 |
+
|
163 |
+
$wpdb->insert( $this->table, $values, $format );
|
164 |
+
}
|
165 |
+
|
166 |
+
function log_manager()
|
167 |
+
{
|
168 |
+
global $wpdb, $ssl_list_table;
|
169 |
+
|
170 |
+
$log_table = new SLL_List_Table;
|
171 |
+
|
172 |
+
$limit = 20;
|
173 |
+
$offset = ( isset($_REQUEST['page']) ) ? $limit * $_REQUEST['page'] : 0;
|
174 |
+
|
175 |
+
if($_GET['filter'])
|
176 |
+
{
|
177 |
+
$where = "WHERE user_login = '{$_GET['filter']}'";
|
178 |
+
}
|
179 |
+
if($_GET['datefilter'])
|
180 |
+
{
|
181 |
+
$year = substr($_GET['datefilter'], 0, 4);
|
182 |
+
$month = substr($_GET['datefilter'], -2);
|
183 |
+
$where = "WHERE YEAR(time) = {$year} AND MONTH(time) = {$month}";
|
184 |
+
}
|
185 |
+
|
186 |
+
$sql = "SELECT * FROM $this->table $where ORDER BY time DESC LIMIT $limit OFFSET $offset";
|
187 |
+
$data = $wpdb->get_results($sql, 'ARRAY_A');
|
188 |
+
|
189 |
+
$log_table->items = $data;
|
190 |
+
$log_table->prepare_items();
|
191 |
+
|
192 |
+
echo '<div class="wrap srp">';
|
193 |
+
echo '<h2>Login Log</h2>';
|
194 |
+
echo '<div class="tablenav top">';
|
195 |
+
echo '<div class="alignleft actions">';
|
196 |
+
echo $this->date_filter();
|
197 |
+
echo '</div>';
|
198 |
+
echo '<form method="get">';
|
199 |
+
echo '<p class="search-box">';
|
200 |
+
echo '<input type="hidden" name="page" value="login_log" />';
|
201 |
+
echo '<label>Username: </label><input type="text" name="filter" class="filter-username" /> <input class="button" type="submit" value="Filter User" />';
|
202 |
+
echo '</p>';
|
203 |
+
echo '</form>';
|
204 |
+
echo '</div>';
|
205 |
+
$log_table->display();
|
206 |
+
echo '</div>';
|
207 |
+
echo '<form method="get" id="export-login-log">';
|
208 |
+
echo '<input type="hidden" name="page" value="login_log" />';
|
209 |
+
echo '<input type="hidden" name="download-login-log" value="true" />';
|
210 |
+
submit_button( __('Export Log to CSV'), 'secondary' );
|
211 |
+
echo '</form>';
|
212 |
+
}
|
213 |
+
|
214 |
+
private function date_filter()
|
215 |
+
{
|
216 |
+
global $wpdb;
|
217 |
+
$sql = "SELECT DISTINCT YEAR(time) as year, MONTH(time)as month FROM {$this->table}";
|
218 |
+
$results = $wpdb->get_results($sql);
|
219 |
+
|
220 |
+
if(!$results)
|
221 |
+
return;
|
222 |
+
|
223 |
+
|
224 |
+
|
225 |
+
foreach($results as $row)
|
226 |
+
{
|
227 |
+
//represent month in double digits
|
228 |
+
$timestamp = mktime(0, 0, 0, $row->month, 1, $row->year);
|
229 |
+
$month = (strlen($row->month) == 1) ? '0' . $row->month : $row->month;
|
230 |
+
|
231 |
+
$option .= '<option value="' . $row->year . $month . '" ' . selected($row->year . $month, $_GET['datefilter'], false) . '>' . date('F', $timestamp) . ' ' . $row->year . '</option>';
|
232 |
+
}
|
233 |
+
|
234 |
+
$output = '<form method="get">';
|
235 |
+
$output .= '<input type="hidden" name="page" value="login_log" />';
|
236 |
+
$output .= '<select name="datefilter"><option value="">View All</option>' . $option . '</select>';
|
237 |
+
$output .= '<input class="button" type="submit" value="Filter" />';
|
238 |
+
$output .= '</form>';
|
239 |
+
return $output;
|
240 |
+
}
|
241 |
+
|
242 |
+
function export_to_CSV(){
|
243 |
+
global $wpdb;
|
244 |
+
|
245 |
+
$sql = "SELECT * FROM $this->table";
|
246 |
+
$data = $wpdb->get_results($sql, 'ARRAY_A');
|
247 |
+
|
248 |
+
if(!$data)
|
249 |
+
return;
|
250 |
+
|
251 |
+
// send response headers to the browser
|
252 |
+
header( 'Content-Type: text/csv' );
|
253 |
+
header( 'Content-Disposition: attachment;filename=login_log.csv');
|
254 |
+
$fp = fopen('php://output', 'w');
|
255 |
+
|
256 |
+
$i = 0;
|
257 |
+
foreach($data as $row){
|
258 |
+
$tmp = unserialize($row['data']);
|
259 |
+
//output header row
|
260 |
+
if(0 == $i)
|
261 |
+
{
|
262 |
+
fputcsv( $fp, array_keys($row) );
|
263 |
+
}
|
264 |
+
$row_data = (!empty($tmp)) ? array_map(create_function('$key, $value', 'return $key.": ".$value." | ";'), array_keys($tmp), array_values($tmp)) : array();
|
265 |
+
$row['data'] = implode($row_data);
|
266 |
+
fputcsv($fp, $row);
|
267 |
+
$i++;
|
268 |
+
}
|
269 |
+
|
270 |
+
fclose($fp);
|
271 |
+
die();
|
272 |
+
}
|
273 |
+
|
274 |
+
}
|
275 |
+
}
|
276 |
+
|
277 |
+
if( class_exists( 'SimpleLoginLog' ) )
|
278 |
+
{
|
279 |
+
$sll = new SimpleLoginLog;
|
280 |
+
//Register for activation
|
281 |
+
register_activation_hook( __FILE__, array(&$sll, 'install') );
|
282 |
+
|
283 |
+
}
|
284 |
+
|
285 |
+
if(!class_exists('WP_List_Table')){
|
286 |
+
require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
|
287 |
+
}
|
288 |
+
class SLL_List_Table extends WP_List_Table
|
289 |
+
{
|
290 |
+
function __construct()
|
291 |
+
{
|
292 |
+
global $status, $page;
|
293 |
+
|
294 |
+
//Set parent defaults
|
295 |
+
parent::__construct( array(
|
296 |
+
'singular' => 'user', //singular name of the listed records
|
297 |
+
'plural' => 'users', //plural name of the listed records
|
298 |
+
'ajax' => false //does this table support ajax?
|
299 |
+
) );
|
300 |
+
|
301 |
+
}
|
302 |
+
|
303 |
+
function column_default($item, $column_name)
|
304 |
+
{
|
305 |
+
switch($column_name){
|
306 |
+
case 'id':
|
307 |
+
case 'uid':
|
308 |
+
case 'time':
|
309 |
+
case 'ip':
|
310 |
+
return $item[$column_name];
|
311 |
+
case 'user_login':
|
312 |
+
return "<a href='" . get_admin_url() . "users.php?page=login_log&filter={$item[$column_name]}' title='Filter log by this name'>{$item[$column_name]}</a>";
|
313 |
+
case 'name';
|
314 |
+
$user_info = get_userdata($item['uid']);
|
315 |
+
return $user_info->first_name . " " . $user_info->last_name;
|
316 |
+
case 'data':
|
317 |
+
$data = unserialize($item[$column_name]);
|
318 |
+
if(is_array($data))
|
319 |
+
{
|
320 |
+
foreach($data as $k => $v)
|
321 |
+
{
|
322 |
+
$output .= $k .': '. $v .'<br />';
|
323 |
+
}
|
324 |
+
return $output;
|
325 |
+
}
|
326 |
+
break;
|
327 |
+
default:
|
328 |
+
print_r($item);
|
329 |
+
}
|
330 |
+
}
|
331 |
+
|
332 |
+
function get_columns()
|
333 |
+
{
|
334 |
+
$columns = array(
|
335 |
+
'id' => '#',
|
336 |
+
'uid' => 'User ID',
|
337 |
+
'user_login' => 'Username',
|
338 |
+
'name' => 'Name',
|
339 |
+
'time' => 'Time',
|
340 |
+
'ip' => 'IP Address',
|
341 |
+
'data' => 'Data',
|
342 |
+
);
|
343 |
+
return $columns;
|
344 |
+
}
|
345 |
+
|
346 |
+
function get_sortable_columns()
|
347 |
+
{
|
348 |
+
$sortable_columns = array(
|
349 |
+
//'id' => array('id',true), //doesn't sort correctly
|
350 |
+
'uid' => array('uid',false),
|
351 |
+
'time' => array('time',true),
|
352 |
+
'ip' => array('ip', false),
|
353 |
+
);
|
354 |
+
return $sortable_columns;
|
355 |
+
}
|
356 |
+
|
357 |
+
function prepare_items()
|
358 |
+
{
|
359 |
+
|
360 |
+
/**
|
361 |
+
* First, lets decide how many records per page to show
|
362 |
+
*/
|
363 |
+
$per_page = 20;
|
364 |
+
|
365 |
+
|
366 |
+
/**
|
367 |
+
* REQUIRED. Now we need to define our column headers. This includes a complete
|
368 |
+
* array of columns to be displayed (slugs & titles), a list of columns
|
369 |
+
* to keep hidden, and a list of columns that are sortable. Each of these
|
370 |
+
* can be defined in another method (as we've done here) before being
|
371 |
+
* used to build the value for our _column_headers property.
|
372 |
+
*/
|
373 |
+
$columns = $this->get_columns();
|
374 |
+
$hidden = array();
|
375 |
+
$sortable = $this->get_sortable_columns();
|
376 |
+
|
377 |
+
|
378 |
+
/**
|
379 |
+
* REQUIRED. Finally, we build an array to be used by the class for column
|
380 |
+
* headers. The $this->_column_headers property takes an array which contains
|
381 |
+
* 3 other arrays. One for all columns, one for hidden columns, and one
|
382 |
+
* for sortable columns.
|
383 |
+
*/
|
384 |
+
$this->_column_headers = array($columns, $hidden, $sortable);
|
385 |
+
|
386 |
+
|
387 |
+
/**
|
388 |
+
* Optional. You can handle your bulk actions however you see fit. In this
|
389 |
+
* case, we'll handle them within our package just to keep things clean.
|
390 |
+
*/
|
391 |
+
//$this->process_bulk_action();
|
392 |
+
|
393 |
+
|
394 |
+
/**
|
395 |
+
* Instead of querying a database, we're going to fetch the example data
|
396 |
+
* property we created for use in this plugin. This makes this example
|
397 |
+
* package slightly different than one you might build on your own. In
|
398 |
+
* this example, we'll be using array manipulation to sort and paginate
|
399 |
+
* our data. In a real-world implementation, you will probably want to
|
400 |
+
* use sort and pagination data to build a custom query instead, as you'll
|
401 |
+
* be able to use your precisely-queried data immediately.
|
402 |
+
*/
|
403 |
+
$data = $this->items;
|
404 |
+
|
405 |
+
|
406 |
+
/**
|
407 |
+
* This checks for sorting input and sorts the data in our array accordingly.
|
408 |
+
*
|
409 |
+
* In a real-world situation involving a database, you would probably want
|
410 |
+
* to handle sorting by passing the 'orderby' and 'order' values directly
|
411 |
+
* to a custom query. The returned data will be pre-sorted, and this array
|
412 |
+
* sorting technique would be unnecessary.
|
413 |
+
*/
|
414 |
+
function usort_reorder($a,$b){
|
415 |
+
$orderby = (!empty($_REQUEST['orderby'])) ? $_REQUEST['orderby'] : 'time'; //If no sort, default to title
|
416 |
+
$order = (!empty($_REQUEST['order'])) ? $_REQUEST['order'] : 'desc'; //If no order, default to asc
|
417 |
+
$result = strcmp($a[$orderby], $b[$orderby]); //Determine sort order
|
418 |
+
return ($order==='asc') ? $result : -$result; //Send final sort direction to usort
|
419 |
+
}
|
420 |
+
usort($data, 'usort_reorder');
|
421 |
+
|
422 |
+
|
423 |
+
/***********************************************************************
|
424 |
+
* ---------------------------------------------------------------------
|
425 |
+
* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
|
426 |
+
*
|
427 |
+
* In a real-world situation, this is where you would place your query.
|
428 |
+
*
|
429 |
+
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
430 |
+
* ---------------------------------------------------------------------
|
431 |
+
**********************************************************************/
|
432 |
+
|
433 |
+
|
434 |
+
/**
|
435 |
+
* REQUIRED for pagination. Let's figure out what page the user is currently
|
436 |
+
* looking at. We'll need this later, so you should always include it in
|
437 |
+
* your own package classes.
|
438 |
+
*/
|
439 |
+
$current_page = $this->get_pagenum();
|
440 |
+
|
441 |
+
/**
|
442 |
+
* REQUIRED for pagination. Let's check how many items are in our data array.
|
443 |
+
* In real-world use, this would be the total number of items in your database,
|
444 |
+
* without filtering. We'll need this later, so you should always include it
|
445 |
+
* in your own package classes.
|
446 |
+
*/
|
447 |
+
$total_items = count($data);
|
448 |
+
|
449 |
+
|
450 |
+
/**
|
451 |
+
* The WP_List_Table class does not handle pagination for us, so we need
|
452 |
+
* to ensure that the data is trimmed to only the current page. We can use
|
453 |
+
* array_slice() to
|
454 |
+
*/
|
455 |
+
$data = array_slice($data,(($current_page-1)*$per_page),$per_page);
|
456 |
+
|
457 |
+
|
458 |
+
|
459 |
+
/**
|
460 |
+
* REQUIRED. Now we can add our *sorted* data to the items property, where
|
461 |
+
* it can be used by the rest of the class.
|
462 |
+
*/
|
463 |
+
$this->items = $data;
|
464 |
+
|
465 |
+
|
466 |
+
/**
|
467 |
+
* REQUIRED. We also have to register our pagination options & calculations.
|
468 |
+
*/
|
469 |
+
$this->set_pagination_args( array(
|
470 |
+
'total_items' => $total_items, //WE have to calculate the total number of items
|
471 |
+
'per_page' => $per_page, //WE have to determine how many items to show on a page
|
472 |
+
'total_pages' => ceil($total_items/$per_page) //WE have to calculate the total number of pages
|
473 |
+
) );
|
474 |
+
}
|
475 |
+
|
476 |
+
}
|