¿Dónde es el mejor lugar para usar add_filter?

12 ene 2013, 07:23:45
Vistas: 30.3K
Votos: 15

¿Debería usar la función add_filter en el hook de acción init de mi plugin o simplemente en el script principal del plugin?

Ya que a veces encuentro que la gente está usando filtros en todas partes y si lo pongo en el hook init, sería demasiado tarde para algunos casos.

¿Hay algún consejo general sobre la precedencia de los hooks de action y filter para que podamos tener un estilo de código más consistente?

0
Todas las respuestas a la pregunta 1
1
18

add_filter() y add_action() están disponibles antes de que cualquier plugin se cargue. Por lo tanto, puedes usar ambos en la primera línea de tu plugin o tema.

Para una mejor legibilidad, recomiendo agrupar los registros de acciones y filtros al principio de tu archivo principal:

  • En un plugin, el archivo con el encabezado del plugin
  • En un tema, el functions.php

Hay excepciones para esta regla:

  • Devoluciones de llamada encadenadas. En este ejemplo, registro una acción para shutdown solo cuando se ha llamado al primer filtro para wp_nav_menu_objects. Por lo tanto, la segunda devolución de llamada no se puede registrar al mismo tiempo que la primera.
  • Estilo OOP. A veces necesitas configurar miembros de la clase antes de poder registrar las devoluciones de llamada. Usando un ejemplo muy similar ...

    add_action(
        'plugins_loaded',
        array ( T5_Plugin_Class_Demo::get_instance(), 'plugin_setup' )
    );
    class T5_Plugin_Class_Demo
    {
        public function plugin_setup()
        {
            $this->plugin_url    = plugins_url( '/', __FILE__ );
            $this->plugin_path   = plugin_dir_path( __FILE__ );
            $this->load_language( 'plugin_unique_name' );
    
            // más cosas: registrar acciones y filtros
        }
    }
    

    ... vemos que la instanciación de la clase puede ser detenida por otro plugin, y una clase hija podría registrar más o diferentes filtros y acciones.

Además de agrupar, puedes ir un paso más allá y ofrecer una acción personalizada para facilitar las personalizaciones para otros desarrolladores.
Aquí hay un ejemplo de un tema en el que estoy trabajando:

add_action( 'activate_header',      't5_activate_screen' );
// wp_loaded es demasiado tarde, el personalizador de WP no detectaría las características entonces.
add_action( 'after_setup_theme',    't5_setup_custom_background' );
add_action( 'after_setup_theme',    't5_setup_custom_header' );
add_filter( 'body_class',           't5_enhance_body_class' );
add_action( 'comment_form_before',  't5_enqueue_comment_reply' );
add_action( 'content_before',       't5_frontpage_widget' );
add_action( 'footer_before',        't5_loop_navigation' );
add_action( 'get_the_excerpt',      't5_excerpt_clean_up', 1 );
add_action( 'header_before',        't5_skiplink', 0, 0 );
add_filter( 'the_title',            't5_fill_empty_title', 20, 1 );
add_action( 'wp_enqueue_scripts',   't5_enqueue_style' );
add_action( 'wp_enqueue_scripts',   't5_enqueue_script' );
add_action( 'wp_loaded',            't5_setup' );
add_action( 'wp_loaded',            't5_page_enhancements' );
add_action( 'wp_loaded',            't5_post_format_support' );
add_action( 'wp_loaded',            't5_load_theme_language' );
add_action( 'wp_loaded',            't5_setup_sidebars' );
add_filter( 'wp_nav_menu_items',    't5_customize_top_menu', 10, 2 );
add_filter( 'wp_nav_menu_args',     't5_nav_menu_args', 10, 1 );
add_filter( 'wp_title',             't5_wp_title_filter', 20, 2 );

add_shortcode( 'gallery',    't5_shortcode_gallery' );
add_shortcode( 'wp_caption', 't5_shortcode_img_caption' );
add_shortcode( 'caption',    't5_shortcode_img_caption' );

// Usa esta acción para anular el registro de acciones y filtros del tema.
do_action( 't5_theme_hooks_registered' );

La última línea es importante: Un tema hijo o un plugin ahora puede engancharse a la acción t5_theme_hooks_registered y anular el registro de cualquier hook anterior. Esto ahorrará problemas con las prioridades, y yo soy libre de cambiar las prioridades de mis devoluciones de llamada en cualquier momento.

Pero no confíes solo en el orden del código fuente. Documenta los hooks que estás usando en tu bloque de documentación. Yo uso una etiqueta personalizada wp-hook para eso. Aquí hay un ejemplo con hooks encadenados del mismo tema:

/**
 * Registra el manejador para el extracto auto-generado.
 *
 * @wp-hook get_the_excerpt
 * @param   string $excerpt
 * @return  string
 */
function t5_excerpt_clean_up( $excerpt )
{
    if ( ! empty ( $excerpt ) )
        return $excerpt;

    add_filter( 'the_content', 't5_excerpt_content' );

    return $excerpt;
}
/**
 * Elimina partes del extracto auto-generado.
 *
 * @wp-hook the_content
 * @param   string $content
 * @return  string
 */
function t5_excerpt_content( $content )
{
    remove_filter( current_filter(), __FUNCTION__ );

    return preg_replace( '~<(pre|table).*</\1>~ms', '', $content );
}

No tienes que desplazarte hacia arriba para ver dónde se llaman estas funciones, un vistazo al bloque de documentación es suficiente. Esto requiere cierto esfuerzo, porque tienes que mantener ambos sincronizados, el registro y el comentario, pero a la larga ahorra un tiempo valioso.

12 ene 2013 08:08:49
Comentarios

+1. Para el "estilo POO", mi preferencia es transferir el control a la clase/objeto que luego registra acciones/filtros en su constructor (o más tarde si es apropiado). Proporciona un mejor encapsulamiento (¡POO!), y difiere el registro de hooks hasta que la clase es utilizada/instanciada.

webaware webaware
12 ene 2013 08:25:18