Si alguna vez te has preguntado cómo es posible que un plugin modifique el comportamiento de WordPress sin tocar ni una línea de su código fuente, la respuesta está en los hooks de WordPress. Los hooks (ganchos, en español) son el mecanismo de extensión sobre el que se construye todo el ecosistema: temas, plugins y hasta el propio núcleo los usan constantemente para insertar funcionalidad o alterar datos en puntos concretos de la ejecución. Entenderlos es la frontera que separa a quien copia y pega fragmentos de código de quien realmente sabe qué está haciendo con su web. En esta guía vamos a ver qué son exactamente los actions y los filters, en qué se diferencian, cómo usarlos con ejemplos reales y funcionales, cómo controlar prioridades y argumentos, y cómo crear tus propios hooks para que tu código también sea extensible. Todo con código PHP probado que puedes adaptar a tu proyecto hoy mismo.
Qué son los hooks de WordPress y por qué existen
WordPress se diseñó desde el principio con una regla de oro: nunca modificar el núcleo. Si cada desarrollador editase los archivos de wp-includes para cambiar un comportamiento, cada actualización borraría esos cambios y mantener una web sería una pesadilla. La solución fue sembrar el código del núcleo con miles de puntos de enganche: momentos concretos de la ejecución en los que WordPress se detiene un instante y pregunta «¿alguien quiere hacer algo aquí?».
Eso es un hook: un punto de extensión con nombre propio. Cuando WordPress carga una página ejecuta, en orden, hooks como init, wp_loaded, template_redirect o wp_head. Tu código puede «engancharse» a cualquiera de ellos registrando una función de callback, y WordPress la ejecutará en ese momento exacto sin que tengas que tocar nada más.
El sistema descansa sobre dos familias:
- Actions (acciones): ejecutan código en un momento dado. No devuelven nada; sirven para hacer cosas (enviar un email, encolar un script, registrar un post type).
- Filters (filtros): reciben un dato, lo modifican y lo devuelven. Sirven para 转变 información (cambiar el texto de un extracto, alterar un título, modificar una consulta).
Esta distinción es la primera pregunta que deberías hacerte ante cualquier hook: ¿estoy haciendo algo o estoy modificando algo?
Actions: ejecutar código en el momento justo
Un action se registra con add_action(), que necesita como mínimo dos parámetros: el nombre del hook y la función que quieres ejecutar. Veamos el ejemplo clásico, cargar una hoja de estilos de la forma correcta:
<?php
function biblioweb_cargar_estilos() {
wp_enqueue_style(
'biblioweb-personalizado',
get_stylesheet_directory_uri() . '/css/personalizado.css',
array(),
'1.0.0'
);
}
add_action( 'wp_enqueue_scripts', 'biblioweb_cargar_estilos' );
Aquí le decimos a WordPress: «cuando llegue el momento de encolar scripts y estilos del frontend (wp_enqueue_scripts), ejecuta mi función». Otro ejemplo muy habitual es reaccionar a un evento, como enviar un aviso cuando se publica una entrada:
<?php
function biblioweb_avisar_publicacion( $post_id, $post ) {
// Evitamos revisiones y autoguardados.
if ( wp_is_post_revision( $post_id ) ) {
return;
}
$asunto = 'Nueva entrada publicada: ' . $post->post_title;
$mensaje = 'Se ha publicado una entrada. Revísala aquí: ' . get_permalink( $post_id );
wp_mail( 'editor@tudominio.com', $asunto, $mensaje );
}
add_action( 'publish_post', 'biblioweb_avisar_publicacion', 10, 2 );
Fíjate en los dos últimos parámetros de add_action(): el 10 es la prioridad y el 2 indica cuántos argumentos acepta nuestra función. Los veremos en detalle más adelante, porque son la causa del 90 % de los errores con hooks.
Actions imprescindibles que conviene conocer
init: WordPress ya está cargado; aquí se registran custom post types, taxonomías y shortcodes.wp_enqueue_scripts: punto correcto para encolar CSS y JS del frontend.admin_inityadmin_menu: equivalentes para el área de administración.wp_headywp_footer: imprimen contenido en el<head>y antes de cerrar el<body>.save_post: se dispara al guardar cualquier entrada; ideal para procesar metadatos.wp_loginyuser_register: reaccionan al inicio de sesión y al alta de usuarios.
Filters: modificar datos antes de que se usen
Un filter funciona igual que un action con una diferencia crucial: tu función recibe un valor y debe devolverlo, modificado o no. Si olvidas el return, el dato llega vacío a su destino y romperás algo (extractos en blanco, títulos desaparecidos…). Es el error más común al empezar con los hooks de WordPress.
Ejemplo real: cambiar la longitud del extracto y el texto de «leer más»:
<?php
function biblioweb_longitud_extracto( $longitud ) {
return 30; // palabras
}
add_filter( 'excerpt_length', 'biblioweb_longitud_extracto' );
function biblioweb_leer_mas( $more ) {
return '… <a href="' . esc_url( get_permalink() ) . '">Seguir leyendo</a>';
}
add_filter( 'excerpt_more', 'biblioweb_leer_mas' );
Otro caso muy útil: añadir automáticamente un aviso al final del contenido de cada entrada, solo en el frontend:
<?php
function biblioweb_nota_final( $content ) {
if ( is_singular( 'post' ) && in_the_loop() && is_main_query() ) {
$nota = '<p class="nota-final">¿Te ha resultado útil? Compártelo o déjanos un comentario.</p>';
return $content . $nota;
}
return $content;
}
add_filter( 'the_content', 'biblioweb_nota_final' );
Observa las comprobaciones condicionales: the_content se aplica en muchos contextos (feeds, widgets, páginas), y filtrar sin condiciones acaba mostrando tu nota donde no debe. Devolver siempre $content al final, aunque no lo modifiques, es obligatorio.
Filters que usarás una y otra vez
the_contentythe_title: el cuerpo y el título de las entradas.excerpt_lengthyexcerpt_more: control del extracto.body_class: añade clases CSS al<body>.upload_mimes: permite (o bloquea) tipos de archivo en la mediateca.wp_mail_fromywp_mail_from_name: remitente de los correos de WordPress.login_errors: mensaje de error del login (útil para no dar pistas a atacantes).
Prioridad y argumentos: los dos números que lo cambian todo
Tanto add_action() como add_filter() aceptan cuatro parámetros:
add_filter( 'nombre_del_hook', 'mi_funcion', $prioridad, $num_argumentos );
| Parámetro | Valor por defecto | Qué controla |
|---|---|---|
| Prioridad | 10 | El orden de ejecución: menor número, antes se ejecuta. Con la misma prioridad, gana el que se registró primero. |
| Nº de argumentos | 1 | 你的回调函数接收多少个钩子参数。如果钩子传递 3 个参数而你只声明 1 个,你将只收到第一个。 |
当多个插件处理相同数据时,优先级很重要。如果你的过滤器作用于 the_content 必须在另一个插件完成其工作后执行,请使用高优先级(例如 99)。如果你需要优先于所有其他插件,请使用 1。另一方面,参数的数量必须与你在函数签名中声明的相匹配:如果你设置 10, 3 但你的函数只接受一个参数,PHP 将抛出致命错误。
要解除一个函数的挂钩,可以使用 remove_action() y remove_filter(),有一个严格的条件:必须传递与注册时完全相同的函数名和优先级:
<?php
// Quitar el generador de versión del head (lo añade el core con prioridad por defecto).
remove_action( 'wp_head', 'wp_generator' );
如何创建你自己的自定义钩子
这是更高层次的飞跃:除了使用钩子,你还可以创建它们。如果你开发主题或插件,在你的代码中植入 do_action() y apply_filters() 允许其他人(或你自己在未来)在不修改它的情况下扩展它。WooCommerce 就是这样运作的,这就是为什么它的生态系统如此庞大。
一个自定义动作是使用...创建的 do_action():
<?php
// En tu plugin, tras procesar un pedido de ejemplo:
function biblioweb_procesar_solicitud( $solicitud_id ) {
// ... lógica principal ...
// Punto de extensión: cualquiera puede engancharse aquí.
do_action( 'biblioweb_solicitud_procesada', $solicitud_id );
}
// Otro desarrollador (u otro archivo) se engancha:
add_action( 'biblioweb_solicitud_procesada', function ( $solicitud_id ) {
error_log( 'Solicitud procesada: ' . $solicitud_id );
} );
以及一个自定义过滤器,使用 apply_filters(),它定义了默认值并提供给任何想要更改它的人:
<?php
function biblioweb_obtener_limite() {
$limite = 25;
// Nombre del filtro, valor por defecto y argumentos extra opcionales.
return apply_filters( 'biblioweb_limite_resultados', $limite );
}
// Cualquier otro código puede ajustarlo sin tocar tu función:
add_filter( 'biblioweb_limite_resultados', function ( $limite ) {
return 50;
} );
两个好的实践:始终用你的项目名称作为钩子的前缀以避免冲突,并记录每个钩子传递的参数。一个没有文档的钩子是没人会用的钩子。
你的钩子代码放在哪里
你有三种合理的选择,根据情况,推荐程度从低到高:
- 子主题的 functions.php: 适用于与设计相关的调整(摘要、body 类)。如果你更换主题,它们就会丢失。
- 一个代码片段插件: 对大多数人来说最方便的选择。像...这样的工具 WPCode,我们深入分析的代码片段管理器,它们允许你单独激活和停用每个代码片段,并且具有语法验证功能,可以避免因一个分号而导致网站崩溃。
- 一个自定义插件: 对于需要独立于主题的功能来说是正确的选择:自定义文章类型、集成、业务逻辑。
你绝不应该编辑父主题的 functions.php 文件,当然也不应该编辑核心文件。如果你刚开始并且还不熟悉 启动 WordPress 的必备插件,在你深入代码之前,先从那里开始。
使用钩子时常见的错误
- 忘记在过滤器中返回。 典型症状:内容或标题消失。所有过滤器都必须始终返回一个值。
- 过早挂钩。 如果你在...之前调用用户函数
init或在...之前调用模板函数wp,你会得到错误或空值。每个钩子在加载周期中都有其特定的时机。 - 不声明参数。 注册
add_action( 'save_post', 'mi_funcion', 10, 3 )使用只接受一个参数的函数会在 PHP 8 中引发致命错误。 - 无限循环。 调用
wp_update_post()在...的回调中save_post再次触发save_post。避免方法是在更新前移除钩子,然后在更新后再添加回来。 - 之后无法移除的匿名回调。 匿名函数很方便,但是
remove_filter()无法轻易删除它们。对于其他人需要能够停用的代码,请使用命名函数。
要探索存在哪些钩子以及它们传递哪些参数,官方参考资料 developer.wordpress.org 关于钩子 是最终的指南:它包含了核心动作和过滤器的完整列表及其文档。
常见问题
动作和过滤器之间真正的区别是什么?
动作(Action)在流程的某个点执行代码,不返回任何内容:它用于做事情。过滤器(Filter)接收一个数据,可以修改它,并且必须返回它:它用于转换信息。在内部,两者使用相同的系统(实际上 add_action() 调用 add_filter()),但从概念上讲,最好将它们视为不同的工具。
不懂编程也能使用钩子吗?
你可以使用现成的代码片段,将其复制到像 WPCode 这样的代码片段插件中,该插件在保存前会验证语法。然而,至少理解每一行代码的作用将避免你粘贴恶意或过时的代码。WordPress 钩子是 PHP:一点点基础知识就能让你获得很大的自主权。
WordPress有多少
核心有超过3000个动作和过滤器,并且这个数字在每个版本中都在增长。此外,你的插件和主题也会注册自己的钩子:例如,WooCommerce就添加了数百个。你无需记住所有钩子:只需了解常用的一打左右,并知道如何在官方文档中查找其余的即可。
钩子会影响我的网站性能吗?
系统本身非常高效;真正影响性能的是你在回调函数中做的事情。一个繁重的查询挂接到 init 将在每次页面加载时执行。将你的代码挂接到尽可能最具体的钩子,并在不需要执行时使用条件语句尽早退出。
结论
WordPress钩子是核心、主题和插件之间相互通信的语言。掌握动作和过滤器这对组合,你就可以在不修改源代码且不怕更新的情况下,自定义几乎任何行为:例如,排队加载资源、响应事件、转换内容,以及当你开始开发时,提供你自己的扩展点。 do_action() y apply_filters()首先,在测试环境或通过代码片段管理器重现本指南中的示例,注意过滤器的优先级和返回值,并在不确定钩子传递哪些参数时查阅官方文档。从那时起,你在WordPress中遇到的每个自定义问题几乎总会有相同的答案:有相应的钩子可以解决。