class-admin.php
6 months ago
class-columns.php
6 months ago
class-counter.php
6 months ago
class-crawler-detect.php
6 months ago
class-cron.php
6 months ago
class-dashboard.php
6 months ago
class-frontend.php
6 months ago
class-functions.php
6 months ago
class-import.php
6 months ago
class-integration-gutenberg.php
6 months ago
class-integrations.php
6 months ago
class-query.php
6 months ago
class-settings-api.php
6 months ago
class-settings-display.php
6 months ago
class-settings-general.php
6 months ago
class-settings-integrations.php
6 months ago
class-settings-other.php
6 months ago
class-settings-reports.php
6 months ago
class-settings.php
6 months ago
class-toolbar.php
6 months ago
class-update.php
6 months ago
class-widgets.php
6 months ago
functions.php
6 months ago
class-settings-general.php
789 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 | 'display_type' => 'horizontal', |
| 131 | 'description' => __( 'Select post types whose views should be counted.', 'post-views-counter' ), |
| 132 | 'options' => $post_types |
| 133 | ], |
| 134 | 'taxonomies_count' => [ |
| 135 | 'tab' => 'general', |
| 136 | 'title' => __( 'Taxonomies', 'post-views-counter' ), |
| 137 | 'section' => 'post_views_counter_general_tracking_targets', |
| 138 | 'type' => 'custom', |
| 139 | 'label' => __( 'Enable counting views on taxonomy term archive pages.', 'post-views-counter' ), |
| 140 | 'class' => 'pvc-pro', |
| 141 | 'skip_saving' => true, |
| 142 | 'callback' => [ $this, 'setting_taxonomies_count' ] |
| 143 | ], |
| 144 | 'users_count' => [ |
| 145 | 'tab' => 'general', |
| 146 | 'title' => __( 'Author Archives', 'post-views-counter' ), |
| 147 | 'section' => 'post_views_counter_general_tracking_targets', |
| 148 | 'type' => 'custom', |
| 149 | 'label' => __( 'Enable counting views on author archive pages.', 'post-views-counter' ), |
| 150 | 'class' => 'pvc-pro', |
| 151 | 'skip_saving' => true, |
| 152 | 'callback' => [ $this, 'setting_users_count' ] |
| 153 | ], |
| 154 | 'other_count' => [ |
| 155 | 'tab' => 'general', |
| 156 | 'title' => __( 'Other Pages', 'post-views-counter' ), |
| 157 | 'section' => 'post_views_counter_general_tracking_targets', |
| 158 | 'type' => 'boolean', |
| 159 | 'label' => __( 'Track views on the front page, post type archives, date archives, search results, and 404 pages.', 'post-views-counter' ), |
| 160 | 'class' => 'pvc-pro', |
| 161 | 'disabled' => true, |
| 162 | 'skip_saving' => true, |
| 163 | 'value' => false |
| 164 | ], |
| 165 | 'technology_count' => [ |
| 166 | 'tab' => 'general', |
| 167 | 'title' => __( 'Traffic Sources', 'post-views-counter' ), |
| 168 | 'section' => 'post_views_counter_general_tracking_targets', |
| 169 | 'type' => 'boolean', |
| 170 | 'label' => __( 'Collect aggregate stats about visitors\' browsers, devices, operating systems and referrers.', 'post-views-counter' ), |
| 171 | 'class' => 'pvc-pro', |
| 172 | 'disabled' => true, |
| 173 | 'skip_saving' => true, |
| 174 | 'value' => false |
| 175 | ], |
| 176 | 'counter_mode' => [ |
| 177 | 'tab' => 'general', |
| 178 | 'title' => __( 'Counter Mode', 'post-views-counter' ), |
| 179 | 'section' => 'post_views_counter_general_tracking_behavior', |
| 180 | 'type' => 'radio', |
| 181 | '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' ), |
| 182 | 'class' => 'pvc-pro-extended', |
| 183 | 'options' => $this->get_counter_modes(), |
| 184 | 'disabled' => [ 'ajax' ] |
| 185 | ], |
| 186 | 'data_storage' => [ |
| 187 | 'tab' => 'general', |
| 188 | 'title' => __( 'Data Storage', 'post-views-counter' ), |
| 189 | 'section' => 'post_views_counter_general_tracking_behavior', |
| 190 | 'type' => 'radio', |
| 191 | 'class' => 'pvc-pro', |
| 192 | 'skip_saving' => true, |
| 193 | 'description' => __( "Choose how to store the content views data in the user's browser - with or without cookies.", 'post-views-counter' ), |
| 194 | 'options' => [ |
| 195 | 'cookies' => __( 'Cookies', 'post-views-counter' ), |
| 196 | 'cookieless' => __( 'Cookieless', 'post-views-counter' ) |
| 197 | ], |
| 198 | 'disabled' => [ 'cookies', 'cookieless' ], |
| 199 | 'value' => 'cookies' |
| 200 | ], |
| 201 | 'time_between_counts' => [ |
| 202 | 'tab' => 'general', |
| 203 | 'title' => __( 'Count Interval', 'post-views-counter' ), |
| 204 | 'section' => 'post_views_counter_general_tracking_behavior', |
| 205 | 'type' => 'custom', |
| 206 | 'description' => '', |
| 207 | 'min' => 0, |
| 208 | 'max' => 999999, |
| 209 | 'options' => $time_types, |
| 210 | 'callback' => [ $this, 'setting_time_between_counts' ], |
| 211 | 'validate' => [ $this, 'validate_time_between_counts' ] |
| 212 | ], |
| 213 | 'count_time' => [ |
| 214 | 'tab' => 'general', |
| 215 | 'title' => __( 'Count Time', 'post-views-counter' ), |
| 216 | 'section' => 'post_views_counter_general_tracking_behavior', |
| 217 | 'type' => 'radio', |
| 218 | 'class' => 'pvc-pro', |
| 219 | 'skip_saving' => true, |
| 220 | 'description' => __( 'Whether to store the views using GMT timezone or adjust it to the GMT offset of the site.', 'post-views-counter' ), |
| 221 | 'options' => [ |
| 222 | 'gmt' => __( 'GMT Time', 'post-views-counter' ), |
| 223 | 'local' => __( 'Local Time', 'post-views-counter' ) |
| 224 | ], |
| 225 | 'disabled' => [ 'gmt', 'local' ], |
| 226 | 'value' => 'gmt' |
| 227 | ], |
| 228 | 'strict_counts' => [ |
| 229 | 'tab' => 'general', |
| 230 | 'title' => __( 'Strict Counts', 'post-views-counter' ), |
| 231 | 'section' => 'post_views_counter_general_tracking_behavior', |
| 232 | 'type' => 'boolean', |
| 233 | 'class' => 'pvc-pro', |
| 234 | 'disabled' => true, |
| 235 | 'skip_saving' => true, |
| 236 | 'value' => false, |
| 237 | 'description' => '', |
| 238 | 'label' => __( 'Prevent bypassing the count interval (for example by using incognito mode or clearing cookies).', 'post-views-counter' ) |
| 239 | ], |
| 240 | 'reset_counts' => [ |
| 241 | 'tab' => 'general', |
| 242 | 'title' => __( 'Cleanup Interval', 'post-views-counter' ), |
| 243 | 'section' => 'post_views_counter_general_tracking_behavior', |
| 244 | 'type' => 'custom', |
| 245 | '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>' ), |
| 246 | 'min' => 0, |
| 247 | 'max' => 999999, |
| 248 | 'options' => $time_types, |
| 249 | 'callback' => [ $this, 'setting_reset_counts' ], |
| 250 | 'validate' => [ $this, 'validate_reset_counts' ] |
| 251 | ], |
| 252 | 'caching_compatibility' => [ |
| 253 | 'tab' => 'general', |
| 254 | 'title' => __( 'Caching Compatibility', 'post-views-counter' ), |
| 255 | 'section' => 'post_views_counter_general_performance', |
| 256 | 'type' => 'boolean', |
| 257 | 'class' => 'pvc-pro', |
| 258 | 'disabled' => true, |
| 259 | 'value' => false, |
| 260 | 'skip_saving' => true, |
| 261 | 'label' => __( 'Enable compatibility tweaks for supported caching plugins.', 'post-views-counter' ), |
| 262 | 'description' => $this->get_caching_compatibility_description() |
| 263 | ], |
| 264 | 'object_cache' => [ |
| 265 | 'tab' => 'general', |
| 266 | 'title' => __( 'Object Cache Support', 'post-views-counter' ), |
| 267 | 'section' => 'post_views_counter_general_performance', |
| 268 | 'type' => 'boolean', |
| 269 | 'class' => 'pvc-pro', |
| 270 | 'disabled' => true, |
| 271 | 'value' => false, |
| 272 | 'skip_saving' => true, |
| 273 | 'label' => __( 'Enable Redis or Memcached object cache optimization.', 'post-views-counter' ), |
| 274 | 'description' => 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>' ) . '<br />' . __( 'Current status', '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>.' |
| 275 | ], |
| 276 | 'exclude' => [ |
| 277 | 'tab' => 'general', |
| 278 | 'title' => __( 'Exclude Visitors', 'post-views-counter' ), |
| 279 | 'section' => 'post_views_counter_general_exclusions', |
| 280 | 'type' => 'custom', |
| 281 | 'description' => '', |
| 282 | 'class' => 'pvc-pro-extended', |
| 283 | 'options' => [ |
| 284 | 'groups' => $groups, |
| 285 | 'roles' => $user_roles |
| 286 | ], |
| 287 | 'disabled' => [ |
| 288 | 'groups' => [ 'ai_bots' ] |
| 289 | ], |
| 290 | 'callback' => [ $this, 'setting_exclude' ], |
| 291 | 'validate' => [ $this, 'validate_exclude' ] |
| 292 | ], |
| 293 | 'exclude_ips' => [ |
| 294 | 'tab' => 'general', |
| 295 | 'title' => __( 'Exclude IPs', 'post-views-counter' ), |
| 296 | 'section' => 'post_views_counter_general_exclusions', |
| 297 | 'type' => 'custom', |
| 298 | 'description' => '', |
| 299 | 'callback' => [ $this, 'setting_exclude_ips' ], |
| 300 | 'validate' => [ $this, 'validate_exclude_ips' ] |
| 301 | ] |
| 302 | ]; |
| 303 | } |
| 304 | |
| 305 | /** |
| 306 | * Setting: taxonomies count. |
| 307 | * |
| 308 | * @param array $field |
| 309 | * @return string |
| 310 | */ |
| 311 | public function setting_taxonomies_count( $field ) { |
| 312 | $html = ' |
| 313 | <label><input id="post_views_counter_general_taxonomies_count" type="checkbox" name="" value="" disabled />' . esc_html( $field['label'] ) . '</label>'; |
| 314 | |
| 315 | return $html; |
| 316 | } |
| 317 | |
| 318 | /** |
| 319 | * Setting: users count. |
| 320 | * |
| 321 | * @param array $field |
| 322 | * @return string |
| 323 | */ |
| 324 | public function setting_users_count( $field ) { |
| 325 | $html = ' |
| 326 | <label><input id="post_views_counter_general_users_count" type="checkbox" name="" value="" disabled />' . esc_html( $field['label'] ) . '</label>'; |
| 327 | |
| 328 | return $html; |
| 329 | } |
| 330 | |
| 331 | /** |
| 332 | * Setting: count interval. |
| 333 | * |
| 334 | * @param array $field |
| 335 | * @return string |
| 336 | */ |
| 337 | public function setting_time_between_counts( $field ) { |
| 338 | $html = ' |
| 339 | <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'] ) . '" /> |
| 340 | <select name="post_views_counter_settings_general[time_between_counts][type]">'; |
| 341 | |
| 342 | foreach ( $field['options'] as $type => $type_name ) { |
| 343 | $html .= ' |
| 344 | <option value="' . esc_attr( $type ) . '" ' . selected( $type, $this->pvc->options['general']['time_between_counts']['type'], false ) . '>' . esc_html( $type_name ) . '</option>'; |
| 345 | } |
| 346 | |
| 347 | $html .= ' |
| 348 | </select> |
| 349 | <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>'; |
| 350 | |
| 351 | return $html; |
| 352 | } |
| 353 | |
| 354 | /** |
| 355 | * Validate count interval. |
| 356 | * |
| 357 | * @param array $input |
| 358 | * @param array $field |
| 359 | * @return array |
| 360 | */ |
| 361 | public function validate_time_between_counts( $input, $field ) { |
| 362 | // number |
| 363 | $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']; |
| 364 | |
| 365 | if ( $input['time_between_counts']['number'] < $field['min'] || $input['time_between_counts']['number'] > $field['max'] ) |
| 366 | $input['time_between_counts']['number'] = $this->pvc->defaults['general']['time_between_counts']['number']; |
| 367 | |
| 368 | // type |
| 369 | $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']; |
| 370 | |
| 371 | return $input; |
| 372 | } |
| 373 | |
| 374 | /** |
| 375 | * Setting: reset data interval. |
| 376 | * |
| 377 | * @param array $field |
| 378 | * @return string |
| 379 | */ |
| 380 | public function setting_reset_counts( $field ) { |
| 381 | $html = ' |
| 382 | <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'] ) . '" /> |
| 383 | <select name="post_views_counter_settings_general[reset_counts][type]">'; |
| 384 | |
| 385 | foreach ( array_slice( $field['options'], 2, null, true ) as $type => $type_name ) { |
| 386 | $html .= ' |
| 387 | <option value="' . esc_attr( $type ) . '" ' . selected( $type, $this->pvc->options['general']['reset_counts']['type'], false ) . '>' . esc_html( $type_name ) . '</option>'; |
| 388 | } |
| 389 | |
| 390 | $html .= ' |
| 391 | </select>'; |
| 392 | |
| 393 | return $html; |
| 394 | } |
| 395 | |
| 396 | /** |
| 397 | * Validate reset data interval. |
| 398 | * |
| 399 | * @param array $input |
| 400 | * @param array $field |
| 401 | * @return array |
| 402 | */ |
| 403 | public function validate_reset_counts( $input, $field ) { |
| 404 | // number |
| 405 | $input['reset_counts']['number'] = isset( $input['reset_counts']['number'] ) ? (int) $input['reset_counts']['number'] : $this->pvc->defaults['general']['reset_counts']['number']; |
| 406 | |
| 407 | if ( $input['reset_counts']['number'] < $field['min'] || $input['reset_counts']['number'] > $field['max'] ) |
| 408 | $input['reset_counts']['number'] = $this->pvc->defaults['general']['reset_counts']['number']; |
| 409 | |
| 410 | // type |
| 411 | $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']; |
| 412 | |
| 413 | // run cron on next visit? |
| 414 | $input['cron_run'] = ( $input['reset_counts']['number'] > 0 ); |
| 415 | |
| 416 | // cron update? |
| 417 | $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'] ) ); |
| 418 | |
| 419 | return $input; |
| 420 | } |
| 421 | |
| 422 | /** |
| 423 | * Setting: object cache. |
| 424 | * |
| 425 | * @param array $field |
| 426 | * @return string |
| 427 | */ |
| 428 | public function setting_object_cache( $field ) { |
| 429 | $html = ' |
| 430 | <input size="4" type="number" min="' . ( (int) $field['min'] ) . '" max="' . ( (int) $field['max'] ) . '" name="" value="0" disabled /> <span>' . __( 'minutes', 'post-views-counter' ) . '</span> |
| 431 | <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> |
| 432 | <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>'; |
| 433 | |
| 434 | return $html; |
| 435 | } |
| 436 | |
| 437 | /** |
| 438 | * Setting: exclude visitors. |
| 439 | * |
| 440 | * @param array $field |
| 441 | * @return string |
| 442 | */ |
| 443 | public function setting_exclude( $field ) { |
| 444 | $html = ''; |
| 445 | |
| 446 | $html .= '<div class="pvc-field-group pvc-checkbox-group">'; |
| 447 | |
| 448 | foreach ( $field['options']['groups'] as $type => $type_name ) { |
| 449 | $is_disabled = ! empty( $field['disabled']['groups'] ) && in_array( $type, $field['disabled']['groups'], true ); |
| 450 | |
| 451 | $html .= ' |
| 452 | <label for="' . esc_attr( 'pvc_exclude-' . $type ) . '"><input id="' . esc_attr( 'pvc_exclude-' . $type ) . '" type="checkbox" name="post_views_counter_settings_general[exclude][groups][' . esc_attr( $type ) . ']" value="1" ' . checked( in_array( $type, $this->pvc->options['general']['exclude']['groups'], true ) && ! $is_disabled, true, false ) . ' ' . disabled( $is_disabled, true, false ) . ' />' . esc_html( $type_name ) . '</label>'; |
| 453 | } |
| 454 | |
| 455 | $html .= '</div>'; |
| 456 | |
| 457 | $html .= ' |
| 458 | <p class="description">' . __( 'Use this to exclude specific visitor groups from counting views.', 'post-views-counter' ) . '</p>'; |
| 459 | |
| 460 | // user roles subfield |
| 461 | $html .= ' |
| 462 | <div class="pvc_user_roles pvc_subfield pvc-field-group pvc-checkbox-group"' . ( in_array( 'roles', $this->pvc->options['general']['exclude']['groups'], true ) ? '' : ' style="display: none;"' ) . '>'; |
| 463 | |
| 464 | foreach ( $field['options']['roles'] as $role => $role_name ) { |
| 465 | $html .= ' |
| 466 | <label><input type="checkbox" name="post_views_counter_settings_general[exclude][roles][' . $role . ']" value="1" ' . checked( in_array( $role, $this->pvc->options['general']['exclude']['roles'], true ), true, false ) . ' />' . esc_html( $role_name ) . '</label>'; |
| 467 | } |
| 468 | |
| 469 | $html .= ' |
| 470 | <p class="description">' . __( 'Use this to exclude specific user roles from counting views.', 'post-views-counter' ) . '</p> |
| 471 | </div>'; |
| 472 | |
| 473 | return $html; |
| 474 | } |
| 475 | |
| 476 | /** |
| 477 | * Validate exclude visitors. |
| 478 | * |
| 479 | * @param array $input |
| 480 | * @param array $field |
| 481 | * @return array |
| 482 | */ |
| 483 | public function validate_exclude( $input, $field ) { |
| 484 | // any groups? |
| 485 | if ( isset( $input['exclude']['groups'] ) ) { |
| 486 | $groups = []; |
| 487 | |
| 488 | foreach ( $input['exclude']['groups'] as $group => $set ) { |
| 489 | // disallow disabled checkboxes |
| 490 | if ( ! empty( $field['disabled']['groups'] ) && in_array( $group, $field['disabled']['groups'], true ) ) |
| 491 | continue; |
| 492 | |
| 493 | if ( isset( $field['options']['groups'][$group] ) ) |
| 494 | $groups[] = $group; |
| 495 | } |
| 496 | |
| 497 | $input['exclude']['groups'] = array_unique( $groups ); |
| 498 | } else |
| 499 | $input['exclude']['groups'] = []; |
| 500 | |
| 501 | // any roles? |
| 502 | if ( in_array( 'roles', $input['exclude']['groups'], true ) && isset( $input['exclude']['roles'] ) ) { |
| 503 | $roles = []; |
| 504 | |
| 505 | foreach ( $input['exclude']['roles'] as $role => $set ) { |
| 506 | if ( isset( $field['options']['roles'][$role] ) ) |
| 507 | $roles[] = $role; |
| 508 | } |
| 509 | |
| 510 | $input['exclude']['roles'] = array_unique( $roles ); |
| 511 | } else |
| 512 | $input['exclude']['roles'] = []; |
| 513 | |
| 514 | return $input; |
| 515 | } |
| 516 | |
| 517 | /** |
| 518 | * Setting: exclude IP addresses. |
| 519 | * |
| 520 | * @return string |
| 521 | */ |
| 522 | public function setting_exclude_ips() { |
| 523 | // get ip addresses |
| 524 | $ips = $this->pvc->options['general']['exclude_ips']; |
| 525 | |
| 526 | $html = ''; |
| 527 | |
| 528 | // any ip addresses? |
| 529 | if ( ! empty( $ips ) ) { |
| 530 | foreach ( $ips as $key => $ip ) { |
| 531 | $html .= ' |
| 532 | <div class="ip-box"> |
| 533 | <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_html__( 'Remove', 'post-views-counter' ) . '</a> |
| 534 | </div>'; |
| 535 | } |
| 536 | } else { |
| 537 | $html .= ' |
| 538 | <div class="ip-box"> |
| 539 | <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' ) . '" style="display: none">' . esc_html__( 'Remove', 'post-views-counter' ) . '</a> |
| 540 | </div>'; |
| 541 | } |
| 542 | |
| 543 | $html .= ' |
| 544 | <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> |
| 545 | <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 | // caching compatibility description |
| 621 | $caching_compatibility_desc = ''; |
| 622 | |
| 623 | // get active caching plugins |
| 624 | $active_plugins = $this->get_active_caching_plugins(); |
| 625 | |
| 626 | if ( ! empty( $active_plugins ) ) { |
| 627 | $empty_active_caching_plugins = false; |
| 628 | $active_plugins_html = []; |
| 629 | |
| 630 | $caching_compatibility_desc .= esc_html__( 'Currently detected active caching plugins', 'post-views-counter' ) . ': '; |
| 631 | |
| 632 | foreach ( $active_plugins as $plugin ) { |
| 633 | $active_plugins_html[] = '<code>' . esc_html( $plugin ) . '</code>'; |
| 634 | } |
| 635 | |
| 636 | $caching_compatibility_desc .= implode( ', ', $active_plugins_html ) . '.'; |
| 637 | } else { |
| 638 | $empty_active_caching_plugins = true; |
| 639 | |
| 640 | $caching_compatibility_desc .= esc_html__( 'No compatible caching plugins found.', 'post-views-counter' ); |
| 641 | } |
| 642 | |
| 643 | return $caching_compatibility_desc . '<br />' . __( 'Current status', 'post-views-counter' ) . ': <span class="' . ( ! $empty_active_caching_plugins ? '' : 'un' ) . 'available">' . ( ! $empty_active_caching_plugins ? __( 'available', 'post-views-counter' ) : __( 'unavailable', 'post-views-counter' ) ) . '</span>.'; |
| 644 | } |
| 645 | |
| 646 | /** |
| 647 | * Extend active caching plugins. |
| 648 | * |
| 649 | * @param array $plugins |
| 650 | * |
| 651 | * @return array |
| 652 | */ |
| 653 | public function extend_active_caching_plugins( $plugins ) { |
| 654 | // breeze |
| 655 | if ( $this->is_plugin_active( 'breeze' ) ) |
| 656 | $plugins[] = 'Breeze'; |
| 657 | |
| 658 | return $plugins; |
| 659 | } |
| 660 | |
| 661 | /** |
| 662 | * Check whether specified plugin is active. |
| 663 | * |
| 664 | * @param bool $is_plugin_active |
| 665 | * @param string $plugin |
| 666 | * |
| 667 | * @return bool |
| 668 | */ |
| 669 | public function extend_is_plugin_active( $is_plugin_active, $plugin ) { |
| 670 | // breeze |
| 671 | 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', '>=' ) ) |
| 672 | $is_plugin_active = true; |
| 673 | |
| 674 | return $is_plugin_active; |
| 675 | } |
| 676 | |
| 677 | /** |
| 678 | * Get active caching plugins. |
| 679 | * |
| 680 | * @return array |
| 681 | */ |
| 682 | public function get_active_caching_plugins() { |
| 683 | $active_plugins = []; |
| 684 | |
| 685 | // autoptimize |
| 686 | if ( $this->is_plugin_active( 'autoptimize' ) ) |
| 687 | $active_plugins[] = 'Autoptimize'; |
| 688 | |
| 689 | // hummingbird |
| 690 | if ( $this->is_plugin_active( 'hummingbird' ) ) |
| 691 | $active_plugins[] = 'Hummingbird'; |
| 692 | |
| 693 | // litespeed |
| 694 | if ( $this->is_plugin_active( 'litespeed' ) ) |
| 695 | $active_plugins[] = 'LiteSpeed Cache'; |
| 696 | |
| 697 | // speed optimizer |
| 698 | if ( $this->is_plugin_active( 'speedoptimizer' ) ) |
| 699 | $active_plugins[] = 'Speed Optimizer'; |
| 700 | |
| 701 | // speedycache |
| 702 | if ( $this->is_plugin_active( 'speedycache' ) ) |
| 703 | $active_plugins[] = 'SpeedyCache'; |
| 704 | |
| 705 | // wp fastest cache |
| 706 | if ( $this->is_plugin_active( 'wpfastestcache' ) ) |
| 707 | $active_plugins[] = 'WP Fastest Cache'; |
| 708 | |
| 709 | // wp-optimize |
| 710 | if ( $this->is_plugin_active( 'wpoptimize' ) ) |
| 711 | $active_plugins[] = 'WP-Optimize'; |
| 712 | |
| 713 | // wp rocket |
| 714 | if ( $this->is_plugin_active( 'wprocket' ) ) |
| 715 | $active_plugins[] = 'WP Rocket'; |
| 716 | |
| 717 | return apply_filters( 'pvc_active_caching_plugins', $active_plugins ); |
| 718 | } |
| 719 | |
| 720 | /** |
| 721 | * Check whether specified plugin is active. |
| 722 | * |
| 723 | * @param string $plugin |
| 724 | * |
| 725 | * @return bool |
| 726 | */ |
| 727 | public function is_plugin_active( $plugin = '' ) { |
| 728 | // set default flag |
| 729 | $is_plugin_active = false; |
| 730 | |
| 731 | switch ( $plugin ) { |
| 732 | // autoptimize |
| 733 | case 'autoptimize': |
| 734 | if ( function_exists( 'autoptimize' ) && defined( 'AUTOPTIMIZE_PLUGIN_VERSION' ) && version_compare( AUTOPTIMIZE_PLUGIN_VERSION, '2.4', '>=' ) ) |
| 735 | $is_plugin_active = true; |
| 736 | break; |
| 737 | |
| 738 | // hummingbird |
| 739 | case 'hummingbird': |
| 740 | if ( class_exists( 'Hummingbird\\WP_Hummingbird' ) && defined( 'WPHB_VERSION' ) && version_compare( WPHB_VERSION, '2.1.0', '>=' ) ) |
| 741 | $is_plugin_active = true; |
| 742 | break; |
| 743 | |
| 744 | // litespeed |
| 745 | case 'litespeed': |
| 746 | if ( class_exists( 'LiteSpeed\Core' ) && defined( 'LSCWP_CUR_V' ) && version_compare( LSCWP_CUR_V, '3.0', '>=' ) ) |
| 747 | $is_plugin_active = true; |
| 748 | break; |
| 749 | |
| 750 | // speed optimizer |
| 751 | case 'speedoptimizer': |
| 752 | global $siteground_optimizer_loader; |
| 753 | |
| 754 | 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', '>=' ) ) |
| 755 | $is_plugin_active = true; |
| 756 | break; |
| 757 | |
| 758 | // speedycache |
| 759 | case 'speedycache': |
| 760 | if ( class_exists( 'SpeedyCache' ) && defined( 'SPEEDYCACHE_VERSION' ) && function_exists( 'speedycache_delete_cache' ) && version_compare( SPEEDYCACHE_VERSION, '1.0.0', '>=' ) ) |
| 761 | $is_plugin_active = true; |
| 762 | break; |
| 763 | |
| 764 | // wp fastest cache |
| 765 | case 'wpfastestcache': |
| 766 | if ( function_exists( 'wpfc_clear_all_cache' ) ) |
| 767 | $is_plugin_active = true; |
| 768 | break; |
| 769 | |
| 770 | // wp-optimize |
| 771 | case 'wpoptimize': |
| 772 | if ( function_exists( 'WP_Optimize' ) && defined( 'WPO_VERSION' ) && version_compare( WPO_VERSION, '3.0.12', '>=' ) ) |
| 773 | $is_plugin_active = true; |
| 774 | break; |
| 775 | |
| 776 | // wp rocket |
| 777 | case 'wprocket': |
| 778 | if ( function_exists( 'rocket_init' ) && defined( 'WP_ROCKET_VERSION' ) && version_compare( WP_ROCKET_VERSION, '3.8', '>=' ) ) |
| 779 | $is_plugin_active = true; |
| 780 | break; |
| 781 | |
| 782 | // other caching plugin |
| 783 | default: |
| 784 | $is_plugin_active = apply_filters( 'pvc_is_plugin_active', false, $plugin ); |
| 785 | } |
| 786 | |
| 787 | return $is_plugin_active; |
| 788 | } |
| 789 | } |