PluginProbe ʕ •ᴥ•ʔ
Post Views Counter / 1.5.5
Post Views Counter v1.5.5
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
952 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.5
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.5
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.5'
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( 'admin_enqueue_scripts', [ $this, 'admin_enqueue_scripts' ] );
270 add_action( 'wp_loaded', [ $this, 'load_pluggable_functions' ] );
271 add_action( 'init', [ $this, 'register_blocks' ] );
272 add_action( 'admin_init', [ $this, 'update_notice' ] );
273 add_action( 'wp_initialize_site', [ $this, 'init_new_network_site' ] );
274 add_action( 'wp_ajax_pvc_dismiss_notice', [ $this, 'dismiss_notice' ] );
275
276 // filters
277 add_filter( 'plugin_action_links_' . POST_VIEWS_COUNTER_BASENAME, [ $this, 'plugin_settings_link' ] );
278 }
279
280 /**
281 * Register blocks.
282 *
283 * @global object $wp_version
284 *
285 * @return void
286 */
287 public function register_blocks() {
288 global $wp_version;
289
290 // actions
291 add_action( 'enqueue_block_editor_assets', [ $this, 'block_editor_enqueue_scripts' ] );
292
293 // filters
294 if ( version_compare( $wp_version, '5.8', '>=' ) )
295 add_filter( 'block_categories_all', [ $this, 'add_block_category' ] );
296 else
297 add_filter( 'block_categories', [ $this, 'add_block_category' ] );
298
299 add_filter( 'register_block_type_args', [ $this, 'update_block_args' ], 10, 2 );
300
301 register_block_type( __DIR__ . '/blocks/most-viewed-posts/build' );
302 register_block_type( __DIR__ . '/blocks/post-views/build' );
303 }
304
305 /**
306 * Enqueue block scripts.
307 *
308 * @global object $wp_version
309 *
310 * @return void
311 */
312 public function block_editor_enqueue_scripts() {
313 // enqueue script
314 wp_enqueue_script( 'post-views-counter-block-editor-script', POST_VIEWS_COUNTER_URL . '/js/dummy.js', [] );
315
316 $block_image_sizes = [];
317
318 // image sizes
319 $image_sizes = array_merge( [ 'full' ], get_intermediate_image_sizes() );
320
321 // sort image sizes by name, ascending
322 sort( $image_sizes, SORT_STRING );
323
324 foreach ( $image_sizes as $image_size ) {
325 $block_image_sizes[] = [
326 'label' => $image_size,
327 'value' => $image_size
328 ];
329 }
330
331 $post_types = Post_Views_Counter()->functions->get_post_types();
332
333 // prepare script data
334 $script_data = [
335 'postTypesKeys' => array_combine( array_keys( $post_types ), array_fill( 0, count( $post_types ), false ) ),
336 'postTypes' => $post_types,
337 'imageSizes' => $block_image_sizes
338 ];
339
340 // force post as enabled
341 $script_data['postTypesKeys']['post'] = true;
342
343 // prepare script data
344 $script_data['periods'] = [ [
345 'label' => __( 'Total Views', 'post-views-counter' ),
346 'value' => 'total'
347 ] ];
348
349 $script_data = apply_filters( 'pvc_block_editor_data', $script_data );
350
351 wp_add_inline_script( 'post-views-counter-block-editor-script', 'var pvcBlockEditorData = ' . wp_json_encode( $script_data ) . ";\n", 'before' );
352 }
353
354 /**
355 * Update block arguments.
356 *
357 * @param array $args
358 * @param string $block_type
359 *
360 * @return array
361 */
362 function update_block_args( $args, $block_type ) {
363 // most viewed posts block
364 if ( $block_type === 'post-views-counter/most-viewed-posts' )
365 $args['render_callback'] = [ $this, 'most_viewed_posts_render_callback' ];
366 // post views block
367 elseif ( $block_type === 'post-views-counter/post-views' )
368 $args['render_callback'] = [ $this, 'post_views_render_callback' ];
369
370 return $args;
371 }
372
373 /**
374 * Server side block renderer for most viewed posts.
375 *
376 * @param array $attributes
377 * @param string $content
378 *
379 * @return array
380 */
381 function most_viewed_posts_render_callback( $attributes, $content ) {
382 $post_types = [];
383
384 foreach ( $attributes['postTypes'] as $post_type => $enabled ) {
385 if ( $enabled === true || $enabled === 'true' )
386 $post_types[] = $post_type;
387 }
388
389 // map block attributes
390 $args = [
391 'number_of_posts' => max( 1, (int) $attributes['numberOfPosts'] ),
392 'post_type' => $post_types,
393 'period' => $attributes['period'],
394 'order' => $attributes['order'],
395 'thumbnail_size' => $attributes['thumbnailSize'],
396 'list_type' => $attributes['listType'],
397 'show_post_views' => (bool) $attributes['displayPostViews'],
398 'show_post_thumbnail' => (bool) $attributes['displayPostThumbnail'],
399 'show_post_author' => (bool) $attributes['displayPostAuthor'],
400 'show_post_excerpt' => (bool) $attributes['displayPostExcerpt'],
401 'no_posts_message' => $attributes['noPostsMessage']
402 ];
403
404 $title = trim( $attributes['title'] );
405
406 $html = '<div ' . get_block_wrapper_attributes() . '>';
407
408 if ( $title !== '' )
409 $html .= '<h2 class="block-title">' . esc_html( $title ) . '</h2>';
410
411 $html .= pvc_most_viewed_posts( $args, false );
412 $html .= '</div>';
413
414 return $html;
415 }
416
417 /**
418 * Server side block renderer for post views.
419 *
420 * @param array $attributes
421 * @param string $content
422 *
423 * @return array
424 */
425 function post_views_render_callback( $attributes, $content ) {
426 $html = '<div ' . get_block_wrapper_attributes() . '>';
427 $html .= pvc_post_views( (int) $attributes['postID'], false, $attributes['period'] );
428 $html .= '</div>';
429
430 return $html;
431 }
432
433 /**
434 * Add new blocks category.
435 *
436 * @param array $categories
437 *
438 * @return array
439 */
440 function add_block_category( $categories ) {
441 $categories[] = [
442 'slug' => 'post-views-counter',
443 'title' => 'Post Views Counter'
444 ];
445
446 return $categories;
447 }
448
449 /**
450 * Update notice.
451 *
452 * @return void
453 */
454 public function update_notice() {
455 if ( ! current_user_can( 'install_plugins' ) )
456 return;
457
458 $current_update = 2;
459
460 // get current time
461 $current_time = time();
462
463 if ( $this->options['general']['update_version'] < $current_update ) {
464 // check version, if update version is lower than plugin version, set update notice to true
465 $this->options['general'] = array_merge(
466 $this->options['general'],
467 [
468 'update_version' => $current_update,
469 'update_notice' => true
470 ]
471 );
472
473 update_option( 'post_views_counter_settings_general', $this->options['general'] );
474
475 // set activation date
476 $activation_date = get_option( 'post_views_counter_activation_date' );
477
478 if ( $activation_date === false )
479 update_option( 'post_views_counter_activation_date', $current_time );
480 }
481
482 // display current version notice
483 if ( $this->options['general']['update_notice'] === true ) {
484 // include notice js, only if needed
485 add_action( 'admin_print_scripts', [ $this, 'admin_inline_js' ], 999 );
486
487 // get activation date
488 $activation_date = get_option( 'post_views_counter_activation_date' );
489
490 if ( (int) $this->options['general']['update_delay_date'] === 0 ) {
491 if ( $activation_date + 2 * WEEK_IN_SECONDS > $current_time )
492 $this->options['general']['update_delay_date'] = $activation_date + 2 * WEEK_IN_SECONDS;
493 else
494 $this->options['general']['update_delay_date'] = $current_time;
495
496 update_option( 'post_views_counter_settings_general', $this->options['general'] );
497 }
498
499 if ( ( ! empty( $this->options['general']['update_delay_date'] ) ? (int) $this->options['general']['update_delay_date'] : $current_time ) <= $current_time )
500 $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' );
501 }
502 }
503
504 /**
505 * Add admin notices.
506 *
507 * @param string $html Notice HTML
508 * @param string $status Notice status
509 * @param bool $paragraph Whether to use paragraph
510 * @param bool $network
511 *
512 * @return void
513 */
514 public function add_notice( $html = '', $status = 'error', $paragraph = true, $network = false ) {
515 $this->notices[] = [
516 'html' => $html,
517 'status' => $status,
518 'paragraph' => $paragraph
519 ];
520
521 add_action( 'admin_notices', [ $this, 'display_notice' ] );
522
523 if ( $network )
524 add_action( 'network_admin_notices', [ $this, 'display_notice' ] );
525 }
526
527 /**
528 * Print admin notices.
529 *
530 * @return void
531 */
532 public function display_notice() {
533 $allowed_html = array_merge(
534 wp_kses_allowed_html( 'post' ),
535 [
536 'input' => [
537 'type' => true,
538 'name' => true,
539 'class' => true,
540 'value' => true
541 ],
542 'form' => [
543 'action' => true,
544 'method' => true
545 ]
546 ]
547 );
548
549 foreach ( $this->notices as $notice ) {
550 echo '
551 <div class="' . esc_attr( $notice['status'] ) . '">
552 ' . ( $notice['paragraph'] ? '<p>' : '' ) . '
553 ' . wp_kses( $notice['html'], $allowed_html ) . '
554 ' . ( $notice['paragraph'] ? '</p>' : '' ) . '
555 </div>';
556 }
557 }
558
559 /**
560 * Print admin scripts.
561 *
562 * @return void
563 */
564 public function admin_inline_js() {
565 if ( ! current_user_can( 'install_plugins' ) )
566 return;
567
568 // register and enqueue styles
569 wp_register_script( 'pvc-notices', false );
570 wp_enqueue_script( 'pvc-notices' );
571
572 // add styles
573 wp_add_inline_script( 'pvc-notices', "
574 ( function( $ ) {
575 // ready event
576 $( function() {
577 // save dismiss state
578 $( '.pvc-notice.is-dismissible' ).on( 'click', '.notice-dismiss, .pvc-dismissible-notice', function( e ) {
579 if ( e.currentTarget.target !== '_blank' )
580 e.preventDefault();
581
582 var notice_action = 'hide';
583
584 if ( e.currentTarget.classList.contains( 'pvc-delay-notice' ) )
585 notice_action = 'delay';
586
587 $.post( ajaxurl, {
588 action: 'pvc_dismiss_notice',
589 notice_action: notice_action,
590 url: '" . esc_url_raw( admin_url( 'admin-ajax.php' ) ) . "',
591 nonce: '" . esc_attr( wp_create_nonce( 'pvc_dismiss_notice' ) ) . "'
592 } );
593
594 $( e.delegateTarget ).slideUp( 'fast' );
595 } );
596 } );
597 } )( jQuery );
598 ", 'after' );
599 }
600
601 /**
602 * Dismiss notice.
603 *
604 * @return void
605 */
606 public function dismiss_notice() {
607 if ( ! current_user_can( 'install_plugins' ) )
608 return;
609
610 if ( isset( $_REQUEST['nonce'] ) && wp_verify_nonce( $_REQUEST['nonce'], 'pvc_dismiss_notice' ) ) {
611 $notice_action = empty( $_REQUEST['notice_action'] ) || $_REQUEST['notice_action'] === 'hide' ? 'hide' : sanitize_text_field( $_REQUEST['notice_action'] );
612
613 switch ( $notice_action ) {
614 // delay notice
615 case 'delay':
616 // set delay period to 1 week from now
617 $this->options['general'] = array_merge(
618 $this->options['general'],
619 [
620 'update_delay_date' => time() + 2 * WEEK_IN_SECONDS
621 ]
622 );
623 update_option( 'post_views_counter_settings_general', $this->options['general'] );
624 break;
625
626 // hide notice
627 default:
628 $this->options['general'] = array_merge(
629 $this->options['general'],
630 [
631 'update_notice' => false
632 ]
633 );
634 $this->options['general'] = array_merge(
635 $this->options['general'],
636 [
637 'update_delay_date' => 0
638 ]
639 );
640
641 update_option( 'post_views_counter_settings_general', $this->options['general'] );
642 }
643 }
644
645 exit;
646 }
647
648 /**
649 * Plugin activation.
650 *
651 * @global object $wpdb
652 *
653 * @param bool $network
654 *
655 * @return void
656 */
657 public function activation( $network ) {
658 // network activation?
659 if ( is_multisite() && $network ) {
660 global $wpdb;
661
662 // get all available sites
663 $blogs_ids = $wpdb->get_col( 'SELECT blog_id FROM ' . $wpdb->blogs );
664
665 foreach ( $blogs_ids as $blog_id ) {
666 // change to another site
667 switch_to_blog( (int) $blog_id );
668
669 // run current site activation process
670 $this->activate_site();
671
672 restore_current_blog();
673 }
674 } else
675 $this->activate_site();
676 }
677
678 /**
679 * Single site activation.
680 *
681 * @global object $wpdb
682 * @global string $charset_collate
683 *
684 * @return void
685 */
686 public function activate_site() {
687 global $wpdb, $charset_collate;
688
689 // required for dbdelta
690 require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
691
692 // create post views table
693 dbDelta( '
694 CREATE TABLE IF NOT EXISTS ' . $wpdb->prefix . 'post_views (
695 `id` bigint unsigned NOT NULL,
696 `type` tinyint(1) unsigned NOT NULL,
697 `period` varchar(8) NOT NULL,
698 `count` bigint unsigned NOT NULL,
699 PRIMARY KEY (type, period, id),
700 UNIQUE INDEX id_type_period_count (id, type, period, count) USING BTREE,
701 INDEX type_period_count (type, period, count) USING BTREE
702 ) ' . $charset_collate . ';'
703 );
704
705 // add default options
706 add_option( 'post_views_counter_settings_general', $this->defaults['general'], null, false );
707 add_option( 'post_views_counter_settings_display', $this->defaults['display'], null, false );
708 add_option( 'post_views_counter_settings_other', $this->defaults['other'], null, false );
709 add_option( 'post_views_counter_version', $this->defaults['version'], null, false );
710 }
711
712 /**
713 * Plugin deactivation.
714 *
715 * @global object $wpdb
716 *
717 * @param bool $network
718 *
719 * @return void
720 */
721 public function deactivation( $network ) {
722 // network deactivation?
723 if ( is_multisite() && $network ) {
724 global $wpdb;
725
726 // get all available sites
727 $blogs_ids = $wpdb->get_col( 'SELECT blog_id FROM ' . $wpdb->blogs );
728
729 foreach ( $blogs_ids as $blog_id ) {
730 // change to another site
731 switch_to_blog( (int) $blog_id );
732
733 // run current site deactivation process
734 $this->deactivate_site( true );
735
736 restore_current_blog();
737 }
738 } else
739 $this->deactivate_site();
740 }
741
742 /**
743 * Single site deactivation.
744 *
745 * @global object $wpdb
746 *
747 * @param bool $multi
748 *
749 * @return void
750 */
751 public function deactivate_site( $multi = false ) {
752 if ( $multi === true ) {
753 $options = get_option( 'post_views_counter_settings_other' );
754 $check = $options['deactivation_delete'];
755 } else
756 $check = $this->options['other']['deactivation_delete'];
757
758 // delete options if needed
759 if ( $check ) {
760 // delete options
761 delete_option( 'post_views_counter_settings_general' );
762 delete_option( 'post_views_counter_settings_display' );
763 delete_option( 'post_views_counter_settings_other' );
764 delete_option( 'post_views_counter_activation_date' );
765 delete_option( 'post_views_counter_version' );
766
767 // delete transients
768 delete_transient( 'post_views_counter_ip_cache' );
769
770 global $wpdb;
771
772 // delete table from database
773 $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'post_views' );
774 }
775
776 // remove schedule
777 wp_clear_scheduled_hook( 'pvc_reset_counts' );
778
779 remove_action( 'pvc_reset_counts', [ $this->cron, 'reset_counts' ] );
780 }
781
782 /**
783 * Initialize new network site.
784 *
785 * @param object $site
786 *
787 * @return void
788 */
789 public function init_new_network_site( $site ) {
790 if ( is_multisite() ) {
791 // change to another site
792 switch_to_blog( $site->blog_id );
793
794 // run current site activation process
795 $this->activate_site();
796
797 restore_current_blog();
798 }
799 }
800
801 /**
802 * Load text domain.
803 *
804 * @return void
805 */
806 public function load_textdomain() {
807 load_plugin_textdomain( 'post-views-counter', false, POST_VIEWS_COUNTER_REL_PATH . '/languages/' );
808 }
809
810 /**
811 * Load pluggable template functions.
812 *
813 * @return void
814 */
815 public function load_pluggable_functions() {
816 include_once( POST_VIEWS_COUNTER_PATH . 'includes/functions.php' );
817 }
818
819 /**
820 * Enqueue admin scripts and styles.
821 *
822 * @global string $post_type
823 * @global string $wp_version
824 *
825 * @param string $page
826 *
827 * @return void
828 */
829 public function admin_enqueue_scripts( $page ) {
830 global $post_type;
831 global $wp_version;
832
833 // register styles
834 wp_register_style( 'pvc-admin', POST_VIEWS_COUNTER_URL . '/css/admin.min.css', [], $this->defaults['version'] );
835
836 // register scripts
837 wp_register_script( 'pvc-admin-settings', POST_VIEWS_COUNTER_URL . '/js/admin-settings.js', [ 'jquery' ], $this->defaults['version'] );
838 wp_register_script( 'pvc-admin-post', POST_VIEWS_COUNTER_URL . '/js/admin-post.js', [ 'jquery' ], $this->defaults['version'] );
839 wp_register_script( 'pvc-admin-quick-edit', POST_VIEWS_COUNTER_URL . '/js/admin-quick-edit.js', [ 'jquery' ], $this->defaults['version'] );
840
841 // load on pvc settings page
842 if ( in_array( $page, [ 'toplevel_page_post-views-counter', 'settings_page_post-views-counter' ], true ) ) {
843 wp_enqueue_script( 'pvc-admin-settings' );
844
845 // prepare script data
846 $script_data = [
847 'resetToDefaults' => esc_html__( 'Are you sure you want to reset these settings to defaults?', 'post-views-counter' ),
848 'resetViews' => esc_html__( 'Are you sure you want to delete all existing data?', 'post-views-counter' )
849 ];
850
851 wp_add_inline_script( 'pvc-admin-settings', 'var pvcArgsSettings = ' . wp_json_encode( $script_data ) . ";\n", 'before' );
852
853 wp_enqueue_style( 'pvc-admin' );
854 // load on single post page
855 } elseif ( $page === 'post.php' || $page === 'post-new.php' ) {
856 $post_types = Post_Views_Counter()->options['general']['post_types_count'];
857
858 if ( ! in_array( $post_type, (array) $post_types ) )
859 return;
860
861 wp_enqueue_style( 'pvc-admin' );
862 wp_enqueue_script( 'pvc-admin-post' );
863 // edit post
864 } elseif ( $page === 'edit.php' ) {
865 $post_types = Post_Views_Counter()->options['general']['post_types_count'];
866
867 if ( ! in_array( $post_type, (array) $post_types ) )
868 return;
869
870 wp_enqueue_style( 'pvc-admin' );
871
872 // woocommerce
873 if ( get_post_type() !== 'product' ) {
874 wp_enqueue_script( 'pvc-admin-quick-edit' );
875
876 // prepare script data
877 $script_data = [
878 'nonce' => wp_create_nonce( 'pvc_save_bulk_post_views' ),
879 'wpVersion59' => version_compare( $wp_version, '5.9', '>=' )
880 ];
881
882 wp_add_inline_script( 'pvc-admin-quick-edit', 'var pvcArgsQuickEdit = ' . wp_json_encode( $script_data ) . ";\n", 'before' );
883 }
884 // widgets
885 } elseif ( $page === 'widgets.php' )
886 wp_enqueue_script( 'pvc-admin-widgets', POST_VIEWS_COUNTER_URL . '/js/admin-widgets.js', [ 'jquery' ], $this->defaults['version'] );
887 // media
888 elseif ( $page === 'upload.php' )
889 wp_enqueue_style( 'pvc-admin' );
890
891 // register and enqueue styles
892 wp_register_style( 'pvc-pro-style', false );
893 wp_enqueue_style( 'pvc-pro-style' );
894
895 // add styles
896 wp_add_inline_style( 'pvc-pro-style', '
897 .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,
898 .post-views-counter-settings tr.pvc-pro-extended label[for="pvc_exclude-ai_bots"]:after {
899 content: \'PRO\';
900 display: inline;
901 background-color: #ffc107;
902 color: white;
903 padding: 2px 4px;
904 text-align: center;
905 border-radius: 4px;
906 margin-left: 4px;
907 font-weight: bold;
908 font-size: 11px;
909 }' );
910 }
911
912 /**
913 * Add link to Settings page.
914 *
915 * @param array $links
916 *
917 * @return array
918 */
919 public function plugin_settings_link( $links ) {
920 if ( ! current_user_can( 'manage_options' ) )
921 return $links;
922
923 // submenu?
924 if ( $this->options['other']['menu_position'] === 'sub' )
925 $url = admin_url( 'options-general.php?page=post-views-counter' );
926 // topmenu?
927 else
928 $url = admin_url( 'admin.php?page=post-views-counter' );
929
930 array_unshift( $links, sprintf( '<a href="%s">%s</a>', esc_url_raw( $url ), esc_html__( 'Settings', 'post-views-counter' ) ) );
931
932 return $links;
933 }
934 }
935 }
936
937 /**
938 * Initialize Post Views Counter.
939 *
940 * @return object
941 */
942 function Post_Views_Counter() {
943 static $instance;
944
945 // first call to instance() initializes the plugin
946 if ( $instance === null || ! ( $instance instanceof Post_Views_Counter ) )
947 $instance = Post_Views_Counter::instance();
948
949 return $instance;
950 }
951
952 Post_Views_Counter();