Как добавить встроенный календарный функционал в тему WordPress

Диагностика задачи: зачем нужен встроенный календарь в теме WordPress

Часто возникает необходимость в отображении календаря событий, записи бронирований или публикаций на конкретные даты без установки громоздких плагинов. Встроенный календарь в теме позволяет полностью контролировать вывод и стилизацию, а также оптимизировать производительность сайта.

Пошаговое решение: как реализовать календарь событий в теме

1. Создаем кастомный тип записи «События»

Для удобного хранения событий регистрируем кастомный тип записи. Добавьте следующий код в functions.php вашей темы:

function register_event_post_type() {
    $labels = array(
        'name'               => 'События',
        'singular_name'      => 'Событие',
        'menu_name'          => 'События',
        'add_new'            => 'Добавить событие',
        'add_new_item'       => 'Добавить новое событие',
        'edit_item'          => 'Редактировать событие',
        'new_item'           => 'Новое событие',
        'view_item'          => 'Просмотреть событие',
        'search_items'       => 'Поиск событий',
        'not_found'          => 'События не найдены',
        'not_found_in_trash' => 'События не найдены в корзине',
    );

    $args = array(
        'labels'             => $labels,
        'public'             => true,
        'has_archive'        => true,
        'supports'           => array('title', 'editor', 'custom-fields'),
        'menu_icon'          => 'dashicons-calendar',
        'rewrite'            => array('slug' => 'events'),
    );

    register_post_type('event', $args);
}
add_action('init', 'register_event_post_type');

2. Добавляем метаполе для даты события

Для хранения даты используем стандартное метаполе с ключом event_date. Добавьте следующий код для добавления поля в админке:

function add_event_date_meta_box() {
    add_meta_box(
        'event_date_meta',
        'Дата события',
        'render_event_date_meta_box',
        'event',
        'side',
        'default'
    );
}
add_action('add_meta_boxes', 'add_event_date_meta_box');

function render_event_date_meta_box($post) {
    $value = get_post_meta($post->ID, 'event_date', true);
    echo '<label for="event_date_field">Дата события:</label>';
    echo '<input type="date" id="event_date_field" name="event_date_field" value="' . esc_attr($value) . '" />';
}

function save_event_date_meta_box($post_id) {
    if (isset($_POST['event_date_field'])) {
        update_post_meta($post_id, 'event_date', sanitize_text_field($_POST['event_date_field']));
    }
}
add_action('save_post', 'save_event_date_meta_box');

3. Вывод календаря в теме с подсветкой дней с событиями

Для вывода календаря используем PHP-функцию wp_calendar() как основу, дополним ее динамическим подсвечиванием дней с событиями.

function custom_event_calendar() {
    global $wpdb, $m, $monthnum, $year, $wp_locale;

    if (isset($_GET['monthnum']) && isset($_GET['year'])) {
        $monthnum = intval($_GET['monthnum']);
        $year = intval($_GET['year']);
    } else {
        $monthnum = date('m');
        $year = date('Y');
    }

    $unixmonth = mktime(0, 0 , 0, $monthnum, 1, $year);

    // Получаем события за месяц
    $start_date = date('Y-m-d', $unixmonth);
    $end_date = date('Y-m-t', $unixmonth);

    $event_dates = $wpdb->get_col($wpdb->prepare(
        "SELECT DISTINCT meta_value FROM {$wpdb->postmeta} pm
        INNER JOIN {$wpdb->posts} p ON p.ID = pm.post_id
        WHERE pm.meta_key = 'event_date'
        AND pm.meta_value BETWEEN %s AND %s
        AND p.post_type = 'event'
        AND p.post_status = 'publish'",
        $start_date, $end_date
    ));

    $events_by_day = array();
    foreach ($event_dates as $date) {
        $day = date('j', strtotime($date));
        $events_by_day[$day] = true;
    }

    $calendar_output = '<table class="wp-calendar">';
    $calendar_output .= '<caption>' . $wp_locale->get_month($monthnum) . ' ' . $year . '</caption>';
    $calendar_output .= '<thead><tr>';
    $headings = array();
    for ($wd = 0; $wd < 7; $wd++) {
        $headings[] = $wp_locale->get_weekday_abbrev(($wd + $wp_locale->week_begins) % 7);
    }
    foreach ($headings as $heading) {
        $calendar_output .= '<th scope="col">' . $heading . '</th>';
    }
    $calendar_output .= '</tr></thead>';

    // Вычисляем день недели первого числа месяца
    $first_day_of_week = date('w', $unixmonth);
    $first_day_of_week = ($first_day_of_week - $wp_locale->week_begins + 7) % 7;

    $days_in_month = date('t', $unixmonth);

    $day = 1;
    $calendar_output .= '<tbody><tr>';

    // Пустые ячейки до первого дня
    if ($first_day_of_week > 0) {
        $calendar_output .= str_repeat('<td> </td>', $first_day_of_week);
    }

    for ($i = $first_day_of_week; $i < 7; $i++) {
        $class = isset($events_by_day[$day]) ? 'event-day' : 'non-event-day';
        $calendar_output .= '<td class="' . $class . '">' . $day . '</td>';
        $day++;
    }
    $calendar_output .= '</tr>';

    while ($day <= $days_in_month) {
        $calendar_output .= '<tr>';
        for ($i = 0; $i < 7; $i++) {
            if ($day > $days_in_month) {
                $calendar_output .= '<td> </td>';
            } else {
                $class = isset($events_by_day[$day]) ? 'event-day' : 'non-event-day';
                $calendar_output .= '<td class="' . $class . '">' . $day . '</td>';
                $day++;
            }
        }
        $calendar_output .= '</tr>';
    }

    $calendar_output .= '</tbody></table>';

    // Стилизация
    $calendar_output .= '<style>
        table.wp-calendar { border-collapse: collapse; width: 100%; }
        table.wp-calendar th, table.wp-calendar td { border: 1px solid #ccc; text-align: center; padding: 5px; }
        td.event-day { background-color: #d1e7dd; font-weight: bold; cursor: pointer; }
        td.non-event-day { background-color: #f8f9fa; }
    </style>';

    echo $calendar_output;
}

Выводите календарь в нужном месте темы вызовом custom_event_calendar().

Проверка результата после внедрения

  • Создайте несколько записей типа «Событие» с разными датами в админке.
  • Откройте страницу с вызовом функции custom_event_calendar().
  • Проверьте, что в календаре дни с событиями подсвечены и отображаются корректно.

Если даты не подсвечиваются, проверьте, что метаполе event_date сохранено корректно и формат даты - YYYY-MM-DD.

Частые ошибки и как их исправить

  • Метаполе даты не сохраняется — убедитесь, что save_post хук используется правильно и нет ошибок в sanitize_text_field.
  • Неправильный формат даты — дата должна быть в формате YYYY-MM-DD, чтобы работать с SQL-запросами.
  • Календарь не отображается — проверьте, что функция вызвана в шаблоне и тема активна.
  • Конфликты стилей — используйте уникальные классы для календаря, чтобы избежать наложения CSS.

Практические советы по безопасности и производительности

  • Используйте prepare для SQL-запросов, чтобы защититься от SQL-инъекций.
  • Кэшируйте результаты запросов к базе, если календарь отображается часто, чтобы снизить нагрузку.
  • Минимизируйте инлайновые стили, лучше выносить CSS в отдельный файл темы.
  • Обрабатывайте сохранение метаполей только при проверке прав пользователя (current_user_can('edit_post', $post_id)), чтобы предотвратить несанкционированные изменения.

Сравнение способов реализации календаря

МетодПреимуществаНедостатки
Встроенный календарь с кастомным типом и метаполями Полный контроль, нет внешних зависимостей, легкая кастомизация Требует программирования, ручная поддержка
Использование плагина календаря (например, The Events Calendar) Быстрая установка, богатый функционал Может замедлять сайт, ограниченная кастомизация темы
Использование shortcode с AJAX для загрузки событий Динамическая загрузка, меньше нагрузки на страницу Сложнее реализовать, требует JS и AJAX навыков
Как использовать хуки в WordPress для разработки тем
02.12.2025
Как создать тему WordPress с поддержкой отзывчивого дизайна
16.03.2026
Как создать динамический журнал в WordPress с помощью REST API
23.11.2025
Как добавить встроенный календарный функционал в тему WordPress
06.05.2026
Как сделать автоматическое обновление темы WordPress без плагина
17.02.2026