Post Views Counter - Version 1.3.9

Version Description

  • Tweak: Remove unnecessary plugin files
Download this release

Release Info

Developer dfactory
Plugin Icon 128x128 Post Views Counter
Version 1.3.9
Comparing to
See all releases

Code changes from version 1.3.8 to 1.3.9

includes/ajax.php DELETED
@@ -1,90 +0,0 @@
1
- <?php
2
- // mimic the actuall admin-ajax
3
- define( 'DOING_AJAX', true );
4
-
5
- if ( ! isset( $_POST['action'] ) )
6
- die( '-1' );
7
-
8
- // hide errors if any
9
- ini_set( 'html_errors', 0 );
10
-
11
- // we need only basics
12
- define( 'SHORTINIT', true );
13
-
14
- // get wp-load.php location
15
- $path = explode( 'wp-content', __FILE__ );
16
-
17
- if ( is_file( reset( $path ) . 'wp-load.php' ) ) {
18
- require_once( reset( $path ) . 'wp-load.php' );
19
- } else {
20
- die( '-1' );
21
- }
22
-
23
- // typical headers
24
- header( 'Content-Type: text/html' );
25
- send_nosniff_header();
26
-
27
- // disable caching
28
- header( 'Cache-Control: no-cache' );
29
- header( 'Pragma: no-cache' );
30
-
31
- // include only the files and function we need
32
- require_once( ABSPATH . 'wp-config.php' );
33
-
34
- require_once( ABSPATH . WPINC . '/post.php' );
35
- require_once( ABSPATH . WPINC . '/formatting.php' );
36
- require_once( ABSPATH . WPINC . '/capabilities.php' );
37
- require_once( ABSPATH . WPINC . '/query.php' );
38
- require_once( ABSPATH . WPINC . '/taxonomy.php' );
39
- require_once( ABSPATH . WPINC . '/meta.php' );
40
- require_once( ABSPATH . WPINC . '/functions.php' );
41
- require_once( ABSPATH . WPINC . '/link-template.php' );
42
- require_once( ABSPATH . WPINC . '/class-wp-post.php' );
43
- require_once( ABSPATH . WPINC . '/kses.php' );
44
- require_once( ABSPATH . WPINC . '/rest-api.php' );
45
- // required for wp user
46
- require_once( ABSPATH . WPINC . '/user.php' );
47
- require_once( ABSPATH . WPINC . '/vars.php' );
48
- require_once( ABSPATH . WPINC . '/class-wp-session-tokens.php' );
49
- require_once( ABSPATH . WPINC . '/class-wp-user-meta-session-tokens.php' );
50
- require_once( ABSPATH . WPINC . '/class-wp-roles.php' );
51
- require_once( ABSPATH . WPINC . '/class-wp-role.php' );
52
- require_once( ABSPATH . WPINC . '/class-wp-user.php' );
53
- require_once( ABSPATH . WPINC . '/pluggable.php' );
54
-
55
- // get constants
56
- wp_plugin_directory_constants();
57
- wp_cookie_constants();
58
- wp_ssl_constants();
59
-
60
- // include Post Views Counter core
61
- require_once( WP_PLUGIN_DIR . '/post-views-counter/post-views-counter.php' );
62
-
63
- // if PVC_SHORTINIT_INC is defined in wp-config.php load theme/pvc/includes.php file
64
- // this allows to perform custom actions, for example hook into pvc_after_count_visit
65
- if ( defined( 'PVC_SHORTINIT_INC' ) && PVC_SHORTINIT_INC ) {
66
- require_once( ABSPATH . WPINC . '/plugin.php' );
67
- require_once( ABSPATH . WPINC . '/theme.php' );
68
-
69
- // get the current theme path
70
- $theme_path = get_theme_file_path();
71
- // load custom pvc includes file
72
- $pvc_file_path = $theme_path . DIRECTORY_SEPARATOR . 'pvc' . DIRECTORY_SEPARATOR . 'includes.php';
73
-
74
- if ( is_file( $pvc_file_path ) ) {
75
- require_once( $pvc_file_path );
76
- }
77
- }
78
-
79
- $action = esc_attr( trim( $_POST['action'] ) );
80
-
81
- // a bit of security
82
- $allowed_actions = array(
83
- 'pvc-check-post'
84
- );
85
-
86
- if ( in_array( $action, $allowed_actions ) ) {
87
- do_action( 'pvc_ajax_' . $action );
88
- } else {
89
- die( '-1' );
90
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/class-columns.php CHANGED
@@ -39,8 +39,11 @@ class Post_Views_Counter_Columns {
39
  public function submitbox_views() {
40
  global $post;
41
 
 
 
 
42
  // incorrect post type?
43
- if ( ! in_array( $post->post_type, (array) Post_Views_Counter()->options['general']['post_types_count'] ) )
44
  return;
45
 
46
  // break if current user can't edit this post
@@ -60,7 +63,7 @@ class Post_Views_Counter_Columns {
60
 
61
  <?php
62
  // restrict editing
63
- $restrict = (bool) Post_Views_Counter()->options['general']['restrict_edit_views'];
64
 
65
  if ( $restrict === false || ( $restrict === true && current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) ) ) ) {
66
  ?>
@@ -112,8 +115,11 @@ class Post_Views_Counter_Columns {
112
  if ( isset( $_POST['current_post_views'] ) && $post_views === (int) $_POST['current_post_views'] )
113
  return $post_id;
114
 
 
 
 
115
  // break if post views in not one of the selected
116
- $post_types = (array) Post_Views_Counter()->options['general']['post_types_count'];
117
 
118
  // get post type
119
  if ( is_null( $post ) )
@@ -126,7 +132,7 @@ class Post_Views_Counter_Columns {
126
  return $post_id;
127
 
128
  // break if views editing is restricted
129
- if ( (bool) Post_Views_Counter()->options['general']['restrict_edit_views'] === true && ! current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) ) )
130
  return $post_id;
131
 
132
  // validate data
@@ -262,11 +268,14 @@ class Post_Views_Counter_Columns {
262
  if ( $column_name !== 'post_views' )
263
  return;
264
 
265
- if ( ! Post_Views_Counter()->options['general']['post_views_column'] || ! in_array( $post_type, Post_Views_Counter()->options['general']['post_types_count'] ) )
 
 
 
266
  return;
267
 
268
  // break if views editing is restricted
269
- $restrict = (bool) Post_Views_Counter()->options['general']['restrict_edit_views'];
270
 
271
  if ( $restrict === true && ! current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) ) )
272
  return;
@@ -363,7 +372,7 @@ class Post_Views_Counter_Columns {
363
  global $post;
364
 
365
  // get countable post types
366
- $post_types = Post_Views_Counter()->options['general']['post_types_count'];
367
 
368
  // whether to count this post type or not
369
  if ( empty( $post_types ) || empty( $post ) || ! in_array( $post->post_type, $post_types, true ) )
39
  public function submitbox_views() {
40
  global $post;
41
 
42
+ // get main instance
43
+ $pvc = Post_Views_Counter();
44
+
45
  // incorrect post type?
46
+ if ( ! in_array( $post->post_type, (array) $pvc->options['general']['post_types_count'] ) )
47
  return;
48
 
49
  // break if current user can't edit this post
63
 
64
  <?php
65
  // restrict editing
66
+ $restrict = (bool) $pvc->options['general']['restrict_edit_views'];
67
 
68
  if ( $restrict === false || ( $restrict === true && current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) ) ) ) {
69
  ?>
115
  if ( isset( $_POST['current_post_views'] ) && $post_views === (int) $_POST['current_post_views'] )
116
  return $post_id;
117
 
118
+ // get main instance
119
+ $pvc = Post_Views_Counter();
120
+
121
  // break if post views in not one of the selected
122
+ $post_types = (array) $pvc->options['general']['post_types_count'];
123
 
124
  // get post type
125
  if ( is_null( $post ) )
132
  return $post_id;
133
 
134
  // break if views editing is restricted
135
+ if ( (bool) $pvc->options['general']['restrict_edit_views'] === true && ! current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) ) )
136
  return $post_id;
137
 
138
  // validate data
268
  if ( $column_name !== 'post_views' )
269
  return;
270
 
271
+ // get main instance
272
+ $pvc = Post_Views_Counter();
273
+
274
+ if ( ! $pvc->options['general']['post_views_column'] || ! in_array( $post_type, $pvc->options['general']['post_types_count'] ) )
275
  return;
276
 
277
  // break if views editing is restricted
278
+ $restrict = (bool) $pvc->options['general']['restrict_edit_views'];
279
 
280
  if ( $restrict === true && ! current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) ) )
281
  return;
372
  global $post;
373
 
374
  // get countable post types
375
+ $post_types = $pvc->options['general']['post_types_count'];
376
 
377
  // whether to count this post type or not
378
  if ( empty( $post_types ) || empty( $post ) || ! in_array( $post->post_type, $post_types, true ) )
includes/class-counter.php CHANGED
@@ -66,6 +66,10 @@ class Post_Views_Counter_Counter {
66
  * @return void
67
  */
68
  public function check_post( $id = 0 ) {
 
 
 
 
69
  // get post id
70
  $id = (int) ( empty( $id ) ? get_the_ID() : $id );
71
 
@@ -578,7 +582,7 @@ class Post_Views_Counter_Counter {
578
  /**
579
  * Flush views data stored in the persistent object cache into
580
  * our custom table and clear the object cache keys when done.
581
- *
582
  * @return bool
583
  */
584
  public function flush_cache_to_db() {
66
  * @return void
67
  */
68
  public function check_post( $id = 0 ) {
69
+ // short init?
70
+ if ( defined( 'SHORTINIT' ) && SHORTINIT )
71
+ $this->check_cookie();
72
+
73
  // get post id
74
  $id = (int) ( empty( $id ) ? get_the_ID() : $id );
75
 
582
  /**
583
  * Flush views data stored in the persistent object cache into
584
  * our custom table and clear the object cache keys when done.
585
+ *
586
  * @return bool
587
  */
588
  public function flush_cache_to_db() {
includes/class-cron.php CHANGED
@@ -27,7 +27,7 @@ class Post_Views_Counter_Cron {
27
 
28
  /**
29
  * Reset daily counts.
30
- *
31
  * @global $wpdb
32
  * @return void
33
  */
@@ -35,10 +35,10 @@ class Post_Views_Counter_Cron {
35
  global $wpdb;
36
 
37
  $counter = [
38
- 'days' => 1,
39
- 'weeks' => 7,
40
- 'months' => 30,
41
- 'years' => 365
42
  ];
43
 
44
  // get main instance
@@ -64,7 +64,7 @@ class Post_Views_Counter_Cron {
64
 
65
  /**
66
  * Add new cron interval from settings.
67
- *
68
  * @param array $schedules
69
  * @return array
70
  */
27
 
28
  /**
29
  * Reset daily counts.
30
+ *
31
  * @global $wpdb
32
  * @return void
33
  */
35
  global $wpdb;
36
 
37
  $counter = [
38
+ 'days' => 1,
39
+ 'weeks' => 7,
40
+ 'months' => 30,
41
+ 'years' => 365
42
  ];
43
 
44
  // get main instance
64
 
65
  /**
66
  * Add new cron interval from settings.
67
+ *
68
  * @param array $schedules
69
  * @return array
70
  */
includes/class-functions.php CHANGED
@@ -25,13 +25,8 @@ class Post_Views_Counter_Functions {
25
  public function get_post_types() {
26
  $post_types = [];
27
 
28
- // built in public post types
29
- foreach ( get_post_types( [ '_builtin' => true, 'public' => true ], 'objects', 'and' ) as $key => $post_type ) {
30
- $post_types[$key] = $post_type->labels->name;
31
- }
32
-
33
- // public custom post types
34
- foreach ( get_post_types( [ '_builtin' => false, 'public' => true ], 'objects', 'and' ) as $key => $post_type ) {
35
  $post_types[$key] = $post_type->labels->name;
36
  }
37
 
@@ -42,7 +37,7 @@ class Post_Views_Counter_Functions {
42
  // filter post types
43
  $post_types = apply_filters( 'pvc_available_post_types', $post_types );
44
 
45
- // sort post types alphabetically with their keys
46
  asort( $post_types, SORT_STRING );
47
 
48
  return $post_types;
@@ -63,7 +58,7 @@ class Post_Views_Counter_Functions {
63
  $roles[$role] = translate_user_role( $details['name'] );
64
  }
65
 
66
- // sort user roles alphabetically with their keys
67
  asort( $roles, SORT_STRING );
68
 
69
  return $roles;
25
  public function get_post_types() {
26
  $post_types = [];
27
 
28
+ // get public post types
29
+ foreach ( get_post_types( [ 'public' => true ], 'objects', 'and' ) as $key => $post_type ) {
 
 
 
 
 
30
  $post_types[$key] = $post_type->labels->name;
31
  }
32
 
37
  // filter post types
38
  $post_types = apply_filters( 'pvc_available_post_types', $post_types );
39
 
40
+ // sort post types alphabetically
41
  asort( $post_types, SORT_STRING );
42
 
43
  return $post_types;
58
  $roles[$role] = translate_user_role( $details['name'] );
59
  }
60
 
61
+ // sort user roles alphabetically
62
  asort( $roles, SORT_STRING );
63
 
64
  return $roles;
includes/class-settings-api.php CHANGED
@@ -164,7 +164,7 @@ class Post_Views_Counter_Settings_API {
164
  $first_tab = key( $tabs );
165
 
166
  // get current tab
167
- $tab_key = ! empty( $_GET['tab'] ) && array_key_exists( sanitize_text_field( $_GET['tab'] ), $tabs ) ? sanitize_text_field( $_GET['tab'] ) : $first_tab;
168
 
169
  echo '
170
  <h2 class="nav-tab-wrapper">';
164
  $first_tab = key( $tabs );
165
 
166
  // get current tab
167
+ $tab_key = ! empty( $_GET['tab'] ) && array_key_exists( $_GET['tab'], $tabs ) ? $_GET['tab'] : $first_tab;
168
 
169
  echo '
170
  <h2 class="nav-tab-wrapper">';
includes/class-settings.php CHANGED
@@ -34,7 +34,7 @@ class Post_Views_Counter_Settings {
34
  $pvc = Post_Views_Counter();
35
 
36
  // Fast AJAX as active but not available counter mode?
37
- if ( $pvc->options['general']['counter_mode'] === 'ajax' && ! in_array( 'ajax', $this->get_counter_modes(), true ) ) {
38
  // set standard JavaScript AJAX calls
39
  $pvc->options['general']['counter_mode'] = 'js';
40
 
34
  $pvc = Post_Views_Counter();
35
 
36
  // Fast AJAX as active but not available counter mode?
37
+ if ( $pvc->options['general']['counter_mode'] === 'ajax' && ! array_key_exists( 'ajax', $this->get_counter_modes() ) ) {
38
  // set standard JavaScript AJAX calls
39
  $pvc->options['general']['counter_mode'] = 'js';
40
 
includes/columns.php DELETED
@@ -1,448 +0,0 @@
1
- <?php
2
- // exit if accessed directly
3
- if ( ! defined( 'ABSPATH' ) )
4
- exit;
5
-
6
- /**
7
- * Post_Views_Counter_Columns class.
8
- *
9
- * @class Post_Views_Counter_Columns
10
- */
11
- class Post_Views_Counter_Columns {
12
-
13
- public function __construct() {
14
- // actions
15
- add_action( 'admin_init', array( $this, 'register_new_column' ) );
16
- add_action( 'post_submitbox_misc_actions', array( $this, 'submitbox_views' ) );
17
- add_action( 'attachment_submitbox_misc_actions', array( $this, 'submitbox_views' ) );
18
- add_action( 'save_post', array( $this, 'save_post' ), 10, 2 );
19
- add_action( 'edit_attachment', array( $this, 'save_post' ), 10 );
20
- add_action( 'bulk_edit_custom_box', array( $this, 'quick_edit_custom_box' ), 10, 2 );
21
- add_action( 'quick_edit_custom_box', array( $this, 'quick_edit_custom_box' ), 10, 2 );
22
- add_action( 'wp_ajax_save_bulk_post_views', array( $this, 'save_bulk_post_views' ) );
23
-
24
- // gutenberg
25
- add_action( 'plugins_loaded', array( $this, 'init_gutemberg' ) );
26
- }
27
-
28
- /**
29
- * Init Gutenberg
30
- */
31
- public function init_gutemberg() {
32
- $block_editor = has_action( 'enqueue_block_assets' );
33
- $gutenberg = function_exists( 'gutenberg_can_edit_post_type' );
34
-
35
- if ( ! $block_editor && ! $gutenberg ) {
36
- return;
37
- }
38
-
39
- add_action( 'add_meta_boxes', array( $this, 'gutenberg_add_meta_box' ) );
40
- add_action( 'rest_api_init', array( $this, 'gutenberg_rest_api_init' ) );
41
- add_action( 'enqueue_block_editor_assets', array( $this, 'gutenberg_enqueue_scripts' ) );
42
- }
43
-
44
- /**
45
- * Register Gutenberg Metabox.
46
- */
47
- public function gutenberg_add_meta_box() {
48
- add_meta_box( 'post_views_meta_box', __( 'Post Views', 'post-views-counter' ), '', 'post', '', '', array(
49
- '__back_compat_meta_box' => false,
50
- '__block_editor_compatible_meta_box' => true
51
- ) );
52
- }
53
-
54
- /**
55
- * Register REST API Gutenberg endpoints.
56
- */
57
- public function gutenberg_rest_api_init() {
58
- // get views route
59
- register_rest_route(
60
- 'post-views-counter',
61
- '/update-post-views/',
62
- array(
63
- 'methods' => array( 'POST' ),
64
- 'callback' => array( $this, 'gutenberg_update_callback' ),
65
- 'args' => array(
66
- 'id' => array(
67
- 'sanitize_callback' => 'absint',
68
- )
69
- )
70
- )
71
- );
72
- }
73
-
74
- /**
75
- * REST API Callback for Gutenberg endpoint.
76
- *
77
- * @param array $data
78
- * @return array|int
79
- */
80
- public function gutenberg_update_callback( $data ) {
81
- $post_id = ! empty( $data['id'] ) ? (int) $data['id'] : 0;
82
- $post_views = ! empty( $data['post_views'] ) ? (int) $data['post_views'] : 0;
83
-
84
- // get countable post types
85
- $post_types = Post_Views_Counter()->options['general']['post_types_count'];
86
-
87
- // check if post exists
88
- $post = get_post( $post_id );
89
-
90
- // whether to count this post type or not
91
- if ( empty( $post_types ) || empty( $post ) || ! in_array( $post->post_type, $post_types, true ) )
92
- return wp_send_json_error( __( 'Invalid post ID.', 'post-views-counter' ) );
93
-
94
- // break if current user can't edit this post
95
- if ( ! current_user_can( 'edit_post', $post_id ) )
96
- return wp_send_json_error( __( 'You are not allowed to edit this item.', 'post-views-counter' ) );
97
-
98
- // break if views editing is restricted
99
- $restrict = (bool) Post_Views_Counter()->options['general']['restrict_edit_views'];
100
-
101
- if ( $restrict === true && ! current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) ) )
102
- return wp_send_json_error( __( 'You are not allowed to edit this item.', 'post-views-counter' ) );
103
-
104
- global $wpdb;
105
-
106
- pvc_update_post_views( $post_id, $post_views );
107
-
108
- do_action( 'pvc_after_update_post_views_count', $post_id );
109
-
110
- return $post_id;
111
- }
112
-
113
- /**
114
- * Enqueue front end and editor JavaScript and CSS
115
- */
116
- public function gutenberg_enqueue_scripts() {
117
- // enqueue the bundled block JS file
118
- wp_enqueue_script(
119
- 'pvc-gutenberg',
120
- POST_VIEWS_COUNTER_URL . '/js/gutenberg.min.js',
121
- array( 'wp-i18n', 'wp-edit-post', 'wp-element', 'wp-editor', 'wp-components', 'wp-data', 'wp-plugins', 'wp-api' ),
122
- Post_Views_Counter()->defaults['version']
123
- );
124
-
125
- // restrict editing
126
- $restrict = (bool) Post_Views_Counter()->options['general']['restrict_edit_views'];
127
- $can_edit = $restrict === false || ( $restrict === true && current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) ) );
128
-
129
- $js_args = array(
130
- 'postID' => get_the_ID(),
131
- 'postViews' => pvc_get_post_views( get_the_ID() ),
132
- 'canEdit' => $can_edit,
133
- 'nonce' => wp_create_nonce( 'wp_rest' ),
134
- 'textPostViews' => __( 'Post Views', 'post-views-counter' ),
135
- 'textHelp' => __( 'Adjust the views count for this post.', 'post-views-counter' ),
136
- 'textCancel' => __( 'Cancel', 'post-views-counter' )
137
- );
138
-
139
- wp_localize_script(
140
- 'pvc-gutenberg',
141
- 'pvcEditorArgs',
142
- $js_args
143
- );
144
-
145
- // enqueue frontend and editor block styles
146
- wp_enqueue_style(
147
- 'pvc-gutenberg',
148
- POST_VIEWS_COUNTER_URL . '/css/gutenberg.min.css', '',
149
- Post_Views_Counter()->defaults['version']
150
- );
151
- }
152
-
153
- /**
154
- * Output post views for single post.
155
- *
156
- * @global object $post
157
- * @return mixed
158
- */
159
- public function submitbox_views() {
160
- global $post;
161
-
162
- if ( ! in_array( $post->post_type, (array) Post_Views_Counter()->options['general']['post_types_count'] ) )
163
- return;
164
-
165
- // break if current user can't edit this post
166
- if ( ! current_user_can( 'edit_post', $post->ID ) )
167
- return;
168
-
169
- // get total post views
170
- $count = (int) pvc_get_post_views( $post->ID ); ?>
171
-
172
- <div class="misc-pub-section" id="post-views">
173
-
174
- <?php wp_nonce_field( 'post_views_count', 'pvc_nonce' ); ?>
175
-
176
- <span id="post-views-display">
177
- <?php echo __( 'Post Views', 'post-views-counter' ) . ': <b>' . number_format_i18n( $count ) . '</b>'; ?>
178
- </span>
179
-
180
- <?php
181
- // restrict editing
182
- $restrict = (bool) Post_Views_Counter()->options['general']['restrict_edit_views'];
183
-
184
- if ( $restrict === false || ( $restrict === true && current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) ) ) ) {
185
- ?>
186
- <a href="#post-views" class="edit-post-views hide-if-no-js"><?php _e( 'Edit', 'post-views-counter' ); ?></a>
187
-
188
- <div id="post-views-input-container" class="hide-if-js">
189
-
190
- <p><?php _e( 'Adjust the views count for this post.', 'post-views-counter' ); ?></p>
191
- <input type="hidden" name="current_post_views" id="post-views-current" value="<?php echo $count; ?>" />
192
- <input type="text" name="post_views" id="post-views-input" value="<?php echo $count; ?>"/><br />
193
- <p>
194
- <a href="#post-views" class="save-post-views hide-if-no-js button"><?php _e( 'OK', 'post-views-counter' ); ?></a>
195
- <a href="#post-views" class="cancel-post-views hide-if-no-js"><?php _e( 'Cancel', 'post-views-counter' ); ?></a>
196
- </p>
197
-
198
- </div>
199
- <?php
200
- }
201
- ?>
202
-
203
- </div>
204
- <?php
205
- }
206
-
207
- /**
208
- * Save post views data.
209
- *
210
- * @param int $post_id
211
- * @param object $post
212
- */
213
- public function save_post( $post_id, $post = null ) {
214
- if ( is_null( $post ) )
215
- $post_type = get_post_type( $post_id );
216
- else
217
- $post_type = $post->post_type;
218
-
219
- // break if doing autosave
220
- if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
221
- return $post_id;
222
-
223
- // break if current user can't edit this post
224
- if ( ! current_user_can( 'edit_post', $post_id ) )
225
- return $post_id;
226
-
227
- // is post views set
228
- if ( ! isset( $_POST['post_views'] ) )
229
- return $post_id;
230
-
231
- // cast numeric post views
232
- $post_views = (int) $_POST['post_views'];
233
-
234
- // unchanged post views value?
235
- if ( isset( $_POST['current_post_views'] ) && $post_views === (int) $_POST['current_post_views'] )
236
- return $post_id;
237
-
238
- // break if post views in not one of the selected
239
- $post_types = Post_Views_Counter()->options['general']['post_types_count'];
240
-
241
- if ( ! in_array( $post_type, (array) $post_types ) )
242
- return $post_id;
243
-
244
- // break if views editing is restricted
245
- $restrict = (bool) Post_Views_Counter()->options['general']['restrict_edit_views'];
246
-
247
- if ( $restrict === true && ! current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) ) )
248
- return $post_id;
249
-
250
- // validate data
251
- if ( ! isset( $_POST['pvc_nonce'] ) || ! wp_verify_nonce( $_POST['pvc_nonce'], 'post_views_count' ) )
252
- return $post_id;
253
-
254
- pvc_update_post_views( $post_id, $post_views );
255
-
256
- do_action( 'pvc_after_update_post_views_count', $post_id );
257
- }
258
-
259
- /**
260
- * Register post views column for specific post types
261
- */
262
- public function register_new_column() {
263
- $post_types = Post_Views_Counter()->options['general']['post_types_count'];
264
-
265
- if ( ! empty( $post_types ) ) {
266
- foreach ( $post_types as $post_type ) {
267
- if ( $post_type === 'attachment' ) {
268
- // actions
269
- add_action( 'manage_media_custom_column', array( $this, 'add_new_column_content' ), 10, 2 );
270
-
271
- // filters
272
- add_filter( 'manage_media_columns', array( $this, 'add_new_column' ) );
273
- add_filter( 'manage_upload_sortable_columns', array( $this, 'register_sortable_custom_column' ) );
274
- } else {
275
- // actions
276
- add_action( 'manage_' . $post_type . '_posts_custom_column', array( $this, 'add_new_column_content' ), 10, 2 );
277
-
278
- // filters
279
- add_filter( 'manage_' . $post_type . '_posts_columns', array( $this, 'add_new_column' ) );
280
- add_filter( 'manage_edit-' . $post_type . '_sortable_columns', array( $this, 'register_sortable_custom_column' ) );
281
-
282
- if ( class_exists( 'bbPress' ) ) {
283
- if ( $post_type === 'forum' )
284
- add_filter( 'bbp_admin_forums_column_headers', array( $this, 'add_new_column' ) );
285
- elseif ( $post_type === 'topic' )
286
- add_filter( 'bbp_admin_topics_column_headers', array( $this, 'add_new_column' ) );
287
- }
288
- }
289
- }
290
- }
291
- }
292
-
293
- /**
294
- * Register sortable post views column.
295
- *
296
- * @param array $columns
297
- * @return array
298
- */
299
- public function register_sortable_custom_column( $columns ) {
300
- // add new sortable column
301
- $columns['post_views'] = 'post_views';
302
-
303
- return $columns;
304
- }
305
-
306
- /**
307
- * Add post views column.
308
- *
309
- * @param array $columns
310
- * @return array
311
- */
312
- public function add_new_column( $columns ) {
313
- $offset = 0;
314
-
315
- if ( isset( $columns['date'] ) )
316
- $offset++;
317
-
318
- if ( isset( $columns['comments'] ) )
319
- $offset++;
320
-
321
- if ( $offset > 0 ) {
322
- $date = array_slice( $columns, -$offset, $offset, true );
323
-
324
- foreach ( $date as $column => $name ) {
325
- unset( $columns[$column] );
326
- }
327
-
328
- $columns['post_views'] = '<span class="dash-icon dashicons dashicons-chart-bar" title="' . __( 'Post Views', 'post-views-counter' ) . '"></span><span class="dash-title">' . __( 'Post Views', 'post-views-counter' ) . '</span>';
329
-
330
- foreach ( $date as $column => $name ) {
331
- $columns[$column] = $name;
332
- }
333
- } else
334
- $columns['post_views'] = '<span class="dash-icon dashicons dashicons-chart-bar" title="' . __( 'Post Views', 'post-views-counter' ) . '"></span><span class="dash-title">' . __( 'Post Views', 'post-views-counter' ) . '</span>';
335
-
336
- return $columns;
337
- }
338
-
339
- /**
340
- * Add post views column content.
341
- *
342
- * @param string $column_name
343
- * @param int $id
344
- * @return muxed
345
- */
346
- public function add_new_column_content( $column_name, $id ) {
347
- if ( $column_name === 'post_views' ) {
348
- // get total post views
349
- $count = pvc_get_post_views( $id );
350
-
351
- echo $count;
352
- }
353
- }
354
-
355
- /**
356
- * Handle quick edit.
357
- *
358
- * @global string $pagenow
359
- * @param string $column_name
360
- * @return mixed
361
- */
362
- function quick_edit_custom_box( $column_name, $post_type ) {
363
- global $pagenow, $post;
364
-
365
- if ( $pagenow !== 'edit.php' )
366
- return;
367
-
368
- if ( $column_name !== 'post_views' )
369
- return;
370
-
371
- if ( ! Post_Views_Counter()->options['general']['post_views_column'] || ! in_array( $post_type, Post_Views_Counter()->options['general']['post_types_count'] ) )
372
- return;
373
-
374
- // break if views editing is restricted
375
- $restrict = (bool) Post_Views_Counter()->options['general']['restrict_edit_views'];
376
-
377
- if ( $restrict === true && ! current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) ) )
378
- return;
379
-
380
- ?>
381
- <fieldset class="inline-edit-col-left">
382
- <div id="inline-edit-post_views" class="inline-edit-col">
383
- <label class="inline-edit-group">
384
- <span class="title"><?php _e( 'Post Views', 'post-views-counter' ); ?></span>
385
- <span class="input-text-wrap"><input type="text" name="post_views" class="title text" value=""></span>
386
- <input type="hidden" name="current_post_views" value="" />
387
- <?php wp_nonce_field( 'post_views_count', 'pvc_nonce' ); ?>
388
- </label>
389
- </div>
390
- </fieldset>
391
- <?php
392
- }
393
-
394
- /**
395
- * Bulk save post views.
396
- *
397
- * @global object $wpdb;
398
- * @return type
399
- */
400
- function save_bulk_post_views() {
401
- if ( ! isset( $_POST['post_views'] ) )
402
- $count = null;
403
- else {
404
- $count = trim( $_POST['post_views'] );
405
-
406
- if ( is_numeric( $_POST['post_views'] ) ) {
407
- $count = (int) $_POST['post_views'];
408
-
409
- if ( $count < 0 )
410
- $count = 0;
411
- } else
412
- $count = null;
413
- }
414
-
415
- $post_ids = ( ! empty( $_POST['post_ids'] ) && is_array( $_POST['post_ids'] ) ) ? array_map( 'absint', $_POST['post_ids'] ) : array();
416
-
417
- if ( is_null( $count ) )
418
- exit;
419
-
420
- // break if views editing is restricted
421
- $restrict = (bool) Post_Views_Counter()->options['general']['restrict_edit_views'];
422
-
423
- if ( $restrict === true && ! current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) ) )
424
- exit;
425
-
426
- if ( ! empty( $post_ids ) ) {
427
- foreach ( $post_ids as $post_id ) {
428
-
429
- // break if current user can't edit this post
430
- if ( ! current_user_can( 'edit_post', $post_id ) )
431
- continue;
432
-
433
- global $wpdb;
434
-
435
- // insert or update db post views count
436
- $wpdb->query(
437
- $wpdb->prepare( "
438
- INSERT INTO " . $wpdb->prefix . "post_views (id, type, period, count)
439
- VALUES (%d, %d, %s, %d)
440
- ON DUPLICATE KEY UPDATE count = %d", $post_id, 4, 'total', $count, $count
441
- )
442
- );
443
- }
444
- }
445
-
446
- exit;
447
- }
448
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/counter.php DELETED
@@ -1,795 +0,0 @@
1
- <?php
2
- // exit if accessed directly
3
- if ( ! defined( 'ABSPATH' ) )
4
- exit;
5
-
6
- /**
7
- * Post_Views_Counter_Counter class.
8
- *
9
- * @class Post_Views_Counter_Counter
10
- */
11
- class Post_Views_Counter_Counter {
12
-
13
- const GROUP = 'pvc';
14
- const NAME_ALLKEYS = 'cached_key_names';
15
- const CACHE_KEY_SEPARATOR = '.';
16
- const MAX_INSERT_STRING_LENGTH = 25000;
17
-
18
- private $db_insert_values = '';
19
- private $cookie = array(
20
- 'exists' => false,
21
- 'visited_posts' => array(),
22
- 'expiration' => 0
23
- );
24
-
25
- public function __construct() {
26
- // actions
27
- add_action( 'plugins_loaded', array( $this, 'check_cookie' ), 1 );
28
- add_action( 'deleted_post', array( $this, 'delete_post_views' ) );
29
- add_action( 'wp', array( $this, 'check_post_php' ) );
30
- add_action( 'wp_ajax_pvc-check-post', array( $this, 'check_post_js' ) );
31
- add_action( 'wp_ajax_nopriv_pvc-check-post', array( $this, 'check_post_js' ) );
32
- add_action( 'pvc_ajax_pvc-check-post', array( $this, 'check_post_ajax' ) );
33
- add_action( 'rest_api_init', array( $this, 'rest_api_init' ) );
34
- }
35
-
36
- /**
37
- * Check whether to count visit.
38
- *
39
- * @param int $id
40
- */
41
- public function check_post( $id = 0 ) {
42
- // force check post in SHORTINIT mode
43
- if ( defined( 'SHORTINIT' ) && SHORTINIT )
44
- $this->check_cookie();
45
-
46
- // get post id
47
- $id = (int) ( empty( $id ) ? get_the_ID() : $id );
48
-
49
- // get user id, from current user or static var in rest api request
50
- $user_id = get_current_user_id();
51
-
52
- // get user IP address
53
- $user_ip = (string) $this->get_user_ip();
54
-
55
- // empty id?
56
- if ( empty( $id ) )
57
- return;
58
-
59
- do_action( 'pvc_before_check_visit', $id, $user_id, $user_ip );
60
-
61
- // get ips
62
- $ips = Post_Views_Counter()->options['general']['exclude_ips'];
63
-
64
- // whether to count this ip
65
- if ( ! empty( $ips ) && filter_var( preg_replace( '/[^0-9a-fA-F:., ]/', '', $user_ip ), FILTER_VALIDATE_IP ) ) {
66
- // check ips
67
- foreach ( $ips as $ip ) {
68
- if ( strpos( $ip, '*' ) !== false ) {
69
- if ( $this->ipv4_in_range( $user_ip, $ip ) )
70
- return;
71
- } else {
72
- if ( $user_ip === $ip )
73
- return;
74
- }
75
- }
76
- }
77
-
78
- // get groups to check them faster
79
- $groups = Post_Views_Counter()->options['general']['exclude']['groups'];
80
-
81
- // whether to count this user
82
- if ( ! empty( $user_id ) ) {
83
- // exclude logged in users?
84
- if ( in_array( 'users', $groups, true ) )
85
- return;
86
- // exclude specific roles?
87
- elseif ( in_array( 'roles', $groups, true ) && $this->is_user_role_excluded( $user_id, Post_Views_Counter()->options['general']['exclude']['roles'] ) )
88
- return;
89
- // exclude guests?
90
- } elseif ( in_array( 'guests', $groups, true ) )
91
- return;
92
-
93
- // whether to count robots
94
- if ( in_array( 'robots', $groups, true ) && Post_Views_Counter()->crawler_detect->is_crawler() )
95
- return;
96
-
97
- $current_time = current_time( 'timestamp', true );
98
-
99
- // cookie already existed?
100
- if ( $this->cookie['exists'] ) {
101
- // post already viewed but not expired?
102
- if ( in_array( $id, array_keys( $this->cookie['visited_posts'] ), true ) && $current_time < $this->cookie['visited_posts'][$id] ) {
103
- // update cookie but do not count visit
104
- $this->save_cookie( $id, $this->cookie, false );
105
-
106
- return;
107
- // update cookie
108
- } else
109
- $this->save_cookie( $id, $this->cookie );
110
- } else {
111
- // set new cookie
112
- $this->save_cookie( $id );
113
- }
114
-
115
- $count_visit = (bool) apply_filters( 'pvc_count_visit', true, $id );
116
-
117
- // count visit
118
- if ( $count_visit ) {
119
- // strict counts?
120
- if ( Post_Views_Counter()->options['general']['strict_counts'] )
121
- $this->save_ip( $id );
122
-
123
- return $this->count_visit( $id );
124
- } else
125
- return;
126
- }
127
-
128
- /**
129
- * Check whether to count visit via PHP request.
130
- */
131
- public function check_post_php() {
132
- // do not count admin entries
133
- if ( is_admin() && ! ( defined( 'DOING_AJAX' ) && DOING_AJAX ) )
134
- return;
135
-
136
- // do we use PHP as counter?
137
- if ( Post_Views_Counter()->options['general']['counter_mode'] !== 'php' )
138
- return;
139
-
140
- $post_types = Post_Views_Counter()->options['general']['post_types_count'];
141
-
142
- // whether to count this post type
143
- if ( empty( $post_types ) || ! is_singular( $post_types ) )
144
- return;
145
-
146
- $this->check_post( get_the_ID() );
147
- }
148
-
149
- /**
150
- * Check whether to count visit via Javascript(Ajax) request.
151
- */
152
- public function check_post_js() {
153
- if ( isset( $_POST['action'], $_POST['id'], $_POST['pvc_nonce'] ) && $_POST['action'] === 'pvc-check-post' && ($post_id = (int) $_POST['id']) > 0 && wp_verify_nonce( $_POST['pvc_nonce'], 'pvc-check-post' ) !== false ) {
154
-
155
- // do we use Ajax as counter?
156
- if ( Post_Views_Counter()->options['general']['counter_mode'] != 'js' )
157
- exit;
158
-
159
- // get countable post types
160
- $post_types = Post_Views_Counter()->options['general']['post_types_count'];
161
-
162
- // check if post exists
163
- $post = get_post( $post_id );
164
-
165
- // whether to count this post type or not
166
- if ( empty( $post_types ) || empty( $post ) || ! in_array( $post->post_type, $post_types, true ) )
167
- exit;
168
-
169
- $this->check_post( $post_id );
170
- }
171
-
172
- exit;
173
- }
174
-
175
- /**
176
- * Check whether to count visit via Fast AJAX request.
177
- */
178
- public function check_post_ajax() {
179
- if ( isset( $_POST['action'], $_POST['id'], $_POST['pvc_nonce'] ) && $_POST['action'] === 'pvc-check-post' && ($post_id = (int) $_POST['id']) > 0 ) {
180
-
181
- // do we use Ajax as counter?
182
- if ( Post_Views_Counter()->options['general']['counter_mode'] != 'ajax' )
183
- exit;
184
-
185
- // get countable post types
186
- $post_types = Post_Views_Counter()->options['general']['post_types_count'];
187
-
188
- // check if post exists
189
- $post = get_post( $post_id );
190
-
191
- // whether to count this post type or not
192
- if ( empty( $post_types ) || empty( $post ) || ! in_array( $post->post_type, $post_types, true ) )
193
- exit;
194
-
195
- $this->check_post( $post_id );
196
- }
197
-
198
- exit;
199
- }
200
-
201
- /**
202
- * Check whether to count visit via REST API request.
203
- *
204
- * @param array $request
205
- * @return int|bool
206
- */
207
- public function check_post_rest_api( $request ) {
208
- $post_id = absint( $request['id'] );
209
-
210
- // do we use REST API as counter?
211
- if ( Post_Views_Counter()->options['general']['counter_mode'] != 'rest_api' )
212
- return new WP_Error( 'pvc_rest_api_disabled', __( 'REST API method is disabled.', 'post-views-counter' ), array( 'status' => 404 ) );
213
-
214
- // @todo: get current user id in direct api endpoint calls
215
-
216
- // check if post exists
217
- $post = get_post( $post_id );
218
-
219
- if ( ! $post )
220
- return new WP_Error( 'pvc_post_invalid_id', __( 'Invalid post ID.', 'post-views-counter' ), array( 'status' => 404 ) );
221
-
222
- $post_types = Post_Views_Counter()->options['general']['post_types_count'];
223
-
224
- // whether to count this post type
225
- if ( empty( $post_types ) || ! in_array( $post->post_type, $post_types ) )
226
- return new WP_Error( 'pvc_post_type_excluded', __( 'Post type excluded.', 'post-views-counter' ), array( 'status' => 404 ) );
227
-
228
- return $this->check_post( $post_id );
229
- }
230
-
231
- /**
232
- * Initialize cookie session.
233
- */
234
- public function check_cookie() {
235
- // do not run in admin except for ajax requests
236
- if ( is_admin() && ! ( defined( 'DOING_AJAX' ) && DOING_AJAX ) )
237
- return;
238
-
239
- // assign cookie name
240
- $cookie_name = 'pvc_visits' . ( is_multisite() ? '_' . get_current_blog_id() : '' );
241
-
242
- // is cookie set?
243
- if ( isset( $_COOKIE[$cookie_name] ) && ! empty( $_COOKIE[$cookie_name] ) ) {
244
- $visited_posts = $expirations = array();
245
-
246
- foreach ( $_COOKIE[$cookie_name] as $content ) {
247
- // is cookie valid?
248
- if ( preg_match( '/^(([0-9]+b[0-9]+a?)+)$/', $content ) === 1 ) {
249
- // get single id with expiration
250
- $expiration_ids = explode( 'a', $content );
251
-
252
- // check every expiration => id pair
253
- foreach ( $expiration_ids as $pair ) {
254
- $pair = explode( 'b', $pair );
255
- $expirations[] = (int) $pair[0];
256
- $visited_posts[(int) $pair[1]] = (int) $pair[0];
257
- }
258
- }
259
- }
260
-
261
- $this->cookie = array(
262
- 'exists' => true,
263
- 'visited_posts' => $visited_posts,
264
- 'expiration' => max( $expirations )
265
- );
266
- }
267
- }
268
-
269
- /**
270
- * Save cookie function.
271
- *
272
- * @param int $id
273
- * @param array $cookie
274
- * @param bool $expired
275
- */
276
- private function save_cookie( $id, $cookie = array(), $expired = true ) {
277
- $set_cookie = apply_filters( 'pvc_maybe_set_cookie', true );
278
-
279
- // Cookie Notice compatibility
280
- if ( function_exists( 'cn_cookies_accepted' ) && ! cn_cookies_accepted() )
281
- $set_cookie = false;
282
-
283
- if ( $set_cookie !== true )
284
- return $id;
285
-
286
- $expiration = $this->get_timestamp( Post_Views_Counter()->options['general']['time_between_counts']['type'], Post_Views_Counter()->options['general']['time_between_counts']['number'] );
287
-
288
- // assign cookie name
289
- $cookie_name = 'pvc_visits' . ( is_multisite() ? '_' . get_current_blog_id() : '' );
290
-
291
- // is this a new cookie?
292
- if ( empty( $cookie ) ) {
293
- // set cookie
294
- setcookie( $cookie_name . '[0]', $expiration . 'b' . $id, $expiration, COOKIEPATH, COOKIE_DOMAIN, (isset( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] !== 'off' ? true : false ), true );
295
- } else {
296
- if ( $expired ) {
297
- // add new id or change expiration date if id already exists
298
- $cookie['visited_posts'][$id] = $expiration;
299
- }
300
-
301
- // create copy for better foreach performance
302
- $visited_posts_expirations = $cookie['visited_posts'];
303
-
304
- // get current gmt time
305
- $time = current_time( 'timestamp', true );
306
-
307
- // check whether viewed id has expired - no need to keep it in cookie (less size)
308
- foreach ( $visited_posts_expirations as $post_id => $post_expiration ) {
309
- if ( $time > $post_expiration )
310
- unset( $cookie['visited_posts'][$post_id] );
311
- }
312
-
313
- // set new last expiration date if needed
314
- $cookie['expiration'] = max( $cookie['visited_posts'] );
315
-
316
- $cookies = $imploded = array();
317
-
318
- // create pairs
319
- foreach ( $cookie['visited_posts'] as $id => $exp ) {
320
- $imploded[] = $exp . 'b' . $id;
321
- }
322
-
323
- // split cookie into chunks (4000 bytes to make sure it is safe for every browser)
324
- $chunks = str_split( implode( 'a', $imploded ), 4000 );
325
-
326
- // more then one chunk?
327
- if ( count( $chunks ) > 1 ) {
328
- $last_id = '';
329
-
330
- foreach ( $chunks as $chunk_id => $chunk ) {
331
- // new chunk
332
- $chunk_c = $last_id . $chunk;
333
-
334
- // is it full-length chunk?
335
- if ( strlen( $chunk ) === 4000 ) {
336
- // get last part
337
- $last_part = strrchr( $chunk_c, 'a' );
338
-
339
- // get last id
340
- $last_id = substr( $last_part, 1 );
341
-
342
- // add new full-lenght chunk
343
- $cookies[$chunk_id] = substr( $chunk_c, 0, strlen( $chunk_c ) - strlen( $last_part ) );
344
- } else {
345
- // add last chunk
346
- $cookies[$chunk_id] = $chunk_c;
347
- }
348
- }
349
- } else {
350
- // only one chunk
351
- $cookies[] = $chunks[0];
352
- }
353
-
354
- foreach ( $cookies as $key => $value ) {
355
- // set cookie
356
- setcookie( $cookie_name . '[' . $key . ']', $value, $cookie['expiration'], COOKIEPATH, COOKIE_DOMAIN, (isset( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] !== 'off' ? true : false ), true );
357
- }
358
- }
359
- }
360
-
361
- /**
362
- * Save user IP function.
363
- *
364
- * @param int $id
365
- */
366
- private function save_ip( $id ) {
367
- $set_cookie = apply_filters( 'pvc_maybe_set_cookie', true );
368
-
369
- // Cookie Notice compatibility
370
- if ( function_exists( 'cn_cookies_accepted' ) && ! cn_cookies_accepted() )
371
- $set_cookie = false;
372
-
373
- if ( $set_cookie !== true )
374
- return $id;
375
-
376
- // get IP cached visits
377
- $ip_cache = get_transient( 'post_views_counter_ip_cache' );
378
-
379
- if ( ! $ip_cache )
380
- $ip_cache = array();
381
-
382
- // get user IP address
383
- $user_ip = (string) $this->get_user_ip();
384
-
385
- // get current time
386
- $current_time = current_time( 'timestamp', true );
387
-
388
- // visit exists in transient?
389
- if ( isset( $ip_cache[$id][$user_ip] ) ) {
390
- if ( $current_time > $ip_cache[$id][$user_ip] + $this->get_timestamp( Post_Views_Counter()->options['general']['time_between_counts']['type'], Post_Views_Counter()->options['general']['time_between_counts']['number'], false ) )
391
- $ip_cache[$id][$user_ip] = $current_time;
392
- else
393
- return;
394
- } else
395
- $ip_cache[$id][$user_ip] = $current_time;
396
-
397
- // keep it light, only 10 records per post and maximum 100 post records (=> max. 1000 ip entries)
398
- // also, the data gets deleted after a week if there's no activity during this time...
399
- if ( count( $ip_cache[$id] ) > 10 )
400
- $ip_cache[$id] = array_slice( $ip_cache[$id], -10, 10, true );
401
-
402
- if ( count( $ip_cache ) > 100 )
403
- $ip_cache = array_slice( $ip_cache, -100, 100, true );
404
-
405
- set_transient( 'post_views_counter_ip_cache', $ip_cache, WEEK_IN_SECONDS );
406
- }
407
-
408
- /**
409
- * Count visit function.
410
- *
411
- * @global object $wpdb
412
- * @param int $id
413
- * @return int $id
414
- */
415
- private function count_visit( $id ) {
416
- global $wpdb;
417
-
418
- $cache_key_names = array();
419
- $using_object_cache = $this->using_object_cache();
420
- $increment_amount = (int) apply_filters( 'pvc_views_increment_amount', 1, $id );
421
-
422
- // get day, week, month and year
423
- $date = explode( '-', date( 'W-d-m-Y-o', current_time( 'timestamp', true ) ) );
424
-
425
- foreach ( array(
426
- 0 => $date[3] . $date[2] . $date[1], // day like 20140324
427
- 1 => $date[4] . $date[0], // week like 201439
428
- 2 => $date[3] . $date[2], // month like 201405
429
- 3 => $date[3], // year like 2014
430
- 4 => 'total' // total views
431
- ) as $type => $period ) {
432
- if ( $using_object_cache ) {
433
- $cache_key = $id . self::CACHE_KEY_SEPARATOR . $type . self::CACHE_KEY_SEPARATOR . $period;
434
- wp_cache_add( $cache_key, 0, self::GROUP );
435
- wp_cache_incr( $cache_key, $increment_amount, self::GROUP );
436
- $cache_key_names[] = $cache_key;
437
- } else {
438
- // hit the db directly
439
- // @TODO: investigate queueing these queries on the 'shutdown' hook instead of running them instantly?
440
- $this->db_insert( $id, $type, $period, $increment_amount );
441
- }
442
- }
443
-
444
- // update the list of cache keys to be flushed
445
- if ( $using_object_cache && ! empty( $cache_key_names ) )
446
- $this->update_cached_keys_list_if_needed( $cache_key_names );
447
-
448
- do_action( 'pvc_after_count_visit', $id );
449
-
450
- return $id;
451
- }
452
-
453
- /**
454
- * Remove post views from database when post is deleted.
455
- *
456
- * @global object $wpdb
457
- * @param int $post_id
458
- */
459
- public function delete_post_views( $post_id ) {
460
- global $wpdb;
461
-
462
- $wpdb->delete( $wpdb->prefix . 'post_views', array( 'id' => $post_id ), array( '%d' ) );
463
- }
464
-
465
- /**
466
- * Get timestamp convertion.
467
- *
468
- * @param string $type
469
- * @param int $number
470
- * @param int $timestamp
471
- * @return string
472
- */
473
- public function get_timestamp( $type, $number, $timestamp = true ) {
474
- $converter = array(
475
- 'minutes' => 60,
476
- 'hours' => 3600,
477
- 'days' => 86400,
478
- 'weeks' => 604800,
479
- 'months' => 2592000,
480
- 'years' => 946080000
481
- );
482
-
483
- return (int) ( ( $timestamp ? current_time( 'timestamp', true ) : 0 ) + $number * $converter[$type] );
484
- }
485
-
486
- /**
487
- * Check if object cache is in use.
488
- *
489
- * @param bool $using
490
- * @return bool
491
- */
492
- public function using_object_cache( $using = null ) {
493
- $using = wp_using_ext_object_cache( $using );
494
-
495
- if ( $using ) {
496
- // check if explicitly disabled by flush_interval setting/option <= 0
497
- $flush_interval_number = Post_Views_Counter()->options['general']['flush_interval']['number'];
498
- $using = ( $flush_interval_number <= 0 ) ? false : true;
499
- }
500
-
501
- return $using;
502
- }
503
-
504
- /**
505
- * Update the single cache key which holds a list of all the cache keys
506
- * that need to be flushed to the db.
507
- *
508
- * The value of that special cache key is a giant string containing key names separated with the `|` character.
509
- * Each such key name then consists of 3 elements: $id, $type, $period (separated by a `.` character).
510
- * Examples:
511
- * 62053.0.20150327|62053.1.201513|62053.2.201503|62053.3.2015|62053.4.total|62180.0.20150327|62180.1.201513|62180.2.201503|62180.3.2015|62180.4.total
512
- * A single key is `62053.0.20150327` and that key's data is: $id = 62053, $type = 0, $period = 20150327
513
- *
514
- * This data format proved more efficient (avoids the (un)serialization overhead completely + duplicates filtering is a string search now)
515
- *
516
- * @param array $key_names
517
- */
518
- private function update_cached_keys_list_if_needed( $key_names = array() ) {
519
- $existing_list = wp_cache_get( self::NAME_ALLKEYS, self::GROUP );
520
- if ( ! $existing_list )
521
- $existing_list = '';
522
-
523
- $list_modified = false;
524
-
525
- // modify the list contents if/when needed
526
- if ( empty( $existing_list ) ) {
527
- // the simpler case of an empty initial list where we just
528
- // transform the specified key names into a string
529
- $existing_list = implode( '|', $key_names );
530
- $list_modified = true;
531
- } else {
532
- // search each specified key name and append it if it's not found
533
- foreach ( $key_names as $key_name ) {
534
- if ( false === strpos( $existing_list, $key_name ) ) {
535
- $existing_list .= '|' . $key_name;
536
- $list_modified = true;
537
- }
538
- }
539
- }
540
-
541
- // save modified list back in cache
542
- if ( $list_modified ) {
543
- wp_cache_set( self::NAME_ALLKEYS, $existing_list, self::GROUP );
544
- }
545
- }
546
-
547
- /**
548
- * Flush views data stored in the persistent object cache into
549
- * our custom table and clear the object cache keys when done.
550
- *
551
- * @global object $wpdb
552
- * @return bool
553
- */
554
- public function flush_cache_to_db() {
555
- global $wpdb;
556
-
557
- $key_names = wp_cache_get( self::NAME_ALLKEYS, self::GROUP );
558
-
559
- if ( ! $key_names )
560
- $key_names = array();
561
- else {
562
- // create an array out of a string that's stored in the cache
563
- $key_names = explode( '|', $key_names );
564
- }
565
-
566
- foreach ( $key_names as $key_name ) {
567
- // get values stored within the key name itself
568
- list( $id, $type, $period ) = explode( self::CACHE_KEY_SEPARATOR, $key_name );
569
-
570
- // get the cached count value
571
- $count = wp_cache_get( $key_name, self::GROUP );
572
-
573
- // store cached value in the db
574
- $this->db_prepare_insert( $id, $type, $period, $count );
575
-
576
- // clear the cache key we just flushed
577
- wp_cache_delete( $key_name, self::GROUP );
578
- }
579
-
580
- // actually flush values to db (if any left)
581
- $this->db_commit_insert();
582
-
583
- // remember last flush to db time
584
- wp_cache_set( 'last-flush', time(), self::GROUP );
585
-
586
- // delete the key holding the list itself after we've successfully flushed it
587
- if ( ! empty( $key_names ) )
588
- wp_cache_delete( self::NAME_ALLKEYS, self::GROUP );
589
-
590
- return true;
591
- }
592
-
593
- /**
594
- * Insert or update views count.
595
- *
596
- * @global object $wpdb
597
- * @param int $id
598
- * @param string $type
599
- * @param string $period
600
- * @param int $count
601
- * @return bool
602
- */
603
- private function db_insert( $id, $type, $period, $count = 1 ) {
604
- global $wpdb;
605
-
606
- $count = (int) $count;
607
-
608
- if ( ! $count )
609
- $count = 1;
610
-
611
- return $wpdb->query(
612
- $wpdb->prepare( "
613
- INSERT INTO " . $wpdb->prefix . "post_views (id, type, period, count)
614
- VALUES (%d, %d, %s, %d)
615
- ON DUPLICATE KEY UPDATE count = count + %d", $id, $type, $period, $count, $count
616
- )
617
- );
618
- }
619
-
620
- /**
621
- * Prepare bulk insert or update views count.
622
- *
623
- * @param int $id
624
- * @param string $type
625
- * @param string $period
626
- * @param int $count
627
- * @return void
628
- */
629
- private function db_prepare_insert( $id, $type, $period, $count = 1 ) {
630
- $count = (int) $count;
631
-
632
- if ( ! $count )
633
- $count = 1;
634
-
635
- if ( ! empty( $this->db_insert_values ) )
636
- $this->db_insert_values .= ', ';
637
-
638
- $this->db_insert_values .= sprintf( '(%d, %d, "%s", %d)', $id, $type, $period, $count );
639
-
640
- if ( strlen( $this->db_insert_values ) > self::MAX_INSERT_STRING_LENGTH )
641
- $this->db_commit_insert();
642
- }
643
-
644
- /**
645
- * Insert accumulated values to database.
646
- *
647
- * @global object $wpdb
648
- * @return bool
649
- */
650
- private function db_commit_insert() {
651
- if ( empty( $this->db_insert_values ) )
652
- return false;
653
-
654
- global $wpdb;
655
-
656
- // $result = $wpdb->query( "
657
- // INSERT INTO " . $wpdb->prefix . "post_views (id, type, period, count)
658
- // VALUES " . $this->db_insert_values . "
659
- // ON DUPLICATE KEY UPDATE count = count + VALUES(count)"
660
- // );
661
-
662
- $this->db_insert_values = '';
663
-
664
- // return $result;
665
- }
666
-
667
- /**
668
- * Check whether user has excluded roles.
669
- *
670
- * @param string $option
671
- * @return bool
672
- */
673
- public function is_user_role_excluded( $user_id, $option ) {
674
- $user = get_user_by( 'id', $user_id );
675
-
676
- if ( empty( $user ) )
677
- return false;
678
-
679
- $roles = (array) $user->roles;
680
-
681
- if ( ! empty( $roles ) ) {
682
- foreach ( $roles as $role ) {
683
- if ( in_array( $role, $option, true ) )
684
- return true;
685
- }
686
- }
687
-
688
- return false;
689
- }
690
-
691
- /**
692
- * Check if IPv4 is in range.
693
- *
694
- * @param string $ip IP address
695
- * @param string $range IP range
696
- * @return boolean Whether IP is in range
697
- */
698
- public function ipv4_in_range( $ip, $range ) {
699
- $start = str_replace( '*', '0', $range );
700
- $end = str_replace( '*', '255', $range );
701
- $ip = (float) sprintf( "%u", ip2long( $ip ) );
702
-
703
- return ( $ip >= (float) sprintf( "%u", ip2long( $start ) ) && $ip <= (float) sprintf( "%u", ip2long( $end ) ) );
704
- }
705
-
706
- /**
707
- * Get user real IP address.
708
- *
709
- * @return string
710
- */
711
- public function get_user_ip() {
712
- foreach ( array( 'HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR' ) as $key ) {
713
- if ( array_key_exists( $key, $_SERVER ) === true ) {
714
- foreach ( explode( ',', $_SERVER[$key] ) as $ip ) {
715
- // trim for safety measures
716
- $ip = trim( $ip );
717
-
718
- // attempt to validate IP
719
- if ( $this->validate_user_ip( $ip ) )
720
- return $ip;
721
- }
722
- }
723
- }
724
-
725
- return isset( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR'] : '';
726
- }
727
-
728
- /**
729
- * Ensure an ip address is both a valid IP and does not fall within a private network range.
730
- *
731
- * @param $ip
732
- * @return bool
733
- */
734
- public function validate_user_ip( $ip ) {
735
- if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) === false )
736
- return false;
737
-
738
- return true;
739
- }
740
-
741
- /**
742
- * Register REST API endpoints.
743
- *
744
- * @return void
745
- */
746
- public function rest_api_init() {
747
- // view post route
748
- register_rest_route( 'post-views-counter', '/view-post/', array(
749
- 'methods' => array( 'GET', 'POST' ),
750
- 'callback' => array( $this, 'check_post_rest_api' ),
751
- 'args' => array(
752
- 'id' => array(
753
- 'default' => 0,
754
- 'sanitize_callback' => 'absint'
755
- )
756
- )
757
- ) );
758
-
759
- // get views route
760
- register_rest_route( 'post-views-counter', '/get-post-views/', array(
761
- 'methods' => array( 'GET', 'POST' ),
762
- 'callback' => array( $this, 'get_post_views_rest_api' ),
763
- 'permission_callback' => array( $this, 'get_post_views_permissions_check' ),
764
- 'args' => array(
765
- 'id' => array(
766
- 'default' => 0,
767
- 'user_id' => get_current_user_id()
768
- )
769
- )
770
- ) );
771
- }
772
-
773
- /**
774
- * Get post views via REST API request.
775
- *
776
- * @param array $request
777
- * @return int
778
- */
779
- public function get_post_views_rest_api( $request ) {
780
- $post_id = is_array( $request['id'] ) ? array_map( 'absint', $request['id'] ) : absint( $request['id'] );
781
-
782
- return pvc_get_post_views( $post_id );
783
- }
784
-
785
- /**
786
- * Check if a given request has access to get views
787
- *
788
- * @param WP_REST_Request $request Full data about the request.
789
- * @return WP_Error|bool
790
- */
791
- public function get_post_views_permissions_check( $request ) {
792
- return (bool) apply_filters( 'pvc_rest_api_get_post_views_check', true, $request );
793
- }
794
-
795
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/crawler-detect.php DELETED
@@ -1,969 +0,0 @@
1
- <?php
2
- // exit if accessed directly
3
- if ( ! defined( 'ABSPATH' ) )
4
- exit;
5
-
6
- /**
7
- * Post_Views_Counter_Crawler_Detect class.
8
- *
9
- * Based on CrawlerDetect php class adjusted to PHP 5.2
10
- * https://github.com/JayBizzle/Crawler-Detect/blob/master/src/CrawlerDetect.php
11
- *
12
- * @since 1.2.4
13
- * @class Post_Views_Counter_Crawler_Detect
14
- */
15
- class Post_Views_Counter_Crawler_Detect {
16
-
17
- /**
18
- * The user agent.
19
- *
20
- * @var null
21
- */
22
- protected $user_agent = null;
23
-
24
- /**
25
- * Headers that contain a user agent.
26
- *
27
- * @var array
28
- */
29
- protected $http_headers = array();
30
-
31
- /**
32
- * Store regex matches.
33
- *
34
- * @var array
35
- */
36
- protected $matches = array();
37
-
38
- /**
39
- * Crawlers object.
40
- *
41
- * @var object
42
- */
43
- protected $crawlers = array();
44
-
45
- /**
46
- * Exclusions object.
47
- *
48
- * @var object
49
- */
50
- protected $exclusions = array();
51
-
52
- /**
53
- * Headers object.
54
- *
55
- * @var object
56
- */
57
- protected $ua_http_headers;
58
-
59
- /**
60
- * Class constructor.
61
- */
62
- public function __construct() {
63
- $this->crawlers = $this->get_crawlers_list();
64
- $this->exclusions = $this->get_exclusions_list();
65
-
66
- add_action( 'after_setup_theme', array( $this, 'init' ) );
67
- }
68
-
69
- /**
70
- * Initialize class.
71
- */
72
- public function init() {
73
- // break on admin side
74
- if ( is_admin() && ! ( defined( 'DOING_AJAX' ) && DOING_AJAX ) )
75
- return;
76
-
77
- $this->ua_http_headers = $this->get_headers_list();
78
- $this->set_http_headers();
79
- $this->set_user_agent();
80
- }
81
-
82
- /**
83
- * Set HTTP headers.
84
- *
85
- * @param array $http_headers
86
- */
87
- public function set_http_headers( $http_headers = null ) {
88
- // use global _SERVER if $http_headers aren't defined
89
- if ( ! is_array( $http_headers ) || ! count( $http_headers ) ) {
90
- $http_headers = $_SERVER;
91
- }
92
- // clear existing headers
93
- $this->http_headers = array();
94
- // only save HTTP headers - in PHP land, that means only _SERVER vars that start with HTTP_.
95
- foreach ( $http_headers as $key => $value ) {
96
- if ( substr( $key, 0, 5 ) === 'HTTP_' ) {
97
- $this->http_headers[$key] = $value;
98
- }
99
- }
100
- }
101
-
102
- /**
103
- * Return user agent headers.
104
- *
105
- * @return array
106
- */
107
- public function get_ua_http_headers() {
108
- return $this->ua_http_headers;
109
- }
110
-
111
- /**
112
- * Return the user agent.
113
- *
114
- * @return string
115
- */
116
- public function get_user_agent() {
117
- return $this->user_agent;
118
- }
119
-
120
- /**
121
- * Set the user agent.
122
- *
123
- * @param string $user_agent
124
- */
125
- public function set_user_agent( $user_agent = null ) {
126
- if ( false === empty( $user_agent ) ) {
127
- return $this->user_agent = $user_agent;
128
- } else {
129
- $this->user_agent = null;
130
- foreach ( $this->get_ua_http_headers() as $alt_header ) {
131
- if ( false === empty( $this->http_headers[$alt_header] ) ) { // @todo: should use get_http_header(), but it would be slow.
132
- $this->user_agent .= $this->http_headers[$alt_header] . ' ';
133
- }
134
- }
135
- return $this->user_agent = ( ! empty( $this->user_agent ) ? trim( $this->user_agent ) : null);
136
- }
137
- }
138
-
139
- /**
140
- * Build the user agent regex.
141
- *
142
- * @return string
143
- */
144
- public function get_regex() {
145
- return '(' . implode( '|', $this->crawlers ) . ')';
146
- }
147
-
148
- /**
149
- * Build the replacement regex.
150
- *
151
- * @return string
152
- */
153
- public function get_exclusions() {
154
- return '(' . implode( '|', $this->exclusions ) . ')';
155
- }
156
-
157
- /**
158
- * Check user agent string against the regex.
159
- *
160
- * @param string $user_agent
161
- *
162
- * @return bool
163
- */
164
- public function is_crawler( $user_agent = null ) {
165
- $agent = is_null( $user_agent ) ? $this->user_agent : $user_agent;
166
- $agent = preg_replace( '/' . $this->get_exclusions() . '/i', '', $agent );
167
- if ( strlen( trim( $agent ) ) == 0 ) {
168
- return false;
169
- } else {
170
- $result = preg_match( '/' . $this->get_regex() . '/i', trim( $agent ), $matches );
171
- }
172
- if ( $matches ) {
173
- $this->matches = $matches;
174
- }
175
- return (bool) $result;
176
- }
177
-
178
- /**
179
- * Return the matches.
180
- *
181
- * @return string
182
- */
183
- public function get_matches() {
184
- return isset( $this->matches[0] ) ? $this->matches[0] : null;
185
- }
186
-
187
- /**
188
- * Return the regular expressions to match against the user agent.
189
- *
190
- * @return array
191
- */
192
- protected function get_crawlers_list() {
193
- $data = array(
194
- '.*Java.*outbrain',
195
- '008\/',
196
- '192.comAgent',
197
- '2ip\.ru',
198
- '404checker',
199
- '^bluefish ',
200
- '^FDM ',
201
- '^Goose\/',
202
- '^Java\/',
203
- '^Mget',
204
- '^NG\/[0-9\.]',
205
- '^NING\/',
206
- '^PHP\/[0-9]',
207
- '^RMA\/',
208
- '^Ruby|Ruby\/[0-9]',
209
- '^scrutiny\/',
210
- '^VSE\/[0-9]',
211
- '^WordPress\.com',
212
- '^XRL\/[0-9]',
213
- 'a3logics\.in',
214
- 'A6-Indexer',
215
- 'a\.pr-cy\.ru',
216
- 'Aboundex',
217
- 'aboutthedomain',
218
- 'Accoona-AI-Agent',
219
- 'acoon',
220
- 'acrylicapps\.com\/pulp',
221
- 'adbeat',
222
- 'AddThis',
223
- 'ADmantX',
224
- 'adressendeutschland',
225
- 'Advanced Email Extractor v',
226
- 'agentslug',
227
- 'AHC',
228
- 'aihit',
229
- 'aiohttp\/',
230
- 'Airmail',
231
- 'akula\/',
232
- 'alertra',
233
- 'alexa site audit',
234
- 'alyze\.info',
235
- 'amagit',
236
- 'AndroidDownloadManager',
237
- 'Anemone',
238
- 'Ant\.com',
239
- 'Anturis Agent',
240
- 'AnyEvent-HTTP\/',
241
- 'Apache-HttpClient\/',
242
- 'AportWorm\/[0-9]',
243
- 'AppEngine-Google',
244
- 'Arachmo',
245
- 'arachnode',
246
- 'Arachnophilia',
247
- 'archive-com',
248
- 'aria2',
249
- 'asafaweb.com',
250
- 'AskQuickly',
251
- 'Astute',
252
- 'autocite',
253
- 'Autonomy',
254
- 'B-l-i-t-z-B-O-T',
255
- 'Backlink-Ceck\.de',
256
- 'Bad-Neighborhood',
257
- 'baidu\.com',
258
- 'baypup\/[0-9]',
259
- 'baypup\/colbert',
260
- 'BazQux',
261
- 'BCKLINKS',
262
- 'BDFetch',
263
- 'BegunAdvertising\/',
264
- 'bibnum\.bnf',
265
- 'BigBozz',
266
- 'biglotron',
267
- 'BingLocalSearch',
268
- 'BingPreview',
269
- 'binlar',
270
- 'biz_Directory',
271
- 'Blackboard Safeassign',
272
- 'Bloglovin',
273
- 'BlogPulseLive',
274
- 'BlogSearch',
275
- 'Blogtrottr',
276
- 'boitho\.com-dc',
277
- 'BPImageWalker',
278
- 'Braintree-Webhooks',
279
- 'Branch Metrics API',
280
- 'Branch-Passthrough',
281
- 'Browsershots',
282
- 'BUbiNG',
283
- 'Butterfly\/',
284
- 'BuzzSumo',
285
- 'CakePHP',
286
- 'CapsuleChecker',
287
- 'CaretNail',
288
- 'cb crawl',
289
- 'CC Metadata Scaper',
290
- 'Cerberian Drtrs',
291
- 'CERT\.at-Statistics-Survey',
292
- 'cg-eye',
293
- 'changedetection',
294
- 'Charlotte',
295
- 'CheckHost',
296
- 'chkme\.com',
297
- 'CirrusExplorer\/',
298
- 'CISPA Vulnerability Notification',
299
- 'CJNetworkQuality',
300
- 'clips\.ua\.ac\.be',
301
- 'Cloud mapping experiment',
302
- 'CloudFlare-AlwaysOnline',
303
- 'Cloudinary\/[0-9]',
304
- 'cmcm\.com',
305
- 'coccoc',
306
- 'CommaFeed',
307
- 'Commons-HttpClient',
308
- 'Comodo SSL Checker',
309
- 'contactbigdatafr',
310
- 'convera',
311
- 'copyright sheriff',
312
- 'cosmos\/[0-9]',
313
- 'Covario-IDS',
314
- 'CrawlForMe\/[0-9]',
315
- 'cron-job\.org',
316
- 'Crowsnest',
317
- 'curb',
318
- 'Curious George',
319
- 'curl',
320
- 'cuwhois\/[0-9]',
321
- 'CyberPatrol',
322
- 'cybo\.com',
323
- 'DareBoost',
324
- 'DataparkSearch',
325
- 'dataprovider',
326
- 'Daum(oa)?[ \/][0-9]',
327
- 'DeuSu',
328
- 'developers\.google\.com\/\+\/web\/snippet\/',
329
- 'Digg',
330
- 'Dispatch\/',
331
- 'dlvr',
332
- 'DNS-Tools Header-Analyzer',
333
- 'DNSPod-reporting',
334
- 'docoloc',
335
- 'DomainAppender',
336
- 'dotSemantic',
337
- 'downforeveryoneorjustme',
338
- 'downnotifier\.com',
339
- 'DowntimeDetector',
340
- 'Dragonfly File Reader',
341
- 'drupact',
342
- 'Drupal (\+http:\/\/drupal\.org\/)',
343
- 'dubaiindex',
344
- 'EARTHCOM',
345
- 'Easy-Thumb',
346
- 'ec2linkfinder',
347
- 'eCairn-Grabber',
348
- 'ECCP',
349
- 'ElectricMonk',
350
- 'elefent',
351
- 'EMail Exractor',
352
- 'EmailWolf',
353
- 'Embed PHP Library',
354
- 'Embedly',
355
- 'europarchive\.org',
356
- 'evc-batch\/[0-9]',
357
- 'EventMachine HttpClient',
358
- 'Evidon',
359
- 'Evrinid',
360
- 'ExactSearch',
361
- 'ExaleadCloudview',
362
- 'Excel\/',
363
- 'Exploratodo',
364
- 'ezooms',
365
- 'facebookexternalhit',
366
- 'facebookplatform',
367
- 'fairshare',
368
- 'Faraday v',
369
- 'Faveeo',
370
- 'Favicon downloader',
371
- 'FavOrg',
372
- 'Feed Wrangler',
373
- 'Feedbin',
374
- 'FeedBooster',
375
- 'FeedBucket',
376
- 'FeedBurner',
377
- 'FeedChecker',
378
- 'Feedly',
379
- 'Feedspot',
380
- 'feeltiptop',
381
- 'Fetch API',
382
- 'Fetch\/[0-9]',
383
- 'Fever\/[0-9]',
384
- 'findlink',
385
- 'findthatfile',
386
- 'Flamingo_SearchEngine',
387
- 'FlipboardBrowserProxy',
388
- 'FlipboardProxy',
389
- 'FlipboardRSS',
390
- 'fluffy',
391
- 'flynxapp',
392
- 'forensiq',
393
- 'FoundSeoTool\/[0-9]',
394
- 'free thumbnails',
395
- 'FreeWebMonitoring SiteChecker',
396
- 'Funnelback',
397
- 'g00g1e\.net',
398
- 'GAChecker',
399
- 'geek-tools',
400
- 'Genderanalyzer',
401
- 'Genieo',
402
- 'GentleSource',
403
- 'GetLinkInfo',
404
- 'getprismatic\.com',
405
- 'GetURLInfo\/[0-9]',
406
- 'GigablastOpenSource',
407
- 'Go [\d\.]* package http',
408
- 'Go-http-client',
409
- 'GomezAgent',
410
- 'gooblog',
411
- 'Goodzer\/[0-9]',
412
- 'Google favicon',
413
- 'Google Keyword Suggestion',
414
- 'Google Keyword Tool',
415
- 'Google Page Speed Insights',
416
- 'Google PP Default',
417
- 'Google Search Console',
418
- 'Google Web Preview',
419
- 'Google-Adwords',
420
- 'Google-Apps-Script',
421
- 'Google-Calendar-Importer',
422
- 'Google-HTTP-Java-Client',
423
- 'Google-Publisher-Plugin',
424
- 'Google-SearchByImage',
425
- 'Google-Site-Verification',
426
- 'Google-Structured-Data-Testing-Tool',
427
- 'google_partner_monitoring',
428
- 'GoogleDocs',
429
- 'GoogleHC\/',
430
- 'GoogleProducer',
431
- 'GoScraper',
432
- 'GoSpotCheck',
433
- 'GoSquared-Status-Checker',
434
- 'gosquared-thumbnailer',
435
- 'GotSiteMonitor',
436
- 'Grammarly',
437
- 'grouphigh',
438
- 'grub-client',
439
- 'GTmetrix',
440
- 'Hatena',
441
- 'hawkReader',
442
- 'HEADMasterSEO',
443
- 'HeartRails_Capture',
444
- 'heritrix',
445
- 'hledejLevne\.cz\/[0-9]',
446
- 'Holmes',
447
- 'HootSuite Image proxy',
448
- 'Hootsuite-WebFeed\/[0-9]',
449
- 'HostTracker',
450
- 'ht:\/\/check',
451
- 'htdig',
452
- 'HTMLParser\/',
453
- 'HTTP-Header-Abfrage',
454
- 'http-kit',
455
- 'HTTP-Tiny',
456
- 'HTTP_Compression_Test',
457
- 'http_request2',
458
- 'http_requester',
459
- 'HttpComponents',
460
- 'httphr',
461
- 'HTTPMon',
462
- 'httpscheck',
463
- 'httpssites_power',
464
- 'httpunit',
465
- 'HttpUrlConnection',
466
- 'httrack',
467
- 'hosterstats',
468
- 'huaweisymantec',
469
- 'HubPages.*crawlingpolicy',
470
- 'HubSpot Connect',
471
- 'HubSpot Marketing Grader',
472
- 'HyperZbozi.cz Feeder',
473
- 'ichiro',
474
- 'IdeelaborPlagiaat',
475
- 'IDG Twitter Links Resolver',
476
- 'IDwhois\/[0-9]',
477
- 'Iframely',
478
- 'igdeSpyder',
479
- 'IlTrovatore',
480
- 'ImageEngine\/',
481
- 'Imagga',
482
- 'InAGist',
483
- 'inbound\.li parser',
484
- 'InDesign%20CC',
485
- 'infegy',
486
- 'infohelfer',
487
- 'InfoWizards Reciprocal Link System PRO',
488
- 'inpwrd\.com',
489
- 'Integrity',
490
- 'integromedb',
491
- 'internet_archive',
492
- 'InternetSeer',
493
- 'internetVista monitor',
494
- 'IODC',
495
- 'IOI',
496
- 'ips-agent',
497
- 'iqdb\/',
498
- 'Irokez',
499
- 'isitup\.org',
500
- 'iskanie',
501
- 'iZSearch',
502
- 'janforman',
503
- 'Jigsaw',
504
- 'Jobboerse',
505
- 'jobo',
506
- 'Jobrapido',
507
- 'KeepRight OpenStreetMap Checker',
508
- 'KimonoLabs\/',
509
- 'knows\.is',
510
- 'kouio',
511
- 'KrOWLer',
512
- 'kulturarw3',
513
- 'KumKie',
514
- 'L\.webis',
515
- 'Larbin',
516
- 'LayeredExtractor',
517
- 'LibVLC',
518
- 'libwww',
519
- 'link checker',
520
- 'Link Valet',
521
- 'link_thumbnailer',
522
- 'linkCheck',
523
- 'linkdex',
524
- 'LinkExaminer',
525
- 'linkfluence',
526
- 'linkpeek',
527
- 'LinkTiger',
528
- 'LinkWalker',
529
- 'Lipperhey',
530
- 'livedoor ScreenShot',
531
- 'LoadImpactPageAnalyzer',
532
- 'LoadImpactRload',
533
- 'LongURL API',
534
- 'looksystems\.net',
535
- 'ltx71',
536
- 'lwp-trivial',
537
- 'lycos',
538
- 'LYT\.SR',
539
- 'mabontland',
540
- 'MagpieRSS',
541
- 'Mail.Ru',
542
- 'MailChimp\.com',
543
- 'Mandrill',
544
- 'marketinggrader',
545
- 'Mediapartners-Google',
546
- 'MegaIndex\.ru',
547
- 'Melvil Rawi\/',
548
- 'MergeFlow-PageReader',
549
- 'MetaInspector',
550
- 'Metaspinner',
551
- 'MetaURI',
552
- 'Microsearch',
553
- 'Microsoft Office ',
554
- 'Microsoft Windows Network Diagnostics',
555
- 'Mindjet',
556
- 'Miniflux',
557
- 'Mnogosearch',
558
- 'mogimogi',
559
- 'Mojolicious (Perl)',
560
- 'monitis',
561
- 'Monitority\/[0-9]',
562
- 'montastic',
563
- 'MonTools',
564
- 'Moreover',
565
- 'Morning Paper',
566
- 'mowser',
567
- 'Mrcgiguy',
568
- 'mShots',
569
- 'MVAClient',
570
- 'nagios',
571
- 'Najdi\.si\/',
572
- 'NETCRAFT',
573
- 'NetLyzer FastProbe',
574
- 'netresearch',
575
- 'NetShelter ContentScan',
576
- 'NetTrack',
577
- 'Netvibes',
578
- 'Neustar WPM',
579
- 'NeutrinoAPI',
580
- 'NewsBlur .*Finder',
581
- 'NewsGator',
582
- 'newsme',
583
- 'newspaper\/',
584
- 'NG-Search',
585
- 'nineconnections\.com',
586
- 'NLNZ_IAHarvester',
587
- 'Nmap Scripting Engine',
588
- 'node-superagent',
589
- 'node\.io',
590
- 'nominet\.org\.uk',
591
- 'Norton-Safeweb',
592
- 'Notifixious',
593
- 'notifyninja',
594
- 'nuhk',
595
- 'nutch',
596
- 'Nuzzel',
597
- 'nWormFeedFinder',
598
- 'Nymesis',
599
- 'Ocelli\/[0-9]',
600
- 'oegp',
601
- 'okhttp',
602
- 'Omea Reader',
603
- 'omgili',
604
- 'Online Domain Tools',
605
- 'OpenCalaisSemanticProxy',
606
- 'Openstat\/',
607
- 'OpenVAS',
608
- 'Optimizer',
609
- 'Orbiter',
610
- 'OrgProbe\/[0-9]',
611
- 'ow\.ly',
612
- 'ownCloud News',
613
- 'Page Analyzer',
614
- 'Page Valet',
615
- 'page2rss',
616
- 'page_verifier',
617
- 'PagePeeker',
618
- 'Pagespeed\/[0-9]',
619
- 'Panopta',
620
- 'panscient',
621
- 'parsijoo',
622
- 'PayPal IPN',
623
- 'Pcore-HTTP',
624
- 'Pearltrees',
625
- 'peerindex',
626
- 'Peew',
627
- 'PhantomJS\/',
628
- 'Photon\/',
629
- 'phpcrawl',
630
- 'phpservermon',
631
- 'Pi-Monster',
632
- 'Pingdom\.com',
633
- 'Pingoscope',
634
- 'PingSpot',
635
- 'Pinterest',
636
- 'Pizilla',
637
- 'Ploetz \+ Zeller',
638
- 'Plukkie',
639
- 'PocketParser',
640
- 'Pompos',
641
- 'Porkbun',
642
- 'Port Monitor',
643
- 'postano',
644
- 'PostPost',
645
- 'postrank',
646
- 'PowerPoint\/',
647
- 'Priceonomics Analysis Engine',
648
- 'Prlog',
649
- 'probethenet',
650
- 'Project 25499',
651
- 'Promotion_Tools_www.searchenginepromotionhelp.com',
652
- 'prospectb2b',
653
- 'Protopage',
654
- 'proximic',
655
- 'PTST ',
656
- 'PTST\/[0-9]+',
657
- 'Pulsepoint XT3 web scraper',
658
- 'Python-httplib2',
659
- 'python-requests',
660
- 'Python-urllib',
661
- 'Qirina Hurdler',
662
- 'Qseero',
663
- 'Qualidator.com SiteAnalyzer',
664
- 'Quora Link Preview',
665
- 'Qwantify',
666
- 'Radian6',
667
- 'RankSonicSiteAuditor',
668
- 'Readability',
669
- 'RealPlayer%20Downloader',
670
- 'RebelMouse',
671
- 'redback\/',
672
- 'Redirect Checker Tool',
673
- 'ReederForMac',
674
- 'ResponseCodeTest\/[0-9]',
675
- 'RestSharp',
676
- 'RetrevoPageAnalyzer',
677
- 'Riddler',
678
- 'Rival IQ',
679
- 'Robosourcer',
680
- 'Robozilla\/[0-9]',
681
- 'ROI Hunter',
682
- 'SalesIntelligent',
683
- 'SauceNAO',
684
- 'SBIder',
685
- 'Scoop',
686
- 'scooter',
687
- 'ScoutJet',
688
- 'ScoutURLMonitor',
689
- 'Scrapy',
690
- 'Scrubby',
691
- 'SearchSight',
692
- 'semanticdiscovery',
693
- 'semanticjuice',
694
- 'SEO Browser',
695
- 'Seo Servis',
696
- 'seo-nastroj.cz',
697
- 'Seobility',
698
- 'SEOCentro',
699
- 'SeoCheck',
700
- 'SeopultContentAnalyzer',
701
- 'SEOstats',
702
- 'Server Density Service Monitoring',
703
- 'servernfo\.com',
704
- 'Seznam screenshot-generator',
705
- 'Shelob',
706
- 'Shoppimon Analyzer',
707
- 'ShoppimonAgent\/[0-9]',
708
- 'ShopWiki',
709
- 'ShortLinkTranslate',
710
- 'shrinktheweb',
711
- 'SilverReader',
712
- 'SimplePie',
713
- 'SimplyFast',
714
- 'Site-Shot\/',
715
- 'Site24x7',
716
- 'SiteBar',
717
- 'SiteCondor',
718
- 'siteexplorer\.info',
719
- 'SiteGuardian',
720
- 'Siteimprove\.com',
721
- 'Sitemap(s)? Generator',
722
- 'Siteshooter B0t',
723
- 'SiteTruth',
724
- 'sitexy\.com',
725
- 'SkypeUriPreview',
726
- 'slider\.com',
727
- 'slurp',
728
- 'SMRF URL Expander',
729
- 'Snappy',
730
- 'SniffRSS',
731
- 'sniptracker',
732
- 'Snoopy',
733
- 'sogou web',
734
- 'SortSite',
735
- 'spaziodati',
736
- 'Specificfeeds',
737
- 'speedy',
738
- 'SPEng',
739
- 'Spinn3r',
740
- 'spray-can',
741
- 'Sprinklr ',
742
- 'spyonweb',
743
- 'Sqworm',
744
- 'SSL Labs',
745
- 'StackRambler',
746
- 'Statastico\/',
747
- 'StatusCake',
748
- 'Stratagems Kumo',
749
- 'Stroke.cz',
750
- 'StudioFACA',
751
- 'suchen',
752
- 'summify',
753
- 'Super Monitoring',
754
- 'Surphace Scout',
755
- 'SwiteScraper',
756
- 'Symfony2 BrowserKit',
757
- 'Sysomos',
758
- 'T0PHackTeam',
759
- 'Tarantula\/',
760
- 'teoma',
761
- 'terrainformatica\.com',
762
- 'The Expert HTML Source Viewer',
763
- 'theinternetrules',
764
- 'theoldreader\.com',
765
- 'Thumbshots',
766
- 'ThumbSniper',
767
- 'TinEye',
768
- 'Tiny Tiny RSS',
769
- 'topster',
770
- 'touche.com',
771
- 'Traackr.com',
772
- 'truwoGPS',
773
- 'tweetedtimes\.com',
774
- 'Tweetminster',
775
- 'Twikle',
776
- 'Twingly',
777
- 'Typhoeus',
778
- 'ubermetrics-technologies',
779
- 'uclassify',
780
- 'UdmSearch',
781
- 'UnwindFetchor',
782
- 'updated',
783
- 'Upflow',
784
- 'URLChecker',
785
- 'URLitor.com',
786
- 'urlresolver',
787
- 'Urlstat',
788
- 'UrlTrends Ranking Updater',
789
- 'Vagabondo',
790
- 'via ggpht\.com GoogleImageProxy',
791
- 'visionutils',
792
- 'vkShare',
793
- 'voltron',
794
- 'Vortex\/[0-9]',
795
- 'voyager\/',
796
- 'VSAgent\/[0-9]',
797
- 'VSB-TUO\/[0-9]',
798
- 'VYU2',
799
- 'w3af\.org',
800
- 'W3C-checklink',
801
- 'W3C-mobileOK',
802
- 'W3C_I18n-Checker',
803
- 'W3C_Unicorn',
804
- 'wangling',
805
- 'Wappalyzer',
806
- 'WatchMouse',
807
- 'WbSrch\/',
808
- 'web-capture\.net',
809
- 'Web-Monitoring',
810
- 'Web-sniffer',
811
- 'Webauskunft',
812
- 'WebCapture',
813
- 'webcollage',
814
- 'WebCookies',
815
- 'WebCorp',
816
- 'WebDoc',
817
- 'WebFetch',
818
- 'WebImages',
819
- 'WebIndex',
820
- 'webkit2png',
821
- 'webmastercoffee',
822
- 'webmon ',
823
- 'webscreenie',
824
- 'Webshot',
825
- 'Website Analyzer\/',
826
- 'websitepulse[+ ]checker',
827
- 'Websnapr\/',
828
- 'Websquash\.com',
829
- 'Webthumb\/[0-9]',
830
- 'WebThumbnail',
831
- 'WeCrawlForThePeace',
832
- 'WeLikeLinks',
833
- 'WEPA',
834
- 'WeSEE',
835
- 'wf84',
836
- 'wget',
837
- 'WhatsApp',
838
- 'WhatsMyIP',
839
- 'WhatWeb',
840
- 'Whibse',
841
- 'Whynder Magnet',
842
- 'Windows-RSS-Platform',
843
- 'WinHttpRequest',
844
- 'wkhtmlto',
845
- 'wmtips',
846
- 'Woko',
847
- 'WomlpeFactory',
848
- 'Word\/',
849
- 'WordPress\/',
850
- 'wotbox',
851
- 'WP Engine Install Performance API',
852
- 'WPScan',
853
- 'wscheck',
854
- 'WWW-Mechanize',
855
- 'www\.monitor\.us',
856
- 'XaxisSemanticsClassifier',
857
- 'Xenu Link Sleuth',
858
- 'XING-contenttabreceiver\/[0-9]',
859
- 'XmlSitemapGenerator',
860
- 'xpymep([0-9]?)\.exe',
861
- 'Y!J-(ASR|BSC)',
862
- 'Yaanb',
863
- 'yacy',
864
- 'Yahoo Ad monitoring',
865
- 'Yahoo Link Preview',
866
- 'YahooCacheSystem',
867
- 'YahooSeeker',
868
- 'YahooYSMcm',
869
- 'YandeG',
870
- 'yandex',
871
- 'yanga',
872
- 'yeti',
873
- 'Yo-yo',
874
- 'Yoleo Consumer',
875
- 'yoogliFetchAgent',
876
- 'YottaaMonitor',
877
- 'yourls\.org',
878
- 'Zao',
879
- 'Zemanta Aggregator',
880
- 'Zend\\\\Http\\\\Client',
881
- 'Zend_Http_Client',
882
- 'zgrab',
883
- 'ZnajdzFoto',
884
- 'ZyBorg',
885
- '[a-z0-9\-_]*((?<!cu)bot|crawler|archiver|transcoder|spider|uptime|validator|fetcher)',
886
- );
887
-
888
- return $data;
889
- }
890
-
891
- /**
892
- * Return the list of strings to remove from the user agent before running the crawler regex.
893
- *
894
- * @return array
895
- */
896
- public function get_exclusions_list() {
897
- $data = array(
898
- 'Safari.[\d\.]*',
899
- 'Firefox.[\d\.]*',
900
- 'Chrome.[\d\.]*',
901
- 'Chromium.[\d\.]*',
902
- 'MSIE.[\d\.]',
903
- 'Opera\/[\d\.]*',
904
- 'Mozilla.[\d\.]*',
905
- 'AppleWebKit.[\d\.]*',
906
- 'Trident.[\d\.]*',
907
- 'Windows NT.[\d\.]*',
908
- 'Android [\d\.]*',
909
- 'Macintosh.',
910
- 'Ubuntu',
911
- 'Linux',
912
- '[ ]Intel',
913
- 'Mac OS X [\d_]*',
914
- '(like )?Gecko(.[\d\.]*)?',
915
- 'KHTML,',
916
- 'CriOS.[\d\.]*',
917
- 'CPU iPhone OS ([0-9_])* like Mac OS X',
918
- 'CPU OS ([0-9_])* like Mac OS X',
919
- 'iPod',
920
- 'compatible',
921
- 'x86_..',
922
- 'i686',
923
- 'x64',
924
- 'X11',
925
- 'rv:[\d\.]*',
926
- 'Version.[\d\.]*',
927
- 'WOW64',
928
- 'Win64',
929
- 'Dalvik.[\d\.]*',
930
- ' \.NET CLR [\d\.]*',
931
- 'Presto.[\d\.]*',
932
- 'Media Center PC',
933
- 'BlackBerry',
934
- 'Build',
935
- 'Opera Mini\/\d{1,2}\.\d{1,2}\.[\d\.]*\/\d{1,2}\.',
936
- 'Opera',
937
- ' \.NET[\d\.]*',
938
- '\(|\)|;|,', // remove the following characters ( ) : ,
939
- );
940
-
941
- return $data;
942
- }
943
-
944
- /**
945
- * Return all possible HTTP headers that represent the User-Agent string.
946
- *
947
- * @return array
948
- */
949
- public function get_headers_list() {
950
- $data = array(
951
- // the default User-Agent string.
952
- 'HTTP_USER_AGENT',
953
- // header can occur on devices using Opera Mini.
954
- 'HTTP_X_OPERAMINI_PHONE_UA',
955
- // vodafone specific header: http://www.seoprinciple.com/mobile-web-community-still-angry-at-vodafone/24/
956
- 'HTTP_X_DEVICE_USER_AGENT',
957
- 'HTTP_X_ORIGINAL_USER_AGENT',
958
- 'HTTP_X_SKYFIRE_PHONE',
959
- 'HTTP_X_BOLT_PHONE_UA',
960
- 'HTTP_DEVICE_STOCK_UA',
961
- 'HTTP_X_UCBROWSER_DEVICE_UA',
962
- // sometimes, bots (especially Google) use a genuine user agent, but fill this header in with their email address
963
- 'HTTP_FROM',
964
- );
965
-
966
- return $data;
967
- }
968
-
969
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/cron.php DELETED
@@ -1,108 +0,0 @@
1
- <?php
2
- // exit if accessed directly
3
- if ( ! defined( 'ABSPATH' ) )
4
- exit;
5
-
6
- /**
7
- * Post_Views_Counter_Cron class.
8
- *
9
- * @class Post_Views_Counter_Cron
10
- */
11
- class Post_Views_Counter_Cron {
12
-
13
- public function __construct() {
14
- // actions
15
- add_action( 'init', array( $this, 'check_cron' ) );
16
- add_action( 'pvc_reset_counts', array( $this, 'reset_counts' ) );
17
- add_action( 'pvc_flush_cached_counts', array( $this, 'flush_cached_counts' ) );
18
-
19
- // filters
20
- add_filter( 'cron_schedules', array( $this, 'cron_time_intervals' ) );
21
- }
22
-
23
- /**
24
- * Reset daily counts.
25
- *
26
- * @global object $wpdb
27
- */
28
- public function reset_counts() {
29
- global $wpdb;
30
-
31
- $counter = array(
32
- 'days' => 1,
33
- 'weeks' => 7,
34
- 'months' => 30,
35
- 'years' => 365
36
- );
37
-
38
- $wpdb->query( 'DELETE FROM ' . $wpdb->prefix . 'post_views WHERE type = 0 AND CAST( period AS SIGNED ) < CAST( ' . date( 'Ymd', strtotime( '-' . ( (int) ( $counter[Post_Views_Counter()->options['general']['reset_counts']['type']] * Post_Views_Counter()->options['general']['reset_counts']['number'] ) ) . ' days' ) ) . ' AS SIGNED)' );
39
- }
40
-
41
- /**
42
- * Call Post_Views_Counter_Counter::flush_cache_to_db().
43
- * This is (un)scheduled on plugin activation/deactivation.
44
- */
45
- public function flush_cached_counts() {
46
- $counter = Post_Views_Counter()->counter;
47
-
48
- if ( $counter && $counter->using_object_cache() )
49
- $counter->flush_cache_to_db();
50
- }
51
-
52
- /**
53
- * Add new cron interval from settings.
54
- *
55
- * @param array $schedules
56
- * @return array
57
- */
58
- public function cron_time_intervals( $schedules ) {
59
- $schedules['post_views_counter_interval'] = array(
60
- 'interval' => 86400,
61
- 'display' => __( 'Post Views Counter reset daily counts interval', 'post-views-counter' )
62
- );
63
-
64
- $schedules['post_views_counter_flush_interval'] = array(
65
- 'interval' => Post_Views_Counter()->counter->get_timestamp( Post_Views_Counter()->options['general']['flush_interval']['type'], Post_Views_Counter()->options['general']['flush_interval']['number'], false ),
66
- 'display' => __( 'Post Views Counter cache flush interval', 'post-views-counter' )
67
- );
68
-
69
- return $schedules;
70
- }
71
-
72
- /**
73
- * Check whether WP Cron needs to add new task.
74
- */
75
- public function check_cron() {
76
- if ( ! is_admin() )
77
- return;
78
-
79
- // set wp cron task
80
- if ( Post_Views_Counter()->options['general']['cron_run'] ) {
81
-
82
- // not set or need to be updated?
83
- if ( ! wp_next_scheduled( 'pvc_reset_counts' ) || Post_Views_Counter()->options['general']['cron_update'] ) {
84
-
85
- // task is added but need to be updated
86
- if ( Post_Views_Counter()->options['general']['cron_update'] ) {
87
- // remove old schedule
88
- wp_clear_scheduled_hook( 'pvc_reset_counts' );
89
-
90
- // set update to false
91
- $general = Post_Views_Counter()->options['general'];
92
- $general['cron_update'] = false;
93
-
94
- // update settings
95
- update_option( 'post_views_counter_settings_general', $general );
96
- }
97
-
98
- // set schedule
99
- wp_schedule_event( current_time( 'timestamp', true ) + 86400, 'post_views_counter_interval', 'pvc_reset_counts' );
100
- }
101
- } else {
102
- // remove schedule
103
- wp_clear_scheduled_hook( 'pvc_reset_counts' );
104
- remove_action( 'pvc_reset_counts', array( $this, 'reset_counts' ) );
105
- }
106
- }
107
-
108
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/dashboard.php DELETED
@@ -1,428 +0,0 @@
1
- <?php
2
- // exit if accessed directly
3
- if ( ! defined( 'ABSPATH' ) )
4
- exit;
5
-
6
- /**
7
- * Post_Views_Counter_Dashboard class.
8
- *
9
- * @class Post_Views_Counter_Dashboard
10
- */
11
- class Post_Views_Counter_Dashboard {
12
-
13
- public function __construct() {
14
- // actions
15
- add_action( 'wp_dashboard_setup', array( $this, 'wp_dashboard_setup' ) );
16
- add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts_styles' ) );
17
- add_action( 'wp_ajax_pvc_dashboard_chart', array( $this, 'dashboard_widget_chart' ) );
18
- add_action( 'wp_ajax_pvc_dashboard_chart_user_post_types', array( $this, 'dashboard_widget_chart_user_post_types' ) );
19
- }
20
-
21
- /**
22
- * Initialize widget.
23
- */
24
- public function wp_dashboard_setup() {
25
- // filter user_can_see_stats
26
- if ( ! apply_filters( 'pvc_user_can_see_stats', current_user_can( 'publish_posts' ) ) ) {
27
- return;
28
- }
29
-
30
- // add dashboard widget
31
- wp_add_dashboard_widget( 'pvc_dashboard', __( 'Post Views', 'post-views-counter' ), array( $this, 'dashboard_widget' ) );
32
- }
33
-
34
- /**
35
- * Render dashboard widget.
36
- *
37
- * @return mixed
38
- */
39
- public function dashboard_widget() {
40
- ?>
41
- <div id="pvc_dashboard_container">
42
- <canvas id="pvc_chart" height="175"></canvas>
43
- <div class="pvc_months">
44
-
45
- <?php echo $this->generate_months( current_time( 'timestamp', false ) ); ?>
46
-
47
- </div>
48
- </div>
49
- <?php
50
- }
51
-
52
- /**
53
- * Generate months.
54
- *
55
- * @param string $timestamp
56
- * @return string
57
- */
58
- public function generate_months( $timestamp ) {
59
- $dates = array(
60
- explode( ' ', date( "m F Y", strtotime( "-1 months", $timestamp ) ) ),
61
- explode( ' ', date( "m F Y", $timestamp ) ),
62
- explode( ' ', date( "m F Y", strtotime( "+1 months", $timestamp ) ) )
63
- );
64
-
65
- $current = date( "Ym", current_time( 'timestamp', false ) );
66
-
67
- if ( (int) $current <= (int) ( $dates[1][2] . $dates[1][0] ) )
68
- $next = '<span class="next">' . $dates[2][1] . ' ' . $dates[2][2] . ' ›</span>';
69
- else
70
- $next = '<a class="next" href="#" data-date="' . ( $dates[2][0] . '|' . $dates[2][2] ) . '">' . $dates[2][1] . ' ' . $dates[2][2] . ' ›</a>';
71
-
72
- $dates = array(
73
- 'prev' => '<a class="prev" href="#" data-date="' . ( $dates[0][0] . '|' . $dates[0][2] ) . '">‹ ' . $dates[0][1] . ' ' . $dates[0][2] . '</a>',
74
- 'current' => '<span class="current">' . $dates[1][1] . ' ' . $dates[1][2] . '</span>',
75
- 'next' => $next
76
- );
77
-
78
- return $dates['prev'] . $dates['current'] . $dates['next'];
79
- }
80
-
81
- /**
82
- * Dashboard widget chart user post types.
83
- *
84
- * @return void
85
- */
86
- public function dashboard_widget_chart_user_post_types() {
87
- if ( ! check_ajax_referer( 'dashboard-chart-user-post-types', 'nonce' ) )
88
- wp_die( __( 'You do not have permission to access this page.', 'post-views-counter' ) );
89
-
90
- // get post types
91
- $post_types = Post_Views_Counter()->options['general']['post_types_count'];
92
-
93
- // simulate total views as post type
94
- $post_types[] = '_pvc_total_views';
95
-
96
- // valid data?
97
- if ( isset( $_POST['nonce'], $_POST['hidden'], $_POST['post_type'] ) && ( in_array( $_POST['post_type'], $post_types, true ) ) ) {
98
- // get user ID
99
- $user_id = get_current_user_id();
100
-
101
- // get user dashboard data
102
- $userdata = get_user_meta( $user_id, 'pvc_dashboard', true );
103
-
104
- // empty userdata?
105
- if ( ! is_array( $userdata ) || empty( $userdata ) )
106
- $userdata = array();
107
-
108
- // empty post types?
109
- if ( ! array_key_exists( 'post_types', $userdata ) || ! is_array( $userdata['post_types'] ) )
110
- $userdata['post_types'] = array();
111
-
112
- // hide post type?
113
- if ( $_POST['hidden'] === 'true' ) {
114
- if ( ! in_array( $_POST['post_type'], $userdata['post_types'], true ) )
115
- $userdata['post_types'][] = $_POST['post_type'];
116
- } else {
117
- if ( ( $key = array_search( $_POST['post_type'], $userdata['post_types'] ) ) !== false )
118
- unset( $userdata['post_types'][$key] );
119
- }
120
-
121
- // update userdata
122
- update_user_meta( $user_id, 'pvc_dashboard', $userdata );
123
- }
124
-
125
- exit;
126
- }
127
-
128
- /**
129
- * Dashboard widget chart data function.
130
- *
131
- * @global $_wp_admin_css_colors
132
- * @return void
133
- */
134
- public function dashboard_widget_chart() {
135
- if ( ! apply_filters( 'pvc_user_can_see_stats', current_user_can( 'publish_posts' ) ) )
136
- wp_die( _( 'You do not have permission to access this page.', 'post-views-counter' ) );
137
-
138
- if ( ! check_ajax_referer( 'dashboard-chart', 'nonce' ) )
139
- wp_die( __( 'You do not have permission to access this page.', 'post-views-counter' ) );
140
-
141
- // get period
142
- $period = isset( $_POST['period'] ) ? esc_attr( $_POST['period'] ) : 'this_month';
143
-
144
- // get post types
145
- $post_types = Post_Views_Counter()->options['general']['post_types_count'];
146
-
147
- // get stats
148
- $query_args = array(
149
- 'post_type' => $post_types,
150
- 'posts_per_page' => -1,
151
- 'paged' => false,
152
- 'orderby' => 'post_views',
153
- 'suppress_filters' => false,
154
- 'no_found_rows' => true
155
- );
156
-
157
- // $now = getdate( current_time( 'timestamp', get_option( 'gmt_offset' ) ) );
158
- $now = getdate( current_time( 'timestamp', get_option( 'gmt_offset' ) ) - 2592000 );
159
-
160
- // get admin color scheme
161
- global $_wp_admin_css_colors;
162
-
163
- $admin_color = get_user_option( 'admin_color' );
164
- $colors = $_wp_admin_css_colors[$admin_color]->colors;
165
- $color = $this->hex2rgb( $colors[2] );
166
-
167
- // set chart labels
168
- switch ( $period ) {
169
- case 'this_week':
170
- $data = array(
171
- 'text' => array(
172
- 'xAxes' => date_i18n( 'F Y' ),
173
- 'yAxes' => __( 'Post Views', 'post-views-counter' )
174
- )
175
- );
176
-
177
- for ( $day = 0; $day <= 6; $day ++ ) {
178
- $date = strtotime( $now['mday'] . '-' . $now['mon'] . '-' . $now['year'] . ' + ' . $day . ' days - ' . $now['wday'] . ' days' );
179
- $query = new WP_Query( wp_parse_args( $query_args, array( 'views_query' => array( 'year' => date( 'Y', $date ), 'month' => date( 'n', $date ), 'day' => date( 'd', $date ) ) ) ) );
180
-
181
- $data['data']['labels'][] = date_i18n( 'j', $date );
182
- $data['data']['datasets'][$type_name]['label'] = __( 'Post Views', 'post-views-counter' );
183
- $data['data']['datasets'][0]['data'][] = $query->total_views;
184
- }
185
- break;
186
-
187
- case 'this_year':
188
- $data = array(
189
- 'text' => array(
190
- 'xAxes' => __( 'Year', 'post-views-counter' ) . date( ' Y' ),
191
- 'yAxes' => __( 'Post Views', 'post-views-counter' ),
192
- ),
193
- 'design' => array(
194
- 'fill' => true,
195
- 'backgroundColor' => 'rgba(' . $color['r'] . ',' . $color['g'] . ',' . $color['b'] . ', 0.2)',
196
- 'borderColor' => 'rgba(' . $color['r'] . ',' . $color['g'] . ',' . $color['b'] . ', 1)',
197
- 'borderWidth' => 1.2,
198
- 'borderDash' => array(),
199
- 'pointBorderColor' => 'rgba(' . $color['r'] . ',' . $color['g'] . ',' . $color['b'] . ', 1)',
200
- 'pointBackgroundColor' => 'rgba(255, 255, 255, 1)',
201
- 'pointBorderWidth' => 1.2
202
- )
203
- );
204
-
205
- $data['data']['datasets'][0]['label'] = __( 'Total Views', 'post-views-counter' );
206
- $data['data']['datasets'][0]['post_type'] = '_pvc_total_views';
207
-
208
- // reindex post types
209
- $post_types = array_combine( range( 1, count( $post_types ) ), array_values( $post_types ) );
210
-
211
- $post_type_data = array();
212
-
213
- foreach ( $post_types as $id => $post_type ) {
214
- $post_type_obj = get_post_type_object( $post_type );
215
-
216
- $data['data']['datasets'][$id]['label'] = $post_type_obj->labels->name;
217
- $data['data']['datasets'][$id]['post_type'] = $post_type_obj->name;
218
- $data['data']['datasets'][$id]['data'] = array();
219
-
220
- // get month views
221
- $post_type_data[$id] = array_values(
222
- pvc_get_views(
223
- array(
224
- 'fields' => 'date=>views',
225
- 'post_type' => $post_type,
226
- 'views_query' => array(
227
- 'year' => date( 'Y' ),
228
- 'month' => '',
229
- 'week' => '',
230
- 'day' => ''
231
- )
232
- )
233
- )
234
- );
235
- }
236
-
237
- $sum = array();
238
-
239
- foreach ( $post_type_data as $post_type_id => $post_views ) {
240
- foreach ( $post_views as $id => $views ) {
241
- // generate chart data for specific post types
242
- $data['data']['datasets'][$post_type_id]['data'][] = $views;
243
-
244
- if ( ! array_key_exists( $id, $sum ) )
245
- $sum[$id] = 0;
246
-
247
- $sum[$id] += $views;
248
- }
249
- }
250
-
251
- // this month all days
252
- for ( $i = 1; $i <= 12; $i ++ ) {
253
- // generate chart data
254
- $data['data']['labels'][] = $i;
255
- $data['data']['dates'][] = date_i18n( 'F Y', strtotime( date( 'Y' ) . '-' . str_pad( $i, 2, '0', STR_PAD_LEFT ) . '-01' ) );
256
- $data['data']['datasets'][0]['data'][] = $sum[$i - 1];
257
- }
258
- break;
259
-
260
- case 'this_month':
261
- default:
262
- $userdata = $this->get_dashboard_user_data( get_current_user_id(), 'post_types' );
263
-
264
- if ( $period !== 'this_month' ) {
265
- $date = explode( '|', $period, 2 );
266
- $months = strtotime( (string) $date[1] . '-' . (string) $date[0] . '-13' );
267
- } else
268
- $months = current_time( 'timestamp', false );
269
-
270
- // get date chunks
271
- $date = explode( ' ', date( "m Y t F", $months ) );
272
-
273
- $data = array(
274
- 'months' => $this->generate_months( $months ),
275
- 'text' => array(
276
- 'xAxes' => $date[3] . ' ' . $date[1],
277
- 'yAxes' => __( 'Post Views', 'post-views-counter' ),
278
- ),
279
- 'design' => array(
280
- 'fill' => true,
281
- 'backgroundColor' => 'rgba(' . $color['r'] . ',' . $color['g'] . ',' . $color['b'] . ', 0.2)',
282
- 'borderColor' => 'rgba(' . $color['r'] . ',' . $color['g'] . ',' . $color['b'] . ', 1)',
283
- 'borderWidth' => 1.2,
284
- 'borderDash' => array(),
285
- 'pointBorderColor' => 'rgba(' . $color['r'] . ',' . $color['g'] . ',' . $color['b'] . ', 1)',
286
- 'pointBackgroundColor' => 'rgba(255, 255, 255, 1)',
287
- 'pointBorderWidth' => 1.2
288
- )
289
- );
290
-
291
- $data['data']['datasets'][0]['label'] = __( 'Total Views', 'post-views-counter' );
292
- $data['data']['datasets'][0]['post_type'] = '_pvc_total_views';
293
- $data['data']['datasets'][0]['hidden'] = in_array( '_pvc_total_views', $userdata, true );
294
-
295
- // reindex post types
296
- $post_types = array_combine( range( 1, count( $post_types ) ), array_values( $post_types ) );
297
-
298
- $post_type_data = array();
299
-
300
- foreach ( $post_types as $id => $post_type ) {
301
- $post_type_obj = get_post_type_object( $post_type );
302
-
303
- $data['data']['datasets'][$id]['label'] = $post_type_obj->labels->name;
304
- $data['data']['datasets'][$id]['post_type'] = $post_type_obj->name;
305
- $data['data']['datasets'][$id]['hidden'] = in_array( $post_type_obj->name, $userdata, true );
306
- $data['data']['datasets'][$id]['data'] = array();
307
-
308
- // get month views
309
- $post_type_data[$id] = array_values(
310
- pvc_get_views(
311
- array(
312
- 'fields' => 'date=>views',
313
- 'post_type' => $post_type,
314
- 'views_query' => array(
315
- 'year' => $date[1],
316
- 'month' => $date[0],
317
- 'week' => '',
318
- 'day' => ''
319
- )
320
- )
321
- )
322
- );
323
- }
324
-
325
- $sum = array();
326
-
327
- foreach ( $post_type_data as $post_type_id => $post_views ) {
328
- foreach ( $post_views as $id => $views ) {
329
- // generate chart data for specific post types
330
- $data['data']['datasets'][$post_type_id]['data'][] = $views;
331
-
332
- if ( ! array_key_exists( $id, $sum ) )
333
- $sum[$id] = 0;
334
-
335
- $sum[$id] += $views;
336
- }
337
- }
338
-
339
- // this month all days
340
- for ( $i = 1; $i <= $date[2]; $i ++ ) {
341
- // generate chart data
342
- $data['data']['labels'][] = ( $i % 2 === 0 ? '' : $i );
343
- $data['data']['dates'][] = date_i18n( get_option( 'date_format' ), strtotime( $date[1] . '-' . $date[0] . '-' . str_pad( $i, 2, '0', STR_PAD_LEFT ) ) );
344
- $data['data']['datasets'][0]['data'][] = $sum[$i - 1];
345
- }
346
- break;
347
- }
348
-
349
- echo json_encode( $data );
350
-
351
- exit;
352
- }
353
-
354
- /**
355
- * Get user dashboard data.
356
- *
357
- * @param string $data_type
358
- * @return array
359
- */
360
- public function get_dashboard_user_data( $user_id, $data_type ) {
361
- $userdata = get_user_meta( $user_id, 'pvc_dashboard', true );
362
-
363
- if ( ! is_array( $userdata ) || empty( $userdata ) )
364
- $userdata = array();
365
-
366
- if ( ! array_key_exists( $data_type, $userdata ) || ! is_array( $userdata[$data_type] ) )
367
- $userdata[$data_type] = array();
368
-
369
- return $userdata[$data_type];
370
- }
371
-
372
- /**
373
- * Enqueue admin scripts and styles.
374
- *
375
- * @param string $pagenow
376
- */
377
- public function admin_scripts_styles( $pagenow ) {
378
- if ( $pagenow != 'index.php' )
379
- return;
380
-
381
- // filter user_can_see_stats
382
- if ( ! apply_filters( 'pvc_user_can_see_stats', current_user_can( 'publish_posts' ) ) )
383
- return;
384
-
385
- wp_register_style( 'pvc-admin-dashboard', POST_VIEWS_COUNTER_URL . '/css/admin-dashboard.css' );
386
- wp_enqueue_style( 'pvc-admin-dashboard' );
387
- wp_enqueue_style( 'pvc-chart-css', POST_VIEWS_COUNTER_URL . '/assets/chartjs/chart.min.css' );
388
-
389
- wp_register_script( 'pvc-chart', POST_VIEWS_COUNTER_URL . '/assets/chartjs/chart.min.js', array( 'jquery' ), Post_Views_Counter()->defaults['version'], true );
390
- wp_register_script( 'pvc-admin-dashboard', POST_VIEWS_COUNTER_URL . '/js/admin-dashboard.js', array( 'jquery', 'pvc-chart' ), Post_Views_Counter()->defaults['version'], true );
391
-
392
- wp_enqueue_script( 'pvc-admin-dashboard' );
393
-
394
- wp_localize_script(
395
- 'pvc-admin-dashboard',
396
- 'pvcArgs',
397
- array(
398
- 'ajaxURL' => admin_url( 'admin-ajax.php' ),
399
- 'nonce' => wp_create_nonce( 'dashboard-chart' ),
400
- 'nonceUser' => wp_create_nonce( 'dashboard-chart-user-post-types' )
401
- )
402
- );
403
- }
404
-
405
- /**
406
- * Convert hex to rgb color.
407
- *
408
- * @param type $color
409
- * @return boolean
410
- */
411
- public function hex2rgb( $color ) {
412
- if ( $color[0] == '#' ) {
413
- $color = substr( $color, 1 );
414
- }
415
- if ( strlen( $color ) == 6 ) {
416
- list( $r, $g, $b ) = array( $color[0] . $color[1], $color[2] . $color[3], $color[4] . $color[5] );
417
- } elseif ( strlen( $color ) == 3 ) {
418
- list( $r, $g, $b ) = array( $color[0] . $color[0], $color[1] . $color[1], $color[2] . $color[2] );
419
- } else {
420
- return false;
421
- }
422
- $r = hexdec( $r );
423
- $g = hexdec( $g );
424
- $b = hexdec( $b );
425
- return array( 'r' => $r, 'g' => $g, 'b' => $b );
426
- }
427
-
428
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/frontend.php DELETED
@@ -1,208 +0,0 @@
1
- <?php
2
- // exit if accessed directly
3
- if ( ! defined( 'ABSPATH' ) )
4
- exit;
5
-
6
- /**
7
- * Post_Views_Counter_Frontend class.
8
- *
9
- * @class Post_Views_Counter_Frontend
10
- */
11
- class Post_Views_Counter_Frontend {
12
-
13
- public function __construct() {
14
- // actions
15
- add_action( 'after_setup_theme', array( $this, 'register_shortcode' ) );
16
- add_action( 'wp_enqueue_scripts', array( $this, 'wp_enqueue_scripts' ) );
17
- add_action( 'wp', array( $this, 'run' ) );
18
- }
19
-
20
- /**
21
- * Register post-views shortcode function.
22
- */
23
- public function register_shortcode() {
24
- add_shortcode( 'post-views', array( $this, 'post_views_shortcode' ) );
25
- }
26
-
27
- /**
28
- * Post views shortcode function.
29
- *
30
- * @param array $args
31
- * @return mixed
32
- */
33
- public function post_views_shortcode( $args ) {
34
- $defaults = array(
35
- 'id' => get_the_ID()
36
- );
37
-
38
- $args = shortcode_atts( $defaults, $args );
39
-
40
- return pvc_post_views( $args['id'], false );
41
- }
42
-
43
- /**
44
- * Set up plugin hooks.
45
- */
46
- public function run() {
47
- if ( is_admin() && ! ( defined( 'DOING_AJAX' ) && DOING_AJAX ) )
48
- return;
49
-
50
- $filter = apply_filters( 'pvc_shortcode_filter_hook', Post_Views_Counter()->options['display']['position'] );
51
-
52
- if ( ! empty( $filter ) && in_array( $filter, array( 'before', 'after' ) ) ) {
53
- // post content
54
- add_filter( 'the_content', array( $this, 'add_post_views_count' ) );
55
-
56
- // bbpress support
57
- add_action( 'bbp_template_' . $filter . '_single_topic', array( $this, 'display_bbpress_post_views' ) );
58
- add_action( 'bbp_template_' . $filter . '_single_forum', array( $this, 'display_bbpress_post_views' ) );
59
- } else {
60
- // custom
61
- if ( $filter != 'manual' && is_string( $filter ) )
62
- add_filter( $filter, array( $this, 'add_post_views_count' ) );
63
- }
64
- }
65
-
66
- /**
67
- * Add post views counter to forum/topic of bbPress.
68
- *
69
- * @return string
70
- */
71
- public function display_bbpress_post_views() {
72
- $post_id = get_the_ID();
73
-
74
- // check only for forums and topics
75
- if ( bbp_is_forum( $post_id ) || bbp_is_topic( $post_id ) )
76
- echo $this->add_post_views_count( '' );
77
- }
78
-
79
- /**
80
- * Add post views counter to content.
81
- *
82
- * @param string $content
83
- * @return mixed
84
- */
85
- public function add_post_views_count( $content = '' ) {
86
- $display = false;
87
-
88
- // get post types
89
- $post_types = Post_Views_Counter()->options['display']['post_types_display'];
90
-
91
- // get pages
92
- $pages = Post_Views_Counter()->options['display']['page_types_display'];
93
-
94
- // page visibility check
95
- if ( $pages ) {
96
- foreach ( $pages as $page ) {
97
- switch ( $page ) {
98
- case 'singular':
99
- if ( is_singular( $post_types ) )
100
- $display = true;
101
- break;
102
-
103
- case 'archive':
104
- if ( is_archive() )
105
- $display = true;
106
- break;
107
-
108
- case 'search':
109
- if ( is_search() )
110
- $display = true;
111
- break;
112
-
113
- case 'home':
114
- if ( is_home() || is_front_page() )
115
- $display = true;
116
- break;
117
- }
118
- }
119
- }
120
-
121
- // get groups to check it faster
122
- $groups = Post_Views_Counter()->options['display']['restrict_display']['groups'];
123
-
124
- // whether to display views
125
- if ( is_user_logged_in() ) {
126
- // exclude logged in users?
127
- if ( in_array( 'users', $groups, true ) )
128
- $display = false;
129
- // exclude specific roles?
130
- elseif ( in_array( 'roles', $groups, true ) && Post_Views_Counter()->counter->is_user_role_excluded( get_current_user_id(), Post_Views_Counter()->options['display']['restrict_display']['roles'] ) )
131
- $display = false;
132
- // exclude guests?
133
- } elseif ( in_array( 'guests', $groups, true ) )
134
- $display = false;
135
-
136
- // we don't want to mess custom loops
137
- if ( ! in_the_loop() && ! class_exists( 'bbPress' ) )
138
- $display = false;
139
-
140
- if ( apply_filters( 'pvc_display_views_count', $display ) === true ) {
141
- $filter = apply_filters( 'pvc_shortcode_filter_hook', Post_Views_Counter()->options['display']['position'] );
142
-
143
- switch ( $filter ) {
144
- case 'after':
145
- $content = $content . do_shortcode( '[post-views]' );
146
- break;
147
-
148
- case 'before':
149
- $content = do_shortcode( '[post-views]' ) . $content;
150
- break;
151
-
152
- case 'manual':
153
- default:
154
- break;
155
- }
156
- }
157
-
158
- return $content;
159
- }
160
-
161
- /**
162
- * Enqueue frontend scripts and styles.
163
- */
164
- public function wp_enqueue_scripts() {
165
- $mode = Post_Views_Counter()->options['general']['counter_mode'];
166
- $post_types = Post_Views_Counter()->options['general']['post_types_count'];
167
-
168
- if ( (bool) apply_filters( 'pvc_enqueue_styles', true ) === true ) {
169
- // load dashicons
170
- wp_enqueue_style( 'dashicons' );
171
-
172
- // load style
173
- wp_enqueue_style( 'post-views-counter-frontend', POST_VIEWS_COUNTER_URL . '/css/frontend.css', array(), Post_Views_Counter()->defaults['version'] );
174
- }
175
-
176
- if ( in_array( $mode, array( 'js', 'ajax', 'rest_api' ) ) ) {
177
- // whether to count this post type or not
178
- if ( empty( $post_types ) || ! is_singular( $post_types ) )
179
- return;
180
-
181
- wp_register_script( 'post-views-counter-frontend', POST_VIEWS_COUNTER_URL . '/js/frontend.js', array( 'jquery' ), Post_Views_Counter()->defaults['version'], true );
182
- wp_enqueue_script( 'post-views-counter-frontend' );
183
-
184
- $js_args = array(
185
- 'mode' => $mode,
186
- 'requestURL' => esc_url_raw( $mode == 'rest_api' ? rest_url( 'post-views-counter/view-post/') : admin_url( 'admin-ajax.php' ) ),
187
- 'postID' => get_the_ID(),
188
- 'nonce' => ( $mode == 'rest_api' ? wp_create_nonce( 'wp_rest' ) : wp_create_nonce( 'pvc-check-post' ) )
189
- );
190
-
191
- switch ( $mode ) {
192
- case 'rest_api':
193
- $js_args['requestURL'] = rest_url( 'post-views-counter/view-post/' );
194
- break;
195
-
196
- case 'ajax':
197
- $js_args['requestURL'] = POST_VIEWS_COUNTER_URL . '/includes/ajax.php';
198
- break;
199
-
200
- default:
201
- $js_args['requestURL'] = admin_url( 'admin-ajax.php' );
202
- break;
203
- }
204
-
205
- wp_localize_script( 'post-views-counter-frontend', 'pvcArgsFrontend', apply_filters( 'pvc_frontend_script_args', $js_args ) );
206
- }
207
- }
208
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/query.php DELETED
@@ -1,374 +0,0 @@
1
- <?php
2
- // exit if accessed directly
3
- if ( ! defined( 'ABSPATH' ) )
4
- exit;
5
-
6
- /**
7
- * Post_Views_Counter_Query class.
8
- *
9
- * @class Post_Views_Counter_Query
10
- */
11
- class Post_Views_Counter_Query {
12
-
13
- public function __construct() {
14
- // actions
15
- add_action( 'pre_get_posts', array( $this, 'extend_pre_query' ), 1 );
16
-
17
- // filters
18
- add_filter( 'query_vars', array( $this, 'query_vars' ) );
19
- add_filter( 'posts_join', array( $this, 'posts_join' ), 10, 2 );
20
- add_filter( 'posts_groupby', array( $this, 'posts_groupby' ), 10, 2 );
21
- add_filter( 'posts_orderby', array( $this, 'posts_orderby' ), 10, 2 );
22
- add_filter( 'posts_fields', array( $this, 'posts_fields' ), 10, 2 );
23
- add_filter( 'the_posts', array( $this, 'the_posts' ), 10, 2 );
24
- }
25
-
26
- /**
27
- * Register views_query var.
28
- *
29
- * @param array $query_vars
30
- * @return array
31
- */
32
- public function query_vars( $query_vars ) {
33
- $query_vars[] = 'views_query';
34
-
35
- return $query_vars;
36
- }
37
-
38
- /**
39
- * Extend query with post_views orderby parameter.
40
- *
41
- * @param object $query
42
- */
43
- public function extend_pre_query( $query ) {
44
- if ( isset( $query->query_vars['orderby'] ) && $query->query_vars['orderby'] === 'post_views' )
45
- $query->pvc_orderby = true;
46
- }
47
-
48
- /**
49
- * Modify the db query to use post_views parameter.
50
- *
51
- * @global object $wpdb
52
- * @param string $join
53
- * @param object $query
54
- * @return string
55
- */
56
- public function posts_join( $join, $query ) {
57
- $sql = '';
58
- $query_chunks = array();
59
-
60
- // views query?
61
- if ( ! empty( $query->query['views_query'] ) ) {
62
- if ( isset( $query->query['views_query']['inclusive'] ) )
63
- $query->query['views_query']['inclusive'] = (bool) $query->query['views_query']['inclusive'];
64
- else
65
- $query->query['views_query']['inclusive'] = true;
66
-
67
- // check after and before dates
68
- foreach ( array( 'after' => '>', 'before' => '<' ) as $date => $type ) {
69
- $year_ = null;
70
- $month_ = null;
71
- $week_ = null;
72
- $day_ = null;
73
-
74
- // check views query date
75
- if ( ! empty( $query->query['views_query'][$date] ) ) {
76
- // is it a date array?
77
- if ( is_array( $query->query['views_query'][$date] ) ) {
78
- // check views query $date date year
79
- if ( ! empty( $query->query['views_query'][$date]['year'] ) )
80
- $year_ = str_pad( (int) $query->query['views_query'][$date]['year'], 4, 0, STR_PAD_LEFT );
81
-
82
- // check views query date month
83
- if ( ! empty( $query->query['views_query'][$date]['month'] ) )
84
- $month_ = str_pad( (int) $query->query['views_query'][$date]['month'], 2, 0, STR_PAD_LEFT );
85
-
86
- // check views query date week
87
- if ( ! empty( $query->query['views_query'][$date]['week'] ) )
88
- $week_ = str_pad( (int) $query->query['views_query'][$date]['week'], 2, 0, STR_PAD_LEFT );
89
-
90
- // check views query date day
91
- if ( ! empty( $query->query['views_query'][$date]['day'] ) )
92
- $day_ = str_pad( (int) $query->query['views_query'][$date]['day'], 2, 0, STR_PAD_LEFT );
93
- // is it a date string?
94
- } elseif ( is_string( $query->query['views_query'][$date] ) ) {
95
- $time_ = strtotime( $query->query['views_query'][$date] );
96
-
97
- // valid datetime?
98
- if ( $time_ !== false ) {
99
- // week does not exists here, string dates are always treated as year + month + day
100
- list( $day_, $month_, $year_ ) = explode( ' ', date( "d m Y", $time_ ) );
101
- }
102
- }
103
-
104
- // valid date?
105
- if ( ! ( $year_ === null && $month_ === null && $week_ === null && $day_ === null ) ) {
106
- $query_chunks[] = array(
107
- 'year' => $year_,
108
- 'month' => $month_,
109
- 'day' => $day_,
110
- 'week' => $week_,
111
- 'type' => $type . ( $query->query['views_query']['inclusive'] ? '=' : '' )
112
- );
113
- }
114
- }
115
- }
116
-
117
- // any after, before query chunks?
118
- if ( ! empty( $query_chunks ) ) {
119
- $valid_dates = true;
120
-
121
- // check only if both dates are in query
122
- if ( count( $query_chunks ) === 2 ) {
123
- // before and after dates should be the same
124
- foreach ( array( 'year', 'month', 'day', 'week' ) as $date_type ) {
125
- if ( ! ( ( $query_chunks[0][$date_type] !== null && $query_chunks[1][$date_type] !== null ) || ( $query_chunks[0][$date_type] === null && $query_chunks[1][$date_type] === null ) ) )
126
- $valid_dates = false;
127
- }
128
- }
129
-
130
- // after and before dates should be
131
- if ( $valid_dates ) {
132
- foreach ( $query_chunks as $chunk ) {
133
- // year
134
- if ( isset( $chunk['year'] ) ) {
135
- // year, week
136
- if ( isset( $chunk['week'] ) )
137
- $sql .= " AND pvc.type = 1 AND pvc.period " . $chunk['type'] . " '" . $chunk['year'] . $chunk['week'] . "'";
138
- // year, month
139
- elseif ( isset( $chunk['month'] ) ) {
140
- // year, month, day
141
- if ( isset( $chunk['day'] ) )
142
- $sql .= " AND pvc.type = 0 AND pvc.period " . $chunk['type'] . " '" . $chunk['year'] . $chunk['month'] . $chunk['day'] . "'";
143
- // year, month
144
- else
145
- $sql .= " AND pvc.type = 2 AND pvc.period " . $chunk['type'] . " '" . $chunk['year'] . $chunk['month'] . "'";
146
- // year
147
- } else
148
- $sql .= " AND pvc.type = 3 AND pvc.period " . $chunk['type'] . " '" . $chunk['year'] . "'";
149
- // month
150
- } elseif ( isset( $chunk['month'] ) ) {
151
- // month, day
152
- if ( isset( $chunk['day'] ) )
153
- $sql .= " AND pvc.type = 0 AND RIGHT( pvc.period, 4 ) " . $chunk['type'] . " '" . $chunk['month'] . $chunk['day'] . "'";
154
- // month
155
- else
156
- $sql .= " AND pvc.type = 2 AND RIGHT( pvc.period, 2 ) " . $chunk['type'] . " '" . $chunk['month'] . "'";
157
- // week
158
- } elseif ( isset( $chunk['week'] ) )
159
- $sql .= " AND pvc.type = 1 AND RIGHT( pvc.period, 2 ) " . $chunk['type'] . " '" . $chunk['week'] . "'";
160
- // day
161
- elseif ( isset( $chunk['day'] ) )
162
- $sql .= " AND pvc.type = 0 AND RIGHT( pvc.period, 2 ) " . $chunk['type'] . " '" . $chunk['day'] . "'";
163
- }
164
- }
165
- }
166
-
167
- // standard query
168
- if ( $sql === '' ) {
169
- // check year
170
- if ( isset( $query->query['views_query']['year'] ) )
171
- $year = (int) $query->query['views_query']['year'];
172
-
173
- // check month
174
- if ( isset( $query->query['views_query']['month'] ) )
175
- $month = (int) $query->query['views_query']['month'];
176
-
177
- // check week
178
- if ( isset( $query->query['views_query']['week'] ) )
179
- $week = (int) $query->query['views_query']['week'];
180
-
181
- // check day
182
- if ( isset( $query->query['views_query']['day'] ) )
183
- $day = (int) $query->query['views_query']['day'];
184
-
185
- // year
186
- if ( isset( $year ) ) {
187
- // year, week
188
- if ( isset( $week ) && $this->is_valid_date( 'yw', $year, 0, 0, $week ) )
189
- $sql = " AND pvc.type = 1 AND pvc.period = '" . str_pad( $year, 4, 0, STR_PAD_LEFT ) . str_pad( $week, 2, 0, STR_PAD_LEFT ) . "'";
190
- // year, month
191
- elseif ( isset( $month ) ) {
192
- // year, month, day
193
- if ( isset( $day ) && $this->is_valid_date( 'ymd', $year, $month, $day ) )
194
- $sql = " AND pvc.type = 0 AND pvc.period = '" . str_pad( $year, 4, 0, STR_PAD_LEFT ) . str_pad( $month, 2, 0, STR_PAD_LEFT ) . str_pad( $day, 2, 0, STR_PAD_LEFT ) . "'";
195
- // year, month
196
- elseif ( $this->is_valid_date( 'ym', $year, $month ) )
197
- $sql = " AND pvc.type = 2 AND pvc.period = '" . str_pad( $year, 4, 0, STR_PAD_LEFT ) . str_pad( $month, 2, 0, STR_PAD_LEFT ) . "'";
198
- // year
199
- } elseif ( $this->is_valid_date( 'y', $year ) )
200
- $sql = " AND pvc.type = 3 AND pvc.period = '" . str_pad( $year, 4, 0, STR_PAD_LEFT ) . "'";
201
- // month
202
- } elseif ( isset( $month ) ) {
203
- // month, day
204
- if ( isset( $day ) && $this->is_valid_date( 'md', 0, $month, $day ) ) {
205
- $sql = " AND pvc.type = 0 AND RIGHT( pvc.period, 4 ) = '" . str_pad( $month, 2, 0, STR_PAD_LEFT ) . str_pad( $day, 2, 0, STR_PAD_LEFT ) . "'";
206
- // month
207
- } elseif ( $this->is_valid_date( 'm', 0, $month ) )
208
- $sql = " AND pvc.type = 2 AND RIGHT( pvc.period, 2 ) = '" . str_pad( $month, 2, 0, STR_PAD_LEFT ) . "'";
209
- // week
210
- } elseif ( isset( $week ) && $this->is_valid_date( 'w', 0, 0, 0, $week ) )
211
- $sql = " AND pvc.type = 1 AND RIGHT( pvc.period, 2 ) = '" . str_pad( $week, 2, 0, STR_PAD_LEFT ) . "'";
212
- // day
213
- elseif ( isset( $day ) && $this->is_valid_date( 'd', 0, 0, $day ) )
214
- $sql = " AND pvc.type = 0 AND RIGHT( pvc.period, 2 ) = '" . str_pad( $day, 2, 0, STR_PAD_LEFT ) . "'";
215
- }
216
-
217
- if ( $sql !== '' )
218
- $query->pvc_query = true;
219
- }
220
-
221
- // is it sorted by post views?
222
- if ( ( $sql === '' && isset( $query->pvc_orderby ) && $query->pvc_orderby ) || apply_filters( 'pvc_extend_post_object', false, $query ) === true )
223
- $sql = ' AND pvc.type = 4';
224
-
225
- // add date range
226
- if ( $sql !== '' ) {
227
- global $wpdb;
228
-
229
- $join .= " LEFT JOIN " . $wpdb->prefix . "post_views pvc ON pvc.id = " . $wpdb->prefix . "posts.ID" . $sql;
230
- }
231
-
232
- return $join;
233
- }
234
-
235
- /**
236
- * Group posts using the post ID.
237
- *
238
- * @global object $wpdb
239
- * @param string $groupby
240
- * @param object $query
241
- * @return string
242
- */
243
- public function posts_groupby( $groupby, $query ) {
244
- // is it sorted by post views or views_query is used?
245
- if ( ( isset( $query->pvc_orderby ) && $query->pvc_orderby ) || ( isset( $query->pvc_query ) && $query->pvc_query ) || apply_filters( 'pvc_extend_post_object', false, $query ) === true ) {
246
- global $pagenow;
247
-
248
- // needed only for sorting
249
- if ( $pagenow === 'upload.php' || $pagenow === 'edit.php' )
250
- $query->query['views_query']['hide_empty'] = false;
251
-
252
- global $wpdb;
253
-
254
- $groupby = trim( $groupby );
255
-
256
- if ( strpos( $groupby, $wpdb->prefix . 'posts.ID' ) === false )
257
- $groupby = ( $groupby !== '' ? $groupby . ', ' : '') . $wpdb->prefix . 'posts.ID';
258
-
259
- if ( ! isset( $query->query['views_query']['hide_empty'] ) || $query->query['views_query']['hide_empty'] === true )
260
- $groupby .= ' HAVING post_views > 0';
261
- }
262
-
263
- return $groupby;
264
- }
265
-
266
- /**
267
- * Order posts by post views.
268
- *
269
- * @global object $wpdb
270
- * @param string $orderby
271
- * @param object $query
272
- * @return string
273
- */
274
- public function posts_orderby( $orderby, $query ) {
275
- // is it sorted by post views?
276
- if ( ( isset( $query->pvc_orderby ) && $query->pvc_orderby ) ) {
277
- global $wpdb;
278
-
279
- $order = $query->get( 'order' );
280
- $orderby = ( ! isset( $query->query['views_query']['hide_empty'] ) || $query->query['views_query']['hide_empty'] === true ? 'post_views' : 'pvc.count' ) . ' ' . $order . ', ' . $wpdb->prefix . 'posts.ID ' . $order;
281
- }
282
-
283
- return $orderby;
284
- }
285
-
286
- /**
287
- * Return post views in queried post objects.
288
- *
289
- * @param string $fields
290
- * @param object $query
291
- * @return string
292
- */
293
- public function posts_fields( $fields, $query ) {
294
- if ( ( ! isset( $query->query['fields'] ) || $query->query['fields'] === '' ) && ( ( isset( $query->pvc_orderby ) && $query->pvc_orderby ) || ( isset( $query->pvc_query ) && $query->pvc_query ) || apply_filters( 'pvc_extend_post_object', false, $query ) === true ) )
295
- $fields = $fields . ', SUM( IFNULL( pvc.count, 0 ) ) AS post_views';
296
-
297
- return $fields;
298
- }
299
-
300
- /**
301
- * Extend query object with total post views.
302
- *
303
- * @param array $posts
304
- * @param object $query
305
- * @return array
306
- */
307
- public function the_posts( $posts, $query ) {
308
- if ( ( isset( $query->pvc_orderby ) && $query->pvc_orderby ) || ( isset( $query->pvc_query ) && $query->pvc_query ) || apply_filters( 'pvc_extend_post_object', false, $query ) === true ) {
309
- $sum = 0;
310
-
311
- // any posts found?
312
- if ( ! empty( $posts ) ) {
313
- foreach ( $posts as $post ) {
314
- if ( ! empty( $post->post_views ) )
315
- $sum += (int) $post->post_views;
316
- }
317
- }
318
-
319
- // pass total views
320
- $query->total_views = $sum;
321
- }
322
-
323
- return $posts;
324
- }
325
-
326
- /**
327
- * Validate date helper function.
328
- *
329
- * @param string $type
330
- * @param int $year
331
- * @param int $month
332
- * @param int $day
333
- * @param int $week
334
- * @return bool
335
- */
336
- private function is_valid_date( $type, $year = 0, $month = 0, $day = 0, $week = 0 ) {
337
- switch ( $type ) {
338
- case 'y':
339
- $bool = ( $year >= 1 && $year <= 32767 );
340
- break;
341
-
342
- case 'yw':
343
- $bool = ( $year >= 1 && $year <= 32767 && $week >= 0 && $week <= 53 );
344
- break;
345
-
346
- case 'ym':
347
- $bool = ( $year >= 1 && $year <= 32767 && $month >= 1 && $month <= 12 );
348
- break;
349
-
350
- case 'ymd':
351
- $bool = checkdate( $month, $day, $year );
352
- break;
353
-
354
- case 'm':
355
- $bool = ( $month >= 1 && $month <= 12 );
356
- break;
357
-
358
- case 'md':
359
- $bool = ( $month >= 1 && $month <= 12 && $day >= 1 && $day <= 31 );
360
- break;
361
-
362
- case 'w':
363
- $bool = ( $week >= 0 && $week <= 53 );
364
- break;
365
-
366
- case 'd':
367
- $bool = ( $day >= 1 && $day <= 31 );
368
- break;
369
- }
370
-
371
- return $bool;
372
- }
373
-
374
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/settings.php DELETED
@@ -1,816 +0,0 @@
1
- <?php
2
- // exit if accessed directly
3
- if ( ! defined( 'ABSPATH' ) )
4
- exit;
5
-
6
- /**
7
- * Post_Views_Counter_Settings class.
8
- *
9
- * @class Post_Views_Counter_Settings
10
- */
11
- class Post_Views_Counter_Settings {
12
-
13
- private $tabs;
14
- private $choices;
15
- private $modes;
16
- private $time_types;
17
- private $groups;
18
- private $user_roles;
19
- private $positions;
20
- private $display_styles;
21
- public $post_types;
22
- public $page_types;
23
-
24
- public function __construct() {
25
- // actions
26
- add_action( 'admin_init', array( $this, 'register_settings' ) );
27
- add_action( 'admin_menu', array( $this, 'admin_menu_options' ) );
28
- add_action( 'after_setup_theme', array( $this, 'load_defaults' ) );
29
- add_action( 'wp_loaded', array( $this, 'load_post_types' ) );
30
- }
31
-
32
- /**
33
- * Load default settings.
34
- */
35
- public function load_defaults() {
36
- if ( ! is_admin() )
37
- return;
38
-
39
- $this->modes = array(
40
- 'php' => __( 'PHP', 'post-views-counter' ),
41
- 'js' => __( 'JavaScript', 'post-views-counter' ),
42
- 'ajax' => __( 'Fast AJAX', 'post-views-counter' )
43
- );
44
-
45
- if ( function_exists( 'register_rest_route' ) )
46
- $this->modes['rest_api'] = __( 'REST API', 'post-views-counter' );
47
-
48
- $this->time_types = array(
49
- 'minutes' => __( 'minutes', 'post-views-counter' ),
50
- 'hours' => __( 'hours', 'post-views-counter' ),
51
- 'days' => __( 'days', 'post-views-counter' ),
52
- 'weeks' => __( 'weeks', 'post-views-counter' ),
53
- 'months' => __( 'months', 'post-views-counter' ),
54
- 'years' => __( 'years', 'post-views-counter' )
55
- );
56
-
57
- $this->groups = array(
58
- 'robots' => __( 'robots', 'post-views-counter' ),
59
- 'users' => __( 'logged in users', 'post-views-counter' ),
60
- 'guests' => __( 'guests', 'post-views-counter' ),
61
- 'roles' => __( 'selected user roles', 'post-views-counter' )
62
- );
63
-
64
- $this->positions = array(
65
- 'before' => __( 'before the content', 'post-views-counter' ),
66
- 'after' => __( 'after the content', 'post-views-counter' ),
67
- 'manual' => __( 'manual', 'post-views-counter' )
68
- );
69
-
70
- $this->display_styles = array(
71
- 'icon' => __( 'icon', 'post-views-counter' ),
72
- 'text' => __( 'label', 'post-views-counter' )
73
- );
74
-
75
- $this->tabs = array(
76
- 'general' => array(
77
- 'name' => __( 'General', 'post-views-counter' ),
78
- 'key' => 'post_views_counter_settings_general',
79
- 'submit' => 'save_pvc_general',
80
- 'reset' => 'reset_pvc_general'
81
- ),
82
- 'display' => array(
83
- 'name' => __( 'Display', 'post-views-counter' ),
84
- 'key' => 'post_views_counter_settings_display',
85
- 'submit' => 'save_pvc_display',
86
- 'reset' => 'reset_pvc_display'
87
- )
88
- );
89
-
90
- $this->user_roles = $this->get_user_roles();
91
-
92
- $this->page_types = apply_filters(
93
- 'pvc_page_types_display_options',
94
- array(
95
- 'home' => __( 'Home', 'post-views-counter' ),
96
- 'archive' => __( 'Archives', 'post-views-counter' ),
97
- 'singular' => __( 'Single pages', 'post-views-counter' ),
98
- 'search' => __( 'Search results', 'post-views-counter' ),
99
- )
100
- );
101
- }
102
-
103
- /**
104
- * Get post types avaiable for counting.
105
- */
106
- public function load_post_types() {
107
- if ( ! is_admin() )
108
- return;
109
-
110
- $post_types = array();
111
-
112
- // built in public post types
113
- foreach ( get_post_types( array( '_builtin' => true, 'public' => true ), 'objects', 'and' ) as $key => $post_type ) {
114
- $post_types[$key] = $post_type->labels->name;
115
- }
116
-
117
- // public custom post types
118
- foreach ( get_post_types( array( '_builtin' => false, 'public' => true ), 'objects', 'and' ) as $key => $post_type ) {
119
- $post_types[$key] = $post_type->labels->name;
120
- }
121
-
122
- // remove bbPress replies
123
- if ( class_exists( 'bbPress' ) && isset( $post_types['reply'] ) )
124
- unset( $post_types['reply'] );
125
-
126
- $post_types = apply_filters( 'pvc_available_post_types', $post_types );
127
-
128
- // sort post types alphabetically with their keys
129
- asort( $post_types, SORT_STRING );
130
-
131
- $this->post_types = $post_types;
132
- }
133
-
134
- /**
135
- * Get all user roles.
136
- *
137
- * @global object $wp_roles
138
- * @return array
139
- */
140
- public function get_user_roles() {
141
- global $wp_roles;
142
-
143
- $roles = array();
144
-
145
- foreach ( apply_filters( 'editable_roles', $wp_roles->roles ) as $role => $details ) {
146
- $roles[$role] = translate_user_role( $details['name'] );
147
- }
148
-
149
- asort( $roles, SORT_STRING );
150
-
151
- return $roles;
152
- }
153
-
154
- /**
155
- * Add options page.
156
- *
157
- * @return void
158
- */
159
- public function admin_menu_options() {
160
- add_options_page( __( 'Post Views Counter', 'post-views-counter' ), __( 'Post Views Counter', 'post-views-counter' ), 'manage_options', 'post-views-counter', array( $this, 'options_page' ) );
161
- }
162
-
163
- /**
164
- * Options page callback.
165
- *
166
- * @return void
167
- */
168
- public function options_page() {
169
- $tab_key = (isset( $_GET['tab'] ) ? esc_attr( $_GET['tab'] ) : 'general');
170
-
171
- echo '
172
- <div class="wrap">
173
- <h2>' . __( 'Post Views Counter', 'post-views-counter' ) . '</h2>
174
- <h2 class="nav-tab-wrapper">';
175
-
176
- foreach ( $this->tabs as $key => $name ) {
177
- echo '
178
- <a class="nav-tab ' . ($tab_key == $key ? 'nav-tab-active' : '') . '" href="' . esc_url( admin_url( 'options-general.php?page=post-views-counter&tab=' . $key ) ) . '">' . $name['name'] . '</a>';
179
- }
180
-
181
- echo '
182
- </h2>
183
- <div class="post-views-counter-settings">
184
- <div class="df-credits">
185
- <h3 class="hndle">' . __( 'Post Views Counter', 'post-views-counter' ) . ' ' . Post_Views_Counter()->defaults['version'] . '</h3>
186
- <div class="inside">
187
- <h4 class="inner">' . __( 'Need support?', 'post-views-counter' ) . '</h4>
188
- <p class="inner">' . sprintf( __( 'If you are having problems with this plugin, please browse it\'s <a href="%s" target="_blank">Documentation</a> or talk about them in the <a href="%s" target="_blank">Support forum</a>', 'post-views-counter' ), 'https://www.dfactory.eu/docs/post-views-counter/?utm_source=post-views-counter-settings&utm_medium=link&utm_campaign=docs', 'https://www.dfactory.eu/support/?utm_source=post-views-counter-settings&utm_medium=link&utm_campaign=support' ) . '</p>
189
- <hr />
190
- <h4 class="inner">' . __( 'Do you like this plugin?', 'post-views-counter' ) . '</h4>
191
- <p class="inner">' . sprintf( __( '<a href="%s" target="_blank">Rate it 5</a> on WordPress.org', 'post-views-counter' ), 'https://wordpress.org/support/plugin/post-views-counter/reviews/?filter=5' ) . '<br />' .
192
- sprintf( __( 'Blog about it & link to the <a href="%s" target="_blank">plugin page</a>.', 'post-views-counter' ), 'https://dfactory.eu/plugins/post-views-counter/?utm_source=post-views-counter-settings&utm_medium=link&utm_campaign=blog-about' ) . '<br />' .
193
- sprintf( __( 'Check out our other <a href="%s" target="_blank">WordPress plugins</a>.', 'post-views-counter' ), 'https://dfactory.eu/plugins/?utm_source=post-views-counter-settings&utm_medium=link&utm_campaign=other-plugins' ) . '
194
- </p>
195
- <hr />
196
- <p class="df-link inner"><a href="http://www.dfactory.eu/?utm_source=post-views-counter-settings&utm_medium=link&utm_campaign=created-by" target="_blank" title="Digital Factory"><img src="//pvc-53eb.kxcdn.com/df-black-sm.png' . '" alt="Digital Factory" /></a></p>
197
- </div>
198
- </div>
199
- <form action="options.php" method="post">';
200
-
201
- wp_nonce_field( 'update-options' );
202
- settings_fields( $this->tabs[$tab_key]['key'] );
203
- do_settings_sections( $this->tabs[$tab_key]['key'] );
204
-
205
- echo '
206
- <p class="submit">';
207
-
208
- submit_button( '', 'primary', $this->tabs[$tab_key]['submit'], false );
209
-
210
- echo ' ';
211
-
212
- submit_button( __( 'Reset to defaults', 'post-views-counter' ), 'secondary reset_pvc_settings', $this->tabs[$tab_key]['reset'], false );
213
-
214
- echo '
215
- </p>
216
- </form>
217
- </div>
218
- <div class="clear"></div>
219
- </div>';
220
- }
221
-
222
- /**
223
- * Register settings callback.
224
- */
225
- public function register_settings() {
226
- // general options
227
- register_setting( 'post_views_counter_settings_general', 'post_views_counter_settings_general', array( $this, 'validate_settings' ) );
228
- add_settings_section( 'post_views_counter_settings_general', __( 'General settings', 'post-views-counter' ), '', 'post_views_counter_settings_general' );
229
- add_settings_field( 'pvc_post_types_count', __( 'Post Types Count', 'post-views-counter' ), array( $this, 'post_types_count' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
230
- add_settings_field( 'pvc_counter_mode', __( 'Counter Mode', 'post-views-counter' ), array( $this, 'counter_mode' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
231
- add_settings_field( 'pvc_post_views_column', __( 'Post Views Column', 'post-views-counter' ), array( $this, 'post_views_column' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
232
- add_settings_field( 'pvc_restrict_edit_views', __( 'Restrict Edit', 'post-views-counter' ), array( $this, 'restrict_edit_views' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
233
- add_settings_field( 'pvc_time_between_counts', __( 'Count Interval', 'post-views-counter' ), array( $this, 'time_between_counts' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
234
- add_settings_field( 'pvc_reset_counts', __( 'Reset Data Interval', 'post-views-counter' ), array( $this, 'reset_counts' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
235
- add_settings_field( 'pvc_flush_interval', __( 'Flush Object Cache Interval', 'post-views-counter' ), array( $this, 'flush_interval' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
236
- add_settings_field( 'pvc_exclude', __( 'Exclude Visitors', 'post-views-counter' ), array( $this, 'exclude' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
237
- add_settings_field( 'pvc_exclude_ips', __( 'Exclude IPs', 'post-views-counter' ), array( $this, 'exclude_ips' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
238
- add_settings_field( 'pvc_strict_counts', __( 'Strict counts', 'post-views-counter' ), array( $this, 'strict_counts' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
239
- add_settings_field( 'pvc_wp_postviews', __( 'Tools', 'post-views-counter' ), array( $this, 'wp_postviews' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
240
- add_settings_field( 'pvc_deactivation_delete', __( 'Deactivation', 'post-views-counter' ), array( $this, 'deactivation_delete' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
241
-
242
- // display options
243
- register_setting( 'post_views_counter_settings_display', 'post_views_counter_settings_display', array( $this, 'validate_settings' ) );
244
- add_settings_section( 'post_views_counter_settings_display', __( 'Display settings', 'post-views-counter' ), '', 'post_views_counter_settings_display' );
245
- add_settings_field( 'pvc_post_views_label', __( 'Post Views Label', 'post-views-counter' ), array( $this, 'post_views_label' ), 'post_views_counter_settings_display', 'post_views_counter_settings_display' );
246
- add_settings_field( 'pvc_post_types_display', __( 'Post Type', 'post-views-counter' ), array( $this, 'post_types_display' ), 'post_views_counter_settings_display', 'post_views_counter_settings_display' );
247
- add_settings_field( 'pvc_page_types_display', __( 'Page Type', 'post-views-counter' ), array( $this, 'page_types_display' ), 'post_views_counter_settings_display', 'post_views_counter_settings_display' );
248
- add_settings_field( 'pvc_restrict_display', __( 'User Type', 'post-views-counter' ), array( $this, 'restrict_display' ), 'post_views_counter_settings_display', 'post_views_counter_settings_display' );
249
- add_settings_field( 'pvc_position', __( 'Position', 'post-views-counter' ), array( $this, 'position' ), 'post_views_counter_settings_display', 'post_views_counter_settings_display' );
250
- add_settings_field( 'pvc_display_style', __( 'Display Style', 'post-views-counter' ), array( $this, 'display_style' ), 'post_views_counter_settings_display', 'post_views_counter_settings_display' );
251
- add_settings_field( 'pvc_icon_class', __( 'Icon Class', 'post-views-counter' ), array( $this, 'icon_class' ), 'post_views_counter_settings_display', 'post_views_counter_settings_display' );
252
- }
253
-
254
- /**
255
- * Post views label option.
256
- */
257
- public function post_views_label() {
258
- echo '
259
- <div id="pvc_post_views_label">
260
- <fieldset>
261
- <input type="text" class="large-text" name="post_views_counter_settings_display[label]" value="' . esc_attr( Post_Views_Counter()->options['display']['label'] ) . '" />
262
- <p class="description">' . __( 'Enter the label for the post views counter field.', 'post-views-counter' ) . '</p>
263
- </fieldset>
264
- </div>';
265
- }
266
-
267
- /**
268
- * Post types to count option.
269
- */
270
- public function post_types_count() {
271
- echo '
272
- <div id="pvc_post_types_count">';
273
-
274
- foreach ( $this->post_types as $post_type => $post_type_name ) {
275
- echo '
276
- <label class="cb-checkbox"><input id="pvc_post_types_count-' . esc_attr( $post_type ) . '" type="checkbox" name="post_views_counter_settings_general[post_types_count][' . esc_attr( $post_type ) . ']" value="1" ' . checked( in_array( $post_type, Post_Views_Counter()->options['general']['post_types_count'], true ), true, false ) . ' />' . esc_html( $post_type_name ) . ' </label>';
277
- }
278
-
279
- echo '
280
- <p class="description">' . __( 'Select post types for which post views will be counted.', 'post-views-counter' ) . '</p>
281
- </div>';
282
- }
283
-
284
- /**
285
- * Post types to display option.
286
- */
287
- public function post_types_display() {
288
- echo '
289
- <div id="pvc_post_types_display">';
290
-
291
- foreach ( $this->post_types as $post_type => $post_type_name ) {
292
- echo '
293
- <label class="cb-checkbox"><input id="pvc_post_types_display-' . esc_attr( $post_type ) . '" type="checkbox" name="post_views_counter_settings_display[post_types_display][' . esc_attr( $post_type ) . ']" value="1" ' . checked( in_array( $post_type, Post_Views_Counter()->options['display']['post_types_display'], true ), true, false ) . ' />' . esc_html( $post_type_name ) . '</label>';
294
- }
295
-
296
- echo '
297
- <p class="description">' . __( 'Select post types for which the views count will be displayed.', 'post-views-counter' ) . '</p>
298
- </div>';
299
- }
300
-
301
- /**
302
- * Counter mode option.
303
- */
304
- public function counter_mode() {
305
- echo '
306
- <div id="pvc_counter_mode">';
307
-
308
- foreach ( $this->modes as $key => $value ) {
309
- $key = esc_attr( $key );
310
-
311
- echo '
312
- <label class="cb-radio"><input type="radio" name="post_views_counter_settings_general[counter_mode]" value="' . $key . '" ' . checked( $key, Post_Views_Counter()->options['general']['counter_mode'], false ) . ' />' . esc_html( $value ) . '</label>';
313
- }
314
-
315
- echo '
316
- <p class="description">' . __( 'Select the method of collecting post views data. If you are using any of the caching plugins select Javascript or REST API (if available).', 'post-views-counter' ) . '<br />' . __( 'Optionally try the Fast AJAX experimental method, usually 10+ times faster than Javascript or REST API.', 'post-views-counter' ) . '</p>
317
- </div>';
318
- }
319
-
320
- /**
321
- * Post views column option.
322
- */
323
- public function post_views_column() {
324
- echo '
325
- <div id="pvc_post_views_column">
326
- <label class="cb-checkbox"><input id="pvc-post-views-column-enable" type="checkbox" name="post_views_counter_settings_general[post_views_column]" value="1" ' . checked( true, Post_Views_Counter()->options['general']['post_views_column'], false ) . ' />' . __( 'Enable to display post views count column for each of the selected post types.', 'post-views-counter' ) . '</label>
327
- </div>';
328
- }
329
-
330
- /**
331
- * Time between counts option.
332
- */
333
- public function time_between_counts() {
334
- echo '
335
- <div id="pvc_time_between_counts">
336
- <input size="4" type="text" name="post_views_counter_settings_general[time_between_counts][number]" value="' . esc_attr( Post_Views_Counter()->options['general']['time_between_counts']['number'] ) . '" />
337
- <select class="pvc-chosen-short" name="post_views_counter_settings_general[time_between_counts][type]">';
338
-
339
- foreach ( $this->time_types as $type => $type_name ) {
340
- echo '
341
- <option value="' . esc_attr( $type ) . '" ' . selected( $type, Post_Views_Counter()->options['general']['time_between_counts']['type'], false ) . '>' . esc_html( $type_name ) . '</option>';
342
- }
343
-
344
- echo '
345
- </select>
346
- <p class="description">' . __( 'Enter the time between single user visit count.', 'post-views-counter' ) . '</p>
347
- </div>';
348
- }
349
-
350
- /**
351
- * Reset counts option.
352
- */
353
- public function reset_counts() {
354
- echo '
355
- <div id="pvc_reset_counts">
356
- <input size="4" type="text" name="post_views_counter_settings_general[reset_counts][number]" value="' . esc_attr( Post_Views_Counter()->options['general']['reset_counts']['number'] ) . '" />
357
- <select class="pvc-chosen-short" name="post_views_counter_settings_general[reset_counts][type]">';
358
-
359
- foreach ( array_slice( $this->time_types, 2, null, true ) as $type => $type_name ) {
360
- echo '
361
- <option value="' . esc_attr( $type ) . '" ' . selected( $type, Post_Views_Counter()->options['general']['reset_counts']['type'], false ) . '>' . esc_html( $type_name ) . '</option>';
362
- }
363
-
364
- echo '
365
- </select>
366
- <p class="description">' . __( 'Delete single day post views data older than specified above. Enter 0 (number zero) if you want to preserve your data regardless of its age.', 'post-views-counter' ) . '</p>
367
- </div>';
368
- }
369
-
370
- /**
371
- * Flush interval option.
372
- */
373
- public function flush_interval() {
374
- echo '
375
- <div id="pvc_flush_interval">
376
- <input size="4" type="text" name="post_views_counter_settings_general[flush_interval][number]" value="' . esc_attr( Post_Views_Counter()->options['general']['flush_interval']['number'] ) . '" />
377
- <select class="pvc-chosen-short" name="post_views_counter_settings_general[flush_interval][type]">';
378
-
379
- foreach ( $this->time_types as $type => $type_name ) {
380
- echo '
381
- <option value="' . esc_attr( $type ) . '" ' . selected( $type, Post_Views_Counter()->options['general']['flush_interval']['type'], false ) . '>' . esc_html( $type_name ) . '</option>';
382
- }
383
-
384
- echo '
385
- </select>
386
- <p class="description">' . __( 'How often to flush cached view counts from the object cache into the database. This feature is used only if a persistent object cache is detected and the interval is greater than 0 (number zero). When used, view counts will be collected and stored in the object cache instead of the database and will then be asynchronously flushed to the database according to the specified interval.<br /><strong>Notice:</strong> Potential data loss may occur if the object cache is cleared/unavailable for the duration of the interval.', 'post-views-counter' ) . '</p>
387
- </div>';
388
- }
389
-
390
- /**
391
- * Exlude user groups option.
392
- */
393
- public function exclude() {
394
- echo '
395
- <div id="pvc_exclude">
396
- <fieldset>';
397
-
398
- foreach ( $this->groups as $type => $type_name ) {
399
- echo '
400
- <label class="cb-checkbox"><input id="pvc_exclude-' . $type . '" type="checkbox" name="post_views_counter_settings_general[exclude][groups][' . $type . ']" value="1" ' . checked( in_array( $type, Post_Views_Counter()->options['general']['exclude']['groups'], true ), true, false ) . ' />' . esc_html( $type_name ) . '</label>';
401
- }
402
-
403
- echo '
404
- <p class="description">' . __( 'Use it to hide the post views counter from selected type of visitors.', 'post-views-counter' ) . '</p>
405
- <div class="pvc_user_roles"' . (in_array( 'roles', Post_Views_Counter()->options['general']['exclude']['groups'], true ) ? '' : ' style="display: none;"') . '>';
406
-
407
- foreach ( $this->user_roles as $role => $role_name ) {
408
- echo '
409
- <label class="cb-checkbox"><input type="checkbox" name="post_views_counter_settings_general[exclude][roles][' . $role . ']" value="1" ' . checked( in_array( $role, Post_Views_Counter()->options['general']['exclude']['roles'], true ), true, false ) . '>' . esc_html( $role_name ) . '</label>';
410
- }
411
-
412
- echo ' <p class="description">' . __( 'Use it to hide the post views counter from selected user roles.', 'post-views-counter' ) . '</p>
413
- </div>
414
- </fieldset>
415
- </div>';
416
- }
417
-
418
- /**
419
- * Exclude IPs option.
420
- */
421
- public function exclude_ips() {
422
- // lovely php 5.2 limitations
423
- $ips = Post_Views_Counter()->options['general']['exclude_ips'];
424
-
425
- echo '
426
- <div id="pvc_exclude_ips">';
427
-
428
- if ( ! empty( $ips ) ) {
429
- foreach ( $ips as $key => $ip ) {
430
- echo '
431
- <div class="ip-box">
432
- <input type="text" name="post_views_counter_settings_general[exclude_ips][]" value="' . esc_attr( $ip ) . '" /> <a href="#" class="remove-exclude-ip" title="' . esc_attr__( 'Remove', 'post-views-counter' ) . '">' . esc_attr__( 'Remove', 'post-views-counter' ) . '</a>
433
- </div>';
434
- }
435
- } else {
436
- echo '
437
- <div class="ip-box">
438
- <input type="text" name="post_views_counter_settings_general[exclude_ips][]" value="" /> <a href="#" class="remove-exclude-ip" title="' . esc_attr__( 'Remove', 'post-views-counter' ) . '">' . esc_attr__( 'Remove', 'post-views-counter' ) . '</a>
439
- </div>';
440
- }
441
-
442
- echo '
443
- <p><input type="button" class="button button-secondary add-exclude-ip" value="' . esc_attr__( 'Add new', 'post-views-counter' ) . '" /> <input type="button" class="button button-secondary add-current-ip" value="' . esc_attr__( 'Add my current IP', 'post-views-counter' ) . '" data-rel="' . esc_attr( $_SERVER['REMOTE_ADDR'] ) . '" /></p>
444
- <p class="description">' . __( 'Enter the IP addresses to be excluded from post views count.', 'post-views-counter' ) . '</p>
445
- </div>';
446
- }
447
-
448
- /**
449
- * Strict counts option.
450
- */
451
- public function strict_counts() {
452
- echo '
453
- <div id="pvc_strict_counts">
454
- <label class="cb-checkbox"><input id="pvc-strict-counts" type="checkbox" name="post_views_counter_settings_general[strict_counts]" value="1" ' . checked( true, Post_Views_Counter()->options['general']['strict_counts'], false ) . ' />' . __( 'Enable to prevent bypassing the counts interval (for e.g. using incognito browser window or by clearing cookies).', 'post-views-counter' ) . '</label>
455
- </div>';
456
- }
457
-
458
- /**
459
- * WP-PostViews import option.
460
- */
461
- public function wp_postviews() {
462
- echo '
463
- <div id="pvc_wp_postviews">
464
- <fieldset>
465
- <input type="submit" class="button button-secondary" name="post_views_counter_import_wp_postviews" value="' . __( 'Import views', 'post-views-counter' ) . '"/> <label class="cb-checkbox"><input id="pvc-wp-postviews" type="checkbox" name="post_views_counter_import_wp_postviews_override" value="1" />' . __( 'Override existing views data.', 'post-views-counter' ) . '</label>
466
- <p class="description">' . __( 'Import post views data from WP-PostViews plugin.', 'post-views-counter' ) . '</p>
467
- <input type="submit" class="button button-secondary" name="post_views_counter_reset_views" value="' . __( 'Delete views', 'post-views-counter' ) . '"/>
468
- <p class="description">' . __( 'Delete ALL the existing post views data.', 'post-views-counter' ) . '</p>
469
- </fieldset>
470
- </div>';
471
- }
472
-
473
- /**
474
- * Limit views edit to admins.
475
- */
476
- public function restrict_edit_views() {
477
- echo '
478
- <div id="pvc_restrict_edit_views">
479
- <label class="cb-checkbox"><input type="checkbox" name="post_views_counter_settings_general[restrict_edit_views]" value="1" ' . checked( true, Post_Views_Counter()->options['general']['restrict_edit_views'], false ) . ' />' . __( 'Enable to restrict post views editing to admins only.', 'post-views-counter' ) . '</label>
480
- </div>';
481
- }
482
-
483
- /**
484
- * Plugin deactivation option.
485
- */
486
- public function deactivation_delete() {
487
- echo '
488
- <div id="pvc_deactivation_delete">
489
- <label class="cb-checkbox"><input type="checkbox" name="post_views_counter_settings_general[deactivation_delete]" value="1" ' . checked( true, Post_Views_Counter()->options['general']['deactivation_delete'], false ) . ' />' . __( 'Enable to delete all plugin data on deactivation.', 'post-views-counter' ) . '</label>
490
- </div>';
491
- }
492
-
493
- /**
494
- * Visibility option.
495
- */
496
- public function page_types_display() {
497
- echo '
498
- <div id="pvc_post_types_display">';
499
-
500
- foreach ( $this->page_types as $key => $label ) {
501
- echo '
502
- <label class="cb-checkbox"><input id="pvc_page_types_display-' . esc_attr( $key ) . '" type="checkbox" name="post_views_counter_settings_display[page_types_display][' . esc_attr( $key ) . ']" value="1" ' . checked( in_array( $key, Post_Views_Counter()->options['display']['page_types_display'], true ), true, false ) . ' />' . esc_html( $label ) . '</label>';
503
- }
504
-
505
- echo '
506
- <p class="description">' . __( 'Select page types where the views count will be displayed.', 'post-views-counter' ) . '</p>
507
- </div>';
508
- }
509
-
510
- /**
511
- * Counter position option.
512
- */
513
- public function position() {
514
- echo '
515
- <div id="pvc_position">
516
- <select class="pvc-chosen-short" name="post_views_counter_settings_display[position]">';
517
-
518
- foreach ( $this->positions as $position => $position_name ) {
519
- echo '
520
- <option value="' . esc_attr( $position ) . '" ' . selected( $position, Post_Views_Counter()->options['display']['position'], false ) . '>' . esc_html( $position_name ) . '</option>';
521
- }
522
-
523
- echo '
524
- </select>
525
- <p class="description">' . __( 'Select where would you like to display the post views counter. Use [post-views] shortcode for manual display.', 'post-views-counter' ) . '</p>
526
- </div>';
527
- }
528
-
529
- /**
530
- * Counter style option.
531
- */
532
- public function display_style() {
533
- echo '
534
- <div id="pvc_display_style">';
535
-
536
- foreach ( $this->display_styles as $display => $style ) {
537
- $display = esc_attr( $display );
538
-
539
- echo '
540
- <label class="cb-checkbox"><input type="checkbox" name="post_views_counter_settings_display[display_style][' . $display . ']" value="1" ' . checked( true, Post_Views_Counter()->options['display']['display_style'][$display], false ) . ' />' . esc_html( $style ) . '</label>';
541
- }
542
-
543
- echo '
544
- <p class="description">' . __( 'Choose how to display the post views counter.', 'post-views-counter' ) . '</p>
545
- </div>';
546
- }
547
-
548
- /**
549
- * Counter icon class option.
550
- */
551
- public function icon_class() {
552
- echo '
553
- <div id="pvc_icon_class">
554
- <input type="text" name="post_views_counter_settings_display[icon_class]" class="large-text" value="' . esc_attr( Post_Views_Counter()->options['display']['icon_class'] ) . '" />
555
- <p class="description">' . sprintf( __( 'Enter the post views icon class. Any of the <a href="%s" target="_blank">Dashicons</a> classes are available.', 'post-views-counter' ), 'https://developer.wordpress.org/resource/dashicons/' ) . '</p>
556
- </div>';
557
- }
558
-
559
- /**
560
- * Restrict display option.
561
- */
562
- public function restrict_display() {
563
- echo '
564
- <div id="pvc_restrict_display">
565
- <fieldset>';
566
-
567
- foreach ( $this->groups as $type => $type_name ) {
568
-
569
- if ( $type === 'robots' )
570
- continue;
571
-
572
- echo '
573
- <label class="cb-checkbox"><input id="pvc_restrict_display-' . $type . '" type="checkbox" name="post_views_counter_settings_display[restrict_display][groups][' . esc_html( $type ) . ']" value="1" ' . checked( in_array( $type, Post_Views_Counter()->options['display']['restrict_display']['groups'], true ), true, false ) . ' />' . esc_html( $type_name ) . '</label>';
574
- }
575
-
576
- echo '
577
- <p class="description">' . __( 'Use it to hide the post views counter from selected type of visitors.', 'post-views-counter' ) . '</p>
578
- <div class="pvc_user_roles"' . (in_array( 'roles', Post_Views_Counter()->options['display']['restrict_display']['groups'], true ) ? '' : ' style="display: none;"') . '>';
579
-
580
- foreach ( $this->user_roles as $role => $role_name ) {
581
- echo '
582
- <label class="cb-checkbox"><input type="checkbox" name="post_views_counter_settings_display[restrict_display][roles][' . $role . ']" value="1" ' . checked( in_array( $role, Post_Views_Counter()->options['display']['restrict_display']['roles'], true ), true, false ) . ' />' . esc_html( $role_name ) . '</label>';
583
- }
584
-
585
- echo '
586
- <p class="description">' . __( 'Use it to hide the post views counter from selected user roles.', 'post-views-counter' ) . '</p>
587
- </div>
588
- </fieldset>
589
- </div>';
590
- }
591
-
592
- /**
593
- * Validate general settings.
594
- */
595
- public function validate_settings( $input ) {
596
- // get main instance
597
- $pvc = Post_Views_Counter();
598
-
599
- if ( isset( $_POST['post_views_counter_import_wp_postviews'] ) ) {
600
- global $wpdb;
601
-
602
- $meta_key = esc_attr( apply_filters( 'pvc_import_meta_key', 'views' ) );
603
-
604
- $views = $wpdb->get_results( "SELECT post_id, meta_value FROM " . $wpdb->postmeta . " WHERE meta_key = '" . $meta_key . "'", ARRAY_A, 0 );
605
-
606
- if ( ! empty( $views ) ) {
607
- $input = $pvc->defaults['general'];
608
- $input['wp_postviews_import'] = true;
609
-
610
- $sql = array();
611
-
612
- foreach ( $views as $view ) {
613
- $sql[] = "(" . $view['post_id'] . ", 4, 'total', " . $view['meta_value'] . ")";
614
- }
615
-
616
- $wpdb->query( "INSERT INTO " . $wpdb->prefix . "post_views(id, type, period, count) VALUES " . implode( ',', $sql ) . " ON DUPLICATE KEY UPDATE count = " . (isset( $_POST['post_views_counter_import_wp_postviews_override'] ) ? '' : 'count + ') . "VALUES(count)" );
617
-
618
- add_settings_error( 'wp_postviews_import', 'wp_postviews_import', __( 'Post views data imported succesfully.', 'post-views-counter' ), 'updated' );
619
- } else {
620
- add_settings_error( 'wp_postviews_import', 'wp_postviews_import', __( 'There was no post views data to import.', 'post-views-counter' ), 'updated' );
621
- }
622
- } elseif ( isset( $_POST['post_views_counter_reset_views'] ) ) {
623
- global $wpdb;
624
-
625
- if ( $wpdb->query( 'TRUNCATE TABLE ' . $wpdb->prefix . 'post_views' ) )
626
- add_settings_error( 'reset_post_views', 'reset_post_views', __( 'All existing data deleted succesfully.', 'post-views-counter' ), 'updated' );
627
- else
628
- add_settings_error( 'reset_post_views', 'reset_post_views', __( 'Error occurred. All existing data were not deleted.', 'post-views-counter' ), 'error' );
629
- } elseif ( isset( $_POST['save_pvc_general'] ) ) {
630
- // post types count
631
- if ( isset( $input['post_types_count'] ) ) {
632
- $post_types = array();
633
-
634
- foreach ( $input['post_types_count'] as $post_type => $set ) {
635
- if ( isset( $this->post_types[$post_type] ) )
636
- $post_types[] = $post_type;
637
- }
638
-
639
- $input['post_types_count'] = array_unique( $post_types );
640
- } else
641
- $input['post_types_count'] = array();
642
-
643
- // counter mode
644
- $input['counter_mode'] = isset( $input['counter_mode'], $this->modes[$input['counter_mode']] ) ? $input['counter_mode'] : $pvc->defaults['general']['counter_mode'];
645
-
646
- // post views column
647
- $input['post_views_column'] = isset( $input['post_views_column'] );
648
-
649
- // time between counts
650
- $input['time_between_counts']['number'] = (int) ( isset( $input['time_between_counts']['number'] ) ? $input['time_between_counts']['number'] : $pvc->defaults['general']['time_between_counts']['number'] );
651
- $input['time_between_counts']['type'] = isset( $input['time_between_counts']['type'], $this->time_types[$input['time_between_counts']['type']] ) ? $input['time_between_counts']['type'] : $pvc->defaults['general']['time_between_counts']['type'];
652
-
653
- // flush interval
654
- $input['flush_interval']['number'] = (int) ( isset( $input['flush_interval']['number'] ) ? $input['flush_interval']['number'] : $pvc->defaults['general']['flush_interval']['number'] );
655
- $input['flush_interval']['type'] = isset( $input['flush_interval']['type'], $this->time_types[$input['flush_interval']['type']] ) ? $input['flush_interval']['type'] : $pvc->defaults['general']['flush_interval']['type'];
656
-
657
- // Since the settings are about to be saved and cache flush interval could've changed,
658
- // we want to make sure that any changes done on the settings page are in effect immediately
659
- // (instead of having to wait for the previous schedule to occur).
660
- // We achieve that by making sure to clear any previous cache flush schedules and
661
- // schedule the new one if the specified interval is > 0
662
- $pvc->remove_cache_flush();
663
-
664
- if ( $input['flush_interval']['number'] > 0 ) {
665
- $pvc->schedule_cache_flush();
666
- }
667
-
668
- // reset counts
669
- $input['reset_counts']['number'] = (int) ( isset( $input['reset_counts']['number'] ) ? $input['reset_counts']['number'] : $pvc->defaults['general']['reset_counts']['number'] );
670
- $input['reset_counts']['type'] = isset( $input['reset_counts']['type'], $this->time_types[$input['reset_counts']['type']] ) ? $input['reset_counts']['type'] : $pvc->defaults['general']['reset_counts']['type'];
671
-
672
- // run cron on next visit?
673
- $input['cron_run'] = ($input['reset_counts']['number'] > 0 ? true : false);
674
- $input['cron_update'] = ($input['cron_run'] && ( $pvc->options['general']['reset_counts']['number'] !== $input['reset_counts']['number'] || $pvc->options['general']['reset_counts']['type'] !== $input['reset_counts']['type'] ) ? true : false);
675
-
676
- // exclude
677
- if ( isset( $input['exclude']['groups'] ) ) {
678
- $groups = array();
679
-
680
- foreach ( $input['exclude']['groups'] as $group => $set ) {
681
- if ( isset( $this->groups[$group] ) )
682
- $groups[] = $group;
683
- }
684
-
685
- $input['exclude']['groups'] = array_unique( $groups );
686
- } else {
687
- $input['exclude']['groups'] = array();
688
- }
689
-
690
- if ( in_array( 'roles', $input['exclude']['groups'], true ) && isset( $input['exclude']['roles'] ) ) {
691
- $roles = array();
692
-
693
- foreach ( $input['exclude']['roles'] as $role => $set ) {
694
- if ( isset( $this->user_roles[$role] ) )
695
- $roles[] = $role;
696
- }
697
-
698
- $input['exclude']['roles'] = array_unique( $roles );
699
- } else
700
- $input['exclude']['roles'] = array();
701
-
702
- // exclude ips
703
- if ( isset( $input['exclude_ips'] ) ) {
704
- $ips = array();
705
-
706
- foreach ( $input['exclude_ips'] as $ip ) {
707
- if ( strpos( $ip, '*' ) !== false ) {
708
- $new_ip = str_replace( '*', '0', $ip );
709
-
710
- if ( filter_var( $new_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) )
711
- $ips[] = $ip;
712
- } elseif ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) )
713
- $ips[] = $ip;
714
- }
715
-
716
- $input['exclude_ips'] = array_unique( $ips );
717
- }
718
-
719
- // restrict edit views
720
- $input['restrict_edit_views'] = isset( $input['restrict_edit_views'] );
721
-
722
- // strict counts
723
- $input['strict_counts'] = isset( $input['strict_counts'] );
724
-
725
- // deactivation delete
726
- $input['deactivation_delete'] = isset( $input['deactivation_delete'] );
727
-
728
- $input['update_version'] = $pvc->options['general']['update_version'];
729
- $input['update_notice'] = $pvc->options['general']['update_notice'];
730
- } elseif ( isset( $_POST['save_pvc_display'] ) ) {
731
-
732
- // post views label
733
- $input['label'] = isset( $input['label'] ) ? $input['label'] : $pvc->defaults['general']['label'];
734
-
735
- if ( function_exists( 'icl_register_string' ) )
736
- icl_register_string( 'Post Views Counter', 'Post Views Label', $input['label'] );
737
-
738
- // position
739
- $input['position'] = isset( $input['position'], $this->positions[$input['position']] ) ? $input['position'] : $pvc->defaults['general']['position'];
740
-
741
- // display style
742
- $input['display_style']['icon'] = isset( $input['display_style']['icon'] );
743
- $input['display_style']['text'] = isset( $input['display_style']['text'] );
744
-
745
- // link to post
746
- $input['link_to_post'] = isset( $input['link_to_post'] ) ? $input['link_to_post'] : $pvc->defaults['display']['link_to_post'];
747
-
748
- // icon class
749
- $input['icon_class'] = isset( $input['icon_class'] ) ? trim( $input['icon_class'] ) : $pvc->defaults['general']['icon_class'];
750
-
751
- // post types display
752
- if ( isset( $input['post_types_display'] ) ) {
753
- $post_types = array();
754
-
755
- foreach ( $input['post_types_display'] as $post_type => $set ) {
756
- if ( isset( $this->post_types[$post_type] ) )
757
- $post_types[] = $post_type;
758
- }
759
-
760
- $input['post_types_display'] = array_unique( $post_types );
761
- } else
762
- $input['post_types_display'] = array();
763
-
764
- // page types display
765
- if ( isset( $input['page_types_display'] ) ) {
766
- $page_types = array();
767
-
768
- foreach ( $input['page_types_display'] as $page_type => $set ) {
769
- if ( isset( $this->page_types[$page_type] ) )
770
- $page_types[] = $page_type;
771
- }
772
-
773
- $input['page_types_display'] = array_unique( $page_types );
774
- } else
775
- $input['page_types_display'] = array();
776
-
777
- // restrict display
778
- if ( isset( $input['restrict_display']['groups'] ) ) {
779
- $groups = array();
780
-
781
- foreach ( $input['restrict_display']['groups'] as $group => $set ) {
782
- if ( $group === 'robots' )
783
- continue;
784
-
785
- if ( isset( $this->groups[$group] ) )
786
- $groups[] = $group;
787
- }
788
-
789
- $input['restrict_display']['groups'] = array_unique( $groups );
790
- } else
791
- $input['restrict_display']['groups'] = array();
792
-
793
- if ( in_array( 'roles', $input['restrict_display']['groups'], true ) && isset( $input['restrict_display']['roles'] ) ) {
794
- $roles = array();
795
-
796
- foreach ( $input['restrict_display']['roles'] as $role => $set ) {
797
- if ( isset( $this->user_roles[$role] ) )
798
- $roles[] = $role;
799
- }
800
-
801
- $input['restrict_display']['roles'] = array_unique( $roles );
802
- } else
803
- $input['restrict_display']['roles'] = array();
804
- } elseif ( isset( $_POST['reset_pvc_general'] ) ) {
805
- $input = $pvc->defaults['general'];
806
-
807
- add_settings_error( 'reset_general_settings', 'settings_reset', __( 'General settings restored to defaults.', 'post-views-counter' ), 'updated' );
808
- } elseif ( isset( $_POST['reset_pvc_display'] ) ) {
809
- $input = $pvc->defaults['display'];
810
-
811
- add_settings_error( 'reset_general_settings', 'settings_reset', __( 'Display settings restored to defaults.', 'post-views-counter' ), 'updated' );
812
- }
813
-
814
- return $input;
815
- }
816
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/update.php DELETED
@@ -1,119 +0,0 @@
1
- <?php
2
- // exit if accessed directly
3
- if ( ! defined( 'ABSPATH' ) )
4
- exit;
5
-
6
- /**
7
- * Post_Views_Counter_Update class.
8
- *
9
- * @class Post_Views_Counter_Update
10
- */
11
- class Post_Views_Counter_Update {
12
-
13
- public function __construct() {
14
- // actions
15
- add_action( 'init', array( $this, 'check_update' ) );
16
- }
17
-
18
- /**
19
- * Check if there's a db update required
20
- */
21
- public function check_update() {
22
- if ( ! current_user_can( 'manage_options' ) )
23
- return;
24
-
25
- // get current database version
26
- $current_db_version = get_option( 'post_views_counter_version', '1.0.0' );
27
-
28
- // update 1.2.4+
29
- if ( version_compare( $current_db_version, '1.2.4', '<=' ) ) {
30
- $general = Post_Views_Counter()->options['general'];
31
-
32
- if ( $general['reset_counts']['number'] > 0 ) {
33
- // unsupported data reset in minutes/hours
34
- if ( in_array( $general['reset_counts']['type'], array( 'minutes', 'hours' ), true ) ) {
35
- // set type to date
36
- $general['reset_counts']['type'] = 'days';
37
-
38
- // new number of days
39
- if ( $general['reset_counts']['type'] === 'minutes' )
40
- $general['reset_counts']['number'] = $general['reset_counts']['number'] * 60;
41
- else
42
- $general['reset_counts']['number'] = $general['reset_counts']['number'] * 3600;
43
-
44
- // how many days?
45
- $general['reset_counts']['number'] = (int) round( ceil( $general['reset_counts']['number'] / 86400 ) );
46
-
47
- // force cron to update
48
- $general['cron_run'] = true;
49
- $general['cron_update'] = true;
50
-
51
- // update settings
52
- update_option( 'post_views_counter_settings_general', $general );
53
-
54
- // update general options
55
- Post_Views_Counter()->options['general'] = $general;
56
- }
57
-
58
- // update cron job for all users
59
- Post_Views_Counter()->cron->check_cron();
60
- }
61
- }
62
-
63
- if ( isset( $_POST['post_view_counter_update'], $_POST['post_view_counter_number'] ) ) {
64
- if ( $_POST['post_view_counter_number'] === 'update_1' ) {
65
- $this->update_1();
66
-
67
- // update plugin version
68
- update_option( 'post_views_counter_version', Post_Views_Counter()->defaults['version'], false );
69
- }
70
- }
71
-
72
- $update_1_html = '
73
- <form action="" method="post">
74
- <input type="hidden" name="post_view_counter_number" value="update_1"/>
75
- <p>' . __( '<strong>Post Views Counter</strong> - this version requires a database update. Make sure to back up your database first.', 'post-views-counter' ) . '</p>
76
- <p><input type="submit" class="button button-primary" name="post_view_counter_update" value="' . __( 'Run the Update', 'post-views-counter' ) . '"/></p>
77
- </form>';
78
-
79
- // get current database version
80
- $current_db_version = get_option( 'post_views_counter_version', '1.0.0' );
81
-
82
- // new version?
83
- if ( version_compare( $current_db_version, Post_Views_Counter()->defaults['version'], '<' ) ) {
84
- // is update 1 required?
85
- if ( version_compare( $current_db_version, '1.2.4', '<=' ) )
86
- Post_Views_Counter()->add_notice( $update_1_html, 'notice notice-info' );
87
- else
88
- // update plugin version
89
- update_option( 'post_views_counter_version', Post_Views_Counter()->defaults['version'], false );
90
- }
91
- }
92
-
93
- /**
94
- * Database update for 1.2.4 and below.
95
- */
96
- public function update_1() {
97
- global $wpdb;
98
-
99
- // get index
100
- $old_index = $wpdb->query( "SHOW INDEX FROM `" . $wpdb->prefix . "post_views` WHERE Key_name = 'id_period'" );
101
-
102
- // check whether index already exists
103
- if ( $old_index > 0 ) {
104
- // drop unwanted index which prevented saving views with indentical weeks and months
105
- $wpdb->query( "ALTER TABLE `" . $wpdb->prefix . "post_views` DROP INDEX id_period" );
106
- }
107
-
108
- // get index
109
- $new_index = $wpdb->query( "SHOW INDEX FROM `" . $wpdb->prefix . "post_views` WHERE Key_name = 'id_type_period_count'" );
110
-
111
- // check whether index already exists
112
- if ( $new_index === 0 ) {
113
- // create new index for better performance of SQL queries
114
- $wpdb->query( 'ALTER TABLE `' . $wpdb->prefix . 'post_views` ADD UNIQUE INDEX `id_type_period_count` (`id`, `type`, `period`, `count`) USING BTREE' );
115
- }
116
-
117
- Post_Views_Counter()->add_notice( __( 'Thank you! Datebase was succesfully updated.', 'post-views-counter' ), 'updated', true );
118
- }
119
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/widgets.php DELETED
@@ -1,234 +0,0 @@
1
- <?php
2
- // exit if accessed directly
3
- if ( ! defined( 'ABSPATH' ) )
4
- exit;
5
-
6
- /**
7
- * Post_Views_Counter_Widgets class.
8
- *
9
- * @class Post_Views_Counter_Widgets
10
- */
11
- class Post_Views_Counter_Widgets {
12
-
13
- public function __construct() {
14
- // actions
15
- add_action( 'widgets_init', array( $this, 'register_widgets' ) );
16
- }
17
-
18
- /**
19
- * Register widgets.
20
- */
21
- public function register_widgets() {
22
- register_widget( 'Post_Views_Counter_List_Widget' );
23
- }
24
-
25
- }
26
-
27
- /**
28
- * Post_Views_Counter_List_Widget class.
29
- *
30
- * @class Post_Views_Counter_List_Widget
31
- */
32
- class Post_Views_Counter_List_Widget extends WP_Widget {
33
-
34
- private $pvc_defaults;
35
- private $pvc_post_types;
36
- private $pvc_order_types;
37
- private $pvc_list_types;
38
- private $pvc_image_sizes;
39
-
40
- public function __construct() {
41
- parent::__construct(
42
- 'Post_Views_Counter_List_Widget', __( 'Most Viewed Posts', 'post-views-counter' ), array(
43
- 'description' => __( 'Displays a list of the most viewed posts', 'post-views-counter' )
44
- )
45
- );
46
-
47
- $this->pvc_defaults = array(
48
- 'title' => __( 'Most Viewed Posts', 'post-views-counter' ),
49
- 'number_of_posts' => 5,
50
- 'thumbnail_size' => 'thumbnail',
51
- 'post_type' => array(),
52
- 'order' => 'desc',
53
- 'list_type' => 'unordered',
54
- 'show_post_views' => true,
55
- 'show_post_thumbnail' => false,
56
- 'show_post_excerpt' => false,
57
- 'show_post_author' => false,
58
- 'no_posts_message' => __( 'No Posts found', 'post-views-counter' )
59
- );
60
-
61
- $this->pvc_order_types = array(
62
- 'asc' => __( 'Ascending', 'post-views-counter' ),
63
- 'desc' => __( 'Descending', 'post-views-counter' )
64
- );
65
-
66
- $this->pvc_list_types = array(
67
- 'unordered' => __( 'Unordered list', 'post-views-counter' ),
68
- 'ordered' => __( 'Ordered list', 'post-views-counter' )
69
- );
70
-
71
- $this->pvc_image_sizes = array_merge( array( 'full' ), get_intermediate_image_sizes() );
72
-
73
- // sort image sizes by name, ascending
74
- sort( $this->pvc_image_sizes, SORT_STRING );
75
-
76
- add_action( 'wp_loaded', array( $this, 'load_post_types' ) );
77
- }
78
-
79
- /**
80
- * Get selected post types.
81
- */
82
- public function load_post_types() {
83
-
84
- if ( ! is_admin() )
85
- return;
86
-
87
- $this->pvc_post_types = Post_Views_Counter()->settings->post_types;
88
- }
89
-
90
- /**
91
- * Display widget.
92
- *
93
- * @param array $args
94
- * @param object $instance
95
- */
96
- public function widget( $args, $instance ) {
97
- $instance['title'] = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
98
-
99
- $html = $args['before_widget'] . ( ! empty( $instance['title'] ) ? $args['before_title'] . $instance['title'] . $args['after_title'] : '');
100
- $html .= pvc_most_viewed_posts( $instance, false );
101
- $html .= $args['after_widget'];
102
-
103
- echo $html;
104
- }
105
-
106
- /** Render widget form.
107
- *
108
- * @param object $instance
109
- * @return mixed
110
- */
111
- public function form( $instance ) {
112
- $html = '
113
- <p>
114
- <label for="' . $this->get_field_id( 'title' ) . '">' . __( 'Title', 'post-views-counter' ) . ':</label>
115
- <input id="' . $this->get_field_id( 'title' ) . '" class="widefat" name="' . $this->get_field_name( 'title' ) . '" type="text" value="' . esc_attr( isset( $instance['title'] ) ? $instance['title'] : $this->pvc_defaults['title'] ) . '" />
116
- </p>
117
- <p>
118
- <label>' . __( 'Post Types', 'post-views-counter' ) . ':</label><br />';
119
-
120
- foreach ( $this->pvc_post_types as $post_type => $post_type_name ) {
121
- $html .= '
122
- <input id="' . $this->get_field_id( 'post_type' ) . '-' . $post_type . '" type="checkbox" name="' . $this->get_field_name( 'post_type' ) . '[]" value="' . $post_type . '" ' . checked( ( ! isset( $instance['post_type'] ) ? true : in_array( $post_type, $instance['post_type'], true ) ), true, false ) . '><label for="' . $this->get_field_id( 'post_type' ) . '-' . $post_type . '">' . esc_html( $post_type_name ) . '</label>';
123
- }
124
-
125
- $show_post_thumbnail = isset( $instance['show_post_thumbnail'] ) ? $instance['show_post_thumbnail'] : $this->pvc_defaults['show_post_thumbnail'];
126
-
127
- $html .= '
128
- </p>
129
- <p>
130
- <label for="' . $this->get_field_id( 'number_of_posts' ) . '">' . __( 'Number of posts to show', 'post-views-counter' ) . ':</label>
131
- <input id="' . $this->get_field_id( 'number_of_posts' ) . '" name="' . $this->get_field_name( 'number_of_posts' ) . '" type="text" size="3" value="' . esc_attr( isset( $instance['number_of_posts'] ) ? $instance['number_of_posts'] : $this->pvc_defaults['number_of_posts'] ) . '" />
132
- </p>
133
- <p>
134
- <label for="' . $this->get_field_id( 'no_posts_message' ) . '">' . __( 'No posts message', 'post-views-counter' ) . ':</label>
135
- <input id="' . $this->get_field_id( 'no_posts_message' ) . '" class="widefat" type="text" name="' . $this->get_field_name( 'no_posts_message' ) . '" value="' . esc_attr( isset( $instance['no_posts_message'] ) ? $instance['no_posts_message'] : $this->pvc_defaults['no_posts_message'] ) . '" />
136
- </p>
137
- <p>
138
- <label for="' . $this->get_field_id( 'order' ) . '">' . __( 'Order', 'post-views-counter' ) . ':</label>
139
- <select id="' . $this->get_field_id( 'order' ) . '" name="' . $this->get_field_name( 'order' ) . '">';
140
-
141
- foreach ( $this->pvc_order_types as $id => $order ) {
142
- $html .= '
143
- <option value="' . esc_attr( $id ) . '" ' . selected( $id, ( isset( $instance['order'] ) ? $instance['order'] : $this->pvc_defaults['order'] ), false ) . '>' . $order . '</option>';
144
- }
145
-
146
- $html .= '
147
- </select>
148
- </p>
149
- <p>
150
- <label for="' . $this->get_field_id( 'list_type' ) . '">' . __( 'Display Style', 'post-views-counter' ) . ':</label>
151
- <select id="' . $this->get_field_id( 'list_type' ) . '" name="' . $this->get_field_name( 'list_type' ) . '">';
152
-
153
- foreach ( $this->pvc_list_types as $id => $list_type ) {
154
- $html .= '
155
- <option value="' . esc_attr( $id ) . '" ' . selected( $id, ( isset( $instance['list_type'] ) ? $instance['list_type'] : $this->pvc_defaults['list_type'] ), false ) . '>' . $list_type . '</option>';
156
- }
157
-
158
- $html .= '
159
- </select>
160
- </p>
161
- <p>
162
- <input id="' . $this->get_field_id( 'show_post_views' ) . '" type="checkbox" name="' . $this->get_field_name( 'show_post_views' ) . '" ' . checked( true, (isset( $instance['show_post_views'] ) ? $instance['show_post_views'] : $this->pvc_defaults['show_post_views'] ), false ) . ' /> <label for="' . $this->get_field_id( 'show_post_views' ) . '">' . __( 'Display post views?', 'post-views-counter' ) . '</label>
163
- <br />
164
- <input id="' . $this->get_field_id( 'show_post_excerpt' ) . '" type="checkbox" name="' . $this->get_field_name( 'show_post_excerpt' ) . '" ' . checked( true, (isset( $instance['show_post_excerpt'] ) ? $instance['show_post_excerpt'] : $this->pvc_defaults['show_post_excerpt'] ), false ) . ' /> <label for="' . $this->get_field_id( 'show_post_excerpt' ) . '">' . __( 'Display post excerpt?', 'post-views-counter' ) . '</label>
165
- <br />
166
- <input id="' . $this->get_field_id( 'show_post_author' ) . '" type="checkbox" name="' . $this->get_field_name( 'show_post_author' ) . '" ' . checked( true, (isset( $instance['show_post_author'] ) ? $instance['show_post_author'] : $this->pvc_defaults['show_post_author'] ), false ) . ' /> <label for="' . $this->get_field_id( 'show_post_author' ) . '">' . __( 'Display post author?', 'post-views-counter' ) . '</label>
167
- <br />
168
- <input id="' . $this->get_field_id( 'show_post_thumbnail' ) . '" class="pvc-show-post-thumbnail" type="checkbox" name="' . $this->get_field_name( 'show_post_thumbnail' ) . '" ' . checked( true, $show_post_thumbnail, false ) . ' /> <label for="' . $this->get_field_id( 'show_post_thumbnail' ) . '">' . __( 'Display post thumbnail?', 'post-views-counter' ) . '</label>
169
- </p>
170
- <p class="pvc-post-thumbnail-size"' . ( $show_post_thumbnail ? '' : ' style="display: none;"' ) . '>
171
- <label for="' . $this->get_field_id( 'thumbnail_size' ) . '">' . __( 'Thumbnail size', 'post-views-counter' ) . ':</label>
172
- <select id="' . $this->get_field_id( 'thumbnail_size' ) . '" name="' . $this->get_field_name( 'thumbnail_size' ) . '">';
173
-
174
- $size_type = isset( $instance['thumbnail_size'] ) ? $instance['thumbnail_size'] : $this->pvc_defaults['thumbnail_size'];
175
-
176
- foreach ( $this->pvc_image_sizes as $size ) {
177
- $html .= '
178
- <option value="' . esc_attr( $size ) . '" ' . selected( $size, $size_type, false ) . '>' . $size . '</option>';
179
- }
180
-
181
- $html .= '
182
- </select>
183
- </p>';
184
-
185
- echo $html;
186
- }
187
-
188
- /**
189
- * Save widget form.
190
- *
191
- * @param array $new_instance
192
- * @param array $old_instance
193
- * @return array
194
- */
195
- public function update( $new_instance, $old_instance ) {
196
- // number of posts
197
- $old_instance['number_of_posts'] = (int) (isset( $new_instance['number_of_posts'] ) ? $new_instance['number_of_posts'] : $this->pvc_defaults['number_of_posts']);
198
-
199
- // order
200
- $old_instance['order'] = isset( $new_instance['order'] ) && in_array( $new_instance['order'], array_keys( $this->pvc_order_types ), true ) ? $new_instance['order'] : $this->pvc_defaults['order'];
201
-
202
- // list type
203
- $old_instance['list_type'] = isset( $new_instance['list_type'] ) && in_array( $new_instance['list_type'], array_keys( $this->pvc_list_types ), true ) ? $new_instance['list_type'] : $this->pvc_defaults['list_type'];
204
-
205
- // thumbnail size
206
- $old_instance['thumbnail_size'] = isset( $new_instance['thumbnail_size'] ) && in_array( $new_instance['thumbnail_size'], $this->pvc_image_sizes, true ) ? $new_instance['thumbnail_size'] : $this->pvc_defaults['thumbnail_size'];
207
-
208
- // booleans
209
- $old_instance['show_post_views'] = isset( $new_instance['show_post_views'] );
210
- $old_instance['show_post_thumbnail'] = isset( $new_instance['show_post_thumbnail'] );
211
- $old_instance['show_post_excerpt'] = isset( $new_instance['show_post_excerpt'] );
212
- $old_instance['show_post_author'] = isset( $new_instance['show_post_author'] );
213
-
214
- // texts
215
- $old_instance['title'] = sanitize_text_field( isset( $new_instance['title'] ) ? $new_instance['title'] : $this->pvc_defaults['title'] );
216
- $old_instance['no_posts_message'] = sanitize_text_field( isset( $new_instance['no_posts_message'] ) ? $new_instance['no_posts_message'] : $this->pvc_defaults['no_posts_message'] );
217
-
218
- // post types
219
- if ( isset( $new_instance['post_type'] ) ) {
220
- $post_types = array();
221
-
222
- foreach ( $new_instance['post_type'] as $post_type ) {
223
- if ( isset( $this->pvc_post_types[$post_type] ) )
224
- $post_types[] = $post_type;
225
- }
226
-
227
- $old_instance['post_type'] = array_unique( $post_types );
228
- } else
229
- $old_instance['post_type'] = array( 'post' );
230
-
231
- return $old_instance;
232
- }
233
-
234
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
post-views-counter.php CHANGED
@@ -2,7 +2,7 @@
2
  /*
3
  Plugin Name: Post Views Counter
4
  Description: Post Views Counter allows you to display how many times a post, page or custom post type had been viewed in a simple, fast and reliable way.
5
- Version: 1.3.8
6
  Author: Digital Factory
7
  Author URI: http://www.dfactory.eu/
8
  Plugin URI: http://www.dfactory.eu/plugins/post-views-counter/
@@ -31,7 +31,7 @@ if ( ! class_exists( 'Post_Views_Counter' ) ) {
31
  * Post Views Counter final class.
32
  *
33
  * @class Post_Views_Counter
34
- * @version 1.3.8
35
  */
36
  final class Post_Views_Counter {
37
 
@@ -84,7 +84,7 @@ if ( ! class_exists( 'Post_Views_Counter' ) ) {
84
  'icon_class' => 'dashicons-chart-bar',
85
  'toolbar_statistics' => true
86
  ],
87
- 'version' => '1.3.8'
88
  ];
89
 
90
  /**
@@ -111,34 +111,45 @@ if ( ! class_exists( 'Post_Views_Counter' ) ) {
111
  self::$instance = new Post_Views_Counter;
112
  self::$instance->define_constants();
113
 
114
- add_action( 'plugins_loaded', [ self::$instance, 'load_textdomain' ] );
115
-
116
- self::$instance->includes();
117
-
118
- // create settings API
119
- self::$instance->settings_api = new Post_Views_Counter_Settings_API(
120
- [
121
- 'object' => self::$instance,
122
- 'prefix' => 'post_views_counter',
123
- 'slug' => 'post-views-counter',
124
- 'domain' => 'post-views-counter',
125
- 'plugin' => 'Post Views Counter',
126
- 'plugin_url' => 'POST_VIEWS_COUNTER_URL'
127
- ]
128
- );
129
-
130
- self::$instance->functions = new Post_Views_Counter_Functions();
131
- self::$instance->update = new Post_Views_Counter_Update();
132
- self::$instance->settings = new Post_Views_Counter_Settings();
133
- self::$instance->admin = new Post_Views_Counter_Admin();
134
- self::$instance->query = new Post_Views_Counter_Query();
135
- self::$instance->cron = new Post_Views_Counter_Cron();
136
- self::$instance->counter = new Post_Views_Counter_Counter();
137
- self::$instance->columns = new Post_Views_Counter_Columns();
138
- self::$instance->crawler_detect = new Post_Views_Counter_Crawler_Detect();
139
- self::$instance->frontend = new Post_Views_Counter_Frontend();
140
- self::$instance->dashboard = new Post_Views_Counter_Dashboard();
141
- self::$instance->widgets = new Post_Views_Counter_Widgets();
 
 
 
 
 
 
 
 
 
 
 
142
  }
143
 
144
  return self::$instance;
@@ -150,8 +161,12 @@ if ( ! class_exists( 'Post_Views_Counter' ) ) {
150
  * @return void
151
  */
152
  private function define_constants() {
153
- define( 'POST_VIEWS_COUNTER_URL', plugins_url( '', __FILE__ ) );
154
- define( 'POST_VIEWS_COUNTER_REL_PATH', dirname( plugin_basename( __FILE__ ) ) . '/' );
 
 
 
 
155
  define( 'POST_VIEWS_COUNTER_PATH', plugin_dir_path( __FILE__ ) );
156
  }
157
 
@@ -182,6 +197,16 @@ if ( ! class_exists( 'Post_Views_Counter' ) ) {
182
  * @return void
183
  */
184
  public function __construct() {
 
 
 
 
 
 
 
 
 
 
185
  register_activation_hook( __FILE__, [ $this, 'multisite_activation' ] );
186
  register_deactivation_hook( __FILE__, [ $this, 'multisite_deactivation' ] );
187
 
2
  /*
3
  Plugin Name: Post Views Counter
4
  Description: Post Views Counter allows you to display how many times a post, page or custom post type had been viewed in a simple, fast and reliable way.
5
+ Version: 1.3.9
6
  Author: Digital Factory
7
  Author URI: http://www.dfactory.eu/
8
  Plugin URI: http://www.dfactory.eu/plugins/post-views-counter/
31
  * Post Views Counter final class.
32
  *
33
  * @class Post_Views_Counter
34
+ * @version 1.3.9
35
  */
36
  final class Post_Views_Counter {
37
 
84
  'icon_class' => 'dashicons-chart-bar',
85
  'toolbar_statistics' => true
86
  ],
87
+ 'version' => '1.3.9'
88
  ];
89
 
90
  /**
111
  self::$instance = new Post_Views_Counter;
112
  self::$instance->define_constants();
113
 
114
+ // short init?
115
+ if ( defined( 'SHORTINIT' ) && SHORTINIT ) {
116
+ include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-counter.php' );
117
+ include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-crawler-detect.php' );
118
+ include_once( POST_VIEWS_COUNTER_PATH . 'includes/functions.php' );
119
+
120
+ self::$instance->counter = new Post_Views_Counter_Counter();
121
+ self::$instance->crawler_detect = new Post_Views_Counter_Crawler_Detect();
122
+ // regular setup
123
+ } else {
124
+ add_action( 'plugins_loaded', [ self::$instance, 'load_textdomain' ] );
125
+
126
+ self::$instance->includes();
127
+
128
+ // create settings API
129
+ self::$instance->settings_api = new Post_Views_Counter_Settings_API(
130
+ [
131
+ 'object' => self::$instance,
132
+ 'prefix' => 'post_views_counter',
133
+ 'slug' => 'post-views-counter',
134
+ 'domain' => 'post-views-counter',
135
+ 'plugin' => 'Post Views Counter',
136
+ 'plugin_url' => 'POST_VIEWS_COUNTER_URL'
137
+ ]
138
+ );
139
+
140
+ self::$instance->functions = new Post_Views_Counter_Functions();
141
+ self::$instance->update = new Post_Views_Counter_Update();
142
+ self::$instance->settings = new Post_Views_Counter_Settings();
143
+ self::$instance->admin = new Post_Views_Counter_Admin();
144
+ self::$instance->query = new Post_Views_Counter_Query();
145
+ self::$instance->cron = new Post_Views_Counter_Cron();
146
+ self::$instance->counter = new Post_Views_Counter_Counter();
147
+ self::$instance->columns = new Post_Views_Counter_Columns();
148
+ self::$instance->crawler_detect = new Post_Views_Counter_Crawler_Detect();
149
+ self::$instance->frontend = new Post_Views_Counter_Frontend();
150
+ self::$instance->dashboard = new Post_Views_Counter_Dashboard();
151
+ self::$instance->widgets = new Post_Views_Counter_Widgets();
152
+ }
153
  }
154
 
155
  return self::$instance;
161
  * @return void
162
  */
163
  private function define_constants() {
164
+ // fix plugin_basename empty $wp_plugin_paths var
165
+ if ( ! ( defined( 'SHORTINIT' ) && SHORTINIT ) ) {
166
+ define( 'POST_VIEWS_COUNTER_URL', plugins_url( '', __FILE__ ) );
167
+ define( 'POST_VIEWS_COUNTER_REL_PATH', dirname( plugin_basename( __FILE__ ) ) . '/' );
168
+ }
169
+
170
  define( 'POST_VIEWS_COUNTER_PATH', plugin_dir_path( __FILE__ ) );
171
  }
172
 
197
  * @return void
198
  */
199
  public function __construct() {
200
+ // short init?
201
+ if ( defined( 'SHORTINIT' ) && SHORTINIT ) {
202
+ $this->options = [
203
+ 'general' => array_merge( $this->defaults['general'], get_option( 'post_views_counter_settings_general', $this->defaults['general'] ) ),
204
+ 'display' => array_merge( $this->defaults['display'], get_option( 'post_views_counter_settings_display', $this->defaults['display'] ) )
205
+ ];
206
+
207
+ return;
208
+ }
209
+
210
  register_activation_hook( __FILE__, [ $this, 'multisite_activation' ] );
211
  register_deactivation_hook( __FILE__, [ $this, 'multisite_deactivation' ] );
212
 
readme.txt CHANGED
@@ -4,8 +4,8 @@ Donate link: http://dfactory.eu/
4
  Tags: counter, hits, posts, postviews, post views, views, count, statistics, stats, analytics, pageviews, tracking
5
  Requires at least: 5.0
6
  Requires PHP: 5.2.4
7
- Tested up to: 5.8.1
8
- Stable tag: 1.3.8
9
  License: MIT License
10
  License URI: http://opensource.org/licenses/MIT
11
 
@@ -62,6 +62,9 @@ No questions yet.
62
 
63
  == Changelog ==
64
 
 
 
 
65
  = 1.3.8 =
66
  * Tweak: Improved user input escaping
67
 
@@ -225,5 +228,5 @@ Initial release
225
 
226
  == Upgrade Notice ==
227
 
228
- = 1.3.8 =
229
- * Tweak: Improved user input escaping
4
  Tags: counter, hits, posts, postviews, post views, views, count, statistics, stats, analytics, pageviews, tracking
5
  Requires at least: 5.0
6
  Requires PHP: 5.2.4
7
+ Tested up to: 5.8.2
8
+ Stable tag: 1.3.9
9
  License: MIT License
10
  License URI: http://opensource.org/licenses/MIT
11
 
62
 
63
  == Changelog ==
64
 
65
+ = 1.3.9 =
66
+ * Tweak: Remove unnecessary plugin files
67
+
68
  = 1.3.8 =
69
  * Tweak: Improved user input escaping
70
 
228
 
229
  == Upgrade Notice ==
230
 
231
+ = 1.3.9 =
232
+ * Tweak: Remove unnecessary plugin files