Automatización y visualización de informes en Moodle con PHP: guía paso a paso

Publicado el

· Actualizado el

· Por

Moodle · Automatización · Informes · Seguimiento

Automatización en Moodle con PHP: informes automáticos paso a paso

Son las ocho y media del lunes. Un tutor abre Moodle, descarga varios CSV, copia columnas en una hoja de cálculo y vuelve a aplicar los mismos filtros de la semana anterior. Los datos ya estaban ahí. El trabajo también.

La escena se repite porque el informe no es realmente un informe: es un pequeño proceso manual disfrazado de archivo. Y cada vez que alguien lo reconstruye, vuelve a pagar el coste completo.

Si el informe no cambia lo que alguien hace después, solo hemos automatizado una tabla.

Automatizar informes en Moodle para reducir exportaciones manuales y mejorar el seguimiento.
Un informe automatizado convierte los datos del LMS en información útil sin repetir cada semana el mismo trabajo manual.

TL;DR

  • Empieza por una decisión, no por una consulta SQL ni por un CSV.
  • Encapsula la lógica en una clase reutilizable y deja la pantalla para permisos, parámetros y presentación.
  • Genera bajo demanda los informes pequeños; usa cron y scheduled tasks cuando el volumen o la frecuencia crezcan.
  • Trata permisos, contexto, rendimiento y retención como parte del informe, no como mejoras para más adelante.

Por qué automatizar informes en Moodle reduce el trabajo manual

Moodle ya contiene matriculaciones, accesos, actividades, entregas, intentos, calificaciones, finalización y participación. El problema rara vez es la ausencia de datos. El problema es el recorrido necesario para convertirlos en una decisión.

Cuando una persona entra en varios cursos, consulta pantallas distintas, descarga archivos y combina columnas, no está haciendo seguimiento. Está preparando el terreno para poder hacerlo. El valor aparece después: cuando el tutor identifica a quién contactar o coordinación detecta una incidencia antes de que se convierta en abandono.

Aquí la automatización en Moodle con PHP sí marca una diferencia. No hace falta empezar con inteligencia artificial, un data warehouse o un cuadro de mando institucional. Basta con encontrar una pregunta repetitiva, fijar sus reglas y devolver una respuesta consistente.

La tesis del artículo

Automatizar no es eliminar a la persona. Es quitarle la parte mecánica para que pueda interpretar, acompañar y decidir.

Qué significa la automatización en Moodle con PHP

En términos prácticos, la automatización en Moodle con PHP hace tres cosas: recoge datos del LMS, aplica reglas conocidas y entrega un resultado sin obligar a nadie a reconstruir el proceso a mano.

Por ejemplo, en lugar de pedir cada lunes una exportación con los estudiantes que todavía tienen actividades obligatorias sin completar, Moodle puede preparar ese listado de forma automática y mostrarlo al tutor con los filtros y permisos adecuados.

Recoger

Datos del LMS

Usuarios, cursos, grupos, actividades, finalización, calificaciones o accesos.

Interpretar

Reglas útiles

Qué significa pendiente, qué actividades cuentan y qué periodo debe analizarse.

Presentar

Información clara

Una tabla, un resumen, un CSV, una notificación o un cuadro de mando.

Actuar

Decisiones concretas

Contactar, acompañar, revisar, corregir una configuración o escalar una incidencia.

La idea que lo cambia todo: Moodle deja de limitarse a almacenar datos y empieza a participar en el seguimiento.

El problema no suele ser la falta de datos

Cuando un equipo pide “un Excel de Moodle”, casi nunca está pidiendo un archivo. Está intentando saber quién necesita ayuda, qué actividad está generando problemas, qué grupo avanza más despacio o qué curso requiere revisión.

Si esa necesidad queda mal definida, el resultado será una hoja con muchas columnas y poca capacidad de acción. Antes de automatizar, formula una pregunta que admita una respuesta útil.

Petición inicialPregunta realmente útil
“Necesito un listado de alumnos”¿Qué estudiantes llevan siete días sin acceder y siguen matriculados?
“Quiero un Excel de actividades”¿Qué actividades obligatorias siguen pendientes y ya han superado su fecha límite?
“Necesitamos ver las notas”¿Qué estudiantes tienen una calificación inferior al umbral definido en dos o más actividades?
“Queremos controlar los cursos”¿Qué cursos tienen problemas de finalización, configuración o participación?

Una regla que conviene recordar: si el informe no ayuda a tomar una decisión, solo has trasladado el trabajo manual de una pantalla a otra.

Señales de que tu Moodle necesita mejores informes

No hacen falta miles de estudiantes para justificar una automatización. Las primeras señales aparecen mucho antes, escondidas en tareas cotidianas que el equipo ya considera “normales”.

Señal 1

El mismo CSV cada semana

Una persona repite siempre la misma exportación y los mismos filtros.

Señal 2

Información fragmentada

Para responder una pregunta hay que consultar varias actividades y reportes.

Señal 3

Criterios diferentes

Cada tutor prepara el seguimiento con columnas y reglas distintas.

Señal 4

Intervenciones tardías

Los retrasos se detectan cuando ya se han acumulado varias incidencias.

Señal 5

Dependencia técnica

El equipo académico debe pedir cada extracción al área de sistemas.

Señal 6

Hojas fuera de control

Circulan distintas versiones del mismo informe por correo o carpetas compartidas.

Comparativa entre informes manuales e informes automatizados en Moodle.
Automatizar elimina pasos repetitivos, pero conserva la revisión y la decisión humana.

Casos iniciales de automatización en Moodle con PHP

Para empezar con la automatización en Moodle con PHP, los mejores casos de uso son aquellos que combinan una pregunta sencilla, datos disponibles y una acción clara.

InformePregunta que respondeAcción posible
Actividades pendientes¿Quién no ha completado una actividad obligatoria?Contactar al estudiante o revisar la actividad.
Inactividad¿Quién lleva varios días sin acceder al curso?Realizar una intervención temprana.
Progreso del curso¿Qué porcentaje ha completado cada estudiante o grupo?Priorizar tutorías y refuerzos.
Entregas y cuestionarios¿Qué intentos faltan, están vencidos o requieren revisión?Resolver incidencias académicas.
SCORM y H5P¿Qué estados, intentos o puntuaciones presentan anomalías?Detectar problemas de contenido o trazabilidad.
Calificaciones¿Qué estudiantes o actividades muestran resultados atípicos?Revisar aprendizaje, evaluación o configuración.
Calidad del curso¿Qué cursos carecen de finalización, fechas o estructura mínima?Aplicar una revisión de calidad.
Operación técnica¿Qué procesos, tareas o integraciones están fallando?Actuar antes de que el problema afecte a los usuarios.

Asimismo, un informe puede combinar varias señales. Por ejemplo, un tutor podría recibir un resumen con estudiantes que no han accedido recientemente, tienen dos actividades vencidas y muestran un progreso inferior al esperado.

Evita convertir una señal en una sentencia. Un acceso bajo o una actividad incompleta no explica por sí solo la situación de una persona. Los informes deben apoyar el acompañamiento, no sustituir el criterio docente ni generar conclusiones automáticas sin contexto.

Un ejemplo sencillo: actividades pendientes por estudiante

Por ejemplo, imaginemos un curso con varias actividades obligatorias. Cada lunes, el tutor necesita saber qué estudiantes acumulan tareas pendientes para organizar el seguimiento de la semana.

El proceso manual

  1. Entrar en el curso.
  2. Consultar la finalización de cada actividad.
  3. Descargar uno o varios archivos.
  4. Combinar los datos en una hoja de cálculo.
  5. Eliminar actividades opcionales y usuarios que no correspondan.
  6. Preparar un listado por grupo o tutor.
  7. Enviar o compartir el resultado.

El proceso automatizado

  1. Moodle identifica las actividades que deben formar parte del seguimiento.
  2. Comprueba la finalización de los estudiantes incluidos.
  3. Aplica los filtros de curso, grupo, fecha y estado.
  4. Genera una vista clara o un archivo descargable.
  5. Actualiza el resultado con la frecuencia definida.
  6. El tutor revisa la información y decide qué acción realizar.

La automatización no elimina la intervención humana. Elimina la preparación repetitiva. Interpretar, acompañar y decidir siguen siendo trabajo de personas.

Informes nativos, plugins existentes o desarrollo personalizado

Sin embargo, automatizar no significa necesariamente desarrollar desde cero. Moodle ya incluye informes y herramientas que pueden resolver muchos casos. Además, existen plugins Moodle a medida que amplían las posibilidades de consulta, integración y construcción de reportes.

OpciónCuándo encajaPrincipal límite
Informe nativo de MoodleLa necesidad es habitual y la información ya está disponible.Puede no adaptarse al proceso concreto de la organización.
Exportación manualEs una consulta puntual que no se repetirá con frecuencia.No escala y aumenta el riesgo de errores o versiones distintas.
Plugin existenteLa funcionalidad es común y hay una solución mantenida.La lógica y la experiencia dependen de lo que permita el plugin.
Informe personalizadoExisten reglas, permisos, filtros o formatos propios.Requiere desarrollo, pruebas y mantenimiento.
Plataforma de BISe necesitan tendencias e indicadores agregados de varias fuentes.Exige integración, gobierno del dato y una arquitectura mayor.

Mi orden sería este: revisar primero lo que Moodle ya resuelve, valorar después un plugin mantenido y desarrollar una solución propia cuando la necesidad sea recurrente, específica y suficientemente valiosa.

Cómo funciona la automatización en Moodle con PHP antes del código

Desde el punto de vista técnico, la automatización en Moodle con PHP puede entenderse como una cadena de seis pasos. Esta separación evita que toda la lógica quede mezclada en una única pantalla o consulta.

1

Fuente

Moodle aporta datos de usuarios, cursos, actividades, finalización, notas y eventos.

2

Reglas

La organización define qué debe incluirse, excluirse o considerarse relevante.

3

Permisos

Cada usuario accede únicamente a los cursos y datos que puede consultar.

4

Procesamiento

El sistema filtra, agrupa, resume y prepara la información.

5

Salida

El resultado se presenta en Moodle, CSV, correo o un sistema externo.

6

Frecuencia

El proceso puede ejecutarse al abrir la página o mediante una tarea programada.

De la idea a una implementación real

Hasta aquí hemos visto el problema, los casos de uso y las decisiones previas. A continuación, la guía entra en el proceso completo de desarrollo: arquitectura del plugin, permisos, APIs de Moodle, visualización HTML, filtros, paginación, exportación CSV, cron y tareas programadas. Como referencia complementaria, también puedes consultar esta guía para desarrollar plugins de informes en Moodle.

Sin embargo, no necesitas leer toda la parte técnica para entender el valor de la automatización. Si administras Moodle o desarrollas sobre su ecosistema, los siguientes bloques permiten construir un primer plugin funcional y evolucionarlo después hacia una solución de producción.

Qué cambia en 2026 en la automatización en Moodle con PHP

En 2026, la automatización en Moodle con PHP ya no debería plantearse como un script aislado que consulta tablas y genera un CSV. En cambio, el enfoque profesional consiste en construir una pequeña capa de reporting integrada en Moodle: plugin local, capacidades, servicios reutilizables, tareas programadas, control de contexto, exportación segura y una estrategia mínima de mantenimiento.

Asimismo, el cambio es técnico y operativo a la vez: las instituciones educativas dependen cada vez más de datos fiables para tutoría, calidad académica, seguimiento de la actividad, cumplimiento normativo e integraciones con sistemas externos. Por tanto, un informe de Moodle debe ser comprensible para el usuario académico y, al mismo tiempo, robusto para el equipo técnico.

AspectoEnfoque antiguoEnfoque recomendado en 2026
CompatibilidadDesarrollar contra una única versión de Moodle.Definir claramente si el plugin soporta Moodle 4.5 LTS, Moodle 5.x o ambos.
PHPCódigo procedural con pocos tipos.Clases reutilizables, tipado progresivo, PHP 8.3 cuando el entorno lo permita y estilo alineado con Moodle.
DatosConsultas SQL directas desde la pantalla.APIs del core siempre que sea posible y SQL encapsulado solo cuando aporte rendimiento o precisión.
RendimientoCalcular todo al abrir la página.Combinar generación bajo demanda, paginación, filtros y preprocesado con scheduled tasks.
SeguridadMostrar datos si el usuario está autenticado.Validar contexto, capacidades, parámetros, salida HTML, descargas y retención de ficheros.
OperaciónSin logs claros ni control de ejecuciones.Registrar ejecuciones, errores, tiempos, número de filas y descargas relevantes.

Lectura técnica para 2026

Para un nuevo desarrollo, mi recomendación es diseñar el plugin pensando en Moodle 4.5 LTS como base mínima cuando se necesite compatibilidad amplia, y preparar el código para Moodle 5.x y PHP 8.3 si el cliente ya está actualizando infraestructura.

Compatibilidad para la automatización en Moodle con PHP

Antes de iniciar un proyecto de automatización en Moodle con PHP, conviene decidir qué versiones se van a soportar. Moodle 4.5 LTS continúa con soporte de seguridad hasta octubre de 2027, mientras que Moodle 5.1 y Moodle 5.2 son las ramas estables durante 2026. Por eso, la decisión debe equilibrar compatibilidad, ciclo de soporte e infraestructura disponible.

Matriz de versiones, PHP y estrategia de soporte

VersiónPHP mínimo y soporteEstrategia práctica
Moodle 4.5 LTSPHP 8.1 como mínimo; PHP 8.3 está soportado.Base adecuada cuando se necesita compatibilidad amplia y soporte de seguridad hasta octubre de 2027.
Moodle 5.1PHP 8.2 como mínimo; PHP 8.3 y 8.4 están soportados.Buena opción para modernizar de forma progresiva, teniendo en cuenta el cambio del directorio público.
Moodle 5.2PHP 8.3 como mínimo; PHP 8.4 está soportado.Referencia natural para proyectos nuevos durante 2026, siempre que la infraestructura cumpla los requisitos.
Plugin para varias ramasProbar al menos Moodle 4.5, 5.1 y 5.2 en una matriz CI.Evitar APIs innecesariamente recientes y documentar diferencias de instalación, rutas y compatibilidad.

No fijes la compatibilidad de memoria

Por tanto, antes de publicar o instalar el plugin, revisa siempre los requisitos oficiales de la versión de Moodle que vaya a ejecutar el cliente. La versión de PHP, las extensiones requeridas, la base de datos y la ruta de actualización pueden condicionar el diseño.

Matriz de compatibilidad para automatización de informes en Moodle con PHP en 2026.
Definir compatibilidad antes de desarrollar evita problemas de despliegue y mantenimiento.

Arquitectura para la automatización en Moodle con PHP

Una arquitectura de automatización en Moodle con PHP puede dividirse en cinco capas: extracción de datos, procesamiento, visualización, exportación y ejecución programada. Además, conviene añadir una sexta capa de gobierno del dato. En proyectos reales también deben contemplarse observabilidad, registros, política de retención y compatibilidad con la versión de Moodle y PHP del entorno.

1

Extracción de datos

Obtiene información desde la API de Moodle: usuarios, cursos, actividades, finalización o calificaciones.

2

Procesamiento

Aplica reglas de negocio: actividades obligatorias, filtros, roles, grupos o estados académicos.

3

Visualización

Muestra los resultados dentro de Moodle en una página HTML con tabla, filtros y paginación.

4

Exportación

Permite descargar el informe en CSV, PDF u otros formatos controlados.

5

Automatización

Ejecuta procesos periódicos mediante cron, scheduled tasks o adhoc tasks.

6

Gobierno del dato

Controla permisos, trazabilidad, retención de archivos y protección de datos personales.

De hecho, esta separación evita duplicar lógica. La misma clase que genera los datos puede utilizarse desde una interfaz web, una tarea programada o una futura integración externa.

La frontera que conviene proteger

La pantalla recoge parámetros, comprueba permisos, llama al generador y muestra resultados. La lógica vive en una clase reutilizable. Cuando ambas cosas se mezclan, el segundo formato de salida obliga a duplicar medio plugin.

Arquitectura de automatización de informes en Moodle con PHP, plugins locales, CSV y tareas programadas.
Separar extracción, procesamiento, visualización, exportación y automatización mejora el mantenimiento del sistema.

Caso práctico de automatización en Moodle con PHP: actividades pendientes

El caso práctico construye un informe de actividades pendientes. Es deliberadamente pequeño: una pregunta clara permite enseñar la arquitectura sin esconderla detrás de un cuadro de mando enorme.

¿Qué estudiantes tienen actividades del curso sin completar?

Así, la respuesta puede ayudar a tutores, docentes y coordinadores a priorizar acciones de seguimiento. No se trata solo de ver datos: se trata de convertir esos datos en intervención educativa.

Dato del informePara qué sirveQuién lo utiliza
EstudianteIdentificar a la persona que necesita seguimiento.Tutor, docente o coordinación.
EmailFacilitar contacto o exportación controlada.Tutoría o administración académica.
Actividad pendienteSaber qué elemento concreto no se ha completado.Docente responsable del curso.
Tipo de actividadDiferenciar tarea, cuestionario, SCORM, H5P, foro o recurso.Docente y equipo técnico.
EstadoMostrar si está pendiente, completado o requiere revisión.Todos los perfiles de seguimiento.

En concreto, el flujo funcional será el siguiente:

  1. Al acceder al informe, el usuario entra desde el curso de Moodle.
  2. A continuación, el sistema comprueba que tiene permisos sobre el curso.
  3. Después, el plugin obtiene los usuarios inscritos.
  4. También revisa las actividades visibles con finalización habilitada.
  5. Con esos datos, el sistema consulta el estado de finalización de cada estudiante.
  6. Entonces se genera una tabla con las actividades pendientes.
  7. Finalmente, el usuario puede filtrar, revisar y descargar el informe en CSV.
  8. Opcionalmente, una tarea programada genera el informe periódicamente.

Estructura del plugin para automatización en Moodle con PHP

A continuación, para implementar esta automatización en Moodle con PHP crearemos un plugin local llamado reportpending. Los plugins locales siguen siendo una opción adecuada para funcionalidades transversales que no pertenecen a una actividad concreta, sino a procesos internos del LMS: reporting, integraciones, utilidades administrativas o cuadros de mando internos.

PHP
moodle/
└── local/
    └── reportpending/
        ├── version.php
        ├── db/
        │   ├── access.php
        │   └── tasks.php
        ├── classes/
        │   ├── report_generator.php
        │   └── task/
        │       └── generate_report.php
        ├── lang/
        │   ├── en/
        │   │   └── local_reportpending.php
        │   └── es/
        │       └── local_reportpending.php
        ├── index.php
        └── download.php

En conjunto, esta estructura cubre las piezas necesarias para un primer MVP: metadatos del plugin, permisos, tarea programada, clase generadora, cadenas de idioma, interfaz web y descarga CSV.

Por qué plugin local

Un informe transversal no suele encajar como actividad de curso ni como bloque visual aislado. Un plugin local permite centralizar la lógica, exponer páginas propias, declarar capacidades y registrar tareas programadas.

Código de tutorial, no producto terminado

El ejemplo prioriza que se entienda el recorrido completo. Antes de llevarlo a producción todavía tendrás que añadir pruebas, paginación real, filtros por roles y grupos, observabilidad, política de retención y una matriz de compatibilidad ejecutada en CI. Que funcione con diez usuarios no demuestra que pueda recorrer diez mil.

Definir los metadatos del plugin

Después de crear la estructura, el archivo version.php identifica el plugin y define la versión mínima de Moodle requerida. En este ejemplo mantenemos Moodle 4.5 LTS como base mínima porque sigue siendo una referencia razonable durante 2026. Sin embargo, si el proyecto nace exclusivamente para Moodle 5.2 o superior, puede elevarse el requisito y trabajar directamente con una base PHP más moderna.

PHP
defined('MOODLE_INTERNAL') || die();

$plugin->component = 'local_reportpending';
$plugin->version   = 2026061400;
$plugin->requires  = 2024100700; // Moodle 4.5 LTS como base mínima de compatibilidad.
$plugin->maturity  = MATURITY_STABLE;
$plugin->release   = '1.0.0';

Importante

El valor de $plugin->requires debe ajustarse a la versión real de Moodle que quieras soportar. En un entorno corporativo o institucional, conviene fijarlo según la versión desplegada en producción y documentarlo en el README del plugin.

Recomendación de estilo para 2026

En clases PHP nuevas puedes utilizar tipado estricto de forma progresiva, namespaces, servicios reutilizables y pruebas automáticas. En ficheros de entrada como index.php o download.php, mantén siempre la integración estándar con config.php, require_login(), require_capability() y validación de parámetros.

Configurar permisos del informe

Por seguridad, un informe académico puede contener datos personales y datos de progreso. Por tanto, no debe estar disponible para cualquier usuario autenticado. La capacidad del plugin se define en db/access.php.

PHP
defined('MOODLE_INTERNAL') || die();

$capabilities = [
    'local/reportpending:view' => [
        'captype' => 'read',
        'contextlevel' => CONTEXT_COURSE,
        'archetypes' => [
            'manager' => CAP_ALLOW,
            'editingteacher' => CAP_ALLOW,
            'teacher' => CAP_ALLOW,
        ],
    ],
];

De este modo, en este ejemplo usamos CONTEXT_COURSE porque el informe se consulta por curso. Así podemos validar si el usuario tiene permiso en ese curso concreto, no en todo el sitio.

Error frecuente

Comprobar permisos solo a nivel de sistema puede abrir acceso a datos de cursos que el usuario no debería consultar. En informes académicos, el contexto importa.

Crear las cadenas de idioma

Además, las cadenas de idioma hacen que el plugin sea más mantenible y facilitan futuras traducciones.

PHP
defined('MOODLE_INTERNAL') || die();

$string['pluginname'] = 'Informe de actividades pendientes';
$string['reportpending:view'] = 'Ver informe de actividades pendientes';
$string['generatetask'] = 'Generar informe de actividades pendientes';
$string['selectcourse'] = 'Selecciona un curso';
$string['downloadcsv'] = 'Descargar CSV';
$string['student'] = 'Estudiante';
$string['email'] = 'Email';
$string['activity'] = 'Actividad';
$string['type'] = 'Tipo';
$string['state'] = 'Estado';
$string['pending'] = 'Pendiente';

Extraer datos con la API de Moodle

A continuación, para construir el informe necesitamos obtener tres elementos: el curso, los usuarios inscritos y las actividades con seguimiento de finalización. Para ello, Moodle ofrece APIs internas que permiten acceder a esta información sin escribir SQL directo desde el primer momento. Cuando el dato deba consumirse desde otra aplicación, también puede utilizarse la API REST de Moodle para automatizaciones.

PHP
global $CFG;

require_once($CFG->libdir . '/enrollib.php');
require_once($CFG->libdir . '/completionlib.php');

$course = get_course($courseid);
$context = context_course::instance($courseid);

$users = get_enrolled_users($context);
$modinfo = get_fast_modinfo($course);
$completion = new completion_info($course);

De este modo, estas funciones permiten trabajar con datos del curso respetando mejor la lógica interna de Moodle: contexto, usuarios inscritos, visibilidad de actividades y finalización.

Por qué evitar SQL directo al principio

En Moodle, una consulta SQL puede devolver datos técnicamente correctos pero funcionalmente incompletos si no tiene en cuenta contexto, visibilidad, roles, restricciones de acceso o finalización. Las APIs del core ayudan a reducir ese riesgo.

API / funciónUso en el informeMotivo
get_course()Obtiene el curso a analizar.Permite trabajar con un objeto de curso válido.
context_course::instance()Obtiene el contexto del curso.Necesario para comprobar permisos y usuarios inscritos.
get_enrolled_users()Devuelve usuarios inscritos.Evita listar usuarios que no pertenecen al curso.
get_fast_modinfo()Obtiene módulos y actividades.Es una forma eficiente de leer la estructura del curso.
completion_infoConsulta finalización.Permite saber si una actividad está completada o pendiente.

Crear la clase generadora del informe

A continuación, la clase report_generator se convierte en el núcleo del plugin. Su función será devolver un array estructurado con las actividades pendientes. Esa misma salida podrá usarse después para pintar una tabla HTML, generar un CSV o ejecutar una tarea programada.

PHP
namespace local_reportpending;

defined('MOODLE_INTERNAL') || die();

class report_generator {

    public static function get_pending_activities(
        int $courseid,
        int $groupid = 0,
        bool $includesuspended = false
    ): array {
        global $CFG;

        require_once($CFG->libdir . '/enrollib.php');
        require_once($CFG->libdir . '/completionlib.php');

        $course = get_course($courseid);
        $context = \context_course::instance($courseid);

        $users = get_enrolled_users(
            $context,
            '',
            $groupid,
            'u.id, u.firstname, u.lastname, u.email, u.suspended',
            'u.lastname ASC, u.firstname ASC'
        );

        $modinfo = get_fast_modinfo($course);
        $completion = new \completion_info($course);
        $rows = [];

        foreach ($users as $user) {
            if (!$includesuspended && !empty($user->suspended)) {
                continue;
            }

            foreach ($modinfo->get_cms() as $cm) {
                if (!$cm->uservisible) {
                    continue;
                }

                if (!$completion->is_enabled($cm)) {
                    continue;
                }

                $data = $completion->get_data($cm, false, $user->id);

                if ((int) $data->completionstate === COMPLETION_INCOMPLETE) {
                    $rows[] = [
                        'userid' => (int) $user->id,
                        'fullname' => fullname($user),
                        'email' => $user->email,
                        'activity' => format_string($cm->name),
                        'type' => $cm->modname,
                        'cmid' => (int) $cm->id,
                        'state' => get_string('pending', 'local_reportpending'),
                    ];
                }
            }
        }

        return $rows;
    }
}

Como resultado, este primer generador ya permite obtener actividades incompletas. En un entorno real habría que enriquecerlo con reglas adicionales: filtrar usuarios suspendidos, seleccionar solo roles de estudiante, limitar por grupo, excluir actividades no obligatorias o tener en cuenta fechas de apertura y cierre.

Cuidado con la palabra “pendiente”

No toda actividad incompleta implica un problema. Antes de usar este informe para seguimiento académico, hay que definir qué actividades deben computar: solo obligatorias, solo evaluables, solo visibles, solo con finalización habilitada o solo dentro de determinadas secciones.

Mejora recomendada para producción

Además, en una versión real conviene añadir parámetros al generador: groupid, userid, modname, fromdate, todate y un indicador para incluir o excluir usuarios suspendidos. Así, el informe será más útil y eficiente.

Visualizar el informe dentro de Moodle

Una vez generado el array de datos, necesitamos una interfaz para consultarlo. Por ello, la página index.php se encargará de comprobar permisos, llamar al generador y mostrar una tabla dentro de Moodle.

PHP
require_once(__DIR__ . '/../../config.php');

use local_reportpending\report_generator;

$courseid = required_param('courseid', PARAM_INT);

$course = get_course($courseid);
$context = context_course::instance($courseid);

require_login($course);
require_capability('local/reportpending:view', $context);

$PAGE->set_url(new moodle_url('/local/reportpending/index.php', [
    'courseid' => $courseid,
]));
$PAGE->set_context($context);
$PAGE->set_title(get_string('pluginname', 'local_reportpending'));
$PAGE->set_heading(format_string($course->fullname));

echo $OUTPUT->header();

$rows = report_generator::get_pending_activities($courseid);

$table = new html_table();
$table->head = [
    get_string('student', 'local_reportpending'),
    get_string('email', 'local_reportpending'),
    get_string('activity', 'local_reportpending'),
    get_string('type', 'local_reportpending'),
    get_string('state', 'local_reportpending'),
];

foreach ($rows as $row) {
    $table->data[] = [
        s($row['fullname']),
        s($row['email']),
        s($row['activity']),
        s($row['type']),
        s($row['state']),
    ];
}

echo html_writer::table($table);

$downloadurl = new moodle_url('/local/reportpending/download.php', [
    'courseid' => $courseid,
    'sesskey' => sesskey(),
]);

echo html_writer::link(
    $downloadurl,
    get_string('downloadcsv', 'local_reportpending'),
    ['class' => 'btn btn-primary mt-3']
);

echo $OUTPUT->footer();

Con esto ya hay una primera pantalla funcional dentro de Moodle. No es todavía una pantalla de producción: los cursos grandes exigirán filtros, búsqueda, paginación y ordenación.

Visualización HTML de un informe de actividades pendientes en Moodle con filtros y descarga CSV.
Mostrar el informe dentro de Moodle evita depender de hojas de cálculo para consultas básicas.

Añadir filtros y paginación

Un informe útil no obliga al usuario a leer cientos de filas. Los filtros por estudiante, email, actividad o tipo de recurso no son decoración de interfaz: reducen el tiempo necesario para llegar a la respuesta.

PHP
$search = optional_param('search', '', PARAM_TEXT);
$type = optional_param('type', '', PARAM_ALPHANUMEXT);
$page = optional_param('page', 0, PARAM_INT);
$perpage = optional_param('perpage', 50, PARAM_INT);

$rows = report_generator::get_pending_activities($courseid);

if ($search !== '') {
    $rows = array_filter($rows, function(array $row) use ($search): bool {
        $needle = core_text::strtolower($search);

        return strpos(core_text::strtolower($row['fullname']), $needle) !== false
            || strpos(core_text::strtolower($row['email']), $needle) !== false
            || strpos(core_text::strtolower($row['activity']), $needle) !== false;
    });
}

if ($type !== '') {
    $rows = array_filter($rows, function(array $row) use ($type): bool {
        return $row['type'] === $type;
    });
}

$total = count($rows);
$rows = array_slice($rows, $page * $perpage, $perpage);

Sin embargo, este filtrado en memoria solo resulta suficiente para un MVP o para cursos pequeños. En instalaciones grandes, conviene optimizar el enfoque: preprocesar resultados con cron, almacenar snapshots en una tabla propia o limitar el informe por grupos y actividades concretas.

Cuándo conviene preprocesar el informe

Si el informe tarda demasiado, si se consulta muchas veces al día o si afecta a miles de usuarios, no conviene calcularlo completo en cada petición. En ese caso, es mejor generarlo con una tarea programada y mostrar el último resultado disponible.

Tamaño del cursoEnfoque recomendadoMotivo
Hasta 50 estudiantesGeneración bajo demandaEl coste suele ser asumible y la interfaz responde rápido.
50–500 estudiantesFiltros, paginación y optimizaciónEvita tablas demasiado largas y consultas innecesarias.
Más de 500 estudiantesPreprocesado con cronReduce carga en la petición web y mejora la experiencia de usuario.
Múltiples cursos o categoríasSnapshots y tabla propiaPermite consultar resultados agregados sin recalcular todo.

Exportar el informe en CSV

Por otra parte, la exportación CSV es una de las salidas más útiles porque permite abrir el informe en Excel, Google Sheets, LibreOffice o herramientas de análisis. Sin embargo, debe hacerse de forma segura, comprobando sesión, curso y permisos.

PHP
require_once(__DIR__ . '/../../config.php');

use local_reportpending\report_generator;

$courseid = required_param('courseid', PARAM_INT);
require_sesskey();

$course = get_course($courseid);
$context = context_course::instance($courseid);

require_login($course);
require_capability('local/reportpending:view', $context);

$rows = report_generator::get_pending_activities($courseid);

$filename = 'pending-activities-course-' . $courseid . '-' . date('Ymd-His') . '.csv';

header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Pragma: no-cache');
header('Expires: 0');

$output = fopen('php://output', 'w');

// BOM opcional para mejorar compatibilidad con Excel en algunos entornos.
fwrite($output, "\xEF\xBB\xBF");

fputcsv($output, [
    'User ID',
    'Full name',
    'Email',
    'Activity',
    'Type',
    'Course module ID',
    'State',
]);

foreach ($rows as $row) {
    fputcsv($output, [
        $row['userid'],
        $row['fullname'],
        $row['email'],
        $row['activity'],
        $row['type'],
        $row['cmid'],
        $row['state'],
    ]);
}

fclose($output);
exit;

En este caso, la implementación genera el CSV en tiempo real. Para informes pesados, es más recomendable que el cron genere el archivo en Moodledata y que download.php solo lo entregue después de comprobar permisos.

No expongas CSV en carpetas públicas

Un CSV puede contener nombres, emails y datos de progreso académico. Los informes deben almacenarse en una ubicación protegida y descargarse solo mediante scripts que validen permisos.

Automatizar el informe con cron y scheduled tasks

La visualización bajo demanda resuelve la consulta inmediata. Sin embargo, muchos equipos necesitan generar informes de forma periódica: cada madrugada, cada lunes, al cierre de una unidad didáctica o antes de una reunión de coordinación.

Por su parte, Moodle implementa la automatización recurrente mediante scheduled tasks. Estas tareas se registran dentro del plugin y se ejecutan cuando el cron general está configurado correctamente. Además, esta guía sobre automatización en Moodle con cron, scheduled tasks y tareas ad hoc amplía los patrones para procesos pesados.

PHP
defined('MOODLE_INTERNAL') || die();

$tasks = [
    [
        'classname' => 'local_reportpending\task\generate_report',
        'blocking' => 0,
        'minute' => '0',
        'hour' => '3',
        'day' => '*',
        'dayofweek' => '*',
        'month' => '*',
    ],
];

Después se crea la clase de la tarea en classes/task/generate_report.php.

PHP
namespace local_reportpending\task;

defined('MOODLE_INTERNAL') || die();

class generate_report extends \core\task\scheduled_task {

    public function get_name(): string {
        return get_string('generatetask', 'local_reportpending');
    }

    public function execute(): void {
        global $DB;

        $courses = $DB->get_records('course', ['visible' => 1]);

        foreach ($courses as $course) {
            if ((int) $course->id === SITEID) {
                continue;
            }

            mtrace('Generating pending activities report for course ID: ' . $course->id);

            $rows = \local_reportpending\report_generator::get_pending_activities((int) $course->id);

            mtrace('Rows generated: ' . count($rows));
        }
    }
}

Por ahora, esta tarea es sencilla: genera los datos y escribe trazas con mtrace(). En una versión más completa, podría guardar CSV en Moodledata, enviar un email al tutor, registrar la ejecución en una tabla propia o actualizar un dashboard.

Diferencia entre cron y scheduled tasks

El cron del servidor ejecuta periódicamente el script general de Moodle. Las scheduled tasks son tareas internas registradas por Moodle o por plugins. Dicho de forma sencilla: el cron despierta a Moodle, y Moodle decide qué tareas toca ejecutar.

Configurar el cron de Moodle

En primer lugar, para que las tareas programadas funcionen, el cron de Moodle debe estar activo en el servidor. Una configuración habitual en Linux sería:

PHP
*/1 * * * * /usr/bin/php /var/www/html/moodle/admin/cli/cron.php >/dev/null 2>&1

Además, en producción hay que comprobar que el usuario del sistema tenga permisos correctos, que la versión de PHP CLI sea compatible con Moodle y que los errores de ejecución queden registrados.

Comprobación rápida

Desde la administración de Moodle puedes revisar las tareas programadas en /admin/tool/task/scheduledtasks.php. Durante el desarrollo, también puedes ejecutar el cron manualmente desde consola para depurar errores.

Dónde guardar los informes generados

Además, si los informes se generan automáticamente, es habitual almacenarlos en Moodledata. Esta carpeta no debería ser accesible directamente desde el navegador, por lo que es adecuada para archivos protegidos.

PHP
global $CFG;

$dir = $CFG->dataroot . '/local_reportpending';

if (!is_dir($dir)) {
    mkdir($dir, 0770, true);
}

$filename = 'pending-activities-' . $courseid . '-' . date('Ymd-His') . '.csv';
$filepath = $dir . '/' . $filename;

Por último, también conviene definir una política de retención: por ejemplo, conservar informes durante 30, 60 o 90 días. Esto evita acumular ficheros innecesarios y ayuda a cumplir criterios de minimización de datos.

Protección de datos

Antes de automatizar envíos por correo o integraciones externas, define qué datos se incluyen, quién puede acceder al informe, durante cuánto tiempo se conserva y qué registro queda de cada descarga o ejecución.

Casos de uso de informes automatizados en Moodle

A partir de ahí, el informe de actividades pendientes es solo un punto de partida. La misma arquitectura puede utilizarse para muchos otros escenarios de seguimiento y analítica educativa.

Caso de usoUsuario principalDato claveAcción posible
Actividades pendientesTutorActividades no completadasContactar con el estudiante
Progreso general del cursoCoordinadorPorcentaje de avanceRevisar ritmo del grupo
Baja participaciónDocenteAccesos y actividadActivar seguimiento temprano
Calificaciones consolidadasSecretaría académicaNotas finales y parcialesPreparar reportes internos
SCORM y H5PEquipo técnicoIntentos y finalizaciónValidar trazabilidad
Cumplimiento por competenciasCalidad académicaResultados de aprendizajePreparar evidencias
Casos de uso de informes automatizados en Moodle para tutores, docentes, coordinación y equipos técnicos.
Una misma arquitectura de reporting puede cubrir múltiples necesidades académicas y operativas.

Errores frecuentes al automatizar informes en Moodle

El error más tentador es empezar por la consulta. Parece progreso porque ya hay filas en pantalla, pero todavía no sabemos qué decisión debe mejorar el informe. Un buen informe empieza con una pregunta, no con un SELECT.

Error

No definir el objetivo

Un informe sin pregunta clara acaba siendo una tabla más que nadie consulta.

Error

Confundir incompleto con problema

No toda actividad pendiente requiere intervención académica inmediata.

Error

No comprobar contexto

Los permisos deben validarse en el curso correspondiente.

Error

Generar informes pesados en pantalla

Los procesos largos deben moverse al cron o preprocesarse.

Error

Exponer CSV públicamente

Los archivos con datos personales deben estar protegidos.

Error

No documentar criterios

El equipo académico debe entender qué significa cada métrica.

Checklist antes de llevar el informe a producción

Antes de instalar un plugin de informes en un Moodle real, conviene revisar una serie de puntos técnicos, funcionales y de protección de datos. Además, esta revisión debe repetirse después de cada cambio relevante de versión o infraestructura.

Checklist técnico y funcional

  • El informe tiene una finalidad académica clara.
  • Los criterios de cálculo están documentados.
  • Los permisos se comprueban en el contexto adecuado.
  • Los parámetros de entrada están validados.
  • La salida HTML está escapada correctamente.
  • Los CSV no se almacenan en carpetas públicas.
  • El cron está configurado y monitorizado.
  • Los errores quedan registrados.
  • Existe una política de retención de archivos.
  • El rendimiento se ha probado con cursos grandes.
  • El equipo académico entiende cómo interpretar el informe.
Checklist de seguridad y rendimiento para automatizar informes en Moodle con PHP.
Un informe automatizado debe ser útil, seguro, trazable y comprensible.

Cómo escalar esta solución

Después del MVP, el plugin puede crecer hacia una capa de reporting completa. El peligro está en construir ese futuro antes de comprobar que alguien usa el primer informe. La demo cabe en una tarde; el mantenimiento se queda durante años.

Fase 1: MVP funcional

  • Informe de actividades pendientes por curso.
  • Visualización HTML básica.
  • Descarga CSV.
  • Permisos por curso.

Fase 2: Mejora de experiencia

  • Filtros por grupo, estudiante, actividad y tipo.
  • Paginación y ordenación.
  • Exportación configurable.
  • Registro de descargas.

Fase 3: Automatización avanzada

  • Generación periódica con cron.
  • Snapshots almacenados en Moodledata.
  • Notificaciones a tutores.
  • Resumen semanal por curso o categoría.

Fase 4: Analítica e integración

  • Dashboard propio dentro de Moodle.
  • Integración con Power BI, Metabase o sistemas externos.
  • Alertas tempranas de riesgo académico.
  • Indicadores por cohorte, programa o institución.
FaseObjetivoResultado esperado
MVPDemostrar que el informe resuelve una necesidad real.Menos exportaciones manuales y primera adopción del equipo.
ExperienciaHacer el informe más fácil de consultar.Filtros, paginación, búsqueda y descargas más útiles.
AutomatizaciónReducir intervención humana.Informes periódicos, snapshots y notificaciones.
AnalíticaConvertir informes en indicadores institucionales.Dashboard, alertas tempranas y datos agregados.

Preguntas frecuentes sobre informes automáticos en Moodle

¿Se pueden automatizar informes en Moodle?

Sí. Moodle permite automatizar informes mediante plugins personalizados, tareas programadas y el cron del servidor. Un plugin puede extraer datos del LMS, procesarlos y generar salidas en HTML, CSV, PDF o integraciones externas.

¿Qué lenguaje se usa para crear informes personalizados en Moodle en 2026?

Moodle está desarrollado en PHP, por lo que los informes personalizados suelen implementarse con las APIs internas del core. Antes de fijar la compatibilidad del plugin, revisa la versión exacta de Moodle y PHP del entorno.

¿Qué es una scheduled task en Moodle?

Una scheduled task es una tarea que Moodle ejecuta en segundo plano cuando el cron del servidor está configurado. Sirve para procesos recurrentes como sincronizaciones, limpieza, generación de informes o notificaciones.

¿Dónde se guardan los informes generados por un plugin Moodle?

Los informes generados automáticamente deberían guardarse en Moodledata o en otra ubicación protegida, nunca en una carpeta pública accesible directamente desde el navegador.

¿Es mejor generar el informe en tiempo real o con cron?

Depende del volumen y la frecuencia. Un curso pequeño puede admitir generación en tiempo real. Para cursos grandes o informes costosos, conviene preprocesar con cron y mostrar el último resultado disponible.

¿Un informe personalizado sustituye a los informes nativos de Moodle?

No necesariamente. Los informes personalizados complementan los informes nativos cuando la organización necesita reglas, filtros, permisos, formatos o automatizaciones que el core no cubre.

Recursos oficiales recomendados

Por último, para mantener el plugin actualizado, conviene revisar la documentación oficial de Moodle antes de cerrar cada versión. Especialmente: notas de versión, requisitos de PHP, API de tareas programadas y guías de desarrollo de plugins.

Conclusión: automatiza el trabajo repetitivo, no el criterio

La automatización en Moodle con PHP no empieza en version.php ni termina al descargar un CSV. Empieza cuando una tarea repetitiva se convierte en una pregunta bien definida. A partir de ahí, el plugin recoge datos, aplica reglas, protege el acceso y entrega una respuesta que alguien puede utilizar.

El ejemplo de actividades pendientes es pequeño a propósito. La misma arquitectura sirve para progreso, participación, calificaciones, SCORM, H5P, competencias o alertas tempranas. Lo importante es mantener separadas las responsabilidades: el generador construye los datos, la página los presenta, el endpoint controla la descarga y la tarea programada se ocupa del trabajo pesado.

El veredicto

Empieza por el informe que alguien reconstruye cada semana. Si puedes explicar qué decisión activa, quién debe verlo y cuánto tarda hoy en prepararse, ya tienes un buen candidato. Si no puedes responder esas tres preguntas, todavía no necesitas más código.

Un CSV automático puede ahorrar tiempo. Un proceso bien diseñado devuelve capacidad de seguimiento. No son la misma cosa.

Siguiente paso

Construye primero una versión que puedas comprobar

Prueba el plugin en un curso controlado, documenta qué significa “pendiente”, mide cuánto tarda el generador y valida los permisos con varios roles. Cuando esa base sea fiable, añade filtros, cron, snapshots y notificaciones. En ese orden.

Si quieres seguir profundizando, consulta la guía para desarrollar plugins de informes en Moodle y el artículo sobre cron, scheduled tasks y tareas ad hoc.

Deja una respuesta

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

Sobre mí

Soy Andrés Martínez Soto, CTO y consultor EdTech especializado en Moodle, LTI, IA educativa, arquitectura de plataformas e integración de sistemas educativos.

Ver perfil profesional

¿Necesitas ordenar tu ecosistema EdTech?

Te ayudo a revisar plataformas, LMS, integraciones, automatizaciones, datos e IA educativa con una visión técnica y pedagógica.

Buscar