PluginProbe ʕ •ᴥ•ʔ
Post Views Counter / 1.5.6
Post Views Counter v1.5.6
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 / post-views-counter.php
post-views-counter Last commit date
assets 9 months ago blocks 9 months ago css 9 months ago includes 9 months ago js 9 months ago languages 9 months ago index.php 6 years ago post-views-counter.php 9 months ago readme.txt 9 months ago
post-views-counter.php
964 lines
1 <?php
2 /*
3 Plugin Name: Post Views Counter
4 Description: Know What Content Drives Your Audience. Collect and display how many times a post, page or custom post type had been viewed in a simple, fast and reliable way.
5 Version: 1.5.6
6 Author: dFactory
7 Author URI: https://dfactory.co/
8 Plugin URI: https://postviewscounter.com/
9 License: MIT License
10 License URI: https://opensource.org/licenses/MIT
11 Text Domain: post-views-counter
12 Domain Path: /languages
13
14 Post Views Counter
15 Copyright (C) 2014-2025, Digital Factory - info@digitalfactory.pl
16
17 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 // exit if accessed directly
25 if ( ! defined( 'ABSPATH' ) )
26 exit;
27
28 if ( ! class_exists( 'Post_Views_Counter' ) ) {
29 /**
30 * Post Views Counter final class.
31 *
32 * @class Post_Views_Counter
33 * @version 1.5.6
34 */
35 final class Post_Views_Counter {
36
37 private static $instance;
38 private $notices;
39 public $options;
40 public $defaults = [
41 'general' => [
42 'post_types_count' => [ 'post' ],
43 'taxonomies_count' => false,
44 'users_count' => false,
45 'other_count' => false,
46 'data_storage' => 'cookies',
47 'amp_support' => false,
48 'counter_mode' => 'php',
49 'time_between_counts' => [
50 'number' => 24,
51 'type' => 'hours'
52 ],
53 'count_time' => 'gmt',
54 'reset_counts' => [
55 'number' => 0,
56 'type' => 'days'
57 ],
58 'caching_compatibility' => false,
59 'object_cache' => false,
60 'flush_interval' => [
61 'number' => 0,
62 'type' => 'minutes'
63 ],
64 'exclude' => [
65 'groups' => [],
66 'roles' => []
67 ],
68 'exclude_ips' => [],
69 'strict_counts' => false,
70 'cron_run' => true,
71 'cron_update' => true,
72 'update_version' => 1,
73 'update_notice' => true,
74 'update_delay_date' => 0
75 ],
76 'display' => [
77 'label' => 'Post Views:',
78 'display_period' => 'total',
79 'taxonomies_display' => [],
80 'user_display' => false,
81 'post_types_display' => [ 'post' ],
82 'page_types_display' => [ 'singular' ],
83 'restrict_display' => [
84 'groups' => [],
85 'roles' => []
86 ],
87 'position' => 'after',
88 'post_views_column' => true,
89 'restrict_edit_views' => false,
90 'dynamic_loading' => false,
91 'use_format' => true,
92 'display_style' => [
93 'icon' => true,
94 'text' => true
95 ],
96 'icon_class' => 'dashicons-chart-bar',
97 'toolbar_statistics' => true
98 ],
99 'other' => [
100 'menu_position' => 'top',
101 'import_meta_key' => 'views',
102 'deactivation_delete' => false,
103 'license' => ''
104 ],
105 'version' => '1.5.6'
106 ];
107
108 // instances
109 public $counter;
110 public $crawler;
111 public $cron;
112 public $dashboard;
113 public $frontend;
114 public $functions;
115 public $settings;
116 public $settings_api;
117
118 /**
119 * Disable object cloning.
120 *
121 * @return void
122 */
123 public function __clone() {}
124
125 /**
126 * Disable unserializing of the class.
127 *
128 * @return void
129 */
130 public function __wakeup() {}
131
132 /**
133 * Main plugin instance, insures that only one instance of the class exists in memory at one time.
134 *
135 * @return object
136 */
137 public static function instance() {
138 if ( ! isset( self::$instance ) && ! ( self::$instance instanceof Post_Views_Counter ) ) {
139 self::$instance = new Post_Views_Counter();
140
141 // short init?
142 if ( defined( 'SHORTINIT' ) && SHORTINIT ) {
143 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-counter.php' );
144 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-crawler-detect.php' );
145 include_once( POST_VIEWS_COUNTER_PATH . 'includes/functions.php' );
146
147 self::$instance->counter = new Post_Views_Counter_Counter();
148 self::$instance->crawler = new Post_Views_Counter_Crawler_Detect();
149 // regular setup
150 } else {
151 add_action( 'init', [ self::$instance, 'load_textdomain' ] );
152
153 self::$instance->includes();
154
155 // create settings API
156 self::$instance->settings_api = new Post_Views_Counter_Settings_API(
157 [
158 'object' => self::$instance,
159 'prefix' => 'post_views_counter',
160 'slug' => 'post-views-counter',
161 'domain' => 'post-views-counter',
162 'plugin' => 'Post Views Counter',
163 'plugin_url' => POST_VIEWS_COUNTER_URL
164 ]
165 );
166
167 // initialize other classes
168 self::$instance->functions = new Post_Views_Counter_Functions();
169
170 new Post_Views_Counter_Update();
171
172 self::$instance->settings = new Post_Views_Counter_Settings();
173
174 new Post_Views_Counter_Admin();
175 new Post_Views_Counter_Query();
176
177 self::$instance->cron = new Post_Views_Counter_Cron();
178 self::$instance->counter = new Post_Views_Counter_Counter();
179
180 new Post_Views_Counter_Columns();
181
182 self::$instance->crawler = new Post_Views_Counter_Crawler_Detect();
183 self::$instance->frontend = new Post_Views_Counter_Frontend();
184 self::$instance->dashboard = new Post_Views_Counter_Dashboard();
185
186 new Post_Views_Counter_Widgets();
187 }
188 }
189
190 return self::$instance;
191 }
192
193 /**
194 * Setup plugin constants.
195 *
196 * @return void
197 */
198 private function define_constants() {
199 // fix plugin_basename empty $wp_plugin_paths var
200 if ( ! ( defined( 'SHORTINIT' ) && SHORTINIT ) ) {
201 define( 'POST_VIEWS_COUNTER_URL', plugins_url( '', __FILE__ ) );
202 define( 'POST_VIEWS_COUNTER_BASENAME', plugin_basename( __FILE__ ) );
203 define( 'POST_VIEWS_COUNTER_REL_PATH', dirname( POST_VIEWS_COUNTER_BASENAME ) );
204 }
205
206 define( 'POST_VIEWS_COUNTER_PATH', plugin_dir_path( __FILE__ ) );
207 }
208
209 /**
210 * Include required files.
211 *
212 * @return void
213 */
214 private function includes() {
215 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-functions.php' );
216 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-update.php' );
217 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-settings-api.php' );
218 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-settings.php' );
219 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-admin.php' );
220 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-columns.php' );
221 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-query.php' );
222 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-cron.php' );
223 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-counter.php' );
224 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-crawler-detect.php' );
225 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-frontend.php' );
226 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-dashboard.php' );
227 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-widgets.php' );
228 }
229
230 /**
231 * Class constructor.
232 *
233 * @return void
234 */
235 private function __construct() {
236 // define plugin constants
237 $this->define_constants();
238
239 // short init?
240 if ( defined( 'SHORTINIT' ) && SHORTINIT ) {
241 $this->options = [
242 'general' => array_merge( $this->defaults['general'], get_option( 'post_views_counter_settings_general', $this->defaults['general'] ) ),
243 'display' => array_merge( $this->defaults['display'], get_option( 'post_views_counter_settings_display', $this->defaults['display'] ) ),
244 'other' => array_merge( $this->defaults['other'], get_option( 'post_views_counter_settings_other', $this->defaults['other'] ) )
245 ];
246
247 return;
248 }
249
250 // activation hooks
251 register_activation_hook( __FILE__, [ $this, 'activation' ] );
252 register_deactivation_hook( __FILE__, [ $this, 'deactivation' ] );
253
254 // settings
255 $this->options = [
256 'general' => array_merge( $this->defaults['general'], get_option( 'post_views_counter_settings_general', $this->defaults['general'] ) ),
257 'display' => array_merge( $this->defaults['display'], get_option( 'post_views_counter_settings_display', $this->defaults['display'] ) ),
258 'other' => array_merge( $this->defaults['other'], get_option( 'post_views_counter_settings_other', $this->defaults['other'] ) )
259 ];
260
261 // 1.5.3+
262 if ( ! isset( $this->options['general']['post_views_column'] ) )
263 $this->options['general']['post_views_column'] = $this->options['display']['post_views_column'];
264
265 if ( ! isset( $this->options['general']['restrict_edit_views'] ) )
266 $this->options['general']['restrict_edit_views'] = $this->options['display']['restrict_edit_views'];
267
268 // actions
269 add_action( 'plugins_loaded', [ $this, 'extend_caching_plugins' ], -1 );
270 add_action( 'admin_enqueue_scripts', [ $this, 'admin_enqueue_scripts' ] );
271 add_action( 'wp_loaded', [ $this, 'load_pluggable_functions' ] );
272 add_action( 'init', [ $this, 'register_blocks' ] );
273 add_action( 'admin_init', [ $this, 'update_notice' ] );
274 add_action( 'wp_initialize_site', [ $this, 'init_new_network_site' ] );
275 add_action( 'wp_ajax_pvc_dismiss_notice', [ $this, 'dismiss_notice' ] );
276
277 // filters
278 add_filter( 'plugin_action_links_' . POST_VIEWS_COUNTER_BASENAME, [ $this, 'plugin_settings_link' ] );
279 }
280
281 /**
282 * Extend list of caching plugins.
283 *
284 * @return void
285 */
286 public function extend_caching_plugins() {
287 // add new caching plugins
288 add_filter( 'pvc_active_caching_plugins', [ $this->settings, 'extend_active_caching_plugins' ] );
289 add_filter( 'pvc_is_plugin_active', [ $this->settings, 'extend_is_plugin_active' ], 10, 2 );
290 }
291
292 /**
293 * Register blocks.
294 *
295 * @global object $wp_version
296 *
297 * @return void
298 */
299 public function register_blocks() {
300 global $wp_version;
301
302 // actions
303 add_action( 'enqueue_block_editor_assets', [ $this, 'block_editor_enqueue_scripts' ] );
304
305 // filters
306 if ( version_compare( $wp_version, '5.8', '>=' ) )
307 add_filter( 'block_categories_all', [ $this, 'add_block_category' ] );
308 else
309 add_filter( 'block_categories', [ $this, 'add_block_category' ] );
310
311 add_filter( 'register_block_type_args', [ $this, 'update_block_args' ], 10, 2 );
312
313 register_block_type( __DIR__ . '/blocks/most-viewed-posts/build' );
314 register_block_type( __DIR__ . '/blocks/post-views/build' );
315 }
316
317 /**
318 * Enqueue block scripts.
319 *
320 * @global object $wp_version
321 *
322 * @return void
323 */
324 public function block_editor_enqueue_scripts() {
325 // enqueue script
326 wp_enqueue_script( 'post-views-counter-block-editor-script', POST_VIEWS_COUNTER_URL . '/js/dummy.js', [] );
327
328 $block_image_sizes = [];
329
330 // image sizes
331 $image_sizes = array_merge( [ 'full' ], get_intermediate_image_sizes() );
332
333 // sort image sizes by name, ascending
334 sort( $image_sizes, SORT_STRING );
335
336 foreach ( $image_sizes as $image_size ) {
337 $block_image_sizes[] = [
338 'label' => $image_size,
339 'value' => $image_size
340 ];
341 }
342
343 $post_types = Post_Views_Counter()->functions->get_post_types();
344
345 // prepare script data
346 $script_data = [
347 'postTypesKeys' => array_combine( array_keys( $post_types ), array_fill( 0, count( $post_types ), false ) ),
348 'postTypes' => $post_types,
349 'imageSizes' => $block_image_sizes
350 ];
351
352 // force post as enabled
353 $script_data['postTypesKeys']['post'] = true;
354
355 // prepare script data
356 $script_data['periods'] = [ [
357 'label' => __( 'Total Views', 'post-views-counter' ),
358 'value' => 'total'
359 ] ];
360
361 $script_data = apply_filters( 'pvc_block_editor_data', $script_data );
362
363 wp_add_inline_script( 'post-views-counter-block-editor-script', 'var pvcBlockEditorData = ' . wp_json_encode( $script_data ) . ";\n", 'before' );
364 }
365
366 /**
367 * Update block arguments.
368 *
369 * @param array $args
370 * @param string $block_type
371 *
372 * @return array
373 */
374 function update_block_args( $args, $block_type ) {
375 // most viewed posts block
376 if ( $block_type === 'post-views-counter/most-viewed-posts' )
377 $args['render_callback'] = [ $this, 'most_viewed_posts_render_callback' ];
378 // post views block
379 elseif ( $block_type === 'post-views-counter/post-views' )
380 $args['render_callback'] = [ $this, 'post_views_render_callback' ];
381
382 return $args;
383 }
384
385 /**
386 * Server side block renderer for most viewed posts.
387 *
388 * @param array $attributes
389 * @param string $content
390 *
391 * @return array
392 */
393 function most_viewed_posts_render_callback( $attributes, $content ) {
394 $post_types = [];
395
396 foreach ( $attributes['postTypes'] as $post_type => $enabled ) {
397 if ( $enabled === true || $enabled === 'true' )
398 $post_types[] = $post_type;
399 }
400
401 // map block attributes
402 $args = [
403 'number_of_posts' => max( 1, (int) $attributes['numberOfPosts'] ),
404 'post_type' => $post_types,
405 'period' => $attributes['period'],
406 'order' => $attributes['order'],
407 'thumbnail_size' => $attributes['thumbnailSize'],
408 'list_type' => $attributes['listType'],
409 'show_post_views' => (bool) $attributes['displayPostViews'],
410 'show_post_thumbnail' => (bool) $attributes['displayPostThumbnail'],
411 'show_post_author' => (bool) $attributes['displayPostAuthor'],
412 'show_post_excerpt' => (bool) $attributes['displayPostExcerpt'],
413 'no_posts_message' => $attributes['noPostsMessage']
414 ];
415
416 $title = trim( $attributes['title'] );
417
418 $html = '<div ' . get_block_wrapper_attributes() . '>';
419
420 if ( $title !== '' )
421 $html .= '<h2 class="block-title">' . esc_html( $title ) . '</h2>';
422
423 $html .= pvc_most_viewed_posts( $args, false );
424 $html .= '</div>';
425
426 return $html;
427 }
428
429 /**
430 * Server side block renderer for post views.
431 *
432 * @param array $attributes
433 * @param string $content
434 *
435 * @return array
436 */
437 function post_views_render_callback( $attributes, $content ) {
438 $html = '<div ' . get_block_wrapper_attributes() . '>';
439 $html .= pvc_post_views( (int) $attributes['postID'], false, $attributes['period'] );
440 $html .= '</div>';
441
442 return $html;
443 }
444
445 /**
446 * Add new blocks category.
447 *
448 * @param array $categories
449 *
450 * @return array
451 */
452 function add_block_category( $categories ) {
453 $categories[] = [
454 'slug' => 'post-views-counter',
455 'title' => 'Post Views Counter'
456 ];
457
458 return $categories;
459 }
460
461 /**
462 * Update notice.
463 *
464 * @return void
465 */
466 public function update_notice() {
467 if ( ! current_user_can( 'install_plugins' ) )
468 return;
469
470 $current_update = 2;
471
472 // get current time
473 $current_time = time();
474
475 if ( $this->options['general']['update_version'] < $current_update ) {
476 // check version, if update version is lower than plugin version, set update notice to true
477 $this->options['general'] = array_merge(
478 $this->options['general'],
479 [
480 'update_version' => $current_update,
481 'update_notice' => true
482 ]
483 );
484
485 update_option( 'post_views_counter_settings_general', $this->options['general'] );
486
487 // set activation date
488 $activation_date = get_option( 'post_views_counter_activation_date' );
489
490 if ( $activation_date === false )
491 update_option( 'post_views_counter_activation_date', $current_time );
492 }
493
494 // display current version notice
495 if ( $this->options['general']['update_notice'] === true ) {
496 // include notice js, only if needed
497 add_action( 'admin_print_scripts', [ $this, 'admin_inline_js' ], 999 );
498
499 // get activation date
500 $activation_date = get_option( 'post_views_counter_activation_date' );
501
502 if ( (int) $this->options['general']['update_delay_date'] === 0 ) {
503 if ( $activation_date + 2 * WEEK_IN_SECONDS > $current_time )
504 $this->options['general']['update_delay_date'] = $activation_date + 2 * WEEK_IN_SECONDS;
505 else
506 $this->options['general']['update_delay_date'] = $current_time;
507
508 update_option( 'post_views_counter_settings_general', $this->options['general'] );
509 }
510
511 if ( ( ! empty( $this->options['general']['update_delay_date'] ) ? (int) $this->options['general']['update_delay_date'] : $current_time ) <= $current_time )
512 $this->add_notice( sprintf( __( "Hey, you've been using <strong>Post Views Counter</strong> for more than %s.", 'post-views-counter' ), human_time_diff( $activation_date, $current_time ) ) . '<br />' . __( 'Could you please do me a BIG favor and give it a 5-star rating on WordPress to help us spread the word and boost our motivation.', 'post-views-counter' ) . '<br /><br />' . __( 'Your help is much appreciated. Thank you very much', 'post-views-counter' ) . ' ~ <strong>Bartosz Arendt</strong>, ' . __( 'founder of', 'post-views-counter' ) . ' <a href="https://postviewscounter.com/" target="_blank">Post Views Counter</a>.' . '<br /><br />' . '<a href="https://wordpress.org/support/plugin/post-views-counter/reviews/?filter=5#new-post" class="pvc-dismissible-notice" target="_blank" rel="noopener">' . __( 'Ok, you deserve it', 'post-views-counter' ) . '</a><br /><a href="#" class="pvc-dismissible-notice pvc-delay-notice" rel="noopener">' . __( 'Nope, maybe later', 'post-views-counter' ) . '</a><br /><a href="#" class="pvc-dismissible-notice" rel="noopener">' . __( 'I already did', 'post-views-counter' ) . '</a>', 'notice notice-info is-dismissible pvc-notice' );
513 }
514 }
515
516 /**
517 * Add admin notices.
518 *
519 * @param string $html Notice HTML
520 * @param string $status Notice status
521 * @param bool $paragraph Whether to use paragraph
522 * @param bool $network
523 *
524 * @return void
525 */
526 public function add_notice( $html = '', $status = 'error', $paragraph = true, $network = false ) {
527 $this->notices[] = [
528 'html' => $html,
529 'status' => $status,
530 'paragraph' => $paragraph
531 ];
532
533 add_action( 'admin_notices', [ $this, 'display_notice' ] );
534
535 if ( $network )
536 add_action( 'network_admin_notices', [ $this, 'display_notice' ] );
537 }
538
539 /**
540 * Print admin notices.
541 *
542 * @return void
543 */
544 public function display_notice() {
545 $allowed_html = array_merge(
546 wp_kses_allowed_html( 'post' ),
547 [
548 'input' => [
549 'type' => true,
550 'name' => true,
551 'class' => true,
552 'value' => true
553 ],
554 'form' => [
555 'action' => true,
556 'method' => true
557 ]
558 ]
559 );
560
561 foreach ( $this->notices as $notice ) {
562 echo '
563 <div class="' . esc_attr( $notice['status'] ) . '">
564 ' . ( $notice['paragraph'] ? '<p>' : '' ) . '
565 ' . wp_kses( $notice['html'], $allowed_html ) . '
566 ' . ( $notice['paragraph'] ? '</p>' : '' ) . '
567 </div>';
568 }
569 }
570
571 /**
572 * Print admin scripts.
573 *
574 * @return void
575 */
576 public function admin_inline_js() {
577 if ( ! current_user_can( 'install_plugins' ) )
578 return;
579
580 // register and enqueue styles
581 wp_register_script( 'pvc-notices', false );
582 wp_enqueue_script( 'pvc-notices' );
583
584 // add styles
585 wp_add_inline_script( 'pvc-notices', "
586 ( function( $ ) {
587 // ready event
588 $( function() {
589 // save dismiss state
590 $( '.pvc-notice.is-dismissible' ).on( 'click', '.notice-dismiss, .pvc-dismissible-notice', function( e ) {
591 if ( e.currentTarget.target !== '_blank' )
592 e.preventDefault();
593
594 var notice_action = 'hide';
595
596 if ( e.currentTarget.classList.contains( 'pvc-delay-notice' ) )
597 notice_action = 'delay';
598
599 $.post( ajaxurl, {
600 action: 'pvc_dismiss_notice',
601 notice_action: notice_action,
602 url: '" . esc_url_raw( admin_url( 'admin-ajax.php' ) ) . "',
603 nonce: '" . esc_attr( wp_create_nonce( 'pvc_dismiss_notice' ) ) . "'
604 } );
605
606 $( e.delegateTarget ).slideUp( 'fast' );
607 } );
608 } );
609 } )( jQuery );
610 ", 'after' );
611 }
612
613 /**
614 * Dismiss notice.
615 *
616 * @return void
617 */
618 public function dismiss_notice() {
619 if ( ! current_user_can( 'install_plugins' ) )
620 return;
621
622 if ( isset( $_REQUEST['nonce'] ) && wp_verify_nonce( $_REQUEST['nonce'], 'pvc_dismiss_notice' ) ) {
623 $notice_action = empty( $_REQUEST['notice_action'] ) || $_REQUEST['notice_action'] === 'hide' ? 'hide' : sanitize_text_field( $_REQUEST['notice_action'] );
624
625 switch ( $notice_action ) {
626 // delay notice
627 case 'delay':
628 // set delay period to 1 week from now
629 $this->options['general'] = array_merge(
630 $this->options['general'],
631 [
632 'update_delay_date' => time() + 2 * WEEK_IN_SECONDS
633 ]
634 );
635 update_option( 'post_views_counter_settings_general', $this->options['general'] );
636 break;
637
638 // hide notice
639 default:
640 $this->options['general'] = array_merge(
641 $this->options['general'],
642 [
643 'update_notice' => false
644 ]
645 );
646 $this->options['general'] = array_merge(
647 $this->options['general'],
648 [
649 'update_delay_date' => 0
650 ]
651 );
652
653 update_option( 'post_views_counter_settings_general', $this->options['general'] );
654 }
655 }
656
657 exit;
658 }
659
660 /**
661 * Plugin activation.
662 *
663 * @global object $wpdb
664 *
665 * @param bool $network
666 *
667 * @return void
668 */
669 public function activation( $network ) {
670 // network activation?
671 if ( is_multisite() && $network ) {
672 global $wpdb;
673
674 // get all available sites
675 $blogs_ids = $wpdb->get_col( 'SELECT blog_id FROM ' . $wpdb->blogs );
676
677 foreach ( $blogs_ids as $blog_id ) {
678 // change to another site
679 switch_to_blog( (int) $blog_id );
680
681 // run current site activation process
682 $this->activate_site();
683
684 restore_current_blog();
685 }
686 } else
687 $this->activate_site();
688 }
689
690 /**
691 * Single site activation.
692 *
693 * @global object $wpdb
694 * @global string $charset_collate
695 *
696 * @return void
697 */
698 public function activate_site() {
699 global $wpdb, $charset_collate;
700
701 // required for dbdelta
702 require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
703
704 // create post views table
705 dbDelta( '
706 CREATE TABLE IF NOT EXISTS ' . $wpdb->prefix . 'post_views (
707 `id` bigint unsigned NOT NULL,
708 `type` tinyint(1) unsigned NOT NULL,
709 `period` varchar(8) NOT NULL,
710 `count` bigint unsigned NOT NULL,
711 PRIMARY KEY (type, period, id),
712 UNIQUE INDEX id_type_period_count (id, type, period, count) USING BTREE,
713 INDEX type_period_count (type, period, count) USING BTREE
714 ) ' . $charset_collate . ';'
715 );
716
717 // add default options
718 add_option( 'post_views_counter_settings_general', $this->defaults['general'], null, false );
719 add_option( 'post_views_counter_settings_display', $this->defaults['display'], null, false );
720 add_option( 'post_views_counter_settings_other', $this->defaults['other'], null, false );
721 add_option( 'post_views_counter_version', $this->defaults['version'], null, false );
722 }
723
724 /**
725 * Plugin deactivation.
726 *
727 * @global object $wpdb
728 *
729 * @param bool $network
730 *
731 * @return void
732 */
733 public function deactivation( $network ) {
734 // network deactivation?
735 if ( is_multisite() && $network ) {
736 global $wpdb;
737
738 // get all available sites
739 $blogs_ids = $wpdb->get_col( 'SELECT blog_id FROM ' . $wpdb->blogs );
740
741 foreach ( $blogs_ids as $blog_id ) {
742 // change to another site
743 switch_to_blog( (int) $blog_id );
744
745 // run current site deactivation process
746 $this->deactivate_site( true );
747
748 restore_current_blog();
749 }
750 } else
751 $this->deactivate_site();
752 }
753
754 /**
755 * Single site deactivation.
756 *
757 * @global object $wpdb
758 *
759 * @param bool $multi
760 *
761 * @return void
762 */
763 public function deactivate_site( $multi = false ) {
764 if ( $multi === true ) {
765 $options = get_option( 'post_views_counter_settings_other' );
766 $check = $options['deactivation_delete'];
767 } else
768 $check = $this->options['other']['deactivation_delete'];
769
770 // delete options if needed
771 if ( $check ) {
772 // delete options
773 delete_option( 'post_views_counter_settings_general' );
774 delete_option( 'post_views_counter_settings_display' );
775 delete_option( 'post_views_counter_settings_other' );
776 delete_option( 'post_views_counter_activation_date' );
777 delete_option( 'post_views_counter_version' );
778
779 // delete transients
780 delete_transient( 'post_views_counter_ip_cache' );
781
782 global $wpdb;
783
784 // delete table from database
785 $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'post_views' );
786 }
787
788 // remove schedule
789 wp_clear_scheduled_hook( 'pvc_reset_counts' );
790
791 remove_action( 'pvc_reset_counts', [ $this->cron, 'reset_counts' ] );
792 }
793
794 /**
795 * Initialize new network site.
796 *
797 * @param object $site
798 *
799 * @return void
800 */
801 public function init_new_network_site( $site ) {
802 if ( is_multisite() ) {
803 // change to another site
804 switch_to_blog( $site->blog_id );
805
806 // run current site activation process
807 $this->activate_site();
808
809 restore_current_blog();
810 }
811 }
812
813 /**
814 * Load text domain.
815 *
816 * @return void
817 */
818 public function load_textdomain() {
819 load_plugin_textdomain( 'post-views-counter', false, POST_VIEWS_COUNTER_REL_PATH . '/languages/' );
820 }
821
822 /**
823 * Load pluggable template functions.
824 *
825 * @return void
826 */
827 public function load_pluggable_functions() {
828 include_once( POST_VIEWS_COUNTER_PATH . 'includes/functions.php' );
829 }
830
831 /**
832 * Enqueue admin scripts and styles.
833 *
834 * @global string $post_type
835 * @global string $wp_version
836 *
837 * @param string $page
838 *
839 * @return void
840 */
841 public function admin_enqueue_scripts( $page ) {
842 global $post_type;
843 global $wp_version;
844
845 // register styles
846 wp_register_style( 'pvc-admin', POST_VIEWS_COUNTER_URL . '/css/admin.min.css', [], $this->defaults['version'] );
847
848 // register scripts
849 wp_register_script( 'pvc-admin-settings', POST_VIEWS_COUNTER_URL . '/js/admin-settings.js', [ 'jquery' ], $this->defaults['version'] );
850 wp_register_script( 'pvc-admin-post', POST_VIEWS_COUNTER_URL . '/js/admin-post.js', [ 'jquery' ], $this->defaults['version'] );
851 wp_register_script( 'pvc-admin-quick-edit', POST_VIEWS_COUNTER_URL . '/js/admin-quick-edit.js', [ 'jquery' ], $this->defaults['version'] );
852
853 // load on pvc settings page
854 if ( in_array( $page, [ 'toplevel_page_post-views-counter', 'settings_page_post-views-counter' ], true ) ) {
855 wp_enqueue_script( 'pvc-admin-settings' );
856
857 // prepare script data
858 $script_data = [
859 'resetToDefaults' => esc_html__( 'Are you sure you want to reset these settings to defaults?', 'post-views-counter' ),
860 'resetViews' => esc_html__( 'Are you sure you want to delete all existing data?', 'post-views-counter' )
861 ];
862
863 wp_add_inline_script( 'pvc-admin-settings', 'var pvcArgsSettings = ' . wp_json_encode( $script_data ) . ";\n", 'before' );
864
865 wp_enqueue_style( 'pvc-admin' );
866 // load on single post page
867 } elseif ( $page === 'post.php' || $page === 'post-new.php' ) {
868 $post_types = Post_Views_Counter()->options['general']['post_types_count'];
869
870 if ( ! in_array( $post_type, (array) $post_types ) )
871 return;
872
873 wp_enqueue_style( 'pvc-admin' );
874 wp_enqueue_script( 'pvc-admin-post' );
875 // edit post
876 } elseif ( $page === 'edit.php' ) {
877 $post_types = Post_Views_Counter()->options['general']['post_types_count'];
878
879 if ( ! in_array( $post_type, (array) $post_types ) )
880 return;
881
882 wp_enqueue_style( 'pvc-admin' );
883
884 // woocommerce
885 if ( get_post_type() !== 'product' ) {
886 wp_enqueue_script( 'pvc-admin-quick-edit' );
887
888 // prepare script data
889 $script_data = [
890 'nonce' => wp_create_nonce( 'pvc_save_bulk_post_views' ),
891 'wpVersion59' => version_compare( $wp_version, '5.9', '>=' )
892 ];
893
894 wp_add_inline_script( 'pvc-admin-quick-edit', 'var pvcArgsQuickEdit = ' . wp_json_encode( $script_data ) . ";\n", 'before' );
895 }
896 // widgets
897 } elseif ( $page === 'widgets.php' )
898 wp_enqueue_script( 'pvc-admin-widgets', POST_VIEWS_COUNTER_URL . '/js/admin-widgets.js', [ 'jquery' ], $this->defaults['version'] );
899 // media
900 elseif ( $page === 'upload.php' )
901 wp_enqueue_style( 'pvc-admin' );
902
903 // register and enqueue styles
904 wp_register_style( 'pvc-pro-style', false );
905 wp_enqueue_style( 'pvc-pro-style' );
906
907 // add styles
908 wp_add_inline_style( 'pvc-pro-style', '
909 .post-views-counter-settings tr.pvc-pro th:after, .nav-tab-wrapper a.nav-tab.nav-tab-disabled.pvc-pro:after, .post-views-counter-settings tr.pvc-pro-extended label[for="post_views_counter_general_counter_mode_ajax"]:after,
910 .post-views-counter-settings tr.pvc-pro-extended label[for="pvc_exclude-ai_bots"]:after {
911 content: \'PRO\';
912 display: inline;
913 background-color: #ffc107;
914 color: white;
915 padding: 2px 4px;
916 text-align: center;
917 border-radius: 4px;
918 margin-left: 4px;
919 font-weight: bold;
920 font-size: 11px;
921 }' );
922 }
923
924 /**
925 * Add link to Settings page.
926 *
927 * @param array $links
928 *
929 * @return array
930 */
931 public function plugin_settings_link( $links ) {
932 if ( ! current_user_can( 'manage_options' ) )
933 return $links;
934
935 // submenu?
936 if ( $this->options['other']['menu_position'] === 'sub' )
937 $url = admin_url( 'options-general.php?page=post-views-counter' );
938 // topmenu?
939 else
940 $url = admin_url( 'admin.php?page=post-views-counter' );
941
942 array_unshift( $links, sprintf( '<a href="%s">%s</a>', esc_url_raw( $url ), esc_html__( 'Settings', 'post-views-counter' ) ) );
943
944 return $links;
945 }
946 }
947 }
948
949 /**
950 * Initialize Post Views Counter.
951 *
952 * @return object
953 */
954 function Post_Views_Counter() {
955 static $instance;
956
957 // first call to instance() initializes the plugin
958 if ( $instance === null || ! ( $instance instanceof Post_Views_Counter ) )
959 $instance = Post_Views_Counter::instance();
960
961 return $instance;
962 }
963
964 Post_Views_Counter();