Como listar todas las funciones enganchadas en WordPress
ES

Como listar todas las funciones enganchadas en WordPress

Última verificación: 17 de agosto de 2026
19 min de lectura
Guía
Desarrollador full-stack

WordPress funciona con Hooks (Acciones y Filtros). A veces, cosas inesperadas suceden: el contenido desaparece, los títulos cambian, los estilos se rompen. Sospecha que un plugin está interfiriendo, pero cual?

Conozca más sobre el desarrollo profesional de WordPress en WPPoland.

Necesita saber exactamente que funciones están adjuntas a un hook específico (ej. the_content o wp_head).

La forma más rápida de depurar eso es inspeccionar $wp_filter, listar callbacks por prioridad y rastrear si cada callback proviene del core, un plugin o el tema activo.

#El sistema de hooks de WordPress: entendiendo la base

El sistema de hooks de WordPress es lo que lo hace extensible. Cada función importante en WordPress dispara hooks, permitiendo que plugins y temas modifiquen el comportamiento sin editar archivos del core.

Dos tipos de hooks:

  1. Acciones: Hacen algo en un punto específico (ej. wp_head, the_content)
  2. Filtros: Modifican datos antes de que se usen (ej. the_title, the_content)

Al depurar, necesita ver:

  • Que funciones están enganchadas
  • Sus prioridades (orden de ejecución)
  • Que plugin/tema las agrego
  • Los nombres de las funciones callback

#Qué guarda realmente $wp_filter

Antes de leer una tabla de callbacks conviene saber qué está leyendo. Desde WordPress 4.7, cada entrada de $wp_filter no es un array sino un objeto WP_Hook, definido en wp-includes/class-wp-hook.php. Esa clase implementa Iterator y ArrayAccess, lo que mantiene la compatibilidad con los snippets anteriores a esa versión, que recorrían $wp_filter['the_content'] con foreach como si fuera un array.

La compatibilidad tiene un límite: las funciones de PHP que reciben el array por referencia fallan sobre un objeto. Por eso el snippet de este artículo hace ksort( $hook_data->callbacks ) y no ksort( $wp_filter[ $hook_name ] ). Si copia un snippet antiguo y ve un error de ksort() quejándose de haber recibido un objeto donde esperaba un array (must be of type array, WP_Hook given en PHP 8), esa es la causa exacta. WP_Hook tampoco implementa Countable, así que count( $wp_filter[ $hook_name ] ) no devuelve el número de callbacks registrados: hay que contar sobre ->callbacks.

La estructura interna tiene tres niveles:

  1. $wp_filter[ $hook ] es el objeto WP_Hook.
  2. $wp_filter[ $hook ]->callbacks es un array indexado por prioridad (entero).
  3. Cada prioridad contiene un array indexado por un identificador único, con la forma array( 'function' => $callable, 'accepted_args' => int ).

Ese identificador lo genera _wp_filter_build_unique_id(). Para una función global es el propio nombre. Para un método estático es Clase::metodo. Para un método de instancia es el hash del objeto concatenado con el nombre del método, y ese hash cambia en cada petición. Esto explica por qué no se puede guardar el identificador de un callback de objeto en una opción y reutilizarlo después: solo es válido dentro de la misma ejecución de PHP.

accepted_args decide cuántos argumentos recibe el callback, y el fallo va en la dirección contraria a la que se suele suponer. Pasar de más es inofensivo: con add_filter( 'the_content', 'mi_funcion', 10, 2 ) y una función que declara un solo parámetro, PHP descarta el segundo y el filtro sigue funcionando. Pasar de menos rompe la petición: con add_filter( 'the_content', 'mi_funcion', 10, 1 ) y una firma mi_funcion( $contenido, $extra ) sin valor por defecto, PHP lanza ArgumentCountError: Too few arguments, que desde PHP 7.1 es un error fatal y no el aviso que era antes. Cuando una entrada deja de renderizarse tras tocar un filtro, comparar accepted_args con la firma real de la función suele ser más rápido que leer el stack trace.

#El snippet de depuración completo

Agregue esta función mejorada a su functions.php o úsela en un plugin Must-Use durante el desarrollo:

/**
 * Inspeccionar hooks de WordPress con información detallada
 *
 * @param string $hook_name El hook a inspeccionar (ej. 'the_content', 'wp_head')
 * @param bool $show_details Mostrar detalles completos del callback
 * @return void
 */
function wppoland_inspect_hook( $hook_name, $show_details = false ) {
    global $wp_filter;

    if ( ! isset( $wp_filter[ $hook_name ] ) ) {
        echo '<div style="background:#fff3cd; border:2px solid #ffc107; padding:15px; margin:20px 0;">';
        echo "<strong>El hook '$hook_name' no tiene funciones adjuntas.</strong>";
        echo '</div>';
        return;
    }

    $hook_data = $wp_filter[ $hook_name ];

    echo '<div style="background:#fff; border:2px solid #dc3545; padding:20px; margin:20px 0; font-family:monospace; font-size:12px; max-width:100%; overflow-x:auto;">';
    echo "<h2 style='margin-top:0; color:#dc3545;'>Depurando Hook: <code>$hook_name</code></h2>";

    // Ordenar por prioridad
    ksort( $hook_data->callbacks );

    echo '<table style="width:100%; border-collapse:collapse;">';
    echo '<thead><tr style="background:#f8f9fa;"><th style="padding:8px; text-align:left; border:1px solid #dee2e6;">Prioridad</th><th style="padding:8px; text-align:left; border:1px solid #dee2e6;">Funcion</th><th style="padding:8px; text-align:left; border:1px solid #dee2e6;">Fuente</th></tr></thead>';
    echo '<tbody>';

    foreach ( $hook_data->callbacks as $priority => $callbacks ) {
        foreach ( $callbacks as $callback ) {
            $function_name = 'Desconocido';
            $source_file = 'Desconocido';

            if ( is_string( $callback['function'] ) ) {
                $function_name = $callback['function'];
                if ( function_exists( $function_name ) ) {
                    $reflection = new ReflectionFunction( $function_name );
                    $source_file = $reflection->getFileName() . ':' . $reflection->getStartLine();
                }
            } elseif ( is_array( $callback['function'] ) ) {
                if ( is_object( $callback['function'][0] ) ) {
                    $function_name = get_class( $callback['function'][0] ) . '::' . $callback['function'][1];
                } else {
                    $function_name = $callback['function'][0] . '::' . $callback['function'][1];
                }

                try {
                    $reflection = new ReflectionMethod( $callback['function'][0], $callback['function'][1] );
                    $source_file = $reflection->getFileName() . ':' . $reflection->getStartLine();
                } catch ( ReflectionException $e ) {
                    $source_file = 'No se pudo determinar';
                }
            } elseif ( is_object( $callback['function'] ) ) {
                $function_name = 'Closure';
                $reflection = new ReflectionFunction( $callback['function'] );
                $source_file = $reflection->getFileName() . ':' . $reflection->getStartLine();
            }

            // Detectar plugin/tema
            $source_type = 'Core';
            if ( strpos( $source_file, 'wp-content/plugins' ) !== false ) {
                $source_type = 'Plugin';
            } elseif ( strpos( $source_file, 'wp-content/themes' ) !== false ) {
                $source_type = 'Tema';
            }

            echo '<tr style="border-bottom:1px solid #dee2e6;">';
            echo '<td style="padding:8px; border:1px solid #dee2e6;"><strong>' . esc_html( $priority ) . '</strong></td>';
            echo '<td style="padding:8px; border:1px solid #dee2e6;"><code>' . esc_html( $function_name ) . '</code></td>';
            echo '<td style="padding:8px; border:1px solid #dee2e6;"><span>' . esc_html( $source_type ) . '</span></td>';
            echo '</tr>';
        }
    }

    echo '</tbody></table>';
    echo '</div>';
}

// Ejemplos de uso:
// add_action( 'wp_footer', function(){ wppoland_inspect_hook('the_content'); } );
// add_action( 'wp_footer', function(){ wppoland_inspect_hook('wp_head', true); } );

#Cómo usar la función de depuración

#Uso básico

Agregue esto temporalmente a su functions.php:

// Inspeccionar el hook the_content
add_action( 'wp_footer', function() {
    if ( current_user_can( 'manage_options' ) ) { // Solo para admins
        wppoland_inspect_hook( 'the_content' );
    }
} );

Visite cualquier página y desplácese al footer. Vera una tabla detallada mostrando todas las funciones enganchadas a the_content.

#Inspeccionar múltiples hooks

add_action( 'wp_footer', function() {
    if ( ! current_user_can( 'manage_options' ) ) return;

    $hooks_a_verificar = array( 'the_content', 'wp_head', 'the_title', 'excerpt_length' );

    foreach ( $hooks_a_verificar as $hook ) {
        wppoland_inspect_hook( $hook );
    }
} );

#Cuando la tabla sale vacía o incompleta

$wp_filter no es un registro estático del sitio: es el estado de las suscripciones en el instante en que usted lo lee. Un callback que se registra dentro de otro hook no aparece si inspecciona antes de que ese hook se haya disparado. Es un fallo fácil de cometer y lleva al diagnóstico equivocado, porque la tabla parece completa.

Tres casos concretos:

  • Un plugin registra sus filtros dentro de init o de wp. Si vuelca la tabla en plugins_loaded, esos callbacks no existen todavía.
  • Un plugin llama a remove_filter() en template_redirect para desactivar algo del tema. Si vuelca en wp_footer, el callback eliminado ya no aparece y usted concluye que nunca estuvo.
  • Un callback solo se registra en el admin, dentro de admin_init. En una petición del front no estará, aunque sea el responsable del comportamiento que ve en el escritorio.

La comprobación que resuelve la ambigüedad es volcar el mismo hook en dos momentos y comparar:

add_action( 'plugins_loaded', function() {
    error_log( 'plugins_loaded: ' . wp_json_encode( array_keys( (array) $GLOBALS['wp_filter']['the_content']->callbacks ) ) );
}, PHP_INT_MAX );

add_action( 'wp_footer', function() {
    error_log( 'wp_footer: ' . wp_json_encode( array_keys( (array) $GLOBALS['wp_filter']['the_content']->callbacks ) ) );
}, PHP_INT_MAX );

Si las dos líneas de debug.log difieren, hay registro o eliminación tardía y necesita inspeccionar en el punto correcto. Para hooks del front, wp_footer con prioridad PHP_INT_MAX es el punto más tardío razonable. Para hooks del admin use admin_footer. Para hooks que se ejecutan antes de que exista salida HTML, como pre_get_posts, la única lectura fiable es la que escribe en error_log(), no la que imprime una tabla.

Otro caso de tabla vacía: el hook simplemente no tiene suscriptores porque escribió mal el nombre. the_excerpt y get_the_excerpt son hooks distintos, igual que wp_enqueue_scripts y admin_enqueue_scripts. Antes de dar por bueno un “no tiene funciones adjuntas”, confirme el nombre con has_filter( 'nombre_del_hook' ), que devuelve false cuando no hay nada registrado, o revise las claves reales con array_keys( $GLOBALS['wp_filter'] ) filtradas por una subcadena.

#Entendiendo la salida

#Columna de prioridad

WordPress ejecuta hooks en orden de prioridad (números menores primero). La prioridad predeterminada es 10.

Prioridades comunes:

  • 1-9: Ejecución temprana (antes del predeterminado)
  • 10: Prioridad predeterminada
  • 11-99: Ejecución tardía (después del predeterminado)
  • 999: Muy tardía (casi última)

#Empates de prioridad

Dos callbacks con la misma prioridad se ejecutan en el orden en que fueron registrados, que en la práctica es el orden de carga de los plugins. Ese orden lo determina la opción active_plugins, que WordPress reordena alfabéticamente por la ruta del archivo principal cada vez que se activa un plugin, y los MU-Plugins se cargan siempre antes. Consecuencia práctica: si dos plugins pelean por the_content en la prioridad 10, renombrar la carpeta de uno cambia el resultado, y esa es exactamente la clase de arreglo que se rompe en el siguiente despliegue. La solución estable es cambiar la prioridad de forma explícita, no confiar en el orden de carga.

Para ver el orden real sin adivinar:

wp option get active_plugins --format=json

#Recursión al inspeccionar filtros de contenido

Si llama al inspector desde dentro del propio hook que está inspeccionando, o si imprime HTML que vuelve a pasar por the_content, entra en recursión y el proceso termina con agotamiento de memoria. Por eso el snippet se engancha a wp_footer y no a the_content. Cuando necesite trazar el paso por un filtro sin recursión, use doing_filter( 'the_content' ) como guarda y did_action() para contar cuántas veces se ha disparado una acción en la petición.

#Escenarios comunes de depuración

Escenario 1: El contenido desaparece

wppoland_inspect_hook( 'the_content' );

Busque funciones que retornen cadenas vacías o tengan prioridad alta.

Escenario 2: Títulos cambian inesperadamente

wppoland_inspect_hook( 'the_title' );

Busque plugins SEO o de traducción que modifiquen títulos.

Escenario 3: Estilos se rompen

wppoland_inspect_hook( 'wp_enqueue_scripts' );

Busque plugins que eliminen hojas de estilo o conflictos de prioridad.

#Confirmar que el callback señalado es el culpable

Una tabla de callbacks es una lista de sospechosos, no una prueba. El paso que suele faltar es la falsación: desactive el callback, repita la petición y compruebe si el síntoma desaparece. Si no desaparece, el sospechoso era inocente y hay que seguir buscando.

Para funciones con nombre basta remove_filter(), pero el nombre y la prioridad tienen que coincidir exactamente con los del registro, y la llamada debe ejecutarse después de que ese registro haya ocurrido:

add_action( 'wp_loaded', function() {
    remove_filter( 'the_content', 'wpautop', 10 );
}, PHP_INT_MAX );

Para métodos de instancia el problema es que necesita el mismo objeto que hizo el registro, y la mayoría de los plugins no lo exponen. La vía que funciona sin acceder al plugin es eliminar la entrada directamente por su identificador único dentro de WP_Hook:

function wppoland_remove_callback_by_name( $hook, $needle, $priority = 10 ) {
    global $wp_filter;

    if ( ! isset( $wp_filter[ $hook ]->callbacks[ $priority ] ) ) {
        return false;
    }

    foreach ( $wp_filter[ $hook ]->callbacks[ $priority ] as $id => $registro ) {
        if ( false !== strpos( $id, $needle ) ) {
            unset( $wp_filter[ $hook ]->callbacks[ $priority ][ $id ] );
            return $id;
        }
    }

    return false;
}

El identificador contiene Clase::metodo para métodos estáticos y el nombre del método al final para métodos de instancia, así que $needle puede ser 'filtrar_contenido' o 'MiClase::'. La función devuelve el identificador eliminado, lo cual sirve como confirmación de que actuó sobre algo.

Protocolo de verificación, en orden:

  1. Anote el síntoma de forma medible: una cadena que falta en el HTML, un <style> que no se imprime, un valor concreto en la respuesta.
  2. Compare contra curl -s https://ejemplo.com/una-entrada/ | grep -c "cadena_esperada" antes del cambio.
  3. Elimine el callback y repita el mismo curl. Un contador que pasa de 0 a 1 es una prueba; “parece que ya funciona” no lo es.
  4. Restaure el callback y confirme que el síntoma vuelve. Si no vuelve, el arreglo fue una coincidencia, probablemente una caché.
  5. Solo entonces escriba el arreglo definitivo en un plugin propio, con la prioridad explícita.

El paso 4 detecta el error más caro de esta clase de depuración: haber limpiado una caché de objetos o de página al mismo tiempo que se quitó el callback, y atribuir el efecto al callback.

#Rastrear closures y métodos hasta el plugin de origen

La detección de fuente del snippet inicial usa strpos( $source_file, 'wp-content/plugins' ). Falla en tres entornos habituales:

  • Instalaciones tipo Bedrock, donde el directorio de contenido se llama app y los plugins viven en web/app/plugins.
  • Plugins montados por enlace simbólico durante el desarrollo, donde getFileName() devuelve la ruta real fuera de wp-content.
  • Windows, donde las rutas usan barras invertidas y la comparación literal contra wp-content/plugins nunca coincide.

La versión robusta compara contra las constantes que define el propio WordPress, normalizando primero las barras:

function wppoland_localizar_fuente( $archivo ) {
    $archivo = wp_normalize_path( $archivo );

    $mapa = array(
        'MU-Plugin' => defined( 'WPMU_PLUGIN_DIR' ) ? WPMU_PLUGIN_DIR : '',
        'Plugin'    => defined( 'WP_PLUGIN_DIR' ) ? WP_PLUGIN_DIR : '',
        'Tema hijo' => get_stylesheet_directory(),
        'Tema'      => get_template_directory(),
        'Core'      => ABSPATH . WPINC,
    );

    foreach ( $mapa as $etiqueta => $ruta ) {
        if ( $ruta && 0 === strpos( $archivo, wp_normalize_path( $ruta ) ) ) {
            return $etiqueta;
        }
    }

    return 'Desconocido';
}

Con la ruta ya identificada como plugin, plugin_basename( $archivo ) devuelve carpeta/archivo.php, y quedarse con el primer segmento da la carpeta del plugin responsable. Ese es el dato que necesita para desactivarlo o para abrir un informe en su repositorio.

Los closures requieren un paso más, porque no tienen nombre. ReflectionFunction sobre el closure da archivo y línea, que suele ser suficiente, pero cuando el closure vive en un archivo de arranque compartido conviene saber a qué clase pertenecía:

$reflection = new ReflectionFunction( $callback['function'] );
$ambito     = $reflection->getClosureScopeClass();
$objeto     = $reflection->getClosureThis();

$etiqueta = 'Closure';
if ( $ambito ) {
    $etiqueta .= ' en ' . $ambito->getName();
} elseif ( $objeto ) {
    $etiqueta .= ' ligado a ' . get_class( $objeto );
}

getClosureScopeClass() devuelve la clase donde se declaró el closure y getClosureThis() el objeto al que está ligado, así que un callback anónimo deja de serlo en la práctica.

Cuando la columna de fuente muestra “No se pudo determinar” no hay un fallo en el snippet. ReflectionMethod lanza ReflectionException cuando el método no existe declarado en la clase, y el caso habitual es un plugin que enruta llamadas por el método mágico __call(). El bloque try del snippet inicial captura esa excepción. Si la ve, abra la clase y busque el método: si no está declarado, el código que se ejecuta vive en el despachador y el nombre de la tabla es solo el nombre lógico del callback.

#Inspeccionar hooks desde WP-CLI

Editar functions.php en un sitio en producción es la peor parte de este flujo. WP-CLI permite leer $wp_filter sin tocar ningún archivo:

wp eval 'global $wp_filter; foreach ( $wp_filter["the_content"]->callbacks as $p => $cbs ) { foreach ( $cbs as $id => $cb ) { echo $p . "\t" . ( is_string( $cb["function"] ) ? $cb["function"] : $id ) . PHP_EOL; } }' --url=https://ejemplo.com/una-entrada/

El parámetro --url fija el contexto de la petición, host y ruta. Importa porque WP-CLI nunca ejecuta la consulta principal, y sin ese contexto los plugins que condicionan el registro al host o a la URL no llegan a registrar nada. En multisitio es obligatorio: es lo que decide de qué sitio de la red se cargan las opciones y los plugins activos.

Dos flags convierten esto en una prueba de aislamiento en segundos:

# Sin plugins: si el síntoma desaparece, el culpable es un plugin
wp eval-file inspector.php --skip-plugins --url=https://ejemplo.com/

# Sin el tema: aísla los callbacks de functions.php
wp eval-file inspector.php --skip-themes --url=https://ejemplo.com/

# Desactivando un solo plugin sospechoso
wp eval-file inspector.php --skip-plugins=nombre-del-plugin --url=https://ejemplo.com/

--skip-plugins acepta una lista separada por comas, así que puede hacer una bisección: desactive la mitad de la lista de wp plugin list --status=active --field=name, repita, y en pocas iteraciones queda un candidato. Es más rápido que desactivar plugins uno a uno desde el escritorio y no deja rastro en la base de datos.

Para medir cuánto cuesta cada callback, no solo cuáles existen, el paquete de perfilado de WP-CLI se instala por separado:

wp package install wp-cli/profile-command
wp profile hook the_content --url=https://ejemplo.com/una-entrada/

La salida desglosa tiempo y consultas por callback del hook indicado. Cuando el problema es lentitud y no comportamiento, esa tabla señala el responsable directamente, sin instalar ningún plugin en el sitio.

wp shell sirve para exploración interactiva: abre un REPL con WordPress cargado, donde has_filter( 'the_content', 'wpautop' ) devuelve la prioridad registrada o false, y count( $GLOBALS['wp_filter']['init']->callbacks ) da el número de prioridades ocupadas sin escribir un script.

#Alternativa moderna: Plugin Query Monitor

En 2026, la mejor forma de depurar hooks es usando el plugin Query Monitor de John Blackbourn.

#¿Por qué Query Monitor?

  1. Interfaz visual: Tabla limpia y buscable
  2. Rutas de archivos: Muestra ubicaciones exactas
  3. Nombres de componentes: Identifica plugins/temas
  4. Datos de rendimiento: Muestra tiempo de ejecución por hook
  5. Sin código requerido: depuración basada en GUI

#Instalación

## Via WP-CLI
wp plugin install query-monitor --activate

#Mejores prácticas para depuración de hooks

#1. Solo depure en desarrollo

Nunca deje código de depuración en producción:

if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
    add_action( 'wp_footer', function() {
        wppoland_inspect_hook( 'the_content' );
    } );
}

#2. Restrinja a administradores

Siempre verifique capacidades del usuario:

if ( current_user_can( 'manage_options' ) ) {
    // Mostrar info de depuración
}

#3. Use nombres descriptivos de hooks

Al crear hooks personalizados, use prefijos:

// Correcto
do_action( 'wppoland_before_content' );

// Incorrecto
do_action( 'before_content' );

#Contextos donde imprimir la tabla rompe el sitio

El snippet imprime HTML. Eso está bien en una página del front vista por un administrador y es un fallo en cualquier petición que espera otro formato. Un echo antes de una respuesta JSON la invalida, y el navegador informa de un error de parseo que no dice nada sobre su causa real. Lo mismo ocurre con las peticiones que aún no han enviado cabeceras: la salida temprana provoca el aviso Cannot modify header information, headers already sent, que a su vez rompe redirecciones y la escritura de cookies de sesión.

Añada una guarda de contexto antes de imprimir:

function wppoland_puede_imprimir_debug() {
    if ( ! current_user_can( 'manage_options' ) ) {
        return false;
    }
    if ( wp_doing_ajax() || wp_doing_cron() ) {
        return false;
    }
    if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
        return false;
    }
    if ( function_exists( 'wp_is_json_request' ) && wp_is_json_request() ) {
        return false;
    }
    if ( defined( 'WP_CLI' ) && WP_CLI ) {
        return false;
    }
    return true;
}

Cuando el hook que investiga solo se dispara en uno de esos contextos, la salida tiene que ir a un canal que no contamine la respuesta. error_log( print_r( $datos, true ) ) escribe en wp-content/debug.log si WP_DEBUG_LOG está activo. Si ya tiene Query Monitor instalado, do_action( 'qm/debug', $datos ) deja el volcado en el panel del propio plugin y funciona igual dentro de peticiones REST, que quedan registradas en el visor de peticiones de Query Monitor.

#Comprobaciones antes de retirar el código de depuración

El inspector es código temporal, y el modo de fallo característico es que deje de serlo. Un functions.php con una llamada olvidada sobrevive a actualizaciones del sitio y reaparece meses después en una petición donde nadie lo espera.

Antes de cerrar la tarea, verifique en este orden:

  1. El código vive en un MU-Plugin (wp-content/mu-plugins/inspector-hooks.php), no en functions.php. Un cambio de tema no lo arrastra ni lo pierde.
  2. grep -rn "wppoland_inspect_hook" wp-content/ no devuelve nada fuera de ese archivo.
  3. wp plugin list --status=must-use confirma qué MU-Plugins siguen cargados en el entorno.
  4. Una petición anónima al front no contiene rastro del volcado: curl -s https://ejemplo.com/ | grep -ci "Depurando Hook" debe devolver 0.
  5. wp config get WP_DEBUG y wp config get WP_DEBUG_DISPLAY devuelven lo esperado para el entorno. En producción, WP_DEBUG_DISPLAY debe estar en false aunque WP_DEBUG_LOG siga activo.
  6. debug.log no ha crecido sin control. Un volcado de $wp_filter en cada petición escribe cientos de líneas por visita y el archivo se dispara en un sitio con tráfico, porque WordPress no lo rota.

El punto 4 es el único que prueba el resultado, porque comprueba el HTML servido y no el código fuente. Los cinco anteriores describen la intención; ese mide el artefacto.

Un último apunte sobre el arreglo definitivo. Cuando ya sabe qué callback causa el problema, la corrección correcta casi nunca es editar el plugin ajeno, porque la siguiente actualización la borra. Escriba un plugin propio de una sola función que llame a remove_filter() con la prioridad exacta en wp_loaded, documente en un comentario qué plugin y qué versión motivaron el cambio, y añada una comprobación de que el callback sigue existiendo. Si un día el plugin lo elimina por su cuenta, quiere enterarse por el registro y no por un comportamiento silencioso.

#Resumen

La depuración de hooks de WordPress es esencial para entender conflictos de plugins y problemas de temas:

  • Use $wp_filter global para inspeccionar hooks
  • Query Monitor es la mejor solución GUI para 2026
  • Siempre restrinja la depuración a desarrollo/usuarios administradores
  • Entienda las prioridades para resolver problemas de orden de ejecución
  • Documente sus hooks personalizados para mantenibilidad

Ya sea que use el snippet personalizado o Query Monitor, entender los hooks de WordPress es crucial para el desarrollo profesional de WordPress en 2026.

Conozca más sobre los servicios de desarrollo WordPress y la auditoría de seguridad WordPress en WPPoland.

Siguiente paso

Transforma el artículo en una implementación real

Este bloque refuerza el enlazado interno y lleva al lector al siguiente paso más útil dentro de la arquitectura del sitio.

¿Quieres implementar esto en tu sitio?

Si quieres transformar el artículo en mejoras concretas, rediseño o un plan de implementación, puedo cerrar el alcance y ejecutar.

FAQ del artículo

Preguntas frecuentes

Respuestas prácticas para aplicar el tema en la ejecución real.

SEO-readyGEO-readyAEO-ready3 Q&A
Como se inspeccionan los callbacks adjuntos a un hook de WordPress?#
La ruta habitual es verificar la estructura global $wp_filter y listar callbacks junto con sus prioridades, luego usar reflection cuando necesite detalles de archivo y línea.
Por qué las funciones anonimás son más difíciles de depurar?#
Porque los closures no exponen un nombre de función simple, por lo que a menudo necesita reflection o inspección más profunda para encontrar su fuente.
Que ayuda más al rastrear un hook roto?#
Conocer el nombre del hook, la prioridad del callback, el archivo fuente y si el callback proviene del tema, del core de WordPress o de un plugin.

¿Necesitas un FAQ adaptado a tu sector y mercado? Preparamos una versión alineada con tus objetivos de negocio.

Hablemos

Artículos Relacionados