Milk Admin

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 year
  • setMonthYear(?int $month = null, ?int $year = null) - Set both (auto-detects from request if null)
  • setLocale(string $locale) - Set locale for formatting
  • setHeaderTitle(string $title) - Set header title
  • setHeaderIcon(string $icon) - Set header icon (Bootstrap Icons)
  • setHeaderColor(string $color) - Set header color
  • setCompact(bool $compact) - Enable/disable compact mode
  • setHighlightDaysWithAppointments(bool $highlight) - Highlight days with events
  • setShowHeader(bool $show) - Show/hide header
  • setShowYearMonthSelect(bool $show) - Show/hide year/month selectors
  • setShowPrevNextButtons(bool $show) - Show/hide navigation buttons
  • setShowTodayButton(bool $show) - Show/hide today button
  • onAppointmentClick(string $url) - Set appointment click URL
  • onEmptyDateClick(string $url) - Set empty date click URL
  • onDateWithAppointmentsClick(string $url, string $mode = 'fetch') - Set date with appointments click handler
  • setMinDate(int $year, ?int $month = null) - Set minimum navigable date
  • setMaxDate(int $year, ?int $month = null) - Set maximum navigable date
  • setDateRange(int $minYear, int $maxYear, ?int $minMonth = null, ?int $maxMonth = null) - Set date range
  • setCustomCellRenderer(callable $renderer) - Set custom cell renderer
  • mapFields(array $mappings) - Map database fields to event properties
Loading...