added maple performance caching plugin
This commit is contained in:
parent
c44c49a836
commit
e468202f95
12 changed files with 4501 additions and 0 deletions
228
native/wordpress/maple-performance-wp/README.md
Normal file
228
native/wordpress/maple-performance-wp/README.md
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
# Maple Performance WP 🍁
|
||||
|
||||
A lightweight, privacy-focused WordPress performance plugin. No external dependencies, no tracking, no upsells.
|
||||
|
||||
**Built by [Maple Open Tech](https://mapleopentech.ca) for Canadian businesses who care about data sovereignty.**
|
||||
|
||||
## Features
|
||||
|
||||
### Page Caching
|
||||
- Static HTML file generation
|
||||
- Gzip pre-compression
|
||||
- Brotli pre-compression (if PHP extension installed)
|
||||
- Smart cache invalidation on content updates
|
||||
- Automatic exclusion for logged-in users
|
||||
|
||||
### Asset Optimization
|
||||
- **HTML**: Minification, comment removal
|
||||
- **CSS**: Minification, aggregation, optional async loading
|
||||
- **JavaScript**: Minification, aggregation (disabled by default for safety)
|
||||
- **Google Fonts**: Combine multiple requests, add display:swap, optional deferred loading
|
||||
|
||||
### Lazy Loading
|
||||
- Native `loading="lazy"` for images
|
||||
- Native `loading="lazy"` for iframes
|
||||
- Exclude LCP/hero images from lazy loading
|
||||
|
||||
### Extra Optimizations
|
||||
- Remove WordPress emoji scripts
|
||||
- Remove query strings from static resources
|
||||
- DNS prefetch hints
|
||||
- Preconnect to third-party domains
|
||||
|
||||
### Smart Plugin Compatibility
|
||||
|
||||
Maple Performance automatically detects these plugins and applies safe exclusions:
|
||||
|
||||
| Plugin | Automatic Protections |
|
||||
|--------|----------------------|
|
||||
| **WooCommerce** | Cart/checkout/account pages excluded from cache, WooCommerce cookies bypass cache, cart fragments and checkout scripts protected |
|
||||
| **LearnDash** | Lesson/topic/quiz pages excluded, progress tracking AJAX protected, quiz scripts excluded from aggregation |
|
||||
| **WPForms** | Form validation scripts excluded, AJAX submissions protected |
|
||||
| **Wordfence** | Security scripts excluded, login pages not cached, firewall bypass cookies respected |
|
||||
| **Gravity Forms** | Form scripts excluded from aggregation |
|
||||
| **Contact Form 7** | Form scripts excluded from aggregation |
|
||||
| **Elementor** | Builder scripts excluded from aggregation |
|
||||
|
||||
## Site Modes
|
||||
|
||||
Select your site type and Maple Performance automatically applies safe defaults:
|
||||
|
||||
| Site Type | JS Aggregate | CSS Defer | Expected Score |
|
||||
|-----------|--------------|-----------|----------------|
|
||||
| Brochure/Blog | ✅ Available | ✅ Available | 80-95 |
|
||||
| WooCommerce | ❌ Disabled | ❌ Disabled | 70-85 |
|
||||
| LearnDash | ❌ Disabled | ❌ Disabled | 70-85 |
|
||||
| WooCommerce + LearnDash | ❌ Disabled | ❌ Disabled | 65-80 |
|
||||
|
||||
## Installation
|
||||
|
||||
### From GitHub
|
||||
1. Download or clone this repository
|
||||
2. Upload the `maple-performance-wp` folder to `/wp-content/plugins/`
|
||||
3. Activate through WordPress admin
|
||||
4. Go to Settings > Maple Performance
|
||||
5. Select your site type and configure
|
||||
|
||||
### From WordPress Admin
|
||||
1. Go to Plugins > Add New
|
||||
2. Upload the zip file
|
||||
3. Activate and configure
|
||||
|
||||
## Configuration
|
||||
|
||||
### Brochure Sites (Maximum Performance)
|
||||
|
||||
```
|
||||
Site Mode: Brochure
|
||||
Cache: Enabled
|
||||
HTML Minify: On
|
||||
CSS Minify: On
|
||||
CSS Aggregate: On
|
||||
CSS Defer: On (optional)
|
||||
JS Minify: On
|
||||
JS Aggregate: On
|
||||
Lazy Load: On
|
||||
```
|
||||
|
||||
### WooCommerce Sites (Safe Defaults)
|
||||
|
||||
```
|
||||
Site Mode: WooCommerce
|
||||
Cache: Enabled (cart/checkout excluded)
|
||||
HTML Minify: On
|
||||
CSS Minify: On
|
||||
CSS Aggregate: On
|
||||
CSS Defer: Off
|
||||
JS Minify: On
|
||||
JS Aggregate: Off (protects checkout)
|
||||
Lazy Load: On
|
||||
```
|
||||
|
||||
### LearnDash Sites (Safe Defaults)
|
||||
|
||||
```
|
||||
Site Mode: LearnDash
|
||||
Cache: Enabled (lessons excluded for logged-in)
|
||||
HTML Minify: On
|
||||
CSS Minify: On
|
||||
CSS Aggregate: On
|
||||
CSS Defer: Off
|
||||
JS Minify: On
|
||||
JS Aggregate: Off (protects tracking)
|
||||
Lazy Load: On
|
||||
```
|
||||
|
||||
## Privacy
|
||||
|
||||
This plugin:
|
||||
- ✅ Processes everything locally on your server
|
||||
- ✅ Makes zero external API calls
|
||||
- ✅ Sends no data to third parties
|
||||
- ✅ Has no tracking or analytics
|
||||
- ✅ Has no premium upsells or nags
|
||||
- ✅ Is fully open source (GPL-2.0)
|
||||
|
||||
## Privacy & GDPR Compliance
|
||||
|
||||
Maple Performance WP is designed with privacy as a core principle:
|
||||
|
||||
| Aspect | Status |
|
||||
|--------|--------|
|
||||
| Personal data collection | ❌ None |
|
||||
| Cookies set by plugin | ❌ None |
|
||||
| External connections | ❌ None |
|
||||
| Tracking/analytics | ❌ None |
|
||||
| Third-party services | ❌ None |
|
||||
|
||||
### What the plugin stores
|
||||
|
||||
- **Page cache**: Static HTML copies of publicly-visible pages (same content any visitor sees)
|
||||
- **Asset cache**: Aggregated/minified CSS and JS files
|
||||
- **Settings**: Your plugin configuration (no personal data)
|
||||
|
||||
### Cookie behavior
|
||||
|
||||
The plugin **reads** existing cookies (WordPress login, WooCommerce cart) only to determine whether to serve cached content. It never sets, modifies, or transmits cookie data.
|
||||
|
||||
### Privacy Policy
|
||||
|
||||
The plugin automatically registers suggested privacy policy text with WordPress (Settings → Privacy) that you can include in your site's privacy policy.
|
||||
|
||||
## Requirements
|
||||
|
||||
- WordPress 5.9+
|
||||
- PHP 7.4+
|
||||
- Write access to `wp-content/cache/`
|
||||
|
||||
## Cache Location
|
||||
|
||||
Cached files are stored in:
|
||||
```
|
||||
wp-content/cache/maple-performance/
|
||||
├── assets/ # Aggregated CSS/JS files
|
||||
├── {domain}/ # Page cache by domain
|
||||
│ └── {path}/ # Page cache by URL path
|
||||
│ ├── https-index.html
|
||||
│ ├── https-index.html.gz
|
||||
│ └── https-index.html.br
|
||||
```
|
||||
|
||||
## Hooks & Filters
|
||||
|
||||
### Actions
|
||||
|
||||
```php
|
||||
// Clear all cache
|
||||
do_action( 'maple_performance_clear_cache' );
|
||||
|
||||
// After cache is cleared
|
||||
do_action( 'maple_performance_cache_cleared' );
|
||||
```
|
||||
|
||||
### Filters
|
||||
|
||||
```php
|
||||
// Modify settings programmatically
|
||||
add_filter( 'maple_performance_settings', function( $settings ) {
|
||||
$settings['cache_enabled'] = false;
|
||||
return $settings;
|
||||
});
|
||||
|
||||
// Exclude specific URLs from caching
|
||||
add_filter( 'maple_performance_exclude_url', function( $exclude, $url ) {
|
||||
if ( strpos( $url, '/members/' ) !== false ) {
|
||||
return true;
|
||||
}
|
||||
return $exclude;
|
||||
}, 10, 2 );
|
||||
```
|
||||
|
||||
## Comparison
|
||||
|
||||
| Feature | Maple Performance | Autoptimize | Cache Enabler | WP Rocket |
|
||||
|---------|------------------|-------------|---------------|-----------|
|
||||
| Page Cache | ✅ | ❌ | ✅ | ✅ |
|
||||
| CSS/JS Minify | ✅ | ✅ | ❌ | ✅ |
|
||||
| CSS/JS Aggregate | ✅ | ✅ | ❌ | ✅ |
|
||||
| Google Fonts Optimization | ✅ | ✅ | ❌ | ✅ |
|
||||
| External Dependencies | ❌ None | ⚠️ Optional | ⚠️ CDN promo | ✅ Required |
|
||||
| Tracking | ❌ None | ⚠️ News feed | ❌ None | ✅ License |
|
||||
| Upsells | ❌ None | ✅ Yes | ✅ Yes | N/A (paid) |
|
||||
| WooCommerce Safe Mode | ✅ | ❌ | ❌ | ✅ |
|
||||
| LearnDash Safe Mode | ✅ | ❌ | ❌ | ❌ |
|
||||
| Price | Free | Free | Free | $59/year |
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Please feel free to submit issues and pull requests.
|
||||
|
||||
## License
|
||||
|
||||
GPL-2.0-or-later - see [LICENSE](LICENSE) for details.
|
||||
|
||||
## Credits
|
||||
|
||||
Built by [Maple Open Tech](https://mapleopentech.ca) 🍁
|
||||
|
||||
Inspired by the core concepts from Autoptimize and Cache Enabler, rebuilt from scratch with privacy and safety in mind.
|
||||
11
native/wordpress/maple-performance-wp/css/index.php
Normal file
11
native/wordpress/maple-performance-wp/css/index.php
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
/**
|
||||
* Silence is golden.
|
||||
*
|
||||
* @package MaplePerformance
|
||||
*/
|
||||
|
||||
// Prevent direct access
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
837
native/wordpress/maple-performance-wp/inc/class-maple-admin.php
Normal file
837
native/wordpress/maple-performance-wp/inc/class-maple-admin.php
Normal file
|
|
@ -0,0 +1,837 @@
|
|||
<?php
|
||||
/**
|
||||
* Admin Settings Class
|
||||
*
|
||||
* Handles plugin settings page and admin functionality.
|
||||
*
|
||||
* @package MaplePerformance
|
||||
*/
|
||||
|
||||
// Prevent direct access
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin class
|
||||
*/
|
||||
class Maple_Performance_Admin {
|
||||
|
||||
/**
|
||||
* Single instance
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Get instance
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( null === self::$instance ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
private function __construct() {
|
||||
$this->init_hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize hooks
|
||||
*/
|
||||
private function init_hooks() {
|
||||
// Add admin menu
|
||||
add_action( 'admin_menu', array( $this, 'add_menu' ) );
|
||||
|
||||
// Register settings
|
||||
add_action( 'admin_init', array( $this, 'register_settings' ) );
|
||||
|
||||
// Admin bar cache clear button
|
||||
add_action( 'admin_bar_menu', array( $this, 'add_admin_bar_button' ), 100 );
|
||||
|
||||
// Handle cache clear action
|
||||
add_action( 'admin_init', array( $this, 'handle_cache_clear' ) );
|
||||
|
||||
// Admin notices
|
||||
add_action( 'admin_notices', array( $this, 'admin_notices' ) );
|
||||
|
||||
// Admin styles
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'admin_styles' ) );
|
||||
|
||||
// Plugin action links
|
||||
add_filter( 'plugin_action_links_' . plugin_basename( MAPLE_PERF_FILE ), array( $this, 'action_links' ) );
|
||||
|
||||
// Privacy policy
|
||||
add_action( 'admin_init', array( $this, 'add_privacy_policy_content' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add privacy policy content
|
||||
*/
|
||||
public function add_privacy_policy_content() {
|
||||
if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$content = sprintf(
|
||||
'<h2>%s</h2><p>%s</p><h3>%s</h3><p>%s</p><h3>%s</h3><p>%s</p><h3>%s</h3><p>%s</p>',
|
||||
__( 'Maple Performance WP', 'maple-performance' ),
|
||||
__( 'This site uses the Maple Performance WP plugin to improve page load times through caching and asset optimization.', 'maple-performance' ),
|
||||
__( 'What personal data we collect and why', 'maple-performance' ),
|
||||
__( 'Maple Performance WP does not collect, store, or process any personal data. The plugin caches publicly-visible page content to improve performance. By default, pages are not cached for logged-in users, ensuring that no user-specific content is stored in the cache.', 'maple-performance' ),
|
||||
__( 'Cookies', 'maple-performance' ),
|
||||
__( 'Maple Performance WP does not set any cookies. The plugin may read existing cookies (such as WordPress login cookies or WooCommerce cart cookies) solely to determine whether to serve a cached page or bypass the cache for dynamic content. No cookie data is stored or transmitted.', 'maple-performance' ),
|
||||
__( 'Third-party services', 'maple-performance' ),
|
||||
__( 'Maple Performance WP does not connect to any external services or transmit any data to third parties. All caching and optimization is performed locally on your web server.', 'maple-performance' )
|
||||
);
|
||||
|
||||
wp_add_privacy_policy_content(
|
||||
'Maple Performance WP',
|
||||
wp_kses_post( $content )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add admin menu
|
||||
*/
|
||||
public function add_menu() {
|
||||
add_options_page(
|
||||
__( 'Maple Performance', 'maple-performance' ),
|
||||
__( 'Maple Performance', 'maple-performance' ),
|
||||
'manage_options',
|
||||
'maple-performance',
|
||||
array( $this, 'settings_page' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register settings
|
||||
*/
|
||||
public function register_settings() {
|
||||
register_setting(
|
||||
'maple_performance_settings',
|
||||
'maple_performance_settings',
|
||||
array( $this, 'sanitize_settings' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize settings
|
||||
*/
|
||||
public function sanitize_settings( $input ) {
|
||||
$sanitized = array();
|
||||
|
||||
// Site mode
|
||||
$sanitized['site_mode'] = sanitize_text_field( $input['site_mode'] ?? 'brochure' );
|
||||
|
||||
// Google Fonts mode
|
||||
$valid_font_modes = array( 'leave', 'remove', 'combine', 'defer' );
|
||||
$sanitized['google_fonts'] = in_array( $input['google_fonts'] ?? 'defer', $valid_font_modes )
|
||||
? $input['google_fonts']
|
||||
: 'defer';
|
||||
|
||||
// Plugin compatibility
|
||||
$sanitized['compat_auto_detect'] = ! empty( $input['compat_auto_detect'] );
|
||||
|
||||
// Manual plugin selection
|
||||
$valid_compat_plugins = array( 'woocommerce', 'learndash', 'wordfence', 'wpforms', 'gutenberg_fse' );
|
||||
$sanitized['compat_plugins'] = array();
|
||||
if ( ! empty( $input['compat_plugins'] ) && is_array( $input['compat_plugins'] ) ) {
|
||||
foreach ( $input['compat_plugins'] as $plugin ) {
|
||||
if ( in_array( $plugin, $valid_compat_plugins ) ) {
|
||||
$sanitized['compat_plugins'][] = $plugin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Boolean settings
|
||||
$booleans = array(
|
||||
'cache_enabled', 'cache_logged_in', 'cache_gzip', 'cache_brotli',
|
||||
'html_minify', 'html_remove_comments',
|
||||
'css_minify', 'css_aggregate', 'css_inline_aggregate', 'css_defer',
|
||||
'js_minify', 'js_aggregate', 'js_defer', 'js_exclude_jquery',
|
||||
'remove_emojis', 'remove_query_strings', 'dns_prefetch',
|
||||
'lazyload_images', 'lazyload_iframes',
|
||||
'local_font_display',
|
||||
);
|
||||
|
||||
foreach ( $booleans as $key ) {
|
||||
$sanitized[ $key ] = ! empty( $input[ $key ] );
|
||||
}
|
||||
|
||||
// Integer settings
|
||||
$sanitized['cache_expiry'] = absint( $input['cache_expiry'] ?? 0 );
|
||||
|
||||
// Array settings (textarea, one per line)
|
||||
$arrays = array(
|
||||
'exclude_paths', 'exclude_cookies', 'exclude_js', 'exclude_css',
|
||||
'preconnect_domains', 'lazyload_exclude', 'preload_fonts',
|
||||
);
|
||||
|
||||
foreach ( $arrays as $key ) {
|
||||
$value = $input[ $key ] ?? '';
|
||||
if ( is_string( $value ) ) {
|
||||
$lines = explode( "\n", $value );
|
||||
$sanitized[ $key ] = array_filter( array_map( function( $line ) {
|
||||
// Sanitize each line - remove potentially dangerous characters
|
||||
$line = trim( $line );
|
||||
$line = str_replace( array( "\0", "\r" ), '', $line );
|
||||
// For URLs/paths, use esc_url_raw for domains, sanitize_text_field for others
|
||||
if ( strpos( $line, 'http' ) === 0 || strpos( $line, '//' ) === 0 ) {
|
||||
return esc_url_raw( $line );
|
||||
}
|
||||
return sanitize_text_field( $line );
|
||||
}, $lines ) );
|
||||
} else {
|
||||
$sanitized[ $key ] = array();
|
||||
}
|
||||
}
|
||||
|
||||
// Clear cache when settings change
|
||||
maple_performance()->clear_cache();
|
||||
|
||||
return $sanitized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add admin bar button
|
||||
*/
|
||||
public function add_admin_bar_button( $wp_admin_bar ) {
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$wp_admin_bar->add_node( array(
|
||||
'id' => 'maple-performance',
|
||||
'title' => '<span class="ab-icon dashicons dashicons-performance" style="font-family: dashicons; font-size: 20px; padding-top: 4px;"></span>' . __( 'Maple Cache', 'maple-performance' ),
|
||||
'href' => '#',
|
||||
) );
|
||||
|
||||
$wp_admin_bar->add_node( array(
|
||||
'parent' => 'maple-performance',
|
||||
'id' => 'maple-clear-cache',
|
||||
'title' => __( 'Clear All Cache', 'maple-performance' ),
|
||||
'href' => wp_nonce_url( admin_url( 'admin.php?action=maple_clear_cache' ), 'maple_clear_cache' ),
|
||||
) );
|
||||
|
||||
$wp_admin_bar->add_node( array(
|
||||
'parent' => 'maple-performance',
|
||||
'id' => 'maple-settings',
|
||||
'title' => __( 'Settings', 'maple-performance' ),
|
||||
'href' => admin_url( 'options-general.php?page=maple-performance' ),
|
||||
) );
|
||||
|
||||
// Show cache stats - use transient to avoid filesystem scan on every page load
|
||||
$stats = get_transient( 'maple_perf_cache_stats' );
|
||||
if ( false === $stats ) {
|
||||
// Only calculate if not cached, with a 5-minute expiry
|
||||
$stats = array(
|
||||
'count' => Maple_Performance_Cache::get_cache_count(),
|
||||
'size' => Maple_Performance_Cache::get_cache_size(),
|
||||
);
|
||||
set_transient( 'maple_perf_cache_stats', $stats, 5 * MINUTE_IN_SECONDS );
|
||||
}
|
||||
|
||||
$wp_admin_bar->add_node( array(
|
||||
'parent' => 'maple-performance',
|
||||
'id' => 'maple-cache-stats',
|
||||
'title' => sprintf( __( 'Cache: %d pages (%s)', 'maple-performance' ), $stats['count'], size_format( $stats['size'] ) ),
|
||||
'href' => admin_url( 'options-general.php?page=maple-performance' ),
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle cache clear action
|
||||
*/
|
||||
public function handle_cache_clear() {
|
||||
if ( ! isset( $_GET['action'] ) || $_GET['action'] !== 'maple_clear_cache' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_die( __( 'Unauthorized', 'maple-performance' ) );
|
||||
}
|
||||
|
||||
if ( ! wp_verify_nonce( $_GET['_wpnonce'] ?? '', 'maple_clear_cache' ) ) {
|
||||
wp_die( __( 'Invalid nonce', 'maple-performance' ) );
|
||||
}
|
||||
|
||||
maple_performance()->clear_cache();
|
||||
|
||||
// Redirect back with notice
|
||||
$redirect = remove_query_arg( array( 'action', '_wpnonce' ), wp_get_referer() );
|
||||
$redirect = add_query_arg( 'maple_cache_cleared', '1', $redirect );
|
||||
|
||||
wp_safe_redirect( $redirect );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin notices
|
||||
*/
|
||||
public function admin_notices() {
|
||||
// Show activation conflict notice (only once, immediately after activation)
|
||||
$activation_conflicts = get_transient( 'maple_perf_activation_conflict' );
|
||||
if ( false !== $activation_conflicts && is_array( $activation_conflicts ) ) {
|
||||
delete_transient( 'maple_perf_activation_conflict' );
|
||||
|
||||
echo '<div class="notice notice-error">';
|
||||
echo '<p><strong>' . esc_html__( '⚠️ Maple Performance WP - Important!', 'maple-performance' ) . '</strong></p>';
|
||||
echo '<p>' . sprintf(
|
||||
esc_html__( 'Another caching plugin is already active: %s', 'maple-performance' ),
|
||||
'<strong>' . esc_html( implode( ', ', $activation_conflicts ) ) . '</strong>'
|
||||
) . '</p>';
|
||||
echo '<p>' . esc_html__( 'Running multiple caching plugins can cause site errors, blank pages, or performance issues.', 'maple-performance' ) . '</p>';
|
||||
echo '<p>';
|
||||
echo '<a href="' . esc_url( admin_url( 'plugins.php' ) ) . '" class="button button-primary">' . esc_html__( 'Choose which plugin to keep', 'maple-performance' ) . '</a> ';
|
||||
echo '<a href="' . esc_url( admin_url( 'options-general.php?page=maple-performance' ) ) . '" class="button">' . esc_html__( 'Go to Settings', 'maple-performance' ) . '</a>';
|
||||
echo '</p>';
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only display check
|
||||
if ( isset( $_GET['maple_cache_cleared'] ) ) {
|
||||
echo '<div class="notice notice-success is-dismissible">';
|
||||
echo '<p>' . esc_html__( 'Maple Performance: Cache cleared successfully.', 'maple-performance' ) . '</p>';
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
// Check if settings were saved
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only display check
|
||||
$page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
|
||||
if ( isset( $_GET['settings-updated'] ) && $page === 'maple-performance' ) {
|
||||
echo '<div class="notice notice-success is-dismissible">';
|
||||
echo '<p>' . esc_html__( 'Maple Performance: Settings saved and cache cleared.', 'maple-performance' ) . '</p>';
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin styles
|
||||
*/
|
||||
public function admin_styles( $hook ) {
|
||||
if ( $hook !== 'settings_page_maple-performance' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_add_inline_style( 'common', '
|
||||
.maple-settings { max-width: 900px; }
|
||||
.maple-settings h2 { border-bottom: 1px solid #ccc; padding-bottom: 10px; margin-top: 30px; }
|
||||
.maple-settings h2:first-of-type { margin-top: 10px; }
|
||||
.maple-settings table { margin-bottom: 20px; }
|
||||
.maple-settings .description { color: #666; font-style: italic; }
|
||||
.maple-settings textarea { width: 100%; max-width: 400px; }
|
||||
.maple-settings .site-mode-card {
|
||||
border: 2px solid #ddd;
|
||||
padding: 15px;
|
||||
margin: 10px 0;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.maple-settings .site-mode-card:hover { border-color: #2271b1; }
|
||||
.maple-settings .site-mode-card.selected { border-color: #2271b1; background: #f0f7fc; }
|
||||
.maple-settings .site-mode-card h4 { margin: 0 0 5px; }
|
||||
.maple-settings .warning { color: #d63638; }
|
||||
.maple-settings .safe { color: #00a32a; }
|
||||
.maple-cache-stats {
|
||||
background: #f0f0f1;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.maple-cache-stats strong { font-size: 1.2em; }
|
||||
.maple-detected-plugins {
|
||||
background: #f9f9f9;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
padding: 15px 20px;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
.maple-detected-plugins h3 { margin-top: 0; }
|
||||
.maple-detected-plugins table { margin-top: 15px; }
|
||||
.maple-detected-plugins ul li { font-size: 13px; color: #555; }
|
||||
' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin action links
|
||||
*/
|
||||
public function action_links( $links ) {
|
||||
$settings_link = '<a href="' . admin_url( 'options-general.php?page=maple-performance' ) . '">' . __( 'Settings', 'maple-performance' ) . '</a>';
|
||||
$clear_link = '<a href="' . wp_nonce_url( admin_url( 'admin.php?action=maple_clear_cache' ), 'maple_clear_cache' ) . '">' . __( 'Clear Cache', 'maple-performance' ) . '</a>';
|
||||
|
||||
array_unshift( $links, $settings_link, $clear_link );
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Settings page
|
||||
*/
|
||||
public function settings_page() {
|
||||
$settings = maple_performance()->settings;
|
||||
|
||||
// Get cache stats
|
||||
$cache_count = Maple_Performance_Cache::get_cache_count();
|
||||
$cache_size = Maple_Performance_Cache::get_cache_size();
|
||||
?>
|
||||
<div class="wrap maple-settings">
|
||||
<h1><?php _e( 'Maple Performance WP', 'maple-performance' ); ?></h1>
|
||||
|
||||
<p><?php _e( 'A lightweight, privacy-focused performance plugin. No external dependencies, no tracking, no upsells.', 'maple-performance' ); ?></p>
|
||||
|
||||
<div class="maple-cache-stats">
|
||||
<strong><?php _e( 'Cache Status:', 'maple-performance' ); ?></strong>
|
||||
<?php printf( __( '%d cached pages (%s)', 'maple-performance' ), $cache_count, size_format( $cache_size ) ); ?>
|
||||
|
||||
<a href="<?php echo wp_nonce_url( admin_url( 'admin.php?action=maple_clear_cache' ), 'maple_clear_cache' ); ?>" class="button button-secondary">
|
||||
<?php _e( 'Clear All Cache', 'maple-performance' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
// Get compat class for detection info
|
||||
$compat = class_exists( 'Maple_Performance_Compat' ) ? Maple_Performance_Compat::get_instance() : null;
|
||||
$detected_plugins = $compat ? $compat->get_detected() : array();
|
||||
?>
|
||||
|
||||
<form method="post" action="options.php">
|
||||
<?php settings_fields( 'maple_performance_settings' ); ?>
|
||||
|
||||
<h2><?php _e( 'Plugin Compatibility', 'maple-performance' ); ?></h2>
|
||||
<p class="description"><?php _e( 'Configure compatibility rules for common plugins. These rules protect critical functionality like checkout, form submissions, and course tracking.', 'maple-performance' ); ?></p>
|
||||
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Detection Mode', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" name="maple_performance_settings[compat_auto_detect]" value="1" <?php checked( $settings['compat_auto_detect'] ); ?> id="compat_auto_detect">
|
||||
<?php _e( 'Auto-detect installed plugins', 'maple-performance' ); ?>
|
||||
</label>
|
||||
<p class="description">
|
||||
<?php _e( 'When enabled, Maple Performance will attempt to detect plugins automatically. This can be fragile if plugins change their file structure. <strong>Manual selection below is recommended for reliability.</strong>', 'maple-performance' ); ?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="manual_compat_row">
|
||||
<th scope="row"><?php _e( 'Enable Compatibility For', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<fieldset>
|
||||
<label style="display: block; margin-bottom: 12px;">
|
||||
<input type="checkbox" name="maple_performance_settings[compat_plugins][]" value="woocommerce" <?php checked( in_array( 'woocommerce', $settings['compat_plugins'] ?? array() ) ); ?>>
|
||||
<strong>WooCommerce</strong>
|
||||
<?php if ( ! empty( $detected_plugins['woocommerce'] ) ) : ?>
|
||||
<span class="safe" style="margin-left: 5px;">✓ Detected</span>
|
||||
<?php endif; ?>
|
||||
<br>
|
||||
<span class="description" style="margin-left: 24px;">Excludes cart, checkout, account pages from cache. Protects payment gateway scripts. Bypasses cache when cart has items.</span>
|
||||
</label>
|
||||
|
||||
<label style="display: block; margin-bottom: 12px;">
|
||||
<input type="checkbox" name="maple_performance_settings[compat_plugins][]" value="learndash" <?php checked( in_array( 'learndash', $settings['compat_plugins'] ?? array() ) ); ?>>
|
||||
<strong>LearnDash</strong>
|
||||
<?php if ( ! empty( $detected_plugins['learndash'] ) ) : ?>
|
||||
<span class="safe" style="margin-left: 5px;">✓ Detected</span>
|
||||
<?php endif; ?>
|
||||
<br>
|
||||
<span class="description" style="margin-left: 24px;">Excludes lesson, topic, quiz pages from cache. Protects progress tracking and quiz submission scripts.</span>
|
||||
</label>
|
||||
|
||||
<label style="display: block; margin-bottom: 12px;">
|
||||
<input type="checkbox" name="maple_performance_settings[compat_plugins][]" value="wpforms" <?php checked( in_array( 'wpforms', $settings['compat_plugins'] ?? array() ) ); ?>>
|
||||
<strong>WPForms</strong>
|
||||
<?php if ( ! empty( $detected_plugins['wpforms'] ) ) : ?>
|
||||
<span class="safe" style="margin-left: 5px;">✓ Detected</span>
|
||||
<?php endif; ?>
|
||||
<br>
|
||||
<span class="description" style="margin-left: 24px;">Protects form validation and submission scripts. Ensures AJAX form submissions work correctly.</span>
|
||||
</label>
|
||||
|
||||
<label style="display: block; margin-bottom: 12px;">
|
||||
<input type="checkbox" name="maple_performance_settings[compat_plugins][]" value="wordfence" <?php checked( in_array( 'wordfence', $settings['compat_plugins'] ?? array() ) ); ?>>
|
||||
<strong>Wordfence</strong>
|
||||
<?php if ( ! empty( $detected_plugins['wordfence'] ) ) : ?>
|
||||
<span class="safe" style="margin-left: 5px;">✓ Detected</span>
|
||||
<?php endif; ?>
|
||||
<br>
|
||||
<span class="description" style="margin-left: 24px;">Excludes login pages from cache. Respects firewall bypass cookies. Protects security scripts.</span>
|
||||
</label>
|
||||
|
||||
<label style="display: block; margin-bottom: 12px;">
|
||||
<input type="checkbox" name="maple_performance_settings[compat_plugins][]" value="gutenberg_fse" <?php checked( in_array( 'gutenberg_fse', $settings['compat_plugins'] ?? array() ) ); ?>>
|
||||
<strong>Gutenberg / Block Themes (FSE)</strong>
|
||||
<?php if ( ! empty( $detected_plugins['gutenberg_fse'] ) ) : ?>
|
||||
<span class="safe" style="margin-left: 5px;">✓ Detected</span>
|
||||
<?php endif; ?>
|
||||
<br>
|
||||
<span class="description" style="margin-left: 24px;">Protects global styles and block CSS. Safe optimization for Full Site Editing themes (Twenty Twenty-Two, etc.).</span>
|
||||
</label>
|
||||
</fieldset>
|
||||
<p class="description" style="margin-top: 10px;">
|
||||
<?php _e( '<strong>Tip:</strong> Select plugins you have installed even if not detected. Detection can miss plugins due to naming changes between versions.', 'maple-performance' ); ?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
var autoDetect = document.getElementById('compat_auto_detect');
|
||||
var manualRow = document.getElementById('manual_compat_row');
|
||||
|
||||
function toggleManual() {
|
||||
if (autoDetect.checked) {
|
||||
manualRow.style.opacity = '0.5';
|
||||
manualRow.querySelectorAll('input').forEach(function(el) {
|
||||
el.disabled = true;
|
||||
});
|
||||
} else {
|
||||
manualRow.style.opacity = '1';
|
||||
manualRow.querySelectorAll('input').forEach(function(el) {
|
||||
el.disabled = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
autoDetect.addEventListener('change', toggleManual);
|
||||
toggleManual();
|
||||
})();
|
||||
</script>
|
||||
|
||||
<h2><?php _e( 'Site Mode', 'maple-performance' ); ?></h2>
|
||||
<p class="description"><?php _e( 'Select your site type to apply safe default settings. This affects which optimizations are enabled.', 'maple-performance' ); ?></p>
|
||||
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Site Type', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<select name="maple_performance_settings[site_mode]" id="site_mode">
|
||||
<option value="brochure" <?php selected( $settings['site_mode'], 'brochure' ); ?>>
|
||||
<?php _e( 'Brochure / Blog (No ecommerce or LMS)', 'maple-performance' ); ?>
|
||||
</option>
|
||||
<option value="woocommerce" <?php selected( $settings['site_mode'], 'woocommerce' ); ?>>
|
||||
<?php _e( 'WooCommerce Store', 'maple-performance' ); ?>
|
||||
</option>
|
||||
<option value="learndash" <?php selected( $settings['site_mode'], 'learndash' ); ?>>
|
||||
<?php _e( 'LearnDash LMS', 'maple-performance' ); ?>
|
||||
</option>
|
||||
<option value="woo_learndash" <?php selected( $settings['site_mode'], 'woo_learndash' ); ?>>
|
||||
<?php _e( 'WooCommerce + LearnDash', 'maple-performance' ); ?>
|
||||
</option>
|
||||
</select>
|
||||
<p class="description">
|
||||
<?php _e( '<strong>Brochure:</strong> Full optimization enabled. <strong>WooCommerce/LearnDash:</strong> Conservative settings to protect checkout and lesson tracking.', 'maple-performance' ); ?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2><?php esc_html_e( 'Page Caching', 'maple-performance' ); ?></h2>
|
||||
|
||||
<?php
|
||||
// Check for caching conflicts
|
||||
$compat = Maple_Performance_Compat::get_instance();
|
||||
if ( method_exists( $compat, 'get_caching_conflicts' ) ) {
|
||||
$caching_conflicts = $compat->get_caching_conflicts();
|
||||
if ( ! empty( $caching_conflicts ) ) {
|
||||
echo '<div class="notice notice-warning inline" style="margin: 10px 0;">';
|
||||
echo '<p><strong>' . esc_html__( '⚠️ Another caching plugin detected:', 'maple-performance' ) . '</strong> ';
|
||||
echo esc_html( implode( ', ', $caching_conflicts ) ) . '</p>';
|
||||
echo '<p>' . esc_html__( 'Consider disabling Page Cache below and using only the CSS/JS/HTML optimizations to avoid conflicts.', 'maple-performance' ) . '</p>';
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e( 'Enable Page Cache', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" name="maple_performance_settings[cache_enabled]" value="1" <?php checked( $settings['cache_enabled'] ); ?>>
|
||||
<?php esc_html_e( 'Create static HTML files for faster delivery', 'maple-performance' ); ?>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Cache Expiry', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<input type="number" name="maple_performance_settings[cache_expiry]" value="<?php echo esc_attr( $settings['cache_expiry'] ); ?>" min="0" step="1" class="small-text">
|
||||
<?php _e( 'hours (0 = never expires, cleared on content updates)', 'maple-performance' ); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Pre-compression', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" name="maple_performance_settings[cache_gzip]" value="1" <?php checked( $settings['cache_gzip'] ); ?>>
|
||||
<?php _e( 'Create Gzip compressed versions', 'maple-performance' ); ?>
|
||||
</label>
|
||||
<br>
|
||||
<label>
|
||||
<input type="checkbox" name="maple_performance_settings[cache_brotli]" value="1" <?php checked( $settings['cache_brotli'] ); ?> <?php disabled( ! function_exists( 'brotli_compress' ) ); ?>>
|
||||
<?php _e( 'Create Brotli compressed versions', 'maple-performance' ); ?>
|
||||
<?php if ( ! function_exists( 'brotli_compress' ) ) : ?>
|
||||
<span class="description">(<?php _e( 'PHP Brotli extension not installed', 'maple-performance' ); ?>)</span>
|
||||
<?php endif; ?>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2><?php _e( 'HTML Optimization', 'maple-performance' ); ?></h2>
|
||||
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Minify HTML', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" name="maple_performance_settings[html_minify]" value="1" <?php checked( $settings['html_minify'] ); ?>>
|
||||
<?php _e( 'Remove unnecessary whitespace from HTML', 'maple-performance' ); ?>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Remove Comments', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" name="maple_performance_settings[html_remove_comments]" value="1" <?php checked( $settings['html_remove_comments'] ); ?>>
|
||||
<?php _e( 'Remove HTML comments (except IE conditionals)', 'maple-performance' ); ?>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2><?php _e( 'CSS Optimization', 'maple-performance' ); ?></h2>
|
||||
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Minify CSS', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" name="maple_performance_settings[css_minify]" value="1" <?php checked( $settings['css_minify'] ); ?>>
|
||||
<?php _e( 'Remove whitespace and comments from CSS', 'maple-performance' ); ?>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Aggregate CSS', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" name="maple_performance_settings[css_aggregate]" value="1" <?php checked( $settings['css_aggregate'] ); ?>>
|
||||
<?php _e( 'Combine CSS files into one', 'maple-performance' ); ?>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Defer CSS', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" name="maple_performance_settings[css_defer]" value="1" <?php checked( $settings['css_defer'] ); ?>>
|
||||
<?php _e( 'Load CSS asynchronously (may cause flash of unstyled content)', 'maple-performance' ); ?>
|
||||
</label>
|
||||
<p class="description warning"><?php _e( '⚠️ Not recommended for WooCommerce/LearnDash sites', 'maple-performance' ); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Exclude CSS', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<textarea name="maple_performance_settings[exclude_css]" rows="4" placeholder="handle-name another-handle"><?php echo esc_textarea( implode( "\n", $settings['exclude_css'] ) ); ?></textarea>
|
||||
<p class="description"><?php _e( 'CSS handles to exclude from optimization (one per line)', 'maple-performance' ); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2><?php _e( 'JavaScript Optimization', 'maple-performance' ); ?></h2>
|
||||
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Minify JavaScript', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" name="maple_performance_settings[js_minify]" value="1" <?php checked( $settings['js_minify'] ); ?>>
|
||||
<?php _e( 'Remove whitespace and comments from JavaScript', 'maple-performance' ); ?>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Aggregate JavaScript', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" name="maple_performance_settings[js_aggregate]" value="1" <?php checked( $settings['js_aggregate'] ); ?>>
|
||||
<?php _e( 'Combine JavaScript files into one', 'maple-performance' ); ?>
|
||||
</label>
|
||||
<p class="description warning"><?php _e( '⚠️ Can break WooCommerce checkout and LearnDash tracking. Test thoroughly!', 'maple-performance' ); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Exclude jQuery', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" name="maple_performance_settings[js_exclude_jquery]" value="1" <?php checked( $settings['js_exclude_jquery'] ); ?>>
|
||||
<?php _e( 'Keep jQuery loading separately (recommended)', 'maple-performance' ); ?>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Exclude JavaScript', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<textarea name="maple_performance_settings[exclude_js]" rows="4" placeholder="handle-name woocommerce learndash"><?php echo esc_textarea( implode( "\n", $settings['exclude_js'] ) ); ?></textarea>
|
||||
<p class="description"><?php _e( 'JavaScript handles/strings to exclude from optimization (one per line)', 'maple-performance' ); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2><?php _e( 'Lazy Loading', 'maple-performance' ); ?></h2>
|
||||
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Lazy Load Images', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" name="maple_performance_settings[lazyload_images]" value="1" <?php checked( $settings['lazyload_images'] ); ?>>
|
||||
<?php _e( 'Add loading="lazy" to images', 'maple-performance' ); ?>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Lazy Load Iframes', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" name="maple_performance_settings[lazyload_iframes]" value="1" <?php checked( $settings['lazyload_iframes'] ); ?>>
|
||||
<?php _e( 'Add loading="lazy" to iframes (YouTube, maps, etc.)', 'maple-performance' ); ?>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Exclude from Lazy Load', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<textarea name="maple_performance_settings[lazyload_exclude]" rows="4" placeholder="wp-image-12345 hero-image logo"><?php echo esc_textarea( implode( "\n", $settings['lazyload_exclude'] ) ); ?></textarea>
|
||||
<p class="description"><?php _e( 'Image class names or strings to exclude from lazy loading (one per line). Exclude your LCP/hero image.', 'maple-performance' ); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2><?php _e( 'Extra Optimizations', 'maple-performance' ); ?></h2>
|
||||
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Google Fonts', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<select name="maple_performance_settings[google_fonts]" id="google_fonts">
|
||||
<option value="leave" <?php selected( $settings['google_fonts'], 'leave' ); ?>>
|
||||
<?php _e( 'Leave as is', 'maple-performance' ); ?>
|
||||
</option>
|
||||
<option value="remove" <?php selected( $settings['google_fonts'], 'remove' ); ?>>
|
||||
<?php _e( 'Remove Google Fonts', 'maple-performance' ); ?>
|
||||
</option>
|
||||
<option value="combine" <?php selected( $settings['google_fonts'], 'combine' ); ?>>
|
||||
<?php _e( 'Combine and link in head (with display:swap)', 'maple-performance' ); ?>
|
||||
</option>
|
||||
<option value="defer" <?php selected( $settings['google_fonts'], 'defer' ); ?>>
|
||||
<?php _e( 'Combine and load deferred (non-render-blocking, with display:swap)', 'maple-performance' ); ?>
|
||||
</option>
|
||||
</select>
|
||||
<p class="description">
|
||||
<?php _e( '<strong>Defer</strong> is recommended - loads fonts without blocking page render.', 'maple-performance' ); ?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Local Font Display', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" name="maple_performance_settings[local_font_display]" value="1" <?php checked( $settings['local_font_display'] ?? true ); ?>>
|
||||
<?php _e( 'Add font-display: swap to theme/plugin fonts', 'maple-performance' ); ?>
|
||||
</label>
|
||||
<p class="description">
|
||||
<?php _e( 'Ensures text remains visible while local fonts load. Fixes "Ensure text remains visible during webfont load" warning.', 'maple-performance' ); ?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Preload Fonts', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<textarea name="maple_performance_settings[preload_fonts]" rows="3" class="large-text code"><?php
|
||||
echo esc_textarea( implode( "\n", $settings['preload_fonts'] ?? array() ) );
|
||||
?></textarea>
|
||||
<p class="description">
|
||||
<?php _e( 'Enter font URLs to preload (one per line). This breaks the CSS → Font chain and improves LCP. Use .woff2 files for best results.', 'maple-performance' ); ?>
|
||||
<br>
|
||||
<?php _e( '<strong>Example:</strong> /wp-content/themes/yourtheme/fonts/font-name.woff2', 'maple-performance' ); ?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Remove Emojis', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" name="maple_performance_settings[remove_emojis]" value="1" <?php checked( $settings['remove_emojis'] ); ?>>
|
||||
<?php _e( 'Remove WordPress emoji CSS and JavaScript', 'maple-performance' ); ?>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Remove Query Strings', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" name="maple_performance_settings[remove_query_strings]" value="1" <?php checked( $settings['remove_query_strings'] ); ?>>
|
||||
<?php _e( 'Remove ?ver= from static resource URLs', 'maple-performance' ); ?>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'DNS Prefetch', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox" name="maple_performance_settings[dns_prefetch]" value="1" <?php checked( $settings['dns_prefetch'] ); ?>>
|
||||
<?php _e( 'Add DNS prefetch hints for external domains', 'maple-performance' ); ?>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Preconnect Domains', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<textarea name="maple_performance_settings[preconnect_domains]" rows="4" placeholder="https://www.googletagmanager.com https://fonts.googleapis.com"><?php echo esc_textarea( implode( "\n", $settings['preconnect_domains'] ) ); ?></textarea>
|
||||
<p class="description"><?php _e( 'Third-party domains to preconnect to (one per line, include https://)', 'maple-performance' ); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2><?php _e( 'Cache Exclusions', 'maple-performance' ); ?></h2>
|
||||
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Exclude Paths', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<textarea name="maple_performance_settings[exclude_paths]" rows="4" placeholder="/cart/ /checkout/ /my-account/"><?php echo esc_textarea( implode( "\n", $settings['exclude_paths'] ) ); ?></textarea>
|
||||
<p class="description"><?php _e( 'URL paths to exclude from caching (one per line)', 'maple-performance' ); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e( 'Exclude Cookies', 'maple-performance' ); ?></th>
|
||||
<td>
|
||||
<textarea name="maple_performance_settings[exclude_cookies]" rows="4" placeholder="woocommerce_items_in_cart woocommerce_cart_hash"><?php echo esc_textarea( implode( "\n", $settings['exclude_cookies'] ) ); ?></textarea>
|
||||
<p class="description"><?php _e( 'Cookie names that bypass cache when present (one per line)', 'maple-performance' ); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<?php submit_button( __( 'Save Settings & Clear Cache', 'maple-performance' ) ); ?>
|
||||
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
<strong><?php _e( 'Maple Performance WP', 'maple-performance' ); ?></strong> v<?php echo MAPLE_PERF_VERSION; ?> |
|
||||
<?php _e( 'by', 'maple-performance' ); ?> <a href="https://mapleopentech.ca" target="_blank">Maple Open Tech</a> |
|
||||
<?php _e( 'No tracking. No external dependencies. No upsells.', 'maple-performance' ); ?> 🍁
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
608
native/wordpress/maple-performance-wp/inc/class-maple-cache.php
Normal file
608
native/wordpress/maple-performance-wp/inc/class-maple-cache.php
Normal file
|
|
@ -0,0 +1,608 @@
|
|||
<?php
|
||||
/**
|
||||
* Page Caching Class
|
||||
*
|
||||
* Handles static HTML file generation and serving.
|
||||
*
|
||||
* @package MaplePerformance
|
||||
*/
|
||||
|
||||
// Prevent direct access
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache class
|
||||
*/
|
||||
class Maple_Performance_Cache {
|
||||
|
||||
/**
|
||||
* Single instance
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Plugin settings
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* Get instance
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( null === self::$instance ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
private function __construct() {
|
||||
$this->settings = maple_performance()->settings;
|
||||
$this->init_hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize hooks
|
||||
*/
|
||||
private function init_hooks() {
|
||||
// Start output buffering early
|
||||
add_action( 'template_redirect', array( $this, 'start_buffering' ), -999 );
|
||||
|
||||
// Cache clearing hooks
|
||||
add_action( 'save_post', array( $this, 'clear_post_cache' ), 10, 1 );
|
||||
add_action( 'delete_post', array( $this, 'clear_post_cache' ), 10, 1 );
|
||||
add_action( 'wp_trash_post', array( $this, 'clear_post_cache' ), 10, 1 );
|
||||
add_action( 'comment_post', array( $this, 'clear_post_cache_by_comment' ), 10, 2 );
|
||||
add_action( 'edit_comment', array( $this, 'clear_post_cache_by_comment' ), 10, 1 );
|
||||
add_action( 'switch_theme', array( __CLASS__, 'clear_all' ) );
|
||||
add_action( 'activated_plugin', array( __CLASS__, 'clear_all' ) );
|
||||
add_action( 'deactivated_plugin', array( __CLASS__, 'clear_all' ) );
|
||||
add_action( 'update_option_permalink_structure', array( __CLASS__, 'clear_all' ) );
|
||||
|
||||
// WooCommerce hooks
|
||||
if ( class_exists( 'WooCommerce' ) ) {
|
||||
add_action( 'woocommerce_product_set_stock', array( $this, 'clear_product_cache' ) );
|
||||
add_action( 'woocommerce_variation_set_stock', array( $this, 'clear_product_cache' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start output buffering
|
||||
*/
|
||||
public function start_buffering() {
|
||||
// Check if we should cache this request
|
||||
if ( maple_performance()->is_excluded() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if cached version exists
|
||||
$cache_file = $this->get_cache_file_path();
|
||||
|
||||
if ( $this->serve_cache( $cache_file ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Start buffering for cache creation
|
||||
ob_start( array( $this, 'process_buffer' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Process output buffer and create cache
|
||||
*/
|
||||
public function process_buffer( $buffer ) {
|
||||
// Don't cache empty or error pages
|
||||
if ( empty( $buffer ) || http_response_code() !== 200 ) {
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
// Don't cache if contains certain markers
|
||||
if ( $this->should_skip_caching( $buffer ) ) {
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
// Write cache file
|
||||
$this->write_cache( $buffer );
|
||||
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if page should skip caching based on content
|
||||
*/
|
||||
private function should_skip_caching( $buffer ) {
|
||||
// Skip if contains no-cache markers
|
||||
$skip_markers = array(
|
||||
'<!-- no-cache -->',
|
||||
'<!-- maple-no-cache -->',
|
||||
'woocommerce-cart',
|
||||
'woocommerce-checkout',
|
||||
);
|
||||
|
||||
foreach ( $skip_markers as $marker ) {
|
||||
if ( strpos( $buffer, $marker ) !== false ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache file path for current request
|
||||
*/
|
||||
private function get_cache_file_path( $url = null ) {
|
||||
if ( null === $url ) {
|
||||
$url = $this->get_current_url();
|
||||
}
|
||||
|
||||
$parsed = parse_url( $url );
|
||||
$host = $parsed['host'] ?? '';
|
||||
$path = $parsed['path'] ?? '/';
|
||||
|
||||
// Sanitize host - only allow alphanumeric, dots, and hyphens
|
||||
$host = preg_replace( '/[^a-zA-Z0-9.-]/', '', $host );
|
||||
|
||||
// Sanitize path - remove any path traversal attempts
|
||||
$path = str_replace( array( '..', "\0" ), '', $path );
|
||||
$path = preg_replace( '/[^a-zA-Z0-9\/_-]/', '', $path );
|
||||
$path = preg_replace( '#/+#', '/', $path ); // Collapse multiple slashes
|
||||
$path = rtrim( $path, '/' );
|
||||
|
||||
if ( empty( $path ) ) {
|
||||
$path = '/index';
|
||||
}
|
||||
|
||||
// Limit path depth to prevent excessive directory creation
|
||||
$path_parts = explode( '/', trim( $path, '/' ) );
|
||||
if ( count( $path_parts ) > 10 ) {
|
||||
$path_parts = array_slice( $path_parts, 0, 10 );
|
||||
$path = '/' . implode( '/', $path_parts );
|
||||
}
|
||||
|
||||
// Build cache directory structure
|
||||
$cache_dir = MAPLE_PERF_CACHE_DIR . $host . $path . '/';
|
||||
|
||||
// Verify the resolved path is within cache directory
|
||||
$real_cache_base = realpath( MAPLE_PERF_CACHE_DIR );
|
||||
if ( $real_cache_base ) {
|
||||
// Use dirname to check parent since $cache_dir may not exist yet
|
||||
$parent_dir = dirname( $cache_dir );
|
||||
while ( ! is_dir( $parent_dir ) && $parent_dir !== dirname( $parent_dir ) ) {
|
||||
$parent_dir = dirname( $parent_dir );
|
||||
}
|
||||
|
||||
if ( is_dir( $parent_dir ) ) {
|
||||
$real_parent = realpath( $parent_dir );
|
||||
if ( $real_parent && strpos( $real_parent, $real_cache_base ) !== 0 ) {
|
||||
// Path escapes cache directory - return safe fallback
|
||||
return MAPLE_PERF_CACHE_DIR . 'fallback/https-index.html';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determine cache file name
|
||||
$is_https = is_ssl() ? 'https' : 'http';
|
||||
$cache_file = $cache_dir . $is_https . '-index.html';
|
||||
|
||||
return $cache_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current URL
|
||||
*/
|
||||
private function get_current_url() {
|
||||
$scheme = is_ssl() ? 'https' : 'http';
|
||||
|
||||
// Sanitize HTTP_HOST
|
||||
$host = isset( $_SERVER['HTTP_HOST'] ) ? $_SERVER['HTTP_HOST'] : '';
|
||||
$host = preg_replace( '/[^a-zA-Z0-9.-]/', '', $host );
|
||||
|
||||
// Sanitize REQUEST_URI
|
||||
$uri = isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : '/';
|
||||
$uri = filter_var( $uri, FILTER_SANITIZE_URL );
|
||||
|
||||
// Remove query strings for cache key
|
||||
$uri = strtok( $uri, '?' );
|
||||
|
||||
// Remove any null bytes or path traversal
|
||||
$uri = str_replace( array( "\0", '..' ), '', $uri );
|
||||
|
||||
return $scheme . '://' . $host . $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serve cached file if exists
|
||||
*/
|
||||
private function serve_cache( $cache_file ) {
|
||||
// Check for gzipped version first
|
||||
if ( $this->settings['cache_gzip'] && $this->client_accepts_gzip() ) {
|
||||
$gzip_file = $cache_file . '.gz';
|
||||
if ( file_exists( $gzip_file ) && $this->is_cache_valid( $gzip_file ) ) {
|
||||
header( 'Content-Encoding: gzip' );
|
||||
header( 'Content-Type: text/html; charset=UTF-8' );
|
||||
header( 'X-Maple-Cache: HIT (gzip)' );
|
||||
readfile( $gzip_file );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for brotli version
|
||||
if ( $this->settings['cache_brotli'] && $this->client_accepts_brotli() ) {
|
||||
$br_file = $cache_file . '.br';
|
||||
if ( file_exists( $br_file ) && $this->is_cache_valid( $br_file ) ) {
|
||||
header( 'Content-Encoding: br' );
|
||||
header( 'Content-Type: text/html; charset=UTF-8' );
|
||||
header( 'X-Maple-Cache: HIT (brotli)' );
|
||||
readfile( $br_file );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Serve uncompressed
|
||||
if ( file_exists( $cache_file ) && $this->is_cache_valid( $cache_file ) ) {
|
||||
header( 'Content-Type: text/html; charset=UTF-8' );
|
||||
header( 'X-Maple-Cache: HIT' );
|
||||
readfile( $cache_file );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if cache file is still valid
|
||||
*/
|
||||
private function is_cache_valid( $cache_file ) {
|
||||
// No expiry set
|
||||
if ( empty( $this->settings['cache_expiry'] ) || $this->settings['cache_expiry'] === 0 ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$file_age = time() - filemtime( $cache_file );
|
||||
$max_age = $this->settings['cache_expiry'] * HOUR_IN_SECONDS;
|
||||
|
||||
return $file_age < $max_age;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if client accepts gzip
|
||||
*/
|
||||
private function client_accepts_gzip() {
|
||||
$encoding = $_SERVER['HTTP_ACCEPT_ENCODING'] ?? '';
|
||||
return strpos( $encoding, 'gzip' ) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if client accepts brotli
|
||||
*/
|
||||
private function client_accepts_brotli() {
|
||||
$encoding = $_SERVER['HTTP_ACCEPT_ENCODING'] ?? '';
|
||||
return strpos( $encoding, 'br' ) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write cache file
|
||||
*/
|
||||
private function write_cache( $content ) {
|
||||
$cache_file = $this->get_cache_file_path();
|
||||
$cache_dir = dirname( $cache_file );
|
||||
|
||||
// Create directory if needed
|
||||
if ( ! file_exists( $cache_dir ) ) {
|
||||
wp_mkdir_p( $cache_dir );
|
||||
}
|
||||
|
||||
// Verify we're still within cache directory (paranoid check)
|
||||
$real_cache_base = realpath( MAPLE_PERF_CACHE_DIR );
|
||||
$real_cache_dir = realpath( $cache_dir );
|
||||
|
||||
if ( false === $real_cache_base || false === $real_cache_dir ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( strpos( $real_cache_dir, $real_cache_base ) !== 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add cache signature
|
||||
$timestamp = gmdate( 'D, d M Y H:i:s' ) . ' GMT';
|
||||
$signature = "\n<!-- Maple Performance WP @ {$timestamp} -->";
|
||||
$content .= $signature;
|
||||
|
||||
// Write HTML file with proper permissions
|
||||
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
|
||||
file_put_contents( $cache_file, $content );
|
||||
if ( file_exists( $cache_file ) ) {
|
||||
chmod( $cache_file, 0644 );
|
||||
}
|
||||
|
||||
// Create gzipped version
|
||||
if ( $this->settings['cache_gzip'] && function_exists( 'gzencode' ) ) {
|
||||
$gzip_content = gzencode( $content, 9 );
|
||||
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
|
||||
file_put_contents( $cache_file . '.gz', $gzip_content );
|
||||
if ( file_exists( $cache_file . '.gz' ) ) {
|
||||
chmod( $cache_file . '.gz', 0644 );
|
||||
}
|
||||
}
|
||||
|
||||
// Create brotli version
|
||||
if ( $this->settings['cache_brotli'] && function_exists( 'brotli_compress' ) ) {
|
||||
$br_content = brotli_compress( $content );
|
||||
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
|
||||
file_put_contents( $cache_file . '.br', $br_content );
|
||||
if ( file_exists( $cache_file . '.br' ) ) {
|
||||
chmod( $cache_file . '.br', 0644 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear cache for a specific post
|
||||
*/
|
||||
public function clear_post_cache( $post_id ) {
|
||||
// Don't clear for autosaves or revisions
|
||||
if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$post = get_post( $post_id );
|
||||
if ( ! $post || $post->post_status !== 'publish' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear post URL
|
||||
$url = get_permalink( $post_id );
|
||||
$this->clear_url_cache( $url );
|
||||
|
||||
// Clear home page
|
||||
$this->clear_url_cache( home_url( '/' ) );
|
||||
|
||||
// Clear archive pages
|
||||
$post_type = get_post_type( $post_id );
|
||||
$archive_url = get_post_type_archive_link( $post_type );
|
||||
if ( $archive_url ) {
|
||||
$this->clear_url_cache( $archive_url );
|
||||
}
|
||||
|
||||
// Clear category/tag archives - limit to prevent performance issues
|
||||
$taxonomies = get_object_taxonomies( $post_type );
|
||||
$terms_cleared = 0;
|
||||
$max_terms = 50; // Limit term cache clearing to prevent slowdown
|
||||
|
||||
foreach ( $taxonomies as $taxonomy ) {
|
||||
if ( $terms_cleared >= $max_terms ) {
|
||||
break;
|
||||
}
|
||||
|
||||
$terms = get_the_terms( $post_id, $taxonomy );
|
||||
if ( $terms && ! is_wp_error( $terms ) ) {
|
||||
foreach ( $terms as $term ) {
|
||||
if ( $terms_cleared >= $max_terms ) {
|
||||
break;
|
||||
}
|
||||
|
||||
$term_url = get_term_link( $term );
|
||||
if ( ! is_wp_error( $term_url ) ) {
|
||||
$this->clear_url_cache( $term_url );
|
||||
$terms_cleared++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear stats transient since cache changed
|
||||
delete_transient( 'maple_perf_cache_stats' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear cache by comment
|
||||
*/
|
||||
public function clear_post_cache_by_comment( $comment_id, $comment_approved = null ) {
|
||||
$comment = get_comment( $comment_id );
|
||||
if ( $comment ) {
|
||||
$this->clear_post_cache( $comment->comment_post_ID );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear product cache (WooCommerce)
|
||||
*/
|
||||
public function clear_product_cache( $product ) {
|
||||
if ( is_numeric( $product ) ) {
|
||||
$product_id = $product;
|
||||
} else {
|
||||
$product_id = $product->get_id();
|
||||
}
|
||||
|
||||
$this->clear_post_cache( $product_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear cache for a specific URL
|
||||
*/
|
||||
public function clear_url_cache( $url ) {
|
||||
$cache_file = $this->get_cache_file_path( $url );
|
||||
|
||||
if ( file_exists( $cache_file ) ) {
|
||||
@unlink( $cache_file );
|
||||
}
|
||||
if ( file_exists( $cache_file . '.gz' ) ) {
|
||||
@unlink( $cache_file . '.gz' );
|
||||
}
|
||||
if ( file_exists( $cache_file . '.br' ) ) {
|
||||
@unlink( $cache_file . '.br' );
|
||||
}
|
||||
|
||||
// Also clear https version if http was cleared and vice versa
|
||||
$alt_file = str_replace(
|
||||
array( '/http-index.html', '/https-index.html' ),
|
||||
array( '/https-index.html', '/http-index.html' ),
|
||||
$cache_file
|
||||
);
|
||||
|
||||
if ( file_exists( $alt_file ) ) {
|
||||
@unlink( $alt_file );
|
||||
}
|
||||
if ( file_exists( $alt_file . '.gz' ) ) {
|
||||
@unlink( $alt_file . '.gz' );
|
||||
}
|
||||
if ( file_exists( $alt_file . '.br' ) ) {
|
||||
@unlink( $alt_file . '.br' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all cache
|
||||
*/
|
||||
public static function clear_all() {
|
||||
self::recursive_delete( MAPLE_PERF_CACHE_DIR );
|
||||
|
||||
// Recreate directories
|
||||
wp_mkdir_p( MAPLE_PERF_CACHE_DIR );
|
||||
wp_mkdir_p( MAPLE_PERF_CACHE_DIR . 'assets/' );
|
||||
|
||||
// Add index.php files with ABSPATH check
|
||||
$index = "<?php\n// Silence is golden.\nif ( ! defined( 'ABSPATH' ) ) { exit; }";
|
||||
file_put_contents( MAPLE_PERF_CACHE_DIR . 'index.php', $index );
|
||||
file_put_contents( MAPLE_PERF_CACHE_DIR . 'assets/index.php', $index );
|
||||
|
||||
// Clear stats transient
|
||||
delete_transient( 'maple_perf_cache_stats' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively delete directory
|
||||
*/
|
||||
private static function recursive_delete( $dir ) {
|
||||
if ( ! is_dir( $dir ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Safety check - only delete within wp-content/cache/maple-performance
|
||||
$real_dir = realpath( $dir );
|
||||
$allowed_base = realpath( WP_CONTENT_DIR );
|
||||
|
||||
if ( false === $real_dir || false === $allowed_base ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( strpos( $real_dir, $allowed_base ) !== 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Additional safety - must contain 'maple-performance' in path
|
||||
if ( strpos( $real_dir, 'maple-performance' ) === false ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Limit iterations to prevent runaway deletion
|
||||
$max_iterations = 50000;
|
||||
$iterations = 0;
|
||||
|
||||
try {
|
||||
$files = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator( $dir, RecursiveDirectoryIterator::SKIP_DOTS ),
|
||||
RecursiveIteratorIterator::CHILD_FIRST
|
||||
);
|
||||
|
||||
foreach ( $files as $file ) {
|
||||
if ( ++$iterations > $max_iterations ) {
|
||||
break; // Safety limit reached
|
||||
}
|
||||
|
||||
$file_path = $file->getRealPath();
|
||||
|
||||
// Verify each file is within allowed directory
|
||||
if ( strpos( $file_path, $real_dir ) !== 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $file->isDir() ) {
|
||||
@rmdir( $file_path );
|
||||
} else {
|
||||
@unlink( $file_path );
|
||||
}
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
// Handle iterator exceptions gracefully
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache size
|
||||
*/
|
||||
public static function get_cache_size() {
|
||||
$size = 0;
|
||||
|
||||
if ( ! is_dir( MAPLE_PERF_CACHE_DIR ) ) {
|
||||
return $size;
|
||||
}
|
||||
|
||||
// Limit iterations to prevent runaway on huge cache directories
|
||||
$max_iterations = 10000;
|
||||
$iterations = 0;
|
||||
|
||||
try {
|
||||
$files = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator( MAPLE_PERF_CACHE_DIR, RecursiveDirectoryIterator::SKIP_DOTS )
|
||||
);
|
||||
|
||||
foreach ( $files as $file ) {
|
||||
if ( ++$iterations > $max_iterations ) {
|
||||
break; // Safety limit reached
|
||||
}
|
||||
|
||||
if ( $file->isFile() ) {
|
||||
$size += $file->getSize();
|
||||
}
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
// Handle iterator exceptions gracefully
|
||||
return $size;
|
||||
}
|
||||
|
||||
return $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of cached files
|
||||
*/
|
||||
public static function get_cache_count() {
|
||||
$count = 0;
|
||||
|
||||
if ( ! is_dir( MAPLE_PERF_CACHE_DIR ) ) {
|
||||
return $count;
|
||||
}
|
||||
|
||||
// Limit iterations to prevent runaway on huge cache directories
|
||||
$max_iterations = 10000;
|
||||
$iterations = 0;
|
||||
|
||||
try {
|
||||
$files = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator( MAPLE_PERF_CACHE_DIR, RecursiveDirectoryIterator::SKIP_DOTS )
|
||||
);
|
||||
|
||||
foreach ( $files as $file ) {
|
||||
if ( ++$iterations > $max_iterations ) {
|
||||
break; // Safety limit reached
|
||||
}
|
||||
|
||||
if ( $file->isFile() && pathinfo( $file, PATHINFO_EXTENSION ) === 'html' ) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
// Handle iterator exceptions gracefully
|
||||
return $count;
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
801
native/wordpress/maple-performance-wp/inc/class-maple-compat.php
Normal file
801
native/wordpress/maple-performance-wp/inc/class-maple-compat.php
Normal file
|
|
@ -0,0 +1,801 @@
|
|||
<?php
|
||||
/**
|
||||
* Plugin Compatibility Class
|
||||
*
|
||||
* Handles automatic detection and safe defaults for common plugins.
|
||||
*
|
||||
* @package MaplePerformance
|
||||
*/
|
||||
|
||||
// Prevent direct access
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compatibility class
|
||||
*/
|
||||
class Maple_Performance_Compat {
|
||||
|
||||
/**
|
||||
* Single instance
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Detected plugins (via auto-detect)
|
||||
*/
|
||||
private $detected = array();
|
||||
|
||||
/**
|
||||
* Enabled plugins (manual selection or auto-detected)
|
||||
*/
|
||||
private $enabled = array();
|
||||
|
||||
/**
|
||||
* Plugin settings
|
||||
*/
|
||||
private $settings = array();
|
||||
|
||||
/**
|
||||
* Get instance
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( null === self::$instance ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
private function __construct() {
|
||||
$this->settings = maple_performance()->settings;
|
||||
$this->determine_enabled_plugins();
|
||||
$this->init_hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine which plugins should have compatibility rules applied
|
||||
*/
|
||||
private function determine_enabled_plugins() {
|
||||
// If auto-detect is enabled, detect plugins
|
||||
if ( ! empty( $this->settings['compat_auto_detect'] ) ) {
|
||||
$this->detect_plugins();
|
||||
$this->enabled = $this->detected;
|
||||
} else {
|
||||
// Use manual selection
|
||||
$manual = $this->settings['compat_plugins'] ?? array();
|
||||
foreach ( $manual as $plugin ) {
|
||||
$this->enabled[ $plugin ] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect active plugins (used when auto-detect is enabled)
|
||||
*/
|
||||
private function detect_plugins() {
|
||||
// WooCommerce
|
||||
if ( class_exists( 'WooCommerce' ) || defined( 'WC_PLUGIN_FILE' ) ) {
|
||||
$this->detected['woocommerce'] = true;
|
||||
}
|
||||
|
||||
// LearnDash
|
||||
if ( defined( 'LEARNDASH_VERSION' ) || class_exists( 'SFWD_LMS' ) ) {
|
||||
$this->detected['learndash'] = true;
|
||||
}
|
||||
|
||||
// WPForms
|
||||
if ( defined( 'WPFORMS_VERSION' ) || class_exists( 'WPForms' ) ) {
|
||||
$this->detected['wpforms'] = true;
|
||||
}
|
||||
|
||||
// Wordfence
|
||||
if ( defined( 'WORDFENCE_VERSION' ) || class_exists( 'wordfence' ) ) {
|
||||
$this->detected['wordfence'] = true;
|
||||
}
|
||||
|
||||
// Gutenberg FSE / Block Themes
|
||||
if ( function_exists( 'wp_is_block_theme' ) && wp_is_block_theme() ) {
|
||||
$this->detected['gutenberg_fse'] = true;
|
||||
}
|
||||
|
||||
// Gravity Forms
|
||||
if ( class_exists( 'GFForms' ) || defined( 'GF_MIN_WP_VERSION' ) ) {
|
||||
$this->detected['gravityforms'] = true;
|
||||
}
|
||||
|
||||
// Contact Form 7
|
||||
if ( defined( 'WPCF7_VERSION' ) || class_exists( 'WPCF7' ) ) {
|
||||
$this->detected['cf7'] = true;
|
||||
}
|
||||
|
||||
// Elementor
|
||||
if ( defined( 'ELEMENTOR_VERSION' ) ) {
|
||||
$this->detected['elementor'] = true;
|
||||
}
|
||||
|
||||
// === Caching plugin conflict detection ===
|
||||
|
||||
// WP Rocket
|
||||
if ( defined( 'WP_ROCKET_VERSION' ) ) {
|
||||
$this->detected['wp_rocket'] = true;
|
||||
}
|
||||
|
||||
// W3 Total Cache
|
||||
if ( defined( 'W3TC' ) || class_exists( 'W3_Plugin_TotalCache' ) ) {
|
||||
$this->detected['w3tc'] = true;
|
||||
}
|
||||
|
||||
// LiteSpeed Cache
|
||||
if ( defined( 'LSCWP_V' ) || class_exists( 'LiteSpeed_Cache' ) ) {
|
||||
$this->detected['litespeed'] = true;
|
||||
}
|
||||
|
||||
// WP Super Cache
|
||||
if ( defined( 'WPCACHEHOME' ) || function_exists( 'wp_cache_phase2' ) ) {
|
||||
$this->detected['wp_super_cache'] = true;
|
||||
}
|
||||
|
||||
// WP Fastest Cache
|
||||
if ( class_exists( 'WpFastestCache' ) || defined( 'WPFC_WP_CONTENT_BASENAME' ) ) {
|
||||
$this->detected['wp_fastest_cache'] = true;
|
||||
}
|
||||
|
||||
// Autoptimize
|
||||
if ( class_exists( 'autoptimizeMain' ) || defined( 'AUTOPTIMIZE_PLUGIN_VERSION' ) ) {
|
||||
$this->detected['autoptimize'] = true;
|
||||
}
|
||||
|
||||
// Cache Enabler
|
||||
if ( class_exists( 'Cache_Enabler' ) || defined( 'CACHE_ENABLER_VERSION' ) ) {
|
||||
$this->detected['cache_enabler'] = true;
|
||||
}
|
||||
|
||||
// Hummingbird
|
||||
if ( class_exists( 'WP_Hummingbird' ) || defined( 'WPHB_VERSION' ) ) {
|
||||
$this->detected['hummingbird'] = true;
|
||||
}
|
||||
|
||||
// Breeze (Cloudways)
|
||||
if ( class_exists( 'Breeze_Admin' ) || defined( 'BREEZE_VERSION' ) ) {
|
||||
$this->detected['breeze'] = true;
|
||||
}
|
||||
|
||||
// SG Optimizer (SiteGround)
|
||||
if ( class_exists( 'SiteGround_Optimizer' ) || defined( 'SG_OPTIMIZER_VERSION' ) ) {
|
||||
$this->detected['sg_optimizer'] = true;
|
||||
}
|
||||
|
||||
// Swift Performance
|
||||
if ( class_exists( 'Swift_Performance' ) || defined( 'FLAVOR_FLAVOR' ) ) {
|
||||
$this->detected['swift_performance'] = true;
|
||||
}
|
||||
|
||||
// Comet Cache
|
||||
if ( class_exists( 'WebSharks\\CometCache\\Classes\\Plugin' ) || defined( 'COMET_CACHE_VERSION' ) ) {
|
||||
$this->detected['comet_cache'] = true;
|
||||
}
|
||||
|
||||
// Powered Cache
|
||||
if ( defined( 'POWERED_CACHE_VERSION' ) ) {
|
||||
$this->detected['powered_cache'] = true;
|
||||
}
|
||||
|
||||
// Perfmatters
|
||||
if ( class_exists( 'Perfmatters' ) || defined( 'PERFMATTERS_VERSION' ) ) {
|
||||
$this->detected['perfmatters'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize hooks
|
||||
*/
|
||||
private function init_hooks() {
|
||||
// Only apply filters if at least one plugin is enabled
|
||||
if ( empty( $this->enabled ) ) {
|
||||
// Still check for caching conflicts in admin
|
||||
add_action( 'admin_notices', array( $this, 'conflict_notices' ) );
|
||||
return;
|
||||
}
|
||||
|
||||
// Filter exclusions based on enabled plugins
|
||||
add_filter( 'maple_performance_js_exclusions', array( $this, 'add_js_exclusions' ) );
|
||||
add_filter( 'maple_performance_css_exclusions', array( $this, 'add_css_exclusions' ) );
|
||||
add_filter( 'maple_performance_path_exclusions', array( $this, 'add_path_exclusions' ) );
|
||||
add_filter( 'maple_performance_cookie_exclusions', array( $this, 'add_cookie_exclusions' ) );
|
||||
|
||||
// Add admin notice for conflicts
|
||||
add_action( 'admin_notices', array( $this, 'conflict_notices' ) );
|
||||
|
||||
// WooCommerce specific hooks
|
||||
if ( $this->is_enabled( 'woocommerce' ) ) {
|
||||
$this->init_woocommerce_compat();
|
||||
}
|
||||
|
||||
// LearnDash specific hooks
|
||||
if ( $this->is_enabled( 'learndash' ) ) {
|
||||
$this->init_learndash_compat();
|
||||
}
|
||||
|
||||
// WPForms specific hooks
|
||||
if ( $this->is_enabled( 'wpforms' ) ) {
|
||||
$this->init_wpforms_compat();
|
||||
}
|
||||
|
||||
// Wordfence specific hooks
|
||||
if ( $this->is_enabled( 'wordfence' ) ) {
|
||||
$this->init_wordfence_compat();
|
||||
}
|
||||
|
||||
// Gutenberg FSE specific hooks
|
||||
if ( $this->is_enabled( 'gutenberg_fse' ) ) {
|
||||
$this->init_gutenberg_fse_compat();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if plugin compatibility is enabled (either via auto-detect or manual)
|
||||
*/
|
||||
public function is_enabled( $plugin ) {
|
||||
return ! empty( $this->enabled[ $plugin ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if plugin was detected (for display purposes)
|
||||
*/
|
||||
public function is_detected( $plugin ) {
|
||||
return ! empty( $this->detected[ $plugin ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all detected plugins
|
||||
*/
|
||||
public function get_detected() {
|
||||
// Always run detection for display in admin
|
||||
if ( empty( $this->detected ) ) {
|
||||
$this->detect_plugins();
|
||||
}
|
||||
return $this->detected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all enabled plugins
|
||||
*/
|
||||
public function get_enabled() {
|
||||
return $this->enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add JS exclusions for enabled plugins
|
||||
*/
|
||||
public function add_js_exclusions( $exclusions ) {
|
||||
// WooCommerce
|
||||
if ( $this->is_enabled( 'woocommerce' ) ) {
|
||||
$exclusions = array_merge( $exclusions, array(
|
||||
'woocommerce',
|
||||
'wc-',
|
||||
'wc_',
|
||||
'jquery-blockui',
|
||||
'selectWoo',
|
||||
'select2',
|
||||
'js-cookie',
|
||||
'cart-fragments',
|
||||
'checkout',
|
||||
'add-to-cart',
|
||||
'payment',
|
||||
'stripe',
|
||||
'paypal',
|
||||
'square',
|
||||
'braintree',
|
||||
) );
|
||||
}
|
||||
|
||||
// LearnDash
|
||||
if ( $this->is_enabled( 'learndash' ) ) {
|
||||
$exclusions = array_merge( $exclusions, array(
|
||||
'learndash',
|
||||
'sfwd-',
|
||||
'sfwd_',
|
||||
'ld-',
|
||||
'ld_',
|
||||
'ldlms',
|
||||
'quiz',
|
||||
'wpProQuiz',
|
||||
) );
|
||||
}
|
||||
|
||||
// WPForms
|
||||
if ( $this->is_enabled( 'wpforms' ) ) {
|
||||
$exclusions = array_merge( $exclusions, array(
|
||||
'wpforms',
|
||||
'wpforms-',
|
||||
'jquery-validation',
|
||||
'mailcheck',
|
||||
'inputmask',
|
||||
) );
|
||||
}
|
||||
|
||||
// Wordfence
|
||||
if ( $this->is_enabled( 'wordfence' ) ) {
|
||||
$exclusions = array_merge( $exclusions, array(
|
||||
'wordfence',
|
||||
'wf-',
|
||||
'wfls-',
|
||||
) );
|
||||
}
|
||||
|
||||
// Gutenberg FSE / Block Themes
|
||||
if ( $this->is_enabled( 'gutenberg_fse' ) ) {
|
||||
$exclusions = array_merge( $exclusions, array(
|
||||
'wp-block-',
|
||||
'wp-edit-',
|
||||
) );
|
||||
}
|
||||
|
||||
// Gravity Forms
|
||||
if ( $this->is_enabled( 'gravityforms' ) ) {
|
||||
$exclusions = array_merge( $exclusions, array(
|
||||
'gform',
|
||||
'gravityforms',
|
||||
'gf_',
|
||||
) );
|
||||
}
|
||||
|
||||
// Contact Form 7
|
||||
if ( $this->is_enabled( 'cf7' ) ) {
|
||||
$exclusions = array_merge( $exclusions, array(
|
||||
'contact-form-7',
|
||||
'wpcf7',
|
||||
) );
|
||||
}
|
||||
|
||||
// Elementor
|
||||
if ( $this->is_enabled( 'elementor' ) ) {
|
||||
$exclusions = array_merge( $exclusions, array(
|
||||
'elementor-',
|
||||
'elementor_',
|
||||
) );
|
||||
}
|
||||
|
||||
return array_unique( $exclusions );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add CSS exclusions for enabled plugins
|
||||
*/
|
||||
public function add_css_exclusions( $exclusions ) {
|
||||
// LearnDash - Focus Mode CSS should load normally
|
||||
if ( $this->is_enabled( 'learndash' ) ) {
|
||||
$exclusions = array_merge( $exclusions, array(
|
||||
'learndash-front',
|
||||
'sfwd-',
|
||||
) );
|
||||
}
|
||||
|
||||
// WPForms
|
||||
if ( $this->is_enabled( 'wpforms' ) ) {
|
||||
$exclusions = array_merge( $exclusions, array(
|
||||
'wpforms',
|
||||
) );
|
||||
}
|
||||
|
||||
// Gutenberg FSE / Block Themes - protect global styles
|
||||
if ( $this->is_enabled( 'gutenberg_fse' ) ) {
|
||||
$exclusions = array_merge( $exclusions, array(
|
||||
'global-styles',
|
||||
'wp-block-',
|
||||
'core-block-',
|
||||
) );
|
||||
}
|
||||
|
||||
return array_unique( $exclusions );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add path exclusions for enabled plugins
|
||||
*/
|
||||
public function add_path_exclusions( $exclusions ) {
|
||||
// WooCommerce
|
||||
if ( $this->is_enabled( 'woocommerce' ) ) {
|
||||
$exclusions = array_merge( $exclusions, array(
|
||||
'/cart/',
|
||||
'/cart',
|
||||
'/checkout/',
|
||||
'/checkout',
|
||||
'/my-account/',
|
||||
'/my-account',
|
||||
'/wc-api/',
|
||||
'/order-received/',
|
||||
'/order-pay/',
|
||||
'/view-order/',
|
||||
'/add-to-cart=',
|
||||
'?add-to-cart=',
|
||||
'?remove_item=',
|
||||
'?removed_item=',
|
||||
) );
|
||||
}
|
||||
|
||||
// LearnDash
|
||||
if ( $this->is_enabled( 'learndash' ) ) {
|
||||
$exclusions = array_merge( $exclusions, array(
|
||||
'/lessons/',
|
||||
'/topic/',
|
||||
'/quiz/',
|
||||
'/quizzes/',
|
||||
'/certificates/',
|
||||
'/sfwd-',
|
||||
) );
|
||||
}
|
||||
|
||||
// Wordfence
|
||||
if ( $this->is_enabled( 'wordfence' ) ) {
|
||||
$exclusions = array_merge( $exclusions, array(
|
||||
'/wp-login.php',
|
||||
'?wfls-',
|
||||
) );
|
||||
}
|
||||
|
||||
return array_unique( $exclusions );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add cookie exclusions for enabled plugins
|
||||
*/
|
||||
public function add_cookie_exclusions( $exclusions ) {
|
||||
// WooCommerce
|
||||
if ( $this->is_enabled( 'woocommerce' ) ) {
|
||||
$exclusions = array_merge( $exclusions, array(
|
||||
'woocommerce_items_in_cart',
|
||||
'woocommerce_cart_hash',
|
||||
'wp_woocommerce_session_',
|
||||
'woocommerce_recently_viewed',
|
||||
) );
|
||||
}
|
||||
|
||||
// Wordfence
|
||||
if ( $this->is_enabled( 'wordfence' ) ) {
|
||||
$exclusions = array_merge( $exclusions, array(
|
||||
'wfCBLBypass',
|
||||
'wf_loginalerted_',
|
||||
) );
|
||||
}
|
||||
|
||||
return array_unique( $exclusions );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize WooCommerce compatibility
|
||||
*/
|
||||
private function init_woocommerce_compat() {
|
||||
// Don't cache cart fragments AJAX
|
||||
add_action( 'wc_ajax_get_refreshed_fragments', array( $this, 'disable_caching' ), 1 );
|
||||
add_action( 'wc_ajax_add_to_cart', array( $this, 'disable_caching' ), 1 );
|
||||
add_action( 'wc_ajax_remove_from_cart', array( $this, 'disable_caching' ), 1 );
|
||||
add_action( 'wc_ajax_apply_coupon', array( $this, 'disable_caching' ), 1 );
|
||||
add_action( 'wc_ajax_remove_coupon', array( $this, 'disable_caching' ), 1 );
|
||||
add_action( 'wc_ajax_update_shipping_method', array( $this, 'disable_caching' ), 1 );
|
||||
add_action( 'wc_ajax_checkout', array( $this, 'disable_caching' ), 1 );
|
||||
|
||||
// Clear cache on stock changes
|
||||
add_action( 'woocommerce_product_set_stock', array( $this, 'clear_product_cache' ) );
|
||||
add_action( 'woocommerce_variation_set_stock', array( $this, 'clear_product_cache' ) );
|
||||
|
||||
// Clear cache on order status changes (affects stock)
|
||||
add_action( 'woocommerce_order_status_changed', array( $this, 'clear_on_order_status' ), 10, 3 );
|
||||
|
||||
// Exclude WooCommerce pages from optimization
|
||||
add_filter( 'maple_performance_exclude_optimization', array( $this, 'exclude_woo_pages' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize LearnDash compatibility
|
||||
*/
|
||||
private function init_learndash_compat() {
|
||||
// Don't cache any LearnDash AJAX
|
||||
add_action( 'wp_ajax_learndash_mark_complete', array( $this, 'disable_caching' ), 1 );
|
||||
add_action( 'wp_ajax_ld_adv_quiz_result', array( $this, 'disable_caching' ), 1 );
|
||||
add_action( 'wp_ajax_wpProQuiz_admin_ajax', array( $this, 'disable_caching' ), 1 );
|
||||
|
||||
// Clear cache on course enrollment/completion
|
||||
add_action( 'learndash_course_completed', array( $this, 'clear_learndash_user_cache' ), 10, 1 );
|
||||
add_action( 'learndash_lesson_completed', array( $this, 'clear_learndash_user_cache' ), 10, 1 );
|
||||
add_action( 'learndash_topic_completed', array( $this, 'clear_learndash_user_cache' ), 10, 1 );
|
||||
add_action( 'learndash_quiz_completed', array( $this, 'clear_learndash_user_cache' ), 10, 2 );
|
||||
|
||||
// Clear cache when user is enrolled
|
||||
add_action( 'learndash_update_course_access', array( $this, 'clear_course_cache' ), 10, 4 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize WPForms compatibility
|
||||
*/
|
||||
private function init_wpforms_compat() {
|
||||
// WPForms AJAX is generally fine, but ensure it's not cached
|
||||
add_action( 'wp_ajax_wpforms_submit', array( $this, 'disable_caching' ), 1 );
|
||||
add_action( 'wp_ajax_nopriv_wpforms_submit', array( $this, 'disable_caching' ), 1 );
|
||||
add_action( 'wp_ajax_wpforms_file_upload_speed_test', array( $this, 'disable_caching' ), 1 );
|
||||
add_action( 'wp_ajax_nopriv_wpforms_file_upload_speed_test', array( $this, 'disable_caching' ), 1 );
|
||||
add_action( 'wp_ajax_wpforms_restricted_email', array( $this, 'disable_caching' ), 1 );
|
||||
add_action( 'wp_ajax_nopriv_wpforms_restricted_email', array( $this, 'disable_caching' ), 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Wordfence compatibility
|
||||
*/
|
||||
private function init_wordfence_compat() {
|
||||
// Don't interfere with Wordfence login security
|
||||
add_action( 'wp_ajax_nopriv_wordfence_ls_authenticate', array( $this, 'disable_caching' ), 1 );
|
||||
add_action( 'wp_ajax_wordfence_ls_authenticate', array( $this, 'disable_caching' ), 1 );
|
||||
|
||||
// Don't cache Wordfence blocked pages
|
||||
if ( defined( 'WORDFENCE_BLOCKED' ) && WORDFENCE_BLOCKED ) {
|
||||
add_filter( 'maple_performance_should_cache', '__return_false' );
|
||||
}
|
||||
|
||||
// Respect Wordfence's caching headers
|
||||
add_filter( 'maple_performance_should_cache', array( $this, 'check_wordfence_bypass' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Gutenberg FSE / Block Theme compatibility
|
||||
*/
|
||||
private function init_gutenberg_fse_compat() {
|
||||
// Don't aggregate global styles inline CSS
|
||||
add_filter( 'maple_performance_aggregate_inline_css', '__return_false' );
|
||||
|
||||
// Protect block editor assets on frontend
|
||||
add_filter( 'maple_performance_exclude_optimization', array( $this, 'exclude_block_editor_frontend' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Exclude block editor frontend from aggressive optimization
|
||||
*/
|
||||
public function exclude_block_editor_frontend( $exclude ) {
|
||||
// If viewing a page with blocks that need JS interaction
|
||||
// This is conservative - most block content is static
|
||||
return $exclude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable caching for current request
|
||||
*/
|
||||
public function disable_caching() {
|
||||
if ( ! defined( 'DONOTCACHEPAGE' ) ) {
|
||||
define( 'DONOTCACHEPAGE', true );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear product cache
|
||||
*/
|
||||
public function clear_product_cache( $product ) {
|
||||
if ( ! class_exists( 'Maple_Performance_Cache' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$product_id = is_numeric( $product ) ? $product : $product->get_id();
|
||||
$url = get_permalink( $product_id );
|
||||
|
||||
if ( $url ) {
|
||||
$cache = Maple_Performance_Cache::get_instance();
|
||||
$cache->clear_url_cache( $url );
|
||||
}
|
||||
|
||||
// Also clear shop page
|
||||
$shop_url = function_exists( 'wc_get_page_permalink' ) ? wc_get_page_permalink( 'shop' ) : '';
|
||||
if ( $shop_url ) {
|
||||
$cache->clear_url_cache( $shop_url );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear cache on order status change
|
||||
*/
|
||||
public function clear_on_order_status( $order_id, $old_status, $new_status ) {
|
||||
// Only clear when status changes might affect stock
|
||||
$stock_statuses = array( 'completed', 'processing', 'cancelled', 'refunded' );
|
||||
|
||||
if ( in_array( $new_status, $stock_statuses ) || in_array( $old_status, $stock_statuses ) ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
if ( $order ) {
|
||||
foreach ( $order->get_items() as $item ) {
|
||||
$product_id = $item->get_product_id();
|
||||
$this->clear_product_cache( $product_id );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exclude WooCommerce pages from JS/CSS optimization
|
||||
*/
|
||||
public function exclude_woo_pages( $exclude ) {
|
||||
if ( function_exists( 'is_cart' ) && is_cart() ) {
|
||||
return true;
|
||||
}
|
||||
if ( function_exists( 'is_checkout' ) && is_checkout() ) {
|
||||
return true;
|
||||
}
|
||||
if ( function_exists( 'is_account_page' ) && is_account_page() ) {
|
||||
return true;
|
||||
}
|
||||
return $exclude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear LearnDash user-related cache
|
||||
*/
|
||||
public function clear_learndash_user_cache( $data ) {
|
||||
// LearnDash pages are user-specific and already excluded for logged-in users
|
||||
// But we can clear the course archive pages
|
||||
if ( ! class_exists( 'Maple_Performance_Cache' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cache = Maple_Performance_Cache::get_instance();
|
||||
|
||||
// Clear course archive
|
||||
$course_archive = get_post_type_archive_link( 'sfwd-courses' );
|
||||
if ( $course_archive ) {
|
||||
$cache->clear_url_cache( $course_archive );
|
||||
}
|
||||
|
||||
// Clear home page (might show course counts)
|
||||
$cache->clear_url_cache( home_url( '/' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear course cache when enrollment changes
|
||||
*/
|
||||
public function clear_course_cache( $user_id, $course_id, $access_list, $remove ) {
|
||||
if ( ! class_exists( 'Maple_Performance_Cache' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cache = Maple_Performance_Cache::get_instance();
|
||||
|
||||
// Clear the course page (might show enrollment count)
|
||||
$course_url = get_permalink( $course_id );
|
||||
if ( $course_url ) {
|
||||
$cache->clear_url_cache( $course_url );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check Wordfence bypass
|
||||
*/
|
||||
public function check_wordfence_bypass( $should_cache ) {
|
||||
// If Wordfence has set bypass cookie, don't cache
|
||||
if ( isset( $_COOKIE['wfCBLBypass'] ) ) {
|
||||
return false;
|
||||
}
|
||||
return $should_cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show admin notices for plugin conflicts
|
||||
*/
|
||||
public function conflict_notices() {
|
||||
// Build list of conflicting caching plugins
|
||||
$caching_conflicts = $this->get_caching_conflicts();
|
||||
|
||||
// Show caching conflict warning on all admin pages (dismissible)
|
||||
if ( ! empty( $caching_conflicts ) && ! get_transient( 'maple_perf_conflict_dismissed' ) ) {
|
||||
$this->show_conflict_warning( $caching_conflicts );
|
||||
}
|
||||
|
||||
// Show detailed info only on Maple Performance settings page
|
||||
$screen = get_current_screen();
|
||||
if ( ! $screen || $screen->id !== 'settings_page_maple-performance' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If conflicts exist but were dismissed, show a subtle reminder on settings page
|
||||
if ( ! empty( $caching_conflicts ) && get_transient( 'maple_perf_conflict_dismissed' ) ) {
|
||||
echo '<div class="notice notice-warning">';
|
||||
echo '<p><strong>' . esc_html__( 'Reminder:', 'maple-performance' ) . '</strong> ';
|
||||
echo sprintf(
|
||||
esc_html__( 'Other caching plugin(s) detected: %s. For best results, use only one caching solution.', 'maple-performance' ),
|
||||
'<code>' . implode( '</code>, <code>', array_map( 'esc_html', $caching_conflicts ) ) . '</code>'
|
||||
);
|
||||
echo '</p></div>';
|
||||
}
|
||||
|
||||
// Show detected compatible plugins (info)
|
||||
$compatible = array();
|
||||
if ( $this->is_detected( 'woocommerce' ) ) $compatible[] = 'WooCommerce';
|
||||
if ( $this->is_detected( 'learndash' ) ) $compatible[] = 'LearnDash';
|
||||
if ( $this->is_detected( 'wpforms' ) ) $compatible[] = 'WPForms';
|
||||
if ( $this->is_detected( 'wordfence' ) ) $compatible[] = 'Wordfence';
|
||||
if ( $this->is_detected( 'gravityforms' ) ) $compatible[] = 'Gravity Forms';
|
||||
if ( $this->is_detected( 'cf7' ) ) $compatible[] = 'Contact Form 7';
|
||||
if ( $this->is_detected( 'elementor' ) ) $compatible[] = 'Elementor';
|
||||
|
||||
if ( ! empty( $compatible ) ) {
|
||||
echo '<div class="notice notice-info">';
|
||||
echo '<p><strong>' . esc_html__( 'Maple Performance - Detected Plugins:', 'maple-performance' ) . '</strong> ';
|
||||
echo sprintf(
|
||||
esc_html__( 'Compatibility rules available for: %s. Enable them in the Plugin Compatibility section below.', 'maple-performance' ),
|
||||
'<code>' . implode( '</code>, <code>', array_map( 'esc_html', $compatible ) ) . '</code>'
|
||||
);
|
||||
echo '</p></div>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of detected caching plugin conflicts
|
||||
*/
|
||||
public function get_caching_conflicts() {
|
||||
$conflicts = array();
|
||||
|
||||
$caching_plugins = array(
|
||||
'wp_rocket' => 'WP Rocket',
|
||||
'w3tc' => 'W3 Total Cache',
|
||||
'litespeed' => 'LiteSpeed Cache',
|
||||
'wp_super_cache' => 'WP Super Cache',
|
||||
'wp_fastest_cache' => 'WP Fastest Cache',
|
||||
'autoptimize' => 'Autoptimize',
|
||||
'cache_enabler' => 'Cache Enabler',
|
||||
'hummingbird' => 'Hummingbird',
|
||||
'breeze' => 'Breeze',
|
||||
'sg_optimizer' => 'SG Optimizer',
|
||||
'swift_performance'=> 'Swift Performance',
|
||||
'comet_cache' => 'Comet Cache',
|
||||
'powered_cache' => 'Powered Cache',
|
||||
'perfmatters' => 'Perfmatters',
|
||||
);
|
||||
|
||||
foreach ( $caching_plugins as $key => $name ) {
|
||||
if ( $this->is_detected( $key ) ) {
|
||||
$conflicts[] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
return $conflicts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any caching conflicts exist
|
||||
*/
|
||||
public function has_caching_conflicts() {
|
||||
return ! empty( $this->get_caching_conflicts() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Show conflict warning notice
|
||||
*/
|
||||
private function show_conflict_warning( $conflicts ) {
|
||||
// Handle dismiss action
|
||||
if ( isset( $_GET['maple_dismiss_conflict'] ) && wp_verify_nonce( $_GET['_wpnonce'] ?? '', 'maple_dismiss_conflict' ) ) {
|
||||
set_transient( 'maple_perf_conflict_dismissed', true, 7 * DAY_IN_SECONDS );
|
||||
return;
|
||||
}
|
||||
|
||||
$dismiss_url = wp_nonce_url( add_query_arg( 'maple_dismiss_conflict', '1' ), 'maple_dismiss_conflict' );
|
||||
|
||||
echo '<div class="notice notice-error">';
|
||||
echo '<p><strong>' . esc_html__( '⚠️ Maple Performance - Caching Conflict Detected', 'maple-performance' ) . '</strong></p>';
|
||||
echo '<p>' . sprintf(
|
||||
esc_html__( 'The following caching/optimization plugin(s) are also active: %s', 'maple-performance' ),
|
||||
'<strong>' . implode( ', ', array_map( 'esc_html', $conflicts ) ) . '</strong>'
|
||||
) . '</p>';
|
||||
echo '<p>' . esc_html__( 'Running multiple caching plugins simultaneously can cause:', 'maple-performance' ) . '</p>';
|
||||
echo '<ul style="list-style: disc; margin-left: 20px;">';
|
||||
echo '<li>' . esc_html__( 'Blank pages or site errors', 'maple-performance' ) . '</li>';
|
||||
echo '<li>' . esc_html__( 'Stale/outdated content being served', 'maple-performance' ) . '</li>';
|
||||
echo '<li>' . esc_html__( 'Slower performance (double processing)', 'maple-performance' ) . '</li>';
|
||||
echo '<li>' . esc_html__( 'Cache invalidation failures', 'maple-performance' ) . '</li>';
|
||||
echo '</ul>';
|
||||
echo '<p><strong>' . esc_html__( 'Recommended action:', 'maple-performance' ) . '</strong> ';
|
||||
echo esc_html__( 'Deactivate the other caching plugin(s), or deactivate Maple Performance if you prefer to keep your existing solution.', 'maple-performance' );
|
||||
echo '</p>';
|
||||
echo '<p>';
|
||||
echo '<a href="' . esc_url( admin_url( 'plugins.php' ) ) . '" class="button button-primary">' . esc_html__( 'Go to Plugins', 'maple-performance' ) . '</a> ';
|
||||
echo '<a href="' . esc_url( $dismiss_url ) . '" class="button">' . esc_html__( 'Dismiss for 7 days', 'maple-performance' ) . '</a>';
|
||||
echo '</p>';
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
1234
native/wordpress/maple-performance-wp/inc/class-maple-optimize.php
Normal file
1234
native/wordpress/maple-performance-wp/inc/class-maple-optimize.php
Normal file
File diff suppressed because it is too large
Load diff
11
native/wordpress/maple-performance-wp/inc/index.php
Normal file
11
native/wordpress/maple-performance-wp/inc/index.php
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
/**
|
||||
* Silence is golden.
|
||||
*
|
||||
* @package MaplePerformance
|
||||
*/
|
||||
|
||||
// Prevent direct access
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
11
native/wordpress/maple-performance-wp/index.php
Normal file
11
native/wordpress/maple-performance-wp/index.php
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
/**
|
||||
* Silence is golden.
|
||||
*
|
||||
* @package MaplePerformance
|
||||
*/
|
||||
|
||||
// Prevent direct access
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
11
native/wordpress/maple-performance-wp/js/index.php
Normal file
11
native/wordpress/maple-performance-wp/js/index.php
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
/**
|
||||
* Silence is golden.
|
||||
*
|
||||
* @package MaplePerformance
|
||||
*/
|
||||
|
||||
// Prevent direct access
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
539
native/wordpress/maple-performance-wp/maple-performance.php
Normal file
539
native/wordpress/maple-performance-wp/maple-performance.php
Normal file
|
|
@ -0,0 +1,539 @@
|
|||
<?php
|
||||
/**
|
||||
* Plugin Name: Maple Performance WP
|
||||
* Plugin URI: https://mapleopentech.ca/maple-performance-wp
|
||||
* Description: A lightweight, privacy-focused WordPress performance plugin. No external dependencies, no tracking, no upsells.
|
||||
* Version: 1.0.0
|
||||
* Author: Maple Open Tech
|
||||
* Author URI: https://mapleopentech.ca
|
||||
* License: GPL-2.0-or-later
|
||||
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
||||
* Text Domain: maple-performance
|
||||
* Domain Path: /languages
|
||||
* Requires at least: 5.9
|
||||
* Requires PHP: 7.4
|
||||
*
|
||||
* @package MaplePerformance
|
||||
*/
|
||||
|
||||
// Prevent direct access
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Plugin constants
|
||||
define( 'MAPLE_PERF_VERSION', '1.0.0' );
|
||||
define( 'MAPLE_PERF_FILE', __FILE__ );
|
||||
define( 'MAPLE_PERF_PATH', plugin_dir_path( __FILE__ ) );
|
||||
define( 'MAPLE_PERF_URL', plugin_dir_url( __FILE__ ) );
|
||||
define( 'MAPLE_PERF_CACHE_DIR', WP_CONTENT_DIR . '/cache/maple-performance/' );
|
||||
define( 'MAPLE_PERF_CACHE_URL', content_url( '/cache/maple-performance/' ) );
|
||||
|
||||
/**
|
||||
* Autoloader for plugin classes
|
||||
*/
|
||||
spl_autoload_register( function( $class ) {
|
||||
$prefix = 'Maple_Performance_';
|
||||
|
||||
if ( strpos( $class, $prefix ) !== 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$class_name = str_replace( $prefix, '', $class );
|
||||
$class_name = strtolower( str_replace( '_', '-', $class_name ) );
|
||||
$file = MAPLE_PERF_PATH . 'inc/class-maple-' . $class_name . '.php';
|
||||
|
||||
if ( file_exists( $file ) ) {
|
||||
require_once $file;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Main plugin class
|
||||
*/
|
||||
final class Maple_Performance {
|
||||
|
||||
/**
|
||||
* Single instance
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Plugin settings
|
||||
*/
|
||||
public $settings = array();
|
||||
|
||||
/**
|
||||
* Get instance
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( null === self::$instance ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
private function __construct() {
|
||||
$this->load_settings();
|
||||
$this->init_hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load settings from database
|
||||
*/
|
||||
private function load_settings() {
|
||||
$defaults = array(
|
||||
// Site mode
|
||||
'site_mode' => 'brochure', // brochure, woocommerce, learndash, woo_learndash
|
||||
|
||||
// Page caching
|
||||
'cache_enabled' => true,
|
||||
'cache_expiry' => 0, // 0 = never expires
|
||||
'cache_logged_in' => false,
|
||||
'cache_gzip' => true,
|
||||
'cache_brotli' => false,
|
||||
|
||||
// HTML optimization
|
||||
'html_minify' => true,
|
||||
'html_remove_comments' => true,
|
||||
|
||||
// CSS optimization
|
||||
'css_minify' => true,
|
||||
'css_aggregate' => true,
|
||||
'css_inline_aggregate' => false,
|
||||
'css_defer' => false, // Disabled by default for safety
|
||||
|
||||
// JS optimization
|
||||
'js_minify' => true,
|
||||
'js_aggregate' => false, // Disabled by default for safety
|
||||
'js_defer' => false,
|
||||
'js_exclude_jquery' => true,
|
||||
|
||||
// Exclusions
|
||||
'exclude_paths' => array(),
|
||||
'exclude_cookies' => array(),
|
||||
'exclude_js' => array(),
|
||||
'exclude_css' => array(),
|
||||
|
||||
// Extra
|
||||
'remove_emojis' => true,
|
||||
'remove_query_strings' => true,
|
||||
'preconnect_domains' => array(),
|
||||
'dns_prefetch' => true,
|
||||
|
||||
// Lazy loading
|
||||
'lazyload_images' => true,
|
||||
'lazyload_iframes' => true,
|
||||
'lazyload_exclude' => array(),
|
||||
|
||||
// Google Fonts
|
||||
'google_fonts' => 'defer', // 'leave', 'remove', 'combine', 'defer'
|
||||
|
||||
// Local Font Optimization
|
||||
'local_font_display' => true, // Add font-display: swap to all @font-face rules
|
||||
'preload_fonts' => array(), // Font URLs to preload (woff2 recommended)
|
||||
|
||||
// Plugin Compatibility
|
||||
'compat_auto_detect' => false, // Auto-detect plugins (can be fragile)
|
||||
'compat_plugins' => array(), // Manually selected: woocommerce, learndash, wordfence, wpforms, gutenberg_fse
|
||||
);
|
||||
|
||||
$saved = get_option( 'maple_performance_settings', array() );
|
||||
$this->settings = wp_parse_args( $saved, $defaults );
|
||||
|
||||
// Apply site mode presets
|
||||
$this->apply_site_mode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply safe defaults based on site mode
|
||||
*/
|
||||
private function apply_site_mode() {
|
||||
switch ( $this->settings['site_mode'] ) {
|
||||
case 'woocommerce':
|
||||
$this->settings['js_aggregate'] = false;
|
||||
$this->settings['css_defer'] = false;
|
||||
$this->settings['cache_logged_in'] = false;
|
||||
break;
|
||||
|
||||
case 'learndash':
|
||||
$this->settings['js_aggregate'] = false;
|
||||
$this->settings['css_defer'] = false;
|
||||
$this->settings['cache_logged_in'] = false;
|
||||
break;
|
||||
|
||||
case 'woo_learndash':
|
||||
$this->settings['js_aggregate'] = false;
|
||||
$this->settings['js_defer'] = false;
|
||||
$this->settings['css_aggregate'] = true;
|
||||
$this->settings['css_inline_aggregate'] = false;
|
||||
$this->settings['css_defer'] = false;
|
||||
$this->settings['cache_logged_in'] = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Ensure arrays are unique
|
||||
$this->settings['exclude_paths'] = array_unique( array_filter( $this->settings['exclude_paths'] ) );
|
||||
$this->settings['exclude_cookies'] = array_unique( array_filter( $this->settings['exclude_cookies'] ) );
|
||||
$this->settings['exclude_js'] = array_unique( array_filter( $this->settings['exclude_js'] ) );
|
||||
$this->settings['exclude_css'] = array_unique( array_filter( $this->settings['exclude_css'] ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize hooks
|
||||
*/
|
||||
private function init_hooks() {
|
||||
// Activation/Deactivation
|
||||
register_activation_hook( MAPLE_PERF_FILE, array( $this, 'activate' ) );
|
||||
register_deactivation_hook( MAPLE_PERF_FILE, array( $this, 'deactivate' ) );
|
||||
|
||||
// Load components
|
||||
add_action( 'plugins_loaded', array( $this, 'load_components' ) );
|
||||
|
||||
// Admin
|
||||
if ( is_admin() ) {
|
||||
add_action( 'plugins_loaded', array( $this, 'load_admin' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load plugin components
|
||||
*/
|
||||
public function load_components() {
|
||||
// Compatibility layer (always load to detect plugins)
|
||||
require_once MAPLE_PERF_PATH . 'inc/class-maple-compat.php';
|
||||
Maple_Performance_Compat::get_instance();
|
||||
|
||||
// Cache component
|
||||
if ( $this->settings['cache_enabled'] && ! is_admin() ) {
|
||||
require_once MAPLE_PERF_PATH . 'inc/class-maple-cache.php';
|
||||
Maple_Performance_Cache::get_instance();
|
||||
}
|
||||
|
||||
// Optimize component (CSS/JS/HTML)
|
||||
if ( ! is_admin() ) {
|
||||
require_once MAPLE_PERF_PATH . 'inc/class-maple-optimize.php';
|
||||
Maple_Performance_Optimize::get_instance();
|
||||
}
|
||||
|
||||
// Extra optimizations
|
||||
if ( $this->settings['remove_emojis'] ) {
|
||||
$this->disable_emojis();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load admin component
|
||||
*/
|
||||
public function load_admin() {
|
||||
require_once MAPLE_PERF_PATH . 'inc/class-maple-admin.php';
|
||||
Maple_Performance_Admin::get_instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable WordPress emojis
|
||||
*/
|
||||
private function disable_emojis() {
|
||||
remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
|
||||
remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
|
||||
remove_action( 'wp_print_styles', 'print_emoji_styles' );
|
||||
remove_action( 'admin_print_styles', 'print_emoji_styles' );
|
||||
remove_filter( 'the_content_feed', 'wp_staticize_emoji' );
|
||||
remove_filter( 'comment_text_rss', 'wp_staticize_emoji' );
|
||||
remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );
|
||||
|
||||
add_filter( 'tiny_mce_plugins', function( $plugins ) {
|
||||
return is_array( $plugins ) ? array_diff( $plugins, array( 'wpemoji' ) ) : array();
|
||||
});
|
||||
|
||||
add_filter( 'wp_resource_hints', function( $urls, $relation_type ) {
|
||||
if ( 'dns-prefetch' === $relation_type ) {
|
||||
$urls = array_filter( $urls, function( $url ) {
|
||||
return strpos( $url, 'https://s.w.org/images/core/emoji/' ) === false;
|
||||
});
|
||||
}
|
||||
return $urls;
|
||||
}, 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin activation
|
||||
*/
|
||||
public function activate() {
|
||||
// Create cache directory
|
||||
if ( ! file_exists( MAPLE_PERF_CACHE_DIR ) ) {
|
||||
wp_mkdir_p( MAPLE_PERF_CACHE_DIR );
|
||||
}
|
||||
|
||||
// Create assets cache directory
|
||||
if ( ! file_exists( MAPLE_PERF_CACHE_DIR . 'assets/' ) ) {
|
||||
wp_mkdir_p( MAPLE_PERF_CACHE_DIR . 'assets/' );
|
||||
}
|
||||
|
||||
// Add index.php for security
|
||||
$index_content = "<?php\n// Silence is golden.\nif ( ! defined( 'ABSPATH' ) ) { exit; }";
|
||||
if ( ! file_exists( MAPLE_PERF_CACHE_DIR . 'index.php' ) ) {
|
||||
file_put_contents( MAPLE_PERF_CACHE_DIR . 'index.php', $index_content );
|
||||
}
|
||||
if ( ! file_exists( MAPLE_PERF_CACHE_DIR . 'assets/index.php' ) ) {
|
||||
file_put_contents( MAPLE_PERF_CACHE_DIR . 'assets/index.php', $index_content );
|
||||
}
|
||||
|
||||
// Set default settings
|
||||
if ( ! get_option( 'maple_performance_settings' ) ) {
|
||||
add_option( 'maple_performance_settings', array() );
|
||||
}
|
||||
|
||||
// Check for caching conflicts and set flag to show notice
|
||||
$conflicts = $this->detect_caching_conflicts();
|
||||
if ( ! empty( $conflicts ) ) {
|
||||
set_transient( 'maple_perf_activation_conflict', $conflicts, 60 );
|
||||
}
|
||||
|
||||
// Clear any existing cache
|
||||
$this->clear_cache();
|
||||
|
||||
// Clear any previously dismissed conflict notice
|
||||
delete_transient( 'maple_perf_conflict_dismissed' );
|
||||
|
||||
flush_rewrite_rules();
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect caching plugin conflicts at activation time
|
||||
*/
|
||||
private function detect_caching_conflicts() {
|
||||
$conflicts = array();
|
||||
|
||||
// Check for common caching plugins
|
||||
if ( defined( 'WP_ROCKET_VERSION' ) ) {
|
||||
$conflicts[] = 'WP Rocket';
|
||||
}
|
||||
if ( defined( 'W3TC' ) || class_exists( 'W3_Plugin_TotalCache' ) ) {
|
||||
$conflicts[] = 'W3 Total Cache';
|
||||
}
|
||||
if ( defined( 'LSCWP_V' ) || class_exists( 'LiteSpeed_Cache' ) ) {
|
||||
$conflicts[] = 'LiteSpeed Cache';
|
||||
}
|
||||
if ( defined( 'WPCACHEHOME' ) || function_exists( 'wp_cache_phase2' ) ) {
|
||||
$conflicts[] = 'WP Super Cache';
|
||||
}
|
||||
if ( class_exists( 'WpFastestCache' ) || defined( 'WPFC_WP_CONTENT_BASENAME' ) ) {
|
||||
$conflicts[] = 'WP Fastest Cache';
|
||||
}
|
||||
if ( class_exists( 'autoptimizeMain' ) || defined( 'AUTOPTIMIZE_PLUGIN_VERSION' ) ) {
|
||||
$conflicts[] = 'Autoptimize';
|
||||
}
|
||||
if ( class_exists( 'Cache_Enabler' ) || defined( 'CACHE_ENABLER_VERSION' ) ) {
|
||||
$conflicts[] = 'Cache Enabler';
|
||||
}
|
||||
if ( class_exists( 'WP_Hummingbird' ) || defined( 'WPHB_VERSION' ) ) {
|
||||
$conflicts[] = 'Hummingbird';
|
||||
}
|
||||
if ( class_exists( 'Breeze_Admin' ) || defined( 'BREEZE_VERSION' ) ) {
|
||||
$conflicts[] = 'Breeze';
|
||||
}
|
||||
if ( class_exists( 'SiteGround_Optimizer' ) || defined( 'SG_OPTIMIZER_VERSION' ) ) {
|
||||
$conflicts[] = 'SG Optimizer';
|
||||
}
|
||||
|
||||
return $conflicts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin deactivation
|
||||
*/
|
||||
public function deactivate() {
|
||||
$this->clear_cache();
|
||||
flush_rewrite_rules();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all caches
|
||||
*/
|
||||
public function clear_cache() {
|
||||
// Clear page cache
|
||||
if ( class_exists( 'Maple_Performance_Cache' ) ) {
|
||||
Maple_Performance_Cache::clear_all();
|
||||
} else {
|
||||
$this->recursive_delete( MAPLE_PERF_CACHE_DIR );
|
||||
}
|
||||
|
||||
// Recreate directories
|
||||
if ( ! file_exists( MAPLE_PERF_CACHE_DIR ) ) {
|
||||
wp_mkdir_p( MAPLE_PERF_CACHE_DIR );
|
||||
}
|
||||
if ( ! file_exists( MAPLE_PERF_CACHE_DIR . 'assets/' ) ) {
|
||||
wp_mkdir_p( MAPLE_PERF_CACHE_DIR . 'assets/' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively delete directory contents
|
||||
*/
|
||||
private function recursive_delete( $dir ) {
|
||||
if ( ! is_dir( $dir ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Safety check - only delete within wp-content/cache/maple-performance
|
||||
$real_dir = realpath( $dir );
|
||||
$allowed_base = realpath( WP_CONTENT_DIR );
|
||||
|
||||
if ( false === $real_dir || false === $allowed_base ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( strpos( $real_dir, $allowed_base ) !== 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Additional safety - must contain 'maple-performance' in path
|
||||
if ( strpos( $real_dir, 'maple-performance' ) === false ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Limit iterations to prevent runaway deletion
|
||||
$max_iterations = 50000;
|
||||
$iterations = 0;
|
||||
|
||||
try {
|
||||
$files = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator( $dir, RecursiveDirectoryIterator::SKIP_DOTS ),
|
||||
RecursiveIteratorIterator::CHILD_FIRST
|
||||
);
|
||||
|
||||
foreach ( $files as $file ) {
|
||||
if ( ++$iterations > $max_iterations ) {
|
||||
break; // Safety limit reached
|
||||
}
|
||||
|
||||
$file_path = $file->getRealPath();
|
||||
|
||||
// Verify each file is within allowed directory
|
||||
if ( strpos( $file_path, $real_dir ) !== 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $file->isDir() ) {
|
||||
@rmdir( $file_path );
|
||||
} else {
|
||||
@unlink( $file_path );
|
||||
}
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
// Handle iterator exceptions gracefully
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get setting value
|
||||
*/
|
||||
public function get_setting( $key, $default = null ) {
|
||||
return isset( $this->settings[ $key ] ) ? $this->settings[ $key ] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current request should be excluded from caching
|
||||
*/
|
||||
public function is_excluded() {
|
||||
// Admin requests
|
||||
if ( is_admin() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// AJAX requests
|
||||
if ( wp_doing_ajax() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Cron requests
|
||||
if ( wp_doing_cron() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// REST API
|
||||
if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// POST requests
|
||||
if ( 'GET' !== $_SERVER['REQUEST_METHOD'] ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// DONOTCACHEPAGE constant (set by compat class or other plugins)
|
||||
if ( defined( 'DONOTCACHEPAGE' ) && DONOTCACHEPAGE ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Logged-in users (unless enabled)
|
||||
if ( ! $this->settings['cache_logged_in'] && is_user_logged_in() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get cookie exclusions with compat filter
|
||||
$exclude_cookies = apply_filters( 'maple_performance_cookie_exclusions', $this->settings['exclude_cookies'] );
|
||||
|
||||
// Check excluded cookies
|
||||
foreach ( $exclude_cookies as $cookie ) {
|
||||
if ( ! empty( $cookie ) ) {
|
||||
// Support partial cookie name matching (for session cookies with dynamic suffixes)
|
||||
foreach ( $_COOKIE as $cookie_name => $cookie_value ) {
|
||||
if ( strpos( $cookie_name, $cookie ) !== false ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get path exclusions with compat filter
|
||||
$exclude_paths = apply_filters( 'maple_performance_path_exclusions', $this->settings['exclude_paths'] );
|
||||
|
||||
// Check excluded paths
|
||||
$request_uri = $_SERVER['REQUEST_URI'] ?? '';
|
||||
foreach ( $exclude_paths as $path ) {
|
||||
if ( ! empty( $path ) && strpos( $request_uri, $path ) !== false ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Allow other plugins/code to exclude
|
||||
if ( apply_filters( 'maple_performance_exclude_optimization', false ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// WooCommerce specific
|
||||
if ( function_exists( 'is_cart' ) && ( is_cart() || is_checkout() || is_account_page() ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// LearnDash specific - always exclude when user is enrolled
|
||||
if ( function_exists( 'learndash_user_get_enrolled_courses' ) && is_user_logged_in() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize plugin
|
||||
*/
|
||||
function maple_performance() {
|
||||
return Maple_Performance::get_instance();
|
||||
}
|
||||
|
||||
// Start the plugin
|
||||
maple_performance();
|
||||
|
||||
/**
|
||||
* Template tag to clear cache
|
||||
*/
|
||||
function maple_clear_cache() {
|
||||
maple_performance()->clear_cache();
|
||||
}
|
||||
142
native/wordpress/maple-performance-wp/readme.txt
Normal file
142
native/wordpress/maple-performance-wp/readme.txt
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
=== Maple Performance WP ===
|
||||
Contributors: mapleopentech
|
||||
Tags: cache, performance, speed, optimization, minify
|
||||
Requires at least: 5.9
|
||||
Tested up to: 6.4
|
||||
Requires PHP: 7.4
|
||||
Stable tag: 1.0.0
|
||||
License: GPLv2 or later
|
||||
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
||||
|
||||
A lightweight, privacy-focused WordPress performance plugin. No external dependencies, no tracking, no upsells.
|
||||
|
||||
== Description ==
|
||||
|
||||
Maple Performance WP is a Canadian-made, privacy-focused performance optimization plugin that speeds up your WordPress site without sending any data to external servers.
|
||||
|
||||
**Key Features:**
|
||||
|
||||
* **Page Caching** - Creates static HTML files with optional Gzip/Brotli pre-compression
|
||||
* **HTML Minification** - Removes unnecessary whitespace and comments
|
||||
* **CSS Optimization** - Minify and aggregate CSS files
|
||||
* **JavaScript Optimization** - Minify and aggregate JS files (with safe defaults)
|
||||
* **Google Fonts Optimization** - Combine, add display:swap, and optionally defer loading
|
||||
* **Lazy Loading** - Native lazy loading for images and iframes
|
||||
* **Extra Optimizations** - Remove emoji scripts, query strings, add preconnect hints
|
||||
* **Smart Plugin Compatibility** - Auto-detects WooCommerce, LearnDash, WPForms, Wordfence and applies safe exclusions
|
||||
|
||||
**Site Mode Presets:**
|
||||
|
||||
Choose your site type and Maple Performance automatically applies safe default settings:
|
||||
|
||||
* **Brochure/Blog** - Full optimization enabled
|
||||
* **WooCommerce** - Conservative JS settings to protect checkout
|
||||
* **LearnDash** - Safe settings to protect lesson tracking and quizzes
|
||||
* **WooCommerce + LearnDash** - Maximum safety for course selling sites
|
||||
|
||||
**Privacy First:**
|
||||
|
||||
* No external API calls
|
||||
* No tracking or analytics
|
||||
* No CDN dependencies
|
||||
* No upsells or premium nags
|
||||
* All processing happens on your server
|
||||
|
||||
**Canadian Data Sovereignty:**
|
||||
|
||||
Built by [Maple Open Tech](https://mapleopentech.ca) for Canadian businesses who care about keeping their data in Canada.
|
||||
|
||||
== Installation ==
|
||||
|
||||
1. Upload the `maple-performance-wp` folder to `/wp-content/plugins/`
|
||||
2. Activate the plugin through the 'Plugins' menu in WordPress
|
||||
3. Go to Settings > Maple Performance
|
||||
4. Select your site type (Brochure, WooCommerce, LearnDash, or both)
|
||||
5. Adjust settings as needed
|
||||
6. Save and test your site
|
||||
|
||||
== Frequently Asked Questions ==
|
||||
|
||||
= Is this safe for WooCommerce? =
|
||||
|
||||
Yes! Select "WooCommerce Store" as your site type and Maple Performance automatically disables aggressive optimizations that could break checkout. Cart and checkout pages are excluded from caching automatically.
|
||||
|
||||
= Is this safe for LearnDash? =
|
||||
|
||||
Yes! Select "LearnDash LMS" as your site type and JavaScript aggregation is disabled to protect lesson completion tracking and quiz functionality.
|
||||
|
||||
= Does this require any external service? =
|
||||
|
||||
No. Everything runs on your server. No API calls, no CDN requirements, no external dependencies.
|
||||
|
||||
= How do I clear the cache? =
|
||||
|
||||
Click "Clear All Cache" in the admin bar, or go to Settings > Maple Performance and click the clear cache button.
|
||||
|
||||
= Can I use this with other caching plugins? =
|
||||
|
||||
Not recommended. Deactivate other caching plugins (W3 Total Cache, WP Rocket, LiteSpeed Cache, etc.) before activating Maple Performance to avoid conflicts.
|
||||
|
||||
= What plugins are automatically compatible? =
|
||||
|
||||
Maple Performance automatically detects and applies safe defaults for:
|
||||
|
||||
* **WooCommerce** - Cart, checkout, account pages excluded from cache. Cart/checkout scripts protected.
|
||||
* **LearnDash** - Lesson, topic, quiz pages excluded. Progress tracking and quiz scripts protected.
|
||||
* **WPForms** - Form scripts excluded from aggregation. AJAX submissions protected.
|
||||
* **Wordfence** - Security scripts excluded. Login pages not cached. Firewall cookies respected.
|
||||
* **Gravity Forms** - Form scripts excluded from aggregation.
|
||||
* **Contact Form 7** - Form scripts excluded from aggregation.
|
||||
* **Elementor** - Builder scripts excluded from aggregation.
|
||||
|
||||
You'll see a list of detected plugins and applied protections on the settings page.
|
||||
|
||||
= Is Maple Performance GDPR compliant? =
|
||||
|
||||
Yes. Maple Performance WP is designed with privacy in mind:
|
||||
|
||||
* **No personal data collection** - The plugin does not collect, store, or process any personal data such as IP addresses, email addresses, names, or user identifiers.
|
||||
* **No cookies set** - The plugin does not set any cookies. It only reads existing cookies (like WordPress login or WooCommerce cart cookies) to determine whether to serve cached content.
|
||||
* **No external connections** - The plugin does not connect to any external services or transmit any data to third parties. All processing happens locally on your server.
|
||||
* **No tracking or analytics** - There is no usage tracking, telemetry, or analytics of any kind.
|
||||
* **Logged-in users excluded** - By default, pages are not cached for logged-in users, ensuring no user-specific content is stored.
|
||||
|
||||
The plugin automatically adds suggested text to your Privacy Policy page (Settings → Privacy) explaining its data practices.
|
||||
|
||||
= What data does the cache store? =
|
||||
|
||||
The cache stores only:
|
||||
|
||||
1. **Static HTML files** - Copies of your publicly-visible pages (the same content any visitor would see)
|
||||
2. **Aggregated CSS/JS files** - Combined and minified versions of your theme/plugin assets
|
||||
|
||||
No personal data, user information, or tracking data is ever stored in the cache.
|
||||
|
||||
= What PageSpeed scores can I expect? =
|
||||
|
||||
* Brochure sites: 80-95
|
||||
* WooCommerce sites: 70-85
|
||||
* LearnDash sites: 70-85
|
||||
* WooCommerce + LearnDash: 65-80
|
||||
|
||||
The conservative settings for ecommerce and LMS sites prioritize functionality over scores.
|
||||
|
||||
== Changelog ==
|
||||
|
||||
= 1.0.0 =
|
||||
* Initial release
|
||||
* Page caching with Gzip/Brotli support
|
||||
* HTML, CSS, and JS minification
|
||||
* CSS and JS aggregation
|
||||
* Google Fonts optimization (combine, display:swap, defer)
|
||||
* Lazy loading for images and iframes
|
||||
* Site mode presets for WooCommerce and LearnDash
|
||||
* Automatic plugin compatibility for WooCommerce, LearnDash, WPForms, Wordfence, Gravity Forms, Contact Form 7, Elementor
|
||||
* DNS prefetch and preconnect support
|
||||
* Emoji removal
|
||||
* Query string removal
|
||||
|
||||
== Upgrade Notice ==
|
||||
|
||||
= 1.0.0 =
|
||||
Initial release of Maple Performance WP.
|
||||
68
native/wordpress/maple-performance-wp/uninstall.php
Normal file
68
native/wordpress/maple-performance-wp/uninstall.php
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
/**
|
||||
* Uninstall Maple Performance WP
|
||||
*
|
||||
* Removes all plugin data when uninstalled.
|
||||
*
|
||||
* @package MaplePerformance
|
||||
*/
|
||||
|
||||
// Exit if not called by WordPress
|
||||
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Delete options
|
||||
delete_option( 'maple_performance_settings' );
|
||||
|
||||
// Delete cache directory
|
||||
$cache_dir = WP_CONTENT_DIR . '/cache/maple-performance/';
|
||||
|
||||
// Verify path is valid and within wp-content
|
||||
$real_cache_dir = realpath( $cache_dir );
|
||||
$real_content_dir = realpath( WP_CONTENT_DIR );
|
||||
|
||||
if ( $real_cache_dir && $real_content_dir && strpos( $real_cache_dir, $real_content_dir ) === 0 ) {
|
||||
if ( is_dir( $cache_dir ) ) {
|
||||
$files = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator( $cache_dir, RecursiveDirectoryIterator::SKIP_DOTS ),
|
||||
RecursiveIteratorIterator::CHILD_FIRST
|
||||
);
|
||||
|
||||
foreach ( $files as $file ) {
|
||||
$file_path = $file->getRealPath();
|
||||
|
||||
// Verify each file is within cache directory
|
||||
if ( strpos( $file_path, $real_cache_dir ) !== 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $file->isDir() ) {
|
||||
@rmdir( $file_path );
|
||||
} else {
|
||||
@unlink( $file_path );
|
||||
}
|
||||
}
|
||||
|
||||
@rmdir( $cache_dir );
|
||||
}
|
||||
}
|
||||
|
||||
// Clear any transients using proper LIKE escaping
|
||||
global $wpdb;
|
||||
|
||||
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
|
||||
$wpdb->query(
|
||||
$wpdb->prepare(
|
||||
"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s",
|
||||
$wpdb->esc_like( '_transient_maple_perf_' ) . '%'
|
||||
)
|
||||
);
|
||||
|
||||
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
|
||||
$wpdb->query(
|
||||
$wpdb->prepare(
|
||||
"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s",
|
||||
$wpdb->esc_like( '_transient_timeout_maple_perf_' ) . '%'
|
||||
)
|
||||
);
|
||||
Loading…
Add table
Add a link
Reference in a new issue