class-admin.php
5 months ago
class-columns.php
5 months ago
class-counter.php
5 months ago
class-crawler-detect.php
5 months ago
class-cron.php
5 months ago
class-dashboard.php
5 months ago
class-frontend.php
5 months ago
class-functions.php
5 months ago
class-import.php
5 months ago
class-integration-gutenberg.php
5 months ago
class-integrations.php
5 months ago
class-query.php
5 months ago
class-settings-api.php
5 months ago
class-settings-display.php
5 months ago
class-settings-general.php
5 months ago
class-settings-integrations.php
5 months ago
class-settings-other.php
5 months ago
class-settings-reports.php
5 months ago
class-settings.php
5 months ago
class-toolbar.php
5 months ago
class-update.php
5 months ago
class-widgets.php
5 months ago
functions.php
5 months ago
class-settings-general.php
849 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, and 404 pages.', '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' => 999999, |
| 216 | 'options' => $time_types, |
| 217 | 'callback' => [ $this, 'setting_time_between_counts' ], |
| 218 | 'validate' => [ $this, 'validate_time_between_counts' ] |
| 219 | ], |
| 220 | 'count_time' => [ |
| 221 | 'tab' => 'general', |
| 222 | 'title' => __( 'Count Time', 'post-views-counter' ), |
| 223 | 'section' => 'post_views_counter_general_tracking_behavior', |
| 224 | 'type' => 'radio', |
| 225 | 'class' => 'pvc-pro', |
| 226 | 'disabled' => true, |
| 227 | 'skip_saving' => true, |
| 228 | 'description' => __( 'Whether to store the views using GMT timezone or adjust it to the GMT offset of the site.', 'post-views-counter' ), |
| 229 | 'options' => [ |
| 230 | 'gmt' => __( 'GMT Time', 'post-views-counter' ), |
| 231 | 'local' => __( 'Local Time', 'post-views-counter' ) |
| 232 | ], |
| 233 | 'pro_only' => true |
| 234 | ], |
| 235 | 'strict_counts' => [ |
| 236 | 'tab' => 'general', |
| 237 | 'title' => __( 'Strict Counts', 'post-views-counter' ), |
| 238 | 'section' => 'post_views_counter_general_tracking_behavior', |
| 239 | 'type' => 'boolean', |
| 240 | 'class' => 'pvc-pro', |
| 241 | 'disabled' => true, |
| 242 | 'skip_saving' => true, |
| 243 | 'value' => false, |
| 244 | 'description' => '', |
| 245 | 'label' => __( 'Prevent bypassing the count interval (for example by using incognito mode or clearing cookies).', 'post-views-counter' ), |
| 246 | 'pro_only' => true |
| 247 | ], |
| 248 | 'reset_counts' => [ |
| 249 | 'tab' => 'general', |
| 250 | 'title' => __( 'Cleanup Interval', 'post-views-counter' ), |
| 251 | 'section' => 'post_views_counter_general_tracking_behavior', |
| 252 | 'type' => 'custom', |
| 253 | '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>' ), |
| 254 | 'min' => 0, |
| 255 | 'max' => 999999, |
| 256 | 'options' => $time_types, |
| 257 | 'callback' => [ $this, 'setting_reset_counts' ], |
| 258 | 'validate' => [ $this, 'validate_reset_counts' ] |
| 259 | ], |
| 260 | 'caching_compatibility' => [ |
| 261 | 'tab' => 'general', |
| 262 | 'title' => __( 'Caching Compatibility', 'post-views-counter' ), |
| 263 | 'section' => 'post_views_counter_general_performance', |
| 264 | 'type' => 'boolean', |
| 265 | 'class' => 'pvc-pro', |
| 266 | 'disabled' => true, |
| 267 | 'value' => false, |
| 268 | 'skip_saving' => true, |
| 269 | 'animation' => 'slide', |
| 270 | 'available' => $this->is_caching_compatibility_available(), |
| 271 | 'label' => $this->get_caching_compatibility_label(), |
| 272 | 'description' => $this->get_caching_compatibility_description(), |
| 273 | 'pro_only' => true |
| 274 | ], |
| 275 | 'object_cache' => [ |
| 276 | 'tab' => 'general', |
| 277 | 'title' => __( 'Object Cache Support', 'post-views-counter' ), |
| 278 | 'section' => 'post_views_counter_general_performance', |
| 279 | 'type' => 'boolean', |
| 280 | 'class' => 'pvc-pro', |
| 281 | 'disabled' => true, |
| 282 | 'value' => false, |
| 283 | 'skip_saving' => true, |
| 284 | 'animation' => 'slide', |
| 285 | 'available' => $this->is_object_cache_available(), |
| 286 | 'label' => $this->get_object_cache_label(), |
| 287 | 'description' => $this->get_object_cache_description(), |
| 288 | 'pro_only' => true |
| 289 | ], |
| 290 | 'exclude_groups' => [ |
| 291 | 'tab' => 'general', |
| 292 | 'title' => __( 'Exclude Visitors', 'post-views-counter' ), |
| 293 | 'section' => 'post_views_counter_general_exclusions', |
| 294 | 'type' => 'checkbox', |
| 295 | 'description' => __( 'Use this to exclude specific visitor groups from counting views.', 'post-views-counter' ), |
| 296 | 'class' => 'pvc-pro-extended', |
| 297 | 'options' => $groups, |
| 298 | 'disabled' => [ 'ai_bots' ], |
| 299 | 'pro_only' => [ 'ai_bots' ], |
| 300 | 'name' => 'post_views_counter_settings_general[exclude][groups]', |
| 301 | 'value' => $this->pvc->options['general']['exclude']['groups'], |
| 302 | 'validate' => [ $this, 'validate_exclude_groups' ] |
| 303 | ], |
| 304 | 'exclude_roles' => [ |
| 305 | 'tab' => 'general', |
| 306 | 'title' => __( 'Exclude User Roles', 'post-views-counter' ), |
| 307 | 'section' => 'post_views_counter_general_exclusions', |
| 308 | 'type' => 'checkbox', |
| 309 | 'description' => __( 'Use this to exclude specific user roles from counting views.', 'post-views-counter' ), |
| 310 | 'options' => $user_roles, |
| 311 | 'logic' => [ |
| 312 | [ |
| 313 | 'field' => 'exclude_groups', |
| 314 | 'operator' => 'contains', |
| 315 | 'value' => 'roles' |
| 316 | ] |
| 317 | ], |
| 318 | 'animation' => 'slide', |
| 319 | 'name' => 'post_views_counter_settings_general[exclude][roles]', |
| 320 | 'value' => $this->pvc->options['general']['exclude']['roles'], |
| 321 | 'validate' => [ $this, 'validate_exclude_roles' ] |
| 322 | ], |
| 323 | 'exclude_ips' => [ |
| 324 | 'tab' => 'general', |
| 325 | 'title' => __( 'Exclude IPs', 'post-views-counter' ), |
| 326 | 'section' => 'post_views_counter_general_exclusions', |
| 327 | 'type' => 'custom', |
| 328 | 'description' => '', |
| 329 | 'callback' => [ $this, 'setting_exclude_ips' ], |
| 330 | 'validate' => [ $this, 'validate_exclude_ips' ] |
| 331 | ] |
| 332 | ]; |
| 333 | } |
| 334 | |
| 335 | /** |
| 336 | * Setting: taxonomies count. |
| 337 | * |
| 338 | * @param array $field |
| 339 | * @return string |
| 340 | */ |
| 341 | public function setting_taxonomies_count( $field ) { |
| 342 | $html = ' |
| 343 | <label class="pvc-disabled"><input id="post_views_counter_general_taxonomies_count" type="checkbox" name="" value="" disabled role="switch" />' . esc_html( $field['label'] ) . '</label>'; |
| 344 | |
| 345 | return $html; |
| 346 | } |
| 347 | |
| 348 | /** |
| 349 | * Setting: users count. |
| 350 | * |
| 351 | * @param array $field |
| 352 | * @return string |
| 353 | */ |
| 354 | public function setting_users_count( $field ) { |
| 355 | $html = ' |
| 356 | <label class="pvc-disabled"><input id="post_views_counter_general_users_count" type="checkbox" name="" value="" disabled role="switch" />' . esc_html( $field['label'] ) . '</label>'; |
| 357 | |
| 358 | return $html; |
| 359 | } |
| 360 | |
| 361 | /** |
| 362 | * Setting: count interval. |
| 363 | * |
| 364 | * @param array $field |
| 365 | * @return string |
| 366 | */ |
| 367 | public function setting_time_between_counts( $field ) { |
| 368 | $html = ' |
| 369 | <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'] ) . '" /> |
| 370 | <select name="post_views_counter_settings_general[time_between_counts][type]">'; |
| 371 | |
| 372 | foreach ( $field['options'] as $type => $type_name ) { |
| 373 | $html .= ' |
| 374 | <option value="' . esc_attr( $type ) . '" ' . selected( $type, $this->pvc->options['general']['time_between_counts']['type'], false ) . '>' . esc_html( $type_name ) . '</option>'; |
| 375 | } |
| 376 | |
| 377 | $html .= ' |
| 378 | </select> |
| 379 | <p class="description">' . __( 'Minimum time between counting new views from the same visitor. Enter <code>0</code> to count every page view.', 'post-views-counter' ) . '</p>'; |
| 380 | |
| 381 | return $html; |
| 382 | } |
| 383 | |
| 384 | /** |
| 385 | * Validate count interval. |
| 386 | * |
| 387 | * @param array $input |
| 388 | * @param array $field |
| 389 | * @return array |
| 390 | */ |
| 391 | public function validate_time_between_counts( $input, $field ) { |
| 392 | // number |
| 393 | $input['time_between_counts']['number'] = isset( $input['time_between_counts']['number'] ) ? (int) $input['time_between_counts']['number'] : $this->pvc->defaults['general']['time_between_counts']['number']; |
| 394 | |
| 395 | if ( $input['time_between_counts']['number'] < $field['min'] || $input['time_between_counts']['number'] > $field['max'] ) |
| 396 | $input['time_between_counts']['number'] = $this->pvc->defaults['general']['time_between_counts']['number']; |
| 397 | |
| 398 | // type |
| 399 | $input['time_between_counts']['type'] = isset( $input['time_between_counts']['type'], $field['options'][$input['time_between_counts']['type']] ) ? $input['time_between_counts']['type'] : $this->pvc->defaults['general']['time_between_counts']['type']; |
| 400 | |
| 401 | return $input; |
| 402 | } |
| 403 | |
| 404 | /** |
| 405 | * Setting: reset data interval. |
| 406 | * |
| 407 | * @param array $field |
| 408 | * @return string |
| 409 | */ |
| 410 | public function setting_reset_counts( $field ) { |
| 411 | $html = ' |
| 412 | <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'] ) . '" /> |
| 413 | <select name="post_views_counter_settings_general[reset_counts][type]">'; |
| 414 | |
| 415 | foreach ( array_slice( $field['options'], 2, null, true ) as $type => $type_name ) { |
| 416 | $html .= ' |
| 417 | <option value="' . esc_attr( $type ) . '" ' . selected( $type, $this->pvc->options['general']['reset_counts']['type'], false ) . '>' . esc_html( $type_name ) . '</option>'; |
| 418 | } |
| 419 | |
| 420 | $html .= ' |
| 421 | </select>'; |
| 422 | |
| 423 | return $html; |
| 424 | } |
| 425 | |
| 426 | /** |
| 427 | * Validate reset data interval. |
| 428 | * |
| 429 | * @param array $input |
| 430 | * @param array $field |
| 431 | * @return array |
| 432 | */ |
| 433 | public function validate_reset_counts( $input, $field ) { |
| 434 | // number |
| 435 | $input['reset_counts']['number'] = isset( $input['reset_counts']['number'] ) ? (int) $input['reset_counts']['number'] : $this->pvc->defaults['general']['reset_counts']['number']; |
| 436 | |
| 437 | if ( $input['reset_counts']['number'] < $field['min'] || $input['reset_counts']['number'] > $field['max'] ) |
| 438 | $input['reset_counts']['number'] = $this->pvc->defaults['general']['reset_counts']['number']; |
| 439 | |
| 440 | // type |
| 441 | $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']; |
| 442 | |
| 443 | // run cron on next visit? |
| 444 | $input['cron_run'] = ( $input['reset_counts']['number'] > 0 ); |
| 445 | |
| 446 | // cron update? |
| 447 | $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'] ) ); |
| 448 | |
| 449 | return $input; |
| 450 | } |
| 451 | |
| 452 | /** |
| 453 | * Setting: object cache. |
| 454 | * |
| 455 | * @param array $field |
| 456 | * @return string |
| 457 | */ |
| 458 | public function setting_object_cache( $field ) { |
| 459 | $html = ' |
| 460 | <input size="4" type="number" min="' . ( (int) $field['min'] ) . '" max="' . ( (int) $field['max'] ) . '" name="" value="0" disabled /> <span>' . __( 'minutes', 'post-views-counter' ) . '</span> |
| 461 | <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> |
| 462 | <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>'; |
| 463 | |
| 464 | return $html; |
| 465 | } |
| 466 | |
| 467 | /** |
| 468 | * Setting: exclude visitors. |
| 469 | * |
| 470 | * @param array $field |
| 471 | * @return string |
| 472 | */ |
| 473 | |
| 474 | |
| 475 | /** |
| 476 | * Validate exclude visitors. |
| 477 | * |
| 478 | * @param array $input |
| 479 | * @param array $field |
| 480 | * @return array |
| 481 | */ |
| 482 | public function validate_exclude_groups( $input, $field ) { |
| 483 | $groups = []; |
| 484 | |
| 485 | if ( is_array( $input ) ) { |
| 486 | foreach ( $input as $group => $set ) { |
| 487 | // disallow disabled checkboxes |
| 488 | if ( ! empty( $field['disabled'] ) && in_array( $group, $field['disabled'], true ) ) |
| 489 | continue; |
| 490 | |
| 491 | if ( isset( $field['options'][$group] ) ) |
| 492 | $groups[] = $group; |
| 493 | } |
| 494 | } |
| 495 | |
| 496 | return array_unique( $groups ); |
| 497 | } |
| 498 | |
| 499 | public function validate_exclude_roles( $input, $field ) { |
| 500 | $roles = []; |
| 501 | |
| 502 | if ( is_array( $input ) ) { |
| 503 | foreach ( $input as $role => $set ) { |
| 504 | if ( isset( $field['options'][$role] ) ) |
| 505 | $roles[] = $role; |
| 506 | } |
| 507 | } |
| 508 | |
| 509 | return array_unique( $roles ); |
| 510 | } |
| 511 | |
| 512 | /** |
| 513 | * Setting: exclude IP addresses. |
| 514 | * |
| 515 | * @return string |
| 516 | */ |
| 517 | public function setting_exclude_ips() { |
| 518 | // get ip addresses |
| 519 | $ips = $this->pvc->options['general']['exclude_ips']; |
| 520 | |
| 521 | $html = '<div class="pvc-ip-box-group">'; |
| 522 | |
| 523 | // any ip addresses? |
| 524 | if ( ! empty( $ips ) ) { |
| 525 | foreach ( $ips as $key => $ip ) { |
| 526 | $html .= ' |
| 527 | <div class="pvc-ip-box"> |
| 528 | <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> |
| 529 | </div>'; |
| 530 | } |
| 531 | } else { |
| 532 | $html .= ' |
| 533 | <div class="pvc-ip-box"> |
| 534 | <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> |
| 535 | </div>'; |
| 536 | } |
| 537 | |
| 538 | $html .= '</div>'; |
| 539 | |
| 540 | $html .= ' |
| 541 | <div class="pvc-field-group pvc-buttons-group"> |
| 542 | <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( $_SERVER['REMOTE_ADDR'] ) . '" /> |
| 543 | </div>'; |
| 544 | |
| 545 | $html .= '<p class="description">' . esc_html__( 'Add IP addresses or wildcards (e.g. 192.168.0.*) to exclude them from counting views.', 'post-views-counter' ) . '</p>'; |
| 546 | |
| 547 | return $html; |
| 548 | } |
| 549 | |
| 550 | /** |
| 551 | * Validate exclude IP addresses. |
| 552 | * |
| 553 | * @param array $input |
| 554 | * @param array $field |
| 555 | * @return array |
| 556 | */ |
| 557 | public function validate_exclude_ips( $input, $field ) { |
| 558 | // any ip addresses? |
| 559 | if ( isset( $input['exclude_ips'] ) ) { |
| 560 | $ips = []; |
| 561 | |
| 562 | foreach ( $input['exclude_ips'] as $ip ) { |
| 563 | if ( strpos( $ip, '*' ) !== false ) { |
| 564 | $new_ip = str_replace( '*', '0', $ip ); |
| 565 | |
| 566 | if ( filter_var( $new_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) |
| 567 | $ips[] = $ip; |
| 568 | } elseif ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) |
| 569 | $ips[] = $ip; |
| 570 | } |
| 571 | |
| 572 | $input['exclude_ips'] = array_unique( $ips ); |
| 573 | } |
| 574 | |
| 575 | return $input; |
| 576 | } |
| 577 | |
| 578 | /** |
| 579 | * Section description: tracking targets. |
| 580 | * |
| 581 | * @return void |
| 582 | */ |
| 583 | public function section_tracking_targets() { |
| 584 | echo '<p class="description">' . esc_html__( 'Control which post types, archives and other content types are included in view counting.', 'post-views-counter' ) . '</p>'; |
| 585 | } |
| 586 | |
| 587 | /** |
| 588 | * Section description: tracking behavior. |
| 589 | * |
| 590 | * @return void |
| 591 | */ |
| 592 | public function section_tracking_behavior() { |
| 593 | echo '<p class="description">' . esc_html__( 'Control how views are recorded — counting mode, intervals, time zone, and cleanup.', 'post-views-counter' ) . '</p>'; |
| 594 | } |
| 595 | |
| 596 | /** |
| 597 | * Section description: tracking exclusions. |
| 598 | * |
| 599 | * @return void |
| 600 | */ |
| 601 | public function section_tracking_exclusions() { |
| 602 | echo '<p class="description">' . esc_html__( 'Exclude specific visitor groups or IP addresses from incrementing view counts.', 'post-views-counter' ) . '</p>'; |
| 603 | } |
| 604 | |
| 605 | /** |
| 606 | * Section description: performance & caching. |
| 607 | * |
| 608 | * @return void |
| 609 | */ |
| 610 | public function section_tracking_performance() { |
| 611 | echo '<p class="description">' . esc_html__( 'Configure caching compatibility and object-cache handling for counting.', 'post-views-counter' ) . '</p>'; |
| 612 | } |
| 613 | |
| 614 | /** |
| 615 | * Get caching compatibility description. |
| 616 | * |
| 617 | * @return string |
| 618 | */ |
| 619 | public function get_caching_compatibility_description() { |
| 620 | // get active caching plugins |
| 621 | $active_plugins = $this->get_active_caching_plugins(); |
| 622 | |
| 623 | if ( ! empty( $active_plugins ) ) { |
| 624 | $active_plugins_html = []; |
| 625 | |
| 626 | $description = esc_html__( 'Currently detected active caching plugins', 'post-views-counter' ) . ': '; |
| 627 | |
| 628 | foreach ( $active_plugins as $plugin ) { |
| 629 | $active_plugins_html[] = '<code>' . esc_html( $plugin ) . '</code>'; |
| 630 | } |
| 631 | |
| 632 | $description .= implode( ', ', $active_plugins_html ) . '.'; |
| 633 | } else { |
| 634 | $description = esc_html__( 'No compatible caching plugins found.', 'post-views-counter' ); |
| 635 | } |
| 636 | |
| 637 | return $description; |
| 638 | } |
| 639 | |
| 640 | /** |
| 641 | * Get caching compatibility label with availability indicator. |
| 642 | * |
| 643 | * @return string |
| 644 | */ |
| 645 | public function get_caching_compatibility_label() { |
| 646 | $label = __( 'Enable compatibility tweaks for supported caching plugins.', 'post-views-counter' ); |
| 647 | |
| 648 | // add availability indicator when Pro is missing but feature is available |
| 649 | if ( ! class_exists( 'Post_Views_Counter_Pro' ) && $this->is_caching_compatibility_available() ) { |
| 650 | $label = '<span class="pvc-availability-status available">' . esc_html__( '(available)', 'post-views-counter' ) . '</span> ' . $label; |
| 651 | } |
| 652 | |
| 653 | return $label; |
| 654 | } |
| 655 | |
| 656 | /** |
| 657 | * Get object cache label with availability indicator. |
| 658 | * |
| 659 | * @return string |
| 660 | */ |
| 661 | public function get_object_cache_label() { |
| 662 | $label = __( 'Enable Redis or Memcached object cache optimization.', 'post-views-counter' ); |
| 663 | |
| 664 | // add availability indicator when Pro is missing but feature is available |
| 665 | if ( ! class_exists( 'Post_Views_Counter_Pro' ) && $this->is_object_cache_available() ) { |
| 666 | $label = '<span class="pvc-availability-status available">' . esc_html__( '(available)', 'post-views-counter' ) . '</span> ' . $label; |
| 667 | } |
| 668 | |
| 669 | return $label; |
| 670 | } |
| 671 | |
| 672 | /** |
| 673 | * Check if caching compatibility feature is available. |
| 674 | * |
| 675 | * @return bool |
| 676 | */ |
| 677 | public function is_caching_compatibility_available() { |
| 678 | $active_plugins = $this->get_active_caching_plugins(); |
| 679 | |
| 680 | return ! empty( $active_plugins ); |
| 681 | } |
| 682 | |
| 683 | /** |
| 684 | * Check if object cache feature is available. |
| 685 | * |
| 686 | * @return bool |
| 687 | */ |
| 688 | public function is_object_cache_available() { |
| 689 | return wp_using_ext_object_cache(); |
| 690 | } |
| 691 | |
| 692 | /** |
| 693 | * Get object cache description based on availability. |
| 694 | * |
| 695 | * @return string |
| 696 | */ |
| 697 | public function get_object_cache_description() { |
| 698 | if ( $this->is_object_cache_available() ) { |
| 699 | return __( 'Persistent object cache has been detected.', 'post-views-counter' ); |
| 700 | } |
| 701 | |
| 702 | 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>' ); |
| 703 | } |
| 704 | |
| 705 | /** |
| 706 | * Extend active caching plugins. |
| 707 | * |
| 708 | * @param array $plugins |
| 709 | * |
| 710 | * @return array |
| 711 | */ |
| 712 | public function extend_active_caching_plugins( $plugins ) { |
| 713 | // breeze |
| 714 | if ( $this->is_plugin_active( 'breeze' ) ) |
| 715 | $plugins[] = 'Breeze'; |
| 716 | |
| 717 | return $plugins; |
| 718 | } |
| 719 | |
| 720 | /** |
| 721 | * Check whether specified plugin is active. |
| 722 | * |
| 723 | * @param bool $is_plugin_active |
| 724 | * @param string $plugin |
| 725 | * |
| 726 | * @return bool |
| 727 | */ |
| 728 | public function extend_is_plugin_active( $is_plugin_active, $plugin ) { |
| 729 | // breeze |
| 730 | 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', '>=' ) ) |
| 731 | $is_plugin_active = true; |
| 732 | |
| 733 | return $is_plugin_active; |
| 734 | } |
| 735 | |
| 736 | /** |
| 737 | * Get active caching plugins. |
| 738 | * |
| 739 | * @return array |
| 740 | */ |
| 741 | public function get_active_caching_plugins() { |
| 742 | $active_plugins = []; |
| 743 | |
| 744 | // autoptimize |
| 745 | if ( $this->is_plugin_active( 'autoptimize' ) ) |
| 746 | $active_plugins[] = 'Autoptimize'; |
| 747 | |
| 748 | // hummingbird |
| 749 | if ( $this->is_plugin_active( 'hummingbird' ) ) |
| 750 | $active_plugins[] = 'Hummingbird'; |
| 751 | |
| 752 | // litespeed |
| 753 | if ( $this->is_plugin_active( 'litespeed' ) ) |
| 754 | $active_plugins[] = 'LiteSpeed Cache'; |
| 755 | |
| 756 | // speed optimizer |
| 757 | if ( $this->is_plugin_active( 'speedoptimizer' ) ) |
| 758 | $active_plugins[] = 'Speed Optimizer'; |
| 759 | |
| 760 | // speedycache |
| 761 | if ( $this->is_plugin_active( 'speedycache' ) ) |
| 762 | $active_plugins[] = 'SpeedyCache'; |
| 763 | |
| 764 | // wp fastest cache |
| 765 | if ( $this->is_plugin_active( 'wpfastestcache' ) ) |
| 766 | $active_plugins[] = 'WP Fastest Cache'; |
| 767 | |
| 768 | // wp-optimize |
| 769 | if ( $this->is_plugin_active( 'wpoptimize' ) ) |
| 770 | $active_plugins[] = 'WP-Optimize'; |
| 771 | |
| 772 | // wp rocket |
| 773 | if ( $this->is_plugin_active( 'wprocket' ) ) |
| 774 | $active_plugins[] = 'WP Rocket'; |
| 775 | |
| 776 | return apply_filters( 'pvc_active_caching_plugins', $active_plugins ); |
| 777 | } |
| 778 | |
| 779 | /** |
| 780 | * Check whether specified plugin is active. |
| 781 | * |
| 782 | * @param string $plugin |
| 783 | * |
| 784 | * @return bool |
| 785 | */ |
| 786 | public function is_plugin_active( $plugin = '' ) { |
| 787 | // set default flag |
| 788 | $is_plugin_active = false; |
| 789 | |
| 790 | switch ( $plugin ) { |
| 791 | // autoptimize |
| 792 | case 'autoptimize': |
| 793 | if ( function_exists( 'autoptimize' ) && defined( 'AUTOPTIMIZE_PLUGIN_VERSION' ) && version_compare( AUTOPTIMIZE_PLUGIN_VERSION, '2.4', '>=' ) ) |
| 794 | $is_plugin_active = true; |
| 795 | break; |
| 796 | |
| 797 | // hummingbird |
| 798 | case 'hummingbird': |
| 799 | if ( class_exists( 'Hummingbird\\WP_Hummingbird' ) && defined( 'WPHB_VERSION' ) && version_compare( WPHB_VERSION, '2.1.0', '>=' ) ) |
| 800 | $is_plugin_active = true; |
| 801 | break; |
| 802 | |
| 803 | // litespeed |
| 804 | case 'litespeed': |
| 805 | if ( class_exists( 'LiteSpeed\Core' ) && defined( 'LSCWP_CUR_V' ) && version_compare( LSCWP_CUR_V, '3.0', '>=' ) ) |
| 806 | $is_plugin_active = true; |
| 807 | break; |
| 808 | |
| 809 | // speed optimizer |
| 810 | case 'speedoptimizer': |
| 811 | global $siteground_optimizer_loader; |
| 812 | |
| 813 | 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', '>=' ) ) |
| 814 | $is_plugin_active = true; |
| 815 | break; |
| 816 | |
| 817 | // speedycache |
| 818 | case 'speedycache': |
| 819 | if ( class_exists( 'SpeedyCache' ) && defined( 'SPEEDYCACHE_VERSION' ) && function_exists( 'speedycache_delete_cache' ) && version_compare( SPEEDYCACHE_VERSION, '1.0.0', '>=' ) ) |
| 820 | $is_plugin_active = true; |
| 821 | break; |
| 822 | |
| 823 | // wp fastest cache |
| 824 | case 'wpfastestcache': |
| 825 | if ( function_exists( 'wpfc_clear_all_cache' ) ) |
| 826 | $is_plugin_active = true; |
| 827 | break; |
| 828 | |
| 829 | // wp-optimize |
| 830 | case 'wpoptimize': |
| 831 | if ( function_exists( 'WP_Optimize' ) && defined( 'WPO_VERSION' ) && version_compare( WPO_VERSION, '3.0.12', '>=' ) ) |
| 832 | $is_plugin_active = true; |
| 833 | break; |
| 834 | |
| 835 | // wp rocket |
| 836 | case 'wprocket': |
| 837 | if ( function_exists( 'rocket_init' ) && defined( 'WP_ROCKET_VERSION' ) && version_compare( WP_ROCKET_VERSION, '3.8', '>=' ) ) |
| 838 | $is_plugin_active = true; |
| 839 | break; |
| 840 | |
| 841 | // other caching plugin |
| 842 | default: |
| 843 | $is_plugin_active = apply_filters( 'pvc_is_plugin_active', false, $plugin ); |
| 844 | } |
| 845 | |
| 846 | return $is_plugin_active; |
| 847 | } |
| 848 | } |
| 849 |