Skip to content

WebCalendar Developer Guide

Version: v1.9.16

Table of Contents

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:

  1. Browser requests a root PHP file.
  2. The file includes includes/init.php, which bootstraps the application: starts the session, authenticates the user, opens a database connection, and loads required includes.
  3. 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

  1. Copy English-US.txt to your new language file:
    cp translations/English-US.txt translations/YourLanguage.txt
    
  2. Translate all text to the right of the :. Do not modify text to the left.
  3. For the month "May", note the special entry May_ which should be the full month name, while May is the abbreviation.
  4. Run the check tool to find missing translations:
    perl tools/check_translation.pl YourLanguage
    
  5. Register the new language in includes/translate.php:
  6. Add an entry to the $languages array
  7. Add an entry to the $browser_languages array
  8. Test by selecting the language in user Preferences.
  9. Submit a pull request.

Updating an Existing Translation

  1. Run the update tool to find missing entries:
    perl tools/update_translation.pl YourLanguage
    
    This scans all PHP files for translate() calls and marks missing entries with << MISSING >> in the translation file.
  2. Open the translation file and search for MISSING. Translate each marked entry.
  3. 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