() translation by (you can also view the original English article)
Una de las muchas cosas que encontrarás al investigar el código fuente de un buen desarrollador de plugins son los enlaces y filtros personalizados que el desarrollador ha colocado en todo el plugin. La presencia de estos enlaces de acción y filtros hacen que el plugin sea "extensible", lo que significa que otros plugins y temas pueden manipular o agregar al comportamiento del plugin.
Escribir plugins extensibles es algo que me gustaría animarte a hacer. Hay muchas buenas razones por las que debes hacerlo, pero muy pocas (si es que hay alguna) razones por las que debes evitar esta práctica.
Veremos varios elementos de plugins extensibles:
- Una explicación de lo que son los plugins extensibles
- Razones por las que debes escribir plugins extensibles
- Las herramientas básicas que necesitas
- Cómo necesitas escribir tus plugins para hacerlos extensibles
- Ejemplos sencillos de enlaces y filtros para ilustrar cómo podrías usarlos
Una nota importante: este tutorial utilizará técnicas de programación basadas puramente en procedimientos. Todo lo que hablo aquí aún se aplica cuando se usa la programación orientada a objetos (POO), pero es más simple aprender primero estas técnicas en un entorno de procedimiento.
¿Qué es un plugin extensible?
Un plugin extensible es aquel que puede ser modificado y extendido más allá de su propósito original por otro plugin o tema. Cuando un plugin es extensible, otros plugins (o temas) pueden alterar el comportamiento o la salida del plugin. Por ejemplo, los plugins de comercio electrónico permiten pasarelas de pago adicionales que permiten que las compras se procesen a través de sistemas de pago adicionales. Estas pasarelas de pago son plugins separados que simplemente se conectan al plugin principal y amplían su funcionalidad.
Todos y cada uno de los plugins pueden ser extensibles, aunque solo una pequeña minoría de plugins publicados lo son. Para ser extensible, o modular (otro término para lo mismo), el desarrollador de un plugin debe tomar una decisión consciente para hacerlo de esa manera mediante la implementación de los elementos necesarios que hacen posible que otros plugins y temas se vinculen con el comportamiento del plugin principal.
¿Por qué escribir plugins extensibles?
Hay muchas buenas razones para escribir plugins extensibles, pero una de las principales razones es que simplemente no hay una buena razón para no escribir tus plugins de esta manera, especialmente cuando tus plugins se lanzan a la comunidad de WordPress, ya sea como plugins gratuitos o de pago.
Cuando escribes plugins extensibles, haces posible que otros desarrolladores amplíen tu plugin y lo hagan aún mejor, pero sin cambiar nunca el código fuente principal. También haces que sea significativamente más fácil para los desarrolladores y usuarios adaptar el plugin para satisfacer mejor sus necesidades. Déjame darte un ejemplo: en mi plugin Easy Digital Downloads hay un sistema de código de descuento. Los códigos de descuento están restringidos a un solo uso por usuario, por lo que si un usuario intenta aplicar el mismo descuento en dos compras diferentes, recibirá un error. Uno de mis usuarios del mundo real descubrió que no quería limitar los descuentos a un solo uso por usuario, así que le di una función simple que colocó en un nuevo plugin personalizado y se eliminó la restricción, sin tocar ningún código de plugin principal.
El código extensible también hace que otros desarrolladores estén extremadamente felices cuando lo encuentran porque su trabajo de adaptar tu código se volvió mucho, mucho más fácil.
Las herramientas básicas / Funciones
Hay varias herramientas clave que necesitas para escribir plugins extensibles. Si has escrito algún plugin o tema antes de leer esto, probablemente estés al menos algo familiarizado con estas funciones, incluso si es solo porque las has visto usar.
Antes de mostrarte las funciones que usarás, hablemos primero de dos conceptos principales: enlaces y filtros.
Un enlace de acción es un lugar en tu plugin al que pueden "engancharse" funciones (tanto en tu plugin como en otros plugins) para que su código se ejecute en ese punto. Cuando se ejecuta un enlace de acción, todas las funciones que están conectadas, o "enganchadas", a él también se ejecutarán.
Un enlace de filtro también es un lugar en tu complemento para que otras funciones se vinculen, pero funcionan de manera ligeramente diferente a las acciones. Los filtros permiten manipular o modificar los datos antes de su uso.
La diferencia clave entre las acciones y los filtros es que las acciones se utilizan normalmente para ejecutar funciones y los filtros se utilizan normalmente para manipular datos.
A menos que ya estés muy familiarizado con las acciones y los filtros, te recomiendo encarecidamente que vayas a leer la entrada del Codex sobre ellos.
Para las acciones hay cuatro funciones principales:
-
do_action()
: define una ubicación enlazable para las acciones -
add_action()
: esto asocia una función a un enlace creado condo_action()
-
has_action()
: comprueba si se registró una acción condo_action()
-
remove_action()
: esto elimina una acción que se estableció conadd_action()
De estos cuatro, usarás más do_action()
y add_action()
.
Para los filtros también hay cuatro funciones principales:
-
apply_filters()
: esto crea una ubicación enlazable para que los filtros personalizados se vinculen -
add_filter()
: esto asocia un filtro personalizado a un enlace creado conapply_filters()
-
has_filter()
: comprueba si se registró un filtro conapply_filters()
-
remove_filter()
: elimina un filtro previamente conectado aapply_filters()
Al igual que con las acciones, apply_filters()
y add_filter()
son los dos que más usarás.
Si estás confundido en este punto, no te preocupes, veremos cómo usarlos realmente en la siguiente sección.
Implementación en tus propios plugins
Con el fin de hacer que tu plugin sea verdaderamente extensible, debes usar las funciones clave mencionadas anteriormente en todo el plugin. Al principio puede resultarte difícil, engorroso, molesto o muchos otros adjetivos aplicables, colocar constantemente estas funciones adicionales en todo el código, especialmente cuando no ves un beneficio inmediato o un uso para ellas.
Sin embargo, lo que encontrarás es que una vez que tengas el hábito de escribir tus plugins con todas estas funciones en mente, se convertirá en una segunda naturaleza para incluirlos.
Hay algunos escenarios principales en los que usarás filtros en tus plugins:
- Cuando se configuran las matrices. Los filtros se agregarán aquí para que otros plugins puedan modificar los datos antes de que se utilicen.
- Cuando se programan los objetos de datos. Al igual que con las matrices, usarás un filtro en los objetos para que otros desarrolladores puedan modificar el objeto antes de que se use.
- Cuando se programan las cadenas de datos. Con un filtro disponible en una cadena, otros desarrolladores pueden cambiar toda la cadena, alterar partes de ella o agregarle algo.
De los escenarios anteriores, es más común usar filtros cuando se devuelven datos o justo antes de que se utilicen. Por ejemplo, si tienes un plugin que realiza una consulta de publicaciones, es mejor pasar la matriz de argumentos de consulta a través de un filtro antes de que se pasen a get_posts()
o WP_Query
para que otros puedan manipular la consulta antes de que se realice.
Cuando se trata de acciones, también hay varios casos principales en las que las colocarás:
- Antes de que se ejecute una tarea.
- Después de ejecutar una tarea.
- Dentro del marcado para permitir que se inserte marcado adicional.
Ahora tengamos en cuenta algunos ejemplos.
1. Visualización de HTML con un código corto
Los códigos cortos que generan HTML son extremadamente comunes (en realidad, son probablemente los más comunes de todos los códigos cortos), y una de las formas en que podemos hacer que los códigos cortos de nuestro plugin sean más amigables para otros desarrolladores es proporcionándoles una forma de alterar el contenido del código corto, pero sin requerir que se cancele el registro y se registre nuevamente.
Todos los códigos cortos regresan en lugar de hacer eco de su contenido, lo que significa que los datos enviados a la pantalla estarán en forma de cadena antes de ser devueltos. Debido a que toda la salida HTML tiene la forma de una cadena, puedes pasar la cadena a través de un filtro antes de devolverla. Si lo hace, será posible que otros desarrolladores alteren el HTML de tu código corto.
Es posible que un desarrollador quiera agregar un marcado adicional antes y después del HTML predeterminado: con el filtro en su lugar, puede hacerlo.
Tu código corto puede verse así:
1 |
function wptp_sample_shortcode( atts, $content = null ) { |
2 |
|
3 |
$html = '<div class="wptp_shortcode">'; |
4 |
$html .= '<p>Contents of the sample shortcode</p>'; |
5 |
$html .= '</div>'; |
6 |
|
7 |
return $html; |
8 |
|
9 |
}
|
Podemos mejorar esto agregándole un filtro a la devolución, así:
1 |
function wptp_sample_shortcode( atts, $content = null ) { |
2 |
|
3 |
$html = '<div class="wptp_shortcode">'; |
4 |
$html .= '<p>Contents of the sample shortcode</p>'; |
5 |
$html .= '</div>'; |
6 |
|
7 |
return apply_filters( 'wptp_shortcode_html', $html ); |
8 |
|
9 |
}
|
El HTML en nuestro código corto ahora se puede modificar así:
1 |
function wptp_modify_html( $html ) { |
2 |
return '<div class="extra_div">' . $html . '</div>'; |
3 |
}
|
4 |
add_filter( 'wptp_shortcode_html', 'wptp_modify_html' ); |
Esto dará como resultado que el HTML original creado en el código corto se envuelva con otra etiqueta div
.
2. Consulta de publicaciones
Realizar consultas personalizadas en plugins es una práctica común. Supongamos por un momento que escribiste un plugin que registra un tipo de publicación personalizada llamada "libros", y en tu plugin es una función para mostrar los libros creados. Tu función para consultar los libros podría verse así:
1 |
function wptp_show_books() { |
2 |
|
3 |
$query_args = array( |
4 |
'post_type' => 'books', |
5 |
'posts_per_page' => 5 |
6 |
);
|
7 |
|
8 |
$books = new WP_Query( $query_args ); |
9 |
if( $books->have_posts() ) : |
10 |
while( $books->have_posts() ) : $books->the_post() |
11 |
// show info about each book here
|
12 |
endwhile; |
13 |
endif; |
14 |
wp_reset_postdata(); |
15 |
|
16 |
}
|
Pero, ¿qué pasa si un usuario quiere modificar los tipos de libros que se devuelven, tal vez seleccionando solo los libros de una categoría específica? Puedes hacerles esto mucho más fácil haciendo esto:
1 |
function wptp_show_books() { |
2 |
|
3 |
$query_args = array( |
4 |
'post_type' => 'books', |
5 |
'posts_per_page' => 5, |
6 |
'author' => 3 |
7 |
);
|
8 |
|
9 |
$books = new WP_Query( apply_filters( 'wptp_books_query', $query_args ) ) ; |
10 |
if( $books->have_posts() ) : |
11 |
while( $books->have_posts() ) : $books->the_post() |
12 |
// show info about each book here
|
13 |
endwhile; |
14 |
endif; |
15 |
wp_reset_postdata(); |
16 |
|
17 |
}
|
El único cambio que hice fue agregar un filtro alrededor de la $query_args
, lo que significa que otros desarrolladores (o usuarios) pueden modificar los argumentos de consulta antes de que realmente se pasen a WP_Query
. Por ejemplo, podríamos configurar la consulta para que solo muestre libros del autor 3 así:
1 |
function wptp_alter_books_query( $args ) { |
2 |
$args['author'] = 3; |
3 |
return $args; |
4 |
}
|
5 |
add_filter( 'wptp_books_query', 'wptp_alter_books_query' ); |
3. Ampliación del marcado
Extendamos el ejemplo número 2 ahora y hagámoslo aún mejor. Ya agregamos un filtro que le permite a los usuarios modificar la consulta, ahora agreguemos algunos enlaces que nos permitan alterar el HTML creado.
Primero modificaremos un poco nuestro HTML original:
1 |
function wptp_show_books() { |
2 |
|
3 |
$query_args = array( |
4 |
'post_type' => 'books', |
5 |
'posts_per_page' => 5, |
6 |
'author' => 3 |
7 |
);
|
8 |
|
9 |
$books = new WP_Query( apply_filters( 'wptp_books_query', $query_args ) ; |
10 |
if( $books->have_posts() ) : |
11 |
|
12 |
echo '<div class="wptp_books">'; |
13 |
|
14 |
while( $books->have_posts() ) : $books->the_post() |
15 |
|
16 |
echo '<div class="wptp_book">'; |
17 |
|
18 |
echo '<h3 class="wptp_book_title">' . get_the_title() . '</h3>'; |
19 |
|
20 |
echo '</div>'; |
21 |
|
22 |
endwhile; |
23 |
|
24 |
echo '</div>'; |
25 |
|
26 |
endif; |
27 |
wp_reset_postdata(); |
28 |
|
29 |
}
|
Ahora nos gustaría hacer posible que los desarrolladores agreguen marcado adicional en varios puntos, como los siguientes:
- Antes de que se genere cualquier HTML
- Después del HTML final
- Antes del título de cada libro
- Después del título de cada libro
Puedes imaginar un escenario en el que un usuario quiera agregar una miniatura antes o después del título del libro. Para que esto sea posible, usamos do_action()
para crear ubicaciones enlazables, como esta:
1 |
function wptp_show_books() { |
2 |
|
3 |
$query_args = array( |
4 |
'post_type' => 'books', |
5 |
'posts_per_page' => 5, |
6 |
'author' => 3 |
7 |
);
|
8 |
|
9 |
$books = new WP_Query( apply_filters( 'wptp_books_query', $query_args ) ); |
10 |
if( $books->have_posts() ) : |
11 |
|
12 |
do_action( 'wptp_books_before' ); |
13 |
echo '<div class="wptp_books">'; |
14 |
|
15 |
while( $books->have_posts() ) : $books->the_post() |
16 |
|
17 |
echo '<div class="wptp_book">'; |
18 |
|
19 |
do_action( 'wptp_before_book_title', get_the_ID() ); |
20 |
|
21 |
echo '<h3 class="wptp_book_title">' . get_the_title() . '</h3>'; |
22 |
|
23 |
do_action( 'wptp_after_book_title', get_the_ID() ); |
24 |
|
25 |
echo '</div>'; |
26 |
|
27 |
endwhile; |
28 |
|
29 |
echo '</div>'; |
30 |
do_action( 'wptp_books_after' ); |
31 |
|
32 |
endif; |
33 |
wp_reset_postdata(); |
34 |
|
35 |
}
|
Ten en cuenta que los dos enlaces internos (que rodean el título) tienen un segundo parámetro de get_the_ID()
. Esta variable, que será el ID del libro, estará disponible como parámetro para cualquier función enlazada. Para agregar una miniatura de libro, por ejemplo, podemos hacer esto:
1 |
function wptp_show_book_image( $book_id ) { |
2 |
echo get_the_post_thumbnail( $book_id, 'thumbnail' ); |
3 |
}
|
4 |
add_action( 'wptp_before_book_title', 'wptp_show_book_image' ); |
Ejemplos del mundo real
Ahora me gustaría mostrarte algunos ejemplos del mundo real de plugins que son extensibles, incluidas muestras de algunas de sus funciones extensibles.
1. Soliloquio
Soliloquio es un poderoso plugin de control deslizante de imagen receptivo de WordPress que hace que la creación y el mantenimiento de controles deslizantes de imagen receptivos, eficientes, seguros y amigables con SEO sea muy fácil.
Casi todo en este plugin es extensible. Este es solo un ejemplo:
1 |
$labels = apply_filters( 'tgmsp_post_type_labels', array( |
2 |
'name' => __( 'Soliloquy', 'soliloquy' ), |
3 |
'singular_name' => __( 'Soliloquy', 'soliloquy' ), |
4 |
'add_new' => __( 'Add New', 'soliloquy' ), |
5 |
'add_new_item' => __( 'Add New Soliloquy Slider', 'soliloquy' ), |
6 |
'edit_item' => __( 'Edit Soliloquy Slider', 'soliloquy' ), |
7 |
'new_item' => __( 'New Soliloquy Slider', 'soliloquy' ), |
8 |
'view_item' => __( 'View Soliloquy Slider', 'soliloquy' ), |
9 |
'search_items' => __( 'Search Soliloquy Sliders', 'soliloquy' ), |
10 |
'not_found' => __( 'No Soliloquy Sliders found', 'soliloquy' ), |
11 |
'not_found_in_trash' => __( 'No Soliloquy Sliders found in trash', 'soliloquy' ), |
12 |
'parent_item_colon' => '', |
13 |
'menu_name' => __( 'Soliloquy', 'soliloquy' ) |
14 |
) ); |
15 |
|
16 |
$args = apply_filters( 'tgmsp_post_type_args', array( |
17 |
'labels' => $labels, |
18 |
'public' => true, |
19 |
'exclude_from_search' => true, |
20 |
'show_ui' => true, |
21 |
'show_in_admin_bar' => false, |
22 |
'rewrite' => false, |
23 |
'query_var' => false, |
24 |
'menu_position' => 100, |
25 |
'menu_icon' => plugins_url( 'css/images/menu-icon.png', dirname( __FILE__ ) ), |
26 |
'supports' => array( 'title' ) |
27 |
) ); |
Así es como Thomas Griffin (el desarrollador del plugin) establece los argumentos para las etiquetas y los atributos de tipo de publicación personalizada. La presencia de sus dos filtros, tgmsp_post_type_labels
y tgmsp_post_type_args
, hacen que sea muy sencillo para otros desarrolladores cambiar el nombre del tipo de publicación deslizante o cambiar lo que admite el tipo de publicación.
2. bbPress
Con mucho, uno de mis plugins favoritos personales de todos los tiempos, bbPress es un plugin de foro con todas las funciones para WordPress. Todo el plugin es un ejemplo perfecto de cómo hacer que tus plugins sean extensibles, ya que literalmente tiene acciones y filtros en todas partes. Tiene un filtro particular que se aplica al recuperar el contenido de un foro:
1 |
function bbp_get_forum_content( $forum_id = 0 ) { |
2 |
$forum_id = bbp_get_forum_id( $forum_id ); |
3 |
|
4 |
// Check if password is required
|
5 |
if ( post_password_required( $forum_id ) ) |
6 |
return get_the_password_form(); |
7 |
|
8 |
$content = get_post_field( 'post_content', $forum_id ); |
9 |
|
10 |
return apply_filters( 'bbp_get_forum_content', $content, $forum_id ); |
11 |
}
|
Antes de que se devuelva el contenido del foro, se pasa a través de un filtro llamado bbp_get_forum_content
que permite que un desarrollador modifique el contenido antes de que se muestre.
3. Descargas digitales fáciles
Easy Digital Downloads, o EDD, es uno de mis plugins que se creó para que sea excepcionalmente fácil vender productos digitales a través de WordPress. Al igual que con la mayoría de los plugins de comercio electrónico, EDD tiene un proceso de pago por el que pasa el comprador para que pueda ingresar sus datos personales y de pago. Después de que se recopila toda esa información, todo va a una pasarela de pago (un sistema para procesar el pago), pero antes de que vaya a la pasarela, se aplica un filtro que permite manipular los datos antes de que sean utilizados por el sistema de pago:
1 |
$purchase_data = apply_filters( |
2 |
'edd_purchase_data_before_gateway', |
3 |
$purchase_data, |
4 |
$valid_data
|
5 |
);
|
La presencia de este filtro permite ajustar los importes de compra (quizás para descuentos especiales), añadir impuestos, quizás añadir o eliminar productos de la compra, y mucho, mucho más.
Conclusión
Los plugins extensibles benefician a todos: al desarrollador original, a otros desarrolladores y a los propios usuarios.
Hay tantas razones por las que deberías escribir tus plugins teniendo en cuenta el código extensible, entonces, ¿por qué no lo haces?
Las herramientas presentadas aquí son todo lo que necesitas para comenzar. ¿Tienes preguntas? ¡Hazlas!