Pluggable Functions
Una característica que nos ofrece WordPress es la de reservar ciertos nombres de funciones para que podamos utilizarlos para reemplazar funcionalidad nativa por la nuestra. A estas funciones, en la terminología propia de WordPress, nos referimos como Pluggable Functions.
Estas funciones tienen la característica de ser definidas recién después de que todos los plugins se hayan cargado, y chequean si la función ya se declaró antes, usando function_exists()
. Lo que hacen es algo como esto:
<?php
if ( ! function_exists( 'wp_mail' ) ) :
function wp_mail( $args... ) {
// Code here…
}
endif;
Esto permite que podamos definir nuestras propias funciones con ese nombre antes de que WordPress lo haga.
<?php
// En nuestro plugin…
function wp_mail( $args... ) {
// Code here…
}
// En WordPress…
if ( ! function_exists( 'wp_mail' ) ) :
function wp_mail( $args... ) {
// Code here…
}
endif;
Si hacemos esto, cada vez que se llame a la función wp_mail()
se va a ejecutar nuestro código para esa función en lugar del código de WordPress.
Esta posibilidad de redefinir funciones nativas es extremadamente útil para plugins que necesitan llevar a cabo sus propios procesos de envío de mails, validación de usuarios, generación de contraseñas, etc.
En nuestros plugins también podemos crear nuestras propias Pluggable Functions, para permitir a otros desarrolladores que redefinan funcionalidad de nuestros plugins cuando lo necesiten.
<?php
// En un plugin de terceros...
function my_function() {
_e( 'Hello John!', 'third-party-plugin' );
}
// En nuestro plugin…
if ( ! function_exists( 'my_function' ) ) :
function my_function() {
_e( 'Hello world!', 'my-plugin' );
}
endif;
Este mismo principio de extensibilidad es aplicable a clases, por medio de class_exists()
:
<?php
// En un plugin de terceros…
class My_Class {
public function __construct() {}
}
// En nuestro plugin…
if ( ! class_exists( 'My_Class' ) ) :
class My_Class {
public function __construct() {}
}
endif;
Hay que tener en cuenta que, si alguien quiere redefinir nuestras funciones, tiene que encargarse de declarar las suyas antes de que se declaren las nuestras. Como no podemos estar seguros del orden en el que WordPress va a cargar los archivos de plugins que vaya encontrando, lo que se puede hacer es definir nuestras Pluggable Functions dentro de un evento, para que otro desarrollador pueda usar ese mismo evento e insertar sus propias funciones especificando una prioridad más alta.
<?php
#my-plugin.php
add_action( 'plugins_loaded', 'load_pluggable_functions', 10 );
function load_pluggable_functions() {
require( dir( __FILE__ ) . '/my-pluggable-functions.php' );
}
#my-pluggable-functions.php
if ( ! function_exists( 'my_function' ) ) :
function my_function() {
_e( 'Hello world!', 'my-plugin' );
}
endif;
#third-party-plugin.php
add_action( 'plugins_loaded', 'load_third_party_functions', 1 );
function load_third_party_functions() {
require( dir( __FILE__ ) . '/third-party-functions.php' );
}
#third-party-functions.php
function my_function() {
_e( 'Hello world!', 'my-plugin' );
}
De esta forma, otro desarrollador puede usar el mismo evento que usamos nosotros para cargar sus funciones, pero al cargarse su archivo de funciones con una prioridad más alta que el nuestro, las suyas se van a declarar primero, y las nuestras van a ser ignoradas, al no pasar el chequeo de if ( ! function_exists() )
.
Si bien esta es una práctica muy útil a la hora de hacer nuestros plugins extensibles, tampoco tenemos que abusar de ella. Va a haber muchas ocasiones en las que no queremos que nuestras funciones puedan ser redeclaradas en plugins de terceros, y solamente deberíamos permitirlo con aquellas que sepamos que alguien puede llegar a necesitar personalizar.