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