/** * Plugin Must-Use: Solución OPTIMIZADA para el conflicto blog ID 45 * * Versión: 3.2 - Performance-first con interceptación quirúrgica * Descripción: Previene blog_id 45 con CERO impacto cuando no hay problema. * * ESTRATEGIA DE RENDIMIENTO V3.2: * 1. Detección temprana: Solo actúa si detecta blog 45 * 2. Cache de queries: No reprocesa queries ya vistas * 3. Hooks condicionales: Solo se activan si hay problema * 4. Zero logging en producción salvo errores críticos * * @package Cambra_WordPress_Project */ if ( ! defined( 'ABSPATH' ) ) { exit; } final class Cambra_Multisite_Fix_V32 { private static $main_site_id = null; private static $problem_detected = false; private static $in_switch = false; private static $query_cache = array(); private static $max_cache_size = 100; /** * Inicialización mínima - solo hooks críticos */ public static function init() { self::$main_site_id = get_main_site_id(); // ÚNICO HOOK PERMANENTE: Interceptar switch_to_blog // Este es el único que DEBE estar siempre activo add_action( 'switch_blog', array( __CLASS__, 'intercept_switch' ), 1, 2 ); // Hook de respaldo para get_blog_details (muy ligero) add_filter( 'pre_get_blog_details', array( __CLASS__, 'check_blog_45' ), 1, 2 ); // Los demás hooks se activan SOLO si detectamos el problema // Esto ahorra procesamiento en el 99% de los requests } /** * Interceptar switch - ÚNICA protección permanente * * @param int $new_blog_id Blog destino * @param int $prev_blog_id Blog anterior */ public static function intercept_switch( $new_blog_id, $prev_blog_id ) { // Fast path: Si no es blog 45, salir inmediatamente (caso 99%) if ( 45 !== (int) $new_blog_id ) { return; } // Prevenir recursión if ( self::$in_switch ) { return; } // PROBLEMA DETECTADO - Activar protecciones adicionales if ( ! self::$problem_detected ) { self::$problem_detected = true; self::activate_full_protection(); } // Verificar si el blog existe (solo una vez) static $blog_45_exists = null; if ( null === $blog_45_exists ) { global $wpdb; $blog_45_exists = (bool) $wpdb->get_var( $wpdb->prepare( "SELECT blog_id FROM {$wpdb->blogs} WHERE blog_id = %d", 45 ) ); } if ( $blog_45_exists ) { return; // El sitio existe, permitir } // BLOQUEAR: Revertir al blog anterior o principal self::$in_switch = true; $safe_blog_id = $prev_blog_id ? $prev_blog_id : self::$main_site_id; switch_to_blog( $safe_blog_id ); self::$in_switch = false; // Log SOLO en modo debug if ( defined( 'WP_DEBUG' ) && WP_DEBUG && defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) { error_log( sprintf( '[BLOG45 FIX] Blocked switch to blog 45 (from %d, reverted to %d)', $prev_blog_id, $safe_blog_id ) ); } } /** * Check ligero de get_blog_details */ public static function check_blog_45( $blog_details, $blog_id ) { if ( 45 === (int) $blog_id ) { // Activar protección completa if ( ! self::$problem_detected ) { self::$problem_detected = true; self::activate_full_protection(); } return get_blog_details( self::$main_site_id ); } return $blog_details; } /** * Activar protecciones adicionales SOLO cuando hay problema */ private static function activate_full_protection() { // Hook de query con cache para evitar reprocesamiento add_filter( 'query', array( __CLASS__, 'cached_query_fix' ), 1, 1 ); // Hooks de plugins SOLO si están activos if ( self::is_plugin_active( 'sitepress-multilingual-cms/sitepress.php' ) ) { self::activate_wpml_protection(); } if ( self::is_plugin_active( 'elasticpress/elasticpress.php' ) ) { self::activate_ep_protection(); } // Log una sola vez if ( defined( 'WP_DEBUG' ) && WP_DEBUG && defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) { error_log( '[BLOG45 FIX] Problem detected - Full protection activated' ); } } /** * Fix de queries con CACHE para evitar reprocesamiento * * @param string $query Query SQL * * @return string */ public static function cached_query_fix( $query ) { // Fast path: Si no contiene wp_45_, salir inmediatamente if ( false === strpos( $query, 'wp_45_' ) ) { return $query; } // Check cache primero $query_hash = md5( $query ); if ( isset( self::$query_cache[ $query_hash ] ) ) { return self::$query_cache[ $query_hash ]; } // Reemplazar tablas global $wpdb; $main_prefix = $wpdb->get_blog_prefix( self::$main_site_id ); $fixed_query = preg_replace( '/`?' . preg_quote( $wpdb->base_prefix, '/' ) . '45_(\w+)`?/i', $main_prefix . '$1', $query ); // Guardar en cache (con límite de tamaño) if ( count( self::$query_cache ) < self::$max_cache_size ) { self::$query_cache[ $query_hash ] = $fixed_query; } return $fixed_query; } /** * Protección específica de WPML (solo si es necesario) */ private static function activate_wpml_protection() { // Limpiar configuración una sola vez add_action( 'wpml_loaded', array( __CLASS__, 'cleanup_wpml_once' ), 1 ); // Interceptar settings en tiempo real add_filter( 'wpml_get_setting', array( __CLASS__, 'fix_wpml_setting' ), 1, 2 ); // CRÍTICO: NO usar ensure_correct_context en hooks de WPML // Eso causa los bloqueos que mencionas en páginas de idiomas // En su lugar, solo filtrar valores problemáticos } /** * Limpiar configuración WPML UNA SOLA VEZ */ public static function cleanup_wpml_once() { // Verificar si ya se limpió antes (usar transient) if ( get_transient( 'blog45_wpml_cleaned' ) ) { return; } $settings = get_option( 'icl_sitepress_settings' ); if ( ! is_array( $settings ) ) { return; } $modified = false; // Limpiar blog_relationships if ( isset( $settings['blog_relationships'][45] ) ) { unset( $settings['blog_relationships'][45] ); $modified = true; } // Buscar referencias a blog 45 array_walk_recursive( $settings, function ( &$value, $key ) use ( &$modified ) { if ( ( 45 === $value || '45' === $value ) && ( false !== stripos( $key, 'blog' ) || false !== stripos( $key, 'site' ) ) ) { $value = get_main_site_id(); $modified = true; } } ); if ( $modified ) { update_option( 'icl_sitepress_settings', $settings ); wp_cache_delete( 'icl_sitepress_settings', 'options' ); // Marcar como limpiado (válido 1 semana) set_transient( 'blog45_wpml_cleaned', true, WEEK_IN_SECONDS ); if ( defined( 'WP_DEBUG' ) && WP_DEBUG && defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) { error_log( '[BLOG45 FIX] WPML configuration cleaned successfully' ); } } } /** * Filtrar setting de WPML (muy ligero) */ public static function fix_wpml_setting( $value, $key ) { // Solo actuar en valores específicamente problemáticos if ( 45 === $value || '45' === $value ) { return self::$main_site_id; } if ( is_array( $value ) && isset( $value[45] ) ) { unset( $value[45] ); } return $value; } /** * Protección específica de ElasticPress */ private static function activate_ep_protection() { // Filtrar sitios indexables add_filter( 'ep_indexable_sites', array( __CLASS__, 'filter_ep_sites' ), 1 ); // Fix de nombres de índice add_filter( 'ep_index_name', array( __CLASS__, 'fix_ep_index' ), 1, 3 ); } /** * Filtrar sitios EP (muy ligero) */ public static function filter_ep_sites( $sites ) { if ( ! is_array( $sites ) ) { return $sites; } return array_filter( $sites, function ( $site ) { $blog_id = is_array( $site ) ? ( $site['blog_id'] ?? 0 ) : 0; return 45 !== (int) $blog_id; } ); } /** * Fix de índice EP (muy ligero) */ public static function fix_ep_index( $index_name, $blog_id, $indexable ) { // Si es cluster ID (hash largo), dejarlo if ( preg_match( '/[a-f0-9]{8,}/', $index_name ) ) { return $index_name; } // Si es blog 45, reemplazar if ( 45 === (int) $blog_id ) { return str_replace( '-45-', '-' . self::$main_site_id . '-', $index_name ); } return $index_name; } /** * Helper: Verificar plugin activo (con cache estática) */ private static function is_plugin_active( $plugin ) { static $cache = array(); if ( isset( $cache[ $plugin ] ) ) { return $cache[ $plugin ]; } if ( ! function_exists( 'is_plugin_active' ) ) { include_once ABSPATH . 'wp-admin/includes/plugin.php'; } $cache[ $plugin ] = is_plugin_active( $plugin ); return $cache[ $plugin ]; } } // Inicializar con overhead mínimo Cambra_Multisite_Fix_V32::init();