PluginProbe ʕ •ᴥ•ʔ
WP Popular Posts / 5.3.2
WP Popular Posts v5.3.2
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
1384 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 array_unshift(
623 $links,
624 '<a href="' . admin_url('options-general.php?page=wordpress-popular-posts') . '">' . __('Settings') . '</a>',
625 '<a href="https://wordpress.org/support/plugin/wordpress-popular-posts/">' . __('Support', 'wordpress-popular-posts') . '</a>'
626 );
627 }
628
629 return $links;
630 }
631
632 /**
633 * Gets current admin color scheme.
634 *
635 * @since 4.0.0
636 * @return array
637 */
638 private function get_admin_color_scheme()
639 {
640 global $_wp_admin_css_colors;
641
642 if (
643 is_array($_wp_admin_css_colors)
644 && count($_wp_admin_css_colors)
645 ) {
646 $current_user = wp_get_current_user();
647 $color_scheme = get_user_option('admin_color', $current_user->ID);
648
649 if (
650 empty($color_scheme)
651 || ! isset($_wp_admin_css_colors[ $color_scheme])
652 ) {
653 $color_scheme = 'fresh';
654 }
655
656 if ( isset($_wp_admin_css_colors[$color_scheme]) && isset($_wp_admin_css_colors[$color_scheme]->colors) ) {
657 return $_wp_admin_css_colors[$color_scheme]->colors;
658 }
659
660 }
661
662 // Fallback, just in case
663 return ['#333', '#999', '#881111', '#a80000'];
664 }
665
666 /**
667 * Fetches chart data.
668 *
669 * @since 4.0.0
670 * @return string
671 */
672 public function get_chart_data($range = 'last7days', $time_unit = 'HOUR', $time_quantity = 24)
673 {
674 $dates = $this->get_dates($range, $time_unit, $time_quantity);
675 $start_date = $dates[0];
676 $end_date = $dates[count($dates) - 1];
677 $date_range = Helper::get_date_range($start_date, $end_date, 'Y-m-d H:i:s');
678 $views_data = $this->get_range_item_count($start_date, $end_date, 'views');
679 $views = [];
680 $comments_data = $this->get_range_item_count($start_date, $end_date, 'comments');
681 $comments = [];
682
683 if ( 'today' != $range ) {
684 foreach($date_range as $date) {
685 $key = date('Y-m-d', strtotime($date));
686 $views[] = ( ! isset($views_data[$key]) ) ? 0 : $views_data[$key]->pageviews;
687 $comments[] = ( ! isset($comments_data[$key]) ) ? 0 : $comments_data[$key]->comments;
688 }
689 } else {
690 $key = date('Y-m-d', strtotime($dates[0]));
691 $views[] = ( ! isset($views_data[$key]) ) ? 0 : $views_data[$key]->pageviews;
692 $comments[] = ( ! isset($comments_data[$key]) ) ? 0 : $comments_data[$key]->comments;
693 }
694
695 if ( $start_date != $end_date )
696 $label_date_range = date_i18n('M, D d', strtotime($start_date)) . ' &mdash; ' . date_i18n('M, D d', strtotime($end_date));
697 else
698 $label_date_range = date_i18n('M, D d', strtotime($start_date));
699
700 $total_views = array_sum($views);
701 $total_comments = array_sum($comments);
702
703 $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>');
704
705 // Format labels
706 if ( 'today' != $range ) {
707 $date_range = array_map(function($d){
708 return date_i18n('D d', strtotime($d));
709 }, $date_range);
710 } else {
711 $date_range = [date_i18n('D d', strtotime($date_range[0]))];
712 $comments = [array_sum($comments)];
713 $views = [array_sum($views)];
714 }
715
716 $response = [
717 'totals' => [
718 'label_summary' => $label_summary,
719 'label_date_range' => $label_date_range,
720 ],
721 'labels' => $date_range,
722 'datasets' => [
723 [
724 'label' => __("Comments", "wordpress-popular-posts"),
725 'data' => $comments
726 ],
727 [
728 'label' => __("Views", "wordpress-popular-posts"),
729 'data' => $views
730 ]
731 ]
732 ];
733
734 return json_encode($response);
735 }
736
737 /**
738 * Returns an array of dates.
739 *
740 * @since 5.0.0
741 * @return array|bool
742 */
743 private function get_dates($range = 'last7days', $time_unit = 'HOUR', $time_quantity = 24)
744 {
745 $valid_ranges = ['today', 'daily', 'last24hours', 'weekly', 'last7days', 'monthly', 'last30days', 'all', 'custom'];
746 $range = in_array($range, $valid_ranges) ? $range : 'last7days';
747 $now = new \DateTime(Helper::now(), new \DateTimeZone(Helper::get_timezone()));
748
749 // Determine time range
750 switch( $range ){
751 case "last24hours":
752 case "daily":
753 $end_date = $now->format('Y-m-d H:i:s');
754 $start_date = $now->modify('-1 day')->format('Y-m-d H:i:s');
755 break;
756
757 case "today":
758 $start_date = $now->format('Y-m-d') . ' 00:00:00';
759 $end_date = $now->format('Y-m-d') . ' 23:59:59';
760 break;
761
762 case "last7days":
763 case "weekly":
764 $end_date = $now->format('Y-m-d') . ' 23:59:59';
765 $start_date = $now->modify('-6 day')->format('Y-m-d') . ' 00:00:00';
766 break;
767
768 case "last30days":
769 case "monthly":
770 $end_date = $now->format('Y-m-d') . ' 23:59:59';
771 $start_date = $now->modify('-29 day')->format('Y-m-d') . ' 00:00:00';
772 break;
773
774 case "custom":
775 $end_date = $now->format('Y-m-d H:i:s');
776
777 if (
778 Helper::is_number($time_quantity)
779 && $time_quantity >= 1
780 ) {
781 $end_date = $now->format('Y-m-d H:i:s');
782 $time_unit = strtoupper($time_unit);
783
784 if ( 'MINUTE' == $time_unit ) {
785 $start_date = $now->sub(new \DateInterval('PT' . (60 * $time_quantity) . 'S'))->format('Y-m-d H:i:s');
786 } elseif ( 'HOUR' == $time_unit ) {
787 $start_date = $now->sub(new \DateInterval('PT' . ((60 * $time_quantity) - 1) . 'M59S'))->format('Y-m-d H:i:s');
788 } else {
789 $end_date = $now->format('Y-m-d') . ' 23:59:59';
790 $start_date = $now->sub(new \DateInterval('P' . ($time_quantity - 1) . 'D'))->format('Y-m-d') . ' 00:00:00';
791 }
792 } // fallback to last 24 hours
793 else {
794 $start_date = $now->modify('-1 day')->format('Y-m-d H:i:s');
795 }
796
797 // Check if custom date range has been requested
798 $dates = null;
799
800 if ( isset($_GET['dates']) ) {
801 $dates = explode(" ~ ", $_GET['dates']);
802
803 if (
804 ! is_array($dates)
805 || empty($dates)
806 || ! Helper::is_valid_date($dates[0])
807 ) {
808 $dates = null;
809 } else {
810 if (
811 ! isset($dates[1])
812 || ! Helper::is_valid_date($dates[1])
813 ) {
814 $dates[1] = $dates[0];
815 }
816
817 $start_date = $dates[0] . ' 00:00:00';
818 $end_date = $dates[1] . ' 23:59:59';
819 }
820 }
821
822 break;
823
824 default:
825 $end_date = $now->format('Y-m-d') . ' 23:59:59';
826 $start_date = $now->modify('-6 day')->format('Y-m-d') . ' 00:00:00';
827 break;
828 }
829
830 return [$start_date, $end_date];
831 }
832
833 /**
834 * Returns an array of dates with views/comments count.
835 *
836 * @since 5.0.0
837 * @param string $start_date
838 * @param string $end_date
839 * @param string $item
840 * @return array
841 */
842 public function get_range_item_count($start_date, $end_date, $item = 'views')
843 {
844 global $wpdb;
845
846 $args = array_map('trim', explode(',', $this->config['stats']['post_type']));
847
848 if ( empty($args) ) {
849 $args = ['post', 'page'];
850 }
851
852 $post_type_placeholders = array_fill(0, count($args), '%s');
853
854 if ( $this->config['stats']['freshness'] ) {
855 $args[] = $start_date;
856 }
857
858 // Append dates to arguments list
859 array_unshift($args, $start_date, $end_date);
860
861 if ( $item == 'comments' ) {
862 $query = $wpdb->prepare(
863 "SELECT DATE(`c`.`comment_date_gmt`) AS `c_date`, COUNT(*) AS `comments`
864 FROM `{$wpdb->comments}` c INNER JOIN `{$wpdb->posts}` p ON `c`.`comment_post_ID` = `p`.`ID`
865 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` = ''
866 " . ( $this->config['stats']['freshness'] ? " AND `p`.`post_date` >= %s" : "" ) . "
867 GROUP BY `c_date` ORDER BY `c_date` DESC;",
868 $args
869 );
870 } else {
871 $query = $wpdb->prepare(
872 "SELECT `v`.`view_date`, SUM(`v`.`pageviews`) AS `pageviews`
873 FROM `{$wpdb->prefix}popularpostssummary` v INNER JOIN `{$wpdb->posts}` p ON `v`.`postid` = `p`.`ID`
874 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` = ''
875 " . ( $this->config['stats']['freshness'] ? " AND `p`.`post_date` >= %s" : "" ) . "
876 GROUP BY `v`.`view_date` ORDER BY `v`.`view_date` DESC;",
877 $args
878 );
879
880 //error_log($query);
881 }
882
883 return $wpdb->get_results($query, OBJECT_K);
884 }
885
886 /**
887 * Updates chart via AJAX.
888 *
889 * @since 4.0.0
890 */
891 public function update_chart()
892 {
893 $response = [
894 'status' => 'error'
895 ];
896 $nonce = isset($_GET['nonce']) ? $_GET['nonce'] : null;
897
898 if ( wp_verify_nonce($nonce, 'wpp_admin_nonce') ) {
899
900 $valid_ranges = ['today', 'daily', 'last24hours', 'weekly', 'last7days', 'monthly', 'last30days', 'all', 'custom'];
901 $time_units = ["MINUTE", "HOUR", "DAY"];
902
903 $range = ( isset($_GET['range']) && in_array($_GET['range'], $valid_ranges) ) ? $_GET['range'] : 'last7days';
904 $time_quantity = ( isset($_GET['time_quantity']) && filter_var($_GET['time_quantity'], FILTER_VALIDATE_INT) ) ? $_GET['time_quantity'] : 24;
905 $time_unit = ( isset($_GET['time_unit']) && in_array(strtoupper($_GET['time_unit']), $time_units) ) ? $_GET['time_unit'] : 'hour';
906
907 $this->config['stats']['range'] = $range;
908 $this->config['stats']['time_quantity'] = $time_quantity;
909 $this->config['stats']['time_unit'] = $time_unit;
910
911 update_option('wpp_settings_config', $this->config);
912
913 $response = [
914 'status' => 'ok',
915 'data' => json_decode(
916 $this->get_chart_data($this->config['stats']['range'], $this->config['stats']['time_unit'], $this->config['stats']['time_quantity']),
917 true
918 )
919 ];
920 }
921
922 wp_send_json($response);
923 }
924
925 /**
926 * Fetches most viewed/commented/trending posts via AJAX.
927 *
928 * @since 5.0.0
929 */
930 public function get_popular_items()
931 {
932 $items = isset($_GET['items']) ? $_GET['items'] : null;
933 $nonce = isset($_GET['nonce']) ? $_GET['nonce'] : null;
934
935 if ( wp_verify_nonce($nonce, 'wpp_admin_nonce') ) {
936 $args = [
937 'range' => $this->config['stats']['range'],
938 'time_quantity' => $this->config['stats']['time_quantity'],
939 'time_unit' => $this->config['stats']['time_unit'],
940 'post_type' => $this->config['stats']['post_type'],
941 'freshness' => $this->config['stats']['freshness'],
942 'limit' => $this->config['stats']['limit'],
943 'stats_tag' => [
944 'date' => [
945 'active' => 1
946 ]
947 ]
948 ];
949
950 if ( 'most-commented' == $items ) {
951 $args['order_by'] = 'comments';
952 $args['stats_tag']['comment_count'] = 1;
953 $args['stats_tag']['views'] = 0;
954 } elseif ( 'trending' == $items ) {
955 $args['range'] = 'custom';
956 $args['time_quantity'] = 1;
957 $args['time_unit'] = 'HOUR';
958 $args['stats_tag']['comment_count'] = 1;
959 $args['stats_tag']['views'] = 1;
960 } else {
961 $args['stats_tag']['comment_count'] = 0;
962 $args['stats_tag']['views'] = 1;
963 }
964
965 if ( 'trending' != $items ) {
966
967 add_filter('wpp_query_join', function($join, $options) use ($items)
968 {
969 global $wpdb;
970 $dates = null;
971
972 if ( isset($_GET['dates']) ) {
973 $dates = explode(" ~ ", $_GET['dates']);
974
975 if (
976 ! is_array($dates)
977 || empty($dates)
978 || ! Helper::is_valid_date($dates[0])
979 ) {
980 $dates = null;
981 } else {
982 if (
983 ! isset($dates[1])
984 || ! Helper::is_valid_date($dates[1])
985 ) {
986 $dates[1] = $dates[0];
987 }
988
989 $start_date = $dates[0];
990 $end_date = $dates[1];
991 }
992
993 }
994
995 if ( $dates ) {
996 if ( 'most-commented' == $items ) {
997 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";
998 }
999
1000 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";
1001 }
1002
1003 $now = Helper::now();
1004
1005 // Determine time range
1006 switch( $options['range'] ){
1007 case "last24hours":
1008 case "daily":
1009 $interval = "24 HOUR";
1010 break;
1011
1012 case "today":
1013 $hours = date('H', strtotime($now));
1014 $minutes = $hours * 60 + (int) date( 'i', strtotime($now) );
1015 $interval = "{$minutes} MINUTE";
1016 break;
1017
1018 case "last7days":
1019 case "weekly":
1020 $interval = "6 DAY";
1021 break;
1022
1023 case "last30days":
1024 case "monthly":
1025 $interval = "29 DAY";
1026 break;
1027
1028 case "custom":
1029 $time_units = ["MINUTE", "HOUR", "DAY"];
1030 $interval = "24 HOUR";
1031
1032 // Valid time unit
1033 if (
1034 isset($options['time_unit'])
1035 && in_array(strtoupper($options['time_unit']), $time_units)
1036 && isset($options['time_quantity'])
1037 && filter_var($options['time_quantity'], FILTER_VALIDATE_INT)
1038 && $options['time_quantity'] > 0
1039 ) {
1040 $interval = "{$options['time_quantity']} " . strtoupper($options['time_unit']);
1041 }
1042
1043 break;
1044
1045 default:
1046 $interval = "1 DAY";
1047 break;
1048 }
1049
1050 if ( 'most-commented' == $items ) {
1051 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";
1052 }
1053
1054 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";
1055 }, 1, 2);
1056
1057 }
1058
1059 $popular_items = new \WordPressPopularPosts\Query($args);
1060 $posts = $popular_items->get_posts();
1061
1062 if ( 'trending' != $items ) {
1063 remove_all_filters('wpp_query_join', 1);
1064 }
1065
1066 $this->render_list($posts, $items);
1067 }
1068
1069 wp_die();
1070 }
1071
1072 /**
1073 * Renders popular posts lists.
1074 *
1075 * @since 5.0.0
1076 * @param array
1077 */
1078 public function render_list($posts, $list = 'most-viewed')
1079 {
1080 if (
1081 is_array($posts)
1082 && ! empty($posts)
1083 ) {
1084 ?>
1085 <ol class="popular-posts-list">
1086 <?php
1087 foreach( $posts as $post ) { ?>
1088 <li>
1089 <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>
1090 <div>
1091 <?php if ( 'most-viewed' == $list ) : ?>
1092 <span><?php printf(_n('%s view', '%s views', $post->pageviews, 'wordpress-popular-posts' ), number_format_i18n($post->pageviews)); ?></span>
1093 <?php elseif ( 'most-commented' == $list ) : ?>
1094 <span><?php printf(_n('%s comment', '%s comments', $post->comment_count, 'wordpress-popular-posts'), number_format_i18n($post->comment_count)); ?></span>
1095 <?php else : ?>
1096 <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>
1097 <?php endif; ?>
1098 <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>
1099 </div>
1100 </li>
1101 <?php
1102 }
1103 ?>
1104 </ol>
1105 <?php
1106 }
1107 else {
1108 ?>
1109 <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>
1110 <?php
1111 }
1112 }
1113
1114 /**
1115 * Truncates data and cache on demand.
1116 *
1117 * @since 2.0.0
1118 * @global object $wpdb
1119 */
1120 public function clear_data()
1121 {
1122 $token = $_POST['token'];
1123 $clear = isset($_POST['clear']) ? $_POST['clear'] : null;
1124 $key = get_option("wpp_rand");
1125
1126 if (
1127 current_user_can('manage_options')
1128 && ( $token === $key )
1129 && $clear
1130 ) {
1131 global $wpdb;
1132
1133 // set table name
1134 $prefix = $wpdb->prefix . "popularposts";
1135
1136 if ( $clear == 'cache' ) {
1137 if ( $wpdb->get_var("SHOW TABLES LIKE '{$prefix}summary'") ) {
1138 $wpdb->query("TRUNCATE TABLE {$prefix}summary;");
1139 $this->flush_transients();
1140
1141 echo 1;
1142 } else {
1143 echo 2;
1144 }
1145 } elseif ( $clear == 'all' ) {
1146 if ( $wpdb->get_var("SHOW TABLES LIKE '{$prefix}data'") && $wpdb->get_var("SHOW TABLES LIKE '{$prefix}summary'") ) {
1147 $wpdb->query("TRUNCATE TABLE {$prefix}data;");
1148 $wpdb->query("TRUNCATE TABLE {$prefix}summary;");
1149 $this->flush_transients();
1150
1151 echo 1;
1152 } else {
1153 echo 2;
1154 }
1155 } else {
1156 echo 3;
1157 }
1158 } else {
1159 echo 4;
1160 }
1161
1162 wp_die();
1163 }
1164
1165 /**
1166 * Deletes cached (transient) data.
1167 *
1168 * @since 3.0.0
1169 * @access private
1170 */
1171 private function flush_transients()
1172 {
1173 $wpp_transients = get_option('wpp_transients');
1174
1175 if ( $wpp_transients && is_array($wpp_transients) && ! empty($wpp_transients) ) {
1176 for ( $t=0; $t < count($wpp_transients); $t++ )
1177 delete_transient($wpp_transients[$t]);
1178
1179 update_option('wpp_transients', []);
1180 }
1181 }
1182
1183 /**
1184 * Truncates thumbnails cache on demand.
1185 *
1186 * @since 2.0.0
1187 * @global object wpdb
1188 */
1189 public function clear_thumbnails()
1190 {
1191 $wpp_uploads_dir = $this->thumbnail->get_plugin_uploads_dir();
1192
1193 if ( is_array($wpp_uploads_dir) && ! empty($wpp_uploads_dir) ) {
1194 $token = isset($_POST['token']) ? $_POST['token'] : null;
1195 $key = get_option("wpp_rand");
1196
1197 if (
1198 current_user_can('edit_published_posts')
1199 && ( $token === $key )
1200 ) {
1201 if ( is_dir($wpp_uploads_dir['basedir']) ) {
1202 $files = glob("{$wpp_uploads_dir['basedir']}/*"); // get all related images
1203
1204 if ( is_array($files) && ! empty($files) ) {
1205 foreach( $files as $file ){ // iterate files
1206 if ( is_file($file) ) {
1207 @unlink($file); // delete file
1208 }
1209 }
1210 echo 1;
1211 } else {
1212 echo 2;
1213 }
1214 } else {
1215 echo 3;
1216 }
1217 } else {
1218 echo 4;
1219 }
1220 }
1221
1222 wp_die();
1223 }
1224
1225 /**
1226 * Fires immediately after deleting metadata of a post.
1227 *
1228 * @since 5.0.0
1229 *
1230 * @param int $meta_id Metadata ID.
1231 * @param int $post_id Post ID.
1232 * @param string $meta_key Meta key.
1233 * @param mixed $meta_value Meta value.
1234 */
1235 public function updated_post_meta($meta_id, $post_id, $meta_key, $meta_value)
1236 {
1237 if ( '_thumbnail_id' == $meta_key ) {
1238 $this->flush_post_thumbnail($post_id);
1239 }
1240 }
1241
1242 /**
1243 * Fires immediately after deleting metadata of a post.
1244 *
1245 * @since 5.0.0
1246 *
1247 * @param array $meta_ids An array of deleted metadata entry IDs.
1248 * @param int $post_id Post ID.
1249 * @param string $meta_key Meta key.
1250 * @param mixed $meta_value Meta value.
1251 */
1252 public function deleted_post_meta($meta_ids, $post_id, $meta_key, $meta_value)
1253 {
1254 if ( '_thumbnail_id' == $meta_key ) {
1255 $this->flush_post_thumbnail($post_id);
1256 }
1257 }
1258
1259 /**
1260 * Flushes post's cached thumbnail(s).
1261 *
1262 * @since 3.3.4
1263 *
1264 * @param integer $post_id Post ID
1265 */
1266 public function flush_post_thumbnail($post_id)
1267 {
1268 $wpp_uploads_dir = $this->thumbnail->get_plugin_uploads_dir();
1269
1270 if ( is_array($wpp_uploads_dir) && ! empty($wpp_uploads_dir) ) {
1271 $files = glob("{$wpp_uploads_dir['basedir']}/{$post_id}-*.*"); // get all related images
1272
1273 if ( is_array($files) && ! empty($files) ) {
1274 foreach( $files as $file ){ // iterate files
1275 if ( is_file($file) ) {
1276 @unlink($file); // delete file
1277 }
1278 }
1279 }
1280 }
1281 }
1282
1283 /**
1284 * Purges post from data/summary tables.
1285 *
1286 * @since 3.3.0
1287 */
1288 public function purge_post_data()
1289 {
1290 if ( current_user_can('delete_posts') )
1291 add_action('delete_post', [$this, 'purge_post']);
1292 }
1293
1294 /**
1295 * Purges post from data/summary tables.
1296 *
1297 * @since 3.3.0
1298 * @global object $wpdb
1299 */
1300 public function purge_post($post_ID)
1301 {
1302 global $wpdb;
1303
1304 if ( $wpdb->get_var($wpdb->prepare("SELECT postid FROM {$wpdb->prefix}popularpostsdata WHERE postid = %d", $post_ID)) ) {
1305 // Delete from data table
1306 $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->prefix}popularpostsdata WHERE postid = %d;", $post_ID));
1307 // Delete from summary table
1308 $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->prefix}popularpostssummary WHERE postid = %d;", $post_ID));
1309 }
1310
1311 // Delete cached thumbnail(s) as well
1312 $this->flush_post_thumbnail($post_ID);
1313 }
1314
1315 /**
1316 * Purges old post data from summary table.
1317 *
1318 * @since 2.0.0
1319 * @global object $wpdb
1320 */
1321 public function purge_data()
1322 {
1323 global $wpdb;
1324 $wpdb->query("DELETE FROM {$wpdb->prefix}popularpostssummary WHERE view_date < DATE_SUB('" . Helper::curdate() . "', INTERVAL {$this->config['tools']['log']['expires_after']} DAY);");
1325 }
1326
1327 /**
1328 * Displays admin notices.
1329 *
1330 * @since 5.0.2
1331 */
1332 public function notices()
1333 {
1334 /** Performance nag */
1335 $performance_nag = get_option('wpp_performance_nag');
1336
1337 if (
1338 isset($performance_nag['status'])
1339 && 3 != $performance_nag['status'] // 0 = inactive, 1 = active, 2 = remind me later, 3 = dismissed
1340 ) {
1341 $now = Helper::timestamp();
1342
1343 if ( isset($_GET['wpp_dismiss_performance_notice']) || isset($_GET['wpp_remind_performance_notice']) ) {
1344 // User dismissed the notice
1345 if ( isset($_GET['wpp_dismiss_performance_notice']) ) {
1346 $performance_nag['status'] = 3;
1347 } // User asked us to remind them later
1348 else {
1349 $performance_nag['status'] = 2;
1350 $performance_nag['last_checked'] = $now;
1351 }
1352
1353 update_option('wpp_performance_nag', $performance_nag);
1354 echo '<script>window.location.replace("'. esc_url(remove_query_arg(['wpp_dismiss_performance_notice', 'wpp_remind_performance_notice'])) .'");</script>';
1355 } // Maybe display the notice
1356 else {
1357 // How much time has passed since the notice was last displayed?
1358 $last_checked = $performance_nag['last_checked'];
1359
1360 if ( $last_checked ) {
1361 $last_checked = ($now - $last_checked) / (60 * 60);
1362 }
1363
1364 if (
1365 1 == $performance_nag['status']
1366 || ( 2 == $performance_nag['status'] && $last_checked && $last_checked >= 24 )
1367 ) {
1368 ?>
1369 <div class="notice notice-warning">
1370 <p><?php printf(
1371 __("<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'),
1372 'https://github.com/cabrerahector/wordpress-popular-posts/wiki/7.-Performance'
1373 ) ?></p>
1374 <?php if ( current_user_can('manage_options') ) : ?>
1375 <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>
1376 <?php endif; ?>
1377 </div>
1378 <?php
1379 }
1380 }
1381 }
1382 }
1383 }
1384