| @@ -13,9 +13,9 @@ | ||
| 13 | 13 | die; |
| 14 | 14 | } |
| 15 | 15 | |
| 16 | 16 | /** |
| 17 | - * Admin Columns Class. | |
| 17 | + * Registers the Top 10 dashboard widgets and At a Glance items. | |
| 18 | 18 | * |
| 19 | 19 | * @since 3.3.0 |
| 20 | 20 | */ |
| 21 | 21 | class Dashboard_Widgets { |
| @@ -32,8 +32,18 @@ | ||
| 32 | 32 | add_action( 'admin_head-index.php', array( $this, 'dashboard_glance_styles' ) ); |
| 33 | 33 | } |
| 34 | 34 | |
| 35 | 35 | /** |
| 36 | + * Clear cached network dashboard widget output. | |
| 37 | + * | |
| 38 | + * @since 4.5.0 | |
| 39 | + */ | |
| 40 | + public static function clear_network_dashboard_cache() { | |
| 41 | + update_site_option( 'tptn_network_dashboard_cache_version', wp_generate_uuid4() ); | |
| 42 | + delete_site_transient( 'tptn_network_popular_posts_count' ); | |
| 43 | + } | |
| 44 | + | |
| 45 | + /** | |
| 36 | 46 | * Add Top 10 views from the current hour to the At a Glance widget. |
| 37 | 47 | * |
| 38 | 48 | * @since 4.3.0 |
| 39 | 49 | * |
| @@ -177,9 +187,10 @@ | ||
| 177 | 187 | |
| 178 | 188 | // Add the daily popular posts widget. |
| 179 | 189 | wp_add_dashboard_widget( |
| 180 | 190 | 'tptn_daily_dashboard', |
| 181 | - __( 'Top 10 - Daily Popular Posts', 'top-10' ), | |
| 191 | + /* translators: %s: Custom period label (e.g. Daily, Custom (7 days)). */ | |
| 192 | + sprintf( __( 'Top 10 - %s Popular Posts', 'top-10' ), Helpers::get_daily_range_label( 1 ) ), | |
| 182 | 193 | array( __CLASS__, 'popular_posts_widget_daily' ), |
| 183 | 194 | array( __CLASS__, 'pop_display' ) |
| 184 | 195 | ); |
| 185 | 196 | |
| @@ -220,9 +231,10 @@ | ||
| 220 | 231 | |
| 221 | 232 | // Add the daily popular posts widget. |
| 222 | 233 | wp_add_dashboard_widget( |
| 223 | 234 | 'tptn_network_daily_dashboard', |
| 224 | - __( 'Top 10 - Network Daily Popular Posts', 'top-10' ), | |
| 235 | + /* translators: %s: Custom period label (e.g. Daily, Custom (7 days)). */ | |
| 236 | + sprintf( __( 'Top 10 - Network %s Popular Posts', 'top-10' ), Helpers::get_daily_range_label( 1 ) ), | |
| 225 | 237 | array( __CLASS__, 'network_popular_posts_widget_daily' ), |
| 226 | 238 | array( __CLASS__, 'pop_display' ) |
| 227 | 239 | ); |
| 228 | 240 | |
| @@ -239,9 +251,9 @@ | ||
| 239 | 251 | * Create the Dashboard Widget and content of the Popular pages |
| 240 | 252 | * |
| 241 | 253 | * @since 3.3.0 |
| 242 | 254 | * |
| 243 | - * @param bool $daily Switch for Daily or Overall popular posts. | |
| 255 | + * @param bool $daily Switch for Custom Period or Overall popular posts. | |
| 244 | 256 | * @param int $page Which page of the lists are on. |
| 245 | 257 | * @param int $limit Maximum number of posts per page. |
| 246 | 258 | * @param bool $widget Is this a WordPress widget. |
| 247 | 259 | * @param bool $network Whether to show network-wide posts. |
| @@ -252,8 +264,42 @@ | ||
| 252 | 264 | if ( ! $limit ) { |
| 253 | 265 | $limit = \tptn_get_option( 'limit' ); |
| 254 | 266 | } |
| 255 | 267 | |
| 268 | + $cache_key = ''; | |
| 269 | + $cache_ttl = 0; | |
| 270 | + if ( $network && $widget ) { | |
| 271 | + /** | |
| 272 | + * Filters how long the network dashboard widget output is cached. | |
| 273 | + * | |
| 274 | + * @since 4.5.0 | |
| 275 | + * | |
| 276 | + * @param int $cache_ttl Cache lifetime in seconds. Default 15 minutes. | |
| 277 | + */ | |
| 278 | + $cache_ttl = max( 0, (int) apply_filters( 'tptn_network_dashboard_cache_ttl', 15 * MINUTE_IN_SECONDS ) ); | |
| 279 | + $cache_key = 'tptn_network_dashboard_' . md5( | |
| 280 | + (string) wp_json_encode( | |
| 281 | + array( | |
| 282 | + 'version' => get_site_option( 'tptn_network_dashboard_cache_version', '1' ), | |
| 283 | + 'daily' => (bool) $daily, | |
| 284 | + 'orderby' => $daily ? 'daily_count' : 'total_count', | |
| 285 | + 'order' => 'DESC', | |
| 286 | + 'from_date' => current_time( 'Y-m-d' ), | |
| 287 | + 'to_date' => current_time( 'Y-m-d' ), | |
| 288 | + 'page' => (int) $page, | |
| 289 | + 'limit' => (int) $limit, | |
| 290 | + ) | |
| 291 | + ) | |
| 292 | + ); | |
| 293 | + | |
| 294 | + if ( $cache_ttl > 0 ) { | |
| 295 | + $cached = get_site_transient( $cache_key ); | |
| 296 | + if ( false !== $cached ) { | |
| 297 | + return $cached; | |
| 298 | + } | |
| 299 | + } | |
| 300 | + } | |
| 301 | + | |
| 256 | 302 | $args = array(); |
| 257 | 303 | $visits = 'total_count'; |
| 258 | 304 | if ( $daily ) { |
| 259 | 305 | $args['orderby'] = 'daily_count'; |
| @@ -270,8 +316,12 @@ | ||
| 270 | 316 | if ( ! absint( $result[ $visits ] ) ) { |
| 271 | 317 | continue; |
| 272 | 318 | } |
| 273 | 319 | |
| 320 | + $context_key = class_exists( 'WebberZone\\Top_Ten\\Pro\\Sitewide_Database' ) && \WebberZone\Top_Ten\Pro\Sitewide_Database::is_available() | |
| 321 | + ? \WebberZone\Top_Ten\Pro\Sitewide_Database::get_context_key( $result['ID'], $result['blog_id'] ?? null ) | |
| 322 | + : ''; | |
| 323 | + | |
| 274 | 324 | // Handle network context differently. |
| 275 | 325 | if ( $network ) { |
| 276 | 326 | // Check if blog exists. |
| 277 | 327 | $blog_details = get_blog_details( $result['blog_id'] ); |
| @@ -278,24 +328,34 @@ | ||
| 278 | 328 | if ( ! $blog_details ) { |
| 279 | 329 | continue; // Skip if blog doesn't exist. |
| 280 | 330 | } |
| 281 | 331 | |
| 282 | - // Get post from specific blog. | |
| 283 | - $post = get_blog_post( $result['blog_id'], $result['ID'] ); | |
| 284 | - if ( ! $post || 'publish' !== $post->post_status ) { | |
| 285 | - continue; // Skip if post doesn't exist or isn't published. | |
| 332 | + if ( '' !== $context_key ) { | |
| 333 | + $label = \WebberZone\Top_Ten\Pro\Sitewide_Database::get_context_label( $context_key ); | |
| 334 | + $output .= '<li>' . esc_html( $label ) . ' <span class="tptn-sitewide-label">(' . esc_html__( 'site-wide', 'top-10' ) . ')</span>'; | |
| 335 | + } else { | |
| 336 | + // Get post from specific blog. | |
| 337 | + $post = get_blog_post( $result['blog_id'], $result['ID'] ); | |
| 338 | + if ( ! $post || 'publish' !== $post->post_status ) { | |
| 339 | + continue; // Skip if post doesn't exist or isn't published. | |
| 340 | + } | |
| 341 | + | |
| 342 | + $output .= '<li><a href="' . get_blog_permalink( $result['blog_id'], $result['ID'] ) . '">' . esc_html( $post->post_title ) . '</a>'; | |
| 286 | 343 | } |
| 287 | - | |
| 288 | - $output .= '<li><a href="' . get_blog_permalink( $result['blog_id'], $result['ID'] ) . '">' . esc_html( $post->post_title ) . '</a>'; | |
| 289 | 344 | $output .= ' (' . Helpers::number_format_i18n( $result[ $visits ] ) . ')'; |
| 290 | 345 | $output .= ' <span class="tptn-blog-name">- ' . esc_html( $blog_details->blogname ) . '</span>'; |
| 291 | 346 | $output .= '</li>'; |
| 292 | 347 | } else { |
| 293 | 348 | // Single site context. |
| 294 | - if ( ! get_post_status( $result['ID'] ) ) { | |
| 295 | - continue; | |
| 349 | + if ( '' !== $context_key ) { | |
| 350 | + $label = \WebberZone\Top_Ten\Pro\Sitewide_Database::get_context_label( $context_key ); | |
| 351 | + $output .= '<li>' . esc_html( $label ) . ' <span class="tptn-sitewide-label">(' . esc_html__( 'site-wide', 'top-10' ) . ')</span>'; | |
| 352 | + } else { | |
| 353 | + if ( ! get_post_status( $result['ID'] ) ) { | |
| 354 | + continue; | |
| 355 | + } | |
| 356 | + $output .= '<li><a href="' . get_permalink( $result['ID'] ) . '">' . get_the_title( $result['ID'] ) . '</a>'; | |
| 296 | 357 | } |
| 297 | - $output .= '<li><a href="' . get_permalink( $result['ID'] ) . '">' . get_the_title( $result['ID'] ) . '</a>'; | |
| 298 | 358 | $output .= ' (' . Helpers::number_format_i18n( $result[ $visits ] ) . ')'; |
| 299 | 359 | $output .= '</li>'; |
| 300 | 360 | } |
| 301 | 361 | } |
| @@ -347,9 +407,15 @@ | ||
| 347 | 407 | * @param int $limit Limit of posts |
| 348 | 408 | * @param bool $widget Is this a widget |
| 349 | 409 | * @param bool $network Is this network-wide |
| 350 | 410 | */ |
| 351 | - return apply_filters( 'tptn_popular_posts_widget_output', $output, $daily, $page, $limit, $widget, $network ); | |
| 411 | + $output = apply_filters( 'tptn_popular_posts_widget_output', $output, $daily, $page, $limit, $widget, $network ); | |
| 412 | + | |
| 413 | + if ( $network && $widget && $cache_ttl > 0 ) { | |
| 414 | + set_site_transient( $cache_key, $output, $cache_ttl ); | |
| 415 | + } | |
| 416 | + | |
| 417 | + return $output; | |
| 352 | 418 | } |
| 353 | 419 | |
| 354 | 420 | |
| 355 | 421 | /** |
| @@ -362,9 +428,9 @@ | ||
| 362 | 428 | } |
| 363 | 429 | |
| 364 | 430 | |
| 365 | 431 | /** |
| 366 | - * Widget for Daily Popular Posts. | |
| 432 | + * Widget for Custom Period Popular Posts. | |
| 367 | 433 | * |
| 368 | 434 | * @since 3.3.0 |
| 369 | 435 | */ |
| 370 | 436 | public static function popular_posts_widget_daily() { |
| @@ -380,9 +446,9 @@ | ||
| 380 | 446 | echo self::pop_display( false, 0, 0, true, true ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped |
| 381 | 447 | } |
| 382 | 448 | |
| 383 | 449 | /** |
| 384 | - * Widget for Network Daily Popular Posts. | |
| 450 | + * Widget for Network Custom Period Popular Posts. | |
| 385 | 451 | * |
| 386 | 452 | * @since 4.2.0 |
| 387 | 453 | */ |
| 388 | 454 | public static function network_popular_posts_widget_daily() { |