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