Simple Login Log - Version 0.9.3

Version Description

Download this release

Release Info

Developer maxchirkov
Plugin Icon wp plugin Simple Login Log
Version 0.9.3
Comparing to
See all releases

Code changes from version 0.9.2 to 0.9.3

Files changed (4) hide show
  1. languages/simple-login-log.pot +46 -34
  2. readme.txt +14 -7
  3. simple-login-log.php +182 -188
  4. uninstall.php +16 -0
languages/simple-login-log.pot CHANGED
@@ -1,134 +1,146 @@
1
- # Copyright (C) 2010 Simple Login Log
2
  # This file is distributed under the same license as the Simple Login Log package.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: Simple Login Log 0.4\n"
6
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/simple-login-log\n"
7
- "POT-Creation-Date: 2011-12-02 17:27:38+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=UTF-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
- "PO-Revision-Date: 2010-MO-DA HO:MI+ZONE\n"
12
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
  "Language-Team: LANGUAGE <LL@li.org>\n"
14
 
15
- #: simple-login-log.php:63 simple-login-log.php:681
16
  msgid "Successful"
17
  msgstr ""
18
 
19
- #: simple-login-log.php:64 simple-login-log.php:682
20
  msgid "Failed"
21
  msgstr ""
22
 
23
- #: simple-login-log.php:65
24
  msgid "Login"
25
  msgstr ""
26
 
27
- #: simple-login-log.php:66
28
  msgid "User Agent"
29
  msgstr ""
30
 
31
- #: simple-login-log.php:67
32
  msgid "Login Redirect"
33
  msgstr ""
34
 
35
- #: simple-login-log.php:68
36
  msgid "#"
37
  msgstr ""
38
 
39
- #: simple-login-log.php:69
40
  msgid "User ID"
41
  msgstr ""
42
 
43
- #: simple-login-log.php:70
44
  msgid "Username"
45
  msgstr ""
46
 
47
- #: simple-login-log.php:71
 
 
 
 
48
  msgid "Name"
49
  msgstr ""
50
 
51
- #: simple-login-log.php:72
52
  msgid "Time"
53
  msgstr ""
54
 
55
- #: simple-login-log.php:73
56
  msgid "IP Address"
57
  msgstr ""
58
 
59
- #: simple-login-log.php:74
60
  msgid "Login Result"
61
  msgstr ""
62
 
63
- #: simple-login-log.php:75
64
  msgid "Data"
65
  msgstr ""
66
 
67
- #: simple-login-log.php:112
68
  msgid "Records"
69
  msgstr ""
70
 
71
- #. #-#-#-#-# plugin.pot (Simple Login Log 0.4) #-#-#-#-#
72
  #. Plugin Name of the plugin/theme
73
- #: simple-login-log.php:259 simple-login-log.php:268
74
  msgid "Simple Login Log"
75
  msgstr ""
76
 
77
- #: simple-login-log.php:260
78
  msgid "Truncate Log Entries"
79
  msgstr ""
80
 
81
- #: simple-login-log.php:261
82
  msgid "Log Failed Attempts"
83
  msgstr ""
84
 
85
- #: simple-login-log.php:268 simple-login-log.php:386
86
  msgid "Login Log"
87
  msgstr ""
88
 
89
- #: simple-login-log.php:281
 
 
 
 
90
  msgid "Leave empty or enter 0 if you don't want the log to be truncated."
91
  msgstr ""
92
 
93
- #: simple-login-log.php:286
94
  msgid ""
95
  "Logs failed attempts where user name and password are entered. Will not log "
96
  "if at least one of the mentioned fields is empty."
97
  msgstr ""
98
 
99
- #: simple-login-log.php:396
100
  msgid "Username:"
101
  msgstr ""
102
 
103
- #: simple-login-log.php:396
104
  msgid "Filter User"
105
  msgstr ""
106
 
107
- #: simple-login-log.php:421
108
  msgid "Export Log to CSV"
109
  msgstr ""
110
 
111
- #: simple-login-log.php:430
112
  msgid "Export Current Results to CSV"
113
  msgstr ""
114
 
115
- #: simple-login-log.php:460
116
  msgid "View All"
117
  msgstr ""
118
 
119
- #: simple-login-log.php:461
120
  msgid "Filter"
121
  msgstr ""
122
 
123
- #: simple-login-log.php:555
124
  msgid "Filter log by this name"
125
  msgstr ""
126
 
127
- #: simple-login-log.php:680
 
 
 
 
128
  msgid "Login Results"
129
  msgstr ""
130
 
131
- #: simple-login-log.php:680
132
  msgid "All"
133
  msgstr ""
134
 
1
+ # Copyright (C) 2012 Simple Login Log
2
  # This file is distributed under the same license as the Simple Login Log package.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: Simple Login Log 0.9.3\n"
6
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/simple-login-log\n"
7
+ "POT-Creation-Date: 2012-05-22 19:12:22+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=UTF-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
+ "PO-Revision-Date: 2012-MO-DA HO:MI+ZONE\n"
12
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
  "Language-Team: LANGUAGE <LL@li.org>\n"
14
 
15
+ #: simple-login-log.php:65 simple-login-log.php:820
16
  msgid "Successful"
17
  msgstr ""
18
 
19
+ #: simple-login-log.php:66 simple-login-log.php:821
20
  msgid "Failed"
21
  msgstr ""
22
 
23
+ #: simple-login-log.php:67
24
  msgid "Login"
25
  msgstr ""
26
 
27
+ #: simple-login-log.php:68
28
  msgid "User Agent"
29
  msgstr ""
30
 
31
+ #: simple-login-log.php:69
32
  msgid "Login Redirect"
33
  msgstr ""
34
 
35
+ #: simple-login-log.php:70
36
  msgid "#"
37
  msgstr ""
38
 
39
+ #: simple-login-log.php:71
40
  msgid "User ID"
41
  msgstr ""
42
 
43
+ #: simple-login-log.php:72
44
  msgid "Username"
45
  msgstr ""
46
 
47
+ #: simple-login-log.php:73
48
+ msgid "User Role"
49
+ msgstr ""
50
+
51
+ #: simple-login-log.php:74
52
  msgid "Name"
53
  msgstr ""
54
 
55
+ #: simple-login-log.php:75
56
  msgid "Time"
57
  msgstr ""
58
 
59
+ #: simple-login-log.php:76
60
  msgid "IP Address"
61
  msgstr ""
62
 
63
+ #: simple-login-log.php:77
64
  msgid "Login Result"
65
  msgstr ""
66
 
67
+ #: simple-login-log.php:78
68
  msgid "Data"
69
  msgstr ""
70
 
71
+ #: simple-login-log.php:128
72
  msgid "Records"
73
  msgstr ""
74
 
75
+ #. #-#-#-#-# plugin.pot (Simple Login Log 0.9.3) #-#-#-#-#
76
  #. Plugin Name of the plugin/theme
77
+ #: simple-login-log.php:339 simple-login-log.php:349
78
  msgid "Simple Login Log"
79
  msgstr ""
80
 
81
+ #: simple-login-log.php:340
82
  msgid "Truncate Log Entries"
83
  msgstr ""
84
 
85
+ #: simple-login-log.php:341
86
  msgid "Log Failed Attempts"
87
  msgstr ""
88
 
89
+ #: simple-login-log.php:349 simple-login-log.php:501
90
  msgid "Login Log"
91
  msgstr ""
92
 
93
+ #: simple-login-log.php:362
94
+ msgid "days and older."
95
+ msgstr ""
96
+
97
+ #: simple-login-log.php:364
98
  msgid "Leave empty or enter 0 if you don't want the log to be truncated."
99
  msgstr ""
100
 
101
+ #: simple-login-log.php:377
102
  msgid ""
103
  "Logs failed attempts where user name and password are entered. Will not log "
104
  "if at least one of the mentioned fields is empty."
105
  msgstr ""
106
 
107
+ #: simple-login-log.php:511
108
  msgid "Username:"
109
  msgstr ""
110
 
111
+ #: simple-login-log.php:511
112
  msgid "Filter User"
113
  msgstr ""
114
 
115
+ #: simple-login-log.php:536
116
  msgid "Export Log to CSV"
117
  msgstr ""
118
 
119
+ #: simple-login-log.php:545
120
  msgid "Export Current Results to CSV"
121
  msgstr ""
122
 
123
+ #: simple-login-log.php:576
124
  msgid "View All"
125
  msgstr ""
126
 
127
+ #: simple-login-log.php:577
128
  msgid "Filter"
129
  msgstr ""
130
 
131
+ #: simple-login-log.php:678
132
  msgid "Filter log by this name"
133
  msgstr ""
134
 
135
+ #: simple-login-log.php:692
136
+ msgid "Filter log by User Role"
137
+ msgstr ""
138
+
139
+ #: simple-login-log.php:819
140
  msgid "Login Results"
141
  msgstr ""
142
 
143
+ #: simple-login-log.php:819
144
  msgid "All"
145
  msgstr ""
146
 
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: http://www.ibsteam.net/donate
4
  Tags: login, log, users
5
  Requires at least: 3.0
6
  Tested up to: 3.3.2
7
- Stable tag: 0.9.2
8
 
9
  This plugin keeps a log of WordPress user logins. Offers user and date filtering, and export features.
10
 
@@ -14,7 +14,7 @@ Simple log of user logins. Tracks username, time of login, IP address and browse
14
 
15
  [Demo Video](http://screenr.com/kfEs "Demo Video")
16
 
17
- **Features include:**
18
 
19
  1. ability to filter by username, successful/failed logins, month and year;
20
  2. export into CSV file;
@@ -28,10 +28,10 @@ Simple log of user logins. Tracks username, time of login, IP address and browse
28
  == Installation ==
29
 
30
  1. Install and activate like any other basic plugin.
31
- 2. If you wish to set log trancation or opt-in to record failed login attemtps, go to Settings => General. Scroll down to Simple Login Log.
32
  3. To view login log, go to Users => Login Log. You can export the log to CSV file form the same page.
33
 
34
- Screen Options are available at the top of the Login Log page. Click on the *Secreen Options* tab to expand the options section. You'll be able to change the number of results pre page as well as hide/display table columns.
35
 
36
  == Screenshots ==
37
 
@@ -40,6 +40,13 @@ Screen Options are available at the top of the Login Log page. Click on the *Sec
40
 
41
  == Changelog ==
42
 
 
 
 
 
 
 
 
43
  **Version 0.9.2**
44
 
45
  - Daily cron job with log truncation didn't work.
@@ -63,7 +70,7 @@ Screen Options are available at the top of the Login Log page. Click on the *Sec
63
 
64
  **Version 0.5**
65
 
66
- - Bug fix: in_array() warning for hidden columns not returning an array.
67
 
68
  **Version 0.4**
69
 
@@ -90,7 +97,7 @@ For example, we can use this filter to link IP addresses to a geo-location servi
90
  <?php
91
  add_filter( 'sll-output-data', 'link_location_by_ip' );
92
  function link_location_by_ip($item){
93
-
94
  //$item is a single row for columns with their values
95
 
96
  $item['ip'] = sprintf('<a target="_blank" href="http://infosniper.net/index.php?ip_address=%1$s&map_source=3&two_maps=1&overview_map=1&lang=1&map_type=1&zoom_level=11">%1$s</a>', $item['ip']);
@@ -101,4 +108,4 @@ function link_location_by_ip($item){
101
 
102
  = Translation =
103
 
104
- Currently there are no trunslations available. If you would like to contribute, the POT file is available in the *languages* folder. Translation file name convention is *sll-{locale}.mo*, where {locale} is the locale of your language. Fore example, Russian file name would be *sll-ru_RU.po*.
4
  Tags: login, log, users
5
  Requires at least: 3.0
6
  Tested up to: 3.3.2
7
+ Stable tag: 0.9.3
8
 
9
  This plugin keeps a log of WordPress user logins. Offers user and date filtering, and export features.
10
 
14
 
15
  [Demo Video](http://screenr.com/kfEs "Demo Video")
16
 
17
+ **Features include:**
18
 
19
  1. ability to filter by username, successful/failed logins, month and year;
20
  2. export into CSV file;
28
  == Installation ==
29
 
30
  1. Install and activate like any other basic plugin.
31
+ 2. If you wish to set log trancation or opt-in to record failed login attempts, go to Settings => General. Scroll down to Simple Login Log.
32
  3. To view login log, go to Users => Login Log. You can export the log to CSV file form the same page.
33
 
34
+ Screen Options are available at the top of the Login Log page. Click on the *Secreen Options* tab to expand the options section. You'll be able to change the number of results per page as well as hide/display table columns.
35
 
36
  == Screenshots ==
37
 
40
 
41
  == Changelog ==
42
 
43
+ **Version 0.9.3**
44
+
45
+ - Improvement: search by partial user name as well as partial IP address per [Commeuneimage's recommendation](http://wordpress.org/support/topic/plugin-simple-login-log-small-enhancement-suggested-on-search-feature).
46
+ - Updated POT file.
47
+ - Added Russian and Ukrainian Translation.
48
+ - Added uninstall.php to all plugin's data from the database on plugin deletion.
49
+
50
  **Version 0.9.2**
51
 
52
  - Daily cron job with log truncation didn't work.
70
 
71
  **Version 0.5**
72
 
73
+ - Bug fix: in_array() warning for hidden columns not returning an array.
74
 
75
  **Version 0.4**
76
 
97
  <?php
98
  add_filter( 'sll-output-data', 'link_location_by_ip' );
99
  function link_location_by_ip($item){
100
+
101
  //$item is a single row for columns with their values
102
 
103
  $item['ip'] = sprintf('<a target="_blank" href="http://infosniper.net/index.php?ip_address=%1$s&map_source=3&two_maps=1&overview_map=1&lang=1&map_type=1&zoom_level=11">%1$s</a>', $item['ip']);
108
 
109
  = Translation =
110
 
111
+ Currently there are no translations available. If you would like to contribute, the POT file is available in the *languages* folder. Translation file name convention is *sll-{locale}.mo*, where {locale} is the locale of your language. Fore example, Russian file name would be *sll-ru_RU.po*.
simple-login-log.php CHANGED
@@ -4,24 +4,24 @@
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.9.2
8
  Author URI: http://SimpleRealtyTheme.com
9
  */
10
 
11
  //TODO: add cleanup method on uninstall
12
 
13
  if( !class_exists( 'SimpleLoginLog' ) )
14
- {
15
  class SimpleLoginLog {
16
  private $db_ver = "1.2";
17
  public $table = 'simple_login_log';
18
  private $log_duration = null; //days
19
  private $opt_name = 'simple_login_log';
20
  private $opt = false;
21
- private $login_success = 1;
22
  public $data_labels = array();
23
 
24
-
25
  function __construct()
26
  {
27
  global $wpdb;
@@ -31,13 +31,13 @@ if( !class_exists( 'SimpleLoginLog' ) )
31
  //Get plugin's DB version
32
  $this->installed_ver = get_option( "sll_db_ver" );
33
 
34
- //Check if download was initiated
35
  $download = @esc_attr( $_GET['download-login-log'] );
36
  if($download)
37
  {
38
  $where = ( isset($_GET['where']) ) ? $_GET['where'] : false;
39
  $this->export_to_CSV($where);
40
- }
41
 
42
 
43
  add_action( 'admin_menu', array(&$this, 'sll_admin_menu') );
@@ -46,10 +46,10 @@ if( !class_exists( 'SimpleLoginLog' ) )
46
 
47
  //check if db needs to be upgraded after plugin update was completed
48
  add_action('plugins_loaded', array(&$this, 'update_db_check') );
49
-
50
  //Init login actions
51
- add_action( 'init', array(&$this, 'init_login_actions') );
52
-
53
  //Style the log table
54
  add_action( 'admin_head', array(&$this, 'admin_header') );
55
 
@@ -58,7 +58,7 @@ if( !class_exists( 'SimpleLoginLog' ) )
58
  add_action('truncate_sll', array(&$this, 'cron') );
59
 
60
  //Load Locale
61
- add_action('init', array(&$this, 'load_locale'), 10 );
62
 
63
  //For translation purposes
64
  $this->data_labels = array(
@@ -85,18 +85,13 @@ if( !class_exists( 'SimpleLoginLog' ) )
85
 
86
 
87
  function load_locale()
88
- {
89
- $locale = get_locale();
90
- if( empty( $locale ) )
91
- $locale = 'en_US';
92
-
93
- $mofile = dirname( __FILE__ )."/languages/sll-{$locale}.mo";
94
- load_textdomain( 'sll', $mofile );
95
  }
96
 
97
 
98
  function cron()
99
- {
100
  SimpleLoginLog::truncate_log();
101
  }
102
 
@@ -107,7 +102,7 @@ if( !class_exists( 'SimpleLoginLog' ) )
107
  //execute only on login_log page, othewise return null
108
  $page = ( isset($_GET['page']) ) ? esc_attr($_GET['page']) : false;
109
  if( 'login_log' != $page )
110
- return;
111
 
112
  $current_screen = get_current_screen();
113
 
@@ -119,17 +114,17 @@ if( !class_exists( 'SimpleLoginLog' ) )
119
  if( isset($_REQUEST['wp_screen_options']) && isset($_REQUEST['wp_screen_options']['value']) )
120
  {
121
  update_option( $per_page_option, esc_html($_REQUEST['wp_screen_options']['value']) );
122
- }
123
 
124
  //prepare options for display
125
 
126
  //if per page option is not set, use default
127
- $per_page_val = get_option($per_page_option, 20);
128
  $args = array('label' => __('Records', 'sll'), 'default' => $per_page_val );
129
 
130
  //display options
131
- add_screen_option($per_page_field, $args);
132
- $_per_page = get_option('users_page_login_log_per_page');
133
 
134
  //needs to be initialized early enough to pre-fill screen options section in the upper (hidden) area.
135
  $this->log_table = new SLL_List_Table;
@@ -141,10 +136,10 @@ if( !class_exists( 'SimpleLoginLog' ) )
141
  //condition to check if "log failed attemts" option is selected
142
 
143
  //Action on successfull login
144
- add_action( 'wp_login', array(&$this, 'login_success') );
145
 
146
- //Action on failed login
147
- if( isset($this->opt['failed_attempts']) ){
148
  add_action( 'wp_login_failed', array(&$this, 'login_failed') );
149
  }
150
 
@@ -166,19 +161,19 @@ if( !class_exists( 'SimpleLoginLog' ) )
166
 
167
 
168
  function init_scheduled_events()
169
- {
170
 
171
  $log_duration = get_option('simple_login_log');
172
 
173
- if ( $log_duration && !wp_next_scheduled( 'truncate_sll' ) )
174
- {
175
  $start = time();
176
  wp_schedule_event($start, 'daily', 'truncate_sll');
177
  }elseif( !$log_duration || 0 == $log_duration)
178
  {
179
  $timestamp = wp_next_scheduled( 'truncate_sll' );
180
  (!$timestamp) ? false : wp_unschedule_event($timestamp, 'truncate_sll');
181
-
182
  }
183
  }
184
 
@@ -188,7 +183,7 @@ if( !class_exists( 'SimpleLoginLog' ) )
188
 
189
  //clean up old cron jobs that no longer exist
190
  wp_clear_scheduled_hook('truncate_log');
191
- wp_clear_scheduled_hook('SimpleLoginLog::truncate_log');
192
  }
193
 
194
 
@@ -198,14 +193,14 @@ if( !class_exists( 'SimpleLoginLog' ) )
198
 
199
  $opt = get_option('simple_login_log');
200
  $log_duration = (int)$opt['log_duration'];
201
-
202
  $table = $wpdb->prefix . 'simple_login_log';
203
 
204
- if( 0 < $log_duration ){
205
  $sql = $wpdb->prepare( "DELETE FROM {$table} WHERE time < DATE_SUB(CURDATE(),INTERVAL %d DAY)", $log_duration);
206
- $wpdb->query($sql);
207
  }
208
-
209
  }
210
 
211
 
@@ -213,20 +208,20 @@ if( !class_exists( 'SimpleLoginLog' ) )
213
  * Runs via plugin activation hook & creates a database
214
  */
215
  function install()
216
- {
217
  global $wpdb;
218
 
219
  if( $this->installed_ver != $this->db_ver )
220
  {
221
  //if table does't exist, create a new one
222
  if( !$wpdb->get_row("SHOW TABLES LIKE '{$this->table}'") ){
223
- $sql = "CREATE TABLE " . $this->table . "
224
  (
225
  id INT( 11 ) NOT NULL AUTO_INCREMENT ,
226
  uid INT( 11 ) NOT NULL ,
227
  user_login VARCHAR( 60 ) NOT NULL ,
228
  user_role VARCHAR( 30 ) NOT NULL ,
229
- time DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL ,
230
  ip VARCHAR( 100 ) NOT NULL ,
231
  login_result VARCHAR (1) ,
232
  data LONGTEXT NOT NULL ,
@@ -240,11 +235,11 @@ if( !class_exists( 'SimpleLoginLog' ) )
240
  update_option( "sll_db_ver", $this->db_ver );
241
  }
242
  }
243
-
244
-
245
  }
246
 
247
-
248
  /**
249
  * Checks if the installed database version is the same as the db version of the current plugin
250
  * calles the version specific function if upgrade is required
@@ -271,7 +266,7 @@ if( !class_exists( 'SimpleLoginLog' ) )
271
  */
272
  function db_update_1_1()
273
  {
274
-
275
  /* this version adds a new field "login_result"
276
  * check if this field exists
277
  */
@@ -284,21 +279,21 @@ if( !class_exists( 'SimpleLoginLog' ) )
284
  $this->install();
285
  return;
286
  }
287
-
288
  $field_names = array_keys( $fields );
289
-
290
  if( !array_search('login_result', $field_names) )
291
- {
292
  //add the new field since it doesn't exist
293
  $sql = "ALTER TABLE {$this->table} ADD COLUMN login_result varchar(1) NOT NULL AFTER ip, ADD INDEX (login_result);";
294
  $insert = $wpdb->query( $sql );
295
-
296
  //update version record if it has been updated
297
  if( false !== $insert )
298
  update_option( "sll_db_ver", $this->db_ver );
299
 
300
  }
301
-
302
  }
303
 
304
 
@@ -316,30 +311,30 @@ if( !class_exists( 'SimpleLoginLog' ) )
316
  $this->install();
317
  return;
318
  }
319
-
320
  $field_names = array_keys( $fields );
321
-
322
  if( !array_search('user_role', $field_names) )
323
- {
324
  //add the new field since it doesn't exist
325
  $sql = "ALTER TABLE {$this->table} ADD COLUMN user_role varchar(30) NOT NULL AFTER user_login;";
326
  $insert = $wpdb->query( $sql );
327
-
328
  //update version record if it has been updated
329
  if( false !== $insert )
330
  update_option( "sll_db_ver", $this->db_ver );
331
-
332
  }
333
  }
334
-
335
 
336
  //Initializing Settings
337
  function settings_api_init()
338
  {
339
- add_settings_section('simple_login_log', __('Simple Login Log', 'sll'), array(&$this, 'sll_settings'), 'general');
340
  add_settings_field('field_log_duration', __('Truncate Log Entries', 'sll'), array(&$this, 'field_log_duration'), 'general', 'simple_login_log');
341
  add_settings_field('field_log_failed_attempts', __('Log Failed Attempts', 'sll'), array(&$this, 'field_log_failed_attempts'), 'general', 'simple_login_log');
342
- register_setting( 'general', 'simple_login_log' );
343
 
344
  }
345
 
@@ -351,21 +346,21 @@ if( !class_exists( 'SimpleLoginLog' ) )
351
 
352
 
353
  function sll_settings()
354
- {
355
  //content that goes before the fields output
356
  }
357
 
358
 
359
  function field_log_duration()
360
  {
361
- $duration = (null !== $this->opt['log_duration']) ? $this->opt['log_duration'] : $this->log_duration;
362
- $output = '<input type="text" value="' . $duration . '" name="simple_login_log[log_duration]" size="10" class="code" /> days and older.';
363
  echo $output;
364
  echo "<p>" . __("Leave empty or enter 0 if you don't want the log to be truncated.", 'sll') . "</p>";
365
 
366
  //since we're on the General Settings page - update cron schedule if settings has been updated
367
- if( isset($_REQUEST['settings-updated']) ){
368
- wp_clear_scheduled_hook('truncate_sll');
369
  //$this->init_scheduled_events();
370
  }
371
  }
@@ -382,7 +377,7 @@ if( !class_exists( 'SimpleLoginLog' ) )
382
  {
383
  $page = ( isset($_GET['page']) ) ? esc_attr($_GET['page']) : false;
384
  if( 'login_log' != $page )
385
- return;
386
 
387
  echo '<style type="text/css">';
388
  echo '.wp-list-table .column-id { width: 5%; }';
@@ -400,15 +395,15 @@ if( !class_exists( 'SimpleLoginLog' ) )
400
  //Catch messages on successful login
401
  function login_action($user_login)
402
  {
403
-
404
  $userdata = get_user_by('login', $user_login);
405
 
406
  $uid = ($userdata && $userdata->ID) ? $userdata->ID : 0;
407
-
408
  $data[$this->data_labels['Login']] = ( 1 == $this->login_success ) ? $this->data_labels['Successful'] : $this->data_labels['Failed'];
409
- if ( isset( $_REQUEST['redirect_to'] ) ) { $data[$this->data_labels['Login Redirect']] = $_REQUEST['redirect_to']; }
410
  $data[$this->data_labels['User Agent']] = $_SERVER['HTTP_USER_AGENT'];
411
-
412
  $serialized_data = serialize($data);
413
 
414
  //get user role
@@ -419,22 +414,22 @@ if( !class_exists( 'SimpleLoginLog' ) )
419
  $user_role = implode(', ', $user->roles);
420
  }
421
  }
422
-
423
-
424
  $values = array(
425
  'uid' => $uid,
426
  'user_login' => $user_login,
427
  'user_role' => $user_role,
428
- 'time' => current_time('mysql'),
429
  'ip' => $_SERVER['REMOTE_ADDR'],
430
  'login_result' => $this->login_success,
431
  'data' => $serialized_data,
432
  );
433
-
434
  $format = array('%d', '%s', '%s', '%s', '%s', '%s', '%s');
435
 
436
  $this->save_data($values, $format);
437
- }
438
 
439
 
440
  function save_data($values, $format)
@@ -447,10 +442,10 @@ if( !class_exists( 'SimpleLoginLog' ) )
447
 
448
  function make_where_query()
449
  {
450
- $where = false;
451
  if( isset($_GET['filter']) && '' != $_GET['filter'] )
452
  {
453
- $where['filter'] = "user_login = '{$_GET['filter']}'";
454
  }
455
  if( isset($_GET['user_role']) && '' != $_GET['user_role'] )
456
  {
@@ -475,15 +470,13 @@ if( !class_exists( 'SimpleLoginLog' ) )
475
  {
476
  global $wpdb;
477
 
478
- $limit = 20;
479
- $where = '';
480
 
481
  $where = $this->make_where_query();
482
 
483
  if( is_array($where) && !empty($where) )
484
  $where = 'WHERE ' . implode(' AND ', $where);
485
 
486
- $sql = "SELECT * FROM $this->table $where ORDER BY time DESC LIMIT $limit";
487
  $sql = "SELECT * FROM $this->table $where ORDER BY time DESC";
488
  $data = $wpdb->get_results($sql, 'ARRAY_A');
489
 
@@ -492,28 +485,28 @@ if( !class_exists( 'SimpleLoginLog' ) )
492
 
493
 
494
  function log_manager()
495
- {
496
-
497
  $log_table = $this->log_table;
498
-
499
  $log_table->items = $this->log_get_data();
500
- $log_table->prepare_items();
501
 
502
  echo '<div class="wrap srp">';
503
  echo '<h2>' . __('Login Log', 'sll') . '</h2>';
504
  echo '<div class="tablenav top">';
505
  echo '<div class="alignleft actions">';
506
  echo $this->date_filter();
507
- echo '</div>';
508
 
509
  $username = ( isset($_GET['filter']) ) ? esc_attr($_GET['filter']) : false;
510
  echo '<form method="get" class="alignright">';
511
  echo '<p class="search-box">';
512
  echo '<input type="hidden" name="page" value="login_log" />';
513
  echo '<label>' . __('Username:', 'sll') . ' </label><input type="text" name="filter" class="filter-username" value="' . $username . '" /> <input class="button" type="submit" value="' . __('Filter User', 'sll') . '" />';
514
- echo '<br />';
515
- echo '</p>';
516
- echo '</form>';
517
  echo '</div>';
518
  echo '<div class="tablenav top">';
519
 
@@ -527,29 +520,29 @@ if( !class_exists( 'SimpleLoginLog' ) )
527
  echo '<div class="alignright actions">';
528
  $mode = ( isset($_GET['mode']) ) ? esc_attr($_GET['mode']) : false;
529
  $log_table->view_switcher($mode);
530
- echo '</div>';
531
  echo '</div>';
532
-
533
- $log_table->display();
534
-
535
  echo '<form method="get" id="export-login-log">';
536
  echo '<input type="hidden" name="page" value="login_log" />';
537
  echo '<input type="hidden" name="download-login-log" value="true" />';
538
- submit_button( __('Export Log to CSV', 'sll'), 'secondary' );
539
- echo '</form>';
540
  //if filtered results - add export filtered results button
541
  if( $where = $this->make_where_query() ){
542
-
543
  echo '<form method="get" id="export-login-log">';
544
  echo '<input type="hidden" name="page" value="login_log" />';
545
- echo '<input type="hidden" name="download-login-log" value="true" />';
546
  echo '<input type="hidden" name="where" value="' . esc_attr(serialize($where)) . '" />';
547
  submit_button( __('Export Current Results to CSV', 'sll'), 'secondary' );
548
- echo '</form>';
549
-
550
  }
551
-
552
- echo '</div>';
553
  }
554
 
555
 
@@ -562,11 +555,11 @@ if( !class_exists( 'SimpleLoginLog' ) )
562
  if(!$results)
563
  return;
564
 
565
-
566
  $option = '';
567
  foreach($results as $row)
568
  {
569
- //represent month in double digits
570
  $timestamp = mktime(0, 0, 0, $row->month, 1, $row->year);
571
  $month = (strlen($row->month) == 1) ? '0' . $row->month : $row->month;
572
  $datefilter = ( isset($_GET['datefilter']) ) ? $_GET['datefilter'] : false;
@@ -585,7 +578,7 @@ if( !class_exists( 'SimpleLoginLog' ) )
585
  function export_to_CSV($where = false){
586
  global $wpdb;
587
 
588
- //if $where is set, then contemplate WHERE sql query
589
  if( $where ){
590
  $where = unserialize($where);
591
 
@@ -594,20 +587,20 @@ if( !class_exists( 'SimpleLoginLog' ) )
594
 
595
  }
596
 
597
- $sql = "SELECT * FROM {$this->table}{$where}";
598
  $data = $wpdb->get_results($sql, 'ARRAY_A');
599
 
600
  if(!$data)
601
  return;
602
 
603
- //date string to suffix the file nanme: month - day - year - hour - minute
604
  $suffix = date('n-j-y_H-i');
605
 
606
  // send response headers to the browser
607
  header( 'Content-Type: text/csv' );
608
  header( 'Content-Disposition: attachment;filename=login_log_' . $suffix . '.csv');
609
  $fp = fopen('php://output', 'w');
610
-
611
  $i = 0;
612
  foreach($data as $row){
613
  $tmp = unserialize($row['data']);
@@ -621,9 +614,9 @@ if( !class_exists( 'SimpleLoginLog' ) )
621
  fputcsv($fp, $row);
622
  $i++;
623
  }
624
-
625
  fclose($fp);
626
- die();
627
  }
628
 
629
  }
@@ -632,10 +625,10 @@ if( !class_exists( 'SimpleLoginLog' ) )
632
 
633
  if( class_exists( 'SimpleLoginLog' ) )
634
  {
635
- $sll = new SimpleLoginLog;
636
  //Register for activation
637
- register_activation_hook( __FILE__, array(&$sll, 'install') );
638
-
639
  }
640
 
641
  if(!class_exists('WP_List_Table'))
@@ -644,11 +637,11 @@ if(!class_exists('WP_List_Table'))
644
  }
645
 
646
  class SLL_List_Table extends WP_List_Table
647
- {
648
  function __construct()
649
  {
650
  global $sll, $_wp_column_headers;
651
-
652
  //Set parent defaults
653
  parent::__construct( array(
654
  'singular' => 'user', //singular name of the listed records
@@ -656,38 +649,38 @@ class SLL_List_Table extends WP_List_Table
656
  'ajax' => false //does this table support ajax?
657
  ) );
658
 
659
- $this->data_labels = $sll->data_labels;
 
 
660
 
661
- }
662
-
663
 
664
  function column_default($item, $column_name)
665
  {
666
  $item = apply_filters('sll-output-data', $item);
667
 
668
  //unset existing filter and pagination
669
- $args = wp_parse_args( parse_url($_SERVER["REQUEST_URI"], PHP_URL_QUERY) );
670
  unset($args['filter']);
671
- unset($args['paged']);
672
 
673
  switch($column_name){
674
  case 'id':
675
- case 'uid':
676
- case 'time':
677
  case 'ip':
678
  return $item[$column_name];
679
- case 'user_login':
680
- return "<a href='" . add_query_arg( array('filter' => $item[$column_name]), menu_page_url('login_log', false) ) . "' title='" . __('Filter log by this name', 'sll') . "'>{$item[$column_name]}</a>";
681
  case 'name';
682
  $user_info = get_userdata($item['uid']);
683
- return ( is_object($user_info) ) ? $user_info->first_name . " " . $user_info->last_name : false;
684
  case 'login_result':
685
  if ( '' == $item[$column_name]) return '';
686
  return ( '1' == $item[$column_name] ) ? $this->data_labels['Successful'] : '<div class="login-failed">' . $this->data_labels['Failed'] . '</div>';
687
  case 'user_role':
688
  if( !$item['uid'] )
689
  return;
690
-
691
  $user = new WP_User( $item['uid'] );
692
  if ( !empty( $user->roles ) && is_array( $user->roles ) ) {
693
  foreach($user->roles as $role){
@@ -697,7 +690,7 @@ class SLL_List_Table extends WP_List_Table
697
  }
698
  break;
699
  case 'data':
700
- $data = unserialize($item[$column_name]);
701
  if(is_array($data))
702
  {
703
  $output = '';
@@ -709,11 +702,11 @@ class SLL_List_Table extends WP_List_Table
709
  $output = ( isset($_GET['mode']) && 'excerpt' == $_GET['mode'] ) ? $output : substr($output, 0, 50) . '...';
710
 
711
  if( isset($data[$this->data_labels['Login']]) && $data[$this->data_labels['Login']] == $this->data_labels['Failed'] ){
712
- return '<div class="login-failed">' . $output . '</div>';
713
  }
714
  return $output;
715
- }
716
- break;
717
  default:
718
  return $item[$column_name];
719
  }
@@ -721,19 +714,19 @@ class SLL_List_Table extends WP_List_Table
721
 
722
 
723
  function get_columns()
724
- {
725
  global $status;
726
  $columns = array(
727
- 'id' => $this->data_labels['id'],
728
- 'uid' => $this->data_labels['uid'],
729
- 'user_login' => $this->data_labels['user_login'],
730
- 'user_role' => $this->data_labels['user_role'],
731
- 'name' => $this->data_labels['name'],
732
- 'time' => $this->data_labels['time'],
733
- 'ip' => $this->data_labels['ip'],
734
- 'login_result' => $this->data_labels['login_result'],
735
- 'data' => $this->data_labels['data'],
736
- );
737
  return $columns;
738
  }
739
 
@@ -755,14 +748,14 @@ class SLL_List_Table extends WP_List_Table
755
  {
756
  //creating class="current" variables
757
  if( !isset($_GET['result']) ){
758
- $all = 'class="current"';
759
- $success = '';
760
  $failed = '';
761
  }else{
762
  $all = '';
763
  $success = ( '1' == $_GET['result'] ) ? 'class="current"' : '';
764
- $failed = ( '0' == $_GET['result'] ) ? 'class="current"' : '';
765
- }
766
 
767
  //get number of successful and failed logins so we can display them in parentheces for each view
768
  global $wpdb, $sll;
@@ -775,14 +768,14 @@ class SLL_List_Table extends WP_List_Table
775
  }else{
776
  $where = false;
777
  }
778
-
779
  $where3 = $where2 = $where1 = $where;
780
  $where2['login_result'] = "login_result = '1'";
781
  $where3['login_result'] = "login_result = '0'";
782
-
783
  if(is_array($where1) && !empty($where1)){
784
- $where1 = 'WHERE ' . implode(' AND ', $where1);
785
- }
786
  $where2 = 'WHERE ' . implode(' AND ', $where2);
787
  $where3 = 'WHERE ' . implode(' AND ', $where3);
788
 
@@ -798,9 +791,9 @@ class SLL_List_Table extends WP_List_Table
798
  if( isset($_GET['datefilter']) && !empty($_GET['datefilter']) ){
799
  $year = substr($_GET['datefilter'], 0, 4);
800
  $month = substr($_GET['datefilter'], -2);
801
- $timestamp = mktime(0, 0, 0, $month, 1, $year);
802
  $date_label = date('F', $timestamp) . ' ' . $year . ' ';
803
- }
804
 
805
  //get args from the URL
806
  $args = wp_parse_args( parse_url($_SERVER["REQUEST_URI"], PHP_URL_QUERY) );
@@ -825,7 +818,7 @@ class SLL_List_Table extends WP_List_Table
825
 
826
  return $views;
827
  }
828
-
829
 
830
  function prepare_items()
831
  {
@@ -833,11 +826,12 @@ class SLL_List_Table extends WP_List_Table
833
 
834
  /**
835
  * First, lets decide how many records per page to show
836
- */
837
- $per_page_option = $screen->id . '_per_page';
838
  $per_page = get_option($per_page_option, 20);
839
-
840
-
 
841
  /**
842
  * REQUIRED. Now we need to define our column headers. This includes a complete
843
  * array of columns to be displayed (slugs & titles), a list of columns
@@ -848,43 +842,43 @@ class SLL_List_Table extends WP_List_Table
848
  $columns = $this->get_columns();
849
  $hidden_cols = get_user_option( 'manage' . $screen->id . 'columnshidden' );
850
  $hidden = ( $hidden_cols ) ? $hidden_cols : array();
851
- $sortable = $this->get_sortable_columns();
852
-
853
-
854
  /**
855
- * REQUIRED. Finally, we build an array to be used by the class for column
856
  * headers. The $this->_column_headers property takes an array which contains
857
  * 3 other arrays. One for all columns, one for hidden columns, and one
858
  * for sortable columns.
859
  */
860
- $this->_column_headers = array($columns, $hidden, $sortable);
861
  $columns = get_column_headers( $screen );
862
-
863
 
864
  /**
865
  * Optional. You can handle your bulk actions however you see fit. In this
866
  * case, we'll handle them within our package just to keep things clean.
867
  */
868
  //$this->process_bulk_action();
869
-
870
-
871
  /**
872
  * Instead of querying a database, we're going to fetch the example data
873
- * property we created for use in this plugin. This makes this example
874
- * package slightly different than one you might build on your own. In
875
- * this example, we'll be using array manipulation to sort and paginate
876
- * our data. In a real-world implementation, you will probably want to
877
  * use sort and pagination data to build a custom query instead, as you'll
878
  * be able to use your precisely-queried data immediately.
879
  */
880
  $data = $this->items;
881
-
882
-
883
  /**
884
  * This checks for sorting input and sorts the data in our array accordingly.
885
- *
886
- * In a real-world situation involving a database, you would probably want
887
- * to handle sorting by passing the 'orderby' and 'order' values directly
888
  * to a custom query. The returned data will be pre-sorted, and this array
889
  * sorting technique would be unnecessary.
890
  */
@@ -895,51 +889,51 @@ class SLL_List_Table extends WP_List_Table
895
  return ($order==='asc') ? $result : -$result; //Send final sort direction to usort
896
  }
897
  usort($data, 'usort_reorder');
898
-
899
-
900
  /***********************************************************************
901
  * ---------------------------------------------------------------------
902
  * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
903
- *
904
  * In a real-world situation, this is where you would place your query.
905
- *
906
  * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
907
  * ---------------------------------------------------------------------
908
  **********************************************************************/
909
-
910
-
911
  /**
912
- * REQUIRED for pagination. Let's figure out what page the user is currently
913
- * looking at. We'll need this later, so you should always include it in
914
  * your own package classes.
915
  */
916
  $current_page = $this->get_pagenum();
917
-
918
  /**
919
- * REQUIRED for pagination. Let's check how many items are in our data array.
920
- * In real-world use, this would be the total number of items in your database,
921
- * without filtering. We'll need this later, so you should always include it
922
  * in your own package classes.
923
  */
924
  $total_items = count($data);
925
-
926
-
927
  /**
928
  * The WP_List_Table class does not handle pagination for us, so we need
929
  * to ensure that the data is trimmed to only the current page. We can use
930
- * array_slice() to
931
  */
932
  $data = array_slice($data,(($current_page-1)*$per_page),$per_page);
933
-
934
-
935
-
936
  /**
937
- * REQUIRED. Now we can add our *sorted* data to the items property, where
938
  * it can be used by the rest of the class.
939
  */
940
  $this->items = $data;
941
-
942
-
943
  /**
944
  * REQUIRED. We also have to register our pagination options & calculations.
945
  */
@@ -950,5 +944,5 @@ class SLL_List_Table extends WP_List_Table
950
  ) );
951
 
952
  }
953
-
954
  }
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.9.3
8
  Author URI: http://SimpleRealtyTheme.com
9
  */
10
 
11
  //TODO: add cleanup method on uninstall
12
 
13
  if( !class_exists( 'SimpleLoginLog' ) )
14
+ {
15
  class SimpleLoginLog {
16
  private $db_ver = "1.2";
17
  public $table = 'simple_login_log';
18
  private $log_duration = null; //days
19
  private $opt_name = 'simple_login_log';
20
  private $opt = false;
21
+ private $login_success = 1;
22
  public $data_labels = array();
23
 
24
+
25
  function __construct()
26
  {
27
  global $wpdb;
31
  //Get plugin's DB version
32
  $this->installed_ver = get_option( "sll_db_ver" );
33
 
34
+ //Check if download was initiated
35
  $download = @esc_attr( $_GET['download-login-log'] );
36
  if($download)
37
  {
38
  $where = ( isset($_GET['where']) ) ? $_GET['where'] : false;
39
  $this->export_to_CSV($where);
40
+ }
41
 
42
 
43
  add_action( 'admin_menu', array(&$this, 'sll_admin_menu') );
46
 
47
  //check if db needs to be upgraded after plugin update was completed
48
  add_action('plugins_loaded', array(&$this, 'update_db_check') );
49
+
50
  //Init login actions
51
+ add_action( 'init', array(&$this, 'init_login_actions') );
52
+
53
  //Style the log table
54
  add_action( 'admin_head', array(&$this, 'admin_header') );
55
 
58
  add_action('truncate_sll', array(&$this, 'cron') );
59
 
60
  //Load Locale
61
+ add_action('plugins_loaded', array(&$this, 'load_locale'), 10 );
62
 
63
  //For translation purposes
64
  $this->data_labels = array(
85
 
86
 
87
  function load_locale()
88
+ {
89
+ load_plugin_textdomain( 'sll', false, basename(dirname(__FILE__)) . '/languages/' );
 
 
 
 
 
90
  }
91
 
92
 
93
  function cron()
94
+ {
95
  SimpleLoginLog::truncate_log();
96
  }
97
 
102
  //execute only on login_log page, othewise return null
103
  $page = ( isset($_GET['page']) ) ? esc_attr($_GET['page']) : false;
104
  if( 'login_log' != $page )
105
+ return;
106
 
107
  $current_screen = get_current_screen();
108
 
114
  if( isset($_REQUEST['wp_screen_options']) && isset($_REQUEST['wp_screen_options']['value']) )
115
  {
116
  update_option( $per_page_option, esc_html($_REQUEST['wp_screen_options']['value']) );
117
+ }
118
 
119
  //prepare options for display
120
 
121
  //if per page option is not set, use default
122
+ $per_page_val = get_option($per_page_option, 20);
123
  $args = array('label' => __('Records', 'sll'), 'default' => $per_page_val );
124
 
125
  //display options
126
+ add_screen_option($per_page_field, $args);
127
+ $_per_page = get_option('users_page_login_log_per_page');
128
 
129
  //needs to be initialized early enough to pre-fill screen options section in the upper (hidden) area.
130
  $this->log_table = new SLL_List_Table;
136
  //condition to check if "log failed attemts" option is selected
137
 
138
  //Action on successfull login
139
+ add_action( 'wp_login', array(&$this, 'login_success') );
140
 
141
+ //Action on failed login
142
+ if( isset($this->opt['failed_attempts']) ){
143
  add_action( 'wp_login_failed', array(&$this, 'login_failed') );
144
  }
145
 
161
 
162
 
163
  function init_scheduled_events()
164
+ {
165
 
166
  $log_duration = get_option('simple_login_log');
167
 
168
+ if ( $log_duration && !wp_next_scheduled( 'truncate_sll' ) )
169
+ {
170
  $start = time();
171
  wp_schedule_event($start, 'daily', 'truncate_sll');
172
  }elseif( !$log_duration || 0 == $log_duration)
173
  {
174
  $timestamp = wp_next_scheduled( 'truncate_sll' );
175
  (!$timestamp) ? false : wp_unschedule_event($timestamp, 'truncate_sll');
176
+
177
  }
178
  }
179
 
183
 
184
  //clean up old cron jobs that no longer exist
185
  wp_clear_scheduled_hook('truncate_log');
186
+ wp_clear_scheduled_hook('SimpleLoginLog::truncate_log');
187
  }
188
 
189
 
193
 
194
  $opt = get_option('simple_login_log');
195
  $log_duration = (int)$opt['log_duration'];
196
+
197
  $table = $wpdb->prefix . 'simple_login_log';
198
 
199
+ if( 0 < $log_duration ){
200
  $sql = $wpdb->prepare( "DELETE FROM {$table} WHERE time < DATE_SUB(CURDATE(),INTERVAL %d DAY)", $log_duration);
201
+ $wpdb->query($sql);
202
  }
203
+
204
  }
205
 
206
 
208
  * Runs via plugin activation hook & creates a database
209
  */
210
  function install()
211
+ {
212
  global $wpdb;
213
 
214
  if( $this->installed_ver != $this->db_ver )
215
  {
216
  //if table does't exist, create a new one
217
  if( !$wpdb->get_row("SHOW TABLES LIKE '{$this->table}'") ){
218
+ $sql = "CREATE TABLE " . $this->table . "
219
  (
220
  id INT( 11 ) NOT NULL AUTO_INCREMENT ,
221
  uid INT( 11 ) NOT NULL ,
222
  user_login VARCHAR( 60 ) NOT NULL ,
223
  user_role VARCHAR( 30 ) NOT NULL ,
224
+ time DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL ,
225
  ip VARCHAR( 100 ) NOT NULL ,
226
  login_result VARCHAR (1) ,
227
  data LONGTEXT NOT NULL ,
235
  update_option( "sll_db_ver", $this->db_ver );
236
  }
237
  }
238
+
239
+
240
  }
241
 
242
+
243
  /**
244
  * Checks if the installed database version is the same as the db version of the current plugin
245
  * calles the version specific function if upgrade is required
266
  */
267
  function db_update_1_1()
268
  {
269
+
270
  /* this version adds a new field "login_result"
271
  * check if this field exists
272
  */
279
  $this->install();
280
  return;
281
  }
282
+
283
  $field_names = array_keys( $fields );
284
+
285
  if( !array_search('login_result', $field_names) )
286
+ {
287
  //add the new field since it doesn't exist
288
  $sql = "ALTER TABLE {$this->table} ADD COLUMN login_result varchar(1) NOT NULL AFTER ip, ADD INDEX (login_result);";
289
  $insert = $wpdb->query( $sql );
290
+
291
  //update version record if it has been updated
292
  if( false !== $insert )
293
  update_option( "sll_db_ver", $this->db_ver );
294
 
295
  }
296
+
297
  }
298
 
299
 
311
  $this->install();
312
  return;
313
  }
314
+
315
  $field_names = array_keys( $fields );
316
+
317
  if( !array_search('user_role', $field_names) )
318
+ {
319
  //add the new field since it doesn't exist
320
  $sql = "ALTER TABLE {$this->table} ADD COLUMN user_role varchar(30) NOT NULL AFTER user_login;";
321
  $insert = $wpdb->query( $sql );
322
+
323
  //update version record if it has been updated
324
  if( false !== $insert )
325
  update_option( "sll_db_ver", $this->db_ver );
326
+
327
  }
328
  }
329
+
330
 
331
  //Initializing Settings
332
  function settings_api_init()
333
  {
334
+ add_settings_section('simple_login_log', __('Simple Login Log', 'sll'), array(&$this, 'sll_settings'), 'general');
335
  add_settings_field('field_log_duration', __('Truncate Log Entries', 'sll'), array(&$this, 'field_log_duration'), 'general', 'simple_login_log');
336
  add_settings_field('field_log_failed_attempts', __('Log Failed Attempts', 'sll'), array(&$this, 'field_log_failed_attempts'), 'general', 'simple_login_log');
337
+ register_setting( 'general', 'simple_login_log' );
338
 
339
  }
340
 
346
 
347
 
348
  function sll_settings()
349
+ {
350
  //content that goes before the fields output
351
  }
352
 
353
 
354
  function field_log_duration()
355
  {
356
+ $duration = (null !== $this->opt['log_duration']) ? $this->opt['log_duration'] : $this->log_duration;
357
+ $output = '<input type="text" value="' . $duration . '" name="simple_login_log[log_duration]" size="10" class="code" /> ' . __('days and older.', 'sll');
358
  echo $output;
359
  echo "<p>" . __("Leave empty or enter 0 if you don't want the log to be truncated.", 'sll') . "</p>";
360
 
361
  //since we're on the General Settings page - update cron schedule if settings has been updated
362
+ if( isset($_REQUEST['settings-updated']) ){
363
+ wp_clear_scheduled_hook('truncate_sll');
364
  //$this->init_scheduled_events();
365
  }
366
  }
377
  {
378
  $page = ( isset($_GET['page']) ) ? esc_attr($_GET['page']) : false;
379
  if( 'login_log' != $page )
380
+ return;
381
 
382
  echo '<style type="text/css">';
383
  echo '.wp-list-table .column-id { width: 5%; }';
395
  //Catch messages on successful login
396
  function login_action($user_login)
397
  {
398
+
399
  $userdata = get_user_by('login', $user_login);
400
 
401
  $uid = ($userdata && $userdata->ID) ? $userdata->ID : 0;
402
+
403
  $data[$this->data_labels['Login']] = ( 1 == $this->login_success ) ? $this->data_labels['Successful'] : $this->data_labels['Failed'];
404
+ if ( isset( $_REQUEST['redirect_to'] ) ) { $data[$this->data_labels['Login Redirect']] = $_REQUEST['redirect_to']; }
405
  $data[$this->data_labels['User Agent']] = $_SERVER['HTTP_USER_AGENT'];
406
+
407
  $serialized_data = serialize($data);
408
 
409
  //get user role
414
  $user_role = implode(', ', $user->roles);
415
  }
416
  }
417
+
418
+
419
  $values = array(
420
  'uid' => $uid,
421
  'user_login' => $user_login,
422
  'user_role' => $user_role,
423
+ 'time' => current_time('mysql'),
424
  'ip' => $_SERVER['REMOTE_ADDR'],
425
  'login_result' => $this->login_success,
426
  'data' => $serialized_data,
427
  );
428
+
429
  $format = array('%d', '%s', '%s', '%s', '%s', '%s', '%s');
430
 
431
  $this->save_data($values, $format);
432
+ }
433
 
434
 
435
  function save_data($values, $format)
442
 
443
  function make_where_query()
444
  {
445
+ $where = false;
446
  if( isset($_GET['filter']) && '' != $_GET['filter'] )
447
  {
448
+ $where['filter'] = "(user_login LIKE '%{$_GET['filter']}%' OR ip LIKE '%{$_GET['filter']}%')";
449
  }
450
  if( isset($_GET['user_role']) && '' != $_GET['user_role'] )
451
  {
470
  {
471
  global $wpdb;
472
 
473
+ $where = '';
 
474
 
475
  $where = $this->make_where_query();
476
 
477
  if( is_array($where) && !empty($where) )
478
  $where = 'WHERE ' . implode(' AND ', $where);
479
 
 
480
  $sql = "SELECT * FROM $this->table $where ORDER BY time DESC";
481
  $data = $wpdb->get_results($sql, 'ARRAY_A');
482
 
485
 
486
 
487
  function log_manager()
488
+ {
489
+
490
  $log_table = $this->log_table;
491
+
492
  $log_table->items = $this->log_get_data();
493
+ $log_table->prepare_items();
494
 
495
  echo '<div class="wrap srp">';
496
  echo '<h2>' . __('Login Log', 'sll') . '</h2>';
497
  echo '<div class="tablenav top">';
498
  echo '<div class="alignleft actions">';
499
  echo $this->date_filter();
500
+ echo '</div>';
501
 
502
  $username = ( isset($_GET['filter']) ) ? esc_attr($_GET['filter']) : false;
503
  echo '<form method="get" class="alignright">';
504
  echo '<p class="search-box">';
505
  echo '<input type="hidden" name="page" value="login_log" />';
506
  echo '<label>' . __('Username:', 'sll') . ' </label><input type="text" name="filter" class="filter-username" value="' . $username . '" /> <input class="button" type="submit" value="' . __('Filter User', 'sll') . '" />';
507
+ echo '<br />';
508
+ echo '</p>';
509
+ echo '</form>';
510
  echo '</div>';
511
  echo '<div class="tablenav top">';
512
 
520
  echo '<div class="alignright actions">';
521
  $mode = ( isset($_GET['mode']) ) ? esc_attr($_GET['mode']) : false;
522
  $log_table->view_switcher($mode);
523
+ echo '</div>';
524
  echo '</div>';
525
+
526
+ $log_table->display();
527
+
528
  echo '<form method="get" id="export-login-log">';
529
  echo '<input type="hidden" name="page" value="login_log" />';
530
  echo '<input type="hidden" name="download-login-log" value="true" />';
531
+ submit_button( __('Export Log to CSV', 'sll'), 'secondary' );
532
+ echo '</form>';
533
  //if filtered results - add export filtered results button
534
  if( $where = $this->make_where_query() ){
535
+
536
  echo '<form method="get" id="export-login-log">';
537
  echo '<input type="hidden" name="page" value="login_log" />';
538
+ echo '<input type="hidden" name="download-login-log" value="true" />';
539
  echo '<input type="hidden" name="where" value="' . esc_attr(serialize($where)) . '" />';
540
  submit_button( __('Export Current Results to CSV', 'sll'), 'secondary' );
541
+ echo '</form>';
542
+
543
  }
544
+
545
+ echo '</div>';
546
  }
547
 
548
 
555
  if(!$results)
556
  return;
557
 
558
+
559
  $option = '';
560
  foreach($results as $row)
561
  {
562
+ //represent month in double digits
563
  $timestamp = mktime(0, 0, 0, $row->month, 1, $row->year);
564
  $month = (strlen($row->month) == 1) ? '0' . $row->month : $row->month;
565
  $datefilter = ( isset($_GET['datefilter']) ) ? $_GET['datefilter'] : false;
578
  function export_to_CSV($where = false){
579
  global $wpdb;
580
 
581
+ //if $where is set, then contemplate WHERE sql query
582
  if( $where ){
583
  $where = unserialize($where);
584
 
587
 
588
  }
589
 
590
+ $sql = "SELECT * FROM {$this->table}{$where}";
591
  $data = $wpdb->get_results($sql, 'ARRAY_A');
592
 
593
  if(!$data)
594
  return;
595
 
596
+ //date string to suffix the file nanme: month - day - year - hour - minute
597
  $suffix = date('n-j-y_H-i');
598
 
599
  // send response headers to the browser
600
  header( 'Content-Type: text/csv' );
601
  header( 'Content-Disposition: attachment;filename=login_log_' . $suffix . '.csv');
602
  $fp = fopen('php://output', 'w');
603
+
604
  $i = 0;
605
  foreach($data as $row){
606
  $tmp = unserialize($row['data']);
614
  fputcsv($fp, $row);
615
  $i++;
616
  }
617
+
618
  fclose($fp);
619
+ die();
620
  }
621
 
622
  }
625
 
626
  if( class_exists( 'SimpleLoginLog' ) )
627
  {
628
+ $sll = new SimpleLoginLog;
629
  //Register for activation
630
+ register_activation_hook( __FILE__, array(&$sll, 'install') );
631
+
632
  }
633
 
634
  if(!class_exists('WP_List_Table'))
637
  }
638
 
639
  class SLL_List_Table extends WP_List_Table
640
+ {
641
  function __construct()
642
  {
643
  global $sll, $_wp_column_headers;
644
+
645
  //Set parent defaults
646
  parent::__construct( array(
647
  'singular' => 'user', //singular name of the listed records
649
  'ajax' => false //does this table support ajax?
650
  ) );
651
 
652
+ $this->data_labels = $sll->data_labels;
653
+
654
+ }
655
 
 
 
656
 
657
  function column_default($item, $column_name)
658
  {
659
  $item = apply_filters('sll-output-data', $item);
660
 
661
  //unset existing filter and pagination
662
+ $args = wp_parse_args( parse_url($_SERVER["REQUEST_URI"], PHP_URL_QUERY) );
663
  unset($args['filter']);
664
+ unset($args['paged']);
665
 
666
  switch($column_name){
667
  case 'id':
668
+ case 'uid':
669
+ case 'time':
670
  case 'ip':
671
  return $item[$column_name];
672
+ case 'user_login':
673
+ return "<a href='" . add_query_arg( array('filter' => $item[$column_name]), menu_page_url('login_log', false) ) . "' title='" . __('Filter log by this name', 'sll') . "'>{$item[$column_name]}</a>";
674
  case 'name';
675
  $user_info = get_userdata($item['uid']);
676
+ return ( is_object($user_info) ) ? $user_info->first_name . " " . $user_info->last_name : false;
677
  case 'login_result':
678
  if ( '' == $item[$column_name]) return '';
679
  return ( '1' == $item[$column_name] ) ? $this->data_labels['Successful'] : '<div class="login-failed">' . $this->data_labels['Failed'] . '</div>';
680
  case 'user_role':
681
  if( !$item['uid'] )
682
  return;
683
+
684
  $user = new WP_User( $item['uid'] );
685
  if ( !empty( $user->roles ) && is_array( $user->roles ) ) {
686
  foreach($user->roles as $role){
690
  }
691
  break;
692
  case 'data':
693
+ $data = unserialize($item[$column_name]);
694
  if(is_array($data))
695
  {
696
  $output = '';
702
  $output = ( isset($_GET['mode']) && 'excerpt' == $_GET['mode'] ) ? $output : substr($output, 0, 50) . '...';
703
 
704
  if( isset($data[$this->data_labels['Login']]) && $data[$this->data_labels['Login']] == $this->data_labels['Failed'] ){
705
+ return '<div class="login-failed">' . $output . '</div>';
706
  }
707
  return $output;
708
+ }
709
+ break;
710
  default:
711
  return $item[$column_name];
712
  }
714
 
715
 
716
  function get_columns()
717
+ {
718
  global $status;
719
  $columns = array(
720
+ 'id' => __('#', 'sll'),
721
+ 'uid' => __('User ID', 'sll'),
722
+ 'user_login' => __('Username', 'sll'),
723
+ 'user_role' => __('User Role', 'sll'),
724
+ 'name' => __('Name', 'sll'),
725
+ 'time' => __('Time', 'sll'),
726
+ 'ip' => __('IP Address', 'sll'),
727
+ 'login_result' => __('Login Result', 'sll'),
728
+ 'data' => __('Data', 'sll'),
729
+ );
730
  return $columns;
731
  }
732
 
748
  {
749
  //creating class="current" variables
750
  if( !isset($_GET['result']) ){
751
+ $all = 'class="current"';
752
+ $success = '';
753
  $failed = '';
754
  }else{
755
  $all = '';
756
  $success = ( '1' == $_GET['result'] ) ? 'class="current"' : '';
757
+ $failed = ( '0' == $_GET['result'] ) ? 'class="current"' : '';
758
+ }
759
 
760
  //get number of successful and failed logins so we can display them in parentheces for each view
761
  global $wpdb, $sll;
768
  }else{
769
  $where = false;
770
  }
771
+
772
  $where3 = $where2 = $where1 = $where;
773
  $where2['login_result'] = "login_result = '1'";
774
  $where3['login_result'] = "login_result = '0'";
775
+
776
  if(is_array($where1) && !empty($where1)){
777
+ $where1 = 'WHERE ' . implode(' AND ', $where1);
778
+ }
779
  $where2 = 'WHERE ' . implode(' AND ', $where2);
780
  $where3 = 'WHERE ' . implode(' AND ', $where3);
781
 
791
  if( isset($_GET['datefilter']) && !empty($_GET['datefilter']) ){
792
  $year = substr($_GET['datefilter'], 0, 4);
793
  $month = substr($_GET['datefilter'], -2);
794
+ $timestamp = mktime(0, 0, 0, $month, 1, $year);
795
  $date_label = date('F', $timestamp) . ' ' . $year . ' ';
796
+ }
797
 
798
  //get args from the URL
799
  $args = wp_parse_args( parse_url($_SERVER["REQUEST_URI"], PHP_URL_QUERY) );
818
 
819
  return $views;
820
  }
821
+
822
 
823
  function prepare_items()
824
  {
826
 
827
  /**
828
  * First, lets decide how many records per page to show
829
+ */
830
+ $per_page_option = $screen->id . '_per_page';
831
  $per_page = get_option($per_page_option, 20);
832
+ $per_page = ($per_page != false) ? $per_page : 20;
833
+
834
+
835
  /**
836
  * REQUIRED. Now we need to define our column headers. This includes a complete
837
  * array of columns to be displayed (slugs & titles), a list of columns
842
  $columns = $this->get_columns();
843
  $hidden_cols = get_user_option( 'manage' . $screen->id . 'columnshidden' );
844
  $hidden = ( $hidden_cols ) ? $hidden_cols : array();
845
+ $sortable = $this->get_sortable_columns();
846
+
847
+
848
  /**
849
+ * REQUIRED. Finally, we build an array to be used by the class for column
850
  * headers. The $this->_column_headers property takes an array which contains
851
  * 3 other arrays. One for all columns, one for hidden columns, and one
852
  * for sortable columns.
853
  */
854
+ $this->_column_headers = array($columns, $hidden, $sortable);
855
  $columns = get_column_headers( $screen );
856
+
857
 
858
  /**
859
  * Optional. You can handle your bulk actions however you see fit. In this
860
  * case, we'll handle them within our package just to keep things clean.
861
  */
862
  //$this->process_bulk_action();
863
+
864
+
865
  /**
866
  * Instead of querying a database, we're going to fetch the example data
867
+ * property we created for use in this plugin. This makes this example
868
+ * package slightly different than one you might build on your own. In
869
+ * this example, we'll be using array manipulation to sort and paginate
870
+ * our data. In a real-world implementation, you will probably want to
871
  * use sort and pagination data to build a custom query instead, as you'll
872
  * be able to use your precisely-queried data immediately.
873
  */
874
  $data = $this->items;
875
+
876
+
877
  /**
878
  * This checks for sorting input and sorts the data in our array accordingly.
879
+ *
880
+ * In a real-world situation involving a database, you would probably want
881
+ * to handle sorting by passing the 'orderby' and 'order' values directly
882
  * to a custom query. The returned data will be pre-sorted, and this array
883
  * sorting technique would be unnecessary.
884
  */
889
  return ($order==='asc') ? $result : -$result; //Send final sort direction to usort
890
  }
891
  usort($data, 'usort_reorder');
892
+
893
+
894
  /***********************************************************************
895
  * ---------------------------------------------------------------------
896
  * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
897
+ *
898
  * In a real-world situation, this is where you would place your query.
899
+ *
900
  * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
901
  * ---------------------------------------------------------------------
902
  **********************************************************************/
903
+
904
+
905
  /**
906
+ * REQUIRED for pagination. Let's figure out what page the user is currently
907
+ * looking at. We'll need this later, so you should always include it in
908
  * your own package classes.
909
  */
910
  $current_page = $this->get_pagenum();
911
+
912
  /**
913
+ * REQUIRED for pagination. Let's check how many items are in our data array.
914
+ * In real-world use, this would be the total number of items in your database,
915
+ * without filtering. We'll need this later, so you should always include it
916
  * in your own package classes.
917
  */
918
  $total_items = count($data);
919
+
920
+
921
  /**
922
  * The WP_List_Table class does not handle pagination for us, so we need
923
  * to ensure that the data is trimmed to only the current page. We can use
924
+ * array_slice() to
925
  */
926
  $data = array_slice($data,(($current_page-1)*$per_page),$per_page);
927
+
928
+
929
+
930
  /**
931
+ * REQUIRED. Now we can add our *sorted* data to the items property, where
932
  * it can be used by the rest of the class.
933
  */
934
  $this->items = $data;
935
+
936
+
937
  /**
938
  * REQUIRED. We also have to register our pagination options & calculations.
939
  */
944
  ) );
945
 
946
  }
947
+
948
  }
uninstall.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( !defined( 'WP_UNINSTALL_PLUGIN' ) )
4
+ exit ();
5
+
6
+ global $wpdb;
7
+ //Delete table
8
+ $sql = "DROP TABLE {$wpdb->prefix}simple_login_log";
9
+ $wpdb->query($sql);
10
+
11
+ //Delete options
12
+ delete_option('sll_db_ver');
13
+ delete_option('simple_login_log');
14
+
15
+ //remove cron jobs
16
+ wp_clear_scheduled_hook('truncate_sll');