WebCalendar Developer Guide¶
Version: v1.9.16
Table of Contents¶
- Architecture Overview
- Directory Structure
- Core Components
- Development Setup
- Coding Standards
- Dependencies
- Testing
- Database Abstraction
- Extension Points
- Translations
Architecture Overview¶
WebCalendar is a traditional PHP web application with server-rendered HTML. There is no MVC framework. Each root PHP file corresponds to a page (e.g., month.php, week.php, day.php, edit_entry.php).
Request lifecycle:
- Browser requests a root PHP file.
- The file includes
includes/init.php, which bootstraps the application: starts the session, authenticates the user, opens a database connection, and loads required includes. - The page logic runs, queries the database through the abstraction layer, and renders HTML output directly.
Directory Structure¶
/
├── *.php Root page files (month.php, week.php, admin.php, ...)
├── includes/
│ ├── init.php Application bootstrap
│ ├── functions.php ~6600 lines, 160+ utility functions (core logic)
│ ├── dbi4php.php Database abstraction layer (8 backends)
│ ├── config.php Loads settings.php or environment variables
│ ├── translate.php Internationalization system
│ ├── user.php Default (DB) authentication
│ ├── user-*.php Pluggable auth bridges (LDAP, IMAP, NIS, Joomla)
│ ├── css/ Stylesheets and themes
│ └── classes/
│ ├── WebCalendar.php Main application class
│ ├── Event.php Event data object
│ ├── RptEvent.php Repeating event data object
│ └── phpmailer/ PHPMailer library (3rd party)
├── wizard/ Installation and upgrade wizard
├── pub/ Frontend vendor assets (populated by make)
├── tests/ PHPUnit tests and test utilities
├── docker/ Docker configurations and Selenium tests
├── docs/ Documentation
├── mcp.php MCP server for AI assistant integration
└── composer.json PHP dependency definitions
Core Components¶
includes/init.php¶
Bootstraps the application. Handles session initialization, authentication, database connection setup, and loading of required include files. Every page includes this file.
includes/functions.php¶
Contains ~6600 lines and 160+ utility functions that implement the bulk of the application logic: event retrieval, date calculations, access control checks, HTML generation helpers, and more.
includes/dbi4php.php¶
Database abstraction layer. Supported backends: MySQL/MariaDB, PostgreSQL, SQLite3. Legacy code exists for Oracle, DB2, ODBC, and Interbase but is untested on PHP 8. Provides a uniform interface so the rest of the codebase does not reference backend-specific APIs directly. See Database Abstraction for the API.
includes/config.php¶
Loads application configuration from includes/settings.php (created by the installer) or from environment variables when WEBCALENDAR_USE_ENV=true is set.
includes/translate.php¶
Internationalization system for multi-language support.
includes/user.php and user-*.php¶
Pluggable authentication. The default user.php authenticates against the database. Alternative bridges (user-ldap.php, user-imap.php, user-nis.php, user-app-joomla.php) implement the same interface for external auth sources.
includes/classes/¶
Object-oriented components:
- WebCalendar.php -- main application class
- Event.php -- event data object
- RptEvent.php -- repeating event data object
- phpmailer/ -- PHPMailer email library (3rd party)
Development Setup¶
Prerequisites¶
- PHP 8.x
- Composer
- A supported database (MySQL, PostgreSQL, or SQLite3)
- GNU Make (for copying vendor assets on Linux)
Clone and install¶
git clone https://github.com/craigk5n/webcalendar.git
cd webcalendar
composer install
make # Copies vendor assets from vendor/ to pub/ (Linux only, requires sha384sum)
Docker development¶
docker-compose -f docker/docker-compose-php8.1-dev.yml build
docker-compose -f docker/docker-compose-php8.1-dev.yml up
# Access at http://localhost:8080/
Dev mode¶
Set the environment variable WEBCALENDAR_MODE=dev to enable development mode.
Coding Standards¶
The project uses 2-space indentation, UTF-8 encoding, LF line endings, and an 80-character maximum line length. See .editorconfig in the repository root for editor configuration.
Naming conventions¶
| Element | Convention | Example |
|---|---|---|
| Classes | UpperCamelCase | WebCalendar, RptEvent |
| Class files | ClassName.php | includes/classes/Event.php |
| Functions | lowerCamelCase | getPostValue(), isAllDay() |
| Variables | lowerCamelCase | $eventDate, $loginName |
| Constants | UPPER_SNAKE_CASE | define('MAX_EVENTS', 100) |
| DB tables | webcal_ prefix | webcal_entry, webcal_user |
| Config values | UPPER_SNAKE_CASE | DISPLAY_WEEKENDS, WORK_DAY_START_HOUR |
Functions should use verb phrases (getPostValue, isAllDay). Variables should be descriptive nouns.
Config values are stored in the webcal_config (system-wide) and webcal_user_pref (per-user) tables.
Dependencies¶
Runtime (composer.json require)¶
| Package | Version | Purpose |
|---|---|---|
| components/jquery | 3.5.* | DOM manipulation |
| twbs/bootstrap | 4.6.* | CSS framework |
| twbs/bootstrap-icons | 1.10.* | Icon set |
| tinymce/tinymce | 7.7.* | Rich text editor |
| phpmailer/phpmailer | 7.0.* | Email sending |
| mcp/sdk | ^0.3.0 | MCP server support |
Development (composer.json require-dev)¶
| Package | Version | Purpose |
|---|---|---|
| phpunit/phpunit | 9.6.* | Unit testing |
| phpstan/phpstan | ^2.0 | Static analysis |
| friendsofphp/php-cs-fixer | ^3.86 | Code formatting |
| squizlabs/php_codesniffer | ^4.0 | Coding standards |
Vendor assets are not served directly from vendor/. The Makefile copies the necessary frontend assets from vendor/ to pub/, which is the web-accessible directory.
Testing¶
Unit tests¶
vendor/bin/phpunit -c tests/phpunit.xml # Run all tests
vendor/bin/phpunit tests/functionsTest.php # Run a specific test file
Test files include functionsTest.php, RepeatingEventsTest.php, EventTest.php, and others under tests/.
PHP syntax check¶
./tests/compile_test.sh
Verifies that all PHP files in the project compile without syntax errors.
Selenium UI tests¶
End-to-end browser tests are located in docker/tests/ and use Python with pytest. These run against the Docker development environment.
Database Abstraction¶
All database access goes through includes/dbi4php.php. The key functions are:
| Function | Purpose |
|---|---|
dbi_connect() |
Open a database connection |
dbi_query() |
Execute a SQL query string |
dbi_execute() |
Execute a prepared/parameterized query |
dbi_fetch_row() |
Fetch the next result row as an array |
dbi_error() |
Return the last database error message |
dbi_close() |
Close the database connection |
Supported backends: MySQL/MariaDB, PostgreSQL, SQLite3. Legacy code paths exist for Oracle, DB2, ODBC, and Interbase but are untested on PHP 8.
Database tables use the webcal_ prefix with lower_snake_case names. See docs/WebCalendar-Database.md for the full schema.
Extension Points¶
Authentication bridges¶
Create includes/user-app-yourapp.php implementing the required auth interface functions (user_valid_login(), user_get_users(), etc.) to integrate with an external authentication system.
Configuration overrides¶
Create includes/config-app-yourapp.php to provide application-specific configuration overrides.
Themes¶
CSS theme files are located in includes/css/. Add or modify stylesheets there to change the application appearance.
Custom event fields (site extras)¶
Additional event fields can be configured through the admin UI without code changes.
MCP server¶
mcp.php in the project root exposes calendar operations as MCP tools for AI assistant integration. It uses STDIO transport and requires an API token set via the MCP_TOKEN environment variable. Available tools: list_events, get_user_info, search_events, add_event.
Translations¶
WebCalendar includes translation files for 100+ languages in the
translations/ directory. Approximately 35 are human-contributed with
substantial coverage; the remainder were generated via AI-assisted bulk
translation (see AI-Assisted Translation)
and should be reviewed by native speakers before being considered
production-quality.
File Format¶
Translation files are plain text with the format:
English phrase: translated phrase
Lines starting with # are comments. A blank line ends the header
comment block. If the translation is identical to English, use =:
January: =
The reference file is translations/English-US.txt.
Adding a New Language¶
- Copy
English-US.txtto your new language file:cp translations/English-US.txt translations/YourLanguage.txt - Translate all text to the right of the
:. Do not modify text to the left. - For the month "May", note the special entry
May_which should be the full month name, whileMayis the abbreviation. - Run the check tool to find missing translations:
perl tools/check_translation.pl YourLanguage - Register the new language in
includes/translate.php: - Add an entry to the
$languagesarray - Add an entry to the
$browser_languagesarray - Test by selecting the language in user Preferences.
- Submit a pull request.
Updating an Existing Translation¶
- Run the update tool to find missing entries:
This scans all PHP files for
perl tools/update_translation.pl YourLanguagetranslate()calls and marks missing entries with<< MISSING >>in the translation file. - Open the translation file and search for
MISSING. Translate each marked entry. - Run the check tool to verify completeness:
perl tools/check_translation.pl YourLanguage
AI-Assisted Translation¶
For bulk translation of missing entries, a Python script using OpenAI is available:
cd tools
OPENAI_API_KEY=your-key python3 complete-translation.py YourLanguage > ../translations/YourLanguage.txt
perl update_translation.pl YourLanguage
Review the output — AI translations may have minor issues like extra quotes. This tool works best with UTF-8 translation files.
Translation Tools Summary¶
| Tool | Purpose |
|---|---|
tools/check_translation.pl |
Report missing translations |
tools/update_translation.pl |
Scan code and update translation file with missing entries |
tools/complete-translation.py |
Use OpenAI to auto-translate missing entries |