PluginProbe ʕ •ᴥ•ʔ
Post Views Counter / trunk
Post Views Counter vtrunk
1.7.13 1.7.12 1.7.11 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2.0 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.2 1.3.2.1 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.7.0 1.7.1 1.7.10 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9
post-views-counter / includes / class-settings-general.php
post-views-counter / includes Last commit date
class-admin.php 3 months ago class-columns-modal.php 1 month ago class-columns.php 2 weeks ago class-counter.php 2 months ago class-crawler-detect.php 7 months ago class-cron.php 1 month ago class-dashboard.php 1 month ago class-emails-mailer.php 1 month ago class-emails-period.php 1 month ago class-emails-query.php 1 month ago class-emails-scheduler.php 1 month ago class-emails-template.php 1 month ago class-emails.php 1 month ago class-frontend.php 2 weeks ago class-functions.php 1 year ago class-import.php 2 months ago class-integration-gutenberg.php 6 months ago class-integrations.php 2 months ago class-query.php 2 months ago class-settings-api.php 1 month ago class-settings-display.php 4 months ago class-settings-emails.php 1 month ago class-settings-general.php 1 month ago class-settings-integrations.php 5 months ago class-settings-other.php 1 month ago class-settings-reports.php 1 month ago class-settings.php 1 month ago class-toolbar.php 3 months ago class-traffic-signals.php 2 months ago class-update.php 1 month ago class-widgets.php 1 month ago functions.php 1 month ago
class-settings-general.php
854 lines
1 <?php
2 // exit if accessed directly
3 if ( ! defined( 'ABSPATH' ) )
4 exit;
5
6 /**
7 * Post_Views_Counter_Settings_General class.
8 *
9 * @class Post_Views_Counter_Settings_General
10 */
11 class Post_Views_Counter_Settings_General {
12
13 private $pvc;
14
15 /**
16 * Class constructor.
17 *
18 * @return void
19 */
20 public function __construct() {
21 $this->pvc = Post_Views_Counter();
22
23 // actions
24 add_action( 'admin_init', [ $this, 'update_counter_mode' ], 12 );
25 }
26
27 /**
28 * Update counter mode.
29 *
30 * @return void
31 */
32 public function update_counter_mode() {
33 // get settings
34 $settings = $this->pvc->settings_api->get_settings();
35
36 // fast ajax as active but not available counter mode?
37 if ( $this->pvc->options['general']['counter_mode'] === 'ajax' && in_array( 'ajax', $settings['post-views-counter']['fields']['counter_mode']['disabled'], true ) ) {
38 // set standard javascript ajax calls
39 $this->pvc->options['general']['counter_mode'] = 'js';
40
41 // update database options
42 update_option( 'post_views_counter_settings_general', $this->pvc->options['general'] );
43 }
44 }
45
46 /**
47 * Get available counter modes.
48 *
49 * @return array
50 */
51 public function get_counter_modes() {
52 // counter modes
53 $modes = [
54 'php' => __( 'PHP', 'post-views-counter' ),
55 'js' => __( 'JavaScript', 'post-views-counter' ),
56 'rest_api' => __( 'REST API', 'post-views-counter' ),
57 'ajax' => __( 'Fast AJAX', 'post-views-counter' )
58 ];
59
60 return apply_filters( 'pvc_get_counter_modes', $modes );
61 }
62
63 /**
64 * Get sections for general tab.
65 *
66 * @return array
67 */
68 public function get_sections() {
69 return [
70 'post_views_counter_general_tracking_targets' => [
71 'tab' => 'general',
72 'title' => __( 'Tracking Targets', 'post-views-counter' ),
73 'callback' => [ $this, 'section_tracking_targets' ],
74 ],
75 'post_views_counter_general_tracking_behavior' => [
76 'tab' => 'general',
77 'title' => __( 'Tracking Behavior', 'post-views-counter' ),
78 'callback' => [ $this, 'section_tracking_behavior' ],
79 ],
80 'post_views_counter_general_exclusions' => [
81 'tab' => 'general',
82 'title' => __( 'Visitor Exclusions', 'post-views-counter' ),
83 'callback' => [ $this, 'section_tracking_exclusions' ],
84 ],
85 'post_views_counter_general_performance' => [
86 'tab' => 'general',
87 'title' => __( 'Performance & Caching', 'post-views-counter' ),
88 'callback' => [ $this, 'section_tracking_performance' ],
89 ]
90 ];
91 }
92
93 /**
94 * Get fields for general tab.
95 *
96 * @return array
97 */
98 public function get_fields() {
99 // time types
100 $time_types = [
101 'minutes' => __( 'minutes', 'post-views-counter' ),
102 'hours' => __( 'hours', 'post-views-counter' ),
103 'days' => __( 'days', 'post-views-counter' ),
104 'weeks' => __( 'weeks', 'post-views-counter' ),
105 'months' => __( 'months', 'post-views-counter' ),
106 'years' => __( 'years', 'post-views-counter' )
107 ];
108
109 // user groups
110 $groups = [
111 'robots' => __( 'crawlers', 'post-views-counter' ),
112 'ai_bots' => __( 'AI bots', 'post-views-counter' ),
113 'users' => __( 'logged in users', 'post-views-counter' ),
114 'guests' => __( 'guests', 'post-views-counter' ),
115 'roles' => __( 'selected user roles', 'post-views-counter' )
116 ];
117
118 // get user roles
119 $user_roles = $this->pvc->functions->get_user_roles();
120
121 // get post types
122 $post_types = $this->pvc->functions->get_post_types();
123
124 return [
125 'post_types_count' => [
126 'tab' => 'general',
127 'title' => __( 'Post Types', 'post-views-counter' ),
128 'section' => 'post_views_counter_general_tracking_targets',
129 'type' => 'checkbox',
130 'description' => __( 'Select post types whose views should be counted.', 'post-views-counter' ),
131 'options' => $post_types
132 ],
133 'taxonomies_count' => [
134 'tab' => 'general',
135 'title' => __( 'Taxonomies', 'post-views-counter' ),
136 'section' => 'post_views_counter_general_tracking_targets',
137 'type' => 'boolean',
138 'label' => __( 'Enable counting views on taxonomy term archive pages.', 'post-views-counter' ),
139 'class' => 'pvc-pro',
140 'disabled' => true,
141 'skip_saving' => true,
142 'value' => false,
143 'pro_only' => true
144 ],
145 'users_count' => [
146 'tab' => 'general',
147 'title' => __( 'Author Archives', 'post-views-counter' ),
148 'section' => 'post_views_counter_general_tracking_targets',
149 'type' => 'boolean',
150 'label' => __( 'Enable counting views on author archive pages.', 'post-views-counter' ),
151 'class' => 'pvc-pro',
152 'disabled' => true,
153 'skip_saving' => true,
154 'value' => false,
155 'pro_only' => true
156 ],
157 'other_count' => [
158 'tab' => 'general',
159 'title' => __( 'Other Pages', 'post-views-counter' ),
160 'section' => 'post_views_counter_general_tracking_targets',
161 'type' => 'boolean',
162 'label' => __( 'Track views on the front page, post type archives, date archives, search results, 404 pages, and WordPress authentication pages such as login, registration, and password reset.', 'post-views-counter' ),
163 'class' => 'pvc-pro',
164 'disabled' => true,
165 'skip_saving' => true,
166 'value' => false,
167 'pro_only' => true
168 ],
169 'technology_count' => [
170 'tab' => 'general',
171 'title' => __( 'Traffic Sources', 'post-views-counter' ),
172 'section' => 'post_views_counter_general_tracking_targets',
173 'type' => 'boolean',
174 'label' => __( 'Collect aggregate stats about visitors\' browsers, devices, operating systems and referrers.', 'post-views-counter' ),
175 'class' => 'pvc-pro',
176 'disabled' => true,
177 'skip_saving' => true,
178 'value' => false,
179 'pro_only' => true
180 ],
181 'counter_mode' => [
182 'tab' => 'general',
183 'title' => __( 'Counter Mode', 'post-views-counter' ),
184 'section' => 'post_views_counter_general_tracking_behavior',
185 'type' => 'radio',
186 'description' => __( 'Choose how views are recorded. If you use caching, select JavaScript, REST API or Fast AJAX (up to <code>10+</code> times faster).', 'post-views-counter' ),
187 'class' => 'pvc-pro-extended',
188 'options' => $this->get_counter_modes(),
189 'disabled' => [ 'ajax' ],
190 'pro_only' => [ 'ajax' ]
191 ],
192 'data_storage' => [
193 'tab' => 'general',
194 'title' => __( 'Data Storage', 'post-views-counter' ),
195 'section' => 'post_views_counter_general_tracking_behavior',
196 'type' => 'radio',
197 'class' => 'pvc-pro',
198 'skip_saving' => true,
199 'description' => __( "Choose how to store the content views data in the user's browser - with or without cookies.", 'post-views-counter' ),
200 'pro_only' => true,
201 'options' => [
202 'cookies' => __( 'Cookies', 'post-views-counter' ),
203 'cookieless' => __( 'Cookieless', 'post-views-counter' )
204 ],
205 'disabled' => [ 'cookies', 'cookieless' ],
206 'value' => 'cookies'
207 ],
208 'time_between_counts' => [
209 'tab' => 'general',
210 'title' => __( 'Count Interval', 'post-views-counter' ),
211 'section' => 'post_views_counter_general_tracking_behavior',
212 'type' => 'custom',
213 'description' => '',
214 'min' => 0,
215 'max' => 720,
216 'type_value' => 'hours',
217 'type_label' => __( 'hours', 'post-views-counter' ),
218 'callback' => [ $this, 'setting_time_between_counts' ],
219 'validate' => [ $this, 'validate_time_between_counts' ]
220 ],
221 'count_time' => [
222 'tab' => 'general',
223 'title' => __( 'Count Time', 'post-views-counter' ),
224 'section' => 'post_views_counter_general_tracking_behavior',
225 'type' => 'radio',
226 'class' => 'pvc-pro',
227 'disabled' => true,
228 'skip_saving' => true,
229 'description' => __( 'Whether to store the views using GMT timezone or adjust it to the GMT offset of the site.', 'post-views-counter' ),
230 'options' => [
231 'gmt' => __( 'GMT Time', 'post-views-counter' ),
232 'local' => __( 'Local Time', 'post-views-counter' )
233 ],
234 'pro_only' => true
235 ],
236 'strict_counts' => [
237 'tab' => 'general',
238 'title' => __( 'Strict Counts', 'post-views-counter' ),
239 'section' => 'post_views_counter_general_tracking_behavior',
240 'type' => 'boolean',
241 'class' => 'pvc-pro',
242 'disabled' => true,
243 'skip_saving' => true,
244 'value' => false,
245 'description' => '',
246 'label' => __( 'Prevent bypassing the count interval (for example by using incognito mode or clearing cookies).', 'post-views-counter' ),
247 'pro_only' => true
248 ],
249 'reset_counts' => [
250 'tab' => 'general',
251 'title' => __( 'Cleanup Interval', 'post-views-counter' ),
252 'section' => 'post_views_counter_general_tracking_behavior',
253 'type' => 'custom',
254 'description' => sprintf( __( 'Delete daily content view data older than the period specified above. Enter %s to keep data regardless of age. Cleanup runs once per day.', 'post-views-counter' ), '<code>0</code>' ),
255 'min' => 0,
256 'max' => 999999,
257 'options' => $time_types,
258 'callback' => [ $this, 'setting_reset_counts' ],
259 'validate' => [ $this, 'validate_reset_counts' ]
260 ],
261 'caching_compatibility' => [
262 'tab' => 'general',
263 'title' => __( 'Caching Compatibility', 'post-views-counter' ),
264 'section' => 'post_views_counter_general_performance',
265 'type' => 'boolean',
266 'class' => 'pvc-pro',
267 'disabled' => true,
268 'value' => false,
269 'skip_saving' => true,
270 'animation' => 'slide',
271 'available' => $this->is_caching_compatibility_available(),
272 'label' => $this->get_caching_compatibility_label(),
273 'description' => $this->get_caching_compatibility_description(),
274 'pro_only' => true
275 ],
276 'object_cache' => [
277 'tab' => 'general',
278 'title' => __( 'Object Cache Support', 'post-views-counter' ),
279 'section' => 'post_views_counter_general_performance',
280 'type' => 'boolean',
281 'class' => 'pvc-pro',
282 'disabled' => true,
283 'value' => false,
284 'skip_saving' => true,
285 'animation' => 'slide',
286 'available' => $this->is_object_cache_available(),
287 'label' => $this->get_object_cache_label(),
288 'description' => $this->get_object_cache_description(),
289 'pro_only' => true
290 ],
291 'exclude_groups' => [
292 'tab' => 'general',
293 'title' => __( 'Exclude Visitors', 'post-views-counter' ),
294 'section' => 'post_views_counter_general_exclusions',
295 'type' => 'checkbox',
296 'description' => __( 'Use this to exclude specific visitor groups from counting views.', 'post-views-counter' ),
297 'class' => 'pvc-pro-extended',
298 'options' => $groups,
299 'disabled' => [ 'ai_bots' ],
300 'pro_only' => [ 'ai_bots' ],
301 'name' => 'post_views_counter_settings_general[exclude][groups]',
302 'value' => $this->pvc->options['general']['exclude']['groups'],
303 'validate' => [ $this, 'validate_exclude_groups' ]
304 ],
305 'exclude_roles' => [
306 'tab' => 'general',
307 'title' => __( 'Exclude User Roles', 'post-views-counter' ),
308 'section' => 'post_views_counter_general_exclusions',
309 'type' => 'checkbox',
310 'description' => __( 'Use this to exclude specific user roles from counting views.', 'post-views-counter' ),
311 'options' => $user_roles,
312 'logic' => [
313 [
314 'field' => 'exclude_groups',
315 'operator' => 'contains',
316 'value' => 'roles'
317 ]
318 ],
319 'animation' => 'slide',
320 'name' => 'post_views_counter_settings_general[exclude][roles]',
321 'value' => $this->pvc->options['general']['exclude']['roles'],
322 'validate' => [ $this, 'validate_exclude_roles' ]
323 ],
324 'exclude_ips' => [
325 'tab' => 'general',
326 'title' => __( 'Exclude IPs', 'post-views-counter' ),
327 'section' => 'post_views_counter_general_exclusions',
328 'type' => 'custom',
329 'description' => '',
330 'callback' => [ $this, 'setting_exclude_ips' ],
331 'validate' => [ $this, 'validate_exclude_ips' ]
332 ]
333 ];
334 }
335
336 /**
337 * Setting: taxonomies count.
338 *
339 * @param array $field
340 * @return string
341 */
342 public function setting_taxonomies_count( $field ) {
343 $html = '
344 <label class="pvc-disabled"><input id="post_views_counter_general_taxonomies_count" type="checkbox" name="" value="" disabled role="switch" />' . esc_html( $field['label'] ) . '</label>';
345
346 return $html;
347 }
348
349 /**
350 * Setting: users count.
351 *
352 * @param array $field
353 * @return string
354 */
355 public function setting_users_count( $field ) {
356 $html = '
357 <label class="pvc-disabled"><input id="post_views_counter_general_users_count" type="checkbox" name="" value="" disabled role="switch" />' . esc_html( $field['label'] ) . '</label>';
358
359 return $html;
360 }
361
362 /**
363 * Setting: count interval.
364 *
365 * @param array $field
366 * @return string
367 */
368 public function setting_time_between_counts( $field ) {
369 $html = '
370 <div class="pvc-field-group horizontal">
371 <input size="6" type="number" min="' . ( (int) $field['min'] ) . '" max="' . ( (int) $field['max'] ) . '" name="post_views_counter_settings_general[time_between_counts][number]" value="' . esc_attr( $this->pvc->options['general']['time_between_counts']['number'] ) . '" />
372 <input type="hidden" name="post_views_counter_settings_general[time_between_counts][type]" value="' . esc_attr( $field['type_value'] ) . '" />
373 <span>' . esc_html( $field['type_label'] ) . '</span>
374 </div>
375 <p class="description">' . __( 'Minimum time between counting new views from the same visitor, in hours. Enter <code>0</code> to count every page view.', 'post-views-counter' ) . '</p>';
376
377 return $html;
378 }
379
380 /**
381 * Validate count interval.
382 *
383 * @param array $input
384 * @param array $field
385 * @return array
386 */
387 public function validate_time_between_counts( $input, $field ) {
388 $input['time_between_counts'] = $this->pvc->normalize_time_between_counts(
389 isset( $input['time_between_counts'] ) ? $input['time_between_counts'] : null,
390 $this->pvc->defaults['general']['time_between_counts']
391 );
392
393 return $input;
394 }
395
396 /**
397 * Setting: reset data interval.
398 *
399 * @param array $field
400 * @return string
401 */
402 public function setting_reset_counts( $field ) {
403 $html = '
404 <input size="6" type="number" min="' . ( (int) $field['min'] ) . '" max="' . ( (int) $field['max'] ) . '" name="post_views_counter_settings_general[reset_counts][number]" value="' . esc_attr( $this->pvc->options['general']['reset_counts']['number'] ) . '" />
405 <select name="post_views_counter_settings_general[reset_counts][type]">';
406
407 foreach ( array_slice( $field['options'], 2, null, true ) as $type => $type_name ) {
408 $html .= '
409 <option value="' . esc_attr( $type ) . '" ' . selected( $type, $this->pvc->options['general']['reset_counts']['type'], false ) . '>' . esc_html( $type_name ) . '</option>';
410 }
411
412 $html .= '
413 </select>';
414
415 return $html;
416 }
417
418 /**
419 * Validate reset data interval.
420 *
421 * @param array $input
422 * @param array $field
423 * @return array
424 */
425 public function validate_reset_counts( $input, $field ) {
426 // number
427 $input['reset_counts']['number'] = isset( $input['reset_counts']['number'] ) ? (int) $input['reset_counts']['number'] : $this->pvc->defaults['general']['reset_counts']['number'];
428
429 if ( $input['reset_counts']['number'] < $field['min'] || $input['reset_counts']['number'] > $field['max'] )
430 $input['reset_counts']['number'] = $this->pvc->defaults['general']['reset_counts']['number'];
431
432 // type
433 $input['reset_counts']['type'] = isset( $input['reset_counts']['type'], $field['options'][$input['reset_counts']['type']] ) ? $input['reset_counts']['type'] : $this->pvc->defaults['general']['reset_counts']['type'];
434
435 // run cron on next visit?
436 $input['cron_run'] = ( $input['reset_counts']['number'] > 0 );
437
438 // cron update?
439 $input['cron_update'] = ( $input['cron_run'] && ( $this->pvc->options['general']['reset_counts']['number'] !== $input['reset_counts']['number'] || $this->pvc->options['general']['reset_counts']['type'] !== $input['reset_counts']['type'] ) );
440
441 return $input;
442 }
443
444 /**
445 * Setting: object cache.
446 *
447 * @param array $field
448 * @return string
449 */
450 public function setting_object_cache( $field ) {
451 $html = '
452 <input size="4" type="number" min="' . ( (int) $field['min'] ) . '" max="' . ( (int) $field['max'] ) . '" name="" value="0" disabled /> <span>' . __( 'minutes', 'post-views-counter' ) . '</span>
453 <p class="">' . __( 'Persistent Object Cache', 'post-views-counter' ) . ': <span class="' . ( wp_using_ext_object_cache() ? '' : 'un' ) . 'available">' . ( wp_using_ext_object_cache() ? __( 'available', 'post-views-counter' ) : __( 'unavailable', 'post-views-counter' ) ) . '</span></p>
454 <p class="description">' . sprintf( __( 'How often to flush cached view counts from the object cache into the database. This feature is used only if a persistent object cache like %s or %s is detected and the interval is greater than %s. 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. The maximum value is %s which means 24 hours.%sNotice:%s Potential data loss may occur if the object cache is cleared/unavailable for the duration of the interval.', 'post-views-counter' ), '<code>Redis</code>', '<code>Memcached</code>', '<code>0</code>', '<code>1440</code>', '<br /><strong> ', '</strong>' ) . '</p>';
455
456 return $html;
457 }
458
459 /**
460 * Setting: exclude visitors.
461 *
462 * @param array $field
463 * @return string
464 */
465
466
467 /**
468 * Validate exclude visitors.
469 *
470 * @param array $input
471 * @param array $field
472 * @return array
473 */
474 public function validate_exclude_groups( $input, $field ) {
475 $groups = [];
476
477 if ( is_array( $input ) ) {
478 foreach ( $input as $group ) {
479 // sanitize value
480 $group = sanitize_key( $group );
481
482 // disallow disabled checkboxes
483 if ( ! empty( $field['disabled'] ) && in_array( $group, $field['disabled'], true ) )
484 continue;
485
486 if ( isset( $field['options'][$group] ) )
487 $groups[] = $group;
488 }
489 }
490
491 return array_unique( $groups );
492 }
493
494 public function validate_exclude_roles( $input, $field ) {
495 $roles = [];
496
497 if ( is_array( $input ) ) {
498 foreach ( $input as $role ) {
499 // sanitize value
500 $role = sanitize_key( $role );
501
502 if ( isset( $field['options'][$role] ) )
503 $roles[] = $role;
504 }
505 }
506
507 return array_unique( $roles );
508 }
509
510 /**
511 * Setting: exclude IP addresses.
512 *
513 * @return string
514 */
515 public function setting_exclude_ips() {
516 // get ip addresses
517 $ips = $this->pvc->options['general']['exclude_ips'];
518 $current_ip = '';
519
520 if ( isset( $this->pvc->counter ) && method_exists( $this->pvc->counter, 'get_user_ip' ) )
521 $current_ip = $this->pvc->counter->get_user_ip();
522
523 if ( $current_ip === '' && isset( $_SERVER['REMOTE_ADDR'] ) )
524 $current_ip = sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) );
525
526 $html = '<div class="pvc-ip-box-group">';
527
528 // any ip addresses?
529 if ( ! empty( $ips ) ) {
530 foreach ( $ips as $key => $ip ) {
531 $html .= '
532 <div class="pvc-ip-box">
533 <input type="text" name="post_views_counter_settings_general[exclude_ips][]" value="' . esc_attr( $ip ) . '" /> <a href="#" class="pvc-remove-exclude-ip" title="' . esc_attr__( 'Remove', 'post-views-counter' ) . '">' . esc_html__( 'Remove', 'post-views-counter' ) . '</a>
534 </div>';
535 }
536 } else {
537 $html .= '
538 <div class="pvc-ip-box">
539 <input type="text" name="post_views_counter_settings_general[exclude_ips][]" value="" /> <a href="#" class="pvc-remove-exclude-ip pvc-hidden" title="' . esc_attr__( 'Remove', 'post-views-counter' ) . '">' . esc_html__( 'Remove', 'post-views-counter' ) . '</a>
540 </div>';
541 }
542
543 $html .= '</div>';
544
545 $html .= '
546 <div class="pvc-field-group pvc-buttons-group">
547 <input type="button" class="button outline pvc-add-exclude-ip" value="' . esc_attr__( 'Add new', 'post-views-counter' ) . '" /> <input type="button" class="button outline pvc-add-current-ip" value="' . esc_attr__( 'Add my current IP', 'post-views-counter' ) . '" data-rel="' . esc_attr( $current_ip ) . '" />
548 </div>';
549
550 $html .= '<p class="description">' . esc_html__( 'Add IPv4 or IPv6 addresses to exclude them from counting views. Wildcards are supported for IPv4 only (e.g. 192.168.0.*).', 'post-views-counter' ) . '</p>';
551
552 return $html;
553 }
554
555 /**
556 * Validate exclude IP addresses.
557 *
558 * @param array $input
559 * @param array $field
560 * @return array
561 */
562 public function validate_exclude_ips( $input, $field ) {
563 // any ip addresses?
564 if ( isset( $input['exclude_ips'] ) ) {
565 $ips = [];
566
567 foreach ( $input['exclude_ips'] as $ip ) {
568 $validated_ip = '';
569
570 if ( isset( $this->pvc->counter ) && method_exists( $this->pvc->counter, 'validate_excluded_ip' ) )
571 $validated_ip = $this->pvc->counter->validate_excluded_ip( $ip );
572
573 if ( $validated_ip !== '' )
574 $ips[] = $validated_ip;
575 }
576
577 $input['exclude_ips'] = array_unique( $ips );
578 }
579
580 return $input;
581 }
582
583 /**
584 * Section description: tracking targets.
585 *
586 * @return void
587 */
588 public function section_tracking_targets() {
589 echo '<p class="description">' . esc_html__( 'Control which post types, archives and other content types are included in view counting.', 'post-views-counter' ) . '</p>';
590 }
591
592 /**
593 * Section description: tracking behavior.
594 *
595 * @return void
596 */
597 public function section_tracking_behavior() {
598 echo '<p class="description">' . esc_html__( 'Control how views are recorded — counting mode, intervals, time zone, and cleanup.', 'post-views-counter' ) . '</p>';
599 }
600
601 /**
602 * Section description: tracking exclusions.
603 *
604 * @return void
605 */
606 public function section_tracking_exclusions() {
607 echo '<p class="description">' . esc_html__( 'Exclude specific visitor groups or IP addresses from incrementing view counts.', 'post-views-counter' ) . '</p>';
608 }
609
610 /**
611 * Section description: performance & caching.
612 *
613 * @return void
614 */
615 public function section_tracking_performance() {
616 echo '<p class="description">' . esc_html__( 'Configure caching compatibility and object-cache handling for counting.', 'post-views-counter' ) . '</p>';
617 }
618
619 /**
620 * Get caching compatibility description.
621 *
622 * @return string
623 */
624 public function get_caching_compatibility_description() {
625 // get active caching plugins
626 $active_plugins = $this->get_active_caching_plugins();
627
628 if ( ! empty( $active_plugins ) ) {
629 $active_plugins_html = [];
630
631 $description = esc_html__( 'Currently detected active caching plugins', 'post-views-counter' ) . ': ';
632
633 foreach ( $active_plugins as $plugin ) {
634 $active_plugins_html[] = '<code>' . esc_html( $plugin ) . '</code>';
635 }
636
637 $description .= implode( ', ', $active_plugins_html ) . '.';
638 } else {
639 $description = esc_html__( 'No compatible caching plugins found.', 'post-views-counter' );
640 }
641
642 return $description;
643 }
644
645 /**
646 * Get caching compatibility label with availability indicator.
647 *
648 * @return string
649 */
650 public function get_caching_compatibility_label() {
651 $label = __( 'Enable compatibility tweaks for supported caching plugins.', 'post-views-counter' );
652
653 // add availability indicator when the feature is available
654 if ( ! class_exists( 'Post_Views_Counter_Pro' ) && $this->is_caching_compatibility_available() ) {
655 $label = '<span class="pvc-availability-status available">' . esc_html__( '(available)', 'post-views-counter' ) . '</span> ' . $label;
656 }
657
658 return $label;
659 }
660
661 /**
662 * Get object cache label with availability indicator.
663 *
664 * @return string
665 */
666 public function get_object_cache_label() {
667 $label = __( 'Enable Redis or Memcached object cache optimization.', 'post-views-counter' );
668
669 // add availability indicator when the feature is available
670 if ( ! class_exists( 'Post_Views_Counter_Pro' ) && $this->is_object_cache_available() ) {
671 $label = '<span class="pvc-availability-status available">' . esc_html__( '(available)', 'post-views-counter' ) . '</span> ' . $label;
672 }
673
674 return $label;
675 }
676
677 /**
678 * Check if caching compatibility feature is available.
679 *
680 * @return bool
681 */
682 public function is_caching_compatibility_available() {
683 $active_plugins = $this->get_active_caching_plugins();
684
685 return ! empty( $active_plugins );
686 }
687
688 /**
689 * Check if object cache feature is available.
690 *
691 * @return bool
692 */
693 public function is_object_cache_available() {
694 return wp_using_ext_object_cache();
695 }
696
697 /**
698 * Get object cache description based on availability.
699 *
700 * @return string
701 */
702 public function get_object_cache_description() {
703 if ( $this->is_object_cache_available() ) {
704 return __( 'Persistent object cache has been detected.', 'post-views-counter' );
705 }
706
707 return sprintf( __( 'This feature requires a persistent object cache like %s or %s to be installed and activated.', 'post-views-counter' ), '<code>Redis</code>', '<code>Memcached</code>' );
708 }
709
710 /**
711 * Extend active caching plugins.
712 *
713 * @param array $plugins
714 *
715 * @return array
716 */
717 public function extend_active_caching_plugins( $plugins ) {
718 // breeze
719 if ( $this->is_plugin_active( 'breeze' ) )
720 $plugins[] = 'Breeze';
721
722 return $plugins;
723 }
724
725 /**
726 * Check whether specified plugin is active.
727 *
728 * @param bool $is_plugin_active
729 * @param string $plugin
730 *
731 * @return bool
732 */
733 public function extend_is_plugin_active( $is_plugin_active, $plugin ) {
734 // breeze
735 if ( $plugin === 'breeze' && class_exists( 'Breeze_PurgeCache' ) && class_exists( 'Breeze_Options_Reader' ) && function_exists( 'breeze_get_option' ) && function_exists( 'breeze_update_option' ) && defined( 'BREEZE_VERSION' ) && version_compare( BREEZE_VERSION, '2.0.30', '>=' ) )
736 $is_plugin_active = true;
737
738 return $is_plugin_active;
739 }
740
741 /**
742 * Get active caching plugins.
743 *
744 * @return array
745 */
746 public function get_active_caching_plugins() {
747 $active_plugins = [];
748
749 // autoptimize
750 if ( $this->is_plugin_active( 'autoptimize' ) )
751 $active_plugins[] = 'Autoptimize';
752
753 // hummingbird
754 if ( $this->is_plugin_active( 'hummingbird' ) )
755 $active_plugins[] = 'Hummingbird';
756
757 // litespeed
758 if ( $this->is_plugin_active( 'litespeed' ) )
759 $active_plugins[] = 'LiteSpeed Cache';
760
761 // speed optimizer
762 if ( $this->is_plugin_active( 'speedoptimizer' ) )
763 $active_plugins[] = 'Speed Optimizer';
764
765 // speedycache
766 if ( $this->is_plugin_active( 'speedycache' ) )
767 $active_plugins[] = 'SpeedyCache';
768
769 // wp fastest cache
770 if ( $this->is_plugin_active( 'wpfastestcache' ) )
771 $active_plugins[] = 'WP Fastest Cache';
772
773 // wp-optimize
774 if ( $this->is_plugin_active( 'wpoptimize' ) )
775 $active_plugins[] = 'WP-Optimize';
776
777 // wp rocket
778 if ( $this->is_plugin_active( 'wprocket' ) )
779 $active_plugins[] = 'WP Rocket';
780
781 return apply_filters( 'pvc_active_caching_plugins', $active_plugins );
782 }
783
784 /**
785 * Check whether specified plugin is active.
786 *
787 * @param string $plugin
788 *
789 * @return bool
790 */
791 public function is_plugin_active( $plugin = '' ) {
792 // set default flag
793 $is_plugin_active = false;
794
795 switch ( $plugin ) {
796 // autoptimize
797 case 'autoptimize':
798 if ( function_exists( 'autoptimize' ) && defined( 'AUTOPTIMIZE_PLUGIN_VERSION' ) && version_compare( AUTOPTIMIZE_PLUGIN_VERSION, '2.4', '>=' ) )
799 $is_plugin_active = true;
800 break;
801
802 // hummingbird
803 case 'hummingbird':
804 if ( class_exists( 'Hummingbird\\WP_Hummingbird' ) && defined( 'WPHB_VERSION' ) && version_compare( WPHB_VERSION, '2.1.0', '>=' ) )
805 $is_plugin_active = true;
806 break;
807
808 // litespeed
809 case 'litespeed':
810 if ( class_exists( 'LiteSpeed\Core' ) && defined( 'LSCWP_CUR_V' ) && version_compare( LSCWP_CUR_V, '3.0', '>=' ) )
811 $is_plugin_active = true;
812 break;
813
814 // speed optimizer
815 case 'speedoptimizer':
816 global $siteground_optimizer_loader;
817
818 if ( ! empty( $siteground_optimizer_loader ) && is_object( $siteground_optimizer_loader ) && is_a( $siteground_optimizer_loader, 'SiteGround_Optimizer\Loader\Loader' ) && defined( '\SiteGround_Optimizer\VERSION' ) && version_compare( \SiteGround_Optimizer\VERSION, '5.5', '>=' ) )
819 $is_plugin_active = true;
820 break;
821
822 // speedycache
823 case 'speedycache':
824 if ( class_exists( 'SpeedyCache' ) && defined( 'SPEEDYCACHE_VERSION' ) && function_exists( 'speedycache_delete_cache' ) && version_compare( SPEEDYCACHE_VERSION, '1.0.0', '>=' ) )
825 $is_plugin_active = true;
826 break;
827
828 // wp fastest cache
829 case 'wpfastestcache':
830 if ( function_exists( 'wpfc_clear_all_cache' ) )
831 $is_plugin_active = true;
832 break;
833
834 // wp-optimize
835 case 'wpoptimize':
836 if ( function_exists( 'WP_Optimize' ) && defined( 'WPO_VERSION' ) && version_compare( WPO_VERSION, '3.0.12', '>=' ) )
837 $is_plugin_active = true;
838 break;
839
840 // wp rocket
841 case 'wprocket':
842 if ( function_exists( 'rocket_init' ) && defined( 'WP_ROCKET_VERSION' ) && version_compare( WP_ROCKET_VERSION, '3.8', '>=' ) )
843 $is_plugin_active = true;
844 break;
845
846 // other caching plugin
847 default:
848 $is_plugin_active = apply_filters( 'pvc_is_plugin_active', false, $plugin );
849 }
850
851 return $is_plugin_active;
852 }
853 }
854