Slimstat Analytics - Version 4.7.8

Version Description

  • [Note] A few users have reached out to us to ask if Slimstat would be compliant with the upcoming General Data Protection Regulation (GDPR) guidelines and regulations that are about to be activated all across Europe. Based on our understanding of this new law, as long as the hosting provider where you are storing the information collected by Slimstat is GDPR compliant, then you won't have to worry about any extra layers of compliance offered by software like ours. One of our primary goals is to make sure that you and only you are the sole owner of the data collected by our plugin. This has always been what makes Slimstat stand out from the crowd: while Jetpack, Google Analytics and many other services have full unrestricted access to the data they collect on your website, we at Slimstat don't treat our users as the product that we sell to other companies.
  • [New] Our plugin now honors the Do Not Track header. Please note that this feature can be turned off in the settings, and will be enabled by default.
  • [New] We introduced an experimental option to allow your users to opt out of tracking via a text box displayed at the bottom of your website. Please go to Settings > Filters to customize the behavior and the message to suit your needs and website layout. You can also use third-party solutions to let your visitors opt out, and then configure Slimstat to read the corresponding cookie they set.
  • [New] You can now add reports to the Access Log screen, and customize it just like any other screen in Slimstat.
  • [Update] Reintroduced the interval_minutes filter, which had been temporarily removed from our code as a side effect of our code clean-up process. Thank you, mth75.
  • [Update] Moved the button to reset the report layouts to the Customizer screen.
  • [Update] Deprecated the Geolocation screen. The World Map report has been moved to the Audience tab. If for some reason you cannot find the World Map, please go to Slimstat > Customize and click the Reset All button.
  • [Fix] Filters were not being set when opening the corresponding links in a new window. Thank you, forumaad
  • [Fix] Bug affecting the report "Currently Online".
  • [Fix] Bug affecting all the filter links after the Export to Excel add-on had been enabled.
  • [Fix] Bug affecting the resource filter when "nice permalinks" are not enabled.
Download this release

Release Info

Developer coolmann
Plugin Icon 128x128 Slimstat Analytics
Version 4.7.8
Comparing to
See all releases

Code changes from version 4.7.7 to 4.7.8

admin/config/index.php CHANGED
@@ -107,6 +107,14 @@ $settings = array(
107
  2 => array(
108
  'title' => __( 'Tracker', 'wp-slimstat' ),
109
  'rows' => array(
 
 
 
 
 
 
 
 
110
  'filters_outbound_header' => array( 'description' => __( 'Link Tracking', 'wp-slimstat' ), 'type' => 'section_header' ),
111
  'do_not_track_outbound_classes_rel_href' => array( 'description' => __( 'Do Not Track', 'wp-slimstat' ), 'type' => 'textarea', 'long_description' => __( "Slimstat will ignore links marked with one of these class names, <em>rel</em> attributes or whose <em>href</em> attribute contains one of these strings. Please keep in mind that the class <code>noslimstat</code> is also used to avoid tracking interactive links throughout the reports. If you remove it from this list, some features might not work as expected.", 'wp-slimstat' ) ),
112
  'extensions_to_track' => array( 'description' => __( 'Downloads', 'wp-slimstat' ), 'type' => 'textarea', 'long_description' => __( 'List all the file extensions that you want to be treated as Downloads. Please note that links pointing to external resources (i.e. PDFs on an external website) are considered Downloads and not Outbound Links (and tracked as such), if their extension matches one of the ones listed here below.', 'wp-slimstat' ) ),
@@ -116,7 +124,6 @@ $settings = array(
116
  'geolocation_country' => array( 'description' => __( 'Geolocation Precision', 'wp-slimstat' ), 'type' => 'toggle', 'long_description' => __( "When Slimstat determines your visitors' Country of origin, it uses a third-party data file <a href='https://dev.maxmind.com/geoip/geoip2/geolite2/' target='_blank'>provided by MaxMind</a>. They offer two precision levels: country and city. By default, Slimstat will install the smaller one (country), and you can decide to use the other one, if you don't mind its 60 Mb average size. After you change this option, please <strong>go to the Maintenance tab</strong> and reload (uninstall/install) the MaxMind GeoLite DB by clicking on the corresponding button.", 'wp-slimstat' ), 'custom_label_on' => __( 'Country', 'wp-slimstat' ), 'custom_label_off' => __( 'City', 'wp-slimstat' ) ),
117
  'session_duration' => array('description' => __( 'Session Duration', 'wp-slimstat' ), 'type' => 'integer', 'long_description' => __( 'How many seconds should a human session last? Google Analytics sets it to 1800 seconds.', 'wp-slimstat' ), 'after_input_field' => __( 'seconds', 'wp-slimstat' ) ),
118
  'extend_session' => array( 'description' => __( 'Extend Session', 'wp-slimstat' ), 'type' => 'toggle', 'long_description' => __( 'Extend the duration of a session each time the user visits a new page.', 'wp-slimstat' ) ),
119
- 'set_tracker_cookie' => array( 'description' => __( 'Set Cookie', 'wp-slimstat' ), 'type' => 'toggle', 'long_description' => __( 'Disable this option if, for legal or security reasons, you do not want Slimstat to assign a <a href="https://en.wikipedia.org/wiki/HTTP_cookie" target="_blank">cookie</a> to your visitors. Please note that, by deactivating this feature, Slimstat will not keep track of returning visitors and sessions.', 'wp-slimstat' ) ),
120
  'enable_cdn' => array( 'description' => __( 'Enable CDN', 'wp-slimstat' ), 'type' => 'toggle', 'long_description' => __( "Use <a href='http://www.jsdelivr.com/' target='_blank'>JSDelivr</a>'s CDN, by serving our tracking code from their fast and reliable network (free service).", 'wp-slimstat' ) ),
121
  'ajax_relative_path' => array( 'description' => __( 'Relative Ajax', 'wp-slimstat' ), 'type' => 'toggle', 'long_description' => __( 'If you are experiencing issues related to the header field X-Requested-With not being allowed by Access-Control-Allow-Headers in preflight response (or similar), try enabling this option to make that <code>admin-ajax.php</code> URL relative.', 'wp-slimstat' ) ),
122
 
@@ -143,8 +150,6 @@ $settings = array(
143
  'ignore_spammers' => array( 'description' => __( 'Ignore Spammers', 'wp-slimstat' ), 'type' => 'toggle', 'long_description' => __( "Enable this option if you don't want to track visits from users identified as spammers by third-party tools like Akismet. Pageviews generated by users whose comments are later marked as spam, will also be removed from the database.", 'wp-slimstat' ) ),
144
  'ignore_bots' => array( 'description' => __( 'Ignore Bots', 'wp-slimstat' ), 'type' => 'toggle', 'long_description' => __( "Turn on this feature if you want to have the accuracy level of server-side tracking, but not the inconvenience of getting your database clogged with pageviews generated by crawlers, spiders, search engine bots, etc. Please note that in Client mode, bots are ignored regardless of this setting.", 'wp-slimstat' ) ),
145
  'ignore_prefetch' => array( 'description' => __( 'Ignore Prefetch Requests', 'wp-slimstat' ), 'type' => 'toggle', 'long_description' => __( "Prevent Slimstat from tracking pageviews generated by Firefox's <a href='https://developer.mozilla.org/en/Link_prefetching_FAQ' target='_blank'>Link Prefetching functionality</a>.", 'wp-slimstat' ) ),
146
- 'anonymize_ip' => array( 'description' => __( 'Enable Privacy Mode', 'wp-slimstat' ), 'type' => 'toggle', 'long_description' => __( "Mask your visitors' IP addresses to comply with European Privacy Laws.", 'wp-slimstat' ) ),
147
-
148
  'filters_users_header' => array( 'description' => __( 'User Properties', 'wp-slimstat' ), 'type' => 'section_header' ),
149
  'ignore_users' => array( 'description' => __( 'Usernames', 'wp-slimstat' ), 'type' => 'textarea', 'long_description' => __( "List all the usernames you don't want to track. Please be aware that spaces are <em>not</em> ignored and that usernames are case sensitive. Wildcards: <code>*</code> matches 'any string, including the empty string', <code>!</code> matches 'any character'. For example, <code>user*</code> will match user12 and userfoo, <code>u*100</code> will match user100 and uber100, <code>user!0</code> will match user10 and user90.", 'wp-slimstat' ) ),
150
  'ignore_ip' => array( 'description' => __( 'IP Addresses', 'wp-slimstat' ), 'type' => 'textarea', 'long_description' => __( "List all the IP addresses you don't want to track. Each subnet <strong>must</strong> be defined using the <a href='https://www.iplocation.net/subnet-mask' target='_blank'>CIDR notation</a> (i.e. <em>192.168.0.0/24</em>). This filter applies both to the public IP and the originating IP, if available. Using the CIDR notation, you will use octets to determine the subnet, so for example 54.0.0.0/8 means that the first number is represented by 8 bits, hence 8 after the slash. Then the second number would be another 8 bits, so you would write 54.12.0.0/16 (16 = 8 + 8), and you could do the same for the third number, for example 54.12.34.0/24 (24 = 8 + 8 + 8).", 'wp-slimstat' ) ),
107
  2 => array(
108
  'title' => __( 'Tracker', 'wp-slimstat' ),
109
  'rows' => array(
110
+ 'privacy_header' => array( 'description' => __( 'Privacy and Data Protection', 'wp-slimstat' ), 'type' => 'section_header' ),
111
+ 'anonymize_ip' => array( 'description' => __( 'Enable Privacy Mode', 'wp-slimstat' ), 'type' => 'toggle', 'long_description' => __( "Mask your visitors' IP addresses to comply with European Privacy Laws.", 'wp-slimstat' ) ),
112
+ 'honor_dnt_header' => array( 'description' => __( 'DNT Header', 'wp-slimstat' ), 'type' => 'toggle', 'long_description' => __( "The <a href='https://en.wikipedia.org/wiki/Do_Not_Track' target='_blank'>Do Not Track (DNT)</a> header is the proposed HTTP header field DNT that requests that a web application disable either its tracking or cross-site user tracking (the ambiguity remains unresolved) of an individual user. You can decide to ignore this header and track any pageview regardless of the headers sent by the browser.", 'wp-slimstat' ) ),
113
+ 'set_tracker_cookie' => array( 'description' => __( 'Set Cookie', 'wp-slimstat' ), 'type' => 'toggle', 'long_description' => __( 'Disable this option if, for legal or security reasons, you do not want Slimstat to assign a <a href="https://en.wikipedia.org/wiki/HTTP_cookie" target="_blank">cookie</a> to your visitors. Please note that, by deactivating this feature, Slimstat will not keep track of returning visitors and sessions.', 'wp-slimstat' ) ),
114
+ 'display_opt_out' => array( 'description' => __( 'Allow Opt-out', 'wp-slimstat' ), 'type' => 'toggle', 'long_description' => __( "The European <a href='https://en.wikipedia.org/wiki/General_Data_Protection_Regulation' target='_blank'>General Data Protection Regulation (GDPR)</a> requires website owners to provide a way for their visitors to opt-out of tracking. If enabled, the message here below will be displayed to all users who don't have the corresponding cookie set. A notice will be recorded under Settings > Maintenance every time a pageview is ignored because the corresponding visitor has opted out of tracking.", 'wp-slimstat' ) ),
115
+ 'opt_out_cookie_names' => array( 'description' => __( 'Opt-out Cookie', 'wp-slimstat' ), 'type' => 'textarea', 'long_description' => __( "If you're already using another solution to record and track opt-out choices made by your users, and it sets its own cookie to remember their selection, you can enter the cookie names and values in this field to let Slimstat leverage that information as well. Please use the following format: <code>cookie_name=value</code>, where 'value' is what is used to remember that the user has chosen to <strong>not</strong> be tracked.", 'wp-slimstat' ) ),
116
+ 'opt_out_message' => array( 'description' => __( 'Opt-out Message', 'wp-slimstat' ), 'type' => 'textarea', 'rows' => 4, 'long_description' => __( "In order to provide maximum flexibility to all site owners, we decided to give you full control over the message and its layout, by allowing you to specify the exact HTML markup that should be displayed on your website. Feel free to customize this code to match your website styles and layout. Use the two placeholders <code>{{accept_url}}</code> and <code>{{deny_url}}</code> for the corresponding links, with the following meaning: Accept = allow tracking, Deny = do not allow tracking.", 'wp-slimstat' ), 'use_tag_list' => false ),
117
+
118
  'filters_outbound_header' => array( 'description' => __( 'Link Tracking', 'wp-slimstat' ), 'type' => 'section_header' ),
119
  'do_not_track_outbound_classes_rel_href' => array( 'description' => __( 'Do Not Track', 'wp-slimstat' ), 'type' => 'textarea', 'long_description' => __( "Slimstat will ignore links marked with one of these class names, <em>rel</em> attributes or whose <em>href</em> attribute contains one of these strings. Please keep in mind that the class <code>noslimstat</code> is also used to avoid tracking interactive links throughout the reports. If you remove it from this list, some features might not work as expected.", 'wp-slimstat' ) ),
120
  'extensions_to_track' => array( 'description' => __( 'Downloads', 'wp-slimstat' ), 'type' => 'textarea', 'long_description' => __( 'List all the file extensions that you want to be treated as Downloads. Please note that links pointing to external resources (i.e. PDFs on an external website) are considered Downloads and not Outbound Links (and tracked as such), if their extension matches one of the ones listed here below.', 'wp-slimstat' ) ),
124
  'geolocation_country' => array( 'description' => __( 'Geolocation Precision', 'wp-slimstat' ), 'type' => 'toggle', 'long_description' => __( "When Slimstat determines your visitors' Country of origin, it uses a third-party data file <a href='https://dev.maxmind.com/geoip/geoip2/geolite2/' target='_blank'>provided by MaxMind</a>. They offer two precision levels: country and city. By default, Slimstat will install the smaller one (country), and you can decide to use the other one, if you don't mind its 60 Mb average size. After you change this option, please <strong>go to the Maintenance tab</strong> and reload (uninstall/install) the MaxMind GeoLite DB by clicking on the corresponding button.", 'wp-slimstat' ), 'custom_label_on' => __( 'Country', 'wp-slimstat' ), 'custom_label_off' => __( 'City', 'wp-slimstat' ) ),
125
  'session_duration' => array('description' => __( 'Session Duration', 'wp-slimstat' ), 'type' => 'integer', 'long_description' => __( 'How many seconds should a human session last? Google Analytics sets it to 1800 seconds.', 'wp-slimstat' ), 'after_input_field' => __( 'seconds', 'wp-slimstat' ) ),
126
  'extend_session' => array( 'description' => __( 'Extend Session', 'wp-slimstat' ), 'type' => 'toggle', 'long_description' => __( 'Extend the duration of a session each time the user visits a new page.', 'wp-slimstat' ) ),
 
127
  'enable_cdn' => array( 'description' => __( 'Enable CDN', 'wp-slimstat' ), 'type' => 'toggle', 'long_description' => __( "Use <a href='http://www.jsdelivr.com/' target='_blank'>JSDelivr</a>'s CDN, by serving our tracking code from their fast and reliable network (free service).", 'wp-slimstat' ) ),
128
  'ajax_relative_path' => array( 'description' => __( 'Relative Ajax', 'wp-slimstat' ), 'type' => 'toggle', 'long_description' => __( 'If you are experiencing issues related to the header field X-Requested-With not being allowed by Access-Control-Allow-Headers in preflight response (or similar), try enabling this option to make that <code>admin-ajax.php</code> URL relative.', 'wp-slimstat' ) ),
129
 
150
  'ignore_spammers' => array( 'description' => __( 'Ignore Spammers', 'wp-slimstat' ), 'type' => 'toggle', 'long_description' => __( "Enable this option if you don't want to track visits from users identified as spammers by third-party tools like Akismet. Pageviews generated by users whose comments are later marked as spam, will also be removed from the database.", 'wp-slimstat' ) ),
151
  'ignore_bots' => array( 'description' => __( 'Ignore Bots', 'wp-slimstat' ), 'type' => 'toggle', 'long_description' => __( "Turn on this feature if you want to have the accuracy level of server-side tracking, but not the inconvenience of getting your database clogged with pageviews generated by crawlers, spiders, search engine bots, etc. Please note that in Client mode, bots are ignored regardless of this setting.", 'wp-slimstat' ) ),
152
  'ignore_prefetch' => array( 'description' => __( 'Ignore Prefetch Requests', 'wp-slimstat' ), 'type' => 'toggle', 'long_description' => __( "Prevent Slimstat from tracking pageviews generated by Firefox's <a href='https://developer.mozilla.org/en/Link_prefetching_FAQ' target='_blank'>Link Prefetching functionality</a>.", 'wp-slimstat' ) ),
 
 
153
  'filters_users_header' => array( 'description' => __( 'User Properties', 'wp-slimstat' ), 'type' => 'section_header' ),
154
  'ignore_users' => array( 'description' => __( 'Usernames', 'wp-slimstat' ), 'type' => 'textarea', 'long_description' => __( "List all the usernames you don't want to track. Please be aware that spaces are <em>not</em> ignored and that usernames are case sensitive. Wildcards: <code>*</code> matches 'any string, including the empty string', <code>!</code> matches 'any character'. For example, <code>user*</code> will match user12 and userfoo, <code>u*100</code> will match user100 and uber100, <code>user!0</code> will match user10 and user90.", 'wp-slimstat' ) ),
155
  'ignore_ip' => array( 'description' => __( 'IP Addresses', 'wp-slimstat' ), 'type' => 'textarea', 'long_description' => __( "List all the IP addresses you don't want to track. Each subnet <strong>must</strong> be defined using the <a href='https://www.iplocation.net/subnet-mask' target='_blank'>CIDR notation</a> (i.e. <em>192.168.0.0/24</em>). This filter applies both to the public IP and the originating IP, if available. Using the CIDR notation, you will use octets to determine the subnet, so for example 54.0.0.0/8 means that the first number is represented by 8 bits, hence 8 after the slash. Then the second number would be another 8 bits, so you would write 54.12.0.0/16 (16 = 8 + 8), and you could do the same for the third number, for example 54.12.34.0/24 (24 = 8 + 8 + 8).", 'wp-slimstat' ) ),
admin/config/maintenance.php CHANGED
@@ -1,364 +1,349 @@
1
- <?php
2
- // Avoid direct access to this piece of code
3
- if ( !function_exists( 'add_action' ) || ( !empty( $_POST ) && !check_admin_referer( 'maintenance_wp_slimstat', 'maintenance_wp_slimstat_nonce' ) ) ) {
4
- exit( 0 );
5
- }
6
-
7
- require_once( dirname( dirname( __FILE__ ) ) . '/view/wp-slimstat-reports.php' );
8
- wp_slimstat_reports::init();
9
-
10
- if ( !empty( $_REQUEST[ 'action' ] ) ) {
11
- switch ( $_REQUEST[ 'action' ] ) {
12
- case 'activate-indexes':
13
- wp_slimstat::$wpdb->query( "ALTER TABLE {$GLOBALS['wpdb']->prefix}slim_stats ADD INDEX {$GLOBALS['wpdb']->prefix}stats_resource_idx( resource( 20 ) )" );
14
- wp_slimstat::$wpdb->query( "ALTER TABLE {$GLOBALS['wpdb']->prefix}slim_stats ADD INDEX {$GLOBALS['wpdb']->prefix}stats_browser_idx( browser( 10 ) )" );
15
- wp_slimstat::$wpdb->query( "ALTER TABLE {$GLOBALS['wpdb']->prefix}slim_stats ADD INDEX {$GLOBALS['wpdb']->prefix}stats_searchterms_idx( searchterms( 15 ) )" );
16
- wp_slimstat_admin::show_alert_message( __( 'Congratulations! Slimstat Analytics is now optimized for <a href="http://www.youtube.com/watch?v=ygE01sOhzz0" target="_blank">ludicrous speed</a>.', 'wp-slimstat' ) );
17
- break;
18
-
19
- case 'activate-sql-debug-mode':
20
- wp_slimstat::$settings[ 'show_sql_debug' ] = 'on';
21
- break;
22
-
23
- case 'deactivate-indexes':
24
- wp_slimstat::$wpdb->query("ALTER TABLE {$GLOBALS['wpdb']->prefix}slim_stats DROP INDEX {$GLOBALS['wpdb']->prefix}stats_resource_idx");
25
- wp_slimstat::$wpdb->query("ALTER TABLE {$GLOBALS['wpdb']->prefix}slim_stats DROP INDEX {$GLOBALS['wpdb']->prefix}stats_browser_idx");
26
- wp_slimstat::$wpdb->query("ALTER TABLE {$GLOBALS['wpdb']->prefix}slim_stats DROP INDEX {$GLOBALS['wpdb']->prefix}stats_searchterms_idx");
27
- wp_slimstat_admin::show_alert_message( __( 'Indexing has been disabled. Enjoy the extra database space!', 'wp-slimstat' ) );
28
- break;
29
-
30
- case 'deactivate-sql-debug-mode':
31
- wp_slimstat::$settings[ 'show_sql_debug' ] = 'no';
32
- break;
33
-
34
- case 'delete-records':
35
- $rows_affected = 0;
36
-
37
- if (key_exists($_REQUEST['f'], wp_slimstat_db::$columns_names)){
38
- $rows_affected = wp_slimstat::$wpdb->query("
39
- DELETE t1.*
40
- FROM {$GLOBALS['wpdb']->prefix}slim_stats t1
41
- WHERE ".wp_slimstat_db::get_combined_where('', '*', false));
42
- }
43
- wp_slimstat_admin::show_alert_message( intval( $rows_affected ) . ' ' . __( 'records deleted from your database.', 'wp-slimstat' ) );
44
- break;
45
-
46
- case 'delete-maxmind':
47
- $is_deleted = @unlink( wp_slimstat::$maxmind_path );
48
-
49
- if ( $is_deleted ) {
50
- wp_slimstat_admin::show_alert_message( __( 'The geolocation database has been uninstalled from your server.', 'wp-slimstat' ) );
51
- }
52
- else {
53
- // Some users have reported that a directory is created, instead of a file
54
- $is_deleted = @rmdir( wp_slimstat::$maxmind_path );
55
-
56
- if ( $is_deleted ) {
57
- wp_slimstat_admin::show_alert_message( __( 'The geolocation database has been uninstalled from your server.', 'wp-slimstat' ) );
58
- }
59
- else {
60
- wp_slimstat_admin::show_alert_message( __( "The geolocation database could not be removed from your server. Please check your folder's permissions and try again.", 'wp-slimstat' ) );
61
- }
62
- }
63
- break;
64
-
65
- case 'download-maxmind':
66
- $error = wp_slimstat::download_maxmind_database();
67
-
68
- if (!empty($error)){
69
- wp_slimstat_admin::show_alert_message( $error, 'wp-ui-notification' );
70
- }
71
- else {
72
- wp_slimstat_admin::show_alert_message( __( 'The geolocation database has been installed on your server.', 'wp-slimstat') );
73
- }
74
- break;
75
-
76
- case 'delete-browscap':
77
- // Delete the existing folder, if there
78
- WP_Filesystem();
79
- if ( $GLOBALS[ 'wp_filesystem' ]->rmdir( wp_slimstat::$upload_dir . '/browscap-db/', true ) ) {
80
- wp_slimstat_admin::show_alert_message( __( 'The Browscap data file has been uninstalled from your server.', 'wp-slimstat' ) );
81
- }
82
- else {
83
- wp_slimstat_admin::show_alert_message( __( 'There was an error deleting the Browscap data folder on your server. Please check your permissions.', 'wp-slimstat' ) );
84
- }
85
- break;
86
-
87
- case 'download-browscap':
88
- $error = slim_browser::update_browscap_database( true );
89
-
90
- if ( is_array( $error ) ) {
91
- wp_slimstat_admin::show_alert_message( $error[ 1 ], ( empty( $error[ 0 ] ) ? 'wp-ui-highlight': 'wp-ui-notification' ) );
92
- }
93
- break;
94
-
95
- case 'import-settings':
96
- $new_settings = @json_decode( stripslashes( $_POST[ 'import-slimstat-settings' ] ), true );
97
-
98
- if ( is_array( $new_settings ) && !empty( $new_settings ) ) {
99
- foreach ( $new_settings as $a_setting_name => $a_setting_value ) {
100
- wp_slimstat::$settings[ $a_setting_name ] = $a_setting_value;
101
- }
102
- wp_slimstat_admin::show_alert_message( __( 'Your new Slimstat settings have been imported and installed.', 'wp-slimstat' ) );
103
- }
104
- else {
105
- wp_slimstat_admin::show_alert_message( __( 'There was an error decoding your settings string. Please verify that it is a valid serialized string.', 'wp-slimstat' ) );
106
- }
107
- break;
108
-
109
- case 'reset-tracker-error-status':
110
- wp_slimstat::$settings[ 'last_tracker_error' ] = array();
111
- break;
112
-
113
- case 'reset-tracker-notice-status':
114
- wp_slimstat::$settings[ 'last_tracker_notice' ] = array();
115
- break;
116
-
117
- case 'restore-views':
118
- $GLOBALS['wpdb']->query("DELETE FROM {$GLOBALS['wpdb']->prefix}usermeta WHERE meta_key LIKE '%meta-box-order_admin_page_slimlayout%'");
119
- $GLOBALS['wpdb']->query("DELETE FROM {$GLOBALS['wpdb']->prefix}usermeta WHERE meta_key LIKE '%mmetaboxhidden_admin_page_slimview%'");
120
- $GLOBALS['wpdb']->query("DELETE FROM {$GLOBALS['wpdb']->prefix}usermeta WHERE meta_key LIKE '%meta-box-order_slimstat%'");
121
- $GLOBALS['wpdb']->query("DELETE FROM {$GLOBALS['wpdb']->prefix}usermeta WHERE meta_key LIKE '%metaboxhidden_slimstat%'");
122
- $GLOBALS['wpdb']->query("DELETE FROM {$GLOBALS['wpdb']->prefix}usermeta WHERE meta_key LIKE '%closedpostboxes_slimstat%'");
123
- wp_slimstat_admin::show_alert_message( __( 'Your reports were successfully restored to their default arrangement.', 'wp-slimstat') );
124
- break;
125
-
126
- case 'switch-engine':
127
- $have_innodb = wp_slimstat::$wpdb->get_results("SHOW VARIABLES LIKE 'have_innodb'", ARRAY_A);
128
- if ($have_innodb[0]['Value'] != 'YES') return;
129
-
130
- wp_slimstat::$wpdb->query("ALTER TABLE {$GLOBALS['wpdb']->prefix}slim_stats ENGINE = InnoDB");
131
- wp_slimstat::$wpdb->query("ALTER TABLE {$GLOBALS['wpdb']->prefix}slim_events ENGINE = InnoDB");
132
-
133
- wp_slimstat_admin::show_alert_message( __( 'Your Slimstat tables have been successfully converted to InnoDB.', 'wp-slimstat' ) );
134
- break;
135
-
136
- case 'truncate-archive':
137
- wp_slimstat::$wpdb->query( "DELETE tsa FROM {$GLOBALS[ 'wpdb' ]->prefix}slim_stats_archive tsa" );
138
- wp_slimstat::$wpdb->query( "OPTIMIZE TABLE {$GLOBALS[ 'wpdb' ]->prefix}slim_stats_archive" );
139
- wp_slimstat_admin::show_alert_message( __( 'All the archived records were successfully deleted.', 'wp-slimstat' ) );
140
- break;
141
-
142
- case 'truncate-table':
143
- wp_slimstat::$wpdb->query( "DELETE te FROM {$GLOBALS[ 'wpdb' ]->prefix}slim_events te" );
144
- wp_slimstat::$wpdb->query( "OPTIMIZE TABLE {$GLOBALS[ 'wpdb' ]->prefix}slim_events" );
145
- wp_slimstat::$wpdb->query( "DELETE t1 FROM {$GLOBALS[ 'wpdb' ]->prefix}slim_stats t1" );
146
- wp_slimstat::$wpdb->query( "OPTIMIZE TABLE {$GLOBALS[ 'wpdb' ]->prefix}slim_stats" );
147
- wp_slimstat_admin::show_alert_message( __( 'All the records were successfully deleted.', 'wp-slimstat' ) );
148
- break;
149
-
150
- default:
151
- break;
152
- }
153
- }
154
-
155
- // Retrieve some information about the tables used by Slimstat
156
- $check_index = wp_slimstat::$wpdb->get_results( "SHOW INDEX FROM {$GLOBALS[ 'wpdb' ]->prefix}slim_stats WHERE Key_name = '{$GLOBALS[ 'wpdb' ]->prefix}stats_resource_idx'" );
157
- $details_wp_slim_tables = array_merge(
158
- wp_slimstat::$wpdb->get_results( "SHOW TABLE STATUS LIKE '{$GLOBALS[ 'wpdb' ]->prefix}slim_stats'", ARRAY_A ),
159
- wp_slimstat::$wpdb->get_results( "SHOW TABLE STATUS LIKE '{$GLOBALS[ 'wpdb' ]->prefix}slim_events'", ARRAY_A ),
160
- wp_slimstat::$wpdb->get_results( "SHOW TABLE STATUS LIKE '{$GLOBALS[ 'wpdb' ]->prefix}slim_stats_archive'", ARRAY_A ),
161
- wp_slimstat::$wpdb->get_results( "SHOW TABLE STATUS LIKE '{$GLOBALS[ 'wpdb' ]->prefix}slim_events_archive'", ARRAY_A )
162
- );
163
- $have_innodb = wp_slimstat::$wpdb->get_results("SHOW VARIABLES LIKE 'have_innodb'", ARRAY_A);
164
- $suffixes = array('bytes', 'KB', 'MB', 'GB', 'TB');
165
- $slim_stats_4_exists = wp_slimstat::$wpdb->get_col( "SHOW TABLES LIKE '{$GLOBALS[ 'wpdb' ]->prefix}slim_stats_4'", 0 );
166
- $slim_stats_3_exists = wp_slimstat::$wpdb->get_col( "SHOW TABLES LIKE '{$GLOBALS[ 'wpdb' ]->prefix}slim_stats_3'", 0 );
167
- $slim_browsers_exists =wp_slimstat::$wpdb->get_col( "SHOW TABLES LIKE '{$GLOBALS[ 'wpdb' ]->prefix}slim_browsers'", 0 );
168
- ?>
169
-
170
- <table class="form-table widefat">
171
- <tbody>
172
- <tr>
173
- <td colspan="2" class="slimstat-options-section-header" id="wp-slimstat-troubleshooting"><?php _e('Troubleshooting','wp-slimstat') ?></td>
174
- </tr>
175
- <tr>
176
- <th scope="row"><?php _e( 'Tracker Error', 'wp-slimstat' ) ?></th>
177
- <td>
178
- <?php echo ( !empty( wp_slimstat::$settings[ 'last_tracker_error' ][ 1 ] ) && !empty( wp_slimstat::$settings[ 'last_tracker_error' ][ 2 ] ) ) ? '<strong>[' . date_i18n( wp_slimstat::$settings[ 'date_format' ], wp_slimstat::$settings[ 'last_tracker_error' ][ 2 ], true ) . ' ' . date_i18n( wp_slimstat::$settings[ 'time_format' ], wp_slimstat::$settings[ 'last_tracker_error' ][ 2 ], true ) . '] ' . wp_slimstat::$settings[ 'last_tracker_error' ][ 0 ] . ' ' . wp_slimstat::$settings[ 'last_tracker_error' ][ 1 ] . '</strong><a class="slimstat-font-cancel" title="' . htmlentities( __( 'Reset this error', 'wp-slimstat' ), ENT_QUOTES, 'UTF-8' ) . '" href="' . wp_slimstat_admin::$config_url.$current_tab . '&amp;action=reset-tracker-error-status"></a>' : __( 'So far so good.', 'wp-slimstat' ); ?>
179
- <span class="description"><?php _e( 'The information here above is useful to troubleshoot issues with the tracker. <strong>Errors</strong> are returned when the tracker could not record a page view for some reason, and are indicative of some kind of malfunction. Please include the message here above when sending a <a href="http://support.wp-slimstat.com" target="_blank">support request</a>.', 'wp-slimstat' ) ?></span>
180
- </td>
181
- </tr>
182
- <tr>
183
- <th scope="row"><?php _e( 'Tracker Notice', 'wp-slimstat' ) ?></th>
184
- <td>
185
- <?php echo ( !empty( wp_slimstat::$settings[ 'last_tracker_notice' ][ 1 ] ) && !empty( wp_slimstat::$settings[ 'last_tracker_notice' ][ 2 ] ) ) ? '<strong>[' . date_i18n( wp_slimstat::$settings[ 'date_format' ], wp_slimstat::$settings[ 'last_tracker_notice' ][ 2 ], true ) . ' ' . date_i18n( wp_slimstat::$settings[ 'time_format' ], wp_slimstat::$settings[ 'last_tracker_notice' ][ 2 ], true ) . '] ' . wp_slimstat::$settings[ 'last_tracker_notice' ][ 0 ] . ' ' . wp_slimstat::$settings[ 'last_tracker_notice' ][ 1 ] . '</strong><a class="slimstat-font-cancel" title="' . htmlentities( __( 'Reset this notice', 'wp-slimstat' ), ENT_QUOTES, 'UTF-8' ) . '" href="' . wp_slimstat_admin::$config_url.$current_tab . '&amp;action=reset-tracker-notice-status"></a>' : __( 'So far so good.', 'wp-slimstat' ); ?>
186
- <span class="description"><?php _e( 'The message here above will indicate if a page view was not recorded because it matched at least one of the conditions you configured in your settings (filters, blackslists, etc).', 'wp-slimstat' ) ?></span>
187
- </td>
188
- </tr>
189
- <tr class="alternate">
190
- <?php if ( wp_slimstat::$settings[ 'show_sql_debug' ] != 'on' ): ?>
191
- <th scope="row">
192
- <a class="button-secondary" href="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>&amp;action=activate-sql-debug-mode"><?php _e("Enable SQL Debug",'wp-slimstat'); ?></a>
193
- </th>
194
- <td>
195
- <span class="description"><?php _e("Display the SQL code used to retrieve the data from the database. Useful to troubleshoot issues with data consistency or missing pageviews.",'wp-slimstat') ?></span>
196
- </td>
197
- <?php else: ?>
198
- <th scope="row">
199
- <a class="button-secondary" href="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>&amp;action=deactivate-sql-debug-mode"><?php _e('Disable SQL Debug','wp-slimstat'); ?></a>
200
- </th>
201
- <td>
202
- <span class="description"><?php _e("Deactivate the SQL output on top of each report.",'wp-slimstat') ?></span>
203
- </td>
204
- <?php endif ?>
205
- </tr>
206
- <tr>
207
- <th scope="row"><a class="button-secondary" href="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>&amp;action=restore-views" onclick="return(confirm('<?php _e('Are you sure you want to restore the default arrangement of your reports?','wp-slimstat'); ?>'))"><?php _e('No Panic Button','wp-slimstat'); ?></a></th>
208
- <td>
209
- <span class="description"><?php _e("Reset the default arrangement of your reports. Helpful when, for some reason, reports disappear from your panels or something doesn't look right in your views.",'wp-slimstat') ?></span>
210
- </td>
211
- </tr>
212
- <tr>
213
- <td colspan="2" class="slimstat-options-section-header" id="wp-slimstat-data-maintenance"><?php _e('Data Maintenance','wp-slimstat') ?></td>
214
- </tr>
215
- <tr>
216
- <th scope="row" style="padding-top: 20px"><?php _e('Delete pageviews where','wp-slimstat') ?></th>
217
- <td>
218
- <form action="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>" method="post">
219
- <?php wp_nonce_field( 'maintenance_wp_slimstat', 'maintenance_wp_slimstat_nonce', true, true ); ?>
220
- <input type="hidden" name="action" value="delete-records" />
221
-
222
- <select name="f" id="slimstat-filter-name">
223
- <?php
224
- foreach (wp_slimstat_db::$columns_names as $a_filter_id => $a_filter_info){
225
- echo "<option value='$a_filter_id'>{$a_filter_info[0]}</option>";
226
- }
227
- ?>
228
- </select>
229
- <select name="o" id="slimstat-filter-operator">
230
- <option value="equals"><?php _e('equals','wp-slimstat') ?></option>
231
- <option value="is_not_equal_to"><?php _e('is not equal to','wp-slimstat') ?></option>
232
- <option value="contains"><?php _e('contains','wp-slimstat') ?></option>
233
- <option value="includes_in_set"><?php _e('is included in','wp-slimstat') ?></option>
234
- <option value="does_not_contain"><?php _e('does not contain','wp-slimstat') ?></option>
235
- <option value="starts_with"><?php _e('starts with','wp-slimstat') ?></option>
236
- <option value="ends_with"><?php _e('ends with','wp-slimstat') ?></option>
237
- <option value="sounds_like"><?php _e('sounds like','wp-slimstat') ?></option>
238
- <option value="is_greater_than"><?php _e('is greater than','wp-slimstat') ?></option>
239
- <option value="is_less_than"><?php _e('is less than','wp-slimstat') ?></option>
240
- <option value="matches"><?php _e('matches','wp-slimstat') ?></option>
241
- <option value="does_not_match"><?php _e('does not match','wp-slimstat') ?></option>
242
- <option value="is_empty"><?php _e('is empty','wp-slimstat') ?></option>
243
- <option value="is_not_empty"><?php _e('is not empty','wp-slimstat') ?></option>
244
- </select>
245
- <input type="text" name="v" id="slimstat-filter-value" value="" size="20">
246
- <input type="submit" value="<?php _e('Apply','wp-slimstat') ?>" class="button-secondary" name="Submit"
247
- onclick="return(confirm('<?php _e('Are you sure you want to PERMANENTLY delete these records from your database?','wp-slimstat'); ?>'))" />
248
- </form>
249
- </td>
250
- </tr>
251
- <tr class="alternate">
252
- <th scope="row">
253
- <a class="button-secondary" href="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>&amp;action=truncate-table"
254
- onclick="return(confirm('<?php _e('Are you sure you want to PERMANENTLY DELETE ALL the records from your database?','wp-slimstat'); ?>'))"><?php _e('Delete All Records','wp-slimstat'); ?></a>
255
- </th>
256
- <td>
257
- <span class="description"><?php _e('Erase all the information collected so far by Slimstat, but not the archived records (<code>wp_slim_stats_archive</code>). This operation <strong>does not</strong> reset your settings and it can be undone by manually copying your records from the archive table.','wp-slimstat') ?></span>
258
- </td>
259
- </tr>
260
- <tr >
261
- <th scope="row">
262
- <a class="button-secondary" href="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>&amp;action=truncate-archive"
263
- onclick="return(confirm('<?php _e('Are you sure you want to PERMANENTLY DELETE ALL the records from your archive?','wp-slimstat'); ?>'))"><?php _e('Delete Archive','wp-slimstat'); ?></a>
264
- </th>
265
- <td>
266
- <span class="description"><?php _e("Erase all the archived records. This operation cannot be undone.",'wp-slimstat') ?></span>
267
- </td>
268
- </tr>
269
- <tr class="alternate">
270
- <?php if (empty($check_index)): ?>
271
- <th scope="row">
272
- <a class="button-secondary" href="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>&amp;action=activate-indexes"><?php _e("Improve Performance",'wp-slimstat'); ?></a>
273
- </th>
274
- <td>
275
-
276
- <span class="description"><?php _e("Please note that you will need about 30% more DB space to store the extra information required.",'wp-slimstat') ?></span>
277
- </td>
278
- <?php else: ?>
279
- <th scope="row">
280
- <a class="button-secondary" href="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>&amp;action=deactivate-indexes"><?php _e('Save DB Space','wp-slimstat'); ?></a>
281
- </th>
282
- <td>
283
- <span class="description"><?php _e("Please note that by removing table indexes, Slimstat's performance will be affected.",'wp-slimstat') ?></span>
284
- </td>
285
- <?php endif ?>
286
- </tr>
287
- <tr>
288
- <td colspan="2" class="slimstat-options-section-header" id="wp-slimstat-external-data-files"><?php _e('External Data Files','wp-slimstat') ?></td>
289
- </tr>
290
- <tr>
291
- <th scope="row">
292
- <?php if (!file_exists(wp_slimstat::$maxmind_path)): ?>
293
- <a class="button-secondary" href="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>&amp;action=download-maxmind"
294
- onclick="return(confirm('<?php _e('Do you want to download and install the geolocation database from MaxMind\'s server?','wp-slimstat'); ?>'))"><?php _e("Install GeoLite DB",'wp-slimstat'); ?></a>
295
- <?php else: ?>
296
- <a class="button-secondary" href="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>&amp;action=delete-maxmind"
297
- onclick="return(confirm('<?php _e('Do you want to uninstall the geolocation database?','wp-slimstat'); ?>'))"><?php _e("Uninstall GeoLite DB",'wp-slimstat'); ?></a>
298
- <?php endif; ?>
299
- </th>
300
- <td>
301
- <span class="description"><?php _e("The <a href='https://dev.maxmind.com/geoip/geoip2/geolite2/' target='_blank'>MaxMind GeoLite2 library</a>, which Slimstat uses to geolocate visitors, is released under the Creative Commons BY-SA 3.0 license, and cannot be directly bundled with the plugin because of license incompatibility issues. We are mandated to have the user take an affirmative action in order to enable this functionality. If you're experiencing issues, please <a href='https://slimstat.freshdesk.com/solution/articles/12000039798-how-to-manually-install-the-maxmind-geolocation-data-file-' target='_blank'>take a look at our knowledge base</a> to learn how to install this file manually.", 'wp-slimstat' ) ?></span>
302
- </td>
303
- </tr>
304
- <tr class="alternate">
305
- <th scope="row">
306
- <?php if ( !file_exists( slim_browser::$browscap_autoload_path ) ) : ?>
307
- <a class="button-secondary" href="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>&amp;action=download-browscap"
308
- onclick="return( confirm( '<?php _e( 'Do you want to download and install the Browscap data file from our server?', 'wp-slimstat' ); ?>' ) )"><?php _e( 'Install Browscap', 'wp-slimstat' ); ?></a>
309
- <?php else: ?>
310
- <a class="button-secondary" href="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>&amp;action=delete-browscap"
311
- onclick="return( confirm( '<?php _e( 'Do you want to uninstall the Browscap data file?', 'wp-slimstat' ); ?>' ) )"><?php _e( 'Uninstall Browscap', 'wp-slimstat' ); ?></a>
312
- <?php endif; ?>
313
- </th>
314
- <td>
315
- <span class="description"><?php _e( "We are contributing to the <a href='http://browscap.org/' target='_blank'>Browscap Capabilities Project</a>, which we use to decode your visitors' user agent string into browser name and operating system. We use an optimized version of their data structure, for improved performance. After you enable this feature, Slimstat will use this data file instead of the built-in heuristic function, to accurately determine your visitors' browser information. It will also automatically check for updates and download the latest version for you. Please feel free to <a href='http://s3.amazonaws.com/browscap/terms-conditions.html' target='_blank'>review our terms and conditions</a>, and do not hesitate to <a href='http://support.wp-slimstat.com' target='_blank'>contact our support team</a> if you have any questions.", 'wp-slimstat' ) ?></span>
316
- </td>
317
- </tr>
318
- <tr>
319
- <td colspan="2" class="slimstat-options-section-header" id="wp-slimstat-configuration-string"><?php _e('Configuration String','wp-slimstat') ?></td>
320
- </tr>
321
- <tr>
322
- <td colspan="2">
323
- <strong><?php _e("Here below you can find the current configuration string for Slimstat. You can update your settings by pasting a new string inside the text area and clicking the Import button.",'wp-slimstat') ?></strong>
324
- <form action="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>" method="post">
325
- <?php wp_nonce_field( 'maintenance_wp_slimstat', 'maintenance_wp_slimstat_nonce', true, true ) ?>
326
- <input type="hidden" name="action" value="import-settings" />
327
- <textarea name="import-slimstat-settings" style="width:100%" rows="10"><?php echo json_encode( wp_slimstat::$settings ) ?></textarea><br/>
328
- <input type="submit" value="<?php _e('Import','wp-slimstat') ?>" class="button-secondary"
329
- onclick="return(confirm('<?php _e('Are you sure you want to OVERWRITE your current settings?','wp-slimstat'); ?>'))">
330
- </form>
331
- </td>
332
- </tr>
333
- <tr>
334
- <td colspan="2" class="slimstat-options-section-header" id="wp-slimstat-database-information"><?php _e('Database Information','wp-slimstat') ?></td>
335
- </tr>
336
- <tr>
337
- <th scope="row"><?php _e('Engine','wp-slimstat') ?></th>
338
- <td><?php
339
- echo $details_wp_slim_tables[0]['Engine'];
340
- if (!empty($have_innodb) && $have_innodb[0]['Value'] == 'YES' && $details_wp_slim_tables[0]['Engine'] == 'MyISAM'){
341
- echo ' [<a class="noslimstat" href="'.wp_slimstat_admin::$config_url.$current_tab.'&amp;action=switch-engine">'.__('switch to InnoDB','wp-slimstat').'</a>]';
342
- }
343
- ?></td>
344
- </tr>
345
- <?php
346
- foreach ($details_wp_slim_tables as $i => $a_table){
347
- $base = ($a_table['Data_length'] != 0)?(log($a_table['Data_length']) / log(1024)):0;
348
- $a_table['Data_length_with_suffix'] = round(pow(1024, $base - floor($base)), 2).' '.$suffixes[floor($base)];
349
-
350
- echo '<tr '.(($i%2==0)?'class="alternate"':'').">
351
- <th scope='row'>{$a_table['Name']}</th>
352
- <td>".$a_table['Data_length_with_suffix'].' ('.number_format($a_table['Rows'], 0).' '.__('records','wp-slimstat').')</td>
353
- </tr>';
354
- }
355
- $i++;
356
- if ( !empty( $slim_stats_4_exists ) || !empty( $slim_stats_3_exists ) || !empty( $slim_browsers_exists ) ):
357
- ?>
358
- <tr<?php echo (($i%2==0)?' class="alternate"':'') ?>>
359
- <th scope="row"><?php _e( 'Old Tables', 'wp-slimstat' ) ?></th>
360
- <td><?php printf( __( 'It looks like your database was upgraded from a version prior to 4.0. Our upgrade procedure follows a conservative approach, and does not automatically perform any garbage collection. In other words, the old tables, leftovers of the upgrade, are not deleted from the database. This allows our users to easily roll back to a working state in case of problems. However, if everything is working as expected (tracker and reports), you may want to log into phpMyAdmin and remove the following tables, if they exist: %s. When in doubt, do not hesitate to contact us for help.', 'wp-slimstat' ), "<code>{$GLOBALS['wpdb']->prefix}slim_browsers</code>, <code>{$GLOBALS['wpdb']->prefix}slim_content_info</code>, <code>{$GLOBALS['wpdb']->prefix}slim_outbound</code>, <code>{$GLOBALS['wpdb']->prefix}slim_screenres</code>, <code>{$GLOBALS['wpdb']->prefix}slim_stats_3</code>, <code>{$GLOBALS['wpdb']->prefix}slim_stats_4</code>, <code>{$GLOBALS['wpdb']->prefix}slim_stats_archive_3</code>, <code>{$GLOBALS['wpdb']->prefix}slim_stats_archive_4</code>" ) ?></td>
361
- </tr>
362
- <?php endif; ?>
363
- </tbody>
364
  </table>
1
+ <?php
2
+ // Avoid direct access to this piece of code
3
+ if ( !function_exists( 'add_action' ) || ( !empty( $_POST ) && !check_admin_referer( 'maintenance_wp_slimstat', 'maintenance_wp_slimstat_nonce' ) ) ) {
4
+ exit( 0 );
5
+ }
6
+
7
+ require_once( dirname( dirname( __FILE__ ) ) . '/view/wp-slimstat-reports.php' );
8
+ wp_slimstat_reports::init();
9
+
10
+ if ( !empty( $_REQUEST[ 'action' ] ) ) {
11
+ switch ( $_REQUEST[ 'action' ] ) {
12
+ case 'activate-indexes':
13
+ wp_slimstat::$wpdb->query( "ALTER TABLE {$GLOBALS['wpdb']->prefix}slim_stats ADD INDEX {$GLOBALS['wpdb']->prefix}stats_resource_idx( resource( 20 ) )" );
14
+ wp_slimstat::$wpdb->query( "ALTER TABLE {$GLOBALS['wpdb']->prefix}slim_stats ADD INDEX {$GLOBALS['wpdb']->prefix}stats_browser_idx( browser( 10 ) )" );
15
+ wp_slimstat::$wpdb->query( "ALTER TABLE {$GLOBALS['wpdb']->prefix}slim_stats ADD INDEX {$GLOBALS['wpdb']->prefix}stats_searchterms_idx( searchterms( 15 ) )" );
16
+ wp_slimstat_admin::show_alert_message( __( 'Congratulations! Slimstat Analytics is now optimized for <a href="http://www.youtube.com/watch?v=ygE01sOhzz0" target="_blank">ludicrous speed</a>.', 'wp-slimstat' ) );
17
+ break;
18
+
19
+ case 'activate-sql-debug-mode':
20
+ wp_slimstat::$settings[ 'show_sql_debug' ] = 'on';
21
+ break;
22
+
23
+ case 'deactivate-indexes':
24
+ wp_slimstat::$wpdb->query("ALTER TABLE {$GLOBALS['wpdb']->prefix}slim_stats DROP INDEX {$GLOBALS['wpdb']->prefix}stats_resource_idx");
25
+ wp_slimstat::$wpdb->query("ALTER TABLE {$GLOBALS['wpdb']->prefix}slim_stats DROP INDEX {$GLOBALS['wpdb']->prefix}stats_browser_idx");
26
+ wp_slimstat::$wpdb->query("ALTER TABLE {$GLOBALS['wpdb']->prefix}slim_stats DROP INDEX {$GLOBALS['wpdb']->prefix}stats_searchterms_idx");
27
+ wp_slimstat_admin::show_alert_message( __( 'Indexing has been disabled. Enjoy the extra database space!', 'wp-slimstat' ) );
28
+ break;
29
+
30
+ case 'deactivate-sql-debug-mode':
31
+ wp_slimstat::$settings[ 'show_sql_debug' ] = 'no';
32
+ break;
33
+
34
+ case 'delete-records':
35
+ $rows_affected = 0;
36
+
37
+ if (key_exists($_REQUEST['f'], wp_slimstat_db::$columns_names)){
38
+ $rows_affected = wp_slimstat::$wpdb->query("
39
+ DELETE t1.*
40
+ FROM {$GLOBALS['wpdb']->prefix}slim_stats t1
41
+ WHERE ".wp_slimstat_db::get_combined_where('', '*', false));
42
+ }
43
+ wp_slimstat_admin::show_alert_message( intval( $rows_affected ) . ' ' . __( 'records deleted from your database.', 'wp-slimstat' ) );
44
+ break;
45
+
46
+ case 'delete-maxmind':
47
+ $is_deleted = @unlink( wp_slimstat::$maxmind_path );
48
+
49
+ if ( $is_deleted ) {
50
+ wp_slimstat_admin::show_alert_message( __( 'The geolocation database has been uninstalled from your server.', 'wp-slimstat' ) );
51
+ }
52
+ else {
53
+ // Some users have reported that a directory is created, instead of a file
54
+ $is_deleted = @rmdir( wp_slimstat::$maxmind_path );
55
+
56
+ if ( $is_deleted ) {
57
+ wp_slimstat_admin::show_alert_message( __( 'The geolocation database has been uninstalled from your server.', 'wp-slimstat' ) );
58
+ }
59
+ else {
60
+ wp_slimstat_admin::show_alert_message( __( "The geolocation database could not be removed from your server. Please check your folder's permissions and try again.", 'wp-slimstat' ) );
61
+ }
62
+ }
63
+ break;
64
+
65
+ case 'download-maxmind':
66
+ $error = wp_slimstat::download_maxmind_database();
67
+
68
+ if (!empty($error)){
69
+ wp_slimstat_admin::show_alert_message( $error, 'wp-ui-notification' );
70
+ }
71
+ else {
72
+ wp_slimstat_admin::show_alert_message( __( 'The geolocation database has been installed on your server.', 'wp-slimstat') );
73
+ }
74
+ break;
75
+
76
+ case 'delete-browscap':
77
+ // Delete the existing folder, if there
78
+ WP_Filesystem();
79
+ if ( $GLOBALS[ 'wp_filesystem' ]->rmdir( wp_slimstat::$upload_dir . '/browscap-db/', true ) ) {
80
+ wp_slimstat_admin::show_alert_message( __( 'The Browscap data file has been uninstalled from your server.', 'wp-slimstat' ) );
81
+ }
82
+ else {
83
+ wp_slimstat_admin::show_alert_message( __( 'There was an error deleting the Browscap data folder on your server. Please check your permissions.', 'wp-slimstat' ) );
84
+ }
85
+ break;
86
+
87
+ case 'download-browscap':
88
+ $error = slim_browser::update_browscap_database( true );
89
+
90
+ if ( is_array( $error ) ) {
91
+ wp_slimstat_admin::show_alert_message( $error[ 1 ], ( empty( $error[ 0 ] ) ? 'wp-ui-highlight': 'wp-ui-notification' ) );
92
+ }
93
+ break;
94
+
95
+ case 'import-settings':
96
+ $new_settings = @json_decode( stripslashes( $_POST[ 'import-slimstat-settings' ] ), true );
97
+
98
+ if ( is_array( $new_settings ) && !empty( $new_settings ) ) {
99
+ foreach ( $new_settings as $a_setting_name => $a_setting_value ) {
100
+ wp_slimstat::$settings[ $a_setting_name ] = $a_setting_value;
101
+ }
102
+ wp_slimstat_admin::show_alert_message( __( 'Your new Slimstat settings have been imported and installed.', 'wp-slimstat' ) );
103
+ }
104
+ else {
105
+ wp_slimstat_admin::show_alert_message( __( 'There was an error decoding your settings string. Please verify that it is a valid serialized string.', 'wp-slimstat' ) );
106
+ }
107
+ break;
108
+
109
+ case 'reset-tracker-error-status':
110
+ wp_slimstat::$settings[ 'last_tracker_error' ] = array();
111
+ break;
112
+
113
+ case 'reset-tracker-notice-status':
114
+ wp_slimstat::$settings[ 'last_tracker_notice' ] = array();
115
+ break;
116
+
117
+ case 'switch-engine':
118
+ $have_innodb = wp_slimstat::$wpdb->get_results("SHOW VARIABLES LIKE 'have_innodb'", ARRAY_A);
119
+ if ($have_innodb[0]['Value'] != 'YES') return;
120
+
121
+ wp_slimstat::$wpdb->query("ALTER TABLE {$GLOBALS['wpdb']->prefix}slim_stats ENGINE = InnoDB");
122
+ wp_slimstat::$wpdb->query("ALTER TABLE {$GLOBALS['wpdb']->prefix}slim_events ENGINE = InnoDB");
123
+
124
+ wp_slimstat_admin::show_alert_message( __( 'Your Slimstat tables have been successfully converted to InnoDB.', 'wp-slimstat' ) );
125
+ break;
126
+
127
+ case 'truncate-archive':
128
+ wp_slimstat::$wpdb->query( "DELETE tsa FROM {$GLOBALS[ 'wpdb' ]->prefix}slim_stats_archive tsa" );
129
+ wp_slimstat::$wpdb->query( "OPTIMIZE TABLE {$GLOBALS[ 'wpdb' ]->prefix}slim_stats_archive" );
130
+ wp_slimstat_admin::show_alert_message( __( 'All the archived records were successfully deleted.', 'wp-slimstat' ) );
131
+ break;
132
+
133
+ case 'truncate-table':
134
+ wp_slimstat::$wpdb->query( "DELETE te FROM {$GLOBALS[ 'wpdb' ]->prefix}slim_events te" );
135
+ wp_slimstat::$wpdb->query( "OPTIMIZE TABLE {$GLOBALS[ 'wpdb' ]->prefix}slim_events" );
136
+ wp_slimstat::$wpdb->query( "DELETE t1 FROM {$GLOBALS[ 'wpdb' ]->prefix}slim_stats t1" );
137
+ wp_slimstat::$wpdb->query( "OPTIMIZE TABLE {$GLOBALS[ 'wpdb' ]->prefix}slim_stats" );
138
+ wp_slimstat_admin::show_alert_message( __( 'All the records were successfully deleted.', 'wp-slimstat' ) );
139
+ break;
140
+
141
+ default:
142
+ break;
143
+ }
144
+ }
145
+
146
+ // Retrieve some information about the tables used by Slimstat
147
+ $check_index = wp_slimstat::$wpdb->get_results( "SHOW INDEX FROM {$GLOBALS[ 'wpdb' ]->prefix}slim_stats WHERE Key_name = '{$GLOBALS[ 'wpdb' ]->prefix}stats_resource_idx'" );
148
+ $details_wp_slim_tables = array_merge(
149
+ wp_slimstat::$wpdb->get_results( "SHOW TABLE STATUS LIKE '{$GLOBALS[ 'wpdb' ]->prefix}slim_stats'", ARRAY_A ),
150
+ wp_slimstat::$wpdb->get_results( "SHOW TABLE STATUS LIKE '{$GLOBALS[ 'wpdb' ]->prefix}slim_events'", ARRAY_A ),
151
+ wp_slimstat::$wpdb->get_results( "SHOW TABLE STATUS LIKE '{$GLOBALS[ 'wpdb' ]->prefix}slim_stats_archive'", ARRAY_A ),
152
+ wp_slimstat::$wpdb->get_results( "SHOW TABLE STATUS LIKE '{$GLOBALS[ 'wpdb' ]->prefix}slim_events_archive'", ARRAY_A )
153
+ );
154
+ $have_innodb = wp_slimstat::$wpdb->get_results("SHOW VARIABLES LIKE 'have_innodb'", ARRAY_A);
155
+ $suffixes = array('bytes', 'KB', 'MB', 'GB', 'TB');
156
+ $slim_stats_4_exists = wp_slimstat::$wpdb->get_col( "SHOW TABLES LIKE '{$GLOBALS[ 'wpdb' ]->prefix}slim_stats_4'", 0 );
157
+ $slim_stats_3_exists = wp_slimstat::$wpdb->get_col( "SHOW TABLES LIKE '{$GLOBALS[ 'wpdb' ]->prefix}slim_stats_3'", 0 );
158
+ $slim_browsers_exists =wp_slimstat::$wpdb->get_col( "SHOW TABLES LIKE '{$GLOBALS[ 'wpdb' ]->prefix}slim_browsers'", 0 );
159
+ ?>
160
+
161
+ <table class="form-table widefat">
162
+ <tbody>
163
+ <tr>
164
+ <td colspan="2" class="slimstat-options-section-header" id="wp-slimstat-troubleshooting"><?php _e('Troubleshooting','wp-slimstat') ?></td>
165
+ </tr>
166
+ <tr>
167
+ <th scope="row"><?php _e( 'Tracker Error', 'wp-slimstat' ) ?></th>
168
+ <td>
169
+ <?php echo ( !empty( wp_slimstat::$settings[ 'last_tracker_error' ][ 1 ] ) && !empty( wp_slimstat::$settings[ 'last_tracker_error' ][ 2 ] ) ) ? '<strong>[' . date_i18n( wp_slimstat::$settings[ 'date_format' ], wp_slimstat::$settings[ 'last_tracker_error' ][ 2 ], true ) . ' ' . date_i18n( wp_slimstat::$settings[ 'time_format' ], wp_slimstat::$settings[ 'last_tracker_error' ][ 2 ], true ) . '] ' . wp_slimstat::$settings[ 'last_tracker_error' ][ 0 ] . ' ' . wp_slimstat::$settings[ 'last_tracker_error' ][ 1 ] . '</strong><a class="slimstat-font-cancel" title="' . htmlentities( __( 'Reset this error', 'wp-slimstat' ), ENT_QUOTES, 'UTF-8' ) . '" href="' . wp_slimstat_admin::$config_url.$current_tab . '&amp;action=reset-tracker-error-status"></a>' : __( 'So far so good.', 'wp-slimstat' ); ?>
170
+ <span class="description"><?php _e( 'The information here above is useful to troubleshoot issues with the tracker. <strong>Errors</strong> are returned when the tracker could not record a page view for some reason, and are indicative of some kind of malfunction. Please include the message here above when sending a <a href="http://support.wp-slimstat.com" target="_blank">support request</a>.', 'wp-slimstat' ) ?></span>
171
+ </td>
172
+ </tr>
173
+ <tr>
174
+ <th scope="row"><?php _e( 'Tracker Notice', 'wp-slimstat' ) ?></th>
175
+ <td>
176
+ <?php echo ( !empty( wp_slimstat::$settings[ 'last_tracker_notice' ][ 1 ] ) && !empty( wp_slimstat::$settings[ 'last_tracker_notice' ][ 2 ] ) ) ? '<strong>[' . date_i18n( wp_slimstat::$settings[ 'date_format' ], wp_slimstat::$settings[ 'last_tracker_notice' ][ 2 ], true ) . ' ' . date_i18n( wp_slimstat::$settings[ 'time_format' ], wp_slimstat::$settings[ 'last_tracker_notice' ][ 2 ], true ) . '] ' . wp_slimstat::$settings[ 'last_tracker_notice' ][ 0 ] . ' ' . wp_slimstat::$settings[ 'last_tracker_notice' ][ 1 ] . '</strong><a class="slimstat-font-cancel" title="' . htmlentities( __( 'Reset this notice', 'wp-slimstat' ), ENT_QUOTES, 'UTF-8' ) . '" href="' . wp_slimstat_admin::$config_url.$current_tab . '&amp;action=reset-tracker-notice-status"></a>' : __( 'So far so good.', 'wp-slimstat' ); ?>
177
+ <span class="description"><?php _e( 'The message here above will indicate if a page view was not recorded because it matched at least one of the conditions you configured in your settings (filters, blackslists, etc).', 'wp-slimstat' ) ?></span>
178
+ </td>
179
+ </tr>
180
+ <tr>
181
+ <?php if ( wp_slimstat::$settings[ 'show_sql_debug' ] != 'on' ): ?>
182
+ <th scope="row">
183
+ <a class="button-secondary" href="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>&amp;action=activate-sql-debug-mode"><?php _e("Enable SQL Debug",'wp-slimstat'); ?></a>
184
+ </th>
185
+ <td>
186
+ <span class="description"><?php _e("Display the SQL code used to retrieve the data from the database. Useful to troubleshoot issues with data consistency or missing pageviews.",'wp-slimstat') ?></span>
187
+ </td>
188
+ <?php else: ?>
189
+ <th scope="row">
190
+ <a class="button-secondary" href="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>&amp;action=deactivate-sql-debug-mode"><?php _e('Disable SQL Debug','wp-slimstat'); ?></a>
191
+ </th>
192
+ <td>
193
+ <span class="description"><?php _e("Deactivate the SQL output on top of each report.",'wp-slimstat') ?></span>
194
+ </td>
195
+ <?php endif ?>
196
+ </tr>
197
+ <tr>
198
+ <td colspan="2" class="slimstat-options-section-header" id="wp-slimstat-data-maintenance"><?php _e('Data Maintenance','wp-slimstat') ?></td>
199
+ </tr>
200
+ <tr>
201
+ <th scope="row" style="padding-top: 20px"><?php _e('Delete pageviews where','wp-slimstat') ?></th>
202
+ <td>
203
+ <form action="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>" method="post">
204
+ <?php wp_nonce_field( 'maintenance_wp_slimstat', 'maintenance_wp_slimstat_nonce', true, true ); ?>
205
+ <input type="hidden" name="action" value="delete-records" />
206
+
207
+ <select name="f" id="slimstat-filter-name">
208
+ <?php
209
+ foreach (wp_slimstat_db::$columns_names as $a_filter_id => $a_filter_info){
210
+ echo "<option value='$a_filter_id'>{$a_filter_info[0]}</option>";
211
+ }
212
+ ?>
213
+ </select>
214
+ <select name="o" id="slimstat-filter-operator">
215
+ <option value="equals"><?php _e('equals','wp-slimstat') ?></option>
216
+ <option value="is_not_equal_to"><?php _e('is not equal to','wp-slimstat') ?></option>
217
+ <option value="contains"><?php _e('contains','wp-slimstat') ?></option>
218
+ <option value="includes_in_set"><?php _e('is included in','wp-slimstat') ?></option>
219
+ <option value="does_not_contain"><?php _e('does not contain','wp-slimstat') ?></option>
220
+ <option value="starts_with"><?php _e('starts with','wp-slimstat') ?></option>
221
+ <option value="ends_with"><?php _e('ends with','wp-slimstat') ?></option>
222
+ <option value="sounds_like"><?php _e('sounds like','wp-slimstat') ?></option>
223
+ <option value="is_greater_than"><?php _e('is greater than','wp-slimstat') ?></option>
224
+ <option value="is_less_than"><?php _e('is less than','wp-slimstat') ?></option>
225
+ <option value="matches"><?php _e('matches','wp-slimstat') ?></option>
226
+ <option value="does_not_match"><?php _e('does not match','wp-slimstat') ?></option>
227
+ <option value="is_empty"><?php _e('is empty','wp-slimstat') ?></option>
228
+ <option value="is_not_empty"><?php _e('is not empty','wp-slimstat') ?></option>
229
+ </select>
230
+ <input type="text" name="v" id="slimstat-filter-value" value="" size="20">
231
+ <input type="submit" value="<?php _e('Apply','wp-slimstat') ?>" class="button-secondary" name="Submit"
232
+ onclick="return(confirm('<?php _e('Are you sure you want to PERMANENTLY delete these records from your database?','wp-slimstat'); ?>'))" />
233
+ </form>
234
+ </td>
235
+ </tr>
236
+ <tr class="alternate">
237
+ <th scope="row">
238
+ <a class="button-secondary" href="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>&amp;action=truncate-table"
239
+ onclick="return(confirm('<?php _e('Are you sure you want to PERMANENTLY DELETE ALL the records from your database?','wp-slimstat'); ?>'))"><?php _e('Delete All Records','wp-slimstat'); ?></a>
240
+ </th>
241
+ <td>
242
+ <span class="description"><?php _e('Erase all the information collected so far by Slimstat, but not the archived records (<code>wp_slim_stats_archive</code>). This operation <strong>does not</strong> reset your settings and it can be undone by manually copying your records from the archive table.','wp-slimstat') ?></span>
243
+ </td>
244
+ </tr>
245
+ <tr >
246
+ <th scope="row">
247
+ <a class="button-secondary" href="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>&amp;action=truncate-archive"
248
+ onclick="return(confirm('<?php _e('Are you sure you want to PERMANENTLY DELETE ALL the records from your archive?','wp-slimstat'); ?>'))"><?php _e('Delete Archive','wp-slimstat'); ?></a>
249
+ </th>
250
+ <td>
251
+ <span class="description"><?php _e("Erase all the archived records. This operation cannot be undone.",'wp-slimstat') ?></span>
252
+ </td>
253
+ </tr>
254
+ <tr class="alternate">
255
+ <?php if (empty($check_index)): ?>
256
+ <th scope="row">
257
+ <a class="button-secondary" href="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>&amp;action=activate-indexes"><?php _e("Improve Performance",'wp-slimstat'); ?></a>
258
+ </th>
259
+ <td>
260
+
261
+ <span class="description"><?php _e("Please note that you will need about 30% more DB space to store the extra information required.",'wp-slimstat') ?></span>
262
+ </td>
263
+ <?php else: ?>
264
+ <th scope="row">
265
+ <a class="button-secondary" href="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>&amp;action=deactivate-indexes"><?php _e('Save DB Space','wp-slimstat'); ?></a>
266
+ </th>
267
+ <td>
268
+ <span class="description"><?php _e("Please note that by removing table indexes, Slimstat's performance will be affected.",'wp-slimstat') ?></span>
269
+ </td>
270
+ <?php endif ?>
271
+ </tr>
272
+ <tr>
273
+ <td colspan="2" class="slimstat-options-section-header" id="wp-slimstat-external-data-files"><?php _e('External Data Files','wp-slimstat') ?></td>
274
+ </tr>
275
+ <tr>
276
+ <th scope="row">
277
+ <?php if (!file_exists(wp_slimstat::$maxmind_path)): ?>
278
+ <a class="button-secondary" href="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>&amp;action=download-maxmind"
279
+ onclick="return(confirm('<?php _e('Do you want to download and install the geolocation database from MaxMind\'s server?','wp-slimstat'); ?>'))"><?php _e("Install GeoLite DB",'wp-slimstat'); ?></a>
280
+ <?php else: ?>
281
+ <a class="button-secondary" href="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>&amp;action=delete-maxmind"
282
+ onclick="return(confirm('<?php _e('Do you want to uninstall the geolocation database?','wp-slimstat'); ?>'))"><?php _e("Uninstall GeoLite DB",'wp-slimstat'); ?></a>
283
+ <?php endif; ?>
284
+ </th>
285
+ <td>
286
+ <span class="description"><?php _e("The <a href='https://dev.maxmind.com/geoip/geoip2/geolite2/' target='_blank'>MaxMind GeoLite2 library</a>, which Slimstat uses to geolocate visitors, is released under the Creative Commons BY-SA 3.0 license, and cannot be directly bundled with the plugin because of license incompatibility issues. We are mandated to have the user take an affirmative action in order to enable this functionality. If you're experiencing issues, please <a href='https://slimstat.freshdesk.com/solution/articles/12000039798-how-to-manually-install-the-maxmind-geolocation-data-file-' target='_blank'>take a look at our knowledge base</a> to learn how to install this file manually.", 'wp-slimstat' ) ?></span>
287
+ </td>
288
+ </tr>
289
+ <tr class="alternate">
290
+ <th scope="row">
291
+ <?php if ( !file_exists( slim_browser::$browscap_autoload_path ) ) : ?>
292
+ <a class="button-secondary" href="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>&amp;action=download-browscap"
293
+ onclick="return( confirm( '<?php _e( 'Do you want to download and install the Browscap data file from our server?', 'wp-slimstat' ); ?>' ) )"><?php _e( 'Install Browscap', 'wp-slimstat' ); ?></a>
294
+ <?php else: ?>
295
+ <a class="button-secondary" href="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>&amp;action=delete-browscap"
296
+ onclick="return( confirm( '<?php _e( 'Do you want to uninstall the Browscap data file?', 'wp-slimstat' ); ?>' ) )"><?php _e( 'Uninstall Browscap', 'wp-slimstat' ); ?></a>
297
+ <?php endif; ?>
298
+ </th>
299
+ <td>
300
+ <span class="description"><?php _e( "We are contributing to the <a href='http://browscap.org/' target='_blank'>Browscap Capabilities Project</a>, which we use to decode your visitors' user agent string into browser name and operating system. We use an optimized version of their data structure, for improved performance. After you enable this feature, Slimstat will use this data file instead of the built-in heuristic function, to accurately determine your visitors' browser information. It will also automatically check for updates and download the latest version for you. Please feel free to <a href='http://s3.amazonaws.com/browscap/terms-conditions.html' target='_blank'>review our terms and conditions</a>, and do not hesitate to <a href='http://support.wp-slimstat.com' target='_blank'>contact our support team</a> if you have any questions.", 'wp-slimstat' ) ?></span>
301
+ </td>
302
+ </tr>
303
+ <tr>
304
+ <td colspan="2" class="slimstat-options-section-header" id="wp-slimstat-configuration-string"><?php _e('Configuration String','wp-slimstat') ?></td>
305
+ </tr>
306
+ <tr>
307
+ <td colspan="2">
308
+ <strong><?php _e("Here below you can find the current configuration string for Slimstat. You can update your settings by pasting a new string inside the text area and clicking the Import button.",'wp-slimstat') ?></strong>
309
+ <form action="<?php echo wp_slimstat_admin::$config_url.$current_tab ?>" method="post">
310
+ <?php wp_nonce_field( 'maintenance_wp_slimstat', 'maintenance_wp_slimstat_nonce', true, true ) ?>
311
+ <input type="hidden" name="action" value="import-settings" />
312
+ <textarea name="import-slimstat-settings" style="width:100%" rows="10"><?php echo json_encode( wp_slimstat::$settings ) ?></textarea><br/>
313
+ <input type="submit" value="<?php _e('Import','wp-slimstat') ?>" class="button-secondary"
314
+ onclick="return(confirm('<?php _e('Are you sure you want to OVERWRITE your current settings?','wp-slimstat'); ?>'))">
315
+ </form>
316
+ </td>
317
+ </tr>
318
+ <tr>
319
+ <td colspan="2" class="slimstat-options-section-header" id="wp-slimstat-database-information"><?php _e('Database Information','wp-slimstat') ?></td>
320
+ </tr>
321
+ <tr>
322
+ <th scope="row"><?php _e('Engine','wp-slimstat') ?></th>
323
+ <td><?php
324
+ echo $details_wp_slim_tables[0]['Engine'];
325
+ if (!empty($have_innodb) && $have_innodb[0]['Value'] == 'YES' && $details_wp_slim_tables[0]['Engine'] == 'MyISAM'){
326
+ echo ' [<a class="noslimstat" href="'.wp_slimstat_admin::$config_url.$current_tab.'&amp;action=switch-engine">'.__('switch to InnoDB','wp-slimstat').'</a>]';
327
+ }
328
+ ?></td>
329
+ </tr>
330
+ <?php
331
+ foreach ($details_wp_slim_tables as $i => $a_table){
332
+ $base = ($a_table['Data_length'] != 0)?(log($a_table['Data_length']) / log(1024)):0;
333
+ $a_table['Data_length_with_suffix'] = round(pow(1024, $base - floor($base)), 2).' '.$suffixes[floor($base)];
334
+
335
+ echo '<tr '.(($i%2==0)?'class="alternate"':'').">
336
+ <th scope='row'>{$a_table['Name']}</th>
337
+ <td>".$a_table['Data_length_with_suffix'].' ('.number_format($a_table['Rows'], 0).' '.__('records','wp-slimstat').')</td>
338
+ </tr>';
339
+ }
340
+ $i++;
341
+ if ( !empty( $slim_stats_4_exists ) || !empty( $slim_stats_3_exists ) || !empty( $slim_browsers_exists ) ):
342
+ ?>
343
+ <tr<?php echo (($i%2==0)?' class="alternate"':'') ?>>
344
+ <th scope="row"><?php _e( 'Old Tables', 'wp-slimstat' ) ?></th>
345
+ <td><?php printf( __( 'It looks like your database was upgraded from a version prior to 4.0. Our upgrade procedure follows a conservative approach, and does not automatically perform any garbage collection. In other words, the old tables, leftovers of the upgrade, are not deleted from the database. This allows our users to easily roll back to a working state in case of problems. However, if everything is working as expected (tracker and reports), you may want to log into phpMyAdmin and remove the following tables, if they exist: %s. When in doubt, do not hesitate to contact us for help.', 'wp-slimstat' ), "<code>{$GLOBALS['wpdb']->prefix}slim_browsers</code>, <code>{$GLOBALS['wpdb']->prefix}slim_content_info</code>, <code>{$GLOBALS['wpdb']->prefix}slim_outbound</code>, <code>{$GLOBALS['wpdb']->prefix}slim_screenres</code>, <code>{$GLOBALS['wpdb']->prefix}slim_stats_3</code>, <code>{$GLOBALS['wpdb']->prefix}slim_stats_4</code>, <code>{$GLOBALS['wpdb']->prefix}slim_stats_archive_3</code>, <code>{$GLOBALS['wpdb']->prefix}slim_stats_archive_4</code>" ) ?></td>
346
+ </tr>
347
+ <?php endif; ?>
348
+ </tbody>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
349
  </table>
admin/css/slimstat.css CHANGED
@@ -90,7 +90,7 @@
90
  #slimstat-date-filters .dropdown select, #slimstat-date-filters .dropdown input{
91
  margin: 0 5px 5px 0;
92
  height: 27px;
93
- width: 135px;
94
  }
95
  #slimstat-date-filters .dropdown select.short, #slimstat-date-filters .dropdown input.short{
96
  width: 65px;
@@ -220,7 +220,7 @@
220
  padding: 0 !important;
221
  }
222
  .wrap.slimstat .postbox.tall .inside{
223
- height: 650px;
224
  }
225
  [id^=slim_] p {
226
  border-bottom: 1px solid #ddd;
@@ -568,7 +568,7 @@
568
  .slimstat-layout .postbox-container {
569
  border: 1px solid #ccc;
570
  float: none;
571
- margin-bottom: 20px;
572
  overflow: hidden;
573
  }
574
  .slimstat-layout .meta-box-sortables {
@@ -597,9 +597,6 @@
597
  margin: 0;
598
  padding: 5px 10px;
599
  }
600
- .slimstat-layout #postbox-container-slimview1 {
601
- display: none;
602
- }
603
 
604
  /* Responsive */
605
  @media screen and ( max-width: 1560px ) {
90
  #slimstat-date-filters .dropdown select, #slimstat-date-filters .dropdown input{
91
  margin: 0 5px 5px 0;
92
  height: 27px;
93
+ width: 130px;
94
  }
95
  #slimstat-date-filters .dropdown select.short, #slimstat-date-filters .dropdown input.short{
96
  width: 65px;
220
  padding: 0 !important;
221
  }
222
  .wrap.slimstat .postbox.tall .inside{
223
+ height: 605px;
224
  }
225
  [id^=slim_] p {
226
  border-bottom: 1px solid #ddd;
568
  .slimstat-layout .postbox-container {
569
  border: 1px solid #ccc;
570
  float: none;
571
+ margin-top: 20px;
572
  overflow: hidden;
573
  }
574
  .slimstat-layout .meta-box-sortables {
597
  margin: 0;
598
  padding: 5px 10px;
599
  }
 
 
 
600
 
601
  /* Responsive */
602
  @media screen and ( max-width: 1560px ) {
admin/js/slimstat.admin.js CHANGED
@@ -46,7 +46,7 @@ jQuery( function() {
46
 
47
  SlimStatAdmin.refresh_report( id );
48
 
49
- // Remove any temporary filters (pagination) set here above
50
  jQuery( '.slimstat-temp-filter' ).remove();
51
 
52
  // Re-initialize SlimScroll on the new content
@@ -183,10 +183,13 @@ jQuery( function() {
183
 
184
  jQuery( 'form#slimstat-filters-form' ).attr( 'action', url.split( '?' )[ 0 ] + '?page=' + SlimStatAdmin.get_current_tab( url.split( '?' )[ 1 ] ) );
185
 
186
- SlimStatAdmin.add_url_filters_to_form( url, typeof jQuery( this ).attr( 'data-reset-filters' ) != 'undefined' );
187
 
188
  jQuery( '#slimstat-filters-form' ).submit();
189
 
 
 
 
190
  return false;
191
  });
192
 
@@ -460,9 +463,14 @@ var SlimStatAdmin = {
460
  return clean_filters;
461
  },
462
 
463
- add_url_filters_to_form: function( url, delete_existing_filters ) {
464
  clean_filters = SlimStatAdmin.get_query_string_filters( url );
465
 
 
 
 
 
 
466
  // Manipulate the existing list of filters (hidden input fields), if we don't want to delete them
467
  if ( typeof delete_existing_filters == 'undefined' || !delete_existing_filters ) {
468
 
@@ -475,7 +483,7 @@ var SlimStatAdmin = {
475
  jQuery( 'input[name="' + i + '"]' ).attr( 'value', clean_filters[ i ] );
476
  }
477
  else {
478
- jQuery( '<input type="hidden" name="' + i + '" class="slimstat-post-filter" value="' + clean_filters[ i ] + '">' ).appendTo( '#slimstat-filters-form' );
479
  }
480
  }
481
  }
@@ -484,7 +492,7 @@ var SlimStatAdmin = {
484
  jQuery( '.slimstat-post-filter' ).remove();
485
 
486
  for( i in clean_filters ) {
487
- jQuery( '<input type="hidden" name="' + i + '" class="slimstat-post-filter" value="' + clean_filters[ i ] + '">' ).appendTo( '#slimstat-filters-form' );
488
  }
489
  }
490
  },
46
 
47
  SlimStatAdmin.refresh_report( id );
48
 
49
+ // Remove any temporary filters set here above
50
  jQuery( '.slimstat-temp-filter' ).remove();
51
 
52
  // Re-initialize SlimScroll on the new content
183
 
184
  jQuery( 'form#slimstat-filters-form' ).attr( 'action', url.split( '?' )[ 0 ] + '?page=' + SlimStatAdmin.get_current_tab( url.split( '?' )[ 1 ] ) );
185
 
186
+ SlimStatAdmin.add_url_filters_to_form( url, typeof jQuery( this ).attr( 'data-reset-filters' ) != 'undefined', jQuery( this ).hasClass( 'slimstat-filter-temp' ) );
187
 
188
  jQuery( '#slimstat-filters-form' ).submit();
189
 
190
+ // Remove any temporary filters set here above
191
+ jQuery( '.slimstat-temp-filter' ).remove();
192
+
193
  return false;
194
  });
195
 
463
  return clean_filters;
464
  },
465
 
466
+ add_url_filters_to_form: function( url, delete_existing_filters, is_temporary ) {
467
  clean_filters = SlimStatAdmin.get_query_string_filters( url );
468
 
469
+ is_temporary_class = '';
470
+ if ( typeof is_temporary != 'undefined' ) {
471
+ is_temporary_class = ' slimstat-temp-filter';
472
+ }
473
+
474
  // Manipulate the existing list of filters (hidden input fields), if we don't want to delete them
475
  if ( typeof delete_existing_filters == 'undefined' || !delete_existing_filters ) {
476
 
483
  jQuery( 'input[name="' + i + '"]' ).attr( 'value', clean_filters[ i ] );
484
  }
485
  else {
486
+ jQuery( '<input type="hidden" name="' + i + '" class="slimstat-post-filter' + is_temporary_class + '" value="' + clean_filters[ i ] + '">' ).appendTo( '#slimstat-filters-form' );
487
  }
488
  }
489
  }
492
  jQuery( '.slimstat-post-filter' ).remove();
493
 
494
  for( i in clean_filters ) {
495
+ jQuery( '<input type="hidden" name="' + i + '" class="slimstat-post-filter' + is_temporary_class + '" value="' + clean_filters[ i ] + '">' ).appendTo( '#slimstat-filters-form' );
496
  }
497
  }
498
  },
admin/view/index.php CHANGED
@@ -7,7 +7,7 @@
7
 
8
  <form action="<?php echo wp_slimstat_reports::fs_url(); ?>" method="post" id="slimstat-filters-form">
9
  <fieldset id="slimstat-filters"><?php
10
- $filter_name_html = '<label for="slimstat-filter-name">Filter by</label><select name="f" id="slimstat-filter-name"><option value="" disabled selected>' . __( 'Filter', 'wp-slimstat' ) . '</option>';
11
  foreach ( wp_slimstat_db::$columns_names as $a_filter_label => $a_filter_info ) {
12
  $filter_name_html .= "<option value='$a_filter_label'>{$a_filter_info[0]}</option>";
13
  }
7
 
8
  <form action="<?php echo wp_slimstat_reports::fs_url(); ?>" method="post" id="slimstat-filters-form">
9
  <fieldset id="slimstat-filters"><?php
10
+ $filter_name_html = '<label for="slimstat-filter-name">Filter by</label><select name="f" id="slimstat-filter-name"><option value="" disabled selected>' . __( 'Dimension', 'wp-slimstat' ) . '</option>';
11
  foreach ( wp_slimstat_db::$columns_names as $a_filter_label => $a_filter_info ) {
12
  $filter_name_html .= "<option value='$a_filter_label'>{$a_filter_info[0]}</option>";
13
  }
admin/view/layout.php CHANGED
@@ -1,113 +1,113 @@
1
- <?php
2
- include_once( dirname(__FILE__) . '/wp-slimstat-reports.php' );
3
- wp_slimstat_reports::init();
4
-
5
- // Get default report placements
6
- $report_locations = array(
7
- 'inactive' => array(),
8
- 'dashboard' => array(),
9
- 'slimview1' => array(),
10
- 'slimview2' => array(),
11
- 'slimview3' => array(),
12
- 'slimview4' => array(),
13
- 'slimview5' => array(),
14
- 'slimview6' => array()
15
- );
16
-
17
- $reset_link = '';
18
- $is_report_reset = false;
19
- if ( !empty( $_GET[ 'action' ] ) && $_GET[ 'action' ] == 'restore-views' ) {
20
- $GLOBALS['wpdb']->query("DELETE FROM {$GLOBALS['wpdb']->prefix}usermeta WHERE meta_key LIKE '%meta-box-order_admin_page_slimlayout%'");
21
- $GLOBALS['wpdb']->query("DELETE FROM {$GLOBALS['wpdb']->prefix}usermeta WHERE meta_key LIKE '%mmetaboxhidden_admin_page_slimview%'");
22
- $GLOBALS['wpdb']->query("DELETE FROM {$GLOBALS['wpdb']->prefix}usermeta WHERE meta_key LIKE '%meta-box-order_slimstat%'");
23
- $GLOBALS['wpdb']->query("DELETE FROM {$GLOBALS['wpdb']->prefix}usermeta WHERE meta_key LIKE '%metaboxhidden_slimstat%'");
24
- $GLOBALS['wpdb']->query("DELETE FROM {$GLOBALS['wpdb']->prefix}usermeta WHERE meta_key LIKE '%closedpostboxes_slimstat%'");
25
- $is_report_reset = true;
26
- }
27
-
28
- if ( empty( wp_slimstat_reports::$user_reports ) || $is_report_reset ) {
29
- foreach ( wp_slimstat_reports::$reports_info as $a_report_id => $a_report_info ) {
30
- if ( !empty( $a_report_info[ 'screens' ] ) ) {
31
- foreach ( $a_report_info[ 'screens' ] as $a_report_screen ) {
32
- if ( isset( $report_locations[ $a_report_screen ] ) ) {
33
- $report_locations[ $a_report_screen ][] = $a_report_id;
34
- }
35
- }
36
- }
37
- }
38
- }
39
- else {
40
- foreach ( $report_locations as $a_location_id => $a_location_list ) {
41
- if ( !empty( wp_slimstat_reports::$user_reports[ $a_location_id ] ) ) {
42
- $report_locations[ $a_location_id ] = explode( ',', wp_slimstat_reports::$user_reports[ $a_location_id ] );
43
- }
44
- else {
45
- $report_locations[ $a_location_id ] = array();
46
- }
47
- }
48
-
49
- if ( is_network_admin() ) {
50
- $reset_link = sprintf( __( 'By using the network-wide customizer, all your users will be seeing the same layout and will not be able to further customize it. You can reset this feature by <a href="%s">clicking here</a>.', 'wp-slimstat' ), 'admin.php?page=slimlayout&&amp;action=restore-views' );
51
- }
52
- }
53
-
54
- // Keep track of multiple occurrences of the same report, to allow users to delete duplicates
55
- $already_seen = array();
56
-
57
- $current_user = wp_get_current_user();
58
- $page_location = ( wp_slimstat::$settings[ 'use_separate_menu' ] == 'on' ) ? 'slimstat' : 'admin';
59
- ?>
60
-
61
- <div class="wrap slimstat-layout">
62
- <h2><?php _e( 'Customize and organize your reports','wp-slimstat' ) ?></h2>
63
- <p><?php
64
- _e( 'Drag and drop report placeholders from one container to another, to customize the information you want to see right away when you open Slimstat. Place two or more charts on the same view, clone reports or move them to the Inactive Reports container for improved performance. It is your website, and you know how metrics should be combined to get a clear picture of the traffic it generates.', 'wp-slimstat' );
65
- echo ' ' . $reset_link . '<br/><br/>';
66
- _e( '<strong>Note</strong>: if a placeholder is greyed out, it means that the corresponding report is currently hidden (Screen Options tab).', 'wp-slimstat');
67
- ?></p>
68
-
69
- <form method="get" action=""><input type="hidden" id="meta-box-order-nonce" name="meta-box-order-nonce" value="<?php echo wp_create_nonce('meta-box-order') ?>" /></form>
70
-
71
- <?php foreach ( $report_locations as $a_location_id => $a_location_list ): $hidden_reports = get_user_option( "metaboxhidden_{$page_location}_page_{$a_location_id}", $current_user->ID ); if ( !is_array( $hidden_reports ) ) $hidden_reports = array(); ?>
72
- <div id="postbox-container-<?php echo $a_location_id ?>" class="postbox-container">
73
- <h2 class="slimstat-options-section-header"><?php echo wp_slimstat_admin::$screens_info[ $a_location_id ][ 'title' ] ?></h2>
74
- <div id="<?php echo $a_location_id ?>-sortables" class="meta-box-sortables"><?php
75
- if ( $a_location_id != 'inactive' ) {
76
- $move_to_inactive = ' <a class="slimstat-font-minus-circled" href="#" title="' . __( 'Move to Inactive', 'wp-slimstat' ) . '"></a>';
77
- }
78
- else {
79
- $move_to_inactive = '';
80
- }
81
-
82
- foreach( $a_location_list as $a_report_id ) {
83
- if ( empty( wp_slimstat_reports::$reports_info[ $a_report_id ] ) ) {
84
- continue;
85
- }
86
-
87
- if ( !in_array( $a_report_id, $already_seen ) ) {
88
- $already_seen[] = $a_report_id;
89
- $icon = 'docs';
90
- $title = __( 'Clone', 'wp-slimstat' );
91
- }
92
- else{
93
- $icon = 'trash';
94
- $title = __( 'Delete', 'wp-slimstat' );
95
- }
96
-
97
- $placeholder_classes = '';
98
- if ( ( in_array( 'hidden', wp_slimstat_reports::$reports_info[ $a_report_id ][ 'classes' ] ) && empty( $hidden_reports ) ) || in_array( $a_report_id, $hidden_reports ) ) {
99
- $placeholder_classes = ' invisible';
100
- }
101
-
102
- echo "
103
- <div class='postbox$placeholder_classes' id='$a_report_id'>
104
- <div class='slimstat-header-buttons'>
105
- <a class='slimstat-font-$icon' href='#' title='$title'></a>
106
- $move_to_inactive
107
- </div>
108
- <h3 class='hndle'>" . wp_slimstat_reports::$reports_info[ $a_report_id ][ 'title' ] . "</h3>
109
- </div>";
110
- } ?>
111
- </div>
112
- </div>
113
  <?php endforeach; ?>
1
+ <?php
2
+ include_once( dirname(__FILE__) . '/wp-slimstat-reports.php' );
3
+ wp_slimstat_reports::init();
4
+
5
+ // Get default report placements
6
+ $report_locations = array(
7
+ 'inactive' => array(),
8
+ 'dashboard' => array(),
9
+ 'slimview1' => array(),
10
+ 'slimview2' => array(),
11
+ 'slimview3' => array(),
12
+ 'slimview4' => array(),
13
+ 'slimview5' => array()
14
+ );
15
+
16
+ $is_report_reset = false;
17
+ if ( !empty( $_GET[ 'action' ] ) && $_GET[ 'action' ] == 'restore-views' ) {
18
+ $GLOBALS[ 'wpdb' ]->query( "DELETE FROM {$GLOBALS['wpdb']->prefix}usermeta WHERE meta_key LIKE '%meta-box-order_admin_page_slimlayout%'" );
19
+ $GLOBALS[ 'wpdb' ]->query( "DELETE FROM {$GLOBALS['wpdb']->prefix}usermeta WHERE meta_key LIKE '%mmetaboxhidden_admin_page_slimview%'" );
20
+ $GLOBALS[ 'wpdb' ]->query( "DELETE FROM {$GLOBALS['wpdb']->prefix}usermeta WHERE meta_key LIKE '%meta-box-order_slimstat%'" );
21
+ $GLOBALS[ 'wpdb' ]->query( "DELETE FROM {$GLOBALS['wpdb']->prefix}usermeta WHERE meta_key LIKE '%metaboxhidden_slimstat%'" );
22
+ $GLOBALS[ 'wpdb' ]->query( "DELETE FROM {$GLOBALS['wpdb']->prefix}usermeta WHERE meta_key LIKE '%closedpostboxes_slimstat%'" );
23
+ $is_report_reset = true;
24
+ }
25
+
26
+ if ( empty( wp_slimstat_reports::$user_reports ) || $is_report_reset ) {
27
+ foreach ( wp_slimstat_reports::$reports_info as $a_report_id => $a_report_info ) {
28
+ if ( !empty( $a_report_info[ 'screens' ] ) ) {
29
+ foreach ( $a_report_info[ 'screens' ] as $a_report_screen ) {
30
+ if ( isset( $report_locations[ $a_report_screen ] ) ) {
31
+ $report_locations[ $a_report_screen ][] = $a_report_id;
32
+ }
33
+ }
34
+ }
35
+ }
36
+ }
37
+ else {
38
+ foreach ( $report_locations as $a_location_id => $a_location_list ) {
39
+ if ( !empty( wp_slimstat_reports::$user_reports[ $a_location_id ] ) ) {
40
+ $report_locations[ $a_location_id ] = explode( ',', wp_slimstat_reports::$user_reports[ $a_location_id ] );
41
+ }
42
+ else {
43
+ $report_locations[ $a_location_id ] = array();
44
+ }
45
+ }
46
+ }
47
+
48
+ // Keep track of multiple occurrences of the same report, to allow users to delete duplicates
49
+ $already_seen = array();
50
+
51
+ $current_user = wp_get_current_user();
52
+ $page_location = ( wp_slimstat::$settings[ 'use_separate_menu' ] == 'on' ) ? 'slimstat' : 'admin';
53
+ ?>
54
+
55
+ <div class="wrap slimstat-layout">
56
+ <h2><?php _e( 'Customize and organize your reports','wp-slimstat' ) ?></h2>
57
+ <p><?php
58
+ _e( 'Drag and drop report placeholders from one container to another, to customize the information you want to see right away when you open Slimstat. Place two or more charts on the same view, clone reports or move them to the Inactive Reports container for improved performance. It is your website, and you know how metrics should be combined to get a clear picture of the traffic it generates.', 'wp-slimstat' );
59
+ echo ' ';
60
+ if ( is_network_admin() ) {
61
+ _e( 'By using the network-wide customizer, all your users will be seeing the same layout and will not be able to further customize it.', 'wp-slimstat' );
62
+ echo ' ';
63
+ }
64
+ _e( '<strong>Note</strong>: if a placeholder is greyed out, it means that the corresponding report is currently hidden (Screen Options tab).', 'wp-slimstat');
65
+ ?></p>
66
+
67
+ <form method="get" action=""><input type="hidden" id="meta-box-order-nonce" name="meta-box-order-nonce" value="<?php echo wp_create_nonce('meta-box-order') ?>" /></form>
68
+
69
+ <a href="admin.php?page=slimlayout&&amp;action=restore-views" class="button"><?php _e( 'Reset All', 'wp-slimstat' ) ?></a>
70
+
71
+ <?php foreach ( $report_locations as $a_location_id => $a_location_list ): $hidden_reports = get_user_option( "metaboxhidden_{$page_location}_page_{$a_location_id}", $current_user->ID ); if ( !is_array( $hidden_reports ) ) $hidden_reports = array(); ?>
72
+ <div id="postbox-container-<?php echo $a_location_id ?>" class="postbox-container">
73
+ <h2 class="slimstat-options-section-header"><?php echo wp_slimstat_admin::$screens_info[ $a_location_id ][ 'title' ] ?></h2>
74
+ <div id="<?php echo $a_location_id ?>-sortables" class="meta-box-sortables"><?php
75
+ if ( $a_location_id != 'inactive' ) {
76
+ $move_to_inactive = ' <a class="slimstat-font-minus-circled" href="#" title="' . __( 'Move to Inactive', 'wp-slimstat' ) . '"></a>';
77
+ }
78
+ else {
79
+ $move_to_inactive = '';
80
+ }
81
+
82
+ foreach( $a_location_list as $a_report_id ) {
83
+ if ( empty( wp_slimstat_reports::$reports_info[ $a_report_id ] ) ) {
84
+ continue;
85
+ }
86
+
87
+ if ( !in_array( $a_report_id, $already_seen ) ) {
88
+ $already_seen[] = $a_report_id;
89
+ $icon = 'docs';
90
+ $title = __( 'Clone', 'wp-slimstat' );
91
+ }
92
+ else{
93
+ $icon = 'trash';
94
+ $title = __( 'Delete', 'wp-slimstat' );
95
+ }
96
+
97
+ $placeholder_classes = '';
98
+ if ( ( in_array( 'hidden', wp_slimstat_reports::$reports_info[ $a_report_id ][ 'classes' ] ) && empty( $hidden_reports ) ) || in_array( $a_report_id, $hidden_reports ) ) {
99
+ $placeholder_classes = ' invisible';
100
+ }
101
+
102
+ echo "
103
+ <div class='postbox$placeholder_classes' id='$a_report_id'>
104
+ <div class='slimstat-header-buttons'>
105
+ <a class='slimstat-font-$icon' href='#' title='$title'></a>
106
+ $move_to_inactive
107
+ </div>
108
+ <h3 class='hndle'>" . wp_slimstat_reports::$reports_info[ $a_report_id ][ 'title' ] . "</h3>
109
+ </div>";
110
+ } ?>
111
+ </div>
112
+ </div>
113
  <?php endforeach; ?>
admin/view/right-now.php CHANGED
@@ -50,248 +50,250 @@ if ( isset( $_args[ 'echo' ] ) && $_args[ 'echo' ] === false ) {
50
 
51
  if ($count_page_results == 0){
52
  echo '<p class="nodata">'.__('No data to display','wp-slimstat').'</p>';
 
53
  }
54
- else {
55
 
56
- // Pagination
57
- echo wp_slimstat_reports::report_pagination( $count_page_results, $count_all_results, true, wp_slimstat::$settings[ 'number_results_raw_data' ] );
58
 
59
- // Show delete button? (only those who can access the settings can see it)
60
- $current_user_can_delete = ( current_user_can( wp_slimstat::$settings[ 'capability_can_admin' ] ) && !is_network_admin() );
61
- $delete_row = '';
62
 
63
- // Loop through the results
64
- for ( $i=0; $i < $count_page_results; $i++ ) {
65
- $host_by_ip = $results[ $i ][ 'ip' ];
66
- if ( wp_slimstat::$settings[ 'convert_ip_addresses' ] == 'on' ) {
67
- $gethostbyaddr = gethostbyaddr( $results[ $i ][ 'ip' ] );
68
- if ( $gethostbyaddr != $host_by_ip && !empty( $gethostbyaddr ) ) {
69
- $host_by_ip .= ', ' . $gethostbyaddr;
70
- }
71
  }
 
72
 
73
- $date_time = "<i class='spaced slimstat-font-clock slimstat-tooltip-trigger' title='".__( 'Date and Time', 'wp-slimstat' )."'></i> " . date_i18n( wp_slimstat::$settings[ 'date_format' ] . ' ' . wp_slimstat::$settings[ 'time_format' ], $results[ $i ][ 'dt' ], true );
74
-
75
- // Print visit header?
76
- if ( $i == 0 || $results[ $i - 1 ][ 'visit_id' ] != $results[ $i ][ 'visit_id' ] || $results[ $i - 1 ][ 'ip' ] != $results[ $i ][ 'ip' ] || $results[ $i - 1 ][ 'browser' ] != $results[ $i ][ 'browser' ] || $results[ $i - 1 ][ 'platform' ] != $results[ $i ][ 'platform' ] || $results[ $i - 1 ][ 'username' ] != $results[ $i ][ 'username' ] ) {
77
-
78
- // Color-coded headers
79
- $highlight_row = !empty($results[$i]['searchterms'])?' is-search-engine':(($results[$i]['browser_type'] != 1)?' is-direct':'');
80
-
81
- // Country
82
- $country_filtered = '';
83
- if ( !empty( $results[ $i ][ 'country' ] ) && $results[ $i ][ 'country' ] != 'xx' ) {
84
- $country_filtered = "<a class='slimstat-filter-link inline-icon' href='" . wp_slimstat_reports::fs_url( 'country equals ' . $results[ $i ][ 'country' ] ) . "'><img class='slimstat-tooltip-trigger' src='$plugin_url/images/flags/{$results[$i]['country']}.png' width='16' height='16' title='" . __( 'c-' . $results[ $i ][ 'country' ], 'wp-slimstat' ) . "'></a>";
85
- }
86
-
87
- // City, if tracked
88
- $city_filtered = '';
89
- if ( !empty( $results[ $i ][ 'city' ] ) ) {
90
- $city_filtered = "<a class='slimstat-filter-link' href='" . wp_slimstat_reports::fs_url( 'city equals ' . $results[ $i ][ 'city' ] ) . "'>{$results[ $i ][ 'city' ]}</a>";
91
- }
92
-
93
- // Browser
94
- if ($results[$i]['browser_version'] == 0) $results[$i]['browser_version'] = '';
95
- $browser_title = ( wp_slimstat::$settings[ 'show_complete_user_agent_tooltip' ] != 'on' ) ? "{$results[ $i ][ 'browser' ]} {$results[ $i ][ 'browser_version' ]}" : $results[ $i ][ 'user_agent' ];
96
- $browser_icon = $plugin_url.'/images/browsers/other-browsers-and-os.png';
97
- if (in_array($results[$i]['browser'], $supported_browser_icons)){
98
- $browser_icon = $plugin_url.'/images/browsers/'.sanitize_title($results[$i]['browser']).'.png';
99
- }
100
- $browser_filtered = "<a class='slimstat-filter-link inline-icon' href='".wp_slimstat_reports::fs_url('browser equals '.$results[$i]['browser'])."'><img class='slimstat-tooltip-trigger' src='$browser_icon' width='16' height='16' title='{$browser_title}'></a>";
101
-
102
- // Platform
103
- $platform_icon = $plugin_url.'/images/browsers/other-browsers-and-os.png';
104
- if (in_array(strtolower($results[$i]['platform']), $supported_os_icons)){
105
- $platform_icon = $plugin_url.'/images/platforms/'.sanitize_title($results[$i]['platform']).'.png';
106
- }
107
- $platform_filtered = "<a class='slimstat-filter-link inline-icon' href='".wp_slimstat_reports::fs_url('platform equals '.$results[$i]['platform'])."'><img class='slimstat-tooltip-trigger' src='$platform_icon' width='16' height='16' title='" . __( $results[ $i ][ 'platform' ], 'wp-slimstat' ) . "'></a>";
108
-
109
- // Browser Type
110
- $browser_type_filtered = '';
111
- if ($results[$i]['browser_type'] != 0){
112
- $browser_type_filtered = "<a class='slimstat-filter-link inline-icon' href='".wp_slimstat_reports::fs_url('browser_type equals '.$results[$i]['browser_type'])."'><img class='slimstat-tooltip-trigger' src='$plugin_url/images/browsers/type{$results[$i]['browser_type']}.png' width='16' height='16' title='{$supported_browser_types[$results[$i]['browser_type']]}'></a>";
113
- }
114
-
115
- // IP Address and user
116
- if (empty($results[$i]['username'])){
117
- $ip_address = "<a class='slimstat-filter-link' href='".wp_slimstat_reports::fs_url('ip equals '.$results[$i]['ip'])."'>$host_by_ip</a>";
118
- }
119
- else{
120
- $display_user_name = $results[ $i ][ 'username' ];
121
- if ( wp_slimstat::$settings[ 'show_display_name' ] == 'on' && strpos( $results[ $i ][ 'notes' ], 'user:' ) !== false ) {
122
- $display_real_name = get_user_by('login', $results[$i]['username']);
123
- if (is_object($display_real_name)) $display_user_name = $display_real_name->display_name;
124
- }
125
- $ip_address = "<a class='slimstat-filter-link' href='".wp_slimstat_reports::fs_url('username equals '.$results[$i]['username'])."'>{$display_user_name}</a>";
126
- $ip_address .= " <a class='slimstat-filter-link' href='".wp_slimstat_reports::fs_url('ip equals '.$results[$i]['ip'])."'>($host_by_ip)</a>";
127
- $highlight_row = (strpos( $results[$i]['notes'], 'user:') !== false)?' is-known-user':' is-known-visitor';
128
-
129
- }
130
 
131
- $whois_pin = '';
132
- if ( is_admin() && !empty( wp_slimstat::$settings[ 'ip_lookup_service' ] ) && !wp_slimstat::is_local_ip_address( $results[ $i ][ 'ip' ] ) ) {
133
- $whois_pin = "<a class='slimstat-font-location-1 whois' href='" . wp_slimstat::$settings[ 'ip_lookup_service' ] . "{$results[ $i ][ 'ip' ]}' target='_blank' title='WHOIS: {$results[ $i ][ 'ip' ]}'></a>";
134
- }
135
 
136
- // Originating IP Address
137
- $other_ip_address = intval( $results[ $i ][ 'other_ip' ] );
138
- if ( !empty( $other_ip_address ) ) {
139
- $other_ip_address = "<a class='slimstat-filter-link' href='" . wp_slimstat_reports::fs_url( 'other_ip equals '. $results[ $i ][ 'other_ip' ] ) . "'>(" . __( 'Originating IP', 'wp-slimstat' ) . ": {$results[$i]['other_ip']})</a>";
140
- }
141
- else {
142
- $other_ip_address = '';
143
- }
144
 
145
- // Plugins
146
- $plugins = '';
147
- if (!empty($results[$i]['plugins'])){
148
- $results[$i]['plugins'] = explode(',', $results[$i]['plugins']);
149
- foreach($results[$i]['plugins'] as $a_plugin){
150
- $a_plugin = trim($a_plugin);
151
- $plugins .= "<a class='slimstat-filter-link inline-icon' href='" . wp_slimstat_reports::fs_url( 'plugins contains ' . $a_plugin ) . "'><img class='slimstat-tooltip-trigger' src='$plugin_url/images/plugins/$a_plugin.png' width='16' height='16' title='" . __( $a_plugin, 'wp-slimstat' ) . "'></a> ";
152
- }
153
- }
154
-
155
- // Screen Resolution
156
- $screen_resolution = '';
157
- if ( !empty( $results[ $i ][ 'screen_width' ] ) && !empty( $results[ $i ][ 'screen_height' ] ) ) {
158
- $screen_resolution = "<span class='pageview-screenres'>{$results[ $i ][ 'screen_width' ]}x{$results[ $i ][ 'screen_height' ]}</span>";
159
- }
160
 
161
- $row_output = "<p class='header$highlight_row'>$browser_filtered $platform_filtered $browser_type_filtered $country_filtered $whois_pin $city_filtered $ip_address $other_ip_address <span class='plugins'>$plugins</span> $screen_resolution</p>";
 
 
 
 
162
 
163
- // Strip all the filter links, if this information is shown on the frontend
164
- if ( !is_admin() ) {
165
- $row_output = preg_replace('/<a (.*?)>(.*?)<\/a>/', "\\2", $row_output);
166
- }
 
 
 
 
 
 
167
 
168
- echo $row_output;
 
 
 
169
  }
 
170
 
171
- // Permalink: find post title, if available
172
- $parse_url = parse_url(get_site_url(empty($results[$i]['blog_id'])?1:$results[$i]['blog_id']));
173
- $base_host = $parse_url['host'];
174
- $base_url = '';
 
175
 
176
- if ( !empty( $results[ $i ][ 'resource' ] ) ) {
177
- if (!empty($results[$i]['blog_id'])){
178
- $base_url = $parse_url['scheme'].'://'.$base_host;
179
- }
180
- $results[$i]['resource'] = "<a class='slimstat-font-logout slimstat-tooltip-trigger' target='_blank' title='".htmlentities(__('Open this URL in a new window','wp-slimstat'), ENT_QUOTES, 'UTF-8')."' href='".$base_url.htmlentities($results[$i]['resource'], ENT_QUOTES, 'UTF-8')."'></a> $base_url<a class='slimstat-filter-link' href='".wp_slimstat_reports::fs_url('resource equals ' . htmlentities($results[$i]['resource'], ENT_QUOTES, 'UTF-8') ) . "'>".wp_slimstat_reports::get_resource_title( $results[$i][ 'resource' ], $results[$i][ 'category' ] ).'</a>';
181
  }
182
  else {
183
- if ( !empty( $results[$i][ 'notes' ] ) ) {
184
- $exploded_notes = explode( ';', $results[$i][ 'notes' ] );
185
- foreach ( $exploded_notes as $a_note ) {
186
- if ( strpos( $a_note, 'results:') !== false ) {
187
- $search_terms_info = $results[ $i ][ 'searchterms' ] . ' (' . $a_note . ')';
188
- break;
189
- }
190
  }
191
  }
192
- $results[$i]['resource'] = __('Local search results page','wp-slimstat');
 
 
193
  }
194
 
195
- if ( empty( $search_terms_info ) ) {
196
- $search_terms_info = wp_slimstat_reports::get_search_terms_info( $results[ $i ][ 'searchterms' ], $results[ $i ][ 'referer' ] );
 
197
  }
198
 
199
- // Search Terms, with link to original SERP, and Outbound Resource
200
- if ( !empty( $search_terms_info ) ) {
201
- $results[$i]['searchterms'] = "<i class='spaced slimstat-font-search' title='" . __( 'Search Terms', 'wp-slimstat' ) . "'></i> $search_terms_info";
 
202
  }
203
  else {
204
- $results[$i]['searchterms'] = '';
205
  }
206
 
207
- // Let's reset this variable for the next item
208
- $search_terms_info = '';
209
-
210
- // Server Latency and Page Speed
211
- $performance = '';
212
- if ( !$is_dashboard && ( !empty( $results[ $i ][ 'server_latency' ] ) || !empty( $results[ $i ][ 'page_performance' ] ) ) ) {
213
- $performance = "<i class='slimstat-font-gauge spaced slimstat-tooltip-trigger' title='".__('Server Latency and Page Speed in milliseconds','wp-slimstat')."'></i> ".__('SL','wp-slimstat').": {$results[$i]['server_latency']} / ".__('PS','wp-slimstat').": {$results[$i]['page_performance']}";
 
214
  }
215
 
216
- // Time on page
217
- $time_on_page = '';
218
- if ( !$is_dashboard && !empty( $results[ $i ][ 'dt_out' ] ) ) {
219
- $duration = $results[ $i ][ 'dt_out' ] - $results[ $i ][ 'dt' ];
220
- $time_on_page = "<i class='slimstat-font-stopwatch spaced slimstat-tooltip-trigger' title='" . __( 'Time spent on this page', 'wp-slimstat' ) . "'></i> " . date( ( $duration > 3599 ? 'H:i:s' : 'i:s' ), $duration );
221
  }
222
 
223
- // Pageview Notes
224
- $notes = '';
225
- if ( is_admin() && !empty( $results[ $i ][ 'notes' ] ) ) {
226
- $notes = str_replace(array(';', ':'), array('<br/>', ': '), $results[$i]['notes']);
227
- $notes = "<i class='slimstat-font-edit slimstat-tooltip-trigger'><b class='slimstat-tooltip-content'>{$notes}</b></i>";
228
  }
229
 
230
- // Avoid XSS attacks through the referer URL
231
- $results[ $i ] [ 'referer' ] = str_replace( array( '<', '>', '%22', '%27', '\'', '"', '%3C', '%3E' ), array( '&lt;', '&gt;', '', '', '', '', '&lt;', '&gt;' ), urldecode( $results[ $i ] [ 'referer' ] ) );
 
 
 
 
 
232
 
233
- $login_logout = '';
234
- if ( !$is_dashboard ) {
235
- $domain = parse_url( $results[ $i ] [ 'referer' ] );
236
- $domain = !empty( $domain[ 'host' ] ) ? $domain[ 'host' ] : __( 'Invalid Referrer', 'wp-slimstat' );
237
- $results[$i][ 'referer' ] = (!empty($results[$i]['referer']) && empty($results[$i]['searchterms']))?"<a class='spaced slimstat-font-login slimstat-tooltip-trigger' target='_blank' title='".htmlentities(__('Open this referrer in a new window','wp-slimstat'), ENT_QUOTES, 'UTF-8')."' href='{$results[$i]['referer']}'></a> $domain":'';
238
- $results[$i][ 'content_type' ] = !empty($results[$i]['content_type'])?"<i class='spaced slimstat-font-doc slimstat-tooltip-trigger' title='".__('Content Type','wp-slimstat')."'></i> <a class='slimstat-filter-link' href='".wp_slimstat_reports::fs_url('content_type equals '.$results[$i]['content_type'])."'>{$results[$i]['content_type']}</a> ":'';
239
-
240
- // The Outbound Links field might contain more than one link
241
- if ( !empty( $results[ $i ][ 'outbound_resource' ] ) ) {
242
- $exploded_outbound_resources = explode( ';;;', $results[ $i ][ 'outbound_resource' ] );
243
- $results[$i][ 'outbound_resource' ] = '';
244
- foreach ( $exploded_outbound_resources as $a_resource ) {
245
- $results[ $i ][ 'outbound_resource' ] .= "<a class='inline-icon spaced slimstat-font-logout slimstat-tooltip-trigger' target='_blank' title='".htmlentities( __( 'Open this outbound link in a new window', 'wp-slimstat' ), ENT_QUOTES, 'UTF-8' ) . "' href='{$a_resource}'></a> {$a_resource}";
246
  }
247
  }
248
- else {
249
- $results[$i][ 'outbound_resource' ] = '';
250
- }
251
 
252
- if ( $current_user_can_delete ){
253
- $delete_row = "<a class='slimstat-delete-entry slimstat-font-cancel slimstat-tooltip-trigger' data-pageview-id='{$results[$i]['id']}' title='".htmlentities(__('Delete this entry from the database','wp-slimstat'), ENT_QUOTES, 'UTF-8')."' href='#'></a>";
254
- }
255
 
256
- // Login / Logout Event
257
- $login_logout = '';
258
- if ( strpos( $results[ $i ][ 'notes' ], 'loggedin:' ) !== false ) {
259
- $exploded_notes = explode( ';', $results[ $i ][ 'notes' ] );
260
- foreach ( $exploded_notes as $a_note ) {
261
- if ( strpos( $a_note, 'loggedin:' ) === false ) {
262
- continue;
263
- }
264
 
265
- $login_logout .= "<i class='slimstat-font-user-plus spaced slimstat-tooltip-trigger' title='" . __( 'User Logged In', 'wp-slimstat' ) . "'></i> " . str_replace( 'loggedin:', '', $a_note );
266
- }
267
- }
268
- if ( strpos( $results[ $i ][ 'notes' ], 'loggedout:' ) !== false ) {
269
- $exploded_notes = explode( ';', $results[ $i ][ 'notes' ] );
270
- foreach ( $exploded_notes as $a_note ) {
271
- if ( strpos( $a_note, 'loggedout:' ) === false ) {
272
- continue;
273
- }
274
-
275
- $login_logout .= "<i class='slimstat-font-user-times spaced slimstat-tooltip-trigger' title='" . __( 'User Logged Out', 'wp-slimstat' ) . "'></i> " . str_replace( 'loggedout:', '', $a_note );
276
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  }
278
  }
279
  else {
280
- $results[$i]['referer'] = $results[$i][ 'outbound_resource' ] = $results[$i][ 'content_type' ] = '';
281
  }
282
 
283
- $row_output = "<p>{$results[$i]['resource']} <span class='details'>$time_on_page $login_logout {$results[$i]['searchterms']} {$results[$i]['referer']} {$results[$i]['outbound_resource']} {$results[$i]['content_type']} $performance $date_time {$notes} {$delete_row}</span></p>";
 
 
284
 
285
- // Strip all the filter links, if this information is shown on the frontend
286
- if ( !is_admin() ) {
287
- $row_output = preg_replace('/<a (.*?)>(.*?)<\/a>/', "\\2", $row_output);
 
 
 
 
 
 
 
 
288
  }
 
 
 
 
 
 
289
 
290
- echo $row_output;
 
 
 
 
 
291
  }
292
 
293
- // Pagination
294
- if ( $count_page_results > 20 ) {
295
- echo wp_slimstat_reports::report_pagination( $count_page_results, $count_all_results, true, wp_slimstat::$settings[ 'number_results_raw_data' ] );
 
 
296
  }
 
 
 
 
 
 
 
297
  }
50
 
51
  if ($count_page_results == 0){
52
  echo '<p class="nodata">'.__('No data to display','wp-slimstat').'</p>';
53
+ return 0;
54
  }
 
55
 
56
+ // Pagination
57
+ echo wp_slimstat_reports::report_pagination( $count_page_results, $count_all_results, true, wp_slimstat::$settings[ 'number_results_raw_data' ] );
58
 
59
+ // Show delete button? (only those who can access the settings can see it)
60
+ $current_user_can_delete = ( current_user_can( wp_slimstat::$settings[ 'capability_can_admin' ] ) && !is_network_admin() );
61
+ $delete_row = '';
62
 
63
+ // Loop through the results
64
+ for ( $i=0; $i < $count_page_results; $i++ ) {
65
+ $host_by_ip = $results[ $i ][ 'ip' ];
66
+ if ( wp_slimstat::$settings[ 'convert_ip_addresses' ] == 'on' ) {
67
+ $gethostbyaddr = gethostbyaddr( $results[ $i ][ 'ip' ] );
68
+ if ( $gethostbyaddr != $host_by_ip && !empty( $gethostbyaddr ) ) {
69
+ $host_by_ip .= ', ' . $gethostbyaddr;
 
70
  }
71
+ }
72
 
73
+ $date_time = "<i class='spaced slimstat-font-clock slimstat-tooltip-trigger' title='".__( 'Date and Time', 'wp-slimstat' )."'></i> " . date_i18n( wp_slimstat::$settings[ 'date_format' ] . ' ' . wp_slimstat::$settings[ 'time_format' ], $results[ $i ][ 'dt' ], true );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
 
75
+ // Print visit header?
76
+ if ( $i == 0 || $results[ $i - 1 ][ 'visit_id' ] != $results[ $i ][ 'visit_id' ] || $results[ $i - 1 ][ 'ip' ] != $results[ $i ][ 'ip' ] || $results[ $i - 1 ][ 'browser' ] != $results[ $i ][ 'browser' ] || $results[ $i - 1 ][ 'platform' ] != $results[ $i ][ 'platform' ] || $results[ $i - 1 ][ 'username' ] != $results[ $i ][ 'username' ] ) {
 
 
77
 
78
+ // Color-coded headers
79
+ $highlight_row = !empty( $results[ $i ][ 'searchterms' ] ) ? ' is-search-engine' : ( ( $results[ $i ][ 'browser_type' ] != 1 ) ? ' is-direct' : '' );
 
 
 
 
 
 
80
 
81
+ // Country
82
+ $country_filtered = '';
83
+ if ( !empty( $results[ $i ][ 'country' ] ) && $results[ $i ][ 'country' ] != 'xx' ) {
84
+ $country_filtered = "<a class='slimstat-filter-link inline-icon' href='" . wp_slimstat_reports::fs_url( 'country equals ' . $results[ $i ][ 'country' ] ) . "'><img class='slimstat-tooltip-trigger' src='$plugin_url/images/flags/{$results[$i]['country']}.png' width='16' height='16' title='" . __( 'c-' . $results[ $i ][ 'country' ], 'wp-slimstat' ) . "'></a>";
85
+ }
 
 
 
 
 
 
 
 
 
 
86
 
87
+ // City, if tracked
88
+ $city_filtered = '';
89
+ if ( !empty( $results[ $i ][ 'city' ] ) ) {
90
+ $city_filtered = "<a class='slimstat-filter-link' href='" . wp_slimstat_reports::fs_url( 'city equals ' . $results[ $i ][ 'city' ] ) . "'>{$results[ $i ][ 'city' ]}</a>";
91
+ }
92
 
93
+ // Browser
94
+ if ( empty( $results[ $i ][ 'browser_version' ] ) ) {
95
+ $results[$i]['browser_version'] = '';
96
+ }
97
+ $browser_title = ( wp_slimstat::$settings[ 'show_complete_user_agent_tooltip' ] != 'on' ) ? "{$results[ $i ][ 'browser' ]} {$results[ $i ][ 'browser_version' ]}" : $results[ $i ][ 'user_agent' ];
98
+ $browser_icon = $plugin_url . '/images/browsers/other-browsers-and-os.png';
99
+ if ( in_array( $results[ $i ][ 'browser' ], $supported_browser_icons ) ) {
100
+ $browser_icon = $plugin_url . '/images/browsers/' . sanitize_title( $results[ $i ][ 'browser' ] ) . '.png';
101
+ }
102
+ $browser_filtered = "<a class='slimstat-filter-link inline-icon' href='" . wp_slimstat_reports::fs_url( 'browser equals ' . $results[ $i ][ 'browser' ] ) . "'><img class='slimstat-tooltip-trigger' src='$browser_icon' width='16' height='16' title='{$browser_title}'></a>";
103
 
104
+ // Platform
105
+ $platform_icon = $plugin_url . '/images/browsers/other-browsers-and-os.png';
106
+ if ( in_array( strtolower( $results[ $i ][ 'platform' ] ), $supported_os_icons ) ) {
107
+ $platform_icon = $plugin_url . '/images/platforms/' . sanitize_title( $results[ $i ][ 'platform' ] ) . '.png';
108
  }
109
+ $platform_filtered = "<a class='slimstat-filter-link inline-icon' href='" . wp_slimstat_reports::fs_url( 'platform equals ' . $results[ $i ][ 'platform' ] ) . "'><img class='slimstat-tooltip-trigger' src='$platform_icon' width='16' height='16' title='" . __( $results[ $i ][ 'platform' ], 'wp-slimstat' ) . "'></a>";
110
 
111
+ // Browser Type
112
+ $browser_type_filtered = '';
113
+ if ( $results[ $i ][ 'browser_type' ] != 0 ) {
114
+ $browser_type_filtered = "<a class='slimstat-filter-link inline-icon' href='" . wp_slimstat_reports::fs_url( 'browser_type equals ' . $results[ $i ][ 'browser_type' ] ) . "'><img class='slimstat-tooltip-trigger' src='$plugin_url/images/browsers/type{$results[$i]['browser_type']}.png' width='16' height='16' title='{$supported_browser_types[$results[$i]['browser_type']]}'></a>";
115
+ }
116
 
117
+ // IP Address and user
118
+ if ( empty( $results[ $i ][ 'username' ] ) ) {
119
+ $ip_address = "<a class='slimstat-filter-link' href='" . wp_slimstat_reports::fs_url( 'ip equals ' . $results[ $i ][ 'ip' ] ) . "'>$host_by_ip</a>";
 
 
120
  }
121
  else {
122
+ $display_user_name = $results[ $i ][ 'username' ];
123
+ if ( wp_slimstat::$settings[ 'show_display_name' ] == 'on' && strpos( $results[ $i ][ 'notes' ], 'user:' ) !== false ) {
124
+ $display_real_name = get_user_by( 'login', $results[ $i ][ 'username' ] );
125
+ if ( is_object( $display_real_name ) ) {
126
+ $display_user_name = $display_real_name->display_name;
 
 
127
  }
128
  }
129
+ $ip_address = "<a class='slimstat-filter-link' href='" . wp_slimstat_reports::fs_url( 'username equals ' . $results[ $i ][ 'username' ] ) . "'>{$display_user_name}</a>";
130
+ $ip_address .= " <a class='slimstat-filter-link' href='" . wp_slimstat_reports::fs_url( 'ip equals ' . $results[ $i ][ 'ip' ] ) . "'>($host_by_ip)</a>";
131
+ $highlight_row = ( strpos( $results[ $i ][ 'notes' ], 'user:' ) !== false ) ? ' is-known-user' : ' is-known-visitor';
132
  }
133
 
134
+ $whois_pin = '';
135
+ if ( is_admin() && !empty( wp_slimstat::$settings[ 'ip_lookup_service' ] ) && !wp_slimstat::is_local_ip_address( $results[ $i ][ 'ip' ] ) ) {
136
+ $whois_pin = "<a class='slimstat-font-location-1 whois' href='" . wp_slimstat::$settings[ 'ip_lookup_service' ] . "{$results[ $i ][ 'ip' ]}' target='_blank' title='WHOIS: {$results[ $i ][ 'ip' ]}'></a>";
137
  }
138
 
139
+ // Originating IP Address
140
+ $other_ip_address = intval( $results[ $i ][ 'other_ip' ] );
141
+ if ( !empty( $other_ip_address ) ) {
142
+ $other_ip_address = "<a class='slimstat-filter-link' href='" . wp_slimstat_reports::fs_url( 'other_ip equals '. $results[ $i ][ 'other_ip' ] ) . "'>(" . __( 'Originating IP', 'wp-slimstat' ) . ": {$results[$i]['other_ip']})</a>";
143
  }
144
  else {
145
+ $other_ip_address = '';
146
  }
147
 
148
+ // Plugins
149
+ $plugins = '';
150
+ if (!empty($results[$i]['plugins'])){
151
+ $results[$i]['plugins'] = explode(',', $results[$i]['plugins']);
152
+ foreach($results[$i]['plugins'] as $a_plugin){
153
+ $a_plugin = trim($a_plugin);
154
+ $plugins .= "<a class='slimstat-filter-link inline-icon' href='" . wp_slimstat_reports::fs_url( 'plugins contains ' . $a_plugin ) . "'><img class='slimstat-tooltip-trigger' src='$plugin_url/images/plugins/$a_plugin.png' width='16' height='16' title='" . __( $a_plugin, 'wp-slimstat' ) . "'></a> ";
155
+ }
156
  }
157
 
158
+ // Screen Resolution
159
+ $screen_resolution = '';
160
+ if ( !empty( $results[ $i ][ 'screen_width' ] ) && !empty( $results[ $i ][ 'screen_height' ] ) ) {
161
+ $screen_resolution = "<span class='pageview-screenres'>{$results[ $i ][ 'screen_width' ]}x{$results[ $i ][ 'screen_height' ]}</span>";
 
162
  }
163
 
164
+ $row_output = "<p class='header$highlight_row'>$browser_filtered $platform_filtered $browser_type_filtered $country_filtered $whois_pin $city_filtered $ip_address $other_ip_address <span class='plugins'>$plugins</span> $screen_resolution</p>";
165
+
166
+ // Strip all the filter links, if this information is shown on the frontend
167
+ if ( !is_admin() ) {
168
+ $row_output = preg_replace('/<a (.*?)>(.*?)<\/a>/', "\\2", $row_output);
169
  }
170
 
171
+ echo $row_output;
172
+ }
173
+
174
+ // Permalink: find post title, if available
175
+ $parse_url = parse_url(get_site_url(empty($results[$i]['blog_id'])?1:$results[$i]['blog_id']));
176
+ $base_host = $parse_url['host'];
177
+ $base_url = '';
178
 
179
+ if ( !empty( $results[ $i ][ 'resource' ] ) ) {
180
+ if (!empty($results[$i]['blog_id'])){
181
+ $base_url = $parse_url['scheme'].'://'.$base_host;
182
+ }
183
+ $results[$i]['resource'] = "<a class='slimstat-font-logout slimstat-tooltip-trigger' target='_blank' title='" . htmlentities( __( 'Open this URL in a new window', 'wp-slimstat' ), ENT_QUOTES, 'UTF-8' ) . "' href='" . $base_url . htmlentities( $results[$i][ 'resource' ], ENT_QUOTES, 'UTF-8' ) . "'></a> $base_url<a class='slimstat-filter-link' href='" . wp_slimstat_reports::fs_url( 'resource equals ' . htmlentities( $results[ $i ][ 'resource' ], ENT_QUOTES, 'UTF-8' ) ) . "'>" . wp_slimstat_reports::get_resource_title( $results[$i][ 'resource' ], $results[$i][ 'category' ] ) . '</a>';
184
+ }
185
+ else {
186
+ if ( !empty( $results[$i][ 'notes' ] ) ) {
187
+ $exploded_notes = explode( ';', $results[$i][ 'notes' ] );
188
+ foreach ( $exploded_notes as $a_note ) {
189
+ if ( strpos( $a_note, 'results:') !== false ) {
190
+ $search_terms_info = $results[ $i ][ 'searchterms' ] . ' (' . $a_note . ')';
191
+ break;
192
  }
193
  }
194
+ }
195
+ $results[$i]['resource'] = __( 'Local search results page', 'wp-slimstat' );
196
+ }
197
 
198
+ if ( empty( $search_terms_info ) ) {
199
+ $search_terms_info = wp_slimstat_reports::get_search_terms_info( $results[ $i ][ 'searchterms' ], $results[ $i ][ 'referer' ] );
200
+ }
201
 
202
+ // Search Terms, with link to original SERP, and Outbound Resource
203
+ if ( !empty( $search_terms_info ) ) {
204
+ $results[$i]['searchterms'] = "<i class='spaced slimstat-font-search' title='" . __( 'Search Terms', 'wp-slimstat' ) . "'></i> $search_terms_info";
205
+ }
206
+ else {
207
+ $results[$i]['searchterms'] = '';
208
+ }
 
209
 
210
+ // Let's reset this variable for the next item
211
+ $search_terms_info = '';
212
+
213
+ // Server Latency and Page Speed
214
+ $performance = '';
215
+ if ( !$is_dashboard && ( !empty( $results[ $i ][ 'server_latency' ] ) || !empty( $results[ $i ][ 'page_performance' ] ) ) ) {
216
+ $performance = "<i class='slimstat-font-gauge spaced slimstat-tooltip-trigger' title='".__('Server Latency and Page Speed in milliseconds','wp-slimstat')."'></i> ".__('SL','wp-slimstat').": {$results[$i]['server_latency']} / ".__('PS','wp-slimstat').": {$results[$i]['page_performance']}";
217
+ }
218
+
219
+ // Time on page
220
+ $time_on_page = '';
221
+ if ( !$is_dashboard && !empty( $results[ $i ][ 'dt_out' ] ) ) {
222
+ $duration = $results[ $i ][ 'dt_out' ] - $results[ $i ][ 'dt' ];
223
+ $time_on_page = "<i class='slimstat-font-stopwatch spaced slimstat-tooltip-trigger' title='" . __( 'Time spent on this page', 'wp-slimstat' ) . "'></i> " . date( ( $duration > 3599 ? 'H:i:s' : 'i:s' ), $duration );
224
+ }
225
+
226
+ // Pageview Notes
227
+ $notes = '';
228
+ if ( is_admin() && !empty( $results[ $i ][ 'notes' ] ) ) {
229
+ $notes = str_replace(array(';', ':'), array('<br/>', ': '), $results[$i]['notes']);
230
+ $notes = "<i class='slimstat-font-edit slimstat-tooltip-trigger'><b class='slimstat-tooltip-content'>{$notes}</b></i>";
231
+ }
232
+
233
+ // Avoid XSS attacks through the referer URL
234
+ $results[ $i ] [ 'referer' ] = str_replace( array( '<', '>', '%22', '%27', '\'', '"', '%3C', '%3E' ), array( '&lt;', '&gt;', '', '', '', '', '&lt;', '&gt;' ), urldecode( $results[ $i ] [ 'referer' ] ) );
235
+
236
+ $login_logout = '';
237
+ if ( !$is_dashboard ) {
238
+ $domain = parse_url( $results[ $i ] [ 'referer' ] );
239
+ $domain = !empty( $domain[ 'host' ] ) ? $domain[ 'host' ] : __( 'Invalid Referrer', 'wp-slimstat' );
240
+ $results[$i][ 'referer' ] = (!empty($results[$i]['referer']) && empty($results[$i]['searchterms']))?"<a class='spaced slimstat-font-login slimstat-tooltip-trigger' target='_blank' title='".htmlentities(__('Open this referrer in a new window','wp-slimstat'), ENT_QUOTES, 'UTF-8')."' href='{$results[$i]['referer']}'></a> $domain":'';
241
+ $results[$i][ 'content_type' ] = !empty($results[$i]['content_type'])?"<i class='spaced slimstat-font-doc slimstat-tooltip-trigger' title='".__('Content Type','wp-slimstat')."'></i> <a class='slimstat-filter-link' href='".wp_slimstat_reports::fs_url('content_type equals '.$results[$i]['content_type'])."'>{$results[$i]['content_type']}</a> ":'';
242
+
243
+ // The Outbound Links field might contain more than one link
244
+ if ( !empty( $results[ $i ][ 'outbound_resource' ] ) ) {
245
+ $exploded_outbound_resources = explode( ';;;', $results[ $i ][ 'outbound_resource' ] );
246
+ $results[$i][ 'outbound_resource' ] = '';
247
+ foreach ( $exploded_outbound_resources as $a_resource ) {
248
+ $results[ $i ][ 'outbound_resource' ] .= "<a class='inline-icon spaced slimstat-font-logout slimstat-tooltip-trigger' target='_blank' title='".htmlentities( __( 'Open this outbound link in a new window', 'wp-slimstat' ), ENT_QUOTES, 'UTF-8' ) . "' href='{$a_resource}'></a> {$a_resource}";
249
  }
250
  }
251
  else {
252
+ $results[$i][ 'outbound_resource' ] = '';
253
  }
254
 
255
+ if ( $current_user_can_delete ){
256
+ $delete_row = "<a class='slimstat-delete-entry slimstat-font-cancel slimstat-tooltip-trigger' data-pageview-id='{$results[$i]['id']}' title='".htmlentities(__('Delete this entry from the database','wp-slimstat'), ENT_QUOTES, 'UTF-8')."' href='#'></a>";
257
+ }
258
 
259
+ // Login / Logout Event
260
+ $login_logout = '';
261
+ if ( strpos( $results[ $i ][ 'notes' ], 'loggedin:' ) !== false ) {
262
+ $exploded_notes = explode( ';', $results[ $i ][ 'notes' ] );
263
+ foreach ( $exploded_notes as $a_note ) {
264
+ if ( strpos( $a_note, 'loggedin:' ) === false ) {
265
+ continue;
266
+ }
267
+
268
+ $login_logout .= "<i class='slimstat-font-user-plus spaced slimstat-tooltip-trigger' title='" . __( 'User Logged In', 'wp-slimstat' ) . "'></i> " . str_replace( 'loggedin:', '', $a_note );
269
+ }
270
  }
271
+ if ( strpos( $results[ $i ][ 'notes' ], 'loggedout:' ) !== false ) {
272
+ $exploded_notes = explode( ';', $results[ $i ][ 'notes' ] );
273
+ foreach ( $exploded_notes as $a_note ) {
274
+ if ( strpos( $a_note, 'loggedout:' ) === false ) {
275
+ continue;
276
+ }
277
 
278
+ $login_logout .= "<i class='slimstat-font-user-times spaced slimstat-tooltip-trigger' title='" . __( 'User Logged Out', 'wp-slimstat' ) . "'></i> " . str_replace( 'loggedout:', '', $a_note );
279
+ }
280
+ }
281
+ }
282
+ else {
283
+ $results[$i]['referer'] = $results[$i][ 'outbound_resource' ] = $results[$i][ 'content_type' ] = '';
284
  }
285
 
286
+ $row_output = "<p>{$results[$i]['resource']} <span class='details'>$time_on_page $login_logout {$results[$i]['searchterms']} {$results[$i]['referer']} {$results[$i]['outbound_resource']} {$results[$i]['content_type']} $performance $date_time {$notes} {$delete_row}</span></p>";
287
+
288
+ // Strip all the filter links, if this information is shown on the frontend
289
+ if ( !is_admin() ) {
290
+ $row_output = preg_replace('/<a (.*?)>(.*?)<\/a>/', "\\2", $row_output);
291
  }
292
+
293
+ echo $row_output;
294
+ }
295
+
296
+ // Pagination
297
+ if ( $count_page_results > 20 ) {
298
+ echo wp_slimstat_reports::report_pagination( $count_page_results, $count_all_results, true, wp_slimstat::$settings[ 'number_results_raw_data' ] );
299
  }
admin/view/wp-slimstat-db.php CHANGED
@@ -19,6 +19,9 @@ class wp_slimstat_db {
19
  // Debug message
20
  public static $debug_message = '';
21
 
 
 
 
22
  /*
23
  * Sets the filters and other structures needed to store the data retrieved from the DB
24
  */
@@ -91,12 +94,14 @@ class wp_slimstat_db {
91
  self::$all_columns_names = array_merge( array(
92
 
93
  // Date and Time
 
94
  'hour' => array( __( 'Hour', 'wp-slimstat' ), 'int' ),
95
  'day' => array( __( 'Day', 'wp-slimstat' ), 'int' ),
96
  'month' => array( __( 'Month', 'wp-slimstat' ), 'int' ),
97
  'year' => array( __( 'Year', 'wp-slimstat' ), 'int' ),
98
  'interval' => array( __( 'days', 'wp-slimstat' ), 'int' ),
99
  'interval_hours' => array( __( 'hours', 'wp-slimstat' ), 'int' ),
 
100
  'dt' => array( __( 'Timestamp', 'wp-slimstat' ), 'int' ),
101
  'dt_out' => array( __( 'Exit Timestamp', 'wp-slimstat' ), 'int' ),
102
 
@@ -108,6 +113,7 @@ class wp_slimstat_db {
108
  'metric' => array( __( 'Metric', 'wp-slimstat' ), 'varchar' ),
109
  'value' => array( __( 'Value', 'wp-slimstat' ), 'varchar' ),
110
  'counthits' => array( __( 'Hits', 'wp-slimstat' ), 'int' ),
 
111
  'percentage' => array( __( 'Percentage', 'wp-slimstat' ), 'int' ),
112
  'tooltip' => array( __( 'Notes', 'wp-slimstat' ), 'varchar' ),
113
  'details' => array( __( 'Notes', 'wp-slimstat' ), 'varchar' ),
@@ -132,13 +138,13 @@ class wp_slimstat_db {
132
  $filters_array = array();
133
 
134
  // Filters are set via javascript as hidden fields and submitted as a POST request. They override anything passed through the regular input fields
135
- if ( !empty( $_POST[ 'fs' ] ) && is_array( $_POST[ 'fs' ] ) ) {
136
- foreach( $_POST[ 'fs' ] as $a_request_filter_name => $a_request_filter_value ) {
137
  $filters_array[ htmlspecialchars( $a_request_filter_name ) ] = "$a_request_filter_name $a_request_filter_value";
138
  }
139
  }
140
 
141
- // Date filters (input fields)
142
  foreach ( array( 'hour', 'day', 'month', 'year', 'interval', 'interval_hours' ) as $a_date_time_filter_name ) {
143
  if ( isset( $_POST[ $a_date_time_filter_name ] ) && strlen( $_POST[ $a_date_time_filter_name ] ) > 0 ) { // here we use isset instead of !empty to handle ZERO as a valid input value
144
  $filters_array[ $a_date_time_filter_name ] = "$a_date_time_filter_name equals " . intval( $_POST[ $a_date_time_filter_name ] );
@@ -178,6 +184,9 @@ class wp_slimstat_db {
178
 
179
  // Normalize the filters
180
  self::$filters_normalized = self::init_filters( $filters_raw );
 
 
 
181
  }
182
  // end init
183
 
@@ -270,18 +279,18 @@ class wp_slimstat_db {
270
  /**
271
  * Translates user-friendly operators into SQL conditions
272
  */
273
- public static function get_single_where_clause( $_column = 'id', $_operator = 'equals', $_value = '', $_slim_stats_table_alias = '' ) {
274
- $filter_empty = ( !empty( self::$columns_names[ $_column ] ) && self::$columns_names[ $_column ] [ 1 ] == 'varchar' ) ? 'IS NULL' : '= 0';
275
- $filter_not_empty = ( !empty( self::$columns_names[ $_column ] ) && self::$columns_names[ $_column ] [ 1 ] == 'varchar' ) ? 'IS NOT NULL' : '<> 0';
276
 
277
- $_column = str_replace( '_calculated', '', $_column );
278
 
279
- $column_with_alias = $_column;
280
  if ( !empty( $_slim_stats_table_alias ) ) {
281
- $column_with_alias = $_slim_stats_table_alias . '.' . $_column;
282
  }
283
 
284
- switch( $_column ) {
285
  case 'ip':
286
  case 'other_ip':
287
  $filter_empty = '= "0.0.0.0"';
@@ -297,28 +306,28 @@ class wp_slimstat_db {
297
  break;
298
 
299
  case 'contains':
300
- $where = array( "$column_with_alias LIKE %s", '%'.$_value.'%' );
301
  break;
302
 
303
  case 'includes_in_set':
304
  case 'included_in_set':
305
- $where[ 0 ] = "FIND_IN_SET($column_with_alias, %s) > 0";
306
  break;
307
 
308
  case 'does_not_contain':
309
- $where = array( "$column_with_alias NOT LIKE %s", '%'.$_value.'%' );
310
  break;
311
 
312
  case 'starts_with':
313
- $where = array( "$column_with_alias LIKE %s", $_value.'%' );
314
  break;
315
 
316
  case 'ends_with':
317
- $where = array( "$column_with_alias LIKE %s", '%'.$_value );
318
  break;
319
 
320
  case 'sounds_like':
321
- $where[ 0 ] = "SOUNDEX($column_with_alias) = SOUNDEX(%s)";
322
  break;
323
 
324
  case 'is_empty':
@@ -403,12 +412,14 @@ class wp_slimstat_db {
403
  case 'strtotime':
404
  $custom_date = strtotime( $a_filter[ 3 ], date_i18n( 'U' ) );
405
 
 
406
  $filters_parsed[ 'date' ][ 'hour' ] = intval( date( 'H', $custom_date ) );
407
  $filters_parsed[ 'date' ][ 'day' ] = intval( date( 'j', $custom_date ) );
408
  $filters_parsed[ 'date' ][ 'month' ] = intval( date( 'n', $custom_date ) );
409
  $filters_parsed[ 'date' ][ 'year' ] = intval( date( 'Y', $custom_date ) );
410
  break;
411
 
 
412
  case 'hour':
413
  case 'day':
414
  case 'month':
@@ -419,6 +430,10 @@ class wp_slimstat_db {
419
  else{
420
  // Try to apply strtotime to value
421
  switch( $a_filter[ 1 ] ) {
 
 
 
 
422
  case 'hour':
423
  $filters_parsed[ 'date' ][ 'hour' ] = intval( date( 'H', strtotime( $a_filter[ 3 ], date_i18n( 'U' ) ) ) );
424
  break;
@@ -447,8 +462,8 @@ class wp_slimstat_db {
447
 
448
  case 'interval':
449
  case 'interval_hours':
450
- $intval_filter = intval( $a_filter[ 3 ] );
451
- $filters_parsed[ 'date' ][ $a_filter[ 1 ] ] = $intval_filter;
452
  break;
453
 
454
  case 'limit_results':
@@ -497,7 +512,8 @@ class wp_slimstat_db {
497
 
498
  // Intervals
499
  // If neither an interval nor interval_hours were specified...
500
- if ( !isset( $fn[ 'date' ][ 'interval_hours' ] ) && empty( $fn[ 'date' ][ 'interval' ] ) ) {
 
501
  $fn[ 'date' ][ 'interval_hours' ] = 0;
502
 
503
  // If a day has been specified, then interval = 1 (show only that day)
@@ -513,16 +529,22 @@ class wp_slimstat_db {
513
  $fn[ 'date' ][ 'interval' ] = - intval( date_i18n( 'j' ) );
514
  }
515
  }
516
- else if ( empty( $fn[ 'date' ][ 'interval_hours' ] ) ) {
517
- // interval was set, but not interval_hours
518
- $fn[ 'date' ][ 'interval_hours' ] = 0;
519
- }
520
- else if ( empty( $fn[ 'date' ][ 'interval' ] ) ) {
521
- // interval_hours was set, but not interval
522
- $fn[ 'date' ][ 'interval' ] = 0;
 
 
 
 
 
 
523
  }
524
 
525
- $fn[ 'utime' ][ 'range' ] = $fn[ 'date' ][ 'interval' ] * 86400 + $fn[ 'date' ][ 'interval_hours' ] * 3600;
526
 
527
  // Day
528
  if ( empty( $fn[ 'date' ][ 'day' ] ) ) {
@@ -542,7 +564,7 @@ class wp_slimstat_db {
542
  if ( $fn[ 'utime' ][ 'range' ] < 0 ) {
543
  $fn[ 'utime' ][ 'end' ] = mktime(
544
  !empty( $fn[ 'date' ][ 'hour' ] ) ? $fn[ 'date' ][ 'hour' ] : 23,
545
- 59,
546
  59,
547
  $fn[ 'date' ][ 'month' ],
548
  $fn[ 'date' ][ 'day' ],
@@ -563,7 +585,7 @@ class wp_slimstat_db {
563
  else {
564
  $fn[ 'utime' ][ 'start' ] = mktime(
565
  !empty( $fn[ 'date' ][ 'hour' ] ) ? $fn[ 'date' ][ 'hour' ] : 0,
566
- 0,
567
  0,
568
  $fn[ 'date' ][ 'month' ],
569
  $fn[ 'date' ][ 'day' ],
@@ -645,6 +667,39 @@ class wp_slimstat_db {
645
  'SUM(counthits) AS counthits' ) );
646
  }
647
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
648
  public static function get_data_for_chart( $_args = array() ) {
649
  // Determine the chart granularity based on the date range
650
  // - Up to 24 hours (86400 seconds): HOURLY
@@ -719,8 +774,6 @@ class wp_slimstat_db {
719
  $output[ $i ][ 'v4' ] = $output[ $i ][ 'v3' ] = $output[ $i ][ 'v2' ] = $output[ $i ][ 'v1' ] = 0;
720
  }
721
 
722
-
723
-
724
  // Now populate all the data points
725
  foreach ( $results as $a_result ) {
726
  $label = date( $params[ 'data_points_label' ], $a_result[ 'dt' ] );
@@ -759,6 +812,28 @@ class wp_slimstat_db {
759
  return number_format( $table_size, 2, self::$formats[ 'decimal' ], self::$formats[ 'thousand' ] ).' '.$suffix;
760
  }
761
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
762
  public static function get_max_and_average_pages_per_visit() {
763
  $where = self::get_combined_where( 'visit_id > 0' );
764
 
@@ -784,47 +859,98 @@ class wp_slimstat_db {
784
  'MIN(dt)' );
785
  }
786
 
787
- public static function get_recent( $_column = 'id', $_where = '', $_having = '', $_use_date_filters = true, $_as_column = '', $_more_columns = '' ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
788
  // This function can be passed individual arguments, or an array of arguments
789
- if ( is_array( $_column ) ) {
790
- $_where = !empty( $_column[ 'where' ] ) ? $_column[ 'where' ] : '';
791
- $_having = !empty( $_column[ 'having' ] ) ? $_column[ 'having' ] : '';
792
- $_use_date_filters = !empty( $_column[ 'use_date_filters' ] ) ? $_column[ 'use_date_filters' ] : true;
793
- $_as_column = !empty( $_column[ 'as_column' ] ) ? $_column[ 'as_column' ] : '';
794
- $_more_columns = !empty( $_column[ 'more_columns' ] ) ? $_column[ 'more_columns' ] : '';
795
- $_column = $_column[ 'columns' ];
 
796
  }
797
 
798
- $columns = $_column;
799
  if ( !empty( $_as_column ) ) {
800
- $columns = "$_column AS $_as_column";
801
  }
802
 
803
- if ( $_column != '*' ) {
804
- $columns .= ', ip, dt';
805
  }
806
  else {
807
- $columns = 'id, ip, other_ip, username, country, city, location, referer, resource, searchterms, plugins, notes, visit_id, server_latency, page_performance, browser, browser_version, browser_type, platform, language, user_agent, resolution, screen_width, screen_height, content_type, category, author, content_id, outbound_resource, dt_out, dt';
808
  }
809
 
810
- if ( !empty( $_more_columns ) ) {
811
- $columns .= ', ' . $_more_columns;
812
  }
813
 
814
- $_where = self::get_combined_where( $_where, $_column, $_use_date_filters );
815
 
816
  $results = self::get_results( "
817
- SELECT $columns
818
  FROM {$GLOBALS['wpdb']->prefix}slim_stats
819
  WHERE $_where
820
- ORDER BY dt DESC
821
  LIMIT 0, " . self::$filters_normalized[ 'misc' ][ 'limit_results' ],
822
- $columns,
823
  'dt DESC' );
824
 
825
- if ( $_column != '*' ) {
826
- $column_values = array_map( 'unserialize', array_unique( array_map( 'serialize', self::array_column( $results, explode( ',', $_column ) ) ) ) );
827
- $results = array_intersect_key( $results, $column_values );
828
  }
829
 
830
  return $results;
@@ -863,7 +989,7 @@ class wp_slimstat_db {
863
  return $clean_outbound_resources;
864
  }
865
 
866
- public static function get_top( $_column = 'id', $_where = '', $_having = '', $_use_date_filters = true, $_as_column = '' ){
867
  // This function can be passed individual arguments, or an array of arguments
868
  if ( is_array( $_column ) ) {
869
  $_where = !empty( $_column[ 'where' ] ) ? $_column[ 'where' ] : '';
@@ -976,6 +1102,196 @@ class wp_slimstat_db {
976
  return $sorted_outbound_resources;
977
  }
978
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
979
  protected static function array_column( $input = array(), $columns = array() ) {
980
  $output = array();
981
 
19
  // Debug message
20
  public static $debug_message = '';
21
 
22
+ // Useful data for the reports
23
+ public static $pageviews = 0;
24
+
25
  /*
26
  * Sets the filters and other structures needed to store the data retrieved from the DB
27
  */
94
  self::$all_columns_names = array_merge( array(
95
 
96
  // Date and Time
97
+ 'minute' => array( __( 'Minute', 'wp-slimstat' ), 'int' ),
98
  'hour' => array( __( 'Hour', 'wp-slimstat' ), 'int' ),
99
  'day' => array( __( 'Day', 'wp-slimstat' ), 'int' ),
100
  'month' => array( __( 'Month', 'wp-slimstat' ), 'int' ),
101
  'year' => array( __( 'Year', 'wp-slimstat' ), 'int' ),
102
  'interval' => array( __( 'days', 'wp-slimstat' ), 'int' ),
103
  'interval_hours' => array( __( 'hours', 'wp-slimstat' ), 'int' ),
104
+ 'interval_minutes' => array( __( 'minutes', 'wp-slimstat' ), 'int' ),
105
  'dt' => array( __( 'Timestamp', 'wp-slimstat' ), 'int' ),
106
  'dt_out' => array( __( 'Exit Timestamp', 'wp-slimstat' ), 'int' ),
107
 
113
  'metric' => array( __( 'Metric', 'wp-slimstat' ), 'varchar' ),
114
  'value' => array( __( 'Value', 'wp-slimstat' ), 'varchar' ),
115
  'counthits' => array( __( 'Hits', 'wp-slimstat' ), 'int' ),
116
+ 'column_group' => array( __( 'Grouped Value', 'wp-slimstat' ), 'varchar' ),
117
  'percentage' => array( __( 'Percentage', 'wp-slimstat' ), 'int' ),
118
  'tooltip' => array( __( 'Notes', 'wp-slimstat' ), 'varchar' ),
119
  'details' => array( __( 'Notes', 'wp-slimstat' ), 'varchar' ),
138
  $filters_array = array();
139
 
140
  // Filters are set via javascript as hidden fields and submitted as a POST request. They override anything passed through the regular input fields
141
+ if ( !empty( $_REQUEST[ 'fs' ] ) && is_array( $_REQUEST[ 'fs' ] ) ) {
142
+ foreach( $_REQUEST[ 'fs' ] as $a_request_filter_name => $a_request_filter_value ) {
143
  $filters_array[ htmlspecialchars( $a_request_filter_name ) ] = "$a_request_filter_name $a_request_filter_value";
144
  }
145
  }
146
 
147
+ // Date filters (input fields) - Please note: interval_minutes is not exposed via the web interface, that's why it's not listed here below
148
  foreach ( array( 'hour', 'day', 'month', 'year', 'interval', 'interval_hours' ) as $a_date_time_filter_name ) {
149
  if ( isset( $_POST[ $a_date_time_filter_name ] ) && strlen( $_POST[ $a_date_time_filter_name ] ) > 0 ) { // here we use isset instead of !empty to handle ZERO as a valid input value
150
  $filters_array[ $a_date_time_filter_name ] = "$a_date_time_filter_name equals " . intval( $_POST[ $a_date_time_filter_name ] );
184
 
185
  // Normalize the filters
186
  self::$filters_normalized = self::init_filters( $filters_raw );
187
+
188
+ // Retrieve data that will be used by multiple reports
189
+ self::$pageviews = wp_slimstat_db::count_records();
190
  }
191
  // end init
192
 
279
  /**
280
  * Translates user-friendly operators into SQL conditions
281
  */
282
+ public static function get_single_where_clause( $_dimension = 'id', $_operator = 'equals', $_value = '', $_slim_stats_table_alias = '' ) {
283
+ $filter_empty = ( !empty( self::$columns_names[ $_dimension ] ) && self::$columns_names[ $_dimension ] [ 1 ] == 'varchar' ) ? 'IS NULL' : '= 0';
284
+ $filter_not_empty = ( !empty( self::$columns_names[ $_dimension ] ) && self::$columns_names[ $_dimension ] [ 1 ] == 'varchar' ) ? 'IS NOT NULL' : '<> 0';
285
 
286
+ $_dimension = str_replace( '_calculated', '', $_dimension );
287
 
288
+ $column_with_alias = $_dimension;
289
  if ( !empty( $_slim_stats_table_alias ) ) {
290
+ $column_with_alias = $_slim_stats_table_alias . '.' . $_dimension;
291
  }
292
 
293
+ switch( $_dimension ) {
294
  case 'ip':
295
  case 'other_ip':
296
  $filter_empty = '= "0.0.0.0"';
306
  break;
307
 
308
  case 'contains':
309
+ $where = array( "$column_with_alias LIKE %s", '%' . $_value . '%' );
310
  break;
311
 
312
  case 'includes_in_set':
313
  case 'included_in_set':
314
+ $where[ 0 ] = "FIND_IN_SET( $column_with_alias, %s ) > 0";
315
  break;
316
 
317
  case 'does_not_contain':
318
+ $where = array( "$column_with_alias NOT LIKE %s", '%' . $_value . '%' );
319
  break;
320
 
321
  case 'starts_with':
322
+ $where = array( "$column_with_alias LIKE %s", $_value . '%' );
323
  break;
324
 
325
  case 'ends_with':
326
+ $where = array( "$column_with_alias LIKE %s", '%' . $_value );
327
  break;
328
 
329
  case 'sounds_like':
330
+ $where[ 0 ] = "SOUNDEX( $column_with_alias ) = SOUNDEX( %s )";
331
  break;
332
 
333
  case 'is_empty':
412
  case 'strtotime':
413
  $custom_date = strtotime( $a_filter[ 3 ], date_i18n( 'U' ) );
414
 
415
+ $filters_parsed[ 'date' ][ 'minute' ] = intval( date( 'i', $custom_date ) );
416
  $filters_parsed[ 'date' ][ 'hour' ] = intval( date( 'H', $custom_date ) );
417
  $filters_parsed[ 'date' ][ 'day' ] = intval( date( 'j', $custom_date ) );
418
  $filters_parsed[ 'date' ][ 'month' ] = intval( date( 'n', $custom_date ) );
419
  $filters_parsed[ 'date' ][ 'year' ] = intval( date( 'Y', $custom_date ) );
420
  break;
421
 
422
+ case 'minute':
423
  case 'hour':
424
  case 'day':
425
  case 'month':
430
  else{
431
  // Try to apply strtotime to value
432
  switch( $a_filter[ 1 ] ) {
433
+ case 'minute':
434
+ $filters_parsed[ 'date' ][ 'minute' ] = intval( date( 'i', strtotime( $a_filter[ 3 ], date_i18n( 'U' ) ) ) );
435
+ break;
436
+
437
  case 'hour':
438
  $filters_parsed[ 'date' ][ 'hour' ] = intval( date( 'H', strtotime( $a_filter[ 3 ], date_i18n( 'U' ) ) ) );
439
  break;
462
 
463
  case 'interval':
464
  case 'interval_hours':
465
+ case 'interval_minutes':
466
+ $filters_parsed[ 'date' ][ $a_filter[ 1 ] ] = intval( $a_filter[ 3 ] );
467
  break;
468
 
469
  case 'limit_results':
512
 
513
  // Intervals
514
  // If neither an interval nor interval_hours were specified...
515
+ if ( !isset( $fn[ 'date' ][ 'interval_minutes' ] ) && !isset( $fn[ 'date' ][ 'interval_hours' ] ) && !isset( $fn[ 'date' ][ 'interval' ] ) ) {
516
+ $fn[ 'date' ][ 'interval_minutes' ] = 0;
517
  $fn[ 'date' ][ 'interval_hours' ] = 0;
518
 
519
  // If a day has been specified, then interval = 1 (show only that day)
529
  $fn[ 'date' ][ 'interval' ] = - intval( date_i18n( 'j' ) );
530
  }
531
  }
532
+ else {
533
+ if ( empty( $fn[ 'date' ][ 'interval_minutes' ] ) ) {
534
+ // interval was set, but not interval_hours
535
+ $fn[ 'date' ][ 'interval_minutes' ] = 0;
536
+ }
537
+ if ( empty( $fn[ 'date' ][ 'interval_hours' ] ) ) {
538
+ // interval_hours was set, but not interval
539
+ $fn[ 'date' ][ 'interval_hours' ] = 0;
540
+ }
541
+ if ( empty( $fn[ 'date' ][ 'interval' ] ) ) {
542
+ // interval_hours was set, but not interval
543
+ $fn[ 'date' ][ 'interval' ] = 0;
544
+ }
545
  }
546
 
547
+ $fn[ 'utime' ][ 'range' ] = $fn[ 'date' ][ 'interval' ] * 86400 + $fn[ 'date' ][ 'interval_hours' ] * 3600 + $fn[ 'date' ][ 'interval_minutes' ] * 60;
548
 
549
  // Day
550
  if ( empty( $fn[ 'date' ][ 'day' ] ) ) {
564
  if ( $fn[ 'utime' ][ 'range' ] < 0 ) {
565
  $fn[ 'utime' ][ 'end' ] = mktime(
566
  !empty( $fn[ 'date' ][ 'hour' ] ) ? $fn[ 'date' ][ 'hour' ] : 23,
567
+ !empty( $fn[ 'date' ][ 'minute' ] ) ? $fn[ 'date' ][ 'minute' ] : 59,
568
  59,
569
  $fn[ 'date' ][ 'month' ],
570
  $fn[ 'date' ][ 'day' ],
585
  else {
586
  $fn[ 'utime' ][ 'start' ] = mktime(
587
  !empty( $fn[ 'date' ][ 'hour' ] ) ? $fn[ 'date' ][ 'hour' ] : 0,
588
+ !empty( $fn[ 'date' ][ 'minute' ] ) ? $fn[ 'date' ][ 'minute' ] : 0,
589
  0,
590
  $fn[ 'date' ][ 'month' ],
591
  $fn[ 'date' ][ 'day' ],
667
  'SUM(counthits) AS counthits' ) );
668
  }
669
 
670
+ public static function get_about_wpslimstat() {
671
+ $dt = wp_slimstat_db::get_oldest_visit( '1=1', false );
672
+ $results = array();
673
+
674
+ $results[ 0 ][ 'metric' ] = __( 'Dataset Size', 'wp-slimstat' );
675
+ $results[ 0 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'id', '1=1', false ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
676
+ $results[ 0 ][ 'tooltip' ] = __( 'Total number of records stored in the database.', 'wp-slimstat' );
677
+
678
+ $results[ 1 ][ 'metric' ] = __( 'DB Size', 'wp-slimstat' );
679
+ $results[ 1 ][ 'value' ] = wp_slimstat_db::get_data_size();
680
+
681
+ $results[ 2 ][ 'metric' ] = __( 'Tracking Enabled', 'wp-slimstat' );
682
+ $results[ 2 ][ 'value' ] = __( ucfirst( wp_slimstat::$settings[ 'is_tracking' ] ), 'wp-slimstat' );
683
+
684
+ $results[ 3 ][ 'metric' ] = __( 'Javascript Mode', 'wp-slimstat' );
685
+ $results[ 3 ][ 'value' ] = __( ucfirst( wp_slimstat::$settings[ 'javascript_mode' ] ), 'wp-slimstat' );
686
+
687
+ $results[ 4 ][ 'metric' ] = __( 'Tracking Browser Caps', 'wp-slimstat' );
688
+ $results[ 4 ][ 'value' ] = __( ucfirst( wp_slimstat::$settings[ 'enable_javascript' ] ), 'wp-slimstat' );
689
+
690
+ $results[ 5 ][ 'metric' ] = __( 'Auto purge', 'wp-slimstat' );
691
+ $results[ 5 ][ 'value' ] = ( wp_slimstat::$settings[ 'auto_purge' ] > 0 ) ? wp_slimstat::$settings[ 'auto_purge' ] . ' ' . __( 'days', 'wp-slimstat' ) : __( 'Off', 'wp-slimstat' );
692
+
693
+ $results[ 6 ][ 'metric' ] = __( 'Oldest pageview', 'wp-slimstat' );
694
+ $results[ 6 ][ 'value' ] = ( $dt == null ) ? __( 'No visits', 'wp-slimstat' ) : date_i18n( wp_slimstat::$settings[ 'date_format' ], $dt );
695
+
696
+ $results[ 7 ][ 'metric' ] = __( 'Geolocation', 'wp-slimstat' );
697
+ $results[ 7 ][ 'value' ] = date_i18n( wp_slimstat::$settings[ 'date_format' ], @filemtime( wp_slimstat::$maxmind_path ) );
698
+ $results[ 7 ][ 'tooltip' ] = __( 'Date when the MaxMind Geolocation database was last updated.', 'wp-slimstat' );
699
+
700
+ return $results;
701
+ }
702
+
703
  public static function get_data_for_chart( $_args = array() ) {
704
  // Determine the chart granularity based on the date range
705
  // - Up to 24 hours (86400 seconds): HOURLY
774
  $output[ $i ][ 'v4' ] = $output[ $i ][ 'v3' ] = $output[ $i ][ 'v2' ] = $output[ $i ][ 'v1' ] = 0;
775
  }
776
 
 
 
777
  // Now populate all the data points
778
  foreach ( $results as $a_result ) {
779
  $label = date( $params[ 'data_points_label' ], $a_result[ 'dt' ] );
812
  return number_format( $table_size, 2, self::$formats[ 'decimal' ], self::$formats[ 'thousand' ] ).' '.$suffix;
813
  }
814
 
815
+ public static function get_group_by( $_args = array() ) {
816
+ $where = self::get_combined_where();
817
+
818
+ if ( empty( $_args[ 'column_group' ] ) ) {
819
+ $_args[ 'column_group' ] = 'id';
820
+ }
821
+
822
+ if ( empty( $_args[ 'group_by' ] ) ) {
823
+ $_args[ 'group_by' ] = 'id';
824
+ }
825
+
826
+ return self::get_results( "
827
+ SELECT {$_args[ 'group_by' ]}, COUNT(*) AS counthits, GROUP_CONCAT( DISTINCT {$_args[ 'column_group' ]} SEPARATOR ';;;' ) as column_group
828
+ FROM {$GLOBALS['wpdb']->prefix}slim_stats
829
+ WHERE $where AND {$_args[ 'group_by' ]} IS NOT NULL
830
+ GROUP BY {$_args[ 'group_by' ]}
831
+ ORDER BY counthits DESC
832
+ LIMIT 0, " . self::$filters_normalized[ 'misc' ][ 'limit_results' ],
833
+ $_args[ 'group_by' ],
834
+ $_args[ 'group_by' ] . ' ASC' );
835
+ }
836
+
837
  public static function get_max_and_average_pages_per_visit() {
838
  $where = self::get_combined_where( 'visit_id > 0' );
839
 
859
  'MIN(dt)' );
860
  }
861
 
862
+ public static function get_overview_summary() {
863
+ $days_in_range = ceil( ( wp_slimstat_db::$filters_normalized[ 'utime' ][ 'end' ] - wp_slimstat_db::$filters_normalized[ 'utime' ][ 'start' ] ) / 86400 );
864
+ $results = array();
865
+
866
+ $results[ 0 ][ 'metric' ] = __( 'Pageviews', 'wp-slimstat' );
867
+ $results[ 0 ][ 'value' ] = number_format( self::$pageviews, 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
868
+ $results[ 0 ][ 'tooltip' ] = __( 'A request to load a single HTML file. Slimstat logs a "pageview" each time the tracking code is executed.', 'wp-slimstat' );
869
+
870
+ $results[ 1 ][ 'metric' ] = __( 'Days in Range', 'wp-slimstat' );
871
+ $results[ 1 ][ 'value' ] = $days_in_range;
872
+
873
+ $results[ 2 ][ 'metric' ] = __( 'Average Daily Pageviews', 'wp-slimstat' );
874
+ $results[ 2 ][ 'value' ] = number_format( round( self::$pageviews / $days_in_range, 0 ), 0, '', wp_slimstat_db::$formats['thousand'] );
875
+ $results[ 2 ][ 'tooltip' ] = __( 'How many pages have been visited on average every day during the current period.', 'wp-slimstat' );
876
+
877
+ $results[ 3 ][ 'metric' ] = __( 'From Search Results', 'wp-slimstat' );
878
+ $results[ 3 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'id', 'searchterms IS NOT NULL' ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
879
+ $results[ 3 ][ 'tooltip' ] = __( 'Visitors who landed on your site after searching for a keyword on Google, Yahoo, etc.', 'wp-slimstat' );
880
+
881
+ $results[ 4 ][ 'metric' ] = __( 'Unique IPs', 'wp-slimstat' );
882
+ $results[ 4 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'ip' ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
883
+ $results[ 4 ][ 'tooltip' ] = __( 'Used to differentiate between multiple requests to download a file from one internet address (IP) and requests originating from many distinct addresses', 'wp-slimstat' );
884
+
885
+ $results[ 5 ][ 'metric' ] = __( 'Last 30 minutes', 'wp-slimstat' );
886
+ $results[ 5 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'id', 'dt > ' . ( date_i18n( 'U' ) - 1800 ), false ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
887
+
888
+ $results[ 6 ][ 'metric' ] = __( 'Today', 'wp-slimstat' );
889
+ $results[ 6 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'id', 'dt > ' . ( date_i18n( 'U', mktime( 0, 0, 0, date_i18n( 'm' ), date_i18n( 'd' ), date_i18n( 'Y' ) ) ) ), false ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
890
+
891
+ $results[ 7 ][ 'metric' ] = __( 'Yesterday', 'wp-slimstat' );
892
+ $results[ 7 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'id', 'dt BETWEEN ' . ( date_i18n( 'U', mktime( 0, 0, 0, date_i18n( 'm' ), date_i18n( 'd' ) - 1, date_i18n( 'Y' ) ) ) ) . ' AND ' . ( date_i18n( 'U', mktime( 23, 59, 59, date_i18n( 'm' ), date_i18n( 'd' ) - 1, date_i18n( 'Y' ) ) ) ), false ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
893
+
894
+ return $results;
895
+ }
896
+
897
+ public static function get_plugins() {
898
+ $wp_slim_plugins = array( 'flash', 'silverlight', 'acrobat', 'java', 'mediaplayer', 'director', 'real', 'quicktime' );
899
+ $total_human_hits = wp_slimstat_db::count_records( 'id', 'visit_id > 0 AND browser_type <> 1' );
900
+ $results = array();
901
+
902
+ foreach ( $wp_slim_plugins as $i => $a_plugin ) {
903
+ $count_results = wp_slimstat_db::count_records( 'id', "plugins LIKE '%{$a_plugin}%'" );
904
+ $results[ $i ][ 'metric' ] = ucfirst( $a_plugin );
905
+ $results[ $i ][ 'value' ] = ( $total_human_hits > 0 ) ? number_format( ( 100 * $count_results / $total_human_hits ), 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] ) : 0;
906
+ $results[ $i ][ 'details' ] = __( 'Hits', 'wp-slimstat' ) . ": $count_results";
907
+ }
908
+
909
+ return $results;
910
+ }
911
+
912
+ public static function get_recent( $_dimension = 'id', $_where = '', $_having = '', $_use_date_filters = true, $_as_column = '', $_more_dimensions = '', $_order_by = 'dt DESC' ) {
913
  // This function can be passed individual arguments, or an array of arguments
914
+ if ( is_array( $_dimension ) ) {
915
+ $_where = !empty( $_dimension[ 'where' ] ) ? $_dimension[ 'where' ] : '';
916
+ $_having = !empty( $_dimension[ 'having' ] ) ? $_dimension[ 'having' ] : '';
917
+ $_use_date_filters = isset( $_dimension[ 'use_date_filters' ] ) ? $_dimension[ 'use_date_filters' ] : true;
918
+ $_as_column = !empty( $_dimension[ 'as_column' ] ) ? $_dimension[ 'as_column' ] : '';
919
+ $_more_dimensions = !empty( $_dimension[ 'more_columns' ] ) ? $_dimension[ 'more_columns' ] : '';
920
+ $_order_by = !empty( $_dimension[ 'order_by' ] ) ? $_dimension[ 'order_by' ] : 'dt DESC';
921
+ $_dimension = $_dimension[ 'columns' ];
922
  }
923
 
924
+ $dimensions = $_dimension;
925
  if ( !empty( $_as_column ) ) {
926
+ $dimensions = "$_column AS $_as_column";
927
  }
928
 
929
+ if ( $_dimension != '*' ) {
930
+ $dimensions .= ', ip, dt';
931
  }
932
  else {
933
+ $dimensions = 'id, ip, other_ip, username, country, city, location, referer, resource, searchterms, plugins, notes, visit_id, server_latency, page_performance, browser, browser_version, browser_type, platform, language, user_agent, resolution, screen_width, screen_height, content_type, category, author, content_id, outbound_resource, dt_out, dt';
934
  }
935
 
936
+ if ( !empty( $_more_dimensions ) ) {
937
+ $dimensions .= ', ' . $_more_dimensions;
938
  }
939
 
940
+ $_where = self::get_combined_where( $_where, $_dimension, $_use_date_filters );
941
 
942
  $results = self::get_results( "
943
+ SELECT $dimensions
944
  FROM {$GLOBALS['wpdb']->prefix}slim_stats
945
  WHERE $_where
946
+ ORDER BY $_order_by
947
  LIMIT 0, " . self::$filters_normalized[ 'misc' ][ 'limit_results' ],
948
+ $dimensions,
949
  'dt DESC' );
950
 
951
+ if ( $_dimension != '*' ) {
952
+ $values = array_map( 'unserialize', array_unique( array_map( 'serialize', self::array_column( $results, explode( ',', $_dimension ) ) ) ) );
953
+ $results = array_intersect_key( $results, $values );
954
  }
955
 
956
  return $results;
989
  return $clean_outbound_resources;
990
  }
991
 
992
+ public static function get_top( $_column = 'id', $_where = '', $_having = '', $_use_date_filters = true, $_as_column = '' ) {
993
  // This function can be passed individual arguments, or an array of arguments
994
  if ( is_array( $_column ) ) {
995
  $_where = !empty( $_column[ 'where' ] ) ? $_column[ 'where' ] : '';
1102
  return $sorted_outbound_resources;
1103
  }
1104
 
1105
+ public static function get_traffic_sources_summary() {
1106
+ $results = array();
1107
+ $total_human_hits = wp_slimstat_db::count_records( 'id', 'visit_id > 0 AND browser_type <> 1' );
1108
+ $new_visitors = wp_slimstat_db::count_records_having( 'ip', 'visit_id > 0', 'COUNT(visit_id) = 1' );
1109
+ $new_visitors_rate = ($total_human_hits > 0)?sprintf("%01.2f", (100*$new_visitors/$total_human_hits)):0;
1110
+ if (intval($new_visitors_rate) > 99) {
1111
+ $new_visitors_rate = '100';
1112
+ }
1113
+
1114
+ $results[ 0 ][ 'metric' ] = __( 'Pageviews', 'wp-slimstat' );
1115
+ $results[ 0 ][ 'value' ] = number_format( self::$pageviews, 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1116
+ $results[ 0 ][ 'tooltip' ] = __( 'A request to load a single HTML file. Slimstat logs a "pageview" each time the tracking code is executed.', 'wp-slimstat' );
1117
+
1118
+ $results[ 1 ][ 'metric' ] = __( 'Unique Referrers', 'wp-slimstat' );
1119
+ $results[ 1 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'referer', "referer NOT LIKE '%{$_SERVER['SERVER_NAME']}%'" ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1120
+ $results[ 1 ][ 'tooltip' ] = __( 'A referrer (or referring site) is the site that a visitor previously visited before following a link to your site.', 'wp-slimstat' );
1121
+
1122
+ $results[ 2 ][ 'metric' ] = __( 'Direct Pageviews', 'wp-slimstat' );
1123
+ $results[ 2 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'id', 'resource IS NULL' ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1124
+ $results[ 2 ][ 'tooltip' ] = __( "Visitors who visited the site by typing the URL directly into their browser. <em>Direct</em> can also refer to the visitors who clicked on the links from their bookmarks/favorites, untagged links within emails, or links from documents that don't include tracking variables.", 'wp-slimstat' );
1125
+
1126
+ $results[ 3 ][ 'metric' ] = __( 'From a search result', 'wp-slimstat' );
1127
+ $results[ 3 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'id', "searchterms IS NOT NULL AND referer IS NOT NULL AND referer NOT LIKE '%" . home_url() . "%'" ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1128
+ $results[ 3 ][ 'tooltip' ] = __( "Visitors who came to your site via searches on Google or some other search engine.", 'wp-slimstat' );
1129
+
1130
+ $results[ 4 ][ 'metric' ] = __( 'Unique Landing Pages', 'wp-slimstat' );
1131
+ $results[ 4 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'resource' ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1132
+ $results[ 4 ][ 'tooltip' ] = __( "The first page that a user views during a session. This is also known as the <em>entrance page</em>. For example, if they search for 'Brooklyn Office Space,' and they land on your home page, it gets counted (for that visit) as a landing page.", 'wp-slimstat' );
1133
+
1134
+ $results[ 5 ][ 'metric' ] = __( 'Bounce Pages', 'wp-slimstat' );
1135
+ $results[ 5 ][ 'value' ] = number_format( wp_slimstat_db::count_bouncing_pages(), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1136
+ $results[ 5 ][ 'tooltip' ] = __( 'Number of single page visits to your site over the selected period.', 'wp-slimstat' );
1137
+
1138
+ $results[ 6 ][ 'metric' ] = __( 'New Visitors Rate', 'wp-slimstat' );
1139
+ $results[ 6 ][ 'value' ] = number_format( $new_visitors_rate, 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] );
1140
+ $results[ 6 ][ 'tooltip' ] = __( 'Percentage of single page visits, i.e. visits in which the person left your site from the entrance page.', 'wp-slimstat' );
1141
+
1142
+ $results[ 7 ][ 'metric' ] = __( 'Currently from search engines', 'wp-slimstat' );
1143
+ $results[ 7 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'id', "searchterms IS NOT NULL AND referer IS NOT NULL AND referer NOT LIKE '%" . home_url() . "%' AND dt > UNIX_TIMESTAMP() - 300", false ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1144
+ $results[ 7 ][ 'tooltip' ] = __( 'Visitors who visited the site in the last 5 minutes coming from a search engine.', 'wp-slimstat' );
1145
+
1146
+ return $results;
1147
+ }
1148
+
1149
+ public static function get_visits_duration() {
1150
+ $total_human_visits = wp_slimstat_db::count_records( 'visit_id', 'visit_id > 0 AND browser_type <> 1' );
1151
+ $results = array();
1152
+
1153
+ $count_results = wp_slimstat_db::count_records_having( 'visit_id', 'visit_id > 0 AND browser_type <> 1', ' GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) >= 0 AND GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) <= 30' );
1154
+ $average_time = 30 * $count_results;
1155
+ $results[ 0 ][ 'metric' ] = __( '0 - 30 seconds', 'wp-slimstat' );
1156
+ $results[ 0 ][ 'value' ] = ( ( $total_human_visits > 0 ) ? number_format( ( 100 * $count_results / $total_human_visits ), 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] ) : 0 ) . '%';
1157
+ $results[ 0 ][ 'details' ] = __( 'Hits', 'wp-slimstat' ) . ": $count_results";
1158
+
1159
+ $count_results = wp_slimstat_db::count_records_having( 'visit_id', 'visit_id > 0 AND browser_type <> 1', 'GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) > 30 AND GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) <= 60' );
1160
+ $average_time += 60 * $count_results;
1161
+ $results[ 1 ][ 'metric' ] = __( '31 - 60 seconds', 'wp-slimstat' );
1162
+ $results[ 1 ][ 'value' ] = ( ( $total_human_visits > 0 ) ? number_format( ( 100 * $count_results / $total_human_visits ), 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] ) : 0 ) . '%';
1163
+ $results[ 1 ][ 'details' ] = __( 'Hits', 'wp-slimstat' ) . ": $count_results";
1164
+
1165
+ $count_results = wp_slimstat_db::count_records_having( 'visit_id', 'visit_id > 0 AND browser_type <> 1', 'GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) > 60 AND GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) <= 180' );
1166
+ $average_time += 180 * $count_results;
1167
+ $results[ 2 ][ 'metric' ] = __( '1 - 3 minutes', 'wp-slimstat' );
1168
+ $results[ 2 ][ 'value' ] = ( ( $total_human_visits > 0 ) ? number_format( ( 100 * $count_results / $total_human_visits ), 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] ) : 0 ) . '%';
1169
+ $results[ 2 ][ 'details' ] = __( 'Hits', 'wp-slimstat' ) . ": $count_results";
1170
+
1171
+ $count_results = wp_slimstat_db::count_records_having( 'visit_id', 'visit_id > 0 AND browser_type <> 1', 'GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) > 180 AND GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) <= 300' );
1172
+ $average_time += 300 * $count_results;
1173
+ $results[ 3 ][ 'metric' ] = __( '3 - 5 minutes', 'wp-slimstat' );
1174
+ $results[ 3 ][ 'value' ] = ( ( $total_human_visits > 0 ) ? number_format( ( 100 * $count_results / $total_human_visits ), 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] ) : 0 ) . '%';
1175
+ $results[ 3 ][ 'details' ] = __( 'Hits', 'wp-slimstat' ) . ": $count_results";
1176
+
1177
+ $count_results = wp_slimstat_db::count_records_having( 'visit_id', 'visit_id > 0 AND browser_type <> 1', 'GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) > 300 AND GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) <= 420' );
1178
+ $average_time += 420 * $count_results;
1179
+ $results[ 4 ][ 'metric' ] = __( '5 - 7 minutes', 'wp-slimstat' );
1180
+ $results[ 4 ][ 'value' ] = ( ( $total_human_visits > 0 ) ? number_format( ( 100 * $count_results / $total_human_visits ), 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] ) : 0 ) . '%';
1181
+ $results[ 4 ][ 'details' ] = __( 'Hits', 'wp-slimstat' ) . ": $count_results";
1182
+
1183
+ $count_results = wp_slimstat_db::count_records_having( 'visit_id', 'visit_id > 0 AND browser_type <> 1', 'GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) > 420 AND GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) <= 600' );
1184
+ $average_time += 600* $count_results;
1185
+ $results[ 5 ][ 'metric' ] = __( '7 - 10 minutes', 'wp-slimstat' );
1186
+ $results[ 5 ][ 'value' ] = ( ( $total_human_visits > 0 ) ? number_format( ( 100 * $count_results / $total_human_visits ), 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] ) : 0 ) . '%';
1187
+ $results[ 5 ][ 'details' ] = __( 'Hits', 'wp-slimstat' ) . ": $count_results";
1188
+
1189
+ $count_results = wp_slimstat_db::count_records_having( 'visit_id', 'visit_id > 0 AND browser_type <> 1', 'GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) > 600' );
1190
+ $average_time += 900 * $count_results;
1191
+ $results[ 6 ][ 'metric' ] = __( 'More than 10 minutes', 'wp-slimstat' );
1192
+ $results[ 6 ][ 'value' ] = ( ( $total_human_visits > 0 ) ? number_format( ( 100 * $count_results / $total_human_visits ), 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] ) : 0 ) . '%';
1193
+ $results[ 6 ][ 'details' ] = __( 'Hits', 'wp-slimstat' ) . ": $count_results";
1194
+
1195
+ if ( $total_human_visits > 0 ) {
1196
+ $average_time /= $total_human_visits;
1197
+ $average_time = date('m:s', intval($average_time));
1198
+ }
1199
+ else{
1200
+ $average_time = '0:00';
1201
+ }
1202
+
1203
+ $results[ 7 ][ 'metric' ] = __( 'Average visit duration', 'wp-slimstat' );
1204
+ $results[ 7 ][ 'value' ] = $average_time;
1205
+ $results[ 7 ][ 'details' ] = '';
1206
+
1207
+ return $results;
1208
+ }
1209
+
1210
+ public static function get_visitors_summary() {
1211
+ $results = array();
1212
+ $total_human_hits = wp_slimstat_db::count_records( 'id', 'visit_id > 0 AND browser_type <> 1');
1213
+ $new_visitors = wp_slimstat_db::count_records_having( 'ip', 'visit_id > 0 AND browser_type <> 1', 'COUNT(visit_id) = 1' );
1214
+ $new_visitors_rate = ( $total_human_hits > 0) ? ( 100 * $new_visitors / $total_human_hits ) : 0;
1215
+ $metrics_per_visit = wp_slimstat_db::get_max_and_average_pages_per_visit();
1216
+ if ( empty( $metrics_per_visit[ 0 ] ) ) {
1217
+ $metrics_per_visit[ 0 ] = array( 'avghits' => 0, 'maxhits' => 0);
1218
+ }
1219
+ if ( intval( $new_visitors_rate ) > 99 ) {
1220
+ $new_visitors_rate = '100';
1221
+ }
1222
+
1223
+ $results[ 0 ][ 'metric' ] = __( 'Visits', 'wp-slimstat' );
1224
+ $results[ 0 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'visit_id', 'visit_id > 0 AND browser_type <> 1' ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1225
+ $results[ 0 ][ 'tooltip' ] = __( 'A visit is a session of at most 30 minutes. Returning visitors are counted multiple times if they perform multiple visits.', 'wp-slimstat' );
1226
+
1227
+ $results[ 1 ][ 'metric' ] = __( 'Unique IPs', 'wp-slimstat' );
1228
+ $results[ 1 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'ip', 'visit_id > 0 AND browser_type <> 1' ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1229
+ $results[ 1 ][ 'tooltip' ] = __( 'It includes only traffic generated by human visitors.', 'wp-slimstat' );
1230
+
1231
+ $results[ 2 ][ 'metric' ] = __( 'Bounce rate', 'wp-slimstat' );
1232
+ $results[ 2 ][ 'value' ] = number_format( $new_visitors_rate, 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] );
1233
+ $results[ 2 ][ 'tooltip' ] = __( 'Percentage of single-page visits, i.e. visits in which the person left your site from the entrance page.', 'wp-slimstat' );
1234
+
1235
+ $results[ 3 ][ 'metric' ] = __( 'Known visitors', 'wp-slimstat' );
1236
+ $results[ 3 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'username' ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1237
+ $results[ 3 ][ 'tooltip' ] = __( 'Visitors who had previously left a comment on your blog.', 'wp-slimstat' );
1238
+
1239
+ $results[ 4 ][ 'metric' ] = __( 'New visitors', 'wp-slimstat' );
1240
+ $results[ 4 ][ 'value' ] = number_format( $new_visitors, 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1241
+ $results[ 4 ][ 'tooltip' ] = __( 'Human users who visited your site only once.', 'wp-slimstat' );
1242
+
1243
+ $results[ 5 ][ 'metric' ] = __( 'Bots', 'wp-slimstat' );
1244
+ $results[ 5 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'id', 'browser_type = 1' ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1245
+
1246
+ $results[ 6 ][ 'metric' ] = __( 'Pageviews per visit', 'wp-slimstat' );
1247
+ $results[ 6 ][ 'value' ] = number_format( $metrics_per_visit[ 0 ][ 'avghits' ], 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] );
1248
+
1249
+ $results[ 7 ][ 'metric' ] = __( 'Longest visit', 'wp-slimstat' );
1250
+ $results[ 7 ][ 'value' ] = number_format( $metrics_per_visit[ 0 ][ 'maxhits' ], 0, '', wp_slimstat_db::$formats[ 'thousand' ] ) . ' ' . __( 'hits', 'wp-slimstat' );
1251
+
1252
+ return $results;
1253
+ }
1254
+
1255
+ public static function get_your_blog(){
1256
+ if ( false === ( $results = get_transient( 'slimstat_your_content' ) ) ) {
1257
+ $results = array();
1258
+
1259
+ $results[ 0 ][ 'metric' ] = __( 'Content Items', 'wp-slimstat' );
1260
+ $results[ 0 ][ 'value' ] = number_format( $GLOBALS[ 'wpdb' ]->get_var( "SELECT COUNT(*) FROM {$GLOBALS['wpdb']->posts} WHERE post_type <> 'revision' AND post_status <> 'auto-draft'" ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1261
+ $results[ 0 ][ 'tooltip' ] = __( 'This value includes not only posts, but also custom post types, regardless of their status', 'wp-slimstat' );
1262
+
1263
+ $results[ 1 ][ 'metric' ] = __( 'Posts', 'wp-slimstat' );
1264
+ $results[ 1 ][ 'value' ] = $GLOBALS[ 'wpdb' ]->get_var( "SELECT COUNT(*) FROM {$GLOBALS['wpdb']->posts} WHERE post_type = 'post'" );
1265
+
1266
+ $results[ 2 ][ 'metric' ] = __( 'Pages', 'wp-slimstat' );
1267
+ $results[ 2 ][ 'value' ] = number_format( $GLOBALS[ 'wpdb' ]->get_var( "SELECT COUNT(*) FROM {$GLOBALS['wpdb']->posts} WHERE post_type = 'page'" ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1268
+
1269
+ $results[ 3 ][ 'metric' ] = __( 'Attachments', 'wp-slimstat' );
1270
+ $results[ 3 ][ 'value' ] = number_format( $GLOBALS[ 'wpdb' ]->get_var( "SELECT COUNT(*) FROM {$GLOBALS['wpdb']->posts} WHERE post_type = 'attachment'" ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1271
+
1272
+ $results[ 4 ][ 'metric' ] = __( 'Revisions', 'wp-slimstat' );
1273
+ $results[ 4 ][ 'value' ] = number_format( $GLOBALS[ 'wpdb' ]->get_var( "SELECT COUNT(*) FROM {$GLOBALS['wpdb']->posts} WHERE post_type = 'revision'" ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1274
+
1275
+ $results[ 5 ][ 'metric' ] = __( 'Comments', 'wp-slimstat' );
1276
+ $results[ 5 ][ 'value' ] = $GLOBALS[ 'wpdb' ]->get_var( "SELECT COUNT(*) FROM {$GLOBALS['wpdb']->comments}" );
1277
+
1278
+ $results[ 6 ][ 'metric' ] = __( 'Avg Comments per Post', 'wp-slimstat' );
1279
+ $results[ 6 ][ 'value' ] = number_format( !empty( $results[ 1 ][ 'value' ] ) ? $results[ 5 ][ 'value' ] / $results[ 1 ][ 'value' ] : 0, 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1280
+
1281
+ $results[ 7 ][ 'metric' ] = __( 'Avg Server Latency', 'wp-slimstat' );
1282
+ $results[ 7 ][ 'value' ] = number_format( wp_slimstat::$wpdb->get_var( "SELECT AVG(server_latency) FROM {$GLOBALS[ 'wpdb' ]->prefix }slim_stats WHERE server_latency <> 0" ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1283
+ $results[ 7 ][ 'tooltip' ] = __( 'Latency is the amount of time it takes for the host server to receive and process a request for a page object. The amount of latency depends largely on how far away the user is from the server.', 'wp-slimstat' );
1284
+
1285
+ $results[ 1 ][ 'value' ] = number_format( $results[ 1 ][ 'value' ], 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1286
+ $results[ 5 ][ 'value' ] = number_format( $results[ 5 ][ 'value' ], 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1287
+
1288
+ // Store values as transients for 30 minutes
1289
+ set_transient( 'slimstat_your_content', $results, 1800 );
1290
+ }
1291
+
1292
+ return $results;
1293
+ }
1294
+
1295
  protected static function array_column( $input = array(), $columns = array() ) {
1296
  $output = array();
1297
 
admin/view/wp-slimstat-reports.php CHANGED
@@ -6,9 +6,6 @@ class wp_slimstat_reports {
6
  public static $reports_info = array();
7
  public static $user_reports = array();
8
 
9
- // Useful data for the reports
10
- protected static $pageviews = 0;
11
-
12
  /**
13
  * Initalize class properties
14
  */
@@ -18,9 +15,6 @@ class wp_slimstat_reports {
18
  include_once( 'wp-slimstat-db.php' );
19
  wp_slimstat_db::init();
20
 
21
- // Retrieve data that will be used by multiple reports
22
- self::$pageviews = wp_slimstat_db::count_records();
23
-
24
  // Define all the reports
25
  //
26
  // Parameters
@@ -69,7 +63,7 @@ class wp_slimstat_reports {
69
  'title' => __( 'About Slimstat', 'wp-slimstat' ),
70
  'callback' => array( __CLASS__, 'raw_results_to_html' ),
71
  'callback_args' => array(
72
- 'raw' => array( __CLASS__, 'get_about_wpslimstat' )
73
  ),
74
  'classes' => array( 'normal', 'hidden' ),
75
  'screens' => array( 'slimview2' )
@@ -79,7 +73,7 @@ class wp_slimstat_reports {
79
  // 'callback' => array( __CLASS__, 'show_overview_summary' ),
80
  'callback' => array( __CLASS__, 'raw_results_to_html' ),
81
  'callback_args' => array(
82
- 'raw' => array( __CLASS__, 'get_overview_summary' )
83
  ),
84
  'classes' => array( 'normal' ),
85
  'screens' => array( 'slimview2', 'dashboard' )
@@ -266,7 +260,7 @@ class wp_slimstat_reports {
266
  'title' => __( 'Audience Overview', 'wp-slimstat' ),
267
  'callback' => array( __CLASS__, 'raw_results_to_html' ),
268
  'callback_args' => array(
269
- 'raw' => array( __CLASS__, 'get_visitors_summary' )
270
  ),
271
  'classes' => array( 'normal' ),
272
  'screens' => array( 'slimview3', 'dashboard' ),
@@ -345,7 +339,7 @@ class wp_slimstat_reports {
345
  'title' => __( 'Browser Capabilities', 'wp-slimstat' ),
346
  'callback' => array( __CLASS__, 'raw_results_to_html' ),
347
  'callback_args' => array(
348
- 'raw' => array( __CLASS__, 'get_plugins' )
349
  ),
350
  'classes' => array( 'normal', 'hidden' ),
351
  'screens' => array( 'slimview3' )
@@ -354,7 +348,7 @@ class wp_slimstat_reports {
354
  'title' => __( 'Visit Duration', 'wp-slimstat' ),
355
  'callback' => array( __CLASS__, 'raw_results_to_html' ),
356
  'callback_args' => array(
357
- 'raw' => array( __CLASS__, 'get_visits_duration' )
358
  ),
359
  'classes' => array( 'normal', 'hidden' ),
360
  'screens' => array( 'slimview3' ),
@@ -507,7 +501,7 @@ class wp_slimstat_reports {
507
  'title' => __( 'Traffic Summary', 'wp-slimstat' ),
508
  'callback' => array( __CLASS__, 'raw_results_to_html' ),
509
  'callback_args' => array(
510
- 'raw' => array( __CLASS__, 'get_traffic_sources_summary' )
511
  ),
512
  'classes' => array( 'normal' ),
513
  'screens' => array( 'slimview5' )
@@ -738,7 +732,7 @@ class wp_slimstat_reports {
738
  'title' => __( 'Your Website', 'wp-slimstat' ),
739
  'callback' => array( __CLASS__, 'raw_results_to_html' ),
740
  'callback_args' => array(
741
- 'raw' => array( __CLASS__, 'get_your_blog' )
742
  ),
743
  'classes' => array( 'normal', 'hidden' ),
744
  'screens' => array( 'slimview4' ),
@@ -801,15 +795,25 @@ class wp_slimstat_reports {
801
  'screens' => array( 'slimview4' ),
802
  'tooltip' => $chart_tooltip
803
  ),
804
-
 
 
 
 
 
 
 
 
 
 
805
  'slim_p6_01' => array(
806
  'title' => __( 'World Map', 'wp-slimstat' ),
807
  'callback' => array( __CLASS__, 'show_world_map' ),
808
  'callback_args' => array(
809
  'id' => 'slim_p6_01'
810
  ),
811
- 'classes' => array( 'full-width', 'tall' ),
812
- 'screens' => array( 'slimview6' ),
813
  'tooltip' => __( 'Dots on the map represent the most recent pageviews geolocated by City. This feature is only available by enabling the corresponding precision level in the settings.', 'wp-slimstat' )
814
  )
815
  );
@@ -854,11 +858,11 @@ class wp_slimstat_reports {
854
  $page_location = ( wp_slimstat::$settings[ 'use_separate_menu' ] == 'on' ) ? 'slimstat' : 'admin';
855
 
856
  // Superadmins can customize the layout at network level, to override per-site settings
857
- self::$user_reports = get_user_option( "meta-box-order_slimstat_page_slimlayout-network", 1 );
858
 
859
  // No network-wide settings exist
860
  if ( empty( self::$user_reports ) ) {
861
- self::$user_reports = get_user_option( "meta-box-order_slimstat_page_slimlayout", $current_user->ID );
862
  }
863
 
864
  // Do this only if we are in one of our screens (no dashboard!)
@@ -955,19 +959,19 @@ class wp_slimstat_reports {
955
  }
956
  $pagination_buttons .= '<a class="refresh slimstat-font-angle-double-' . $direction_next . '" href="' . wp_slimstat_reports::fs_url( 'start_from equals ' . $startpoint ) . '"></a> ';
957
  }
958
- if ($endpoint < $_count_all_results && $_count_page_results > 0){
959
- $startpoint = wp_slimstat_db::$filters_normalized['misc']['start_from'] + $_results_per_page;
960
- $pagination_buttons .= '<a class="refresh slimstat-font-angle-'.$direction_next.'" href="' . wp_slimstat_reports::fs_url( 'start_from equals ' . $startpoint ) . '"></a> ';
961
  }
962
- if (wp_slimstat_db::$filters_normalized['misc']['start_from'] > 0){
963
- $startpoint = (wp_slimstat_db::$filters_normalized['misc']['start_from'] > $_results_per_page)?wp_slimstat_db::$filters_normalized['misc']['start_from'] - $_results_per_page : 0;
964
- $pagination_buttons .= '<a class="refresh slimstat-font-angle-'.$direction_prev.'" href="'.wp_slimstat_reports::fs_url('start_from equals '.$startpoint).'"></a> ';
965
  }
966
- if (wp_slimstat_db::$filters_normalized['misc']['start_from'] - $_results_per_page > 0){
967
- $pagination_buttons .= '<a class="refresh slimstat-font-angle-double-'.$direction_prev.'" href="'.wp_slimstat_reports::fs_url('start_from equals 0').'"></a> ';
968
  }
969
 
970
- $pagination = '<p class="pagination">' . sprintf( __( 'Results %s - %s of %s', 'wp-slimstat' ), number_format( wp_slimstat_db::$filters_normalized[ 'misc' ][ 'start_from' ] + 1, 0, '', wp_slimstat_db::$formats[ 'thousand' ] ), number_format( $endpoint, 0, '', wp_slimstat_db::$formats[ 'thousand' ] ), number_format( $_count_all_results, 0, '', wp_slimstat_db::$formats[ 'thousand' ] ) . ( ( $_count_all_results == wp_slimstat::$settings[ 'limit_results' ] ) ? '+' : '') );
971
 
972
  if ( $_show_refresh_countdown && wp_slimstat::$settings[ 'refresh_interval' ] > 0 && wp_slimstat_db::$filters_normalized[ 'utime' ][ 'end' ] >= date_i18n( 'U' ) - 300 ) {
973
  $pagination .= ' [' . __( 'Refresh in', 'wp-slimstat' ) . ' <i class="refresh-timer"></i>]';
@@ -1022,7 +1026,7 @@ class wp_slimstat_reports {
1022
  // Count the results
1023
  $count_page_results = count( $results );
1024
 
1025
- if ($count_page_results == 0){
1026
  echo '<p class="nodata">' . __( 'No data to display', 'wp-slimstat' ) . '</p>';
1027
 
1028
  if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
@@ -1053,7 +1057,7 @@ class wp_slimstat_reports {
1053
  $permalinks_enabled = get_option( 'permalink_structure' );
1054
  $column_not_calculated = str_replace( '_calculated', '', $_args[ 'columns' ] );
1055
 
1056
- for($i=0; $i<$count_page_results; $i++){
1057
  $row_details = $percentage = '';
1058
  $element_pre_value = '';
1059
  $element_value = $results[ $i ][ $_args[ 'columns' ] ];
@@ -1162,7 +1166,7 @@ class wp_slimstat_reports {
1162
  }
1163
 
1164
  if ( !empty($_args[ 'type' ] ) && $_args[ 'type' ] == 'top' ) {
1165
- $percentage_value = ( ( self::$pageviews > 0 ) ? number_format( sprintf( "%01.2f", ( 100 * $results[ $i ][ 'counthits' ] / self::$pageviews ) ), 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] ) : 0 );
1166
  $counthits = number_format( $results[ $i ][ 'counthits' ], 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1167
 
1168
  if ( !empty( $_args[ 'criteria' ] ) && $_args[ 'criteria' ] == 'swap' ) {
@@ -1368,237 +1372,99 @@ class wp_slimstat_reports {
1368
  }
1369
  }
1370
 
1371
- public static function get_about_wpslimstat() {
1372
- $dt = wp_slimstat_db::get_oldest_visit( '1=1', false );
1373
- $results = array();
1374
-
1375
- $results[ 0 ][ 'metric' ] = __( 'Dataset Size', 'wp-slimstat' );
1376
- $results[ 0 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'id', '1=1', false ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1377
- $results[ 0 ][ 'tooltip' ] = __( 'Total number of records stored in the database.', 'wp-slimstat' );
1378
-
1379
- $results[ 1 ][ 'metric' ] = __( 'DB Size', 'wp-slimstat' );
1380
- $results[ 1 ][ 'value' ] = wp_slimstat_db::get_data_size();
1381
-
1382
- $results[ 2 ][ 'metric' ] = __( 'Tracking Enabled', 'wp-slimstat' );
1383
- $results[ 2 ][ 'value' ] = __( ucfirst( wp_slimstat::$settings[ 'is_tracking' ] ), 'wp-slimstat' );
1384
-
1385
- $results[ 3 ][ 'metric' ] = __( 'Javascript Mode', 'wp-slimstat' );
1386
- $results[ 3 ][ 'value' ] = __( ucfirst( wp_slimstat::$settings[ 'javascript_mode' ] ), 'wp-slimstat' );
1387
-
1388
- $results[ 4 ][ 'metric' ] = __( 'Tracking Browser Caps', 'wp-slimstat' );
1389
- $results[ 4 ][ 'value' ] = __( ucfirst( wp_slimstat::$settings[ 'enable_javascript' ] ), 'wp-slimstat' );
1390
-
1391
- $results[ 5 ][ 'metric' ] = __( 'Auto purge', 'wp-slimstat' );
1392
- $results[ 5 ][ 'value' ] = ( wp_slimstat::$settings[ 'auto_purge' ] > 0 ) ? wp_slimstat::$settings[ 'auto_purge' ] . ' ' . __( 'days', 'wp-slimstat' ) : __( 'Off', 'wp-slimstat' );
1393
-
1394
- $results[ 6 ][ 'metric' ] = __( 'Oldest pageview', 'wp-slimstat' );
1395
- $results[ 6 ][ 'value' ] = ( $dt == null ) ? __( 'No visits', 'wp-slimstat' ) : date_i18n( wp_slimstat::$settings[ 'date_format' ], $dt );
1396
-
1397
- $results[ 7 ][ 'metric' ] = __( 'Geolocation', 'wp-slimstat' );
1398
- $results[ 7 ][ 'value' ] = date_i18n( wp_slimstat::$settings[ 'date_format' ], @filemtime( wp_slimstat::$maxmind_path ) );
1399
- $results[ 7 ][ 'tooltip' ] = __( 'Date when the MaxMind Geolocation database was last updated.', 'wp-slimstat' );
1400
-
1401
- return $results;
1402
- }
1403
-
1404
- public static function get_overview_summary() {
1405
- $days_in_range = ceil( ( wp_slimstat_db::$filters_normalized[ 'utime' ][ 'end' ] - wp_slimstat_db::$filters_normalized[ 'utime' ][ 'start' ] ) / 86400 );
1406
- $results = array();
1407
-
1408
- $results[ 0 ][ 'metric' ] = __( 'Pageviews', 'wp-slimstat' );
1409
- $results[ 0 ][ 'value' ] = number_format( self::$pageviews, 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1410
- $results[ 0 ][ 'tooltip' ] = __( 'A request to load a single HTML file. Slimstat logs a "pageview" each time the tracking code is executed.', 'wp-slimstat' );
1411
-
1412
- $results[ 1 ][ 'metric' ] = __( 'Days in Range', 'wp-slimstat' );
1413
- $results[ 1 ][ 'value' ] = $days_in_range;
1414
-
1415
- $results[ 2 ][ 'metric' ] = __( 'Average Daily Pageviews', 'wp-slimstat' );
1416
- $results[ 2 ][ 'value' ] = number_format( round( self::$pageviews / $days_in_range, 0 ), 0, '', wp_slimstat_db::$formats['thousand'] );
1417
- $results[ 2 ][ 'tooltip' ] = __( 'How many pages have been visited on average every day during the current period.', 'wp-slimstat' );
1418
 
1419
- $results[ 3 ][ 'metric' ] = __( 'From Search Results', 'wp-slimstat' );
1420
- $results[ 3 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'id', 'searchterms IS NOT NULL' ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1421
- $results[ 3 ][ 'tooltip' ] = __( 'Visitors who landed on your site after searching for a keyword on Google, Yahoo, etc.', 'wp-slimstat' );
 
 
1422
 
1423
- $results[ 4 ][ 'metric' ] = __( 'Unique IPs', 'wp-slimstat' );
1424
- $results[ 4 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'ip' ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1425
- $results[ 4 ][ 'tooltip' ] = __( 'Used to differentiate between multiple requests to download a file from one internet address (IP) and requests originating from many distinct addresses', 'wp-slimstat' );
1426
 
1427
- $results[ 5 ][ 'metric' ] = __( 'Last 30 minutes', 'wp-slimstat' );
1428
- $results[ 5 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'id', 'dt > ' . ( date_i18n( 'U' ) - 1800 ), false ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1429
 
1430
- $results[ 6 ][ 'metric' ] = __( 'Today', 'wp-slimstat' );
1431
- $results[ 6 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'id', 'dt > ' . ( date_i18n( 'U', mktime( 0, 0, 0, date_i18n( 'm' ), date_i18n( 'd' ), date_i18n( 'Y' ) ) ) ), false ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
 
 
 
 
 
1432
 
1433
- $results[ 7 ][ 'metric' ] = __( 'Yesterday', 'wp-slimstat' );
1434
- $results[ 7 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'id', 'dt BETWEEN ' . ( date_i18n( 'U', mktime( 0, 0, 0, date_i18n( 'm' ), date_i18n( 'd' ) - 1, date_i18n( 'Y' ) ) ) ) . ' AND ' . ( date_i18n( 'U', mktime( 23, 59, 59, date_i18n( 'm' ), date_i18n( 'd' ) - 1, date_i18n( 'Y' ) ) ) ), false ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1435
 
1436
- return $results;
1437
- }
1438
 
1439
- public static function get_plugins() {
1440
- $wp_slim_plugins = array( 'flash', 'silverlight', 'acrobat', 'java', 'mediaplayer', 'director', 'real', 'quicktime' );
1441
- $total_human_hits = wp_slimstat_db::count_records( 'id', 'visit_id > 0 AND browser_type <> 1' );
1442
- $results = array();
 
 
 
1443
 
1444
- foreach ( $wp_slim_plugins as $i => $a_plugin ) {
1445
- $count_results = wp_slimstat_db::count_records( 'id', "plugins LIKE '%{$a_plugin}%'" );
1446
- $results[ $i ][ 'metric' ] = ucfirst( $a_plugin );
1447
- $results[ $i ][ 'value' ] = ( $total_human_hits > 0 ) ? number_format( ( 100 * $count_results / $total_human_hits ), 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] ) : 0;
1448
- $results[ $i ][ 'details' ] = __( 'Hits', 'wp-slimstat' ) . ": $count_results";
1449
  }
1450
 
1451
- return $results;
1452
- }
1453
-
1454
- public static function get_visitors_summary() {
1455
- $results = array();
1456
- $total_human_hits = wp_slimstat_db::count_records( 'id', 'visit_id > 0 AND browser_type <> 1');
1457
- $new_visitors = wp_slimstat_db::count_records_having( 'ip', 'visit_id > 0 AND browser_type <> 1', 'COUNT(visit_id) = 1' );
1458
- $new_visitors_rate = ( $total_human_hits > 0) ? ( 100 * $new_visitors / $total_human_hits ) : 0;
1459
- $metrics_per_visit = wp_slimstat_db::get_max_and_average_pages_per_visit();
1460
- if ( empty( $metrics_per_visit[ 0 ] ) ) {
1461
- $metrics_per_visit[ 0 ] = array( 'avghits' => 0, 'maxhits' => 0);
1462
- }
1463
- if ( intval( $new_visitors_rate ) > 99 ) {
1464
- $new_visitors_rate = '100';
1465
  }
 
1466
 
1467
- $results[ 0 ][ 'metric' ] = __( 'Visits', 'wp-slimstat' );
1468
- $results[ 0 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'visit_id', 'visit_id > 0 AND browser_type <> 1' ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1469
- $results[ 0 ][ 'tooltip' ] = __( 'A visit is a session of at most 30 minutes. Returning visitors are counted multiple times if they perform multiple visits.', 'wp-slimstat' );
1470
 
1471
- $results[ 1 ][ 'metric' ] = __( 'Unique IPs', 'wp-slimstat' );
1472
- $results[ 1 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'ip', 'visit_id > 0 AND browser_type <> 1' ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1473
- $results[ 1 ][ 'tooltip' ] = __( 'It includes only traffic generated by human visitors.', 'wp-slimstat' );
 
 
1474
 
1475
- $results[ 2 ][ 'metric' ] = __( 'Bounce rate', 'wp-slimstat' );
1476
- $results[ 2 ][ 'value' ] = number_format( $new_visitors_rate, 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] );
1477
- $results[ 2 ][ 'tooltip' ] = __( 'Percentage of single-page visits, i.e. visits in which the person left your site from the entrance page.', 'wp-slimstat' );
1478
 
1479
- $results[ 3 ][ 'metric' ] = __( 'Known visitors', 'wp-slimstat' );
1480
- $results[ 3 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'username' ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1481
- $results[ 3 ][ 'tooltip' ] = __( 'Visitors who had previously left a comment on your blog.', 'wp-slimstat' );
1482
 
1483
- $results[ 4 ][ 'metric' ] = __( 'New visitors', 'wp-slimstat' );
1484
- $results[ 4 ][ 'value' ] = number_format( $new_visitors, 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1485
- $results[ 4 ][ 'tooltip' ] = __( 'Human users who visited your site only once.', 'wp-slimstat' );
 
 
 
 
1486
 
1487
- $results[ 5 ][ 'metric' ] = __( 'Bots', 'wp-slimstat' );
1488
- $results[ 5 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'id', 'browser_type = 1' ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1489
 
1490
- $results[ 6 ][ 'metric' ] = __( 'Pageviews per visit', 'wp-slimstat' );
1491
- $results[ 6 ][ 'value' ] = number_format( $metrics_per_visit[ 0 ][ 'avghits' ], 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] );
 
 
1492
 
1493
- $results[ 7 ][ 'metric' ] = __( 'Longest visit', 'wp-slimstat' );
1494
- $results[ 7 ][ 'value' ] = number_format( $metrics_per_visit[ 0 ][ 'maxhits' ], 0, '', wp_slimstat_db::$formats[ 'thousand' ] ) . ' ' . __( 'hits', 'wp-slimstat' );
1495
 
1496
- return $results;
1497
- }
 
 
 
 
 
 
1498
 
1499
- public static function get_visits_duration() {
1500
- $total_human_visits = wp_slimstat_db::count_records( 'visit_id', 'visit_id > 0 AND browser_type <> 1' );
1501
- $results = array();
1502
-
1503
- $count_results = wp_slimstat_db::count_records_having( 'visit_id', 'visit_id > 0 AND browser_type <> 1', ' GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) >= 0 AND GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) <= 30' );
1504
- $average_time = 30 * $count_results;
1505
- $results[ 0 ][ 'metric' ] = __( '0 - 30 seconds', 'wp-slimstat' );
1506
- $results[ 0 ][ 'value' ] = ( ( $total_human_visits > 0 ) ? number_format( ( 100 * $count_results / $total_human_visits ), 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] ) : 0 ) . '%';
1507
- $results[ 0 ][ 'details' ] = __( 'Hits', 'wp-slimstat' ) . ": $count_results";
1508
-
1509
- $count_results = wp_slimstat_db::count_records_having( 'visit_id', 'visit_id > 0 AND browser_type <> 1', 'GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) > 30 AND GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) <= 60' );
1510
- $average_time += 60 * $count_results;
1511
- $results[ 1 ][ 'metric' ] = __( '31 - 60 seconds', 'wp-slimstat' );
1512
- $results[ 1 ][ 'value' ] = ( ( $total_human_visits > 0 ) ? number_format( ( 100 * $count_results / $total_human_visits ), 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] ) : 0 ) . '%';
1513
- $results[ 1 ][ 'details' ] = __( 'Hits', 'wp-slimstat' ) . ": $count_results";
1514
-
1515
- $count_results = wp_slimstat_db::count_records_having( 'visit_id', 'visit_id > 0 AND browser_type <> 1', 'GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) > 60 AND GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) <= 180' );
1516
- $average_time += 180 * $count_results;
1517
- $results[ 2 ][ 'metric' ] = __( '1 - 3 minutes', 'wp-slimstat' );
1518
- $results[ 2 ][ 'value' ] = ( ( $total_human_visits > 0 ) ? number_format( ( 100 * $count_results / $total_human_visits ), 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] ) : 0 ) . '%';
1519
- $results[ 2 ][ 'details' ] = __( 'Hits', 'wp-slimstat' ) . ": $count_results";
1520
-
1521
- $count_results = wp_slimstat_db::count_records_having( 'visit_id', 'visit_id > 0 AND browser_type <> 1', 'GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) > 180 AND GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) <= 300' );
1522
- $average_time += 300 * $count_results;
1523
- $results[ 3 ][ 'metric' ] = __( '3 - 5 minutes', 'wp-slimstat' );
1524
- $results[ 3 ][ 'value' ] = ( ( $total_human_visits > 0 ) ? number_format( ( 100 * $count_results / $total_human_visits ), 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] ) : 0 ) . '%';
1525
- $results[ 3 ][ 'details' ] = __( 'Hits', 'wp-slimstat' ) . ": $count_results";
1526
-
1527
- $count_results = wp_slimstat_db::count_records_having( 'visit_id', 'visit_id > 0 AND browser_type <> 1', 'GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) > 300 AND GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) <= 420' );
1528
- $average_time += 420 * $count_results;
1529
- $results[ 4 ][ 'metric' ] = __( '5 - 7 minutes', 'wp-slimstat' );
1530
- $results[ 4 ][ 'value' ] = ( ( $total_human_visits > 0 ) ? number_format( ( 100 * $count_results / $total_human_visits ), 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] ) : 0 ) . '%';
1531
- $results[ 4 ][ 'details' ] = __( 'Hits', 'wp-slimstat' ) . ": $count_results";
1532
-
1533
- $count_results = wp_slimstat_db::count_records_having( 'visit_id', 'visit_id > 0 AND browser_type <> 1', 'GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) > 420 AND GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) <= 600' );
1534
- $average_time += 600* $count_results;
1535
- $results[ 5 ][ 'metric' ] = __( '7 - 10 minutes', 'wp-slimstat' );
1536
- $results[ 5 ][ 'value' ] = ( ( $total_human_visits > 0 ) ? number_format( ( 100 * $count_results / $total_human_visits ), 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] ) : 0 ) . '%';
1537
- $results[ 5 ][ 'details' ] = __( 'Hits', 'wp-slimstat' ) . ": $count_results";
1538
-
1539
- $count_results = wp_slimstat_db::count_records_having( 'visit_id', 'visit_id > 0 AND browser_type <> 1', 'GREATEST( MAX( dt ), MAX( dt_out ) ) - MIN( dt ) > 600' );
1540
- $average_time += 900 * $count_results;
1541
- $results[ 6 ][ 'metric' ] = __( 'More than 10 minutes', 'wp-slimstat' );
1542
- $results[ 6 ][ 'value' ] = ( ( $total_human_visits > 0 ) ? number_format( ( 100 * $count_results / $total_human_visits ), 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] ) : 0 ) . '%';
1543
- $results[ 6 ][ 'details' ] = __( 'Hits', 'wp-slimstat' ) . ": $count_results";
1544
-
1545
- if ( $total_human_visits > 0 ) {
1546
- $average_time /= $total_human_visits;
1547
- $average_time = date('m:s', intval($average_time));
1548
- }
1549
- else{
1550
- $average_time = '0:00';
1551
  }
1552
 
1553
- $results[ 7 ][ 'metric' ] = __( 'Average visit duration', 'wp-slimstat' );
1554
- $results[ 7 ][ 'value' ] = $average_time;
1555
- $results[ 7 ][ 'details' ] = '';
1556
-
1557
- return $results;
1558
- }
1559
-
1560
- public static function get_traffic_sources_summary() {
1561
- $results = array();
1562
- $total_human_hits = wp_slimstat_db::count_records( 'id', 'visit_id > 0 AND browser_type <> 1' );
1563
- $new_visitors = wp_slimstat_db::count_records_having( 'ip', 'visit_id > 0', 'COUNT(visit_id) = 1' );
1564
- $new_visitors_rate = ($total_human_hits > 0)?sprintf("%01.2f", (100*$new_visitors/$total_human_hits)):0;
1565
- if (intval($new_visitors_rate) > 99) {
1566
- $new_visitors_rate = '100';
1567
  }
1568
-
1569
- $results[ 0 ][ 'metric' ] = __( 'Pageviews', 'wp-slimstat' );
1570
- $results[ 0 ][ 'value' ] = number_format( self::$pageviews, 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1571
- $results[ 0 ][ 'tooltip' ] = __( 'A request to load a single HTML file. Slimstat logs a "pageview" each time the tracking code is executed.', 'wp-slimstat' );
1572
-
1573
- $results[ 1 ][ 'metric' ] = __( 'Unique Referrers', 'wp-slimstat' );
1574
- $results[ 1 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'referer', "referer NOT LIKE '%{$_SERVER['SERVER_NAME']}%'" ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1575
- $results[ 1 ][ 'tooltip' ] = __( 'A referrer (or referring site) is the site that a visitor previously visited before following a link to your site.', 'wp-slimstat' );
1576
-
1577
- $results[ 2 ][ 'metric' ] = __( 'Direct Pageviews', 'wp-slimstat' );
1578
- $results[ 2 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'id', 'resource IS NULL' ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1579
- $results[ 2 ][ 'tooltip' ] = __( "Visitors who visited the site by typing the URL directly into their browser. <em>Direct</em> can also refer to the visitors who clicked on the links from their bookmarks/favorites, untagged links within emails, or links from documents that don't include tracking variables.", 'wp-slimstat' );
1580
-
1581
- $results[ 3 ][ 'metric' ] = __( 'From a search result', 'wp-slimstat' );
1582
- $results[ 3 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'id', "searchterms IS NOT NULL AND referer IS NOT NULL AND referer NOT LIKE '%" . home_url() . "%'" ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1583
- $results[ 3 ][ 'tooltip' ] = __( "Visitors who came to your site via searches on Google or some other search engine.", 'wp-slimstat' );
1584
-
1585
- $results[ 4 ][ 'metric' ] = __( 'Unique Landing Pages', 'wp-slimstat' );
1586
- $results[ 4 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'resource' ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1587
- $results[ 4 ][ 'tooltip' ] = __( "The first page that a user views during a session. This is also known as the <em>entrance page</em>. For example, if they search for 'Brooklyn Office Space,' and they land on your home page, it gets counted (for that visit) as a landing page.", 'wp-slimstat' );
1588
-
1589
- $results[ 5 ][ 'metric' ] = __( 'Bounce Pages', 'wp-slimstat' );
1590
- $results[ 5 ][ 'value' ] = number_format( wp_slimstat_db::count_bouncing_pages(), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1591
- $results[ 5 ][ 'tooltip' ] = __( 'Number of single page visits to your site over the selected period.', 'wp-slimstat' );
1592
-
1593
- $results[ 6 ][ 'metric' ] = __( 'New Visitors Rate', 'wp-slimstat' );
1594
- $results[ 6 ][ 'value' ] = number_format( $new_visitors_rate, 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] );
1595
- $results[ 6 ][ 'tooltip' ] = __( 'Percentage of single page visits, i.e. visits in which the person left your site from the entrance page.', 'wp-slimstat' );
1596
-
1597
- $results[ 7 ][ 'metric' ] = __( 'Currently from search engines', 'wp-slimstat' );
1598
- $results[ 7 ][ 'value' ] = number_format( wp_slimstat_db::count_records( 'id', "searchterms IS NOT NULL AND referer IS NOT NULL AND referer NOT LIKE '%" . home_url() . "%' AND dt > UNIX_TIMESTAMP() - 300", false ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1599
- $results[ 7 ][ 'tooltip' ] = __( 'Visitors who visited the site in the last 5 minutes coming from a search engine.', 'wp-slimstat' );
1600
-
1601
- return $results;
1602
  }
1603
 
1604
  public static function show_rankings(){
@@ -1738,91 +1604,6 @@ class wp_slimstat_reports {
1738
  }
1739
  }
1740
 
1741
- public static function get_your_blog(){
1742
- if ( false === ( $results = get_transient( 'slimstat_your_content' ) ) ) {
1743
- $results = array();
1744
-
1745
- $results[ 0 ][ 'metric' ] = __( 'Content Items', 'wp-slimstat' );
1746
- $results[ 0 ][ 'value' ] = number_format( $GLOBALS[ 'wpdb' ]->get_var( "SELECT COUNT(*) FROM {$GLOBALS['wpdb']->posts} WHERE post_type <> 'revision' AND post_status <> 'auto-draft'" ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1747
- $results[ 0 ][ 'tooltip' ] = __( 'This value includes not only posts, but also custom post types, regardless of their status', 'wp-slimstat' );
1748
-
1749
- $results[ 1 ][ 'metric' ] = __( 'Posts', 'wp-slimstat' );
1750
- $results[ 1 ][ 'value' ] = $GLOBALS[ 'wpdb' ]->get_var( "SELECT COUNT(*) FROM {$GLOBALS['wpdb']->posts} WHERE post_type = 'post'" );
1751
-
1752
- $results[ 2 ][ 'metric' ] = __( 'Pages', 'wp-slimstat' );
1753
- $results[ 2 ][ 'value' ] = number_format( $GLOBALS[ 'wpdb' ]->get_var( "SELECT COUNT(*) FROM {$GLOBALS['wpdb']->posts} WHERE post_type = 'page'" ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1754
-
1755
- $results[ 3 ][ 'metric' ] = __( 'Attachments', 'wp-slimstat' );
1756
- $results[ 3 ][ 'value' ] = number_format( $GLOBALS[ 'wpdb' ]->get_var( "SELECT COUNT(*) FROM {$GLOBALS['wpdb']->posts} WHERE post_type = 'attachment'" ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1757
-
1758
- $results[ 4 ][ 'metric' ] = __( 'Revisions', 'wp-slimstat' );
1759
- $results[ 4 ][ 'value' ] = number_format( $GLOBALS[ 'wpdb' ]->get_var( "SELECT COUNT(*) FROM {$GLOBALS['wpdb']->posts} WHERE post_type = 'revision'" ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1760
-
1761
- $results[ 5 ][ 'metric' ] = __( 'Comments', 'wp-slimstat' );
1762
- $results[ 5 ][ 'value' ] = $GLOBALS[ 'wpdb' ]->get_var( "SELECT COUNT(*) FROM {$GLOBALS['wpdb']->comments}" );
1763
-
1764
- $results[ 6 ][ 'metric' ] = __( 'Avg Comments per Post', 'wp-slimstat' );
1765
- $results[ 6 ][ 'value' ] = number_format( !empty( $results[ 1 ][ 'value' ] ) ? $results[ 5 ][ 'value' ] / $results[ 1 ][ 'value' ] : 0, 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1766
-
1767
- $results[ 7 ][ 'metric' ] = __( 'Avg Server Latency', 'wp-slimstat' );
1768
- $results[ 7 ][ 'value' ] = number_format( wp_slimstat::$wpdb->get_var( "SELECT AVG(server_latency) FROM {$GLOBALS[ 'wpdb' ]->prefix }slim_stats WHERE server_latency <> 0" ), 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1769
- $results[ 7 ][ 'tooltip' ] = __( 'Latency is the amount of time it takes for the host server to receive and process a request for a page object. The amount of latency depends largely on how far away the user is from the server.', 'wp-slimstat' );
1770
-
1771
- $results[ 1 ][ 'value' ] = number_format( $results[ 1 ][ 'value' ], 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1772
- $results[ 5 ][ 'value' ] = number_format( $results[ 5 ][ 'value' ], 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1773
-
1774
- // Store values as transients for 30 minutes
1775
- set_transient( 'slimstat_your_content', $results, 1800 );
1776
- }
1777
-
1778
- return $results;
1779
- }
1780
-
1781
- public static function show_events( $_args = array() ) {
1782
- $all_results = call_user_func( $_args[ 'raw' ] , $_args );
1783
-
1784
- $results = array_slice(
1785
- $all_results,
1786
- wp_slimstat_db::$filters_normalized[ 'misc' ][ 'start_from' ],
1787
- wp_slimstat::$settings[ 'rows_to_show' ]
1788
- );
1789
-
1790
- // Count the results
1791
- $count_page_results = count( $results );
1792
-
1793
- if ($count_page_results == 0){
1794
- echo '<p class="nodata">' . __( 'No data to display', 'wp-slimstat' ) . '</p>';
1795
-
1796
- if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
1797
- die();
1798
- }
1799
- else{
1800
- return array();
1801
- }
1802
- }
1803
-
1804
- echo self::report_pagination( $count_page_results, count( $all_results ) );
1805
- $is_expanded = ( wp_slimstat::$settings[ 'expand_details' ] == 'on' ) ? ' expanded' : '';
1806
-
1807
- foreach ( $results as $a_result ) {
1808
- echo "<p class='slimstat-tooltip-trigger'>{$a_result[ 'notes' ]} <b class='slimstat-tooltip-content$is_expanded'>" . __( 'Type', 'wp-slimstat' ) . ": {$a_result[ 'type' ]}";
1809
-
1810
- if ( !empty( $a_result[ 'dt' ] ) ) {
1811
- $date_time = date_i18n( wp_slimstat::$settings[ 'date_format' ] . ' ' . wp_slimstat::$settings[ 'time_format' ], $a_result[ 'dt' ], true );
1812
- echo '<br/>' . __( 'Coordinates', 'wp-slimstat' ) . ": {$a_result[ 'position' ]}<br/>" . __( 'Date', 'wp-slimstat' ) . ": $date_time";
1813
- }
1814
- if ( !empty( $a_result[ 'counthits' ] ) ) {
1815
- echo '<br/>' . __( 'Hits', 'wp-slimstat' ) . ": {$a_result[ 'counthits' ]}";
1816
- }
1817
-
1818
- echo "</b></p>";
1819
- }
1820
-
1821
- if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
1822
- die();
1823
- }
1824
- }
1825
-
1826
  public static function show_world_map() {
1827
  $countries = wp_slimstat_db::get_top( 'country' );
1828
  $recent_visits = wp_slimstat_db::get_recent( 'location', '', '', true, '', 'city' );
@@ -1850,7 +1631,7 @@ class wp_slimstat_reports {
1850
  continue;
1851
  }
1852
 
1853
- $percentage = ( self::$pageviews > 0 ) ? sprintf( "%01.2f", ( 100 * $a_country[ 'counthits' ] / self::$pageviews ) ) : 0;
1854
  $percentage_format = number_format( $percentage, 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] );
1855
  $balloon_text = __( 'c-' . $a_country[ 'country' ], 'wp-slimstat' ) . ': ' . $percentage_format . '% (' . number_format( $a_country[ 'counthits' ], 0, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] ) . ')';
1856
  $data_areas[ $a_country[ 'country' ] ] = '{id:"' . strtoupper( $a_country[ 'country' ] ) . '",balloonText:"' . $balloon_text . '",value:' . $percentage . '}';
@@ -1995,7 +1776,7 @@ class wp_slimstat_reports {
1995
  $filters_html = "<ul class='slimstat-filter-list'>$filters_html</ul><a href='#' id='slimstat-save-filter' class='slimstat-filter-action-button button-secondary noslimstat' data-filter-array='" . htmlentities( json_encode( $_filters_array ), ENT_QUOTES, 'UTF-8' ) . "'>" . __( 'Save', 'wp-slimstat' ) . '</a>';
1996
  }
1997
 
1998
- if ( count( $_filters_array ) > 1 ) {
1999
  $filters_html .= '<a href="' . self::fs_url() . '" id="slimstat-remove-all-filters" class="button-secondary slimstat-filter-action-button noslimstat">' . __( 'Reset All', 'wp-slimstat' ) . '</a>';
2000
  }
2001
 
@@ -2029,19 +1810,19 @@ class wp_slimstat_reports {
2029
  }
2030
  }
2031
 
2032
- $filters_normalized = wp_slimstat_db::parse_filters( $_filters_string );
2033
 
2034
  // Columns
2035
- if ( !empty( $filters_normalized[ 'columns' ] ) ) {
2036
- foreach ( $filters_normalized[ 'columns' ] as $a_key => $a_filter ) {
2037
  $a_key = str_replace( '_calculated', '', $a_key );
2038
- $request_uri .= "&amp;fs%5B$a_key%5D=" . urlencode( $a_filter[ 0 ] . ' ' . $a_filter[ 1 ] );
2039
  }
2040
  }
2041
 
2042
  // Date ranges
2043
- if ( !empty( $filters_normalized[ 'date' ] ) ) {
2044
- foreach ( $filters_normalized[ 'date' ] as $a_key => $a_filter ) {
2045
  if ( isset( $a_filter ) ) {
2046
  $request_uri .= "&amp;fs%5B$a_key%5D=" . urlencode( 'equals ' . $a_filter );
2047
  }
@@ -2049,8 +1830,8 @@ class wp_slimstat_reports {
2049
  }
2050
 
2051
  // Misc filters
2052
- if ( !empty( $filters_normalized[ 'misc' ] ) ) {
2053
- foreach ( $filters_normalized[ 'misc' ] as $a_key => $a_filter ) {
2054
  $request_uri .= "&amp;fs%5B$a_key%5D=" . urlencode( 'equals ' . $a_filter );
2055
  }
2056
  }
6
  public static $reports_info = array();
7
  public static $user_reports = array();
8
 
 
 
 
9
  /**
10
  * Initalize class properties
11
  */
15
  include_once( 'wp-slimstat-db.php' );
16
  wp_slimstat_db::init();
17
 
 
 
 
18
  // Define all the reports
19
  //
20
  // Parameters
63
  'title' => __( 'About Slimstat', 'wp-slimstat' ),
64
  'callback' => array( __CLASS__, 'raw_results_to_html' ),
65
  'callback_args' => array(
66
+ 'raw' => array( 'wp_slimstat_db', 'get_about_wpslimstat' )
67
  ),
68
  'classes' => array( 'normal', 'hidden' ),
69
  'screens' => array( 'slimview2' )
73
  // 'callback' => array( __CLASS__, 'show_overview_summary' ),
74
  'callback' => array( __CLASS__, 'raw_results_to_html' ),
75
  'callback_args' => array(
76
+ 'raw' => array( 'wp_slimstat_db', 'get_overview_summary' )
77
  ),
78
  'classes' => array( 'normal' ),
79
  'screens' => array( 'slimview2', 'dashboard' )
260
  'title' => __( 'Audience Overview', 'wp-slimstat' ),
261
  'callback' => array( __CLASS__, 'raw_results_to_html' ),
262
  'callback_args' => array(
263
+ 'raw' => array( 'wp_slimstat_db', 'get_visitors_summary' )
264
  ),
265
  'classes' => array( 'normal' ),
266
  'screens' => array( 'slimview3', 'dashboard' ),
339
  'title' => __( 'Browser Capabilities', 'wp-slimstat' ),
340
  'callback' => array( __CLASS__, 'raw_results_to_html' ),
341
  'callback_args' => array(
342
+ 'raw' => array( 'wp_slimstat_db', 'get_plugins' )
343
  ),
344
  'classes' => array( 'normal', 'hidden' ),
345
  'screens' => array( 'slimview3' )
348
  'title' => __( 'Visit Duration', 'wp-slimstat' ),
349
  'callback' => array( __CLASS__, 'raw_results_to_html' ),
350
  'callback_args' => array(
351
+ 'raw' => array( 'wp_slimstat_db', 'get_visits_duration' )
352
  ),
353
  'classes' => array( 'normal', 'hidden' ),
354
  'screens' => array( 'slimview3' ),
501
  'title' => __( 'Traffic Summary', 'wp-slimstat' ),
502
  'callback' => array( __CLASS__, 'raw_results_to_html' ),
503
  'callback_args' => array(
504
+ 'raw' => array( 'wp_slimstat_db', 'get_traffic_sources_summary' )
505
  ),
506
  'classes' => array( 'normal' ),
507
  'screens' => array( 'slimview5' )
732
  'title' => __( 'Your Website', 'wp-slimstat' ),
733
  'callback' => array( __CLASS__, 'raw_results_to_html' ),
734
  'callback_args' => array(
735
+ 'raw' => array( 'wp_slimstat_db', 'get_your_blog' )
736
  ),
737
  'classes' => array( 'normal', 'hidden' ),
738
  'screens' => array( 'slimview4' ),
795
  'screens' => array( 'slimview4' ),
796
  'tooltip' => $chart_tooltip
797
  ),
798
+ 'slim_p4_27' => array(
799
+ 'title' => __( 'Users by Page', 'wp-slimstat' ),
800
+ 'callback' => array( __CLASS__, 'show_group_by' ),
801
+ 'callback_args' => array(
802
+ 'column_group' => 'username',
803
+ 'group_by' => 'resource',
804
+ 'raw' => array( 'wp_slimstat_db', 'get_group_by' )
805
+ ),
806
+ 'classes' => array( 'large' ),
807
+ 'screens' => array( 'slimview4' )
808
+ ),
809
  'slim_p6_01' => array(
810
  'title' => __( 'World Map', 'wp-slimstat' ),
811
  'callback' => array( __CLASS__, 'show_world_map' ),
812
  'callback_args' => array(
813
  'id' => 'slim_p6_01'
814
  ),
815
+ 'classes' => array( 'large', 'tall' ),
816
+ 'screens' => array( 'slimview3' ),
817
  'tooltip' => __( 'Dots on the map represent the most recent pageviews geolocated by City. This feature is only available by enabling the corresponding precision level in the settings.', 'wp-slimstat' )
818
  )
819
  );
858
  $page_location = ( wp_slimstat::$settings[ 'use_separate_menu' ] == 'on' ) ? 'slimstat' : 'admin';
859
 
860
  // Superadmins can customize the layout at network level, to override per-site settings
861
+ self::$user_reports = get_user_option( "meta-box-order_{$page_location}_page_slimlayout-network", 1 );
862
 
863
  // No network-wide settings exist
864
  if ( empty( self::$user_reports ) ) {
865
+ self::$user_reports = get_user_option( "meta-box-order_{$page_location}_page_slimlayout", $current_user->ID );
866
  }
867
 
868
  // Do this only if we are in one of our screens (no dashboard!)
959
  }
960
  $pagination_buttons .= '<a class="refresh slimstat-font-angle-double-' . $direction_next . '" href="' . wp_slimstat_reports::fs_url( 'start_from equals ' . $startpoint ) . '"></a> ';
961
  }
962
+ if ( $endpoint < $_count_all_results && $_count_page_results > 0 ) {
963
+ $startpoint = wp_slimstat_db::$filters_normalized[ 'misc' ][ 'start_from' ] + $_results_per_page;
964
+ $pagination_buttons .= '<a class="refresh slimstat-font-angle-' . $direction_next . '" href="' . wp_slimstat_reports::fs_url( 'start_from equals ' . $startpoint ) . '"></a> ';
965
  }
966
+ if ( wp_slimstat_db::$filters_normalized[ 'misc' ][ 'start_from' ] > 0 ) {
967
+ $startpoint = ( wp_slimstat_db::$filters_normalized[ 'misc' ][ 'start_from' ] > $_results_per_page ) ? wp_slimstat_db::$filters_normalized[ 'misc' ][ 'start_from' ] - $_results_per_page : 0;
968
+ $pagination_buttons .= '<a class="refresh slimstat-font-angle-' . $direction_prev . '" href="' . wp_slimstat_reports::fs_url( 'start_from equals ' . $startpoint ) . '"></a> ';
969
  }
970
+ if ( wp_slimstat_db::$filters_normalized[ 'misc' ][ 'start_from' ] - $_results_per_page > 0 ) {
971
+ $pagination_buttons .= '<a class="refresh slimstat-font-angle-double-' . $direction_prev . '" href="' . wp_slimstat_reports::fs_url( 'start_from equals 0' ) . '"></a> ';
972
  }
973
 
974
+ $pagination = '<p class="pagination">' . sprintf( __( 'Results %s - %s of %s', 'wp-slimstat' ), number_format( wp_slimstat_db::$filters_normalized[ 'misc' ][ 'start_from' ] + 1, 0, '', wp_slimstat_db::$formats[ 'thousand' ] ), number_format( $endpoint, 0, '', wp_slimstat_db::$formats[ 'thousand' ] ), number_format( $_count_all_results, 0, '', wp_slimstat_db::$formats[ 'thousand' ] ) . ( ( $_count_all_results == wp_slimstat::$settings[ 'limit_results' ] ) ? '+' : '' ) );
975
 
976
  if ( $_show_refresh_countdown && wp_slimstat::$settings[ 'refresh_interval' ] > 0 && wp_slimstat_db::$filters_normalized[ 'utime' ][ 'end' ] >= date_i18n( 'U' ) - 300 ) {
977
  $pagination .= ' [' . __( 'Refresh in', 'wp-slimstat' ) . ' <i class="refresh-timer"></i>]';
1026
  // Count the results
1027
  $count_page_results = count( $results );
1028
 
1029
+ if ( $count_page_results == 0 ) {
1030
  echo '<p class="nodata">' . __( 'No data to display', 'wp-slimstat' ) . '</p>';
1031
 
1032
  if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
1057
  $permalinks_enabled = get_option( 'permalink_structure' );
1058
  $column_not_calculated = str_replace( '_calculated', '', $_args[ 'columns' ] );
1059
 
1060
+ for ( $i=0; $i<$count_page_results; $i++ ) {
1061
  $row_details = $percentage = '';
1062
  $element_pre_value = '';
1063
  $element_value = $results[ $i ][ $_args[ 'columns' ] ];
1166
  }
1167
 
1168
  if ( !empty($_args[ 'type' ] ) && $_args[ 'type' ] == 'top' ) {
1169
+ $percentage_value = ( ( wp_slimstat_db::$pageviews > 0 ) ? number_format( sprintf( "%01.2f", ( 100 * $results[ $i ][ 'counthits' ] / wp_slimstat_db::$pageviews ) ), 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] ) : 0 );
1170
  $counthits = number_format( $results[ $i ][ 'counthits' ], 0, '', wp_slimstat_db::$formats[ 'thousand' ] );
1171
 
1172
  if ( !empty( $_args[ 'criteria' ] ) && $_args[ 'criteria' ] == 'swap' ) {
1372
  }
1373
  }
1374
 
1375
+ public static function show_events( $_args = array() ) {
1376
+ $all_results = call_user_func( $_args[ 'raw' ] , $_args );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1377
 
1378
+ $results = array_slice(
1379
+ $all_results,
1380
+ wp_slimstat_db::$filters_normalized[ 'misc' ][ 'start_from' ],
1381
+ wp_slimstat::$settings[ 'rows_to_show' ]
1382
+ );
1383
 
1384
+ // Count the results
1385
+ $count_page_results = count( $results );
 
1386
 
1387
+ if ($count_page_results == 0){
1388
+ echo '<p class="nodata">' . __( 'No data to display', 'wp-slimstat' ) . '</p>';
1389
 
1390
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
1391
+ die();
1392
+ }
1393
+ else{
1394
+ return array();
1395
+ }
1396
+ }
1397
 
1398
+ echo self::report_pagination( $count_page_results, count( $all_results ) );
1399
+ $is_expanded = ( wp_slimstat::$settings[ 'expand_details' ] == 'on' ) ? ' expanded' : '';
1400
 
1401
+ foreach ( $results as $a_result ) {
1402
+ echo "<p class='slimstat-tooltip-trigger'>{$a_result[ 'notes' ]} <b class='slimstat-tooltip-content$is_expanded'>" . __( 'Type', 'wp-slimstat' ) . ": {$a_result[ 'type' ]}";
1403
 
1404
+ if ( !empty( $a_result[ 'dt' ] ) ) {
1405
+ $date_time = date_i18n( wp_slimstat::$settings[ 'date_format' ] . ' ' . wp_slimstat::$settings[ 'time_format' ], $a_result[ 'dt' ], true );
1406
+ echo '<br/>' . __( 'Coordinates', 'wp-slimstat' ) . ": {$a_result[ 'position' ]}<br/>" . __( 'Date', 'wp-slimstat' ) . ": $date_time";
1407
+ }
1408
+ if ( !empty( $a_result[ 'counthits' ] ) ) {
1409
+ echo '<br/>' . __( 'Hits', 'wp-slimstat' ) . ": {$a_result[ 'counthits' ]}";
1410
+ }
1411
 
1412
+ echo "</b></p>";
 
 
 
 
1413
  }
1414
 
1415
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
1416
+ die();
 
 
 
 
 
 
 
 
 
 
 
 
1417
  }
1418
+ }
1419
 
1420
+ public static function show_group_by( $_args = array() ) {
1421
+ $all_results = call_user_func( $_args[ 'raw' ], $_args );
 
1422
 
1423
+ $results = array_slice(
1424
+ $all_results,
1425
+ wp_slimstat_db::$filters_normalized[ 'misc' ][ 'start_from' ],
1426
+ wp_slimstat::$settings[ 'rows_to_show' ]
1427
+ );
1428
 
1429
+ // Count the results
1430
+ $count_page_results = count( $results );
 
1431
 
1432
+ if ( $count_page_results == 0 ) {
1433
+ echo '<p class="nodata">' . __( 'No data to display', 'wp-slimstat' ) . '</p>';
 
1434
 
1435
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
1436
+ die();
1437
+ }
1438
+ else{
1439
+ return 0;
1440
+ }
1441
+ }
1442
 
1443
+ echo wp_slimstat_db::$debug_message;
1444
+ echo self::report_pagination( $count_page_results, count( $all_results ) );
1445
 
1446
+ foreach ( $results as $a_result ) {
1447
+ if ( empty( $a_result[ 'counthits' ] ) ) {
1448
+ $a_result[ 'counthits' ] = 0;
1449
+ }
1450
 
1451
+ $a_result[ 'resource' ] = "<a class='slimstat-font-logout slimstat-tooltip-trigger' target='_blank' title='" . htmlentities( __( 'Open this URL in a new window', 'wp-slimstat' ), ENT_QUOTES, 'UTF-8' ) . "' href='" . htmlentities( $a_result[ 'resource' ], ENT_QUOTES, 'UTF-8' ) . "'></a> <a class='slimstat-filter-link' href='" . wp_slimstat_reports::fs_url( 'resource equals ' . htmlentities( $a_result[ 'resource' ], ENT_QUOTES, 'UTF-8' ) ) . "'>" . self::get_resource_title( $a_result[ 'resource' ] ) . '</a>';
 
1452
 
1453
+ $group_markup = array();
1454
+ if ( !empty( $a_result[ 'column_group' ] ) ) {
1455
+ $exploded_group = explode( ';;;', $a_result[ 'column_group' ] );
1456
+ $group_markup = array();
1457
+ foreach ( $exploded_group as $a_item ) {
1458
+ $group_markup[] = '<a class="slimstat-filter-link" title="' . __( 'Filter by element in a group', 'wp-slimstat' ) . '" href="' . self::fs_url( $_args[ 'column_group' ] . ' equals ' . $a_item ) . '">' . $a_item . '</a>';
1459
+ }
1460
+ }
1461
 
1462
+ echo "<p>{$a_result[ 'resource' ]} <span>{$a_result[ 'counthits' ]}</span><br/>" . implode( ', ', $group_markup ) . "</p>";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1463
  }
1464
 
1465
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
1466
+ die();
 
 
 
 
 
 
 
 
 
 
 
 
1467
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1468
  }
1469
 
1470
  public static function show_rankings(){
1604
  }
1605
  }
1606
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1607
  public static function show_world_map() {
1608
  $countries = wp_slimstat_db::get_top( 'country' );
1609
  $recent_visits = wp_slimstat_db::get_recent( 'location', '', '', true, '', 'city' );
1631
  continue;
1632
  }
1633
 
1634
+ $percentage = ( wp_slimstat_db::$pageviews > 0 ) ? sprintf( "%01.2f", ( 100 * $a_country[ 'counthits' ] / wp_slimstat_db::$pageviews ) ) : 0;
1635
  $percentage_format = number_format( $percentage, 2, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] );
1636
  $balloon_text = __( 'c-' . $a_country[ 'country' ], 'wp-slimstat' ) . ': ' . $percentage_format . '% (' . number_format( $a_country[ 'counthits' ], 0, wp_slimstat_db::$formats[ 'decimal' ], wp_slimstat_db::$formats[ 'thousand' ] ) . ')';
1637
  $data_areas[ $a_country[ 'country' ] ] = '{id:"' . strtoupper( $a_country[ 'country' ] ) . '",balloonText:"' . $balloon_text . '",value:' . $percentage . '}';
1776
  $filters_html = "<ul class='slimstat-filter-list'>$filters_html</ul><a href='#' id='slimstat-save-filter' class='slimstat-filter-action-button button-secondary noslimstat' data-filter-array='" . htmlentities( json_encode( $_filters_array ), ENT_QUOTES, 'UTF-8' ) . "'>" . __( 'Save', 'wp-slimstat' ) . '</a>';
1777
  }
1778
 
1779
+ if ( !empty( $filters_html ) ) {
1780
  $filters_html .= '<a href="' . self::fs_url() . '" id="slimstat-remove-all-filters" class="button-secondary slimstat-filter-action-button noslimstat">' . __( 'Reset All', 'wp-slimstat' ) . '</a>';
1781
  }
1782
 
1810
  }
1811
  }
1812
 
1813
+ $fn = wp_slimstat_db::parse_filters( $_filters_string );
1814
 
1815
  // Columns
1816
+ if ( !empty( $fn[ 'columns' ] ) ) {
1817
+ foreach ( $fn[ 'columns' ] as $a_key => $a_filter ) {
1818
  $a_key = str_replace( '_calculated', '', $a_key );
1819
+ $request_uri .= "&amp;fs%5B$a_key%5D=" . urlencode( $a_filter[ 0 ] . ' ' . str_replace( '=', '%3D', $a_filter[ 1 ] ) );
1820
  }
1821
  }
1822
 
1823
  // Date ranges
1824
+ if ( !empty( $fn[ 'date' ] ) ) {
1825
+ foreach ( $fn[ 'date' ] as $a_key => $a_filter ) {
1826
  if ( isset( $a_filter ) ) {
1827
  $request_uri .= "&amp;fs%5B$a_key%5D=" . urlencode( 'equals ' . $a_filter );
1828
  }
1830
  }
1831
 
1832
  // Misc filters
1833
+ if ( !empty( $fn[ 'misc' ] ) ) {
1834
+ foreach ( $fn[ 'misc' ] as $a_key => $a_filter ) {
1835
  $request_uri .= "&amp;fs%5B$a_key%5D=" . urlencode( 'equals ' . $a_filter );
1836
  }
1837
  }
admin/wp-slimstat-admin.php CHANGED
@@ -11,7 +11,10 @@ class wp_slimstat_admin {
11
  * Init -- Sets things up.
12
  */
13
  public static function init() {
14
- self::$admin_notice = "We've completely rewritten the portion of code that handles the date ranges in the Filter Bar. In order to simplify things, <strong>we have deprecated</strong> the shortcode filter <code>interval_direction</code>, which is now expressed by the sign in front of the interval value (positive for going forward from a given start date, and negative for going back in time). Please note that this change affect your existing shortcodes, if they use the aforementioned filter. We will update our documentation in the next few days to remove any reference to this filter, and to avoid any confusion. We've also reintroduced the various levels of granularity for our charts: hourly (when a single day is selected), daily (for ranges up to 120 days) and monthly. Last but not least, the comparison chart is now <strong>always</strong> displayed, using new criteria to determine the range to use. You may want to change your settings (Settings > Reports > Default Time Span > Days, and Reports > Comparison Chart) to mimic the old behavior or hide the comparison chart altogether, if you like. Please feel free to contact us if you have any questions or to report any issues.";
 
 
 
15
  self::$admin_notice .= '<br/><br/><a id="slimstat-hide-admin-notice" href="#" class="button-secondary">Got it, thanks</a>';
16
 
17
  // Load language files
@@ -26,7 +29,7 @@ class wp_slimstat_admin {
26
  $has_network_reports = get_user_option( "meta-box-order_slimstat_page_slimlayout-network", 1 );
27
  self::$screens_info = array(
28
  'slimview1' => array(
29
- 'is_report_group' => false,
30
  'show_in_sidebar' => true,
31
  'title' => __( 'Access Log', 'wp-slimstat' ),
32
  'callback' => array( __CLASS__, 'wp_slimstat_include_view' )
@@ -55,12 +58,6 @@ class wp_slimstat_admin {
55
  'title' => __( 'Traffic Sources', 'wp-slimstat' ),
56
  'callback' => array( __CLASS__, 'wp_slimstat_include_view' )
57
  ),
58
- 'slimview6' => array(
59
- 'is_report_group' => true,
60
- 'show_in_sidebar' => true,
61
- 'title' => __( 'Geolocation', 'wp-slimstat' ),
62
- 'callback' => array( __CLASS__, 'wp_slimstat_include_view' )
63
- ),
64
  'slimlayout' => array(
65
  'is_report_group' => false,
66
  'show_in_sidebar' => ( empty( $has_network_reports ) || current_user_can( 'manage_options' ) ),
@@ -396,6 +393,25 @@ class wp_slimstat_admin {
396
  }
397
  // --- END: Updates for version 4.7.3.1 ---
398
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
  // Now we can update the version stored in the database
400
  wp_slimstat::$settings[ 'version' ] = wp_slimstat::$version;
401
 
@@ -886,6 +902,7 @@ class wp_slimstat_admin {
886
  $_setting_info = array_merge( array(
887
  'description' =>'',
888
  'type' => '',
 
889
  'long_description' => '',
890
  'before_input_field' => '',
891
  'after_input_field' => '',
@@ -980,6 +997,7 @@ class wp_slimstat_admin {
980
  <p>
981
  <textarea class="large-text code' . $use_tag_list . '"' . $is_readonly . '
982
  id="' . $_setting_slug . '"
 
983
  name="options[' . $_setting_slug . ']">' . ( isset( wp_slimstat::$settings[ $_setting_slug ] ) ? stripslashes( wp_slimstat::$settings[ $_setting_slug ] ) : '' ) . '</textarea>
984
  <span class="description">' . $_setting_info[ 'after_input_field' ] . '</span>
985
  </p>
11
  * Init -- Sets things up.
12
  */
13
  public static function init() {
14
+ self::$admin_notice = "A few users have reached out to us to ask if Slimstat would be compliant with the upcoming <a href='https://en.wikipedia.org/wiki/General_Data_Protection_Regulation' target='_blank'>General Data Protection Regulation (GDPR)</a> guidelines and regulations that are about to be activated all across Europe. Based on our understanding of this new law, as long as the hosting provider where you are storing the information collected by Slimstat is GDPR compliant, then you won't have to worry about any extra layers of compliance offered by software like ours. One of our primary goals is to make sure that you and only you are the sole owner of the data collected by our plugin. This has always been what makes Slimstat stand out from the crowd: while Jetpack, Google Analytics and many other services have full unrestricted access to the data they collect on your website, we at Slimstat don't treat our users as <em>the product</em> that we sell to other companies. Also, starting with this update, our plugin honors the <a href='https://en.wikipedia.org/wiki/Do_Not_Track' target='_blank'>Do Not Track header</a> (this feature can be turned off in the settings), and we introduced an experimental option to allow your users to opt out of tracking via a text box displayed. Please let us know if you notice any issues with these new features.";
15
+
16
+ // self::$admin_notice = "Now that we have a cleaner foundation to build on, it's time to start introducing new reports and new ways to segment your audience and the traffic they generate. While our users test the latest changes and updates (to confirm that the foundation is indeed solid and bug-free), we are hard at work implementing the first batch of new reports. Some of them will be made available in the free version, while others will be added to our premium add-on, <a href='http://www.wp-slimstat.com/downloads/user-overview/' target='_blank'>User Overview</a>. And we need your help! If you think that a specific report should be added to Slimstat, please do not hesitate <a href='http://support.wp-slimstat.com' target='_blank'>to let us know</a>.";
17
+
18
  self::$admin_notice .= '<br/><br/><a id="slimstat-hide-admin-notice" href="#" class="button-secondary">Got it, thanks</a>';
19
 
20
  // Load language files
29
  $has_network_reports = get_user_option( "meta-box-order_slimstat_page_slimlayout-network", 1 );
30
  self::$screens_info = array(
31
  'slimview1' => array(
32
+ 'is_report_group' => true,
33
  'show_in_sidebar' => true,
34
  'title' => __( 'Access Log', 'wp-slimstat' ),
35
  'callback' => array( __CLASS__, 'wp_slimstat_include_view' )
58
  'title' => __( 'Traffic Sources', 'wp-slimstat' ),
59
  'callback' => array( __CLASS__, 'wp_slimstat_include_view' )
60
  ),
 
 
 
 
 
 
61
  'slimlayout' => array(
62
  'is_report_group' => false,
63
  'show_in_sidebar' => ( empty( $has_network_reports ) || current_user_can( 'manage_options' ) ),
393
  }
394
  // --- END: Updates for version 4.7.3.1 ---
395
 
396
+ // --- Updates for version 4.7.8 ---
397
+ if ( version_compare( wp_slimstat::$settings[ 'version' ], '4.7.8', '<' ) ) {
398
+ // The Geolocation screen has been removed, and the World Map has been moved to the Audience tab
399
+ $page_location = ( wp_slimstat::$settings[ 'use_separate_menu' ] == 'on' ) ? 'slimstat' : 'admin';
400
+ $user_reports = get_user_option( "meta-box-order_{$page_location}_page_slimlayout", $GLOBALS[ 'current_user' ]->ID );
401
+
402
+ if ( !empty( $user_reports[ 'slimview6' ] ) ) {
403
+ if ( !empty( $user_reports[ 'slimview3' ] ) ) {
404
+ $user_reports[ 'slimview3' ] = $user_reports[ 'slimview3' ] . ',' . $user_reports[ 'slimview6' ];
405
+ }
406
+ else {
407
+ $user_reports[ 'slimview3' ] = $user_reports[ 'slimview6' ];
408
+ }
409
+ }
410
+
411
+ update_user_option( $GLOBALS[ 'current_user' ]->ID, "meta-box-order_{$page_location}_page_slimlayout", $user_reports );
412
+ }
413
+ // --- END: Updates for version 4.7.8 ---
414
+
415
  // Now we can update the version stored in the database
416
  wp_slimstat::$settings[ 'version' ] = wp_slimstat::$version;
417
 
902
  $_setting_info = array_merge( array(
903
  'description' =>'',
904
  'type' => '',
905
+ 'rows' => 4,
906
  'long_description' => '',
907
  'before_input_field' => '',
908
  'after_input_field' => '',
997
  <p>
998
  <textarea class="large-text code' . $use_tag_list . '"' . $is_readonly . '
999
  id="' . $_setting_slug . '"
1000
+ rows="' . $_setting_info[ 'rows' ] . '"
1001
  name="options[' . $_setting_slug . ']">' . ( isset( wp_slimstat::$settings[ $_setting_slug ] ) ? stripslashes( wp_slimstat::$settings[ $_setting_slug ] ) : '' ) . '</textarea>
1002
  <span class="description">' . $_setting_info[ 'after_input_field' ] . '</span>
1003
  </p>
readme.txt CHANGED
@@ -6,7 +6,7 @@ Text Domain: wp-slimstat
6
  Requires at least: 3.8
7
  Requires PHP: 5.2
8
  Tested up to: 4.9
9
- Stable tag: 4.7.7
10
 
11
  == Description ==
12
  The leading web analytics plugin for WordPress. Track returning customers and registered users, monitor Javascript events, detect intrusions, analyze email campaigns. Thousands of WordPress sites are already using it.
@@ -77,6 +77,19 @@ Our knowledge base is available on our [support center](http://docs.wp-slimstat.
77
  5. **Responsive layout** - Keep an eye on your reports on the go
78
 
79
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  = 4.7.7 =
81
  * [New] We've completely rewritten the portion of code that handles the date ranges in the Filter Bar. In order to simplify things, **we have deprecated** the `interval_direction` filter, which is now expressed by the sign in front of the interval value (positive for going forward from a given start date, and negative for going back in time). Please note that this change affect your existing shortcodes, if they use the aforementioned filter. We will update our documentation in the next few days to remove any reference to this filter, and to avoid any confusion. Please feel free to contact us if you have any questions or to report any issues.
82
  * [New] The comparison chart is now always displayed, using new criteria to determine the range to use. You may want to update your settings (Settings > Reports > Default Time Span > Days, and Reports > Comparison Chart) to mimic the old behavior or hide the comparison chart altogether, if you like.
6
  Requires at least: 3.8
7
  Requires PHP: 5.2
8
  Tested up to: 4.9
9
+ Stable tag: 4.7.8
10
 
11
  == Description ==
12
  The leading web analytics plugin for WordPress. Track returning customers and registered users, monitor Javascript events, detect intrusions, analyze email campaigns. Thousands of WordPress sites are already using it.
77
  5. **Responsive layout** - Keep an eye on your reports on the go
78
 
79
  == Changelog ==
80
+ = 4.7.8 =
81
+ * [Note] A few users have reached out to us to ask if Slimstat would be compliant with the upcoming [General Data Protection Regulation (GDPR)](https://en.wikipedia.org/wiki/General_Data_Protection_Regulation) guidelines and regulations that are about to be activated all across Europe. Based on our understanding of this new law, as long as the hosting provider where you are storing the information collected by Slimstat is GDPR compliant, then you won't have to worry about any extra layers of compliance offered by software like ours. One of our primary goals is to make sure that you and only you are the sole owner of the data collected by our plugin. This has always been what makes Slimstat stand out from the crowd: while Jetpack, Google Analytics and many other services have full unrestricted access to the data they collect on your website, we at Slimstat don't treat our users as *the product* that we sell to other companies.
82
+ * [New] Our plugin now honors the [Do Not Track header](https://en.wikipedia.org/wiki/Do_Not_Track). Please note that this feature can be turned off in the settings, and will be enabled by default.
83
+ * [New] We introduced an experimental option to allow your users to opt out of tracking via a text box displayed at the bottom of your website. Please go to Settings > Filters to customize the behavior and the message to suit your needs and website layout. You can also use third-party solutions to let your visitors opt out, and then configure Slimstat to read the corresponding cookie they set.
84
+ * [New] You can now add reports to the Access Log screen, and customize it just like any other screen in Slimstat.
85
+ * [Update] Reintroduced the `interval_minutes` filter, which had been temporarily removed from our code as a side effect of our code clean-up process. Thank you, [mth75](https://wordpress.org/support/topic/wrong-currently-online-value-shortcode/).
86
+ * [Update] Moved the button to reset the report layouts to the Customizer screen.
87
+ * [Update] Deprecated the Geolocation screen. The World Map report has been moved to the Audience tab. If for some reason you cannot find the World Map, please go to Slimstat > Customize and click the Reset All button.
88
+ * [Fix] Filters were not being set when opening the corresponding links in a new window. Thank you, [forumaad](https://wordpress.org/support/topic/bug-empty-filter-line-then-open-at-new-windows/)
89
+ * [Fix] Bug affecting the report "Currently Online".
90
+ * [Fix] Bug affecting all the filter links after the Export to Excel add-on had been enabled.
91
+ * [Fix] Bug affecting the resource filter when "nice permalinks" are not enabled.
92
+
93
  = 4.7.7 =
94
  * [New] We've completely rewritten the portion of code that handles the date ranges in the Filter Bar. In order to simplify things, **we have deprecated** the `interval_direction` filter, which is now expressed by the sign in front of the interval value (positive for going forward from a given start date, and negative for going back in time). Please note that this change affect your existing shortcodes, if they use the aforementioned filter. We will update our documentation in the next few days to remove any reference to this filter, and to avoid any confusion. Please feel free to contact us if you have any questions or to report any issues.
95
  * [New] The comparison chart is now always displayed, using new criteria to determine the range to use. You may want to update your settings (Settings > Reports > Default Time Span > Days, and Reports > Comparison Chart) to mimic the old behavior or hide the comparison chart altogether, if you like.
wp-slimstat.js CHANGED
@@ -1,464 +1,471 @@
1
- var SlimStat = {
2
- // Private Properties
3
- _id: "undefined" != typeof SlimStatParams.id ? SlimStatParams.id : "-1.0",
4
- _base64_key_str: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
5
- _plugins: {
6
- acrobat: {
7
- substrings: ["Adobe", "Acrobat"],
8
- active_x_strings: ["AcroPDF.PDF", "PDF.PDFCtrl.5"]
9
- },
10
- pdfviewer: {
11
- substrings: ["PDF"],
12
- active_x_strings: ["AcroPDF.PDF"]
13
- },
14
- flash: {
15
- substrings: ["Shockwave", "Flash"],
16
- active_x_strings: ["ShockwaveFlash.ShockwaveFlash"]
17
- },
18
- mediaplayer: {
19
- substrings: ["Windows Media"],
20
- active_x_strings: ["WMPlayer.OCX"]
21
- },
22
- quicktime: {
23
- substrings: ["QuickTime"],
24
- active_x_strings: ["QuickTime.QuickTime"]
25
- },
26
- silverlight: {
27
- substrings: ["Silverlight"],
28
- active_x_strings: ["AgControl.AgControl"]
29
- }
30
- },
31
-
32
- _utf8_encode : function( string ) {
33
- var n, c, utftext = "";
34
-
35
- string = string.replace(/\r\n/g, "\n");
36
-
37
- for ( n = 0; n < string.length; n++ ) {
38
- c = string.charCodeAt( n );
39
-
40
- if ( c < 128 ) {
41
- utftext += String.fromCharCode( c );
42
- }
43
- else if ( ( c > 127 ) && ( c < 2048 ) ) {
44
- utftext += String.fromCharCode( ( c >> 6 ) | 192 );
45
- utftext += String.fromCharCode( ( c & 63 ) | 128 );
46
- }
47
- else {
48
- utftext += String.fromCharCode( ( c >> 12 ) | 224 );
49
- utftext += String.fromCharCode( ( ( c >> 6 ) & 63 ) | 128 );
50
- utftext += String.fromCharCode( ( c & 63 ) | 128 );
51
- }
52
- }
53
- return utftext;
54
- },
55
-
56
- // Base64 Encode - http://www.webtoolkit.info/
57
- _base64_encode : function( input ) {
58
- var chr1, chr2, chr3, enc1, enc2, enc3, enc4, output = "", i = 0;
59
-
60
- input = SlimStat._utf8_encode( input );
61
-
62
- while ( i < input.length ) {
63
- chr1 = input.charCodeAt( i++ );
64
- chr2 = input.charCodeAt( i++ );
65
- chr3 = input.charCodeAt( i++ );
66
-
67
- enc1 = chr1 >> 2;
68
- enc2 = ( ( chr1 & 3 ) << 4 ) | ( chr2 >> 4 );
69
- enc3 = ( ( chr2 & 15 ) << 2 ) | ( chr3 >> 6 );
70
- enc4 = chr3 & 63;
71
-
72
- if ( isNaN( chr2 ) ) {
73
- enc3 = enc4 = 64;
74
- }
75
- else if ( isNaN( chr3 ) ) {
76
- enc4 = 64;
77
- }
78
-
79
- output = output + SlimStat._base64_key_str.charAt( enc1 ) + SlimStat._base64_key_str.charAt( enc2 ) + SlimStat._base64_key_str.charAt( enc3 ) + SlimStat._base64_key_str.charAt( enc4 );
80
- }
81
- return output;
82
- },
83
-
84
- _detect_single_plugin_not_ie : function( plugin_name ) {
85
- var plugin, haystack, found, i, j;
86
-
87
- for ( i in navigator.plugins ) {
88
- haystack = '' + navigator.plugins[ i ].name + navigator.plugins[ i ].description;
89
- found = 0;
90
-
91
- for ( j in SlimStat._plugins[ plugin_name ].substrings ) {
92
- if ( haystack.indexOf( SlimStat._plugins[ plugin_name ].substrings[ j ] ) != -1 ) {
93
- found++;
94
- }
95
- }
96
-
97
- if ( found == SlimStat._plugins[ plugin_name ].substrings.length ) {
98
- return true;
99
- }
100
- }
101
- return false;
102
- },
103
-
104
- _detect_single_plugin_ie : function( plugin_name ) {
105
- var i = '', found = false;
106
-
107
- for ( i in SlimStat._plugins[plugin_name].active_x_strings ) {
108
- try {
109
- new ActiveXObject( SlimStat._plugins[plugin_name].active_x_strings[i] );
110
- found = true;
111
- }
112
- catch( e ) { }
113
- }
114
-
115
- return found;
116
- },
117
-
118
- _detect_single_plugin : function( plugin_name ) {
119
- if ( navigator.plugins.length ) {
120
- this.detect = SlimStat._detect_single_plugin_not_ie;
121
- }
122
- else {
123
- this.detect = SlimStat._detect_single_plugin_ie;
124
- }
125
- return this.detect( plugin_name );
126
- },
127
-
128
- detect_plugins : function() {
129
- var a_plugin, plugins = [];
130
-
131
- for (a_plugin in SlimStat._plugins) {
132
- if (SlimStat._detect_single_plugin(a_plugin)) {
133
- plugins.push( a_plugin );
134
- }
135
- }
136
-
137
- // Detect Java
138
- if ( typeof navigator.javaEnabled == "function" && navigator.javaEnabled() ) {
139
- plugins.push( 'java' );
140
- }
141
-
142
- return plugins.join( "," );
143
- },
144
-
145
- get_page_performance : function() {
146
- slim_performance = window.performance || window.mozPerformance || window.msPerformance || window.webkitPerformance || {};
147
- if ( "undefined" == typeof slim_performance.timing ){
148
- return 0;
149
- }
150
-
151
- return slim_performance.timing.loadEventEnd - slim_performance.timing.responseEnd;
152
- },
153
-
154
- get_server_latency : function() {
155
- slim_performance = window.performance || window.mozPerformance || window.msPerformance || window.webkitPerformance || {};
156
- if ( "undefined" == typeof slim_performance.timing ){
157
- return 0;
158
- }
159
-
160
- return slim_performance.timing.responseEnd - slim_performance.timing.connectEnd;
161
- },
162
-
163
- add_event : function( obj, type, fn ) {
164
- if ( obj && obj.addEventListener ) {
165
- obj.addEventListener( type, fn, false );
166
- }
167
- else if ( obj && obj.attachEvent ) {
168
- obj[ "e" + type + fn ] = fn;
169
- obj[ type + fn ] = function() { obj[ "e" + type + fn ] ( window.event ); }
170
- obj.attachEvent( "on"+type, obj[type+fn] );
171
- }
172
- else {
173
- obj[ "on" + type ] = obj[ "e" + type + fn ];
174
- }
175
- },
176
-
177
- in_array : function( needle, haystack ) {
178
- for ( var i = 0; i < haystack.length; i++ ) {
179
- if ( haystack[ i ].trim() == needle ) {
180
- return true;
181
- }
182
- }
183
- return false;
184
- },
185
-
186
- in_array_substring : function( needle, haystack_of_substrings ) {
187
- for ( var i = 0; i < haystack_of_substrings.length; i++ ) {
188
- if ( needle.indexOf( haystack_of_substrings[ i ].trim() ) != -1 ) {
189
- return true;
190
- }
191
- }
192
- return false;
193
- },
194
-
195
- send_to_server : function( data, use_beacon ) {
196
- if ( "undefined" == typeof SlimStatParams.ajaxurl || "undefined" == typeof data ) {
197
- return false;
198
- }
199
-
200
- if ( "undefined" == typeof use_beacon ) {
201
- use_beacon = true;
202
- }
203
-
204
- slimstat_data_with_client_info = data + "&sw=" + screen.width + "&sh=" + screen.height + "&bw=" + window.innerWidth + "&bh=" + window.innerHeight + "&sl=" + SlimStat.get_server_latency() + "&pp=" + SlimStat.get_page_performance() + "&pl=" + SlimStat.detect_plugins();
205
-
206
- if ( use_beacon && navigator.sendBeacon ) {
207
- navigator.sendBeacon( SlimStatParams.ajaxurl, slimstat_data_with_client_info );
208
- }
209
- else {
210
- try {
211
- if ( window.XMLHttpRequest ) {
212
- request = new XMLHttpRequest();
213
- }
214
- else if ( window.ActiveXObject ) { // code for IE6, IE5
215
- request = new ActiveXObject( "Microsoft.XMLHTTP" );
216
- }
217
- } catch ( failed ) {
218
- return false;
219
- }
220
-
221
- if ( request ) {
222
- request.open( "POST", SlimStatParams.ajaxurl, true );
223
- request.setRequestHeader( "Content-type", "application/x-www-form-urlencoded" );
224
- request.setRequestHeader( "X-Requested-With", "XMLHttpRequest" );
225
- request.withCredentials = true;
226
- request.send( slimstat_data_with_client_info );
227
-
228
- request.onreadystatechange = function() {
229
- if ( 4 == request.readyState ) {
230
- parsed_id = parseInt( request.responseText );
231
- if ( !isNaN( parsed_id ) && parsed_id > 0 ) {
232
- SlimStat._id = request.responseText;
233
- }
234
- }
235
- }
236
-
237
- return true;
238
- }
239
- }
240
-
241
- return false;
242
- },
243
-
244
- ss_track : function( e, type, note, use_beacon ) {
245
- // Check function params
246
- e = e ? e : window.event;
247
- type = ( "undefined" == typeof type ) ? 0 : parseInt( type );
248
- note_array = [];
249
-
250
- if ( "undefined" == typeof use_beacon ) {
251
- use_beacon = true;
252
- }
253
-
254
- parsed_id = parseInt( SlimStat._id );
255
- if ( isNaN( parsed_id ) || parsed_id <= 0 ) {
256
- return false;
257
- }
258
-
259
- node = ( "undefined" != typeof e.target ) ? e.target : ( ( "undefined" != typeof e.srcElement ) ? e.srcElement : false );
260
- if ( !node ) {
261
- return false;
262
- }
263
-
264
- // Safari bug
265
- if ( 3 == node.nodeType ) {
266
- node = node.parentNode;
267
- }
268
-
269
- parent_node = node.parentNode;
270
- resource_url = '';
271
-
272
- // This handler can be attached to any element, but only A tags carry the extra info we need
273
- switch ( node.nodeName ) {
274
- case 'FORM':
275
- if ( "undefined" != typeof node.action && node.action ) {
276
- resource_url = node.action;
277
- }
278
- break;
279
-
280
- case 'INPUT':
281
- // Let's look for a FORM element
282
- while ( "undefined" != typeof parent_node && parent_node.nodeName != "FORM" && parent_node.nodeName != "BODY" ) {
283
- parent_node = parent_node.parentNode;
284
- }
285
- if ( "undefined" != typeof parent_node.action && parent_node.action ) {
286
- resource_url = parent_node.action;
287
- break;
288
- }
289
-
290
- default:
291
- // Any other element
292
- if ( "A" != node.nodeName ) {
293
- while ( "undefined" != typeof node.parentNode && null != node.parentNode && "A" != node.nodeName && "BODY" != node.nodeName ) {
294
- node = node.parentNode;
295
- }
296
- }
297
-
298
- // Anchor in the same page
299
- if ( "undefined" != typeof node.hash && node.hash && node.hostname == location.hostname ) {
300
- resource_url = node.hash;
301
- }
302
- else if ( "undefined" != typeof node.href && node.href.indexOf( 'javascript:' ) == -1 ) {
303
- resource_url = node.href;
304
- }
305
-
306
- // If this element has a title, we can record that as well
307
- if ( "function" == typeof node.getAttribute ) {
308
- if ( "undefined" != typeof node.getAttribute( "title" ) && node.getAttribute( "title" ) ) {
309
- note_array.push( "Title:" + node.getAttribute( "title" ) );
310
- }
311
- if ( "undefined" != typeof node.getAttribute( "id" ) && node.getAttribute( "id" ) ) {
312
- note_array.push( "ID:" + node.getAttribute( "id" ) );
313
- }
314
- }
315
- }
316
-
317
- // Event coordinates
318
- pos_x = -1;
319
- pos_y = -1;
320
- position = "";
321
-
322
- if ( "undefined" != typeof e.pageX && "undefined" != typeof e.pageY ) {
323
- pos_x = e.pageX;
324
- pos_y = e.pageY;
325
- }
326
- else if ( "undefined" != typeof e.clientX && "undefined" != typeof e.clientY &&
327
- "undefined" != typeof document.body.scrollLeft && "undefined" != typeof document.documentElement.scrollLeft &&
328
- "undefined" != typeof document.body.scrollTop && "undefined" != typeof document.documentElement.scrollTop ) {
329
- pos_x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
330
- pos_y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
331
- }
332
-
333
- if ( pos_x > 0 && pos_y > 0 ) {
334
- position = pos_x + "," + pos_y;
335
- }
336
-
337
- // Event description and button pressed
338
- if ( "undefined" != typeof e.type ) {
339
- event_description = e.type;
340
- if ( "keypress" == e.type ) {
341
- event_description += '; keypress:' + String.fromCharCode( parseInt( e.which ) );
342
- }
343
- else if ( "click" == e.type ) {
344
- event_description += '; which:' + e.which;
345
- }
346
- }
347
-
348
- // Custom description for this event
349
- if ( "undefined" != typeof note && note ){
350
- note_array.push( note );
351
- }
352
-
353
- note_string = SlimStat._base64_encode( note_array.join( ", " ) );
354
- requested_op = "add";
355
-
356
- if ( 1 == type ) {
357
- resource_url = resource_url.substring( resource_url.indexOf( location.hostname ) + location.hostname.length );
358
- }
359
- else if ( 0 == type || 2 == type ) {
360
- requested_op = "update";
361
- }
362
- else {
363
- requested_op = "event";
364
- }
365
-
366
- SlimStat.send_to_server( "action=slimtrack&op=" + requested_op + "&id=" + SlimStat._id + "&ty=" + type + "&ref=" + SlimStat._base64_encode( document.referrer ) + "&res=" + SlimStat._base64_encode( resource_url ) + "&pos=" + position + "&des=" + SlimStat._base64_encode( event_description ) + "&no=" + note_string, use_beacon );
367
-
368
- return true;
369
- }
370
- }
371
-
372
- // Helper function
373
- if ( typeof String.prototype.trim !== 'function' ) {
374
- String.prototype.trim = function() {
375
- return this.replace( /^\s+|\s+$/g, '' );
376
- }
377
- }
378
-
379
- SlimStat.add_event( window, "load", function() {
380
- all_links = document.getElementsByTagName( "a" );
381
- var extensions_to_track = ( "undefined" != typeof SlimStatParams.extensions_to_track && SlimStatParams.extensions_to_track ) ? SlimStatParams.extensions_to_track.split( ',' ) : [];
382
- var to_not_track = ( "undefined" != typeof SlimStatParams.outbound_classes_rel_href_to_not_track && SlimStatParams.outbound_classes_rel_href_to_not_track ) ? SlimStatParams.outbound_classes_rel_href_to_not_track.split( ',' ) : [];
383
-
384
- for (var i = 0; i < all_links.length; i++) {
385
- // Types
386
- // 0: external
387
- // 1: download
388
- // 2: internal (track coordinates only)
389
-
390
- linktype = ( all_links[ i ].href && ( all_links[ i ].hostname == location.hostname || all_links[ i ].href.indexOf( '://' ) == -1 ) || all_links[ i ].href.indexOf( 'javascript:' ) == -1 ) ? 2 : 0;
391
- tracking = 1;
392
-
393
- // Do not track links with given class names...
394
- if ( to_not_track.length > 0 ) {
395
- if ( 1 == tracking ) {
396
- classes_current_link = ( "undefined" != typeof all_links[ i ].className && all_links[ i ].className ) ? all_links[ i ].className.split( " " ) : [];
397
-
398
- for ( var cl = 0; cl < classes_current_link.length; cl++ ) {
399
- if ( SlimStat.in_array_substring( classes_current_link[ cl ], to_not_track ) ) {
400
- tracking = 0;
401
- break;
402
- }
403
- }
404
- }
405
-
406
- // ... or rel attribute
407
- if ( 1 == tracking && "undefined" != typeof all_links[ i ].attributes.rel && all_links[ i ].attributes.rel.value ) {
408
- if ( SlimStat.in_array_substring( all_links[ i ].attributes.rel.value, to_not_track ) ) {
409
- tracking = 0;
410
- }
411
- }
412
-
413
- // ... or HREF attribute
414
- if ( 1 == tracking && "undefined" != typeof all_links[ i ].href && all_links[ i ].href ) {
415
- if ( SlimStat.in_array_substring( all_links[ i ].href, to_not_track ) ) {
416
- tracking = 0;
417
- }
418
- }
419
- }
420
-
421
- // Downloads
422
- extension_current_link = all_links[ i ].pathname.split( /[?#]/ )[ 0 ].split( '.' ).pop().replace( /[\/\-]/g, '' );
423
- if ( 2 == linktype && extensions_to_track.length > 0 && SlimStat.in_array( extension_current_link, extensions_to_track ) ) {
424
- tracking = 1;
425
- linktype = 1;
426
- }
427
-
428
- all_links[ i ].setAttribute( "data-slimstat", ( linktype << 1 ) + tracking );
429
-
430
- SlimStat.add_event( all_links[ i ], "click", function( e ) {
431
- link_info = parseInt( this.getAttribute( "data-slimstat" ) );
432
- if ( isNaN ( link_info ) ) {
433
- link_info = 0;
434
- }
435
-
436
- // tracking: link_info & 1 --- linktype: link_info >> 1;
437
- if ( link_info & 1 == 1 ) {
438
- SlimStat.ss_track( e, link_info >> 1, "" );
439
- }
440
- });
441
- }
442
- } );
443
-
444
- var slimstat_data = "";
445
- var use_beacon = true;
446
-
447
- if ( "undefined" != typeof SlimStatParams.id && parseInt( SlimStatParams.id ) > 0 ) {
448
- slimstat_data = "action=slimtrack&op=update&id=" + SlimStatParams.id;
449
- }
450
- else if ( "undefined" != typeof SlimStatParams.ci ) {
451
- slimstat_data = "action=slimtrack&op=add&id=" + SlimStatParams.ci + "&ref=" + SlimStat._base64_encode( document.referrer ) + "&res=" + SlimStat._base64_encode( window.location.href );
452
-
453
- // If the tracker is working in "client mode", it needs to wait for the server to assign it a page view ID
454
- use_beacon = false;
455
- }
456
-
457
- // Gather all the information and send it to the server
458
- if ( slimstat_data.length > 0 ) {
459
- SlimStat.add_event( window, 'load', function(){
460
- setTimeout( function(){
461
- SlimStat.send_to_server( slimstat_data, '' );
462
- }, 0 );
463
- } );
 
 
 
 
 
 
 
464
  }
1
+ var SlimStat = {
2
+ // Private Properties
3
+ _id: "undefined" != typeof SlimStatParams.id ? SlimStatParams.id : "-1.0",
4
+ _base64_key_str: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
5
+ _plugins: {
6
+ acrobat: {
7
+ substrings: ["Adobe", "Acrobat"],
8
+ active_x_strings: ["AcroPDF.PDF", "PDF.PDFCtrl.5"]
9
+ },
10
+ pdfviewer: {
11
+ substrings: ["PDF"],
12
+ active_x_strings: ["AcroPDF.PDF"]
13
+ },
14
+ flash: {
15
+ substrings: ["Shockwave", "Flash"],
16
+ active_x_strings: ["ShockwaveFlash.ShockwaveFlash"]
17
+ },
18
+ mediaplayer: {
19
+ substrings: ["Windows Media"],
20
+ active_x_strings: ["WMPlayer.OCX"]
21
+ },
22
+ quicktime: {
23
+ substrings: ["QuickTime"],
24
+ active_x_strings: ["QuickTime.QuickTime"]
25
+ },
26
+ silverlight: {
27
+ substrings: ["Silverlight"],
28
+ active_x_strings: ["AgControl.AgControl"]
29
+ }
30
+ },
31
+
32
+ _utf8_encode : function( string ) {
33
+ var n, c, utftext = "";
34
+
35
+ string = string.replace(/\r\n/g, "\n");
36
+
37
+ for ( n = 0; n < string.length; n++ ) {
38
+ c = string.charCodeAt( n );
39
+
40
+ if ( c < 128 ) {
41
+ utftext += String.fromCharCode( c );
42
+ }
43
+ else if ( ( c > 127 ) && ( c < 2048 ) ) {
44
+ utftext += String.fromCharCode( ( c >> 6 ) | 192 );
45
+ utftext += String.fromCharCode( ( c & 63 ) | 128 );
46
+ }
47
+ else {
48
+ utftext += String.fromCharCode( ( c >> 12 ) | 224 );
49
+ utftext += String.fromCharCode( ( ( c >> 6 ) & 63 ) | 128 );
50
+ utftext += String.fromCharCode( ( c & 63 ) | 128 );
51
+ }
52
+ }
53
+ return utftext;
54
+ },
55
+
56
+ // Base64 Encode - http://www.webtoolkit.info/
57
+ _base64_encode : function( input ) {
58
+ var chr1, chr2, chr3, enc1, enc2, enc3, enc4, output = "", i = 0;
59
+
60
+ input = SlimStat._utf8_encode( input );
61
+
62
+ while ( i < input.length ) {
63
+ chr1 = input.charCodeAt( i++ );
64
+ chr2 = input.charCodeAt( i++ );
65
+ chr3 = input.charCodeAt( i++ );
66
+
67
+ enc1 = chr1 >> 2;
68
+ enc2 = ( ( chr1 & 3 ) << 4 ) | ( chr2 >> 4 );
69
+ enc3 = ( ( chr2 & 15 ) << 2 ) | ( chr3 >> 6 );
70
+ enc4 = chr3 & 63;
71
+
72
+ if ( isNaN( chr2 ) ) {
73
+ enc3 = enc4 = 64;
74
+ }
75
+ else if ( isNaN( chr3 ) ) {
76
+ enc4 = 64;
77
+ }
78
+
79
+ output = output + SlimStat._base64_key_str.charAt( enc1 ) + SlimStat._base64_key_str.charAt( enc2 ) + SlimStat._base64_key_str.charAt( enc3 ) + SlimStat._base64_key_str.charAt( enc4 );
80
+ }
81
+ return output;
82
+ },
83
+
84
+ _detect_single_plugin_not_ie : function( plugin_name ) {
85
+ var plugin, haystack, found, i, j;
86
+
87
+ for ( i in navigator.plugins ) {
88
+ haystack = '' + navigator.plugins[ i ].name + navigator.plugins[ i ].description;
89
+ found = 0;
90
+
91
+ for ( j in SlimStat._plugins[ plugin_name ].substrings ) {
92
+ if ( haystack.indexOf( SlimStat._plugins[ plugin_name ].substrings[ j ] ) != -1 ) {
93
+ found++;
94
+ }
95
+ }
96
+
97
+ if ( found == SlimStat._plugins[ plugin_name ].substrings.length ) {
98
+ return true;
99
+ }
100
+ }
101
+ return false;
102
+ },
103
+
104
+ _detect_single_plugin_ie : function( plugin_name ) {
105
+ var i = '', found = false;
106
+
107
+ for ( i in SlimStat._plugins[plugin_name].active_x_strings ) {
108
+ try {
109
+ new ActiveXObject( SlimStat._plugins[plugin_name].active_x_strings[i] );
110
+ found = true;
111
+ }
112
+ catch( e ) { }
113
+ }
114
+
115
+ return found;
116
+ },
117
+
118
+ _detect_single_plugin : function( plugin_name ) {
119
+ if ( navigator.plugins.length ) {
120
+ this.detect = SlimStat._detect_single_plugin_not_ie;
121
+ }
122
+ else {
123
+ this.detect = SlimStat._detect_single_plugin_ie;
124
+ }
125
+ return this.detect( plugin_name );
126
+ },
127
+
128
+ detect_plugins : function() {
129
+ var a_plugin, plugins = [];
130
+
131
+ for (a_plugin in SlimStat._plugins) {
132
+ if (SlimStat._detect_single_plugin(a_plugin)) {
133
+ plugins.push( a_plugin );
134
+ }
135
+ }
136
+
137
+ // Detect Java
138
+ if ( typeof navigator.javaEnabled == "function" && navigator.javaEnabled() ) {
139
+ plugins.push( 'java' );
140
+ }
141
+
142
+ return plugins.join( "," );
143
+ },
144
+
145
+ get_page_performance : function() {
146
+ slim_performance = window.performance || window.mozPerformance || window.msPerformance || window.webkitPerformance || {};
147
+ if ( "undefined" == typeof slim_performance.timing ){
148
+ return 0;
149
+ }
150
+
151
+ return slim_performance.timing.loadEventEnd - slim_performance.timing.responseEnd;
152
+ },
153
+
154
+ get_server_latency : function() {
155
+ slim_performance = window.performance || window.mozPerformance || window.msPerformance || window.webkitPerformance || {};
156
+ if ( "undefined" == typeof slim_performance.timing ){
157
+ return 0;
158
+ }
159
+
160
+ return slim_performance.timing.responseEnd - slim_performance.timing.connectEnd;
161
+ },
162
+
163
+ add_event : function( obj, type, fn ) {
164
+ if ( obj && obj.addEventListener ) {
165
+ obj.addEventListener( type, fn, false );
166
+ }
167
+ else if ( obj && obj.attachEvent ) {
168
+ obj[ "e" + type + fn ] = fn;
169
+ obj[ type + fn ] = function() { obj[ "e" + type + fn ] ( window.event ); }
170
+ obj.attachEvent( "on"+type, obj[type+fn] );
171
+ }
172
+ else {
173
+ obj[ "on" + type ] = obj[ "e" + type + fn ];
174
+ }
175
+ },
176
+
177
+ in_array : function( needle, haystack ) {
178
+ for ( var i = 0; i < haystack.length; i++ ) {
179
+ if ( haystack[ i ].trim() == needle ) {
180
+ return true;
181
+ }
182
+ }
183
+ return false;
184
+ },
185
+
186
+ in_array_substring : function( needle, haystack_of_substrings ) {
187
+ for ( var i = 0; i < haystack_of_substrings.length; i++ ) {
188
+ if ( needle.indexOf( haystack_of_substrings[ i ].trim() ) != -1 ) {
189
+ return true;
190
+ }
191
+ }
192
+ return false;
193
+ },
194
+
195
+ send_to_server : function( data, use_beacon ) {
196
+ if ( "undefined" == typeof SlimStatParams.ajaxurl || "undefined" == typeof data ) {
197
+ return false;
198
+ }
199
+
200
+ if ( "undefined" == typeof use_beacon ) {
201
+ use_beacon = true;
202
+ }
203
+
204
+ slimstat_data_with_client_info = data + "&sw=" + screen.width + "&sh=" + screen.height + "&bw=" + window.innerWidth + "&bh=" + window.innerHeight + "&sl=" + SlimStat.get_server_latency() + "&pp=" + SlimStat.get_page_performance() + "&pl=" + SlimStat.detect_plugins();
205
+
206
+ if ( use_beacon && navigator.sendBeacon ) {
207
+ navigator.sendBeacon( SlimStatParams.ajaxurl, slimstat_data_with_client_info );
208
+ }
209
+ else {
210
+ try {
211
+ if ( window.XMLHttpRequest ) {
212
+ request = new XMLHttpRequest();
213
+ }
214
+ else if ( window.ActiveXObject ) { // code for IE6, IE5
215
+ request = new ActiveXObject( "Microsoft.XMLHTTP" );
216
+ }
217
+ } catch ( failed ) {
218
+ return false;
219
+ }
220
+
221
+ if ( request ) {
222
+ request.open( "POST", SlimStatParams.ajaxurl, true );
223
+ request.setRequestHeader( "Content-type", "application/x-www-form-urlencoded" );
224
+ request.setRequestHeader( "X-Requested-With", "XMLHttpRequest" );
225
+ request.withCredentials = true;
226
+ request.send( slimstat_data_with_client_info );
227
+
228
+ request.onreadystatechange = function() {
229
+ if ( 4 == request.readyState ) {
230
+ parsed_id = parseInt( request.responseText );
231
+ if ( !isNaN( parsed_id ) && parsed_id > 0 ) {
232
+ SlimStat._id = request.responseText;
233
+ }
234
+ }
235
+ }
236
+
237
+ return true;
238
+ }
239
+ }
240
+
241
+ return false;
242
+ },
243
+
244
+ ss_track : function( e, type, note, use_beacon ) {
245
+ // Check function params
246
+ e = e ? e : window.event;
247
+ type = ( "undefined" == typeof type ) ? 0 : parseInt( type );
248
+ note_array = [];
249
+
250
+ if ( "undefined" == typeof use_beacon ) {
251
+ use_beacon = true;
252
+ }
253
+
254
+ parsed_id = parseInt( SlimStat._id );
255
+ if ( isNaN( parsed_id ) || parsed_id <= 0 ) {
256
+ return false;
257
+ }
258
+
259
+ node = ( "undefined" != typeof e.target ) ? e.target : ( ( "undefined" != typeof e.srcElement ) ? e.srcElement : false );
260
+ if ( !node ) {
261
+ return false;
262
+ }
263
+
264
+ // Safari bug
265
+ if ( 3 == node.nodeType ) {
266
+ node = node.parentNode;
267
+ }
268
+
269
+ parent_node = node.parentNode;
270
+ resource_url = '';
271
+
272
+ // This handler can be attached to any element, but only A tags carry the extra info we need
273
+ switch ( node.nodeName ) {
274
+ case 'FORM':
275
+ if ( "undefined" != typeof node.action && node.action ) {
276
+ resource_url = node.action;
277
+ }
278
+ break;
279
+
280
+ case 'INPUT':
281
+ // Let's look for a FORM element
282
+ while ( "undefined" != typeof parent_node && parent_node.nodeName != "FORM" && parent_node.nodeName != "BODY" ) {
283
+ parent_node = parent_node.parentNode;
284
+ }
285
+ if ( "undefined" != typeof parent_node.action && parent_node.action ) {
286
+ resource_url = parent_node.action;
287
+ break;
288
+ }
289
+
290
+ default:
291
+ // Any other element
292
+ if ( "A" != node.nodeName ) {
293
+ while ( "undefined" != typeof node.parentNode && null != node.parentNode && "A" != node.nodeName && "BODY" != node.nodeName ) {
294
+ node = node.parentNode;
295
+ }
296
+ }
297
+
298
+ // Anchor in the same page
299
+ if ( "undefined" != typeof node.hash && node.hash && node.hostname == location.hostname ) {
300
+ resource_url = node.hash;
301
+ }
302
+ else if ( "undefined" != typeof node.href && node.href.indexOf( 'javascript:' ) == -1 ) {
303
+ resource_url = node.href;
304
+ }
305
+
306
+ // If this element has a title, we can record that as well
307
+ if ( "function" == typeof node.getAttribute ) {
308
+ if ( "undefined" != typeof node.getAttribute( "title" ) && node.getAttribute( "title" ) ) {
309
+ note_array.push( "Title:" + node.getAttribute( "title" ) );
310
+ }
311
+ if ( "undefined" != typeof node.getAttribute( "id" ) && node.getAttribute( "id" ) ) {
312
+ note_array.push( "ID:" + node.getAttribute( "id" ) );
313
+ }
314
+ }
315
+ }
316
+
317
+ // Event coordinates
318
+ pos_x = -1;
319
+ pos_y = -1;
320
+ position = "";
321
+
322
+ if ( "undefined" != typeof e.pageX && "undefined" != typeof e.pageY ) {
323
+ pos_x = e.pageX;
324
+ pos_y = e.pageY;
325
+ }
326
+ else if ( "undefined" != typeof e.clientX && "undefined" != typeof e.clientY &&
327
+ "undefined" != typeof document.body.scrollLeft && "undefined" != typeof document.documentElement.scrollLeft &&
328
+ "undefined" != typeof document.body.scrollTop && "undefined" != typeof document.documentElement.scrollTop ) {
329
+ pos_x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
330
+ pos_y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
331
+ }
332
+
333
+ if ( pos_x > 0 && pos_y > 0 ) {
334
+ position = pos_x + "," + pos_y;
335
+ }
336
+
337
+ // Event description and button pressed
338
+ if ( "undefined" != typeof e.type ) {
339
+ event_description = e.type;
340
+ if ( "keypress" == e.type ) {
341
+ event_description += '; keypress:' + String.fromCharCode( parseInt( e.which ) );
342
+ }
343
+ else if ( "click" == e.type ) {
344
+ event_description += '; which:' + e.which;
345
+ }
346
+ }
347
+
348
+ // Custom description for this event
349
+ if ( "undefined" != typeof note && note ){
350
+ note_array.push( note );
351
+ }
352
+
353
+ note_string = SlimStat._base64_encode( note_array.join( ", " ) );
354
+ requested_op = "add";
355
+
356
+ if ( 1 == type ) {
357
+ resource_url = resource_url.substring( resource_url.indexOf( location.hostname ) + location.hostname.length );
358
+ }
359
+ else if ( 0 == type || 2 == type ) {
360
+ requested_op = "update";
361
+ }
362
+ else {
363
+ requested_op = "event";
364
+ }
365
+
366
+ SlimStat.send_to_server( "action=slimtrack&op=" + requested_op + "&id=" + SlimStat._id + "&ty=" + type + "&ref=" + SlimStat._base64_encode( document.referrer ) + "&res=" + SlimStat._base64_encode( resource_url ) + "&pos=" + position + "&des=" + SlimStat._base64_encode( event_description ) + "&no=" + note_string, use_beacon );
367
+
368
+ return true;
369
+ },
370
+
371
+ attach_tracker: function() {
372
+ all_links = document.getElementsByTagName( "a" );
373
+ var extensions_to_track = ( "undefined" != typeof SlimStatParams.extensions_to_track && SlimStatParams.extensions_to_track ) ? SlimStatParams.extensions_to_track.split( ',' ) : [];
374
+ var to_not_track = ( "undefined" != typeof SlimStatParams.outbound_classes_rel_href_to_not_track && SlimStatParams.outbound_classes_rel_href_to_not_track ) ? SlimStatParams.outbound_classes_rel_href_to_not_track.split( ',' ) : [];
375
+
376
+ for ( var i = 0; i < all_links.length; i++ ) {
377
+ // Types
378
+ // 0: external
379
+ // 1: download
380
+ // 2: internal (track coordinates only)
381
+
382
+ linktype = ( all_links[ i ].href && ( all_links[ i ].hostname == location.hostname || all_links[ i ].href.indexOf( '://' ) == -1 ) || all_links[ i ].href.indexOf( 'javascript:' ) == -1 ) ? 2 : 0;
383
+ tracking = 1;
384
+
385
+ // Do not track links with given class names...
386
+ if ( to_not_track.length > 0 ) {
387
+ if ( 1 == tracking ) {
388
+ classes_current_link = ( "undefined" != typeof all_links[ i ].className && all_links[ i ].className ) ? all_links[ i ].className.split( " " ) : [];
389
+
390
+ for ( var cl = 0; cl < classes_current_link.length; cl++ ) {
391
+ if ( SlimStat.in_array_substring( classes_current_link[ cl ], to_not_track ) ) {
392
+ tracking = 0;
393
+ break;
394
+ }
395
+ }
396
+ }
397
+
398
+ // ... or rel attribute
399
+ if ( 1 == tracking && "undefined" != typeof all_links[ i ].attributes.rel && all_links[ i ].attributes.rel.value ) {
400
+ if ( SlimStat.in_array_substring( all_links[ i ].attributes.rel.value, to_not_track ) ) {
401
+ tracking = 0;
402
+ }
403
+ }
404
+
405
+ // ... or HREF attribute
406
+ if ( 1 == tracking && "undefined" != typeof all_links[ i ].href && all_links[ i ].href ) {
407
+ if ( SlimStat.in_array_substring( all_links[ i ].href, to_not_track ) ) {
408
+ tracking = 0;
409
+ }
410
+ }
411
+ }
412
+
413
+ // Downloads
414
+ extension_current_link = all_links[ i ].pathname.split( /[?#]/ )[ 0 ].split( '.' ).pop().replace( /[\/\-]/g, '' );
415
+ if ( 2 == linktype && extensions_to_track.length > 0 && SlimStat.in_array( extension_current_link, extensions_to_track ) ) {
416
+ tracking = 1;
417
+ linktype = 1;
418
+ }
419
+
420
+ all_links[ i ].setAttribute( "data-slimstat", ( linktype << 1 ) + tracking );
421
+
422
+ SlimStat.add_event( all_links[ i ], "click", function( e ) {
423
+ link_info = parseInt( this.getAttribute( "data-slimstat" ) );
424
+ if ( isNaN ( link_info ) ) {
425
+ link_info = 0;
426
+ }
427
+
428
+ // tracking: link_info & 1 --- linktype: link_info >> 1;
429
+ if ( link_info & 1 == 1 ) {
430
+ SlimStat.ss_track( e, link_info >> 1, "" );
431
+ }
432
+ });
433
+ }
434
+ }
435
+ }
436
+
437
+ // Helper function
438
+ if ( typeof String.prototype.trim !== 'function' ) {
439
+ String.prototype.trim = function() {
440
+ return this.replace( /^\s+|\s+$/g, '' );
441
+ }
442
+ }
443
+
444
+ SlimStat.add_event( window, "load", function() {
445
+ // Attach an event tracker to all the links on the page that satisfy the criteria set by the admin
446
+ SlimStat.attach_tracker();
447
+
448
+ //
449
+ } );
450
+
451
+ var slimstat_data = "";
452
+ var use_beacon = true;
453
+
454
+ if ( "undefined" != typeof SlimStatParams.id && parseInt( SlimStatParams.id ) > 0 ) {
455
+ slimstat_data = "action=slimtrack&op=update&id=" + SlimStatParams.id;
456
+ }
457
+ else if ( "undefined" != typeof SlimStatParams.ci ) {
458
+ slimstat_data = "action=slimtrack&op=add&id=" + SlimStatParams.ci + "&ref=" + SlimStat._base64_encode( document.referrer ) + "&res=" + SlimStat._base64_encode( window.location.href );
459
+
460
+ // If the tracker is working in "client mode", it needs to wait for the server to assign it a page view ID
461
+ use_beacon = false;
462
+ }
463
+
464
+ // Gather all the information and send it to the server
465
+ if ( slimstat_data.length > 0 ) {
466
+ SlimStat.add_event( window, 'load', function(){
467
+ setTimeout( function(){
468
+ SlimStat.send_to_server( slimstat_data, '' );
469
+ }, 0 );
470
+ } );
471
  }
wp-slimstat.min.js CHANGED
@@ -1 +1 @@
1
- var SlimStat={_id:void 0!==SlimStatParams.id?SlimStatParams.id:"-1.0",_base64_key_str:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",_plugins:{acrobat:{substrings:["Adobe","Acrobat"],active_x_strings:["AcroPDF.PDF","PDF.PDFCtrl.5"]},pdfviewer:{substrings:["PDF"],active_x_strings:["AcroPDF.PDF"]},flash:{substrings:["Shockwave","Flash"],active_x_strings:["ShockwaveFlash.ShockwaveFlash"]},mediaplayer:{substrings:["Windows Media"],active_x_strings:["WMPlayer.OCX"]},quicktime:{substrings:["QuickTime"],active_x_strings:["QuickTime.QuickTime"]},silverlight:{substrings:["Silverlight"],active_x_strings:["AgControl.AgControl"]}},_utf8_encode:function(e){var t,n,i="";for(e=e.replace(/\r\n/g,"\n"),t=0;t<e.length;t++)(n=e.charCodeAt(t))<128?i+=String.fromCharCode(n):n>127&&n<2048?(i+=String.fromCharCode(n>>6|192),i+=String.fromCharCode(63&n|128)):(i+=String.fromCharCode(n>>12|224),i+=String.fromCharCode(n>>6&63|128),i+=String.fromCharCode(63&n|128));return i},_base64_encode:function(e){var t,n,i,r,a,o,s,l="",d=0;for(e=SlimStat._utf8_encode(e);d<e.length;)r=(t=e.charCodeAt(d++))>>2,a=(3&t)<<4|(n=e.charCodeAt(d++))>>4,o=(15&n)<<2|(i=e.charCodeAt(d++))>>6,s=63&i,isNaN(n)?o=s=64:isNaN(i)&&(s=64),l=l+SlimStat._base64_key_str.charAt(r)+SlimStat._base64_key_str.charAt(a)+SlimStat._base64_key_str.charAt(o)+SlimStat._base64_key_str.charAt(s);return l},_detect_single_plugin_not_ie:function(e){var t,n,i,r;for(i in navigator.plugins){t=""+navigator.plugins[i].name+navigator.plugins[i].description,n=0;for(r in SlimStat._plugins[e].substrings)-1!=t.indexOf(SlimStat._plugins[e].substrings[r])&&n++;if(n==SlimStat._plugins[e].substrings.length)return!0}return!1},_detect_single_plugin_ie:function(e){var t="",n=!1;for(t in SlimStat._plugins[e].active_x_strings)try{new ActiveXObject(SlimStat._plugins[e].active_x_strings[t]),n=!0}catch(e){}return n},_detect_single_plugin:function(e){return navigator.plugins.length?this.detect=SlimStat._detect_single_plugin_not_ie:this.detect=SlimStat._detect_single_plugin_ie,this.detect(e)},detect_plugins:function(){var e,t=[];for(e in SlimStat._plugins)SlimStat._detect_single_plugin(e)&&t.push(e);return"function"==typeof navigator.javaEnabled&&navigator.javaEnabled()&&t.push("java"),t.join(",")},get_page_performance:function(){return slim_performance=window.performance||window.mozPerformance||window.msPerformance||window.webkitPerformance||{},void 0===slim_performance.timing?0:slim_performance.timing.loadEventEnd-slim_performance.timing.responseEnd},get_server_latency:function(){return slim_performance=window.performance||window.mozPerformance||window.msPerformance||window.webkitPerformance||{},void 0===slim_performance.timing?0:slim_performance.timing.responseEnd-slim_performance.timing.connectEnd},add_event:function(e,t,n){e&&e.addEventListener?e.addEventListener(t,n,!1):e&&e.attachEvent?(e["e"+t+n]=n,e[t+n]=function(){e["e"+t+n](window.event)},e.attachEvent("on"+t,e[t+n])):e["on"+t]=e["e"+t+n]},in_array:function(e,t){for(var n=0;n<t.length;n++)if(t[n].trim()==e)return!0;return!1},in_array_substring:function(e,t){for(var n=0;n<t.length;n++)if(-1!=e.indexOf(t[n].trim()))return!0;return!1},send_to_server:function(e,t){if(void 0===SlimStatParams.ajaxurl||void 0===e)return!1;if(void 0===t&&(t=!0),slimstat_data_with_client_info=e+"&sw="+screen.width+"&sh="+screen.height+"&bw="+window.innerWidth+"&bh="+window.innerHeight+"&sl="+SlimStat.get_server_latency()+"&pp="+SlimStat.get_page_performance()+"&pl="+SlimStat.detect_plugins(),t&&navigator.sendBeacon)navigator.sendBeacon(SlimStatParams.ajaxurl,slimstat_data_with_client_info);else{try{window.XMLHttpRequest?request=new XMLHttpRequest:window.ActiveXObject&&(request=new ActiveXObject("Microsoft.XMLHTTP"))}catch(e){return!1}if(request)return request.open("POST",SlimStatParams.ajaxurl,!0),request.setRequestHeader("Content-type","application/x-www-form-urlencoded"),request.setRequestHeader("X-Requested-With","XMLHttpRequest"),request.withCredentials=!0,request.send(slimstat_data_with_client_info),request.onreadystatechange=function(){4==request.readyState&&(parsed_id=parseInt(request.responseText),!isNaN(parsed_id)&&parsed_id>0&&(SlimStat._id=request.responseText))},!0}return!1},ss_track:function(e,t,n,i){if(e=e||window.event,t=void 0===t?0:parseInt(t),note_array=[],void 0===i&&(i=!0),parsed_id=parseInt(SlimStat._id),isNaN(parsed_id)||parsed_id<=0)return!1;if(node=void 0!==e.target?e.target:void 0!==e.srcElement&&e.srcElement,!node)return!1;switch(3==node.nodeType&&(node=node.parentNode),parent_node=node.parentNode,resource_url="",node.nodeName){case"FORM":void 0!==node.action&&node.action&&(resource_url=node.action);break;case"INPUT":for(;"undefined"!=typeof parent_node&&"FORM"!=parent_node.nodeName&&"BODY"!=parent_node.nodeName;)parent_node=parent_node.parentNode;if(void 0!==parent_node.action&&parent_node.action){resource_url=parent_node.action;break}default:if("A"!=node.nodeName)for(;void 0!==node.parentNode&&null!=node.parentNode&&"A"!=node.nodeName&&"BODY"!=node.nodeName;)node=node.parentNode;void 0!==node.hash&&node.hash&&node.hostname==location.hostname?resource_url=node.hash:void 0!==node.href&&-1==node.href.indexOf("javascript:")&&(resource_url=node.href),"function"==typeof node.getAttribute&&(void 0!==node.getAttribute("title")&&node.getAttribute("title")&&note_array.push("Title:"+node.getAttribute("title")),void 0!==node.getAttribute("id")&&node.getAttribute("id")&&note_array.push("ID:"+node.getAttribute("id")))}return pos_x=-1,pos_y=-1,position="",void 0!==e.pageX&&void 0!==e.pageY?(pos_x=e.pageX,pos_y=e.pageY):void 0!==e.clientX&&void 0!==e.clientY&&void 0!==document.body.scrollLeft&&void 0!==document.documentElement.scrollLeft&&void 0!==document.body.scrollTop&&void 0!==document.documentElement.scrollTop&&(pos_x=e.clientX+document.body.scrollLeft+document.documentElement.scrollLeft,pos_y=e.clientY+document.body.scrollTop+document.documentElement.scrollTop),pos_x>0&&pos_y>0&&(position=pos_x+","+pos_y),void 0!==e.type&&(event_description=e.type,"keypress"==e.type?event_description+="; keypress:"+String.fromCharCode(parseInt(e.which)):"click"==e.type&&(event_description+="; which:"+e.which)),void 0!==n&&n&&note_array.push(n),note_string=SlimStat._base64_encode(note_array.join(", ")),requested_op="add",1==t?resource_url=resource_url.substring(resource_url.indexOf(location.hostname)+location.hostname.length):requested_op=0==t||2==t?"update":"event",SlimStat.send_to_server("action=slimtrack&op="+requested_op+"&id="+SlimStat._id+"&ty="+t+"&ref="+SlimStat._base64_encode(document.referrer)+"&res="+SlimStat._base64_encode(resource_url)+"&pos="+position+"&des="+SlimStat._base64_encode(event_description)+"&no="+note_string,i),!0}};"function"!=typeof String.prototype.trim&&(String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"")}),SlimStat.add_event(window,"load",function(){all_links=document.getElementsByTagName("a");for(var e=void 0!==SlimStatParams.extensions_to_track&&SlimStatParams.extensions_to_track?SlimStatParams.extensions_to_track.split(","):[],t=void 0!==SlimStatParams.outbound_classes_rel_href_to_not_track&&SlimStatParams.outbound_classes_rel_href_to_not_track?SlimStatParams.outbound_classes_rel_href_to_not_track.split(","):[],n=0;n<all_links.length;n++){if(linktype=all_links[n].href&&(all_links[n].hostname==location.hostname||-1==all_links[n].href.indexOf("://"))||-1==all_links[n].href.indexOf("javascript:")?2:0,tracking=1,t.length>0){if(1==tracking){classes_current_link=void 0!==all_links[n].className&&all_links[n].className?all_links[n].className.split(" "):[];for(var i=0;i<classes_current_link.length;i++)if(SlimStat.in_array_substring(classes_current_link[i],t)){tracking=0;break}}1==tracking&&void 0!==all_links[n].attributes.rel&&all_links[n].attributes.rel.value&&SlimStat.in_array_substring(all_links[n].attributes.rel.value,t)&&(tracking=0),1==tracking&&void 0!==all_links[n].href&&all_links[n].href&&SlimStat.in_array_substring(all_links[n].href,t)&&(tracking=0)}extension_current_link=all_links[n].pathname.split(/[?#]/)[0].split(".").pop().replace(/[\/\-]/g,""),2==linktype&&e.length>0&&SlimStat.in_array(extension_current_link,e)&&(tracking=1,linktype=1),all_links[n].setAttribute("data-slimstat",(linktype<<1)+tracking),SlimStat.add_event(all_links[n],"click",function(e){link_info=parseInt(this.getAttribute("data-slimstat")),isNaN(link_info)&&(link_info=0),!0&link_info&&SlimStat.ss_track(e,link_info>>1,"")})}});var slimstat_data="",use_beacon=!0;void 0!==SlimStatParams.id&&parseInt(SlimStatParams.id)>0?slimstat_data="action=slimtrack&op=update&id="+SlimStatParams.id:void 0!==SlimStatParams.ci&&(slimstat_data="action=slimtrack&op=add&id="+SlimStatParams.ci+"&ref="+SlimStat._base64_encode(document.referrer)+"&res="+SlimStat._base64_encode(window.location.href),use_beacon=!1),slimstat_data.length>0&&SlimStat.add_event(window,"load",function(){setTimeout(function(){SlimStat.send_to_server(slimstat_data,"")},0)});
1
+ var SlimStat={_id:void 0!==SlimStatParams.id?SlimStatParams.id:"-1.0",_base64_key_str:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",_plugins:{acrobat:{substrings:["Adobe","Acrobat"],active_x_strings:["AcroPDF.PDF","PDF.PDFCtrl.5"]},pdfviewer:{substrings:["PDF"],active_x_strings:["AcroPDF.PDF"]},flash:{substrings:["Shockwave","Flash"],active_x_strings:["ShockwaveFlash.ShockwaveFlash"]},mediaplayer:{substrings:["Windows Media"],active_x_strings:["WMPlayer.OCX"]},quicktime:{substrings:["QuickTime"],active_x_strings:["QuickTime.QuickTime"]},silverlight:{substrings:["Silverlight"],active_x_strings:["AgControl.AgControl"]}},_utf8_encode:function(e){var t,n,i="";for(e=e.replace(/\r\n/g,"\n"),t=0;t<e.length;t++)(n=e.charCodeAt(t))<128?i+=String.fromCharCode(n):n>127&&n<2048?(i+=String.fromCharCode(n>>6|192),i+=String.fromCharCode(63&n|128)):(i+=String.fromCharCode(n>>12|224),i+=String.fromCharCode(n>>6&63|128),i+=String.fromCharCode(63&n|128));return i},_base64_encode:function(e){var t,n,i,r,a,o,s,l="",d=0;for(e=SlimStat._utf8_encode(e);d<e.length;)r=(t=e.charCodeAt(d++))>>2,a=(3&t)<<4|(n=e.charCodeAt(d++))>>4,o=(15&n)<<2|(i=e.charCodeAt(d++))>>6,s=63&i,isNaN(n)?o=s=64:isNaN(i)&&(s=64),l=l+SlimStat._base64_key_str.charAt(r)+SlimStat._base64_key_str.charAt(a)+SlimStat._base64_key_str.charAt(o)+SlimStat._base64_key_str.charAt(s);return l},_detect_single_plugin_not_ie:function(e){var t,n,i,r;for(i in navigator.plugins){for(r in t=""+navigator.plugins[i].name+navigator.plugins[i].description,n=0,SlimStat._plugins[e].substrings)-1!=t.indexOf(SlimStat._plugins[e].substrings[r])&&n++;if(n==SlimStat._plugins[e].substrings.length)return!0}return!1},_detect_single_plugin_ie:function(e){var t="",n=!1;for(t in SlimStat._plugins[e].active_x_strings)try{new ActiveXObject(SlimStat._plugins[e].active_x_strings[t]),n=!0}catch(e){}return n},_detect_single_plugin:function(e){return navigator.plugins.length?this.detect=SlimStat._detect_single_plugin_not_ie:this.detect=SlimStat._detect_single_plugin_ie,this.detect(e)},detect_plugins:function(){var e,t=[];for(e in SlimStat._plugins)SlimStat._detect_single_plugin(e)&&t.push(e);return"function"==typeof navigator.javaEnabled&&navigator.javaEnabled()&&t.push("java"),t.join(",")},get_page_performance:function(){return slim_performance=window.performance||window.mozPerformance||window.msPerformance||window.webkitPerformance||{},void 0===slim_performance.timing?0:slim_performance.timing.loadEventEnd-slim_performance.timing.responseEnd},get_server_latency:function(){return slim_performance=window.performance||window.mozPerformance||window.msPerformance||window.webkitPerformance||{},void 0===slim_performance.timing?0:slim_performance.timing.responseEnd-slim_performance.timing.connectEnd},add_event:function(e,t,n){e&&e.addEventListener?e.addEventListener(t,n,!1):e&&e.attachEvent?(e["e"+t+n]=n,e[t+n]=function(){e["e"+t+n](window.event)},e.attachEvent("on"+t,e[t+n])):e["on"+t]=e["e"+t+n]},in_array:function(e,t){for(var n=0;n<t.length;n++)if(t[n].trim()==e)return!0;return!1},in_array_substring:function(e,t){for(var n=0;n<t.length;n++)if(-1!=e.indexOf(t[n].trim()))return!0;return!1},send_to_server:function(e,t){if(void 0===SlimStatParams.ajaxurl||void 0===e)return!1;if(void 0===t&&(t=!0),slimstat_data_with_client_info=e+"&sw="+screen.width+"&sh="+screen.height+"&bw="+window.innerWidth+"&bh="+window.innerHeight+"&sl="+SlimStat.get_server_latency()+"&pp="+SlimStat.get_page_performance()+"&pl="+SlimStat.detect_plugins(),t&&navigator.sendBeacon)navigator.sendBeacon(SlimStatParams.ajaxurl,slimstat_data_with_client_info);else{try{window.XMLHttpRequest?request=new XMLHttpRequest:window.ActiveXObject&&(request=new ActiveXObject("Microsoft.XMLHTTP"))}catch(e){return!1}if(request)return request.open("POST",SlimStatParams.ajaxurl,!0),request.setRequestHeader("Content-type","application/x-www-form-urlencoded"),request.setRequestHeader("X-Requested-With","XMLHttpRequest"),request.withCredentials=!0,request.send(slimstat_data_with_client_info),request.onreadystatechange=function(){4==request.readyState&&(parsed_id=parseInt(request.responseText),!isNaN(parsed_id)&&parsed_id>0&&(SlimStat._id=request.responseText))},!0}return!1},ss_track:function(e,t,n,i){if(e=e||window.event,t=void 0===t?0:parseInt(t),note_array=[],void 0===i&&(i=!0),parsed_id=parseInt(SlimStat._id),isNaN(parsed_id)||parsed_id<=0)return!1;if(node=void 0!==e.target?e.target:void 0!==e.srcElement&&e.srcElement,!node)return!1;switch(3==node.nodeType&&(node=node.parentNode),parent_node=node.parentNode,resource_url="",node.nodeName){case"FORM":void 0!==node.action&&node.action&&(resource_url=node.action);break;case"INPUT":for(;"undefined"!=typeof parent_node&&"FORM"!=parent_node.nodeName&&"BODY"!=parent_node.nodeName;)parent_node=parent_node.parentNode;if(void 0!==parent_node.action&&parent_node.action){resource_url=parent_node.action;break}default:if("A"!=node.nodeName)for(;void 0!==node.parentNode&&null!=node.parentNode&&"A"!=node.nodeName&&"BODY"!=node.nodeName;)node=node.parentNode;void 0!==node.hash&&node.hash&&node.hostname==location.hostname?resource_url=node.hash:void 0!==node.href&&-1==node.href.indexOf("javascript:")&&(resource_url=node.href),"function"==typeof node.getAttribute&&(void 0!==node.getAttribute("title")&&node.getAttribute("title")&&note_array.push("Title:"+node.getAttribute("title")),void 0!==node.getAttribute("id")&&node.getAttribute("id")&&note_array.push("ID:"+node.getAttribute("id")))}return pos_x=-1,pos_y=-1,position="",void 0!==e.pageX&&void 0!==e.pageY?(pos_x=e.pageX,pos_y=e.pageY):void 0!==e.clientX&&void 0!==e.clientY&&void 0!==document.body.scrollLeft&&void 0!==document.documentElement.scrollLeft&&void 0!==document.body.scrollTop&&void 0!==document.documentElement.scrollTop&&(pos_x=e.clientX+document.body.scrollLeft+document.documentElement.scrollLeft,pos_y=e.clientY+document.body.scrollTop+document.documentElement.scrollTop),pos_x>0&&pos_y>0&&(position=pos_x+","+pos_y),void 0!==e.type&&(event_description=e.type,"keypress"==e.type?event_description+="; keypress:"+String.fromCharCode(parseInt(e.which)):"click"==e.type&&(event_description+="; which:"+e.which)),void 0!==n&&n&&note_array.push(n),note_string=SlimStat._base64_encode(note_array.join(", ")),requested_op="add",1==t?resource_url=resource_url.substring(resource_url.indexOf(location.hostname)+location.hostname.length):requested_op=0==t||2==t?"update":"event",SlimStat.send_to_server("action=slimtrack&op="+requested_op+"&id="+SlimStat._id+"&ty="+t+"&ref="+SlimStat._base64_encode(document.referrer)+"&res="+SlimStat._base64_encode(resource_url)+"&pos="+position+"&des="+SlimStat._base64_encode(event_description)+"&no="+note_string,i),!0},attach_tracker:function(){all_links=document.getElementsByTagName("a");for(var e=void 0!==SlimStatParams.extensions_to_track&&SlimStatParams.extensions_to_track?SlimStatParams.extensions_to_track.split(","):[],t=void 0!==SlimStatParams.outbound_classes_rel_href_to_not_track&&SlimStatParams.outbound_classes_rel_href_to_not_track?SlimStatParams.outbound_classes_rel_href_to_not_track.split(","):[],n=0;n<all_links.length;n++){if(linktype=all_links[n].href&&(all_links[n].hostname==location.hostname||-1==all_links[n].href.indexOf("://"))||-1==all_links[n].href.indexOf("javascript:")?2:0,tracking=1,t.length>0){if(1==tracking){classes_current_link=void 0!==all_links[n].className&&all_links[n].className?all_links[n].className.split(" "):[];for(var i=0;i<classes_current_link.length;i++)if(SlimStat.in_array_substring(classes_current_link[i],t)){tracking=0;break}}1==tracking&&void 0!==all_links[n].attributes.rel&&all_links[n].attributes.rel.value&&SlimStat.in_array_substring(all_links[n].attributes.rel.value,t)&&(tracking=0),1==tracking&&void 0!==all_links[n].href&&all_links[n].href&&SlimStat.in_array_substring(all_links[n].href,t)&&(tracking=0)}extension_current_link=all_links[n].pathname.split(/[?#]/)[0].split(".").pop().replace(/[\/\-]/g,""),2==linktype&&e.length>0&&SlimStat.in_array(extension_current_link,e)&&(tracking=1,linktype=1),all_links[n].setAttribute("data-slimstat",(linktype<<1)+tracking),SlimStat.add_event(all_links[n],"click",function(e){link_info=parseInt(this.getAttribute("data-slimstat")),isNaN(link_info)&&(link_info=0),!0&link_info&&SlimStat.ss_track(e,link_info>>1,"")})}}};"function"!=typeof String.prototype.trim&&(String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"")}),SlimStat.add_event(window,"load",function(){SlimStat.attach_tracker()});var slimstat_data="",use_beacon=!0;void 0!==SlimStatParams.id&&parseInt(SlimStatParams.id)>0?slimstat_data="action=slimtrack&op=update&id="+SlimStatParams.id:void 0!==SlimStatParams.ci&&(slimstat_data="action=slimtrack&op=add&id="+SlimStatParams.ci+"&ref="+SlimStat._base64_encode(document.referrer)+"&res="+SlimStat._base64_encode(window.location.href),use_beacon=!1),slimstat_data.length>0&&SlimStat.add_event(window,"load",function(){setTimeout(function(){SlimStat.send_to_server(slimstat_data,"")},0)});
wp-slimstat.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Slimstat Analytics
4
  Plugin URI: http://wordpress.org/plugins/wp-slimstat/
5
  Description: The leading web analytics plugin for WordPress
6
- Version: 4.7.7
7
  Author: Jason Crouse
8
  Author URI: http://www.wp-slimstat.com/
9
  Text Domain: wp-slimstat
@@ -15,7 +15,7 @@ if ( !empty( wp_slimstat::$settings ) ) {
15
  }
16
 
17
  class wp_slimstat {
18
- public static $version = '4.7.7';
19
  public static $settings = array();
20
 
21
  public static $wpdb = '';
@@ -56,12 +56,6 @@ class wp_slimstat {
56
  // Allow third-party tools to use a custom database for Slimstat
57
  self::$wpdb = apply_filters( 'slimstat_custom_wpdb', $GLOBALS[ 'wpdb' ] );
58
 
59
- // Hook a DB clean-up routine to the daily cronjob
60
- add_action( 'wp_slimstat_purge', array( __CLASS__, 'wp_slimstat_purge' ) );
61
-
62
- // Allow external domains on CORS requests
63
- add_filter( 'allowed_http_origins', array(__CLASS__, 'open_cors_admin_ajax' ) );
64
-
65
  // Define the folder where to store the geolocation database (shared among sites in a network, by default)
66
  self::$upload_dir = wp_upload_dir();
67
  self::$upload_dir = self::$upload_dir[ 'basedir' ];
@@ -94,17 +88,42 @@ class wp_slimstat {
94
  if ( self::$settings[ 'track_users' ] == 'on' ) {
95
  add_action( 'login_enqueue_scripts', array( __CLASS__, 'wp_slimstat_enqueue_tracking_script' ), 10 );
96
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  }
98
 
 
 
 
 
 
 
99
  // Shortcodes
100
  add_shortcode('slimstat', array(__CLASS__, 'slimstat_shortcode'), 15);
101
 
102
- // Load the admin library
103
- if ( is_user_logged_in() ) {
104
- include_once ( plugin_dir_path( __FILE__ ) . 'admin/wp-slimstat-admin.php' );
105
- add_action( 'init', array( 'wp_slimstat_admin', 'init' ), 60 );
106
- }
107
-
108
  // Include our browser detector library
109
  include_once( plugin_dir_path( __FILE__ ) . 'browscap/browser.php' );
110
  add_action( 'init', array( 'slim_browser', 'init' ) );
@@ -117,6 +136,12 @@ class wp_slimstat {
117
 
118
  // REST API Support
119
  add_action( 'rest_api_init', array( __CLASS__, 'register_rest_route' ) );
 
 
 
 
 
 
120
  }
121
  // end init
122
 
@@ -262,12 +287,43 @@ class wp_slimstat {
262
  return $_argument;
263
  }
264
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
  // User's IP address
266
  list ( self::$stat[ 'ip' ], self::$stat[ 'other_ip' ] ) = self::_get_remote_ip();
267
 
268
  if ( empty( self::$stat[ 'ip' ] ) || self::$stat[ 'ip' ] == '0.0.0.0' ) {
269
  self::$stat[ 'id' ] = -202;
270
- self::_set_error_array( __( 'Empty or not supported IP address format (IPv6)', 'wp-slimstat' ), false );
271
  return $_argument;
272
  }
273
 
@@ -1606,6 +1662,10 @@ class wp_slimstat {
1606
  'ignore_bots' => 'no',
1607
  'ignore_prefetch' => 'on',
1608
  'anonymize_ip' => 'no',
 
 
 
 
1609
 
1610
  'ignore_users' => '',
1611
  'ignore_ip' => '',
@@ -1712,7 +1772,7 @@ class wp_slimstat {
1712
 
1713
  if ( self::$settings[ 'javascript_mode' ] != 'on' ) {
1714
  // Do not enqueue the tracker if this page view was not tracked for some reason
1715
- if ( intval( self::$stat[ 'id' ] ) < 0 ) {
1716
  return false;
1717
  }
1718
 
@@ -1771,23 +1831,24 @@ class wp_slimstat {
1771
  WHERE dt < $days_ago");
1772
 
1773
  if ( $is_copy_done !== false ) {
1774
- self::$wpdb->query("DELETE ts FROM {$GLOBALS[ 'wpdb' ]->prefix}slim_stats ts WHERE ts.dt < $days_ago");
1775
  }
1776
 
1777
- $is_copy_done = self::$wpdb->query("
1778
  INSERT INTO {$GLOBALS['wpdb']->prefix}slim_events_archive (type, event_description, notes, position, id, dt)
1779
  SELECT type, event_description, notes, position, id, dt
1780
  FROM {$GLOBALS[ 'wpdb' ]->prefix}slim_events
1781
- WHERE dt < $days_ago");
 
1782
 
1783
  if ( $is_copy_done !== false ) {
1784
- self::$wpdb->query("DELETE te FROM {$GLOBALS[ 'wpdb' ]->prefix}slim_events te WHERE te.dt < $days_ago");
1785
  }
1786
  }
1787
  else {
1788
  // Delete old entries
1789
- self::$wpdb->query("DELETE ts FROM {$GLOBALS[ 'wpdb' ]->prefix}slim_stats ts WHERE ts.dt < $days_ago");
1790
- self::$wpdb->query("DELETE te FROM {$GLOBALS[ 'wpdb' ]->prefix}slim_events te WHERE te.dt < $days_ago");
1791
  }
1792
 
1793
  // Optimize tables
@@ -1797,6 +1858,23 @@ class wp_slimstat {
1797
  self::$wpdb->query( "OPTIMIZE TABLE {$GLOBALS[ 'wpdb' ]->prefix}slim_events_archive" );
1798
  }
1799
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1800
  /**
1801
  * Checks for add-on updates
1802
  */
3
  Plugin Name: Slimstat Analytics
4
  Plugin URI: http://wordpress.org/plugins/wp-slimstat/
5
  Description: The leading web analytics plugin for WordPress
6
+ Version: 4.7.8
7
  Author: Jason Crouse
8
  Author URI: http://www.wp-slimstat.com/
9
  Text Domain: wp-slimstat
15
  }
16
 
17
  class wp_slimstat {
18
+ public static $version = '4.7.8';
19
  public static $settings = array();
20
 
21
  public static $wpdb = '';
56
  // Allow third-party tools to use a custom database for Slimstat
57
  self::$wpdb = apply_filters( 'slimstat_custom_wpdb', $GLOBALS[ 'wpdb' ] );
58
 
 
 
 
 
 
 
59
  // Define the folder where to store the geolocation database (shared among sites in a network, by default)
60
  self::$upload_dir = wp_upload_dir();
61
  self::$upload_dir = self::$upload_dir[ 'basedir' ];
88
  if ( self::$settings[ 'track_users' ] == 'on' ) {
89
  add_action( 'login_enqueue_scripts', array( __CLASS__, 'wp_slimstat_enqueue_tracking_script' ), 10 );
90
  }
91
+
92
+ // GDPR Compliance: opt-out text box and handling
93
+ $is_cookie_empty = !isset( $_COOKIE[ 'slimstat_optout_' . COOKIEHASH ] );
94
+ if ( $is_cookie_empty && !empty( self::$settings[ 'opt_out_cookie_names' ] ) ) {
95
+ foreach ( self::string_to_array( self::$settings[ 'opt_out_cookie_names' ] ) as $a_cookie_pair ) {
96
+ list( $name, $value ) = explode( '=', $a_cookie_pair );
97
+
98
+ if ( !empty( $name ) && isset( $_COOKIE[ $name ] ) ) {
99
+ $is_cookie_empty = false;
100
+ break;
101
+ }
102
+ }
103
+ }
104
+ if ( self::$settings[ 'display_opt_out' ] == 'on' && $is_cookie_empty && !isset( $_GET[ 'slimstat-opt-out' ] ) ) {
105
+ add_action( 'wp_footer', array( __CLASS__, 'opt_out_box' ) );
106
+ }
107
+
108
+ if ( isset( $_GET[ 'slimstat-opt-out' ] ) ) {
109
+ @setcookie(
110
+ 'slimstat_optout_' . COOKIEHASH,
111
+ $_GET[ 'slimstat-opt-out' ],
112
+ time() + 31557600, // 365 days
113
+ COOKIEPATH
114
+ );
115
+ }
116
  }
117
 
118
+ // Hook a DB clean-up routine to the daily cronjob
119
+ add_action( 'wp_slimstat_purge', array( __CLASS__, 'wp_slimstat_purge' ) );
120
+
121
+ // Allow external domains on CORS requests
122
+ add_filter( 'allowed_http_origins', array(__CLASS__, 'open_cors_admin_ajax' ) );
123
+
124
  // Shortcodes
125
  add_shortcode('slimstat', array(__CLASS__, 'slimstat_shortcode'), 15);
126
 
 
 
 
 
 
 
127
  // Include our browser detector library
128
  include_once( plugin_dir_path( __FILE__ ) . 'browscap/browser.php' );
129
  add_action( 'init', array( 'slim_browser', 'init' ) );
136
 
137
  // REST API Support
138
  add_action( 'rest_api_init', array( __CLASS__, 'register_rest_route' ) );
139
+
140
+ // Load the admin library
141
+ if ( is_user_logged_in() ) {
142
+ include_once ( plugin_dir_path( __FILE__ ) . 'admin/wp-slimstat-admin.php' );
143
+ add_action( 'init', array( 'wp_slimstat_admin', 'init' ), 60 );
144
+ }
145
  }
146
  // end init
147
 
287
  return $_argument;
288
  }
289
 
290
+ // Honor the Do Not Track HTTP header - https://en.wikipedia.org/wiki/Do_Not_Track
291
+ if ( self::$settings[ 'honor_dnt_header' ] == 'on' && !empty( $_SERVER[ 'HTTP_DNT' ] ) ) {
292
+ self::$stat[ 'id' ] = -314;
293
+ self::_set_error_array( __( 'Browser sent DNT header request', 'wp-slimstat' ), true );
294
+ return $_argument;
295
+ }
296
+
297
+ // Opt-out of tracking via cookie
298
+ $cookie_names = array( 'slimstat_optout_' . COOKIEHASH => 'true' );
299
+
300
+ if ( !empty( self::$settings[ 'opt_out_cookie_names' ] ) ) {
301
+ $cookie_names = array();
302
+ $opt_out_cookie_names = self::string_to_array( self::$settings[ 'opt_out_cookie_names' ] );
303
+
304
+ foreach ( $opt_out_cookie_names as $a_cookie_pair ) {
305
+ list( $name, $value ) = explode( '=', $a_cookie_pair );
306
+
307
+ if ( !empty( $name ) && !empty( $value ) ) {
308
+ $cookie_names[ $name ] = $value;
309
+ }
310
+ }
311
+ }
312
+
313
+ foreach ( $cookie_names as $a_name => $a_value ) {
314
+ if ( isset( $_COOKIE[ $a_name ] ) && $_COOKIE[ $a_name ] == $a_value ) {
315
+ self::$stat[ 'id' ] = -315;
316
+ self::_set_error_array( __( 'Visitor has opted out of tracking', 'wp-slimstat' ), true );
317
+ return $_argument;
318
+ }
319
+ }
320
+
321
  // User's IP address
322
  list ( self::$stat[ 'ip' ], self::$stat[ 'other_ip' ] ) = self::_get_remote_ip();
323
 
324
  if ( empty( self::$stat[ 'ip' ] ) || self::$stat[ 'ip' ] == '0.0.0.0' ) {
325
  self::$stat[ 'id' ] = -202;
326
+ self::_set_error_array( __( 'Empty or not supported IP address format', 'wp-slimstat' ), false );
327
  return $_argument;
328
  }
329
 
1662
  'ignore_bots' => 'no',
1663
  'ignore_prefetch' => 'on',
1664
  'anonymize_ip' => 'no',
1665
+ 'honor_dnt_header' => 'yes',
1666
+ 'display_opt_out' => 'no',
1667
+ 'opt_out_cookie_names' => '',
1668
+ 'opt_out_message' => '<p style="display:block;position:fixed;left:0;bottom:0;margin:0;padding:1em 2em;background-color:#eee;width:100%;z-index:99999;">This website stores cookies on your computer. These cookies are used to provide a more personalized experience and to track your whereabouts around our website in compliance with the European General Data Protection Regulation. If you decide to to opt-out of any future tracking, a cookie will be setup in your browser to remember this choice for one year.<br><br><a href="{{accept_url}}">Accept</a> or <a href="{{deny_url}}">Deny</a></p>',
1669
 
1670
  'ignore_users' => '',
1671
  'ignore_ip' => '',
1772
 
1773
  if ( self::$settings[ 'javascript_mode' ] != 'on' ) {
1774
  // Do not enqueue the tracker if this page view was not tracked for some reason
1775
+ if ( !isset( self::$stat[ 'id' ] ) || intval( self::$stat[ 'id' ] ) < 0 ) {
1776
  return false;
1777
  }
1778
 
1831
  WHERE dt < $days_ago");
1832
 
1833
  if ( $is_copy_done !== false ) {
1834
+ self::$wpdb->query( "DELETE ts FROM {$GLOBALS[ 'wpdb' ]->prefix}slim_stats ts WHERE ts.dt < $days_ago" );
1835
  }
1836
 
1837
+ $is_copy_done = self::$wpdb->query( "
1838
  INSERT INTO {$GLOBALS['wpdb']->prefix}slim_events_archive (type, event_description, notes, position, id, dt)
1839
  SELECT type, event_description, notes, position, id, dt
1840
  FROM {$GLOBALS[ 'wpdb' ]->prefix}slim_events
1841
+ WHERE dt < $days_ago"
1842
+ );
1843
 
1844
  if ( $is_copy_done !== false ) {
1845
+ self::$wpdb->query( "DELETE te FROM {$GLOBALS[ 'wpdb' ]->prefix}slim_events te WHERE te.dt < $days_ago" );
1846
  }
1847
  }
1848
  else {
1849
  // Delete old entries
1850
+ self::$wpdb->query( "DELETE ts FROM {$GLOBALS[ 'wpdb' ]->prefix}slim_stats ts WHERE ts.dt < $days_ago" );
1851
+ self::$wpdb->query( "DELETE te FROM {$GLOBALS[ 'wpdb' ]->prefix}slim_events te WHERE te.dt < $days_ago" );
1852
  }
1853
 
1854
  // Optimize tables
1858
  self::$wpdb->query( "OPTIMIZE TABLE {$GLOBALS[ 'wpdb' ]->prefix}slim_events_archive" );
1859
  }
1860
 
1861
+ /**
1862
+ * Allow users to opt-out of tracking
1863
+ */
1864
+ public static function opt_out_box() {
1865
+ if ( strpos( $_SERVER[ 'REQUEST_URI' ], '?' ) !== false ) {
1866
+ $concat_char = '&';
1867
+ }
1868
+ else {
1869
+ $concat_char = '?';
1870
+ }
1871
+
1872
+ $opt_out_url = '//' . $_SERVER[ 'HTTP_HOST' ] . $_SERVER[ 'REQUEST_URI' ] . $concat_char . 'slimstat-opt-out=';
1873
+
1874
+ $message = str_replace( '{{accept_url}}', $opt_out_url . 'false', stripslashes( self::$settings[ 'opt_out_message' ] ) );
1875
+ echo str_replace( '{{deny_url}}', $opt_out_url . 'true', $message );
1876
+ }
1877
+
1878
  /**
1879
  * Checks for add-on updates
1880
  */