| Server IP : 156.67.83.116 / Your IP : 216.73.217.130 Web Server : Apache System : Linux vmi1896282.contaboserver.net 5.10.0-33-amd64 #1 SMP Debian 5.10.226-1 (2024-10-03) x86_64 User : maltem.ma ( 10009) PHP Version : 8.3.33 Disable Function : opcache_get_status MySQL : OFF | cURL : ON | WGET : OFF | Perl : OFF | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : /var/www/vhosts/maltem.ma/preprodonhym.maltem.ma/wp-content/mu-plugins/ |
Upload File : |
<?php
/**
* Plugin Name: Fast Page Cache
* Description: Cache de page ultra-rapide pour les pages statiques lentes (Redis).
* Sert le HTML mis en cache avant le chargement d'Elementor.
* Version: 1.0.0
* Author: ONHYM / Maltem
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
define( 'FPC_CACHE_TTL', 7200 ); // 2 heures
define( 'FPC_REDIS_HOST', '127.0.0.1' );
define( 'FPC_REDIS_PORT', 6379 );
define( 'FPC_REDIS_DB', 1 ); // DB séparée pour ne pas mélanger avec W3TC (DB 0)
define( 'FPC_REDIS_KEY_PRE', 'fpc:' );
define( 'FPC_BYPASS_COOKIE', 'wordpress_logged_in' ); // ne pas cacher si connecté
/**
* Connexion Redis partagée (singleton).
*/
function fpc_redis(): ?Redis {
static $redis = null;
if ( $redis !== null ) {
return $redis;
}
if ( ! extension_loaded( 'redis' ) ) {
return null;
}
try {
$r = new Redis();
if ( ! $r->connect( FPC_REDIS_HOST, FPC_REDIS_PORT, 1.0 ) ) {
return null;
}
$r->select( FPC_REDIS_DB );
$redis = $r;
} catch ( Exception $e ) {
return null;
}
return $redis;
}
/**
* Construit la clé de cache pour l'URL courante.
*/
function fpc_cache_key(): string {
$scheme = ( isset( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] !== 'off' ) ? 'https' : 'http';
$host = $_SERVER['HTTP_HOST'] ?? 'localhost';
$uri = strtok( $_SERVER['REQUEST_URI'] ?? '/', '?' );
return FPC_REDIS_KEY_PRE . md5( $scheme . '://' . $host . $uri );
}
/**
* Détermine si la requête peut être servie depuis le cache.
*/
function fpc_is_cacheable(): bool {
// Seulement GET
if ( ( $_SERVER['REQUEST_METHOD'] ?? 'GET' ) !== 'GET' ) {
return false;
}
// Pas de query string (sauf aaeid qui ne change pas le contenu)
$qs = $_SERVER['QUERY_STRING'] ?? '';
if ( $qs !== '' ) {
// Autorise uniquement aaeid (Animation Addons Elementor ID) et la langue
$allowed = ['aaeid', 'lang'];
parse_str( $qs, $params );
foreach ( array_keys( $params ) as $key ) {
if ( ! in_array( $key, $allowed, true ) ) {
return false;
}
}
}
// Pas connecté (vérifie les cookies)
foreach ( array_keys( $_COOKIE ) as $name ) {
if ( str_starts_with( $name, FPC_BYPASS_COOKIE ) ) {
return false;
}
}
// Pas de requête admin/preview/cron
if ( str_contains( $_SERVER['REQUEST_URI'] ?? '', 'wp-admin' ) ) {
return false;
}
if ( isset( $_GET['preview'] ) || isset( $_GET['elementor-preview'] ) ) {
return false;
}
return true;
}
/* ══════════════════════════════════════════════════════════════════════
* PHASE 1 — Lecture du cache AVANT WordPress (via advanced-cache.php)
* Cette partie est exécutée très tôt depuis wp-content/advanced-cache.php
* ══════════════════════════════════════════════════════════════════════ */
function fpc_serve_if_cached(): void {
if ( ! fpc_is_cacheable() ) {
return;
}
$redis = fpc_redis();
if ( ! $redis ) {
return;
}
$cached = $redis->get( fpc_cache_key() );
if ( $cached === false ) {
return;
}
// Sert directement la page cachée
header( 'Content-Type: text/html; charset=UTF-8' );
header( 'X-FPC-Cache: HIT' );
header( 'X-FPC-Cached-At: ' . gmdate( 'D, d M Y H:i:s', (int) $redis->get( fpc_cache_key() . ':ts' ) ) . ' GMT' );
echo $cached;
exit;
}
/* ══════════════════════════════════════════════════════════════════════
* PHASE 2 — Écriture du cache APRÈS rendu (hook WordPress)
* ══════════════════════════════════════════════════════════════════════ */
add_action( 'init', function () {
if ( ! fpc_is_cacheable() ) {
return;
}
ob_start( 'fpc_ob_callback' );
} );
function fpc_ob_callback( string $buffer ): string {
// Ne cache que les pages HTML complètes avec </html>
if ( ! str_contains( $buffer, '</html>' ) ) {
return $buffer;
}
// Ne cache pas les pages d'erreur
$status = http_response_code();
if ( $status !== 200 ) {
return $buffer;
}
// Ne cache pas si WordPress l'interdit
if ( defined( 'DONOTCACHEPAGE' ) && DONOTCACHEPAGE ) {
return $buffer;
}
$redis = fpc_redis();
if ( ! $redis ) {
return $buffer;
}
$key = fpc_cache_key();
$redis->setEx( $key, FPC_CACHE_TTL, $buffer );
$redis->setEx( $key . ':ts', FPC_CACHE_TTL, (string) time() );
// Ajoute un commentaire HTML invisible pour debug
return $buffer . "\n<!-- FPC MISS: cached at " . gmdate( 'Y-m-d H:i:s' ) . " UTC -->\n";
}
/* ══════════════════════════════════════════════════════════════════════
* Purge du cache quand une page/post est mis à jour
* ══════════════════════════════════════════════════════════════════════ */
add_action( 'save_post', 'fpc_purge_post', 10, 1 );
add_action( 'elementor/editor/after_save', 'fpc_purge_post', 10, 1 );
function fpc_purge_post( int $post_id ): void {
$permalink = get_permalink( $post_id );
if ( ! $permalink ) {
return;
}
$redis = fpc_redis();
if ( ! $redis ) {
return;
}
$scheme = str_starts_with( $permalink, 'https' ) ? 'https' : 'http';
$parts = parse_url( $permalink );
$uri = $parts['path'] ?? '/';
$host = $parts['host'] ?? ( $_SERVER['HTTP_HOST'] ?? 'localhost' );
$key = FPC_REDIS_KEY_PRE . md5( $scheme . '://' . $host . $uri );
$redis->del( $key, $key . ':ts' );
}
/**
* Purge manuelle — utilisée par le cron ou l'admin.
*/
function fpc_purge_all(): void {
$redis = fpc_redis();
if ( ! $redis ) {
return;
}
$keys = $redis->keys( FPC_REDIS_KEY_PRE . '*' );
if ( ! empty( $keys ) ) {
$redis->del( ...$keys );
}
}
// Purge auto toutes les 2 heures via WP-Cron
add_action( 'fpc_scheduled_purge', 'fpc_purge_all' );
if ( ! wp_next_scheduled( 'fpc_scheduled_purge' ) ) {
wp_schedule_event( time(), 'twicedaily', 'fpc_scheduled_purge' );
}