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