| @@ -17,8 +17,15 @@ | ||
| 17 | 17 | class SQLite_Object_Cache { |
| 18 | 18 | const CLEAN_EVENT_HOOK = 'sqlite_object_cache_clean'; |
| 19 | 19 | |
| 20 | 20 | /** |
| 21 | + * Local instance of SQLite_Object_Cache_Admin_API | |
| 22 | + * | |
| 23 | + * @var SQLite_Object_Cache_Admin_API|null | |
| 24 | + */ | |
| 25 | + public $admin; | |
| 26 | + | |
| 27 | + /** | |
| 21 | 28 | * Settings class object |
| 22 | 29 | * |
| 23 | 30 | * @var object |
| 24 | 31 | * @access public |
| @@ -113,9 +120,9 @@ | ||
| 113 | 120 | * |
| 114 | 121 | * @param string $file File constructor. |
| 115 | 122 | * @param string $version Plugin version. |
| 116 | 123 | */ |
| 117 | - public function __construct( $file = '', $version = '1.6.5' ) { | |
| 124 | + public function __construct( $file = '', $version = '1.6.0' ) { | |
| 118 | 125 | $this->_version = $version; |
| 119 | 126 | $this->_token = 'sqlite_object_cache'; |
| 120 | 127 | |
| 121 | 128 | // Load plugin environment variables. |
| @@ -127,26 +134,27 @@ | ||
| 127 | 134 | $this->dropinfiledest = trailingslashit( WP_CONTENT_DIR ) . 'object-cache.php'; |
| 128 | 135 | |
| 129 | 136 | $this->assets_url = esc_url( trailingslashit( plugins_url( '/assets/', $this->file ) ) ); |
| 130 | 137 | |
| 138 | + $this->script_suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; | |
| 139 | + | |
| 131 | 140 | register_activation_hook( $this->file, array( $this, 'on_activation' ) ); |
| 132 | 141 | register_deactivation_hook( $this->file, array( $this, 'on_deactivation' ) ); |
| 133 | 142 | |
| 134 | 143 | if ( is_admin() ) { |
| 135 | - /* Suppress backups of .sqlite files if possible. */ | |
| 144 | + // Load API for generic admin functions. | |
| 145 | + $this->admin = new SQLite_Object_Cache_Admin_API(); | |
| 146 | + // Suppress backups | |
| 136 | 147 | new SQLite_Backup_Exclusion(); |
| 137 | 148 | |
| 138 | - /* Health check */ | |
| 139 | - new SQLite_Object_Cache_Opcache(); | |
| 140 | - | |
| 141 | 149 | add_action( 'admin_notices', function () { |
| 142 | - $flushed = get_site_transient( 'sqlite-object-cache-flush-on-update' ); | |
| 143 | - if ( $flushed ) { | |
| 150 | + $purged = get_site_transient( 'sqlite-object-cache-flush-on-update' ); | |
| 151 | + if ( $purged ) { | |
| 144 | 152 | delete_site_transient( 'sqlite-object-cache-flush-on-update' ); |
| 145 | - $message = __( 'Flushed the SQLite Object Cache successfully after a software installation or upgrade.', 'sqlite-object-cache' ); | |
| 153 | + $message = esc_html( __( 'A software installation or upgrade operation flushed the SQLite Object Cache.', 'sqlite-object-cache' ) ) | |
| 146 | 154 | ?> |
| 147 | - <div class="notice notice-success sqlite-object-cache is-dismissible"> | |
| 148 | - <p><?php echo esc_html( $message ); ?></p> | |
| 155 | + <div class="notice notice-info sqlite-object-cache is-dismissible"> | |
| 156 | + <p><?php echo $message ?></p> | |
| 149 | 157 | </div> |
| 150 | 158 | <?php |
| 151 | 159 | } |
| 152 | 160 | } ); |
| @@ -163,36 +171,19 @@ | ||
| 163 | 171 | wp_cache_flush(); |
| 164 | 172 | }, 0 ); |
| 165 | 173 | |
| 166 | 174 | |
| 167 | - /* Handle cron cache cleanup, but only on main site. */ | |
| 175 | + /* handle cron cache cleanup */ | |
| 168 | 176 | add_action( self::CLEAN_EVENT_HOOK, array( $this, 'clean_job' ), 10, 0 ); |
| 169 | - $next_event = wp_next_scheduled( self::CLEAN_EVENT_HOOK ); | |
| 170 | - if ( false === $next_event && is_main_site() ) { | |
| 177 | + if ( ! wp_next_scheduled( self::CLEAN_EVENT_HOOK ) ) { | |
| 171 | 178 | wp_schedule_event( time() + HOUR_IN_SECONDS, 'hourly', self::CLEAN_EVENT_HOOK ); |
| 172 | - } else if (false !== $next_event && is_multisite() && ! is_main_site() ) { | |
| 173 | - wp_unschedule_event ( $next_event, self::CLEAN_EVENT_HOOK); | |
| 174 | 179 | } |
| 175 | - /* Handle probabilistic non-cron cleanup, one request in 2500. */ | |
| 176 | - /* We don't need cryptographic-grade random numbering here. */ | |
| 177 | - // phpcs:ignore WordPress.WP.AlternativeFunctions.rand_rand | |
| 178 | - if ( 1 === rand( 1, 2500 ) ) { | |
| 180 | + /* Handle probabilistic non-cron cleanup, one request in 2000. */ | |
| 181 | + if ( 1 === rand( 1, 2000 ) ) { | |
| 179 | 182 | add_action( 'shutdown', function () { |
| 180 | 183 | $this->clean_job( 1.25 ); |
| 181 | 184 | }, 999, 0 ); |
| 182 | 185 | } |
| 183 | - | |
| 184 | - /* Admin bar flush button - works on both frontend and backend. */ | |
| 185 | - $option = get_option( $this->_token . '_settings', array() ); | |
| 186 | - if ( array_key_exists ('adminbarflush', $option ) && 'on' === $option['adminbarflush'] ) { | |
| 187 | - add_action( 'init', array( $this, 'handle_admin_bar_flush' ) ); | |
| 188 | - add_action ( 'init', function() { | |
| 189 | - if ( ! ( is_multisite() && ! is_main_site() ) && current_user_can( 'manage_options') ) { | |
| 190 | - add_action( 'admin_bar_menu', array( $this, 'admin_bar_flush_button' ), 100 ); | |
| 191 | - add_action( 'admin_notices', array( $this, 'maybe_show_flush_notice' ) ); | |
| 192 | - } | |
| 193 | - }); | |
| 194 | - } | |
| 195 | 186 | } |
| 196 | 187 | |
| 197 | 188 | /** |
| 198 | 189 | * WP_Cron task to clean cache entries. |
| @@ -201,13 +192,8 @@ | ||
| 201 | 192 | * |
| 202 | 193 | * @return void |
| 203 | 194 | */ |
| 204 | 195 | public function clean_job( $grace_factor = 1.0 ) { |
| 205 | - $current_blogid = null; | |
| 206 | - if ( is_multisite() && ! is_main_site() ) { | |
| 207 | - $current_blogid = get_current_blog_id(); | |
| 208 | - switch_to_blog( get_main_site_id() ); | |
| 209 | - } | |
| 210 | 196 | $option = get_option( $this->_token . '_settings', array() ); |
| 211 | 197 | $target_size = empty ( $option['target_size'] ) ? 16 : $option['target_size']; |
| 212 | 198 | $target_size *= ( 1024 * 1024 ); |
| 213 | 199 | $threshold_size = (int) ( $target_size * $grace_factor ); |
| @@ -238,12 +224,8 @@ | ||
| 238 | 224 | } |
| 239 | 225 | |
| 240 | 226 | /* Delete the least-recently-updated items to get to the target size. */ |
| 241 | 227 | $wp_object_cache->sqlite_delete_old( $target_size, $current_size ); |
| 242 | - | |
| 243 | - if ( null !== $current_blogid ) { | |
| 244 | - switch_to_blog ( $current_blogid ); | |
| 245 | - } | |
| 246 | 228 | } |
| 247 | 229 | |
| 248 | 230 | /** |
| 249 | 231 | * Plugin activation hook |
| @@ -537,22 +519,21 @@ | ||
| 537 | 519 | try { |
| 538 | 520 | switch_to_blog( $site_id ); |
| 539 | 521 | $this->clear_blog_transients(); |
| 540 | 522 | } catch ( Exception $ex ) { |
| 541 | - /* Empty, intentionally. Don't crash clearing transients. */ | |
| 523 | + /* Avoid crashes on transient clearing */ | |
| 524 | + error_log( 'SQLite Object Cache problem clearing transients. Blog ' . $site_id . ':' . $ex->getMessage() ); | |
| 542 | 525 | } finally { |
| 543 | 526 | restore_current_blog(); |
| 544 | 527 | } |
| 545 | 528 | } |
| 546 | 529 | // Multisite stores site transients in the sitemeta table. |
| 547 | - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching | |
| 548 | 530 | $wpdb->query( |
| 549 | 531 | $wpdb->prepare( |
| 550 | - "DELETE FROM {$wpdb->sitemeta} WHERE a.meta_key LIKE %s", | |
| 532 | + "DELETE FROM {$wpdb->sitemeta} WHERE a.meta_key LIKE %s", | |
| 551 | 533 | $wpdb->esc_like( '_site_transient_' ) . '%' |
| 552 | 534 | ) |
| 553 | 535 | ); |
| 554 | - | |
| 555 | 536 | } |
| 556 | 537 | } |
| 557 | 538 | |
| 558 | 539 | /** |
| @@ -563,9 +544,8 @@ | ||
| 563 | 544 | * @return void |
| 564 | 545 | */ |
| 565 | 546 | private function clear_blog_transients( $tag = '_transient_') { |
| 566 | 547 | global $wpdb; |
| 567 | - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching | |
| 568 | 548 | $wpdb->query( |
| 569 | 549 | $wpdb->prepare( |
| 570 | 550 | "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", |
| 571 | 551 | $wpdb->esc_like( $tag ) . '%' |
| @@ -620,118 +600,7 @@ | ||
| 620 | 600 | update_option( $this->_token . '_settings', $option, true ); |
| 621 | 601 | } |
| 622 | 602 | |
| 623 | 603 | return $target_use_apcu; |
| 624 | - } | |
| 625 | - | |
| 626 | - /** | |
| 627 | - * Add a flush button to the admin bar. | |
| 628 | - * | |
| 629 | - * @param WP_Admin_Bar $wp_admin_bar The admin bar instance. | |
| 630 | - * | |
| 631 | - * @return void | |
| 632 | - */ | |
| 633 | - public function admin_bar_flush_button( $wp_admin_bar ) { | |
| 634 | - if ( ! is_admin_bar_showing() ) { | |
| 635 | - return; | |
| 636 | - } | |
| 637 | - | |
| 638 | - if ( ! current_user_can( 'manage_options' ) ) { | |
| 639 | - return; | |
| 640 | - } | |
| 641 | - | |
| 642 | - // Only show on main site for multisite installations. | |
| 643 | - if ( is_multisite() && ! is_main_site() ) { | |
| 644 | - return; | |
| 645 | - } | |
| 646 | - | |
| 647 | - $flush_url = add_query_arg( | |
| 648 | - array( 'sqlite_object_cache_action' => 'flush' ), | |
| 649 | - remove_query_arg( 'sqlite_object_cache_action' ) | |
| 650 | - ); | |
| 651 | - $nonced_url = wp_nonce_url( $flush_url, 'sqlite_object_cache_flush' ); | |
| 652 | - | |
| 653 | - $wp_admin_bar->add_node( | |
| 654 | - array( | |
| 655 | - 'id' => 'sqlite-object-cache-flush', | |
| 656 | - 'title' => __( 'Flush Object Cache', 'sqlite-object-cache' ), | |
| 657 | - 'href' => $nonced_url, | |
| 658 | - 'meta' => array( | |
| 659 | - 'title' => __( 'Delete all object cache entries now, including all transients.', 'sqlite-object-cache' ), | |
| 660 | - ), | |
| 661 | - ) | |
| 662 | - ); | |
| 663 | - } | |
| 664 | - | |
| 665 | - /** | |
| 666 | - * Handle the admin bar flush action. | |
| 667 | - * | |
| 668 | - * @return void | |
| 669 | - */ | |
| 670 | - public function handle_admin_bar_flush() { | |
| 671 | - if ( ! isset( $_GET['sqlite_object_cache_action'] ) ) { | |
| 672 | - return; | |
| 673 | - } | |
| 674 | - | |
| 675 | - $action = sanitize_key( wp_unslash( $_GET['sqlite_object_cache_action'] ) ); | |
| 676 | - | |
| 677 | - if ( 'flush' !== $action ) { | |
| 678 | - return; | |
| 679 | - } | |
| 680 | - | |
| 681 | - if ( ! current_user_can( 'manage_options' ) ) { | |
| 682 | - wp_die( esc_html__( 'You do not have permission to flush the object cache.', 'sqlite-object-cache' ) ); | |
| 683 | - } | |
| 684 | - | |
| 685 | - // Only allow flush on main site for multisite installations (matches button visibility). | |
| 686 | - if ( is_multisite() && ! is_main_site() ) { | |
| 687 | - wp_die( esc_html__( 'Cache flush is only available on the main site.', 'sqlite-object-cache' ) ); | |
| 688 | - } | |
| 689 | - | |
| 690 | - check_admin_referer( 'sqlite_object_cache_flush' ); | |
| 691 | - | |
| 692 | - wp_cache_flush(); | |
| 693 | - | |
| 694 | - // Use a user-specific transient so only the initiating user sees the flush notice (applies to both single-site and multisite). | |
| 695 | - $transient_key = 'sqlite_object_cache_flushed_' . get_current_user_id(); | |
| 696 | - set_transient( $transient_key, true, 30 ); | |
| 697 | - | |
| 698 | - $referer = wp_get_referer(); | |
| 699 | - if ( $referer ) { | |
| 700 | - $redirect_url = $referer; | |
| 701 | - } else { | |
| 702 | - $redirect_url = is_admin() ? admin_url() : home_url(); | |
| 703 | - } | |
| 704 | - // Remove action and nonce query parameters from URL. | |
| 705 | - $redirect_url = remove_query_arg( array( 'sqlite_object_cache_action', '_wpnonce' ), $redirect_url ); | |
| 706 | - | |
| 707 | - wp_safe_redirect( $redirect_url ); | |
| 708 | - exit; | |
| 709 | - } | |
| 710 | - | |
| 711 | - /** | |
| 712 | - * Check for flush transient and show notice if set. | |
| 713 | - * | |
| 714 | - * @return void | |
| 715 | - */ | |
| 716 | - public function maybe_show_flush_notice() { | |
| 717 | - $transient_key = 'sqlite_object_cache_flushed_' . get_current_user_id(); | |
| 718 | - if ( get_transient( $transient_key ) ) { | |
| 719 | - delete_transient( $transient_key ); | |
| 720 | - $this->show_flush_notice(); | |
| 721 | - } | |
| 722 | - } | |
| 723 | - | |
| 724 | - /** | |
| 725 | - * Display a notice when the object cache was flushed via admin bar. | |
| 726 | - * | |
| 727 | - * @return void | |
| 728 | - */ | |
| 729 | - public function show_flush_notice() { | |
| 730 | - ?> | |
| 731 | - <div class="notice notice-success sqlite-object-cache is-dismissible"> | |
| 732 | - <p><?php esc_html_e( 'SQLite Object Cache flushed successfully.', 'sqlite-object-cache' ); ?></p> | |
| 733 | - </div> | |
| 734 | - <?php | |
| 735 | 604 | } |
| 736 | 605 | |
| 737 | 606 | } |