Calendar Plugin
The Calendar plugin provides a flexible, AJAX-enabled monthly calendar with support for multi-day events, localization, and extensive customization options.
Basic Usage
Simple Calendar with Events
// Define events
$events = [
(object)[
'id' => 1,
'title' => 'Team Meeting',
'start_datetime' => new \DateTime('2025-11-22 10:00:00'),
'end_datetime' => new \DateTime('2025-11-22 11:30:00'),
'class' => 'event-primary'
],
(object)[
'id' => 2,
'title' => 'Client Call',
'start_datetime' => new \DateTime('2025-11-25 14:00:00'),
'end_datetime' => new \DateTime('2025-11-25 15:00:00'),
'class' => 'event-info'
]
];
// Generate calendar
$calendar_html = Get::themePlugin('Calendar', [
'month' => date('n'),
'year' => date('Y'),
'locale' => 'it_IT',
'calendar_id' => 'my_calendar',
'events' => $events
]);
echo $calendar_html;
Event Structure
Events must be objects with the following properties:
(object)[
'id' => 1, // Unique event ID
'title' => 'Event Title', // Event title
'start_datetime' => new \DateTime('2025-11-22 10:00:00'), // Start date and time
'end_datetime' => new \DateTime('2025-11-22 11:30:00'), // End date and time
'class' => 'event-primary' // CSS class for styling
]
Available event classes: event-primary, event-secondary, event-success, event-danger, event-warning, event-info, event-light, event-dark
Configuration Options
Basic Options
| Option | Type | Default | Description |
|---|---|---|---|
month |
int | Current month | Month to display (1-12) |
year |
int | Current year | Year to display |
locale |
string | 'en_US' | Locale for date formatting (e.g., 'it_IT', 'fr_FR') |
calendar_id |
string | 'calendar' | Unique ID for the calendar (required for AJAX) |
events |
array | [] | Array of event objects |
Header Customization
| Option | Type | Default | Description |
|---|---|---|---|
header_title |
string | 'Calendar' | Title displayed in header |
header_icon |
string | '' | Bootstrap Icons class (e.g., 'bi-calendar-event') |
header_color |
string | 'primary' | Header color: primary, secondary, success, danger, warning, info, light, dark |
show_header |
bool | true | Show/hide header completely |
Navigation Controls
| Option | Type | Default | Description |
|---|---|---|---|
show_year_month_select |
bool | true | Show year/month dropdown selectors |
show_prev_next_buttons |
bool | true | Show previous/next month buttons |
show_today_button |
bool | true | Show "today" button |
min_year |
int|null | null | Minimum year for navigation |
max_year |
int|null | null | Maximum year for navigation |
min_month |
int|null | null | Minimum month for navigation (1-12) |
max_month |
int|null | null | Maximum month for navigation (1-12) |
Display Options
| Option | Type | Default | Description |
|---|---|---|---|
compact |
bool | false | Enable compact mode (smaller calendar, no event details shown) |
highlight_days_with_appointments |
bool | false | Add special styling to days with events |
Click Handlers
| Option | Type | Default | Description |
|---|---|---|---|
on_appointment_click_url |
string | '' | URL for event clicks. Use %id% placeholder |
on_empty_date_click_url |
string | '' | URL for empty date clicks. Use %date% placeholder |
on_date_with_appointments_click_url |
string | '' | URL for dates with events. Use %date% placeholder |
on_date_with_appointments_click_mode |
string | 'fetch' | Click mode: 'fetch' (AJAX) or 'link' (navigation) |
Advanced Customization
| Option | Type | Default | Description |
|---|---|---|---|
custom_cell_renderer |
callable | null | Custom function to render day cells |
Examples
Compact Calendar
$calendar_html = Get::themePlugin('Calendar', [
'month' => date('n'),
'year' => date('Y'),
'locale' => 'it_IT',
'calendar_id' => 'compact_calendar',
'events' => $events,
'header_title' => 'My Calendar',
'header_color' => 'success',
'compact' => true,
'highlight_days_with_appointments' => true,
'show_year_month_select' => false
]);
Calendar Without Header
$calendar_html = Get::themePlugin('Calendar', [
'month' => date('n'),
'year' => date('Y'),
'locale' => 'it_IT',
'calendar_id' => 'no_header_cal',
'events' => $events,
'show_header' => false,
'compact' => true
]);
Calendar with Click Handlers
$calendar_html = Get::themePlugin('Calendar', [
'month' => date('n'),
'year' => date('Y'),
'locale' => 'it_IT',
'calendar_id' => 'interactive_cal',
'events' => $events,
'on_appointment_click_url' => '?page=events&action=view&id=%id%',
'on_empty_date_click_url' => '?page=events&action=new&date=%date%'
]);
Calendar with Date Range Limits
$calendar_html = Get::themePlugin('Calendar', [
'month' => date('n'),
'year' => date('Y'),
'locale' => 'it_IT',
'calendar_id' => 'limited_cal',
'events' => $events,
'min_year' => 2024,
'max_year' => 2026
]);
Custom Cell Renderer
For advanced customization, you can provide a custom function to render each day cell:
function customCellRenderer(
int $day,
int $month,
int $year,
bool $otherMonth,
string $date,
bool $isToday,
array $appointments,
$calendar
): string {
$classes = ['calendar-day', 'custom-cell'];
if ($otherMonth) $classes[] = 'other-month';
if ($isToday) $classes[] = 'today';
$html = '<div class="' . implode(' ', $classes) . '">';
$html .= '<div class="day-number">' . $day . '</div>';
if (!empty($appointments)) {
$count = count($appointments);
$html .= '<span class="badge bg-primary">' . $count . '</span>';
}
$html .= '</div>';
return $html;
}
$calendar_html = Get::themePlugin('Calendar', [
'month' => date('n'),
'year' => date('Y'),
'calendar_id' => 'custom_cal',
'events' => $events,
'custom_cell_renderer' => 'customCellRenderer'
]);
AJAX Implementation
To enable AJAX calendar updates, handle requests in your controller:
#[RequestAction('home')]
public function calendar()
{
$events = $this->getEvents();
$calendar_id = 'my_calendar';
// Check for AJAX request
if (isset($_REQUEST[$calendar_id])) {
$html = $this->buildCalendarHtml($calendar_id, $events);
Response::render($html, ['html' => $html]);
return;
}
// Full page render
$html = $this->buildCalendarHtml($calendar_id, $events);
Response::render($html, ['html' => $html]);
}
private function buildCalendarHtml(string $id, array $events): string
{
$req = $_REQUEST[$id] ?? [];
$month = (int)($req['month'] ?? date('n'));
$year = (int)($req['year'] ?? date('Y'));
return Get::themePlugin('Calendar', [
'month' => $month,
'year' => $year,
'locale' => 'it_IT',
'calendar_id' => $id,
'events' => $events
]);
}
JavaScript Events
The calendar dispatches custom events that you can listen to:
// Listen to appointment clicks
document.addEventListener('calendar:appointmentClick', function(e) {
console.log('Appointment clicked:', e.detail);
// Prevent default behavior if needed
// e.preventDefault();
});
// Listen to "more appointments" clicks
document.addEventListener('calendar:moreClick', function(e) {
console.log('More clicked for date:', e.detail.date);
});
Multi-day Events
The calendar automatically supports events spanning multiple days:
$events = [
(object)[
'id' => 1,
'title' => 'Conference',
'start_datetime' => new \DateTime('2025-11-20 09:00:00'),
'end_datetime' => new \DateTime('2025-11-22 17:00:00'),
'class' => 'event-warning'
]
];
The event will appear on all days from November 20 to November 22, with appropriate time ranges shown for each day.
CalendarBuilder - Database Integration
For database-driven calendars, use the CalendarBuilder class which provides automatic query filtering and event mapping:
Basic CalendarBuilder Usage
use Builders\CalendarBuilder;
// Assuming you have an Event model
$calendar = CalendarBuilder::create($eventModel)
->setMonthYear() // Auto-detects from request or uses current month/year
->setLocale('it_IT')
->setHeaderTitle('My Events')
->setHeaderIcon('bi-calendar-event')
->setHeaderColor('primary')
->render();
echo $calendar;
Field Mapping
Map your database fields to calendar properties:
$calendar = CalendarBuilder::create($eventModel)
->mapFields([
'id' => 'event_id',
'title' => 'event_name',
'start_datetime' => 'start_date',
'end_datetime' => 'end_date',
'class' => 'css_class'
])
->setMonthYear()
->render();
Complete CalendarBuilder Example
$calendar = CalendarBuilder::create($eventModel, 'events_calendar')
->setMonthYear(11, 2025)
->setLocale('it_IT')
->setHeaderTitle('Team Events')
->setHeaderIcon('bi-calendar-check')
->setHeaderColor('success')
->setCompact(false)
->setHighlightDaysWithAppointments(true)
->setShowYearMonthSelect(true)
->setShowPrevNextButtons(true)
->setShowTodayButton(true)
->onAppointmentClick('?page=events&action=edit&id=%id%')
->onEmptyDateClick('?page=events&action=new&date=%date%')
->onDateWithAppointmentsClick('?page=events&action=list&date=%date%', 'fetch')
->setDateRange(2024, 2026)
->render();
CalendarBuilder with Custom Cell Renderer
$calendar = CalendarBuilder::create($eventModel)
->setMonthYear()
->setCustomCellRenderer(function($day, $month, $year, $otherMonth, $date, $isToday, $appointments, $cal) {
$html = '<div class="custom-day">';
$html .= '<div class="day-num">' . $day . '</div>';
if (!empty($appointments)) {
$html .= '<span class="badge">' . count($appointments) . '</span>';
}
$html .= '</div>';
return $html;
})
->render();
CalendarBuilder Available Methods
setMonth(int $month)- Set display month (1-12)setYear(int $year)- Set display yearsetMonthYear(?int $month = null, ?int $year = null)- Set both (auto-detects from request if null)setLocale(string $locale)- Set locale for formattingsetHeaderTitle(string $title)- Set header titlesetHeaderIcon(string $icon)- Set header icon (Bootstrap Icons)setHeaderColor(string $color)- Set header colorsetCompact(bool $compact)- Enable/disable compact modesetHighlightDaysWithAppointments(bool $highlight)- Highlight days with eventssetShowHeader(bool $show)- Show/hide headersetShowYearMonthSelect(bool $show)- Show/hide year/month selectorssetShowPrevNextButtons(bool $show)- Show/hide navigation buttonssetShowTodayButton(bool $show)- Show/hide today buttononAppointmentClick(string $url)- Set appointment click URLonEmptyDateClick(string $url)- Set empty date click URLonDateWithAppointmentsClick(string $url, string $mode = 'fetch')- Set date with appointments click handlersetMinDate(int $year, ?int $month = null)- Set minimum navigable datesetMaxDate(int $year, ?int $month = null)- Set maximum navigable datesetDateRange(int $minYear, int $maxYear, ?int $minMonth = null, ?int $maxMonth = null)- Set date rangesetCustomCellRenderer(callable $renderer)- Set custom cell renderermapFields(array $mappings)- Map database fields to event properties