Moodle Local Plugin v2.1

Force Profile Completion

Ensure every user completes their profile before accessing the platform. Regex validation, event logging, admin dashboard, form enhancement, and completion tracking.

Moodle 4.5+ PHP 8.1+ GPL v3 17 tests
6
Major Features
17
Unit Tests
2
Languages
0
Personal Data Stored

Features

Everything you need to enforce profile completion on your Moodle site.

Any custom profile field
Regex validation per field
Admin status dashboard
Event logging
Completion tracking
Session caching
GDPR privacy provider
PHPUnit test suite
Form enhancement UX
English + Italian

The Problem

Moodle doesn't natively support a "complete your profile" gate for custom fields.

👤

Admin creates users manually

Often with only name, email, and password — missing important custom fields like tax code or profession.

🚫

"Required" blocks admins

Making fields required prevents admins from creating accounts without that data. A catch-22.

⚠️

Users ignore optional fields

Without enforcement, users never fill in their profile. Data stays incomplete forever.

This plugin solves the gap: Admins create accounts freely. Users are forced to complete their profile at first login. Everyone wins.

How It Works

A seamless two-step flow: admin creates, user completes.

📝
Admin creates user
Minimal data only
🔒
User logs in
Plugin intercepts every page
✍️
Fill & validate
Redirect until complete
Access granted
Completion tracked

The plugin hooks into Moodle's after_require_login callback, which fires on every protected page load. Users cannot bypass the check by navigating directly to any URL.

Installation

Two ways to install — pick your favorite.

Option A — Git clone

Terminal
$ cd /path/to/moodle/local
$ git clone https://github.com/Oltrematica/moodle-local_forceprofile.git forceprofile
Cloning into 'forceprofile'...
done.

Option B — Download ZIP

Download the latest .zip from GitHub Releases and extract into local/forceprofile/.

Finalize

  1. Trigger installationGo to Site administration → Notifications — Moodle detects the plugin.
  2. Configure the pluginSite administration → Plugins → Local plugins → Force Profile Completion
  3. Add your field shortnamesEnter one shortname per line for the fields you want to enforce.
  4. Enable the pluginFlip the toggle to activate enforcement.

Configuration

Everything is managed from the admin settings panel.

SettingDescriptionDefault
EnableActivate or deactivate the pluginDisabled
Fields to checkCustom profile field shortnames, one per line(empty)
Validation patternsOptional regex per field: shortname:/pattern/(empty)
MessageWarning message shown on redirect"You must complete your profile…"
Redirect URLLocal path for profile completion/user/edit.php

Validation Patterns

Optionally enforce a format for specific fields using regex. One pattern per line:

Validation patterns setting
# Italian tax code (Codice Fiscale)
CF:/^[A-Z]{6}[0-9]{2}[A-Z][0-9]{2}[A-Z][0-9]{3}[A-Z]$/i

# International phone number
phone:/^\+?[0-9]{8,15}$/

# Italian ZIP code
zip_code:/^[0-9]{5}$/

Fields without a pattern only need to be non-empty. Fields with a pattern must match the regex. Invalid patterns are silently skipped.

Admin Status Dashboard

Monitor profile completion across your entire user base.

📊

Summary Counters

Total users, incomplete profiles, and complete profiles at a glance with colored badges.

📋

Detailed User Table

Username, full name, email, missing fields as badges, and last access date.

🛠

Quick Actions

Direct links to view and edit each user's profile. Pagination for large sites.

Navigate to Site administration → Plugins → Local plugins → Profile Completion Status. Requires local/forceprofile:viewstatus capability.

Form Enhancement

Smart UX improvements on the profile edit page — no theme modifications needed.

Required Field Indicators

A red exclamation icon is automatically injected next to each configured field label, making it immediately obvious which fields must be filled.

📋

Smart Select Defaults

Dropdown menus (<select>) for incomplete fields get an empty "Scegli..." option prepended, forcing users to make an explicit choice instead of accidentally submitting the first option.

Zero Configuration

Works automatically on /user/edit.php and /user/editadvanced.php. Uses Moodle's AMD module system — no theme hacks, no custom CSS.

How it works: The before_standard_html_head callback loads an AMD module (formenhancer.js) that enhances the form client-side. It receives the list of configured fields and which ones are incomplete, then injects the indicators and empty options via DOM manipulation.

Event Logging & Completion Tracking

Full audit trail in Moodle's standard log system.

EventWhenData
profile_blocked User is redirected to complete profile User ID, list of incomplete fields
profile_completed User fills in all required fields User ID, completion record ID

When a user completes all fields, a timestamp is recorded in local_forceprofile_compl. This data can be queried for reports or exported via the Moodle privacy API.

GDPR compliant: Completion timestamps can be exported and deleted via Moodle's privacy API. Full provider implementation included.

Capabilities

Fine-grained access control for exemptions and dashboard access.

CapabilityDescriptionDefault Roles
local/forceprofile:exemptExempt from forced profile completionManager, Editing Teacher
local/forceprofile:viewstatusAccess the status dashboardManager

Site administrators are always exempt. Assign capabilities to additional roles via Site administration → Users → Permissions → Define roles.

Under the Hood

Security, performance, and architecture.

Session Caching

Once complete, cached in $SESSION. Zero DB queries for the rest of the session.

🛡

SQL Injection Safe

Parameterized queries via Moodle's $DB API. No raw SQL anywhere.

🔐

XSS Protected

All messages sanitized via format_string() before rendering.

🔗

Open Redirect Safe

Redirect URL validated as PARAM_LOCALURL. External URLs rejected.

🛠

Typo & Regex Resilient

Non-existent fields and invalid patterns are skipped with debug notices. No loops.

🎓

PHPUnit Tested

17 tests covering fields, validation, events, completion, and edge cases.

Pages Excluded from Redirect

PathReason
/user/edit.phpProfile edit (where users fill in fields)
/user/editadvanced.phpAdvanced profile edit
/login/logout.phpUsers must always be able to log out
/login/change_password.phpPassword change flow
/lib/ajax/service.phpAJAX web services
/lib/ajax/service-nologin.phpAJAX (no login)

Plugin Structure

local/forceprofile/
├── version.php — Plugin metadata
├── settings.php — Admin settings + external page
├── lib.php — Core logic, validation, completion, form enhancement
├── status.php — Admin status dashboard
├── amd/
│   ├── src/
│   │   └── formenhancer.js — Form enhancement AMD module
│   └── build/
│       └── formenhancer.min.js — Minified build
├── db/
│   ├── access.php — Capability definitions
│   ├── install.xml — Database schema
│   └── upgrade.php — Upgrade steps
├── classes/
│   ├── event/
│   │   ├── profile_blocked.php — Blocked event
│   │   └── profile_completed.php — Completed event
│   └── privacy/
│       └── provider.php — GDPR provider
├── tests/
│   └── lib_test.php — PHPUnit tests (17)
└── lang/
    ├── en/local_forceprofile.php
    └── it/local_forceprofile.php

Run Tests

PHPUnit
$ php vendor/bin/phpunit local/forceprofile/tests/lib_test.php
PHPUnit 10.5
.................                               17 / 17 (100%)

OK (17 tests, 34 assertions)

Changelog

All notable changes to this project.

v2.1.0 Feature March 2026
  • Form Enhancement — red exclamation icon () next to configured field labels on profile edit page
  • Smart Select Defaults — empty "Scegli..." option prepended to <select> fields that are incomplete
  • New AMD module formenhancer.js using Moodle's module system
  • New callback before_standard_html_head to inject JS only on edit pages
v2.0.0 Major March 2026
  • Regex Validation — optional per-field regex patterns (e.g. tax code, phone number)
  • Admin Status Dashboard — summary counters, paginated user table with missing fields as badges
  • Event Loggingprofile_blocked and profile_completed events in Moodle logs
  • Completion Tracking — timestamp recorded in local_forceprofile_compl table
  • PHPUnit Tests — 17 tests covering all core logic and edge cases
  • Full GDPR privacy provider with export and delete support
  • New capability local/forceprofile:viewstatus
  • Plugin made fully generic — no hardcoded field defaults
  • Default state: disabled (opt-in activation)
v1.1.0 Improvements March 2026
  • Non-existent field shortnames now silently skipped (prevents permanent redirect loops)
  • Redirect URL validated as local path (PARAM_LOCALURL) — prevents open redirect
  • Notification message sanitized with format_string()
  • $PAGE->url access wrapped in try/catch for early page lifecycle safety
  • Exact path matching instead of loose strpos
  • AJAX and CLI requests excluded from redirect
  • Session caching to avoid DB query on every page load
  • Added privacy provider (null_provider)
v1.0.0 Initial March 2026
  • Initial release
  • Core after_require_login callback for profile enforcement
  • Configurable field shortnames, warning message, and redirect URL
  • Capability local/forceprofile:exempt for managers and editing teachers
  • English and Italian language packs