PluginProbe ʕ •ᴥ•ʔ
WP Popular Posts / 5.2.1
WP Popular Posts v5.2.1
4.0.8 4.0.9 4.1.0 4.1.1 4.1.2 4.2.0 4.2.1 4.2.2 5.0.0 5.0.1 5.0.2 5.1.0 5.2.0 5.2.1 5.2.2 5.2.3 5.2.4 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 6.0.0 6.0.1 6.0.2 6.0.3 6.0.4 6.0.5 6.1.0 6.1.1 6.1.2 6.1.3 6.1.4 6.2.0 6.2.1 6.3.0 6.3.1 6.3.2 6.3.3 6.3.4 6.4.0 6.4.1 6.4.2 7.0.0 7.0.1 7.1.0 7.2.0 7.3.0 7.3.1 7.3.2 7.3.3 7.3.4 7.3.5 7.3.6 7.3.7 7.3.8 7.4.0 trunk 2.3.7 3.0.0 3.0.1 3.0.2 3.0.3 3.1.0 3.1.1 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 4.0.0 4.0.1 4.0.10 4.0.11 4.0.12 4.0.13 4.0.2 4.0.3 4.0.5 4.0.6
wordpress-popular-posts / src / Admin / Admin.php
wordpress-popular-posts / src / Admin Last commit date
Admin.php 5 years ago admin-page.php 5 years ago
Admin.php
1380 lines
1 <?php
2 /**
3 * The admin-facing functionality of the plugin.
4 *
5 * Defines hooks to enqueue the admin-specific stylesheet and JavaScript,
6 * plugin settings and other admin stuff.
7 *
8 * @package WordPressPopularPosts
9 * @subpackage WordPressPopularPosts/Admin
10 * @author Hector Cabrera <me@cabrerahector.com>
11 */
12
13 namespace WordPressPopularPosts\Admin;
14
15 use WordPressPopularPosts\Helper;
16 use WordPressPopularPosts\Output;
17 use WordPressPopularPosts\Query;
18
19 class Admin {
20
21 /**
22 * Slug of the plugin screen.
23 *
24 * @since 3.0.0
25 * @var string
26 */
27 protected $screen_hook_suffix = NULL;
28
29 /**
30 * Plugin options.
31 *
32 * @var array $config
33 * @access private
34 */
35 private $config;
36
37 /**
38 * Image object
39 *
40 * @since 4.0.2
41 * @var WordPressPopularPosts\Image
42 */
43 private $thumbnail;
44
45 /**
46 * Construct.
47 *
48 * @since 5.0.0
49 * @param array $config Admin settings.
50 * @param \WordPressPopularPosts\Image $thumbnail Image class.
51 */
52 public function __construct(array $config, \WordPressPopularPosts\Image $thumbnail)
53 {
54 $this->config = $config;
55 $this->thumbnail = $thumbnail;
56
57 // Delete old data on demand
58 if ( 1 == $this->config['tools']['log']['limit'] ) {
59 if ( ! wp_next_scheduled('wpp_cache_event') ) {
60 $midnight = strtotime('midnight') - ( get_option('gmt_offset') * HOUR_IN_SECONDS ) + DAY_IN_SECONDS;
61 wp_schedule_event($midnight, 'daily', 'wpp_cache_event');
62 }
63 } else {
64 // Remove the scheduled event if exists
65 if ( $timestamp = wp_next_scheduled('wpp_cache_event') ) {
66 wp_unschedule_event($timestamp, 'wpp_cache_event');
67 }
68 }
69
70 // Allow WP themers / coders to override data sampling status (active/inactive)
71 $this->config['tools']['sampling']['active'] = apply_filters('wpp_data_sampling', $this->config['tools']['sampling']['active']);
72
73 if (
74 ! ( wp_using_ext_object_cache() && defined('WPP_CACHE_VIEWS') && WPP_CACHE_VIEWS ) // Not using a persistent object cache
75 && ! $this->config['tools']['sampling']['active'] // Not using Data Sampling
76 ) {
77 // Schedule performance nag
78 if ( ! wp_next_scheduled('wpp_maybe_performance_nag') ) {
79 wp_schedule_event(time(), 'hourly', 'wpp_maybe_performance_nag');
80 }
81 } else {
82 // Remove the scheduled performance nag if found
83 if ( $timestamp = wp_next_scheduled('wpp_maybe_performance_nag') ) {
84 wp_unschedule_event($timestamp, 'wpp_maybe_performance_nag');
85 }
86 }
87 }
88
89 /**
90 * WordPress public-facing hooks.
91 *
92 * @since 5.0.0
93 */
94 public function hooks()
95 {
96 // Upgrade check
97 add_action('init', [$this, 'upgrade_check']);
98 // Hook fired when a new blog is activated on WP Multisite
99 add_action('wpmu_new_blog', [$this, 'activate_new_site']);
100 // Hook fired when a blog is deleted on WP Multisite
101 add_filter('wpmu_drop_tables', [$this, 'delete_site_data'], 10, 2);
102 // At-A-Glance
103 add_filter('dashboard_glance_items', [$this, 'at_a_glance_stats']);
104 add_action('admin_head', [$this, 'at_a_glance_stats_css']);
105 // Dashboard Trending Now widget
106 //if ( current_user_can('edit_published_posts') )
107 add_action('wp_dashboard_setup', [$this, 'add_dashboard_widgets']);
108 // Load WPP's admin styles and scripts
109 add_action('admin_enqueue_scripts', [$this, 'enqueue_assets']);
110 // Add admin screen
111 add_action('admin_menu', [$this, 'add_plugin_admin_menu']);
112 // Contextual help
113 add_action('admin_head', [$this, 'add_contextual_help']);
114 // Add plugin settings link
115 add_filter('plugin_action_links', [$this, 'add_plugin_settings_link'], 10, 2);
116 // Update chart
117 add_action('wp_ajax_wpp_update_chart', [$this, 'update_chart']);
118 // Get lists
119 add_action('wp_ajax_wpp_get_most_viewed', [$this, 'get_popular_items']);
120 add_action('wp_ajax_wpp_get_most_commented', [$this, 'get_popular_items']);
121 add_action('wp_ajax_wpp_get_trending', [$this, 'get_popular_items']);
122 // Delete plugin data
123 add_action('wp_ajax_wpp_clear_data', [$this, 'clear_data']);
124 // Empty plugin's images cache
125 add_action('wp_ajax_wpp_clear_thumbnail', [$this, 'clear_thumbnails']);
126 // Flush cached thumbnail on featured image change/deletion
127 add_action('updated_post_meta', [$this, 'updated_post_meta'], 10, 4);
128 add_action('deleted_post_meta', [$this, 'deleted_post_meta'], 10, 4);
129 // Purge post data on post/page deletion
130 add_action('admin_init', [$this, 'purge_post_data']);
131 // Purge old data on demand
132 add_action('wpp_cache_event', [$this, 'purge_data']);
133 // Maybe performance nag
134 add_action('wpp_maybe_performance_nag', [$this, 'performance_check']);
135 // Show notices
136 add_action('admin_notices', [$this, 'notices']);
137 }
138
139 /**
140 * Checks if an upgrade procedure is required.
141 *
142 * @since 2.4.0
143 */
144 public function upgrade_check()
145 {
146 $this->upgrade_site();
147 }
148
149 /**
150 * Checks whether a performance tweak may be necessary.
151 *
152 * @since 5.0.2
153 */
154 public function performance_check()
155 {
156 $performance_nag = get_option('wpp_performance_nag');
157
158 if ( ! $performance_nag ) {
159 $performance_nag = [
160 'status' => 0,
161 'last_checked' => null
162 ];
163 add_option('wpp_performance_nag', $performance_nag);
164 }
165
166 if ( 3 != $performance_nag['status'] ) { // 0 = inactive, 1 = active, 2 = remind me later, 3 = dismissed
167 global $wpdb;
168
169 $views_count = $wpdb->get_var(
170 $wpdb->prepare(
171 "SELECT IFNULL(SUM(pageviews), 0) AS views FROM {$wpdb->prefix}popularpostssummary WHERE view_datetime > DATE_SUB(%s, INTERVAL 1 HOUR);",
172 Helper::now()
173 )
174 );
175
176 // This site is probably a mid/high traffic one,
177 // display performance nag
178 if ( $views_count >= 420 ) {
179 if ( 0 == $performance_nag['status'] ) {
180 $performance_nag['status'] = 1;
181 $performance_nag['last_checked'] = Helper::timestamp();
182 update_option('wpp_performance_nag', $performance_nag);
183 }
184 }
185 }
186 }
187
188 /**
189 * Upgrades single site.
190 *
191 * @since 4.0.7
192 */
193 private function upgrade_site()
194 {
195 // Get WPP version
196 $wpp_ver = get_option('wpp_ver');
197
198 if ( ! $wpp_ver ) {
199 add_option('wpp_ver', WPP_VERSION);
200 } elseif ( version_compare($wpp_ver, WPP_VERSION, '<') ) {
201 $this->upgrade();
202 }
203 }
204
205 /**
206 * On plugin upgrade, performs a number of actions: update WPP database tables structures (if needed),
207 * run the setup wizard (if needed), and some other checks.
208 *
209 * @since 2.4.0
210 * @access private
211 * @global object $wpdb
212 */
213 private function upgrade()
214 {
215 $now = Helper::now();
216
217 // Keep the upgrade process from running too many times
218 if ( $wpp_update = get_option('wpp_update') ) {
219 $from_time = strtotime($wpp_update);
220 $to_time = strtotime($now);
221 $difference_in_minutes = round(abs($to_time - $from_time)/60, 2);
222
223 // Upgrade flag is still valid, abort
224 if ( $difference_in_minutes <= 15 )
225 return;
226 // Upgrade flag expired, delete it and continue
227 delete_option('wpp_update');
228 }
229
230 global $wpdb;
231
232 // Upgrade flag
233 add_option('wpp_update', $now);
234
235 // Set table name
236 $prefix = $wpdb->prefix . "popularposts";
237
238 // Update data table structure and indexes
239 $dataFields = $wpdb->get_results("SHOW FIELDS FROM {$prefix}data;");
240
241 foreach ( $dataFields as $column ) {
242 if ( "day" == $column->Field ) {
243 $wpdb->query("ALTER TABLE {$prefix}data ALTER COLUMN day DROP DEFAULT;");
244 }
245
246 if ( "last_viewed" == $column->Field ) {
247 $wpdb->query("ALTER TABLE {$prefix}data ALTER COLUMN last_viewed DROP DEFAULT;");
248 }
249 }
250
251 // Update summary table structure and indexes
252 $summaryFields = $wpdb->get_results("SHOW FIELDS FROM {$prefix}summary;");
253
254 foreach ( $summaryFields as $column ) {
255 if ( "last_viewed" == $column->Field ) {
256 $wpdb->query("ALTER TABLE {$prefix}summary CHANGE last_viewed view_datetime datetime NOT NULL, ADD KEY view_datetime (view_datetime);");
257 }
258
259 if ( "view_date" == $column->Field ) {
260 $wpdb->query("ALTER TABLE {$prefix}summary ALTER COLUMN view_date DROP DEFAULT;");
261 }
262
263 if ( "view_datetime" == $column->Field ) {
264 $wpdb->query("ALTER TABLE {$prefix}summary ALTER COLUMN view_datetime DROP DEFAULT;");
265 }
266 }
267
268 $summaryIndexes = $wpdb->get_results("SHOW INDEX FROM {$prefix}summary;");
269
270 foreach( $summaryIndexes as $index ) {
271 if ( 'ID_date' == $index->Key_name ) {
272 $wpdb->query("ALTER TABLE {$prefix}summary DROP INDEX ID_date;");
273 }
274
275 if ( 'last_viewed' == $index->Key_name ) {
276 $wpdb->query("ALTER TABLE {$prefix}summary DROP INDEX last_viewed;");
277 }
278 }
279
280 // Validate the structure of the tables, create missing tables / fields if necessary
281 \WordPressPopularPosts\Activation\Activator::track_new_site();
282
283 // Check storage engine
284 $storage_engine_data = $wpdb->get_var("SELECT `ENGINE` FROM `information_schema`.`TABLES` WHERE `TABLE_SCHEMA`='{$wpdb->dbname}' AND `TABLE_NAME`='{$prefix}data';");
285
286 if ( 'InnoDB' != $storage_engine_data ) {
287 $wpdb->query("ALTER TABLE {$prefix}data ENGINE=InnoDB;");
288 }
289
290 $storage_engine_summary = $wpdb->get_var("SELECT `ENGINE` FROM `information_schema`.`TABLES` WHERE `TABLE_SCHEMA`='{$wpdb->dbname}' AND `TABLE_NAME`='{$prefix}summary';");
291
292 if ( 'InnoDB' != $storage_engine_summary ) {
293 $wpdb->query("ALTER TABLE {$prefix}summary ENGINE=InnoDB;");
294 }
295
296 // Update WPP version
297 update_option('wpp_ver', WPP_VERSION);
298 // Remove upgrade flag
299 delete_option('wpp_update');
300 }
301
302 /**
303 * Fired when a new blog is activated on WP Multisite.
304 *
305 * @since 3.0.0
306 * @param int $blog_id New blog ID
307 */
308 public function activate_new_site($blog_id)
309 {
310 if ( 1 !== did_action('wpmu_new_blog') )
311 return;
312
313 // run activation for the new blog
314 switch_to_blog($blog_id);
315 \WordPressPopularPosts\Activation\Activator::track_new_site();
316 // switch back to current blog
317 restore_current_blog();
318 }
319
320 /**
321 * Fired when a blog is deleted on WP Multisite.
322 *
323 * @since 4.0.0
324 * @param array $tables
325 * @param int $blog_id
326 * @return array
327 */
328 public function delete_site_data($tables, $blog_id)
329 {
330 global $wpdb;
331
332 $tables[] = $wpdb->prefix . 'popularpostsdata';
333 $tables[] = $wpdb->prefix . 'popularpostssummary';
334
335 return $tables;
336 }
337
338 /**
339 * Display some statistics at the "At a Glance" box from the Dashboard.
340 *
341 * @since 4.1.0
342 */
343 public function at_a_glance_stats()
344 {
345 global $wpdb;
346
347 $glances = [];
348 $args = ['post', 'page'];
349 $post_type_placeholders = '%s, %s';
350
351 if (
352 isset($this->config['stats']['post_type'])
353 && ! empty($this->config['stats']['post_type'])
354 ) {
355 $args = array_map('trim', explode(',', $this->config['stats']['post_type']));
356 $post_type_placeholders = implode(', ', array_fill(0, count($args), '%s'));
357 }
358
359 $args[] = Helper::now();
360
361 $query = $wpdb->prepare(
362 "SELECT SUM(pageviews) AS total
363 FROM `{$wpdb->prefix}popularpostssummary` v LEFT JOIN `{$wpdb->prefix}posts` p ON v.postid = p.ID
364 WHERE p.post_type IN({$post_type_placeholders}) AND p.post_status = 'publish' AND p.post_password = '' AND v.view_datetime > DATE_SUB(%s, INTERVAL 1 HOUR);"
365 , $args
366 );
367
368 $total_views = $wpdb->get_var($query);
369
370 $pageviews = sprintf(
371 _n('%s view in the last hour', '%s views in the last hour', $total_views, 'wordpress-popular-posts'),
372 number_format_i18n($total_views)
373 );
374
375 if ( current_user_can('edit_published_posts') ) {
376 $glances[] = '<a class="wpp-views-count" href="' . admin_url('options-general.php?page=wordpress-popular-posts') . '">' . $pageviews . '</a>';
377 }
378 else {
379 $glances[] = '<span class="wpp-views-count">' . $pageviews . '</a>';
380 }
381
382 return $glances;
383 }
384
385 /**
386 * Add custom inline CSS styles for At a Glance stats.
387 *
388 * @since 4.1.0
389 */
390 public function at_a_glance_stats_css()
391 {
392 echo '<style>#dashboard_right_now a.wpp-views-count:before, #dashboard_right_now span.wpp-views-count:before {content: "\f177";}</style>';
393 }
394
395 /**
396 * Adds a widget to the dashboard.
397 *
398 * @since 5.0.0
399 */
400 public function add_dashboard_widgets()
401 {
402 if ( current_user_can('edit_published_posts') ) {
403 wp_add_dashboard_widget(
404 'wpp_trending_dashboard_widget',
405 __('Trending now', 'wordpress-popular-posts'),
406 [$this, 'trending_dashboard_widget']
407 );
408 }
409 }
410
411 /**
412 * Outputs the contents of our Trending Dashboard Widget.
413 *
414 * @since 5.0.0
415 */
416 function trending_dashboard_widget()
417 {
418 ?>
419 <style>
420 #wpp_trending_dashboard_widget .inside {
421 overflow: hidden;
422 position: relative;
423 min-height: 150px;
424 padding-bottom: 22px;
425 }
426
427 #wpp_trending_dashboard_widget .inside::after {
428 position: absolute;
429 top: 0;
430 left: 0;
431 opacity: 0.2;
432 display: block;
433 content: '';
434 width: 100%;
435 height: 100%;
436 z-index: 1;
437 background-image: url('<?php echo plugin_dir_url(dirname(dirname(__FILE__))) . 'assets/images/flame.png'; ?>');
438 background-position: right bottom;
439 background-repeat: no-repeat;
440 background-size: 34% auto;
441 }
442
443 #wpp_trending_dashboard_widget .inside .no-data {
444 position: absolute;
445 top: calc(50% - 11px);
446 left: 50%;
447 z-index: 2;
448 margin: 0;
449 padding: 0;
450 width: 96%;
451 transform: translate(-50.0001%, -50.0001%);
452 }
453
454 #wpp_trending_dashboard_widget .inside .popular-posts-list,
455 #wpp_trending_dashboard_widget .inside p#wpp_read_more {
456 position: relative;
457 z-index: 2;
458 }
459
460 #wpp_trending_dashboard_widget .inside .popular-posts-list {
461 margin: 1em 0;
462 }
463
464 #wpp_trending_dashboard_widget .inside p#wpp_read_more {
465 position: absolute;
466 left: 0;
467 bottom: 0;
468 width: 100%;
469 text-align: center;
470 }
471 </style>
472 <?php
473 $args = [
474 'range' => 'custom',
475 'time_quantity' => 1,
476 'time_unit' => 'HOUR',
477 'post_type' => $this->config['stats']['post_type'],
478 'limit' => 5,
479 'stats_tag' => [
480 'views' => 1,
481 'comment_count' => 1
482 ]
483 ];
484 $options = apply_filters('wpp_trending_dashboard_widget_args', []);
485
486 if ( is_array($options) && ! empty($options) )
487 $args = Helper::merge_array_r($args, $options);
488
489 $trending = new Query($args);
490 $posts = $trending->get_posts();
491
492 $this->render_list($posts, 'trending');
493 echo '<p id="wpp_read_more"><a href="' . admin_url('options-general.php?page=wordpress-popular-posts') . '">' . __('View more', 'wordpress-popular-posts') . '</a><p>';
494
495 }
496
497 /**
498 * Enqueues admin facing assets.
499 *
500 * @since 5.0.0
501 */
502 public function enqueue_assets()
503 {
504 $screen = get_current_screen();
505
506 if ( isset($screen->id) ) {
507 if ( $screen->id == $this->screen_hook_suffix ) {
508 wp_enqueue_style('wpp-datepicker-theme', plugin_dir_url(dirname(dirname(__FILE__))) . 'assets/css/datepicker.css', [], WPP_VERSION, 'all');
509
510 wp_enqueue_media();
511 wp_enqueue_script('jquery-ui-datepicker');
512 wp_enqueue_script('chartjs', plugin_dir_url(dirname(dirname(__FILE__))) . 'assets/js/vendor/Chart.min.js', [], WPP_VERSION);
513
514 wp_register_script('wpp-chart', plugin_dir_url(dirname(dirname(__FILE__))) . 'assets/js/chart.js', ['chartjs'], WPP_VERSION);
515 wp_localize_script('wpp-chart', 'wpp_chart_params', [
516 'colors' => $this->get_admin_color_scheme()
517 ]);
518 wp_enqueue_script('wpp-chart');
519
520 wp_register_script('wordpress-popular-posts-admin-script', plugin_dir_url(dirname(dirname(__FILE__))) . 'assets/js/admin.js', ['jquery'], WPP_VERSION, true);
521 wp_localize_script('wordpress-popular-posts-admin-script', 'wpp_admin_params', [
522 'label_media_upload_button' => __("Use this image", "wordpress-popular-posts"),
523 'nonce' => wp_create_nonce("wpp_admin_nonce")
524 ]);
525 wp_enqueue_script('wordpress-popular-posts-admin-script');
526 }
527
528 if ( $screen->id == $this->screen_hook_suffix || 'dashboard' == $screen->id ) {
529 // Fontello icons
530 wp_enqueue_style('wpp-fontello', plugin_dir_url(dirname(dirname(__FILE__))) . 'assets/css/fontello.css', [], WPP_VERSION, 'all');
531 wp_enqueue_style('wordpress-popular-posts-admin-styles', plugin_dir_url(dirname(dirname(__FILE__))) . 'assets/css/admin.css', [], WPP_VERSION, 'all');
532 }
533 }
534 }
535
536 /**
537 * Register the administration menu for this plugin into the WordPress Dashboard menu.
538 *
539 * @since 1.0.0
540 */
541 public function add_plugin_admin_menu()
542 {
543 $this->screen_hook_suffix = add_options_page(
544 'WordPress Popular Posts',
545 'WordPress Popular Posts',
546 'edit_published_posts',
547 'wordpress-popular-posts',
548 [$this, 'display_plugin_admin_page']
549 );
550 }
551
552 /**
553 * Render the settings page for this plugin.
554 *
555 * @since 1.0.0
556 */
557 public function display_plugin_admin_page()
558 {
559 include_once plugin_dir_path(__FILE__) . 'admin-page.php';
560 }
561
562 /**
563 * Adds contextual help menu.
564 *
565 * @since 4.0.0
566 */
567 public function add_contextual_help()
568 {
569 $screen = get_current_screen();
570
571 if ( isset($screen->id) && $screen->id == $this->screen_hook_suffix ){
572 $screen->add_help_tab(
573 [
574 'id' => 'wpp_help_overview',
575 'title' => __('Overview', 'wordpress-popular-posts'),
576 'content' => "<p>" . __("Welcome to WordPress Popular Posts' Dashboard! In this screen you will find statistics on what's popular on your site, tools to further tweak WPP to your needs, and more!", "wordpress-popular-posts") . "</p>"
577 ]
578 );
579 $screen->add_help_tab(
580 [
581 'id' => 'wpp_help_donate',
582 'title' => __('Like this plugin?', 'wordpress-popular-posts'),
583 'content' => '
584 <p style="text-align: center;">' . __('Each donation motivates me to keep releasing free stuff for the WordPress community!', 'wordpress-popular-posts') . '</p>
585 <form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top" style="margin: 0; padding: 0; text-align: center;">
586 <input type="hidden" name="cmd" value="_s-xclick">
587 <input type="hidden" name="hosted_button_id" value="RP9SK8KVQHRKS">
588 <input type="image" src="//www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!" style="display: inline; margin: 0;">
589 <img alt="" border="0" src="//www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">
590 </form>
591 <p style="text-align: center;">' . sprintf(__('You can <a href="%s" target="_blank">leave a review</a>, too!', 'wordpress-popular-posts'), 'https://wordpress.org/support/view/plugin-reviews/wordpress-popular-posts?rate=5#postform') . '</p>'
592 ]
593 );
594
595 // Help sidebar
596 $screen->set_help_sidebar(
597 sprintf(
598 __('<p><strong>For more information:</strong></p><ul><li><a href="%1$s">Documentation</a></li><li><a href="%2$s">Support</a></li></ul>', 'wordpress-popular-posts'),
599 "https://github.com/cabrerahector/wordpress-popular-posts/",
600 "https://wordpress.org/support/plugin/wordpress-popular-posts/"
601 )
602 );
603 }
604 }
605
606 /**
607 * Registers Settings link on plugin description.
608 *
609 * @since 2.3.3
610 * @param array $links
611 * @param string $file
612 * @return array
613 */
614 public function add_plugin_settings_link($links, $file)
615 {
616 $plugin_file = 'wordpress-popular-posts/wordpress-popular-posts.php';
617
618 if (
619 is_plugin_active($plugin_file)
620 && $plugin_file == $file
621 ) {
622 $links[] = '<a href="' . admin_url('options-general.php?page=wordpress-popular-posts') . '">' . __('Settings') . '</a>';
623 }
624
625 return $links;
626 }
627
628 /**
629 * Gets current admin color scheme.
630 *
631 * @since 4.0.0
632 * @return array
633 */
634 private function get_admin_color_scheme()
635 {
636 global $_wp_admin_css_colors;
637
638 if (
639 is_array($_wp_admin_css_colors)
640 && count($_wp_admin_css_colors)
641 ) {
642 $current_user = wp_get_current_user();
643 $color_scheme = get_user_option('admin_color', $current_user->ID);
644
645 if (
646 empty($color_scheme)
647 || ! isset($_wp_admin_css_colors[ $color_scheme])
648 ) {
649 $color_scheme = 'fresh';
650 }
651
652 if ( isset($_wp_admin_css_colors[$color_scheme]) && isset($_wp_admin_css_colors[$color_scheme]->colors) ) {
653 return $_wp_admin_css_colors[$color_scheme]->colors;
654 }
655
656 }
657
658 // Fallback, just in case
659 return ['#333', '#999', '#881111', '#a80000'];
660 }
661
662 /**
663 * Fetches chart data.
664 *
665 * @since 4.0.0
666 * @return string
667 */
668 public function get_chart_data($range = 'last7days', $time_unit = 'HOUR', $time_quantity = 24)
669 {
670 $dates = $this->get_dates($range, $time_unit, $time_quantity);
671 $start_date = $dates[0];
672 $end_date = $dates[count($dates) - 1];
673 $date_range = Helper::get_date_range($start_date, $end_date, 'Y-m-d H:i:s');
674 $views_data = $this->get_range_item_count($start_date, $end_date, 'views');
675 $views = [];
676 $comments_data = $this->get_range_item_count($start_date, $end_date, 'comments');
677 $comments = [];
678
679 if ( 'today' != $range ) {
680 foreach($date_range as $date) {
681 $key = date('Y-m-d', strtotime($date));
682 $views[] = ( ! isset($views_data[$key]) ) ? 0 : $views_data[$key]->pageviews;
683 $comments[] = ( ! isset($comments_data[$key]) ) ? 0 : $comments_data[$key]->comments;
684 }
685 } else {
686 $key = date('Y-m-d', strtotime($dates[0]));
687 $views[] = ( ! isset($views_data[$key]) ) ? 0 : $views_data[$key]->pageviews;
688 $comments[] = ( ! isset($comments_data[$key]) ) ? 0 : $comments_data[$key]->comments;
689 }
690
691 if ( $start_date != $end_date )
692 $label_date_range = date_i18n('M, D d', strtotime($start_date)) . ' &mdash; ' . date_i18n('M, D d', strtotime($end_date));
693 else
694 $label_date_range = date_i18n('M, D d', strtotime($start_date));
695
696 $total_views = array_sum($views);
697 $total_comments = array_sum($comments);
698
699 $label_summary = sprintf(_n('%s view', '%s views', $total_views, 'wordpress-popular-posts'), '<strong>' . number_format_i18n($total_views) . '</strong>') . '<br style="display: none;" /> / ' . sprintf(_n('%s comment', '%s comments', $total_comments, 'wordpress-popular-posts'), '<strong>' . number_format_i18n($total_comments) . '</strong>');
700
701 // Format labels
702 if ( 'today' != $range ) {
703 $date_range = array_map(function($d){
704 return date_i18n('D d', strtotime($d));
705 }, $date_range);
706 } else {
707 $date_range = [date_i18n('D d', strtotime($date_range[0]))];
708 $comments = [array_sum($comments)];
709 $views = [array_sum($views)];
710 }
711
712 $response = [
713 'totals' => [
714 'label_summary' => $label_summary,
715 'label_date_range' => $label_date_range,
716 ],
717 'labels' => $date_range,
718 'datasets' => [
719 [
720 'label' => __("Comments", "wordpress-popular-posts"),
721 'data' => $comments
722 ],
723 [
724 'label' => __("Views", "wordpress-popular-posts"),
725 'data' => $views
726 ]
727 ]
728 ];
729
730 return json_encode($response);
731 }
732
733 /**
734 * Returns an array of dates.
735 *
736 * @since 5.0.0
737 * @return array|bool
738 */
739 private function get_dates($range = 'last7days', $time_unit = 'HOUR', $time_quantity = 24)
740 {
741 $valid_ranges = ['today', 'daily', 'last24hours', 'weekly', 'last7days', 'monthly', 'last30days', 'all', 'custom'];
742 $range = in_array($range, $valid_ranges) ? $range : 'last7days';
743 $now = new \DateTime(Helper::now(), new \DateTimeZone(Helper::get_timezone()));
744
745 // Determine time range
746 switch( $range ){
747 case "last24hours":
748 case "daily":
749 $end_date = $now->format('Y-m-d H:i:s');
750 $start_date = $now->modify('-1 day')->format('Y-m-d H:i:s');
751 break;
752
753 case "today":
754 $start_date = $now->format('Y-m-d') . ' 00:00:00';
755 $end_date = $now->format('Y-m-d') . ' 23:59:59';
756 break;
757
758 case "last7days":
759 case "weekly":
760 $end_date = $now->format('Y-m-d') . ' 23:59:59';
761 $start_date = $now->modify('-6 day')->format('Y-m-d') . ' 00:00:00';
762 break;
763
764 case "last30days":
765 case "monthly":
766 $end_date = $now->format('Y-m-d') . ' 23:59:59';
767 $start_date = $now->modify('-29 day')->format('Y-m-d') . ' 00:00:00';
768 break;
769
770 case "custom":
771 $end_date = $now->format('Y-m-d H:i:s');
772
773 if (
774 Helper::is_number($time_quantity)
775 && $time_quantity >= 1
776 ) {
777 $end_date = $now->format('Y-m-d H:i:s');
778 $time_unit = strtoupper($time_unit);
779
780 if ( 'MINUTE' == $time_unit ) {
781 $start_date = $now->sub(new \DateInterval('PT' . (60 * $time_quantity) . 'S'))->format('Y-m-d H:i:s');
782 } elseif ( 'HOUR' == $time_unit ) {
783 $start_date = $now->sub(new \DateInterval('PT' . ((60 * $time_quantity) - 1) . 'M59S'))->format('Y-m-d H:i:s');
784 } else {
785 $end_date = $now->format('Y-m-d') . ' 23:59:59';
786 $start_date = $now->sub(new \DateInterval('P' . ($time_quantity - 1) . 'D'))->format('Y-m-d') . ' 00:00:00';
787 }
788 } // fallback to last 24 hours
789 else {
790 $start_date = $now->modify('-1 day')->format('Y-m-d H:i:s');
791 }
792
793 // Check if custom date range has been requested
794 $dates = null;
795
796 if ( isset($_GET['dates']) ) {
797 $dates = explode(" ~ ", $_GET['dates']);
798
799 if (
800 ! is_array($dates)
801 || empty($dates)
802 || ! Helper::is_valid_date($dates[0])
803 ) {
804 $dates = null;
805 } else {
806 if (
807 ! isset($dates[1])
808 || ! Helper::is_valid_date($dates[1])
809 ) {
810 $dates[1] = $dates[0];
811 }
812
813 $start_date = $dates[0] . ' 00:00:00';
814 $end_date = $dates[1] . ' 23:59:59';
815 }
816 }
817
818 break;
819
820 default:
821 $end_date = $now->format('Y-m-d') . ' 23:59:59';
822 $start_date = $now->modify('-6 day')->format('Y-m-d') . ' 00:00:00';
823 break;
824 }
825
826 return [$start_date, $end_date];
827 }
828
829 /**
830 * Returns an array of dates with views/comments count.
831 *
832 * @since 5.0.0
833 * @param string $start_date
834 * @param string $end_date
835 * @param string $item
836 * @return array
837 */
838 public function get_range_item_count($start_date, $end_date, $item = 'views')
839 {
840 global $wpdb;
841
842 $args = array_map('trim', explode(',', $this->config['stats']['post_type']));
843
844 if ( empty($args) ) {
845 $args = ['post', 'page'];
846 }
847
848 $post_type_placeholders = array_fill(0, count($args), '%s');
849
850 if ( $this->config['stats']['freshness'] ) {
851 $args[] = $start_date;
852 }
853
854 // Append dates to arguments list
855 array_unshift($args, $start_date, $end_date);
856
857 if ( $item == 'comments' ) {
858 $query = $wpdb->prepare(
859 "SELECT DATE(`c`.`comment_date_gmt`) AS `c_date`, COUNT(*) AS `comments`
860 FROM `{$wpdb->comments}` c INNER JOIN `{$wpdb->posts}` p ON `c`.`comment_post_ID` = `p`.`ID`
861 WHERE (`c`.`comment_date_gmt` BETWEEN %s AND %s) AND `c`.`comment_approved` = '1' AND `p`.`post_type` IN (". implode(", ", $post_type_placeholders) . ") AND `p`.`post_status` = 'publish' AND `p`.`post_password` = ''
862 " . ( $this->config['stats']['freshness'] ? " AND `p`.`post_date` >= %s" : "" ) . "
863 GROUP BY `c_date` ORDER BY `c_date` DESC;",
864 $args
865 );
866 } else {
867 $query = $wpdb->prepare(
868 "SELECT `v`.`view_date`, SUM(`v`.`pageviews`) AS `pageviews`
869 FROM `{$wpdb->prefix}popularpostssummary` v INNER JOIN `{$wpdb->posts}` p ON `v`.`postid` = `p`.`ID`
870 WHERE (`v`.`view_datetime` BETWEEN %s AND %s) AND `p`.`post_type` IN (". implode(", ", $post_type_placeholders) . ") AND `p`.`post_status` = 'publish' AND `p`.`post_password` = ''
871 " . ( $this->config['stats']['freshness'] ? " AND `p`.`post_date` >= %s" : "" ) . "
872 GROUP BY `v`.`view_date` ORDER BY `v`.`view_date` DESC;",
873 $args
874 );
875
876 //error_log($query);
877 }
878
879 return $wpdb->get_results($query, OBJECT_K);
880 }
881
882 /**
883 * Updates chart via AJAX.
884 *
885 * @since 4.0.0
886 */
887 public function update_chart()
888 {
889 $response = [
890 'status' => 'error'
891 ];
892 $nonce = isset($_GET['nonce']) ? $_GET['nonce'] : null;
893
894 if ( wp_verify_nonce($nonce, 'wpp_admin_nonce') ) {
895
896 $valid_ranges = ['today', 'daily', 'last24hours', 'weekly', 'last7days', 'monthly', 'last30days', 'all', 'custom'];
897 $time_units = ["MINUTE", "HOUR", "DAY"];
898
899 $range = ( isset($_GET['range']) && in_array($_GET['range'], $valid_ranges) ) ? $_GET['range'] : 'last7days';
900 $time_quantity = ( isset($_GET['time_quantity']) && filter_var($_GET['time_quantity'], FILTER_VALIDATE_INT) ) ? $_GET['time_quantity'] : 24;
901 $time_unit = ( isset($_GET['time_unit']) && in_array(strtoupper($_GET['time_unit']), $time_units) ) ? $_GET['time_unit'] : 'hour';
902
903 $this->config['stats']['range'] = $range;
904 $this->config['stats']['time_quantity'] = $time_quantity;
905 $this->config['stats']['time_unit'] = $time_unit;
906
907 update_option('wpp_settings_config', $this->config);
908
909 $response = [
910 'status' => 'ok',
911 'data' => json_decode(
912 $this->get_chart_data($this->config['stats']['range'], $this->config['stats']['time_unit'], $this->config['stats']['time_quantity']),
913 true
914 )
915 ];
916 }
917
918 wp_send_json($response);
919 }
920
921 /**
922 * Fetches most viewed/commented/trending posts via AJAX.
923 *
924 * @since 5.0.0
925 */
926 public function get_popular_items()
927 {
928 $items = isset($_GET['items']) ? $_GET['items'] : null;
929 $nonce = isset($_GET['nonce']) ? $_GET['nonce'] : null;
930
931 if ( wp_verify_nonce($nonce, 'wpp_admin_nonce') ) {
932 $args = [
933 'range' => $this->config['stats']['range'],
934 'time_quantity' => $this->config['stats']['time_quantity'],
935 'time_unit' => $this->config['stats']['time_unit'],
936 'post_type' => $this->config['stats']['post_type'],
937 'freshness' => $this->config['stats']['freshness'],
938 'limit' => $this->config['stats']['limit'],
939 'stats_tag' => [
940 'date' => [
941 'active' => 1
942 ]
943 ]
944 ];
945
946 if ( 'most-commented' == $items ) {
947 $args['order_by'] = 'comments';
948 $args['stats_tag']['comment_count'] = 1;
949 $args['stats_tag']['views'] = 0;
950 } elseif ( 'trending' == $items ) {
951 $args['range'] = 'custom';
952 $args['time_quantity'] = 1;
953 $args['time_unit'] = 'HOUR';
954 $args['stats_tag']['comment_count'] = 1;
955 $args['stats_tag']['views'] = 1;
956 } else {
957 $args['stats_tag']['comment_count'] = 0;
958 $args['stats_tag']['views'] = 1;
959 }
960
961 if ( 'trending' != $items ) {
962
963 add_filter('wpp_query_join', function($join, $options) use ($items)
964 {
965 global $wpdb;
966 $dates = null;
967
968 if ( isset($_GET['dates']) ) {
969 $dates = explode(" ~ ", $_GET['dates']);
970
971 if (
972 ! is_array($dates)
973 || empty($dates)
974 || ! Helper::is_valid_date($dates[0])
975 ) {
976 $dates = null;
977 } else {
978 if (
979 ! isset($dates[1])
980 || ! Helper::is_valid_date($dates[1])
981 ) {
982 $dates[1] = $dates[0];
983 }
984
985 $start_date = $dates[0];
986 $end_date = $dates[1];
987 }
988
989 }
990
991 if ( $dates ) {
992 if ( 'most-commented' == $items ) {
993 return "INNER JOIN (SELECT comment_post_ID, COUNT(comment_post_ID) AS comment_count, comment_date_gmt FROM `{$wpdb->comments}` WHERE comment_date_gmt BETWEEN '{$dates[0]} 00:00:00' AND '{$dates[1]} 23:59:59' AND comment_approved = '1' GROUP BY comment_post_ID) c ON p.ID = c.comment_post_ID";
994 }
995
996 return "INNER JOIN (SELECT SUM(pageviews) AS pageviews, view_date, postid FROM `{$wpdb->prefix}popularpostssummary` WHERE view_datetime BETWEEN '{$dates[0]} 00:00:00' AND '{$dates[1]} 23:59:59' GROUP BY postid) v ON p.ID = v.postid";
997 }
998
999 $now = Helper::now();
1000
1001 // Determine time range
1002 switch( $options['range'] ){
1003 case "last24hours":
1004 case "daily":
1005 $interval = "24 HOUR";
1006 break;
1007
1008 case "today":
1009 $hours = date('H', strtotime($now));
1010 $minutes = $hours * 60 + (int) date( 'i', strtotime($now) );
1011 $interval = "{$minutes} MINUTE";
1012 break;
1013
1014 case "last7days":
1015 case "weekly":
1016 $interval = "6 DAY";
1017 break;
1018
1019 case "last30days":
1020 case "monthly":
1021 $interval = "29 DAY";
1022 break;
1023
1024 case "custom":
1025 $time_units = ["MINUTE", "HOUR", "DAY"];
1026 $interval = "24 HOUR";
1027
1028 // Valid time unit
1029 if (
1030 isset($options['time_unit'])
1031 && in_array(strtoupper($options['time_unit']), $time_units)
1032 && isset($options['time_quantity'])
1033 && filter_var($options['time_quantity'], FILTER_VALIDATE_INT)
1034 && $options['time_quantity'] > 0
1035 ) {
1036 $interval = "{$options['time_quantity']} " . strtoupper($options['time_unit']);
1037 }
1038
1039 break;
1040
1041 default:
1042 $interval = "1 DAY";
1043 break;
1044 }
1045
1046 if ( 'most-commented' == $items ) {
1047 return "INNER JOIN (SELECT comment_post_ID, COUNT(comment_post_ID) AS comment_count, comment_date_gmt FROM `{$wpdb->comments}` WHERE comment_date_gmt > DATE_SUB('{$now}', INTERVAL {$interval}) AND comment_approved = '1' GROUP BY comment_post_ID) c ON p.ID = c.comment_post_ID";
1048 }
1049
1050 return "INNER JOIN (SELECT SUM(pageviews) AS pageviews, view_date, postid FROM `{$wpdb->prefix}popularpostssummary` WHERE view_datetime > DATE_SUB('{$now}', INTERVAL {$interval}) GROUP BY postid) v ON p.ID = v.postid";
1051 }, 1, 2);
1052
1053 }
1054
1055 $popular_items = new \WordPressPopularPosts\Query($args);
1056 $posts = $popular_items->get_posts();
1057
1058 if ( 'trending' != $items ) {
1059 remove_all_filters('wpp_query_join', 1);
1060 }
1061
1062 $this->render_list($posts, $items);
1063 }
1064
1065 wp_die();
1066 }
1067
1068 /**
1069 * Renders popular posts lists.
1070 *
1071 * @since 5.0.0
1072 * @param array
1073 */
1074 public function render_list($posts, $list = 'most-viewed')
1075 {
1076 if (
1077 is_array($posts)
1078 && ! empty($posts)
1079 ) {
1080 ?>
1081 <ol class="popular-posts-list">
1082 <?php
1083 foreach( $posts as $post ) { ?>
1084 <li>
1085 <a href="<?php echo get_permalink($post->id); ?>" class="wpp-title"><?php echo sanitize_text_field(apply_filters('the_title', $post->title, $post->id)); ?></a>
1086 <div>
1087 <?php if ( 'most-viewed' == $list ) : ?>
1088 <span><?php printf(_n('%s view', '%s views', $post->pageviews, 'wordpress-popular-posts' ), number_format_i18n($post->pageviews)); ?></span>
1089 <?php elseif ( 'most-commented' == $list ) : ?>
1090 <span><?php printf(_n('%s comment', '%s comments', $post->comment_count, 'wordpress-popular-posts'), number_format_i18n($post->comment_count)); ?></span>
1091 <?php else : ?>
1092 <span><?php printf(_n('%s view', '%s views', $post->pageviews, 'wordpress-popular-posts' ), number_format_i18n($post->pageviews)); ?></span>, <span><?php printf(_n('%s comment', '%s comments', $post->comment_count, 'wordpress-popular-posts'), number_format_i18n($post->comment_count)); ?></span>
1093 <?php endif; ?>
1094 <small> &mdash; <a href="<?php echo get_permalink($post->id); ?>"><?php _e("View"); ?></a><?php if ( current_user_can('edit_others_posts') ): ?> | <a href="<?php echo get_edit_post_link($post->id); ?>"><?php _e("Edit"); ?></a><?php endif; ?></small>
1095 </div>
1096 </li>
1097 <?php
1098 }
1099 ?>
1100 </ol>
1101 <?php
1102 }
1103 else {
1104 ?>
1105 <p class="no-data" style="text-align: center;"><?php _e("Looks like your site's activity is a little low right now. <br />Spread the word and come back later!", "wordpress-popular-posts"); ?></p>
1106 <?php
1107 }
1108 }
1109
1110 /**
1111 * Truncates data and cache on demand.
1112 *
1113 * @since 2.0.0
1114 * @global object $wpdb
1115 */
1116 public function clear_data()
1117 {
1118 $token = $_POST['token'];
1119 $clear = isset($_POST['clear']) ? $_POST['clear'] : null;
1120 $key = get_option("wpp_rand");
1121
1122 if (
1123 current_user_can('manage_options')
1124 && ( $token === $key )
1125 && $clear
1126 ) {
1127 global $wpdb;
1128
1129 // set table name
1130 $prefix = $wpdb->prefix . "popularposts";
1131
1132 if ( $clear == 'cache' ) {
1133 if ( $wpdb->get_var("SHOW TABLES LIKE '{$prefix}summary'") ) {
1134 $wpdb->query("TRUNCATE TABLE {$prefix}summary;");
1135 $this->flush_transients();
1136
1137 echo 1;
1138 } else {
1139 echo 2;
1140 }
1141 } elseif ( $clear == 'all' ) {
1142 if ( $wpdb->get_var("SHOW TABLES LIKE '{$prefix}data'") && $wpdb->get_var("SHOW TABLES LIKE '{$prefix}summary'") ) {
1143 $wpdb->query("TRUNCATE TABLE {$prefix}data;");
1144 $wpdb->query("TRUNCATE TABLE {$prefix}summary;");
1145 $this->flush_transients();
1146
1147 echo 1;
1148 } else {
1149 echo 2;
1150 }
1151 } else {
1152 echo 3;
1153 }
1154 } else {
1155 echo 4;
1156 }
1157
1158 wp_die();
1159 }
1160
1161 /**
1162 * Deletes cached (transient) data.
1163 *
1164 * @since 3.0.0
1165 * @access private
1166 */
1167 private function flush_transients()
1168 {
1169 $wpp_transients = get_option('wpp_transients');
1170
1171 if ( $wpp_transients && is_array($wpp_transients) && ! empty($wpp_transients) ) {
1172 for ( $t=0; $t < count($wpp_transients); $t++ )
1173 delete_transient($wpp_transients[$t]);
1174
1175 update_option('wpp_transients', []);
1176 }
1177 }
1178
1179 /**
1180 * Truncates thumbnails cache on demand.
1181 *
1182 * @since 2.0.0
1183 * @global object wpdb
1184 */
1185 public function clear_thumbnails()
1186 {
1187 $wpp_uploads_dir = $this->thumbnail->get_plugin_uploads_dir();
1188
1189 if ( is_array($wpp_uploads_dir) && ! empty($wpp_uploads_dir) ) {
1190 $token = isset($_POST['token']) ? $_POST['token'] : null;
1191 $key = get_option("wpp_rand");
1192
1193 if (
1194 current_user_can('edit_published_posts')
1195 && ( $token === $key )
1196 ) {
1197 if ( is_dir($wpp_uploads_dir['basedir']) ) {
1198 $files = glob("{$wpp_uploads_dir['basedir']}/*"); // get all related images
1199
1200 if ( is_array($files) && ! empty($files) ) {
1201 foreach( $files as $file ){ // iterate files
1202 if ( is_file($file) ) {
1203 @unlink($file); // delete file
1204 }
1205 }
1206 echo 1;
1207 } else {
1208 echo 2;
1209 }
1210 } else {
1211 echo 3;
1212 }
1213 } else {
1214 echo 4;
1215 }
1216 }
1217
1218 wp_die();
1219 }
1220
1221 /**
1222 * Fires immediately after deleting metadata of a post.
1223 *
1224 * @since 5.0.0
1225 *
1226 * @param int $meta_id Metadata ID.
1227 * @param int $post_id Post ID.
1228 * @param string $meta_key Meta key.
1229 * @param mixed $meta_value Meta value.
1230 */
1231 public function updated_post_meta($meta_id, $post_id, $meta_key, $meta_value)
1232 {
1233 if ( '_thumbnail_id' == $meta_key ) {
1234 $this->flush_post_thumbnail($post_id);
1235 }
1236 }
1237
1238 /**
1239 * Fires immediately after deleting metadata of a post.
1240 *
1241 * @since 5.0.0
1242 *
1243 * @param array $meta_ids An array of deleted metadata entry IDs.
1244 * @param int $post_id Post ID.
1245 * @param string $meta_key Meta key.
1246 * @param mixed $meta_value Meta value.
1247 */
1248 public function deleted_post_meta($meta_ids, $post_id, $meta_key, $meta_value)
1249 {
1250 if ( '_thumbnail_id' == $meta_key ) {
1251 $this->flush_post_thumbnail($post_id);
1252 }
1253 }
1254
1255 /**
1256 * Flushes post's cached thumbnail(s).
1257 *
1258 * @since 3.3.4
1259 *
1260 * @param integer $post_id Post ID
1261 */
1262 public function flush_post_thumbnail($post_id)
1263 {
1264 $wpp_uploads_dir = $this->thumbnail->get_plugin_uploads_dir();
1265
1266 if ( is_array($wpp_uploads_dir) && ! empty($wpp_uploads_dir) ) {
1267 $files = glob("{$wpp_uploads_dir['basedir']}/{$post_id}-*.*"); // get all related images
1268
1269 if ( is_array($files) && ! empty($files) ) {
1270 foreach( $files as $file ){ // iterate files
1271 if ( is_file($file) ) {
1272 @unlink($file); // delete file
1273 }
1274 }
1275 }
1276 }
1277 }
1278
1279 /**
1280 * Purges post from data/summary tables.
1281 *
1282 * @since 3.3.0
1283 */
1284 public function purge_post_data()
1285 {
1286 if ( current_user_can('delete_posts') )
1287 add_action('delete_post', [$this, 'purge_post']);
1288 }
1289
1290 /**
1291 * Purges post from data/summary tables.
1292 *
1293 * @since 3.3.0
1294 * @global object $wpdb
1295 */
1296 public function purge_post($post_ID)
1297 {
1298 global $wpdb;
1299
1300 if ( $wpdb->get_var($wpdb->prepare("SELECT postid FROM {$wpdb->prefix}popularpostsdata WHERE postid = %d", $post_ID)) ) {
1301 // Delete from data table
1302 $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->prefix}popularpostsdata WHERE postid = %d;", $post_ID));
1303 // Delete from summary table
1304 $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->prefix}popularpostssummary WHERE postid = %d;", $post_ID));
1305 }
1306
1307 // Delete cached thumbnail(s) as well
1308 $this->flush_post_thumbnail($post_ID);
1309 }
1310
1311 /**
1312 * Purges old post data from summary table.
1313 *
1314 * @since 2.0.0
1315 * @global object $wpdb
1316 */
1317 public function purge_data()
1318 {
1319 global $wpdb;
1320 $wpdb->query("DELETE FROM {$wpdb->prefix}popularpostssummary WHERE view_date < DATE_SUB('" . Helper::curdate() . "', INTERVAL {$this->config['tools']['log']['expires_after']} DAY);");
1321 }
1322
1323 /**
1324 * Displays admin notices.
1325 *
1326 * @since 5.0.2
1327 */
1328 public function notices()
1329 {
1330 /** Performance nag */
1331 $performance_nag = get_option('wpp_performance_nag');
1332
1333 if (
1334 isset($performance_nag['status'])
1335 && 3 != $performance_nag['status'] // 0 = inactive, 1 = active, 2 = remind me later, 3 = dismissed
1336 ) {
1337 $now = Helper::timestamp();
1338
1339 if ( isset($_GET['wpp_dismiss_performance_notice']) || isset($_GET['wpp_remind_performance_notice']) ) {
1340 // User dismissed the notice
1341 if ( isset($_GET['wpp_dismiss_performance_notice']) ) {
1342 $performance_nag['status'] = 3;
1343 } // User asked us to remind them later
1344 else {
1345 $performance_nag['status'] = 2;
1346 $performance_nag['last_checked'] = $now;
1347 }
1348
1349 update_option('wpp_performance_nag', $performance_nag);
1350 echo '<script>window.location.replace("'. esc_url(remove_query_arg(['wpp_dismiss_performance_notice', 'wpp_remind_performance_notice'])) .'");</script>';
1351 } // Maybe display the notice
1352 else {
1353 // How much time has passed since the notice was last displayed?
1354 $last_checked = $performance_nag['last_checked'];
1355
1356 if ( $last_checked ) {
1357 $last_checked = ($now - $last_checked) / (60 * 60);
1358 }
1359
1360 if (
1361 1 == $performance_nag['status']
1362 || ( 2 == $performance_nag['status'] && $last_checked && $last_checked >= 24 )
1363 ) {
1364 ?>
1365 <div class="notice notice-warning">
1366 <p><?php printf(
1367 __("<strong>WordPress Popular Posts:</strong> It seems your site is popular (great!) You may want to check <a href=\"%s\">these suggestions</a> to make sure your website's performance stays up to par.", 'wordpress-popular-posts'),
1368 'https://github.com/cabrerahector/wordpress-popular-posts/wiki/7.-Performance'
1369 ) ?></p>
1370 <?php if ( current_user_can('manage_options') ) : ?>
1371 <p><a href="<?php echo add_query_arg('wpp_dismiss_performance_notice', '1'); ?>">Dismiss</a> | <a href="<?php echo add_query_arg('wpp_remind_performance_notice', '1'); ?>">Remind me later</a></p>
1372 <?php endif; ?>
1373 </div>
1374 <?php
1375 }
1376 }
1377 }
1378 }
1379 }
1380