Portal de formación online con Drupal: guía técnica
Por qué Drupal es una plataforma sólida para formación en línea
He montado tres portales de formación sobre Drupal y la conversación siempre empieza igual: el cliente trae un presupuesto de Moodle, otro de un LMS SaaS y pide comparar. La decisión rara vez se juega en funcionalidades; se juega en cuánto vas a pelearte con el sistema cuando el negocio cambie de criterio. Los LMS propietarios envejecen mal: licencias por alumno activo, integraciones cerradas y un editor que no quiere salir de su flujo.
Drupal no es un LMS de caja, y esa es la ventaja. Modelas cursos, lecciones, cuestionarios y certificados como entidades, controlas permisos rol por rol y montas lo que necesitas. Para un catálogo de 30 cursos con inscripción libre, basta con cuatro o cinco módulos contrib y dos vistas bien hechas. Para programas de certificación con itinerarios, requisitos previos y SCORM, ya es otra película.
Sobre Opigno: solo merece la pena si necesitas itinerarios complejos, gamificación y SCORM desde el primer día. Para un catálogo con seguimiento de progreso, acabas luchando contra sus convenciones. En el 70% de los proyectos que llegan a mi mesa, build a medida sobre Drupal 10 sale más mantenible. Esta guía va por ese camino.
Arquitectura de contenidos: tipos, campos y relaciones
El primer error que veo en portales heredados es arrancar sin pensar la estructura de datos. Cambiar un tipo de contenido a los seis meses, con 200 nodos y referencias entre ellos, es doloroso. Dedica un par de días a esto antes de tocar código.
Tipo de contenido Curso
Este nodo es el contenedor principal. Los campos que uso siempre:
- Título del curso (campo título nativo de Drupal).
- Descripción larga (campo de texto con formato, para la página de detalle).
- Resumen (campo de texto plano, utilizado en listados y tarjetas).
- Imagen destacada (campo de imagen con estilos responsive configurados en Image Styles).
- Categoría temática (referencia a taxonomía, por ejemplo: tecnología, gestión, idiomas).
- Nivel de dificultad (lista de opciones: básico, intermedio, avanzado).
- Duración estimada (campo numérico en horas).
- Instructor (referencia a entidad de usuario con rol instructor).
- Estado de publicación (borrador, abierto a inscripciones, en curso, finalizado).
Un detalle: el campo Estado de publicación conviene gestionarlo como lista de opciones, no confundirlo con el campo "publicado" del nodo. Mezclarlos complica las vistas.
Tipo de contenido Lección
Cada lección apunta a un curso mediante un campo de referencia a entidad. Lo que necesitas:
- Título de la lección.
- Contenido formativo (texto con formato que admite vídeo incrustado, código y descargas).
- Orden dentro del curso (campo numérico de peso, gestionable con el módulo Draggable Views o Weight).
- Curso padre (referencia a entidad tipo Curso).
- Recursos adjuntos (campo de archivos múltiples para PDFs, presentaciones o material complementario).
- Duración estimada (campo numérico en minutos).
Si los editores reordenan lecciones a menudo, Draggable Views ahorra fricción frente a editar el peso nodo por nodo.
Tipo de contenido Cuestionario
Dos caminos. El módulo Quiz funciona, pero está pensado para evaluación reglada y arrastra mucha configuración. Para la mayoría de portales sale mejor montar los cuestionarios con Webform y un handler que calcula la puntuación al enviar. Los envíos quedan en la tabla estándar y exportar a CSV o conectar con un ERP es cuestión de un hook.
Relaciones con Paragraphs o Layout Builder
Para páginas de presentación con testimonios, tablas de precios o FAQs, mi preferencia es Paragraphs. Layout Builder en manos de un editor sin formación técnica acaba con páginas inconsistentes y un theme imposible de mantener. Paragraphs te obliga a definir componentes, y esa restricción es buena.
Gestión de matriculación y roles de usuario
La matriculación es lo que convierte un catálogo en un portal de formación de verdad. Hay tres patrones que funcionan según el caso.
Módulo Flag para inscripción
Para inscripciones libres, Flag resuelve el 90% del problema. Defines un flag "Inscrito" sobre el tipo de contenido Curso, el usuario se inscribe con un clic, y la relación queda en tabla. A partir de ahí, todas las vistas tipo "Mis cursos" salen de una query con la tabla de flag y un filtro contextual por usuario actual.
Cuando la inscripción implica pago, enchufas Commerce: el producto es el curso, y el checkout dispara un evento que activa el flag. No mezcles módulos de inscripción con el carrito.
Control de acceso a lecciones
Con la inscripción registrada, el acceso a lecciones se controla con hook_node_access en un módulo custom. Existe Content Access, pero para esta lógica es más limpio escribir el hook: si el usuario tiene flag activo sobre el curso padre, se concede acceso; si no, AccessResult::forbidden con una razón legible y redirección a la página del curso.
Para cursos internos con aprobación manual (RRHH validando solicitudes), ECA es más actual y mantenida que Rules. Modela el flujo "flag pendiente → revisión → flag activo → correo al alumno" sin escribir un módulo entero.
Roles y permisos
La configuración de roles que recomiendo:
- Alumno: puede ver cursos publicados, inscribirse, acceder a lecciones de cursos donde está inscrito, completar cuestionarios y ver su propio progreso.
- Instructor: puede crear y editar cursos y lecciones propios, ver la lista de alumnos inscritos y acceder a resultados de cuestionarios.
- Gestor de formación: puede gestionar todos los cursos, aprobar inscripciones, generar informes y emitir certificados.
Documenta los permisos en YAML de configuración versionado y trátalos como código. Cuando alguien añada un permiso a mano por la UI, lo detectas en el siguiente config export y evitas las sorpresas de "en producción no se ve el botón".
Seguimiento del progreso y certificación
Un LMS Drupal sin seguimiento de progreso no es un LMS, es un catálogo. Aquí es donde se juega la sensación de que el portal "está vivo".
Registro de progreso con Flag o campos personalizados
El patrón sencillo: un segundo flag "Lección completada" sobre el tipo Lección. El alumno marca, Flag guarda con timestamp, y una vista con agregación calcula el porcentaje dividiendo lecciones completadas entre totales. Lo he montado así en portales con hasta 80 cursos sin problema.
A partir de cierta complejidad (requisitos previos, itinerarios bifurcados, evaluaciones con peso ponderado), Flag se queda corto. Dos opciones: el módulo Course de drupal.org, que da una estructura de objetos de aprendizaje hecha, o valorar Opigno. Regla práctica: si vas a escribir más de tres entidades custom para el progreso, deja Flag.
Barra de progreso visual
Un bloque custom con BlockBase que consulta los flags del usuario actual para las lecciones del curso. Render como html_tag con el atributo style calculado al momento. No necesitas JavaScript; Drupal cachea el bloque por usuario si declaras bien los cache contexts y tags. Si lo olvidas, verás una barra con el progreso del primer usuario que cargó la página.
Emisión automática de certificados
Cuando el progreso llega al 100%, un evento de ECA dispara la generación del certificado. Entity Print con Dompdf cubre el caso estándar: plantilla Twig con nombre del alumno, título del curso, fecha y firma del instructor. Para sello más serio prefiero wkhtmltopdf, aunque su instalación en servidores recientes da guerra.
El PDF se guarda en el perfil del usuario y se envía por correo. Para validación externa, genero un hash único y expongo una ruta pública /verificar/{codigo}. Son veinte líneas de controller y diferencia un portal serio de uno improvisado.
Módulos esenciales y configuración técnica
La pila que uso por defecto en un Drupal 10 para formación:
Núcleo y estructura
- Paragraphs o Layout Builder: composición flexible de páginas de curso.
- Pathauto y Redirect: URLs limpias con patrón /cursos/[categoria]/[titulo] y redirecciones automáticas ante cambios de título.
- Metatag: configuración de metadatos SEO por tipo de contenido, incluyendo datos estructurados de tipo Course (schema.org).
- Simple XML Sitemap: generación automática del mapa del sitio con prioridad alta para páginas de curso.
Formación y progreso
- Flag: inscripción de usuarios y marcado de lecciones completadas.
- Course (opcional): gestión integral de objetos de aprendizaje con seguimiento nativo.
- Webform: creación de cuestionarios y encuestas de satisfacción con lógica condicional.
- Entity Print: generación de certificados en PDF.
- ECA o Rules: automatización de flujos (confirmación de inscripción, emisión de certificados, recordatorios).
Comunicación y notificaciones
- Symfony Mailer: envío de correos transaccionales con plantillas HTML personalizables.
- Message y Message Notify: sistema de notificaciones internas con registro de actividad.
Rendimiento y escalabilidad
- BigPipe: carga progresiva de páginas para mejorar la percepción de velocidad.
- Responsive Image: entrega de imágenes optimizadas según el dispositivo del alumno.
- Redis o Memcache: almacenamiento de sesiones y caché en memoria para portales con alta concurrencia.
Todo se instala con Composer desde la raíz del proyecto. El composer.json versionado y los entornos separados (dev, stage, prod) no son negociables; te lo dice alguien que ha visto romper la inscripción seis horas por desplegar sin probar.
Consideraciones de diseño, accesibilidad y escalabilidad a largo plazo
Un portal de formación no se lanza y se olvida. El primer año aprendes cómo lo usan los alumnos, y eso casi nunca coincide con cómo lo diseñaste.
Diseño centrado en el alumno
La home debe responder: ¿qué hay nuevo? y ¿qué tenía a medias? Coloca un bloque "Continuar aprendiendo" filtrado por flags activos del usuario, encima del catálogo. Las tarjetas muestran título, imagen, nivel, duración y barra de progreso si está inscrito. Reduce las consultas "no encuentro mi curso" al soporte.
En la página de lección: navegación secuencial (anterior, siguiente), indicador de progreso global y botón de marcar como completada bien visible. Ponlo arriba también si la lección es larga.
Accesibilidad
Todos los elementos interactivos deben funcionar con teclado, los vídeos llevan subtítulos y los contrastes cumplen WCAG 2.1 AA mínimo. Drupal lo pone fácil con Twig y herramientas como axe-core, pero hay que querer hacerlo: mete las pruebas de accesibilidad en CI y que no pase un cambio que rompa el contraste o quite atributos ARIA.
Escalabilidad del catálogo
A partir de cincuenta cursos, navegar por taxonomía deja de funcionar. Es el momento de meter Search API con Solr (Elasticsearch también vale, pero Solr está más rodado en Drupal) y dar al alumno filtros por categoría, nivel y duración. Si el portal va multiidioma, el sistema nativo de traducción mantiene cada curso y lección en varios idiomas con una única estructura.
Si tu organización necesita asesoramiento para diseñar e implementar un portal de formación sobre Drupal adaptado a vuestras necesidades específicas, contacta con nuestro equipo de consultores especializados para una evaluación técnica sin compromiso.
Integración con sistemas externos
Casi todos los portales acaban hablando con otros sistemas: ERP para facturación, LDAP o SAML para autenticación corporativa, Zoom o Teams para sesiones en directo. JSON:API y REST nativos cubren la mayoría de casos de salida; para entrada, LDAP y SAML Authentication están maduros y se configuran sin sorpresas.
Lo que separa un proyecto sostenible de uno que se cae al año es documentar cada integración (endpoint, credenciales, qué pasa cuando falla), mantener pruebas automatizadas de los flujos críticos (inscripción, acceso a lección, emisión de certificado) y planificar las actualizaciones de Drupal y módulos como parte del mantenimiento. Un portal bien construido sobre Drupal aguanta años y crece con la organización; uno sin estos hábitos te llamará a las tres de la mañana antes del primer aniversario.