WebCalendar

Running WordPress? There’s now a WordPress-native version — WebCalendar for WordPress — that installs as a plugin instead of a separate PHP application, with full recurring-event support, iCal import/export, and a built-in holiday library. It’s free on WordPress.org, and there’s an overview here on k5n.us. The standalone PHP application on this page is still maintained and is not going away.

About WebCalendar

WebCalendar is a PHP-based calendar application that can be configured as a single-user calendar, a multi-user calendar for groups of users, or as an event calendar viewable by visitors. MySQL/MariaDB, SQLite3, PostgreSQL, Oracle, DB2, Interbase, MS SQL Server, or ODBC is required. The version 1.9.X releases are still a little rough around the edges since these include an overhaul of the UI to use Bootstrap and jQuery and a complete rewrite of the web-based installer.

WebCalendar can be setup in a variety of ways, such as…

  • A schedule management system for a single person
  • A schedule management system for a group of people, allowing one or more assistants to manage the calendar of another user
  • An events schedule that anyone can view, allowing visitors to submit new events
  • A calendar server that can be viewed with iCalendar-compliant calendar applications like Mozilla Sunbird, Apple iCal or GNOME Evolution or RSS-enabled applications like Firefox, Thunderbird, RSSOwl, FeedDemon, or BlogExpress.

Overview of Features

  • Multi-user support
  • 30 supported languages: Basque, Bulgarian, Chinese-Big5, Chinese-GB2312, Czech, Danish, Dutch, English-US, Estonian, Finnish, French, Galician, German, Greek, Holo-Big5, Hungarian, Icelandic, Italian, Japanese, Korean, Norwegian, Polish, Portuguese_BR, Portuguese, Romanian, Russian, Spanish, Swedish, Turkish, Welsh (see current list of translations here)
  • Web-based installer
  • Auto-detect user’s language preference from browser settings
  • View calendars by day, week, month or year
  • View another user’s calendar
  • View one or more users’ calendar via layers on top of your own calendar
  • Add/Edit/Delete users
  • Add/Edit/Delete events
  • Repeating events including support for overriding or deleting (exceptions)
  • Configurable custom event fields
  • User-configurable preferences for colors, 12/24 time format, Sun/Mon week start
  • Checks for scheduling conflicts
  • Email reminders for upcoming events
  • Email notifications for new/updated/deleted events
  • Export events to iCalendar
  • Import from iCalendar/ics format
  • Optional general access (no login required) to allow calendar to be viewed by people without a login (useful for event calendars)
  • Users can make their calendar available publicly to anyone with an iCalendar-compliant calendar program (such as Apple’s iCal, Mozilla Calendar or Sunbird)
  • Publishing of free/busy schedules (part of the iCalendar standard)
  • RSS support that puts a user’s calendar into RSS
  • Subscribe to “remote” calendars (hosted elsewhere on the net) in either iCalendar or hCalendar formats (WebCalendar 1.1+)
  • User authentication: Web-based, HTTP, LDAP or NIS

System Requirements

  • PHP 8 or later
  • PHP support and access to one of the following databases:
    • SQLite
    • MySQL/MariaDB
    • Oracle
    • Postgres
    • IBM DB2
  • Access to cron for Linux/Unix systems (to send out reminders)

Development Cost

The following metrics from Ohloh show how much it would have cost to commercially develop WebCalendar.

  • Codebase Size: 138,588 lines
  • Estimated Effort: 34 person-years
  • Estimated Cost: $1,884,469
  • (As of 11 August 2024)

Donations

If you’d like to help support the costs of developing, maintaining and supporting WebCalendar, please consider donating.

Developer Resources

License

WebCalendar is available under the GNU General Public License, version 2.

For more information on this license:

Documentation

Most Recent Changes

Below are the most recent source code commits to github on the master branch.

  • Merge pull request #757 from craigk5n/fix/concurrent-test-isolation
    by craigk5n on September 25, 2026 at 12:25 am

    Merge pull request #757 from craigk5n/fix/concurrent-test-isolation Give every test run its own ports and paths

  • fix: require the test fixture rather than relying on the bootstrap
    by craigk5n on September 25, 2026 at 12:19 am

    fix: require the test fixture rather than relying on the bootstrap The previous commit loaded tests/McpServerFixture.php from tests/bootstrap.php. That passed locally and produced 57 “Class McpServerFixture not found” errors in CI, because .github/workflows/test-mcp.yml runs vendor/bin/phpunit tests/McpTest.php with no -c, so phpunit.xml is never read and its bootstrap never loads. tests/run_unit_tests.sh invokes five more files the same way. This was self-inflicted twice over. The first attempt added a require to each test class and reached only those whose existing requires used the same quoting style, so I moved the load into the bootstrap and called it cleaner. It traded a drift problem for a dependency on how phpunit is invoked, which is worse because it is invisible until a workflow that invokes it differently runs. Running only `phpunit -c tests/phpunit.xml` locally could never have caught it. Every file that uses the fixture now requires it, which is the convention in this tree and does not care how phpunit was started. Verified against both invocations: `phpunit tests/McpTest.php` and `phpunit -c tests/phpunit.xml`. tests/TestFixtureRequiresTest.php fails when any test uses McpServerFixture, McpTestHelper or CrossDatabaseTestHelper without requiring it, and says why in the message. Checked by deleting one require. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

  • test: give every run its own ports and paths
    by craigk5n on September 25, 2026 at 12:06 am

    test: give every run its own ports and paths Six MCP test classes hard-coded a port between 8099 and 8104, a SQLite file and a server log path. McpTestHelper and CrossDatabaseTestHelper defaulted to fixed database paths, and two probes wrote scratch scripts straight into tests/ under fixed names. All of that is machine-wide, so two runs deleted each other’s files and competed for the ports, and the damage showed up as errors in tests that had nothing to do with it. Ports now come from the kernel: bind to port 0, read back what was assigned, release it. There is a window between releasing and `php -S` taking it, which is unavoidable without passing the socket itself, and the callers already confirm the server answers before running anything. Measured rather than assumed. Two concurrent runs of the MCP and cross-database tests, with the lock disabled: before 59 errors and 57 errors after ports and databases 1 error and 1 error after all six collisions clean, and clean again at three runs Two concurrent full suites now pass: 792 tests each, no errors. The last two collisions were the ones reading the code would not have found: tests/test_bearer_bug.php and tests/test_duplicate_bug.php are written into the repository directory, so whichever run finished first deleted the file the other was still executing. tests/McpServerFixture.php holds both helpers and is loaded from tests/bootstrap.php rather than by each test file. The first attempt added a require to every class and silently reached only those whose existing requires used the same quoting style, which is the kind of thing that leaves half a change working. The lock in tests/bootstrap.php is left in place. The collisions it guards are gone, but one new test with a fixed path would bring them back, and the failure is expensive to read. AGENT_ROADMAP.md records what removing it would need. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

  • Merge pull request #756 from craigk5n/feat/ai-signal-lint
    by craigk5n on September 24, 2026 at 11:40 pm

    Merge pull request #756 from craigk5n/feat/ai-signal-lint Flag machine-written comments on lines a change adds

  • fix: let a comment opt out of the AI-signal check
    by craigk5n on September 24, 2026 at 11:34 pm

    fix: let a comment opt out of the AI-signal check The new job failed on its first run in CI, on this file’s own docblock: tools/check-ai-signals.php:29 (“You can test this script from the command line”), which is good writing That line quotes an example of the phrasing the tool detects, inside the explanation of why the tool does not flag such comments in existing code. It is a real category rather than a one-off: anything discussing these phrases has to be able to quote one, including this tool, its test, and any comment explaining why a particular wording was chosen. A comment containing ai-signals:allow is now skipped. It is deliberately a visible marker in the comment rather than a configuration file, so a reader sees that the author made a decision instead of wondering why the check did not apply. It covers only the comment it appears in, so it cannot be dropped at the top of a file to switch the check off for everything below. There is a test for that, and writing it found that the first draft of the suppression test used two separate // lines, which PHP tokenises as two comments — the marker correctly did not reach the second. The fixture now uses one docblock, which is how the marker is actually used. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Download Metrics

  • Downloads via Github: 21261
  • Downloads via SourceForge: 1417952

Related Links

  • Standards
    • RFC 2445: Internet Calendaring and Scheduling Core Object Specification (iCalendar)
    • CalDAV: Calendaring and Scheduling Extensions to WebDAV (DRAFT) 
      [Note: WebCalendar does not yet support CalDAV.)
  • Calendar client applications – You can use the applications to view events stored in WebCalendar if you enable its publishing settings.
  • iCalendar/ics download sites – These sites contain calendars for holidays, sports teams schedules, music converts, etc. You can import these files into WebCalendar.