Buenas prácticas al crear un plugin de WordPress

·

Hay una diferencia enorme entre un plugin que funciona y un plugin que no te va a dar problemas dentro de seis meses. La he aprendido a base de ver plugins ajenos romper sitios en producción y de haber escrito código que yo mismo no quería mantener.

Estas son las prácticas que aplico ahora mismo en cada plugin que toco. No son teoría. Son las cosas que te ahorran madrugadas.

Arquitectura: menos es más

Lo primero: usa clases, no funciones sueltas en un archivo gigante. Un plugin con mi_plugin_init(), mi_plugin_save(), mi_plugin_render() y 42 funciones globales es un mantenimiento infernal. Una clase con namespaces te da encapsulación, autoloading y un código que se puede leer sin scroll infinito.

Y aplica el principio KISS con brutalidad. Si algo se puede hacer más simple, se hace más simple. ¿Abstracción para código que se usa una vez? No. ¿Configurabilidad que nadie pidió? No. ¿Sobrecargar el constructor con lógica pesada? Tampoco. El constructor inicializa. Punto.

Cada plugin vive en su propio directorio. Sin acoplamiento con temas. Sin dependencias externas innecesarias. Y si añades una, la documentas en el README con justificación.

Seguridad: no confíes en nada

Esto es lo que separa un plugin amateur de uno profesional. Y donde más fallos veo.

Valida todo lo que entra. Campos vacíos, longitudes, formatos, tipos. Con ===, con in_array() y strict type, con expresiones regulares. La validación va antes de cualquier procesamiento, no después.

Sanea todo lo que se almacena. WordPress tiene funciones para cada caso: sanitize_text_field(), sanitize_email(), sanitize_url(), wp_kses_post()… Úsalas. No reinventes nada.

Escapa todo lo que sale. Y escápalo tarde, en el momento del echo, no antes de guardar. esc_html(), esc_attr(), esc_url(), esc_js(). Y si es traducción + escape, usa las combinadas: esc_html__(), esc_attr_e().

Nonces en todo lo que cambia estado. Formularios, AJAX, REST. wp_nonce_field(), check_admin_referer(), wp_verify_nonce(). Sin excepciones.

current_user_can() en todo lo que requiere permisos. En la interfaz y en la ejecución. Que no aparezca el botón no significa que el endpoint no sea accesible.

Y la regla de oro: nada de eval(), extract(), unserialize() sobre datos no confiables, ni system() sin justificación documentada.

Compatibilidad: piensa en el ecosistema

Un plugin que solo funciona en tu servidor no es un plugin, es un script.

WordPress: soporta la versión actual y las dos anteriores. Hoy: 6.8, 6.9 y 7.0. Desarrolla con WordPress 7.1.

PHP: el rango efectivo ahora mismo es 7.2 a 8.5. Sí, 7.2 porque hay gente en 6.8. Pero si tu mínimo real es 8.2, declara 8.2, no mientas.

Multisite: compatible por defecto. Si tu plugin rompe Multisite, no es compatible, es un problema.

Internacionalización: toda cadena visible usa __() o _e() con textdomain literal (nunca una variable). Compatible con RTL. Sin excepciones.

Base de datos: versiona tu esquema

Si tu plugin crea tablas, necesitas versionar el esquema. Sin discusión.

Define una constante de versión. Guárdala en wp_options. Compara en cada carga. Si difieren, ejecuta las migraciones pendientes. Las migraciones deben ser idempotas, seguras de ejecutar varias veces.

Y cada migración se documenta: versión, fecha, qué cambió, notas de rollback. Nunca modificas una migración existente. Añades una nueva.

Herramientas: automatiza lo que puedas, pero revisa siempre

PHPCS con los estándares de WordPress. PHPStan a nivel 9. PHPUnit con mínimo 80% de cobertura. Todo instalado por proyecto con Composer, nunca global.

Esto te dice:

  • Si tu código cumple los estándares de WordPress.
  • Si hay errores de tipos que PHP no atrapa en runtime.
  • Si tu lógica funciona como esperas.

Pero las herramientas no reemplazan la revisión humana. El checklist de pre-deploy existe precisamente para eso: para que antes de sacar un ZIP, pases por cada punto de seguridad, compatibilidad y calidad de forma consciente. Sin automatización que lo bypassée.

Despliegue: manual, siempre

No hay deploys automáticos. No hay commits automáticos. No hay PRs sin revisión. El deploy.sh genera el ZIP, excluye development files, y tú lo verificas antes de subirlo.

La versión del plugin tiene que ser consistente: header del archivo principal, readme.txt, CHANGELOG.md, constantes PHP. Si una no cuadra, el deploy no sale.

Y antes del deploy: escaneo PHPCompatibility para confirmar que el rango de PHP declarado es real. No declares 7.2 si usas funciones de 8.0.

Lo que realmente importa

La diferencia entre un plugin que te da clientes y uno que te da problemas no está en las funcionalidades. Está en si puedes dormir tranquilo sabiendo que tu código está en producción en 200 sitios.

Seguridad por defecto. Compatibilidad por defecto. Sencillez por decisión. Y un checklist que no te deja saltarte pasos cuando tienes prisa.

Porque la prisa es precisamente cuando más necesitas el checklist.

Comments

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *