PluginProbe
WebberZone Top 10 — Popular Posts / 4.3.4
WebberZone Top 10 — Popular Posts v4.3.4
4.5.1 4.5.0 4.4.3 4.4.2 4.4.1 4.4.0 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 trunk 1.0 1.0.1 1.1 1.2 1.3 1.4 1.4.1 1.5 1.5.1 1.5.2 1.5.3 1.6 1.6.1 All 117 releases
top-10 / includes / admin / class-dashboard-widgets.php

class-dashboard-widgets.php in WebberZone Top 10 — Popular Posts 4.3.4, at includes/admin/class-dashboard-widgets.php

430 lines 13.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Dashboard Widgets class.
4 *
5 * @package WebberZone\Top_Ten\Admin
6 */
7
8 namespace WebberZone\Top_Ten\Admin;
9
10 use WebberZone\Top_Ten\Util\Helpers;
11
12 if ( ! defined( 'WPINC' ) ) {
13 die;
14 }
15
16 /**
17 * Admin Columns Class.
18 *
19 * @since 3.3.0
20 */
21 class Dashboard_Widgets {
22
23 /**
24 * Constructor class.
25 *
26 * @since 3.3.0
27 */
28 public function __construct() {
29 add_filter( 'wp_dashboard_setup', array( $this, 'wp_dashboard_setup' ) );
30 add_filter( 'wp_network_dashboard_setup', array( $this, 'wp_network_dashboard_setup' ) );
31 add_filter( 'dashboard_glance_items', array( $this, 'dashboard_glance_items' ) );
32 add_action( 'admin_head-index.php', array( $this, 'dashboard_glance_styles' ) );
33 }
34
35 /**
36 * Add Top 10 views from the current hour to the At a Glance widget.
37 *
38 * @since 4.3.0
39 *
40 * @param string[] $items Array of extra At a Glance items.
41 * @return string[] Modified array of extra At a Glance items.
42 */
43 public function dashboard_glance_items( $items ) {
44 if ( ! current_user_can( 'manage_options' ) && ! \tptn_get_option( 'show_count_non_admins' ) ) {
45 return $items;
46 }
47
48 $current_hour = current_time( 'Y-m-d H' );
49 $hour_views = self::get_current_hour_views();
50 $day_views = self::get_views_for_period( current_time( 'Y-m-d 00' ), $current_hour );
51
52 $items[] = self::get_glance_item(
53 $hour_views,
54 /* translators: %s: Number of views in the last hour. */
55 _n( '%s view in the last hour', '%s views in the last hour', $hour_views, 'top-10' ),
56 admin_url( 'admin.php?page=tptn_dashboard' )
57 );
58
59 $items[] = self::get_glance_item(
60 $day_views,
61 /* translators: %s: Number of views in the past day. */
62 _n( '%s view in the past day', '%s views in the past day', $day_views, 'top-10' ),
63 wp_nonce_url(
64 add_query_arg(
65 array(
66 'page' => 'tptn_dashboard',
67 'post-date-filter-from' => current_time( 'd M Y' ),
68 'post-date-filter-to' => current_time( 'd M Y' ),
69 ),
70 admin_url( 'admin.php' )
71 ),
72 'tptn-dashboard'
73 )
74 );
75
76 return $items;
77 }
78
79 /**
80 * Add a better icon for Top 10 At a Glance items.
81 *
82 * @since 4.3.0
83 */
84 public function dashboard_glance_styles() {
85 ?>
86 <style>
87 #dashboard_right_now li a.tptn-glance-views:before {
88 content: "\f239";
89 content: "\f239" / "";
90 }
91 </style>
92 <?php
93 }
94
95 /**
96 * Get the number of views recorded in the current hour.
97 *
98 * Top 10 stores daily counts in hourly buckets, so this returns the current
99 * hour bucket rather than a rolling 60-minute window.
100 *
101 * @since 4.3.0
102 *
103 * @return int Number of views in the current hour.
104 */
105 public static function get_current_hour_views() {
106 return self::get_views_for_period( current_time( 'Y-m-d H' ), current_time( 'Y-m-d H' ) );
107 }
108
109 /**
110 * Get the number of views recorded in a period.
111 *
112 * @since 4.3.0
113 *
114 * @param string $from_hour Start hour in Y-m-d H format.
115 * @param string $to_hour End hour in Y-m-d H format.
116 * @return int Number of views in the period.
117 */
118 public static function get_views_for_period( $from_hour, $to_hour ) {
119 global $wpdb;
120
121 $table = $wpdb->base_prefix . 'top_ten_daily';
122 $sql = $wpdb->prepare(
123 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
124 "SELECT SUM(cntaccess) FROM {$table} WHERE dp_date >= %s AND dp_date <= %s AND blog_id = %d",
125 $from_hour,
126 $to_hour,
127 get_current_blog_id()
128 );
129 $views = $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
130
131 return (int) $views;
132 }
133
134 /**
135 * Build a Top 10 At a Glance item.
136 *
137 * @since 4.3.0
138 *
139 * @param int $views Views.
140 * @param string $label Label with a %s placeholder for the formatted count.
141 * @param string $url Link URL.
142 * @return string At a Glance item markup.
143 */
144 public static function get_glance_item( $views, $label, $url ) {
145 return sprintf(
146 '<a class="tptn-glance-views" href="%1$s">%2$s</a>',
147 esc_url( $url ),
148 esc_html( sprintf( $label, Helpers::number_format_i18n( $views ) ) )
149 );
150 }
151
152 /**
153 * Function to add the widgets to the Dashboard.
154 *
155 * @since 3.3.0
156 */
157 public static function wp_dashboard_setup() {
158
159 /**
160 * Filter whether to register the dashboard widgets.
161 *
162 * @since 3.3.0
163 *
164 * @param bool $dashboard_setup Whether to register the dashboard widgets.
165 */
166 $dashboard_setup = apply_filters( 'tptn_dashboard_setup', true );
167
168 if ( $dashboard_setup && ( current_user_can( 'manage_options' ) || \tptn_get_option( 'show_count_non_admins' ) ) ) {
169
170 // Add the overall popular posts widget.
171 wp_add_dashboard_widget(
172 'tptn_overall_dashboard',
173 __( 'Top 10 - Overall Popular Posts', 'top-10' ),
174 array( __CLASS__, 'popular_posts_widget' ),
175 array( __CLASS__, 'pop_display' )
176 );
177
178 // Add the daily popular posts widget.
179 wp_add_dashboard_widget(
180 'tptn_daily_dashboard',
181 /* translators: %s: Custom period label (e.g. Daily, Custom (7 days)). */
182 sprintf( __( 'Top 10 - %s Popular Posts', 'top-10' ), Helpers::get_daily_range_label( 1 ) ),
183 array( __CLASS__, 'popular_posts_widget_daily' ),
184 array( __CLASS__, 'pop_display' )
185 );
186
187 // Add the mini views overview widget.
188 wp_add_dashboard_widget(
189 'tptn_views_over_time_dashboard',
190 __( 'Top 10 Views Overview', 'top-10' ),
191 array( __CLASS__, 'views_over_time_widget' ),
192 );
193 }
194 }
195
196 /**
197 * Function to add the widgets to the Network Dashboard.
198 *
199 * @since 4.2.0
200 */
201 public static function wp_network_dashboard_setup() {
202
203 /**
204 * Filter whether to register the network dashboard widgets.
205 *
206 * @since 4.2.0
207 *
208 * @param bool $dashboard_setup Whether to register the network dashboard widgets.
209 */
210 $dashboard_setup = apply_filters( 'tptn_network_dashboard_setup', true );
211
212 if ( $dashboard_setup && current_user_can( 'manage_network' ) ) {
213
214 // Add the overall popular posts widget.
215 wp_add_dashboard_widget(
216 'tptn_network_overall_dashboard',
217 __( 'Top 10 - Network Popular Posts', 'top-10' ),
218 array( __CLASS__, 'network_popular_posts_widget' ),
219 array( __CLASS__, 'pop_display' )
220 );
221
222 // Add the daily popular posts widget.
223 wp_add_dashboard_widget(
224 'tptn_network_daily_dashboard',
225 /* translators: %s: Custom period label (e.g. Daily, Custom (7 days)). */
226 sprintf( __( 'Top 10 - Network %s Popular Posts', 'top-10' ), Helpers::get_daily_range_label( 1 ) ),
227 array( __CLASS__, 'network_popular_posts_widget_daily' ),
228 array( __CLASS__, 'pop_display' )
229 );
230
231 // Add the mini views overview widget to network dashboard.
232 wp_add_dashboard_widget(
233 'tptn_network_views_over_time_dashboard',
234 __( 'Top 10 Network Views Overview', 'top-10' ),
235 array( __CLASS__, 'views_over_time_widget' ),
236 );
237 }
238 }
239
240 /**
241 * Create the Dashboard Widget and content of the Popular pages
242 *
243 * @since 3.3.0
244 *
245 * @param bool $daily Switch for Custom Period or Overall popular posts.
246 * @param int $page Which page of the lists are on.
247 * @param int $limit Maximum number of posts per page.
248 * @param bool $widget Is this a WordPress widget.
249 * @param bool $network Whether to show network-wide posts.
250 * @return string Formatted list of popular posts
251 */
252 public static function pop_display( $daily = false, $page = 0, $limit = 0, $widget = true, $network = false ) {
253
254 if ( ! $limit ) {
255 $limit = \tptn_get_option( 'limit' );
256 }
257
258 $args = array();
259 $visits = 'total_count';
260 if ( $daily ) {
261 $args['orderby'] = 'daily_count';
262 $visits = 'daily_count';
263 }
264 $statistics_table = new Statistics_Table( $network );
265 $results = $statistics_table->get_popular_posts( $limit, $page + 1, $args );
266
267 $output = '<div id="tptn_popular_posts' . ( $daily ? '_daily' : '' ) . '">';
268
269 if ( $results ) {
270 $output .= '<ul>';
271 foreach ( $results as $result ) {
272 if ( ! absint( $result[ $visits ] ) ) {
273 continue;
274 }
275
276 // Handle network context differently.
277 if ( $network ) {
278 // Check if blog exists.
279 $blog_details = get_blog_details( $result['blog_id'] );
280 if ( ! $blog_details ) {
281 continue; // Skip if blog doesn't exist.
282 }
283
284 // Get post from specific blog.
285 $post = get_blog_post( $result['blog_id'], $result['ID'] );
286 if ( ! $post || 'publish' !== $post->post_status ) {
287 continue; // Skip if post doesn't exist or isn't published.
288 }
289
290 $output .= '<li><a href="' . get_blog_permalink( $result['blog_id'], $result['ID'] ) . '">' . esc_html( $post->post_title ) . '</a>';
291 $output .= ' (' . Helpers::number_format_i18n( $result[ $visits ] ) . ')';
292 $output .= ' <span class="tptn-blog-name">- ' . esc_html( $blog_details->blogname ) . '</span>';
293 $output .= '</li>';
294 } else {
295 // Single site context.
296 if ( ! get_post_status( $result['ID'] ) ) {
297 continue;
298 }
299 $output .= '<li><a href="' . get_permalink( $result['ID'] ) . '">' . get_the_title( $result['ID'] ) . '</a>';
300 $output .= ' (' . Helpers::number_format_i18n( $result[ $visits ] ) . ')';
301 $output .= '</li>';
302 }
303 }
304 $output .= '</ul>';
305 }
306
307 $output .= '<p style="text-align:center">';
308
309 if ( $daily ) {
310 if ( $network ) {
311 $output .= '<a href="' . network_admin_url( 'admin.php?page=tptn_network_pop_posts_page&orderby=daily_count&order=desc' ) . '">' . __( 'View all network daily popular posts', 'top-10' ) . '</a>';
312 } else {
313 $output .= '<a href="' . esc_url(
314 add_query_arg(
315 array(
316 'page' => 'tptn_popular_posts',
317 'orderby' => 'daily_count',
318 'order' => 'desc',
319 'post-date-filter-from' => current_time( 'd M Y' ),
320 'post-date-filter-to' => current_time( 'd M Y' ),
321 ),
322 admin_url( 'admin.php' )
323 )
324 ) . '">' . __( 'View all daily popular posts', 'top-10' ) . '</a>';
325 }
326 } elseif ( $network ) {
327 $output .= '<a href="' . network_admin_url( 'admin.php?page=tptn_network_pop_posts_page&orderby=total_count&order=desc' ) . '">' . __( 'View all network popular posts', 'top-10' ) . '</a>';
328 } else {
329 $output .= '<a href="' . admin_url( 'admin.php?page=tptn_popular_posts&orderby=total_count&order=desc' ) . '">' . __( 'View all popular posts', 'top-10' ) . '</a>';
330 }
331
332 $output .= '</p>';
333
334 $output .= '<p style="text-align:center;border-top: #000 1px solid">';
335
336 /* translators: 1: Top 10 page link. */
337 $output .= sprintf( __( 'Popular posts by <a href="%s" target="_blank">Top 10 plugin</a>', 'top-10' ), esc_url( 'https://webberzone.com/plugins/top-10/' ) );
338 $output .= '</p>';
339 $output .= '</div>';
340
341 /**
342 * Filters the dashboard widget output
343 *
344 * @since 3.3.0
345 *
346 * @param string $output Widget output
347 * @param bool $daily Is this a daily widget
348 * @param int $page Page number
349 * @param int $limit Limit of posts
350 * @param bool $widget Is this a widget
351 * @param bool $network Is this network-wide
352 */
353 return apply_filters( 'tptn_popular_posts_widget_output', $output, $daily, $page, $limit, $widget, $network );
354 }
355
356
357 /**
358 * Widget for Popular Posts.
359 *
360 * @since 3.3.0
361 */
362 public static function popular_posts_widget() {
363 echo self::pop_display( false ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
364 }
365
366
367 /**
368 * Widget for Custom Period Popular Posts.
369 *
370 * @since 3.3.0
371 */
372 public static function popular_posts_widget_daily() {
373 echo self::pop_display( true ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
374 }
375
376 /**
377 * Widget for Network Popular Posts.
378 *
379 * @since 4.2.0
380 */
381 public static function network_popular_posts_widget() {
382 echo self::pop_display( false, 0, 0, true, true ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
383 }
384
385 /**
386 * Widget for Network Custom Period Popular Posts.
387 *
388 * @since 4.2.0
389 */
390 public static function network_popular_posts_widget_daily() {
391 echo self::pop_display( true, 0, 0, true, true ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
392 }
393
394 /**
395 * Widget for Views Overview (mini chart).
396 *
397 * @since 4.2.0
398 */
399 public static function views_over_time_widget() {
400 global $tptn_freemius;
401
402 $output = '<div class="tptn-views-over-time-widget">';
403
404 if ( ! $tptn_freemius->is_paying() ) {
405 $output .= sprintf(
406 '<div class="tptn-views-over-time-chart-placeholder" style="height:150px;margin-bottom:15px;border:1px dashed #ccd0d4;background:#f8f9fa;display:flex;align-items:center;justify-content:center;color:#6c757d;font-style:italic;">%s</div>',
407 esc_html__( 'Upgrade to Top 10 Pro to see your views over time chart here.', 'top-10' )
408 );
409 $output .= sprintf(
410 '<p style="text-align:center;"><a class="button button-primary" href="%s">%s</a></p>',
411 esc_url( $tptn_freemius->get_upgrade_url() ),
412 esc_html__( 'Upgrade to Pro', 'top-10' )
413 );
414 }
415
416 $output .= '</div>';
417
418 /**
419 * Filters the views over time widget content.
420 *
421 * @since 4.2.0
422 *
423 * @param string $output The widget content.
424 */
425 $output = apply_filters( 'tptn_views_over_time_widget_content', $output );
426
427 echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
428 }
429 }
430