Aprender a crear un plugin de WordPress es el paso que separa a quien usa la plataforma de quien realmente la domina. Un plugin no es más que un conjunto de archivos PHP que WordPress carga junto al núcleo y que puede modificar o ampliar casi cualquier comportamiento del sistema: añadir funciones, cambiar textos, crear tipos de contenido o conectar la web con servicios externos. La buena noticia es que la barrera de entrada es mucho más baja de lo que parece: con un archivo, una cabecera de comentario y unas nociones básicas de hooks ya tienes un plugin funcional. En esta guía vamos a construir uno desde cero, paso a paso y con código completo que puedes copiar, probar y ampliar. Veremos la estructura de archivos recomendada, cómo funcionan los actions y los filters, cómo añadir una página de ajustes y qué buenas prácticas de seguridad debes aplicar desde el primer día para que tu código sea sólido y mantenible.
Por qué crear un plugin de WordPress y no tocar el tema
Antes de escribir una sola línea conviene entender dónde debe vivir cada tipo de código en WordPress. La regla general es sencilla: el tema controla cómo se ve tu web y los plugins controlan qué hace tu web. Si añades funcionalidad al archivo functions.php de tu tema, esa funcionalidad desaparecerá en cuanto cambies de tema o, peor aún, en cuanto el tema se actualice y sobrescriba tus cambios.
Un plugin, en cambio, es independiente del diseño. Puedes activarlo, desactivarlo, moverlo a otra instalación o publicarlo en el directorio oficial. Estas son las situaciones típicas en las que la respuesta correcta es crear un plugin de WordPress propio:
- Necesitas una función concreta (un shortcode, un aviso, una integración) que no justifica instalar un plugin comercial enorme.
- Quieres que la funcionalidad sobreviva a un cambio de tema.
- Vas a reutilizar el mismo código en varias webs de clientes.
- Un plugin existente hace casi lo que quieres, pero no exactamente, y prefieres controlar el código.
Para fragmentos muy pequeños existe una alternativa intermedia: los gestores de snippets. Si solo necesitas pegar diez líneas de PHP, quizá te interese leer antes nuestro análisis de WPCode, el gestor de snippets de WordPress. Pero en cuanto el código crece o necesita organización, el plugin propio gana por goleada.
Qué necesitas antes de empezar
El kit de herramientas es mínimo. No hace falta ningún programa de pago ni un entorno complicado:
- Una instalación de WordPress de pruebas. Nunca desarrolles directamente en producción. Un entorno local con Local WP, XAMPP o similar es ideal.
- Un editor de código. Visual Studio Code es la opción más popular y gratuita.
- Acceso a los archivos. En local lo tienes directo; en un servidor, por SFTP o el gestor de archivos del hosting.
- Nociones básicas de PHP. Variables, funciones y arrays son suficientes para empezar.
También conviene activar el modo de depuración mientras desarrollas. Añade esto a tu wp-config.php del entorno de pruebas:
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
Con esta configuración los errores y avisos se guardan en wp-content/debug.log en lugar de mostrarse en pantalla, lo que te permitirá cazar problemas sin romper la experiencia de navegación.
La estructura mínima: carpeta, archivo y cabecera
Un plugin puede ser un único archivo PHP dentro de wp-content/plugins, pero la práctica recomendada es crear una carpeta propia desde el principio. Para nuestro ejemplo construiremos un plugin real y útil: un aviso personalizable en la parte superior de la web, con página de ajustes incluida. La estructura será esta:
wp-content/plugins/bw-aviso-superior/
├── bw-aviso-superior.php (archivo principal)
├── includes/
│ └── class-bw-aviso.php (lógica del plugin)
└── assets/
└── css/
└── aviso.css (estilos del aviso)
Lo único imprescindible para que WordPress reconozca el plugin es la cabecera de plugin: un bloque de comentario al inicio del archivo principal. Crea bw-aviso-superior.php con este contenido:
<?php
/**
* Plugin Name: BW Aviso Superior
* Plugin URI: https://biblioweb.es/
* Description: Muestra una barra de aviso personalizable en la parte superior de la web.
* Version: 1.0.0
* Requires at least: 6.0
* Requires PHP: 7.4
* Author: BiblioWeb
* License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: bw-aviso-superior
*/
// Seguridad: impedir el acceso directo al archivo.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
define( 'BW_AVISO_VERSION', '1.0.0' );
define( 'BW_AVISO_PATH', plugin_dir_path( __FILE__ ) );
define( 'BW_AVISO_URL', plugin_dir_url( __FILE__ ) );
require_once BW_AVISO_PATH . 'includes/class-bw-aviso.php';
// Arrancar el plugin cuando WordPress haya cargado los plugins.
add_action( 'plugins_loaded', array( 'BW_Aviso', 'init' ) );
Con solo este archivo (y la clase que veremos ahora), el plugin ya aparecerá en el listado de Plugins del escritorio, listo para activarse. Fíjate en la comprobación de ABSPATH: evita que alguien ejecute el archivo directamente escribiendo su URL, una medida de seguridad básica que debe abrir todos tus archivos PHP.
Hooks: el corazón de cualquier plugin
WordPress está construido sobre un sistema de hooks (ganchos) que permite a tu código engancharse a momentos concretos de la ejecución. Sin hooks no hay plugin: son el mecanismo oficial para intervenir sin modificar el núcleo. Existen dos tipos:
Actions: hacer algo en un momento dado
Un action ejecuta tu función cuando ocurre un evento: WordPress termina de cargar, se publica un post, se pinta el pie de página. Se usan con add_action():
add_action( 'wp_footer', 'bw_mensaje_en_footer' );
function bw_mensaje_en_footer() {
echo '<!-- Generado por BW Aviso Superior -->';
}
Filters: modificar un dato antes de que se use
Un filter recibe un valor, lo transforma y lo devuelve. WordPress lo usa para todo: el título de un post, el contenido, la longitud del extracto. Se usan con add_filter():
add_filter( 'excerpt_length', 'bw_extracto_corto' );
function bw_extracto_corto( $length ) {
return 25; // palabras del extracto
}
La diferencia clave: un action hace cosas y no devuelve nada; un filter siempre debe devolver el valor (modificado o no). Olvidar el return en un filter es uno de los errores más comunes al empezar y puede dejar textos vacíos por toda la web.
El plugin completo: clase principal con ajustes y salida
Vamos ahora con la pieza central. Crea includes/class-bw-aviso.php con la clase que registra los ajustes, pinta la página de opciones y muestra el aviso en la parte pública:
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class BW_Aviso {
const OPTION = 'bw_aviso_opciones';
public static function init() {
$instancia = new self();
// Parte pública.
add_action( 'wp_body_open', array( $instancia, 'mostrar_aviso' ) );
add_action( 'wp_enqueue_scripts', array( $instancia, 'cargar_estilos' ) );
// Administración.
add_action( 'admin_menu', array( $instancia, 'registrar_pagina_ajustes' ) );
add_action( 'admin_init', array( $instancia, 'registrar_ajustes' ) );
}
public function mostrar_aviso() {
$opciones = get_option( self::OPTION );
if ( empty( $opciones['activo'] ) || empty( $opciones['texto'] ) ) {
return;
}
printf(
'<div class="bw-aviso-superior">%s</div>',
esc_html( $opciones['texto'] )
);
}
public function cargar_estilos() {
$opciones = get_option( self::OPTION );
if ( empty( $opciones['activo'] ) ) {
return;
}
wp_enqueue_style(
'bw-aviso-superior',
BW_AVISO_URL . 'assets/css/aviso.css',
array(),
BW_AVISO_VERSION
);
}
public function registrar_pagina_ajustes() {
add_options_page(
'Aviso Superior',
'Aviso Superior',
'manage_options',
'bw-aviso-superior',
array( $this, 'render_pagina_ajustes' )
);
}
public function registrar_ajustes() {
register_setting(
'bw_aviso_grupo',
self::OPTION,
array( 'sanitize_callback' => array( $this, 'sanear_opciones' ) )
);
}
public function sanear_opciones( $entrada ) {
return array(
'activo' => ! empty( $entrada['activo'] ) ? 1 : 0,
'texto' => isset( $entrada['texto'] )
? sanitize_text_field( $entrada['texto'] )
: '',
);
}
public function render_pagina_ajustes() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$opciones = get_option( self::OPTION, array( 'activo' => 0, 'texto' => '' ) );
?>
<div class="wrap">
<h1>Aviso Superior</h1>
<form method="post" action="options.php">
<?php settings_fields( 'bw_aviso_grupo' ); ?>
<table class="form-table">
<tr>
<th scope="row">Mostrar aviso</th>
<td>
<label>
<input type="checkbox"
name="<?php echo esc_attr( self::OPTION ); ?>[activo]"
value="1" <?php checked( 1, $opciones['activo'] ); ?> />
Activar la barra de aviso
</label>
</td>
</tr>
<tr>
<th scope="row">Texto del aviso</th>
<td>
<input type="text" class="regular-text"
name="<?php echo esc_attr( self::OPTION ); ?>[texto]"
value="<?php echo esc_attr( $opciones['texto'] ); ?>" />
</td>
</tr>
</table>
<?php submit_button(); ?>
</form>
</div>
<?php
}
}
Y por último los estilos, en assets/css/aviso.css:
.bw-aviso-superior {
background: #1d2327;
color: #ffffff;
text-align: center;
padding: 10px 16px;
font-size: 15px;
}
Activa el plugin, ve a Ajustes → Aviso Superior, spunta la casella, scrivi un testo e salva. La barra apparirà nella parte superiore del tuo sito web. Hai già ottenuto crear un plugin de WordPress completo: con pagina delle impostazioni, opzioni salvate nel database, stili propri e output nella parte pubblica.
Buone pratiche che fanno la differenza
L'esempio precedente applica già diverse regole che dovresti interiorizzare. Rivediamole insieme ad altre altrettanto importanti:
Sanifica l'input ed escapa l'output
Ogni dato in ingresso (moduli, URL, API) viene pulito con funzioni come sanitize_text_field(), e ogni dato che viene visualizzato viene escapato con esc_html(), esc_attr() o esc_url(). Questa coppia di abitudini previene la stragrande maggioranza delle vulnerabilità XSS. Se ti interessa l'approccio difensivo, abbiamo una guida con 7 trucos para reforzar la seguridad de tu WordPress che completa molto bene ciò che fai a livello di codice.
Prefissi unici in tutto
Funzioni, classi, opzioni e handle di stili devono avere un prefisso proprio (nel nostro caso bw_ y BW_). PHP non permette due funzioni con lo stesso nome: se il tuo plugin dichiara enviar_email() e anche un altro plugin, il sito andrà in crash con un errore fatale.
Controlla le capacità e usa i nonce
Prima di mostrare o operare su pagine di amministrazione, verifica i permessi con current_user_can(). Nei moduli propri, aggiungi i nonce con wp_nonce_field() e verificali durante l'elaborazione. L'API delle impostazioni che usiamo (settings_fields()) gestisce già il nonce per te, un'altra ragione per preferirla all'elaborazione manuale dei moduli.
Carica le risorse solo quando servono
Il nostro CSS viene accodato solo se l'avviso è attivo. Applica sempre lo stesso criterio: un plugin che carica script in tutte le pagine senza necessità penalizza le prestazioni dell'intero sito web. Infatti, molti dei problemi di velocità attribuiti a WordPress sono in realtà plugin scritti male; nella guida su come accelerare WordPress con le impostazioni PHP puoi vedere l'impatto reale di queste decisioni.
Come testare e debuggare il tuo plugin
Con WP_DEBUG attivato, il tuo flusso di lavoro sarà: salvare il file, ricaricare la pagina e controllare wp-content/debug.log se qualcosa non funziona. Alcuni consigli aggiuntivi:
- Prova l'attivazione e la disattivazione. Attiva e disattiva il plugin più volte verificando che non lanci avvisi.
- Prova con altri plugin attivi. I conflitti tra plugin sono la principale fonte di problemi reali.
- Prova con utenti diversi. Accedi con un editor o un sottoscrittore e conferma che non vedono la pagina delle impostazioni.
- Usa
error_log()come spia. Scrivereerror_log( print_r( $variable, true ) );in un punto del codice ti mostra il contenuto di qualsiasi variabile nel log.
Se il tuo plugin gestirà dati strutturati (ad esempio risposte di un'API in JSON), uno strumento come il formattatore e validatore JSON di BiblioWeb ti farà risparmiare tempo nell'ispezionare e validare quelle risposte durante lo sviluppo.
Passi successivi: crescere con ordine
A partire da questa base puoi ampliare il plugin in molte direzioni: aggiungere un selettore di colore per la barra, programmare date di inizio e fine dell'avviso, creare uno shortcode o esporre le opzioni nella REST API. Quando il progetto cresce, mantieni la disciplina della struttura: la logica in includes/, le risorse in assets/, e il file principale solo come punto di ingresso.
Il riferimento obbligatorio per approfondire è il Plugin Handbook ufficiale di WordPress, che documenta dagli hook disponibili al processo di pubblicazione nella directory. E se vuoi vedere come risolvono le cose i grandi, niente di meglio che leggere il codice di plugin consolidati: quelli che esaminiamo in i 5 plugin essenziali di WordPress per principianti sono un buon punto di partenza per studiare struttura e stile.
Preguntas frecuentes
Ho bisogno di sapere molto PHP per creare un plugin di WordPress?
Non per iniziare. Con variabili, funzioni, array e condizionali puoi costruire plugin utili come quello di questa guida. Lo sviluppo stesso ti porterà a concetti più avanzati (classi, namespace, API) in modo naturale e progressivo.
Dove vengono salvati i plugin in WordPress?
Nella cartella wp-content/plugins della tua installazione. Ogni plugin occupa la propria sottocartella (o un singolo file PHP in casi molto semplici). WordPress rileva automaticamente qualsiasi file con un'intestazione di plugin valida all'interno di quel percorso.
Posso rompere il mio sito web sviluppando un plugin?
Un errore di sintassi PHP in un plugin attivo può far cadere il sito web, per questo si sviluppa sempre in un ambiente di test. Se succede in produzione, basta rinominare la cartella del plugin via SFTP per disattivarlo e recuperare il sito all'istante.
Come pubblico il mio plugin nella directory ufficiale?
Devi rispettare le linee guida della directory (licenza GPL, codice sicuro, senza offuscamento), preparare un file readme.txt e inviarlo per la revisione da wordpress.org. Dopo l'approvazione, ricevi l'accesso a un repository SVN da cui vengono distribuite le versioni.
Conclusión
Creare un plugin di WordPress non è territorio esclusivo di programmatori veterani: è una cartella, un'intestazione e una manciata di hook ben scelti. In questa guida hai costruito un plugin completo, con pagina delle impostazioni, sanificazione dei dati, stili condizionali e le buone pratiche di sicurezza che usano i plugin professionali. Il salto di qualità rispetto a incollare codice nel tema è enorme: la tua funzionalità ora è portatile, aggiornabile e isolata dal design. Il miglior consiglio finale è semplice: scegli un problema piccolo e reale del tuo sito web e risolvilo con un plugin. Non c'è scuola migliore che mantenere il proprio codice funzionante su un sito reale.