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