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