state = new Consent_State();
$this->log = new Consent_Log();
$this->banner = new Banner( $this->state );
$this->blocker = new Script_Blocker();
$this->consent_mode = new Consent_Mode();
$this->rights = new Rights();
$this->transfers = new Transfers();
$this->rat = new Rat();
$this->diagnostics = new Diagnostics();
$this->forms = new Forms();
$this->provision = new Provision();
}
/** Engancha todos los módulos. */
public function run(): void {
// Las tablas de este plugin pueden crecer entre versiones: dbDelta vuelve a correr
// cuando cambia la versión del esquema, no solo al activar.
if ( get_option( Rights::SCHEMA_OPT ) !== Rights::SCHEMA_VERSION ) {
Rights::install();
}
if ( get_option( Consent_Log::SCHEMA_OPT ) !== Consent_Log::SCHEMA_VERSION ) {
Consent_Log::install();
}
// Las versiones anteriores guardaban todo con el prefijo corto “ccn_”, que no
// cumple el mínimo de cuatro caracteres que pide el directorio: se traslada
// una sola vez, conservando los valores (sobre todo la sal del registro).
if ( '1' !== get_option( 'cumpleconsent_migrated' ) ) {
self::migrate_legacy_names();
update_option( 'cumpleconsent_migrated', '1' );
}
// La opción se registra en `init` (no en `admin_init`): las peticiones REST
// no pasan por `admin_init` y la configuración tiene que estar disponible
// para /wp/v2/settings, que es la vía de aprovisionamiento por contraseña
// de aplicación.
add_action( 'init', array( 'CumpleConsent\\Settings', 'register' ) );
$this->state->hook();
$this->consent_mode->hook();
$this->blocker->hook();
$this->banner->hook();
$this->rights->hook();
$this->transfers->hook();
$this->forms->hook();
$this->provision->hook();
add_action( CUMPLECONSENT_CRON_PURGE, array( $this->log, 'purge' ) );
add_action( 'admin_notices', array( $this, 'admin_notices' ) );
if ( is_admin() ) {
$this->admin = new Admin();
$this->admin->hook();
}
}
/** Avisos de configuración pendiente (solo administradores). */
public function admin_notices(): void {
if ( ! current_user_can( CUMPLECONSENT_CAP ) ) {
return;
}
$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
if ( $screen && false !== strpos( (string) $screen->id, 'cumpleconsent' ) ) {
return; // En las pantallas del plugin ya se muestra todo el contexto.
}
if ( ! Settings::is_ready() ) {
printf(
'
',
esc_html__( 'falta completar la identidad del responsable y activar el aviso de privacidad.', 'cumpleconsent' ),
esc_url( admin_url( 'admin.php?page=cumpleconsent-ajustes' ) ),
esc_html__( 'Configurar ahora', 'cumpleconsent' )
);
return;
}
if ( '' === Policy::url() ) {
printf(
'',
esc_html__( 'el aviso está activo pero no hay política de privacidad publicada ni enlazada (art. 14 ter).', 'cumpleconsent' ),
esc_url( admin_url( 'admin.php?page=cumpleconsent-documentos' ) ),
esc_html__( 'Generar la política', 'cumpleconsent' )
);
}
}
/**
* Traslada lo guardado con el prefijo corto anterior.
*
* Cambiar el prefijo es obligatorio para el directorio, pero no puede costarle
* datos a quien ya tenía el plugin instalado: opciones, tablas, el metadato de
* la política y las tareas programadas se mueven conservando su contenido.
*/
public static function migrate_legacy_names(): void {
global $wpdb;
$opciones = array(
'ccn_settings' => 'cumpleconsent_settings',
'ccn_log_salt' => 'cumpleconsent_log_salt',
'ccn_requests_schema' => 'cumpleconsent_requests_schema',
'ccn_log_schema' => 'cumpleconsent_log_schema',
);
foreach ( $opciones as $viejo => $nuevo ) {
$valor = get_option( $viejo );
if ( false === $valor ) {
continue;
}
if ( false === get_option( $nuevo ) ) {
update_option( $nuevo, $valor );
}
delete_option( $viejo );
}
$tablas = array(
'ccn_requests' => 'cumpleconsent_requests',
'ccn_consent_log' => 'cumpleconsent_consent_log',
);
foreach ( $tablas as $viejo => $nuevo ) {
$t_vieja = $wpdb->prefix . $viejo;
$t_nueva = $wpdb->prefix . $nuevo;
$hay_vieja = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $t_vieja ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
$hay_nueva = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $t_nueva ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
if ( $hay_vieja && ! $hay_nueva ) {
$wpdb->query( "RENAME TABLE `{$t_vieja}` TO `{$t_nueva}`" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL, PluginCheck.Security.DirectDB.UnescapedDBParameter -- El nombre de la tabla se arma con $wpdb->prefix y un sufijo literal del plugin; no entra nada del visitante.
}
}
$meta = $wpdb->prefix . 'postmeta';
$wpdb->query( "UPDATE `{$meta}` SET meta_key = '_cumpleconsent_generated' WHERE meta_key = '_ccn_generated'" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL, PluginCheck.Security.DirectDB.UnescapedDBParameter -- La tabla se arma con $wpdb->prefix y las claves son literales; no entra nada del visitante.
wp_clear_scheduled_hook( 'ccn_daily_maintenance' );
wp_clear_scheduled_hook( 'ccn_check_deadlines' );
}
// ── Ciclo de vida ────────────────────────────────────────────────────────
/** Activación: tablas, opciones base y tareas programadas. */
public static function on_activate(): void {
Consent_Log::install();
Rights::install();
Settings::log_salt();
$all = Settings::all();
if ( empty( $all['installed_at'] ) ) {
Settings::save(
array(
'installed_at' => current_time( 'mysql', true ),
'wp_version' => get_bloginfo( 'version' ),
)
);
}
if ( ! wp_next_scheduled( CUMPLECONSENT_CRON_PURGE ) ) {
wp_schedule_event( time() + HOUR_IN_SECONDS, 'daily', CUMPLECONSENT_CRON_PURGE );
}
if ( ! wp_next_scheduled( CUMPLECONSENT_CRON_DEADLINES ) ) {
wp_schedule_event( time() + ( 2 * HOUR_IN_SECONDS ), 'daily', CUMPLECONSENT_CRON_DEADLINES );
}
}
/** Desactivación: se quitan las tareas y se conservan los datos. */
public static function on_deactivate(): void {
wp_clear_scheduled_hook( CUMPLECONSENT_CRON_PURGE );
wp_clear_scheduled_hook( CUMPLECONSENT_CRON_DEADLINES );
}
/**
* Purga las cachés de página conocidas.
*
* Necesario porque el aviso y su versión viajan en el HTML: si el sitio
* sirve una página cacheada con la versión anterior, el visitante no ve el
* aviso nuevo. Se llama al guardar ajustes que cambian el aviso.
*
* @return string[] Cachés purgadas.
*/
public static function purge_caches(): array {
$done = array();
if ( function_exists( 'rocket_clean_domain' ) ) {
rocket_clean_domain();
$done[] = 'WP Rocket';
}
if ( function_exists( 'wp_cache_clear_cache' ) ) {
wp_cache_clear_cache();
$done[] = 'WP Super Cache';
}
if ( function_exists( 'w3tc_flush_all' ) ) {
w3tc_flush_all();
$done[] = 'W3 Total Cache';
}
if ( function_exists( 'wpfc_clear_all_cache' ) ) {
wpfc_clear_all_cache( true );
$done[] = 'WP Fastest Cache';
}
if ( has_action( 'litespeed_purge_all' ) ) {
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- litespeed_purge_all es el hook de LiteSpeed Cache: hay que invocarlo con su nombre exacto, y solo si alguien lo escucha (lo comprueba has_action).
do_action( 'litespeed_purge_all' );
$done[] = 'LiteSpeed Cache';
}
if ( function_exists( 'cache_enabler_clear_complete_cache' ) ) {
cache_enabler_clear_complete_cache();
$done[] = 'Cache Enabler';
}
if ( function_exists( 'wp_cache_flush' ) ) {
wp_cache_flush();
$done[] = 'Caché de objetos';
}
return $done;
}
}