init_modules();
$this->init_hooks();
}
/**
* Initialize modules.
*/
private function init_modules() {
// Core modules (always loaded).
$this->modules['conflict_detector'] = new WPSCO_Conflict_Detector();
$this->modules['cache_manager'] = new WPSCO_Cache_Manager();
$this->modules['cache_purger'] = new WPSCO_Cache_Purger();
$this->modules['security'] = new WPSCO_Security();
$this->modules['settings'] = new WPSCO_Settings();
// Frontend optimization modules (loaded conditionally).
if ( ! is_admin() && ! wpsco_get_setting( 'emergency_disable', false ) ) {
if ( wpsco_get_setting( 'page_cache_enabled', false ) ) {
$this->modules['page_cache'] = new WPSCO_Page_Cache();
}
if ( wpsco_get_setting( 'css_minify', false ) || wpsco_get_setting( 'css_combine', false ) || wpsco_get_setting( 'css_critical', false ) || wpsco_get_setting( 'css_async', false ) ) {
$this->modules['css_optimizer'] = new WPSCO_CSS_Optimizer();
}
if ( wpsco_get_setting( 'js_minify', false ) || wpsco_get_setting( 'js_defer', false ) || wpsco_get_setting( 'js_delay', false ) ) {
$this->modules['js_optimizer'] = new WPSCO_JS_Optimizer();
}
$this->modules['html_optimizer'] = new WPSCO_HTML_Optimizer();
if ( wpsco_get_setting( 'lazy_load_images', false ) || wpsco_get_setting( 'add_missing_dimensions', false ) || wpsco_get_setting( 'lcp_image_preload', false ) ) {
$this->modules['image_optimizer'] = new WPSCO_Image_Optimizer();
}
if ( wpsco_get_setting( 'font_display_swap', false ) || wpsco_get_setting( 'google_fonts_local', false ) || wpsco_get_setting( 'preload_fonts', false ) ) {
$this->modules['font_optimizer'] = new WPSCO_Font_Optimizer();
}
}
// WordPress optimizations (always check even on admin).
$this->modules['wordpress_optimizer'] = new WPSCO_WordPress_Optimizer();
// Integrations.
if ( wpsco_is_woocommerce_active() ) {
$this->modules['woocommerce'] = new WPSCO_WooCommerce();
}
if ( wpsco_is_elementor_active() ) {
$this->modules['elementor'] = new WPSCO_Elementor();
}
if ( wpsco_get_setting( 'cloudflare_enabled', false ) ) {
$this->modules['cloudflare'] = new WPSCO_Cloudflare();
}
if ( wpsco_get_setting( 'cdn_enabled', false ) ) {
$this->modules['cdn'] = new WPSCO_CDN();
}
// Admin.
if ( is_admin() ) {
$this->modules['admin'] = new WPSCO_Admin();
}
// Diagnostics (loaded on demand via admin).
// Database cleaner (loaded on demand via admin).
}
/**
* Initialize hooks.
*/
private function init_hooks() {
// Admin bar.
add_action( 'admin_bar_menu', array( $this, 'admin_bar_menu' ), 100 );
// Auto cache purge hooks.
add_action( 'save_post', array( $this, 'on_content_change' ), 10, 2 );
add_action( 'delete_post', array( $this, 'on_content_change' ), 10 );
add_action( 'wp_update_nav_menu', array( $this, 'on_menu_update' ) );
add_action( 'update_option_sidebars_widgets', array( $this, 'on_widget_update' ) );
add_action( 'switch_theme', array( $this, 'on_theme_change' ) );
add_action( 'customize_save_after', array( $this, 'on_theme_change' ) );
add_action( 'activated_plugin', array( $this, 'on_plugin_change' ) );
add_action( 'deactivated_plugin', array( $this, 'on_plugin_change' ) );
// Cron handlers.
add_action( 'wpsco_cache_cleanup', array( $this, 'cron_cache_cleanup' ) );
add_action( 'wpsco_expired_transients_cleanup', array( $this, 'cron_expired_transients' ) );
add_action( 'wpsco_cache_warming', array( $this, 'cron_cache_warming' ) );
// Plugin action links.
add_filter( 'plugin_action_links_' . WPSCO_PLUGIN_BASENAME, array( $this, 'plugin_action_links' ) );
}
/**
* Get a module instance.
*
* @param string $name Module name.
* @return object|null
*/
public function get_module( $name ) {
return isset( $this->modules[ $name ] ) ? $this->modules[ $name ] : null;
}
/**
* Admin bar menu.
*
* @param WP_Admin_Bar $admin_bar Admin bar instance.
*/
public function admin_bar_menu( $admin_bar ) {
if ( ! wpsco_current_user_can() ) {
return;
}
$admin_bar->add_node( array(
'id' => 'wpsco',
'title' => ' ' . esc_html__( 'WP Speed', 'speednest' ),
'href' => admin_url( 'admin.php?page=wpsco-dashboard' ),
) );
$items = array(
'clear-cache' => array(
'title' => __( 'Clear Cache', 'speednest' ),
'href' => wp_nonce_url( admin_url( 'admin.php?page=wpsco-cache&action=clear_all' ), 'wpsco_cache_action' ),
),
'clear-all' => array(
'title' => __( 'Purge Everything Possible', 'speednest' ),
'href' => wp_nonce_url( admin_url( 'admin.php?page=wpsco-cache&action=purge_everything' ), 'wpsco_cache_action' ),
),
'clear-css' => array(
'title' => __( 'Clear CSS Cache', 'speednest' ),
'href' => wp_nonce_url( admin_url( 'admin.php?page=wpsco-cache&action=clear_css' ), 'wpsco_cache_action' ),
),
'clear-js' => array(
'title' => __( 'Clear JS Cache', 'speednest' ),
'href' => wp_nonce_url( admin_url( 'admin.php?page=wpsco-cache&action=clear_js' ), 'wpsco_cache_action' ),
),
'clear-html' => array(
'title' => __( 'Clear HTML Cache', 'speednest' ),
'href' => wp_nonce_url( admin_url( 'admin.php?page=wpsco-cache&action=clear_html' ), 'wpsco_cache_action' ),
),
'clear-object' => array(
'title' => __( 'Clear Object Cache', 'speednest' ),
'href' => wp_nonce_url( admin_url( 'admin.php?page=wpsco-cache&action=clear_object' ), 'wpsco_cache_action' ),
),
'reset-opcache' => array(
'title' => __( 'Reset OPcache', 'speednest' ),
'href' => wp_nonce_url( admin_url( 'admin.php?page=wpsco-cache&action=reset_opcache' ), 'wpsco_cache_action' ),
),
'diagnostics' => array(
'title' => __( 'Run Diagnostics', 'speednest' ),
'href' => admin_url( 'admin.php?page=wpsco-diagnostics' ),
),
);
foreach ( $items as $id => $item ) {
$admin_bar->add_node( array(
'parent' => 'wpsco',
'id' => 'wpsco-' . $id,
'title' => esc_html( $item['title'] ),
'href' => esc_url( $item['href'] ),
) );
}
}
/**
* Handle content changes — targeted cache purge.
*
* @param int $post_id Post ID.
* @param WP_Post $post Post object (optional).
*/
public function on_content_change( $post_id, $post = null ) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
if ( wp_is_post_revision( $post_id ) ) {
return;
}
$purger = $this->get_module( 'cache_purger' );
if ( ! $purger ) {
return;
}
$post_obj = $post ? $post : get_post( $post_id );
$post_type = $post_obj ? $post_obj->post_type : '';
// If a template/header/footer is updated, clear all page HTML & CSS caches.
$is_template = in_array( $post_type, array(
'elementor_library',
'elementor-hf',
'shopengine-template',
'wp_template',
'wp_template_part',
'custom_css',
), true );
if ( $is_template ) {
$purger->purge_html_cache();
$purger->purge_css_cache();
wpsco_increment_cache_version();
wpsco_log( sprintf( 'Global template updated (ID %d, type %s) — purged all HTML & CSS cache.', $post_id, $post_type ) );
return;
}
// Purge specific post URL.
$url = get_permalink( $post_id );
if ( $url ) {
$purger->purge_url( $url );
}
// Purge homepage.
$purger->purge_url( home_url( '/' ) );
// Purge category/archive pages.
if ( $post_obj ) {
$taxonomies = get_object_taxonomies( $post_obj->post_type );
foreach ( $taxonomies as $taxonomy ) {
$terms = get_the_terms( $post_id, $taxonomy );
if ( $terms && ! is_wp_error( $terms ) ) {
foreach ( $terms as $term ) {
$term_link = get_term_link( $term );
if ( ! is_wp_error( $term_link ) ) {
$purger->purge_url( $term_link );
}
}
}
}
}
// Purge CSS/JS cache if settings changed.
wpsco_log( sprintf( 'Cache purged for post ID %d', $post_id ) );
}
/**
* Handle menu updates.
*/
public function on_menu_update() {
$purger = $this->get_module( 'cache_purger' );
if ( $purger ) {
$purger->purge_all_html();
}
wpsco_log( 'Cache purged: menu update' );
}
/**
* Handle widget updates.
*/
public function on_widget_update() {
$purger = $this->get_module( 'cache_purger' );
if ( $purger ) {
$purger->purge_all_html();
}
wpsco_log( 'Cache purged: widget update' );
}
/**
* Handle theme changes.
*/
public function on_theme_change() {
$purger = $this->get_module( 'cache_purger' );
if ( $purger ) {
$purger->purge_all();
}
wpsco_increment_cache_version();
wpsco_log( 'Full cache purge: theme change' );
}
/**
* Handle plugin changes.
*/
public function on_plugin_change() {
$purger = $this->get_module( 'cache_purger' );
if ( $purger ) {
$purger->purge_all();
}
// Re-detect conflicts.
$detector = $this->get_module( 'conflict_detector' );
if ( $detector ) {
$detector->detect_all();
}
wpsco_log( 'Full cache purge: plugin change' );
}
/**
* Cron: cache cleanup.
*/
public function cron_cache_cleanup() {
$purger = $this->get_module( 'cache_purger' );
if ( $purger ) {
$purger->cleanup_expired_html_cache();
}
}
/**
* Cron: expired transients.
*/
public function cron_expired_transients() {
if ( function_exists( 'delete_expired_transients' ) ) {
delete_expired_transients( true );
return;
}
global $wpdb;
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Fallback direct query required for bulk deletion of expired transients.
$wpdb->query(
$wpdb->prepare(
"DELETE a, b FROM {$wpdb->options} a
INNER JOIN {$wpdb->options} b ON b.option_name = CONCAT('_transient_timeout_', SUBSTRING(a.option_name, 12))
WHERE a.option_name LIKE %s AND b.option_value < %d",
$wpdb->esc_like( '_transient_' ) . '%',
time()
)
);
}
/**
* Cron: cache warming.
*/
public function cron_cache_warming() {
if ( ! wpsco_get_setting( 'cache_warming_enabled', false ) ) {
return;
}
$urls = $this->get_cache_warming_urls();
$concurrency = (int) wpsco_get_setting( 'cache_warming_concurrency', 2 );
$concurrency = max( 1, min( 5, $concurrency ) );
$batch_size = $concurrency;
$batches = array_chunk( $urls, $batch_size );
foreach ( $batches as $batch ) {
foreach ( $batch as $url ) {
wp_remote_get( $url, array(
'timeout' => 10,
'blocking' => false,
'user-agent' => 'WPSpeedCacheOptimizer/CacheWarmer',
) );
}
// Small delay between batches.
usleep( 500000 );
}
}
/**
* Get URLs for cache warming.
*
* @return array
*/
private function get_cache_warming_urls() {
$urls = array( home_url( '/' ) );
// Get recent pages.
$pages = get_posts( array(
'post_type' => 'page',
'post_status' => 'publish',
'posts_per_page' => 20,
'fields' => 'ids',
) );
foreach ( $pages as $page_id ) {
$urls[] = get_permalink( $page_id );
}
// Get recent posts.
$posts = get_posts( array(
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => 20,
'fields' => 'ids',
) );
foreach ( $posts as $post_id ) {
$urls[] = get_permalink( $post_id );
}
// WooCommerce products.
if ( wpsco_is_woocommerce_active() ) {
$products = get_posts( array(
'post_type' => 'product',
'post_status' => 'publish',
'posts_per_page' => 30,
'fields' => 'ids',
) );
foreach ( $products as $product_id ) {
$urls[] = get_permalink( $product_id );
}
}
return array_unique( $urls );
}
/**
* Plugin action links.
*
* @param array $links Existing links.
* @return array
*/
public function plugin_action_links( $links ) {
$custom = array(
'' . esc_html__( 'Dashboard', 'speednest' ) . '',
'' . esc_html__( 'Settings', 'speednest' ) . '',
);
return array_merge( $custom, $links );
}
}