Blog

Arquitectura de Hooks de WordPress: Acciones vs. Filtros Explicados

La base de todo gran plugin. Aprende cómo PAGEnza AI utiliza hooks y filtros para crear código mantenible y escalable.

Cada plugin de WordPress hace una de dos cosas: ejecuta código en un momento específico (acción) o modifica un valor antes de que se utilice (filtro). Eso es todo. Todo el ecosistema de plugins de WordPress se basa en esta distinción.

Comprender la diferencia —y cuándo usar cada uno— es lo que separa a los plugins que funcionan de los que causan problemas.

Acciones: hacer algo en un momento dado

Un hook de acción es una señal que WordPress (o otro plugin) envía en un momento específico. Adjuntas una función a esa señal, y tu función se ejecuta cuando la señal se dispara.

add_action( 'wp_enqueue_scripts', 'my_plugin_load_assets' );

function my_plugin_load_assets() {
    wp_enqueue_style( 'my-plugin', plugin_dir_url( __FILE__ ) . 'style.css' );
    wp_enqueue_script( 'my-plugin', plugin_dir_url( __FILE__ ) . 'script.js', ['jquery'], '1.0', true );
}

wp_enqueue_scripts se dispara cuando WordPress se prepara para cargar los assets del front-end. Engancharse a él es la forma correcta de cargar CSS y JS, no de insertar etiquetas <script> directamente en las plantillas.

Hooks de acción comunes que usarás constantemente:

  • init — se ejecuta temprano, bueno para registrar tipos de contenido y taxonomías
  • wp_enqueue_scripts — cargar assets del front-end
  • admin_enqueue_scripts — cargar assets del admin
  • save_post — se ejecuta cuando se guarda una entrada, bueno para procesar campos personalizados
  • wp_ajax_{action} — manejar solicitudes AJAX de usuarios autenticados
  • wp_ajax_nopriv_{action} — manejar AJAX de usuarios no registrados

Filtros: modificar un valor antes de que se utilice

Un hook de filtro te da un valor, te permite modificarlo y espera que devuelvas la versión modificada. WordPress luego usa tu valor modificado en lugar del original.

add_filter( 'the_content', 'my_plugin_append_cta' );

function my_plugin_append_cta( $content ) {
    if ( ! is_single() ) {
        return $content;
    }
    $cta = '<div class="post-cta">¿Listo para probar PAGEnza? <a href="#">Comienza gratis →</a></div>';
    return $content . $cta;
}

La regla crítica: siempre devuelve algo de un filtro. Si olvidas el return, el valor se vuelve nulo y habrás roto lo que sea que lo estuviera usando.

Hooks de filtro comunes:

  • the_content — el contenido de la entrada antes de mostrarse
  • the_title — el título de la entrada
  • wp_nav_menu_items — HTML del menú de navegación
  • upload_mimes — tipos de archivo permitidos para subir
  • plugin_action_links_{plugin-file} — enlaces que se muestran en la página de lista de plugins

Cómo PAGEnza AI utiliza los hooks

Cuando el Plugin Builder genera un plugin, estructura el código alrededor de una clase con métodos adjuntos a hooks en el constructor. Este patrón evita colisiones de nombres de funciones globales y mantiene el código organizado.

class My_Plugin {
    public function __construct() {
        add_action( 'init', [ $this, 'register_post_type' ] );
        add_action( 'wp_enqueue_scripts', [ $this, 'load_assets' ] );
        add_filter( 'the_content', [ $this, 'append_content' ] );
    }

    public function register_post_type() { /* ... */ }
    public function load_assets() { /* ... */ }
    public function append_content( $content ) {
        // siempre devuelve
        return $content;
    }
}

new My_Plugin();

El escaneo de seguridad comprueba específicamente que los manejadores AJAX incluyan una verificación de nonce y una verificación de capacidades antes de hacer nada:

add_action( 'wp_ajax_my_action', [ $this, 'handle_ajax' ] );

public function handle_ajax() {
    // Seguridad: verificar nonce
    check_ajax_referer( 'my_nonce_action', 'nonce' );

    // Seguridad: verificar permisos
    if ( ! current_user_can( 'manage_options' ) ) {
        wp_send_json_error( 'Permisos insuficientes', 403 );
    }

    // Ahora es seguro procesar
    $data = sanitize_text_field( $_POST['data'] ?? '' );
    wp_send_json_success( [ 'result' => $data ] );
}

La falta de cualquiera de estas es marcada como un problema de seguridad y bloquea la publicación del plugin.

Prioridad y la cola de hooks

Cuando múltiples funciones están adjuntas al mismo hook, se ejecutan en orden de prioridad (número menor = se ejecuta primero). La prioridad por defecto es 10.

add_action( 'init', 'runs_first', 5 );
add_action( 'init', 'runs_second', 10 );   // por defecto
add_action( 'init', 'runs_last', 20 );

Esto importa cuando tu plugin necesita ejecutarse antes o después del código de otro plugin. Si estás modificando algo que otro plugin también modifica, la prioridad controla quién gana.

Un patrón común: si estás sobrescribiendo el filtro de un tema, usa la prioridad 20 o superior para asegurarte de que se ejecuta después del código del tema.

Eliminar hooks

Puedes eliminar un hook que alguien más agregó —incluyendo hooks de temas y plugins:

remove_action( 'wp_head', 'wp_generator' );  // elimina la versión de WP de <head>
remove_filter( 'the_content', 'wpautop' );   // elimina el envoltorio automático de párrafos

La trampa: solo puedes eliminar un hook si llamas a remove_action/remove_filter después de que el add_action/add_filter original se haya ejecutado. Esto usualmente significa enganchar tu eliminación a una acción posterior.