Как создать динамический календарь событий в WordPress с примерами и кодом

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

Создание пользовательского типа записи для событий

Для начала создадим пользовательский тип записи wpdesk_event, чтобы хранить события. Это позволит удобно управлять ими через админку и использовать стандартные возможности WordPress.

function wpdesk_register_event_cpt() {
    $labels = array(
        'name'               => 'События',
        'singular_name'      => 'Событие',
        'add_new'            => 'Добавить событие',
        'add_new_item'       => 'Добавить новое событие',
        'edit_item'          => 'Редактировать событие',
        'new_item'           => 'Новое событие',
        'view_item'          => 'Просмотреть событие',
        'search_items'       => 'Поиск событий',
        'not_found'          => 'События не найдены',
        'not_found_in_trash' => 'События не найдены в корзине',
        'menu_name'          => 'События'
    );
    $args = array(
        'labels'             => $labels,
        'public'             => true,
        'has_archive'        => true,
        'supports'           => array('title', 'editor'),
        'show_in_rest'       => true,
        'menu_position'      => 5,
        'menu_icon'          => 'dashicons-calendar-alt',
    );
    register_post_type('wpdesk_event', $args);
}
add_action('init', 'wpdesk_register_event_cpt');

После добавления этого кода в functions.php вашей темы или в плагин, появится новый раздел «События» в админке WordPress.

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

Чтобы привязать событие к конкретной дате, создадим метаполе wpdesk_event_date. Для простоты используем стандартный meta box с календарём выбора даты.

function wpdesk_add_event_date_metabox() {
    add_meta_box('wpdesk_event_date_box', 'Дата события', 'wpdesk_event_date_metabox_html', 'wpdesk_event', 'side', 'default');
}
add_action('add_meta_boxes', 'wpdesk_add_event_date_metabox');

function wpdesk_event_date_metabox_html($post) {
    wp_nonce_field('wpdesk_event_date_nonce', 'wpdesk_event_date_nonce_field');
    $date = get_post_meta($post->ID, 'wpdesk_event_date', true);
    echo '<input type="date" name="wpdesk_event_date" value="' . esc_attr($date) . '" />';
}

function wpdesk_save_event_date($post_id) {
    if (!isset($_POST['wpdesk_event_date_nonce_field']) || !wp_verify_nonce($_POST['wpdesk_event_date_nonce_field'], 'wpdesk_event_date_nonce')) {
        return;
    }
    if (array_key_exists('wpdesk_event_date', $_POST)) {
        update_post_meta($post_id, 'wpdesk_event_date', sanitize_text_field($_POST['wpdesk_event_date']));
    }
}
add_action('save_post', 'wpdesk_save_event_date');

Теперь при создании или редактировании события можно выбрать дату через удобный календарь.

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

Создадим шорткод [wpdesk_event_calendar], который будет выводить календарь с навигацией по месяцам и отображать даты с событиями.

Основная идея: по выбранному месяцу (параметры GET или текущий месяц) выбираем события из базы, группируем по датам и выводим таблицу календаря, где даты с событиями выделены и кликабельны.

function wpdesk_event_calendar_shortcode() {
    // Получаем год и месяц из запроса или текущие
    $year = isset($_GET['year']) ? intval($_GET['year']) : date('Y');
    $month = isset($_GET['month']) ? intval($_GET['month']) : date('n');

    // Получаем первый и последний день месяца
    $first_day = strtotime("$year-$month-01");
    $days_in_month = date('t', $first_day);
    
    // Получаем день недели первого дня (1=Пн, 7=Вс)
    $first_weekday = date('N', $first_day);

    // Запрос событий за месяц
    $args = array(
        'post_type' => 'wpdesk_event',
        'posts_per_page' => -1,
        'meta_query' => array(
            array(
                'key' => 'wpdesk_event_date',
                'value' => array("$year-$month-01", "$year-$month-$days_in_month"),
                'compare' => 'BETWEEN',
                'type' => 'DATE'
            )
        ),
        'orderby' => 'meta_value',
        'order' => 'ASC'
    );
    $events = get_posts($args);

    // Группируем события по дате
    $events_by_date = array();
    foreach ($events as $event) {
        $date = get_post_meta($event->ID, 'wpdesk_event_date', true);
        if (!$date) continue;
        $events_by_date[$date][] = $event;
    }

    // Навигация по месяцам
    $prev_month = date('Y-m', strtotime("$year-$month-01 -1 month"));
    $next_month = date('Y-m', strtotime("$year-$month-01 +1 month"));

    $html = '<div class="wpdesk-event-calendar">';
    $html .= '<div class="wpdesk-calendar-nav">';
    $html .= '<a href="?year=' . date('Y', strtotime($prev_month . '-01')) . '&month=' . date('n', strtotime($prev_month . '-01')) . '"><< Предыдущий</a>';
    $html .= '<span>' . date('F Y', $first_day) . '</span>';
    $html .= '<a href="?year=' . date('Y', strtotime($next_month . '-01')) . '&month=' . date('n', strtotime($next_month . '-01')) . '">Следующий >></a>';
    $html .= '</div>';

    // Таблица календаря
    $html .= '<table border="1" cellspacing="0" cellpadding="5">';
    $html .= '<thead><tr>';
    $weekdays = array('Пн','Вт','Ср','Чт','Пт','Сб','Вс');
    foreach ($weekdays as $day) {
        $html .= '<th>' . $day . '</th>';
    }
    $html .= '</tr></thead>';
    $html .= '<tbody><tr>';

    // Пустые ячейки до первого дня
    for ($i = 1; $i < $first_weekday; $i++) {
        $html .= '<td> </td>';
    }

    $day_counter = $first_weekday;
    for ($day = 1; $day <= $days_in_month; $day++) {
        $date_str = sprintf('%04d-%02d-%02d', $year, $month, $day);
        if (isset($events_by_date[$date_str])) {
            $html .= '<td style="background:#d1e7dd;cursor:pointer;" title="' . esc_attr(implode(', ', wp_list_pluck($events_by_date[$date_str], 'post_title'))) . '">' . $day . '</td>';
        } else {
            $html .= '<td>' . $day . '</td>';
        }
        if ($day_counter % 7 == 0) {
            $html .= '</tr><tr>';
        }
        $day_counter++;
    }

    // Пустые ячейки до конца недели
    $remaining = 7 - (($day_counter - 1) % 7);
    if ($remaining < 7) {
        for ($i = 0; $i < $remaining; $i++) {
            $html .= '<td> </td>';
        }
    }

    $html .= '</tr></tbody></table>';
    $html .= '</div>';

    return $html;
}
add_shortcode('wpdesk_event_calendar', 'wpdesk_event_calendar_shortcode');

Этот шорткод можно вставить в любой пост или страницу, и он отобразит интерактивный календарь с событиями за текущий или выбранный месяц.

Улучшение: вывод подробностей события через AJAX

Для удобства пользователей можно сделать клик по дате с событиями, чтобы показать список мероприятий в модальном окне или под календарём без перезагрузки страницы с помощью AJAX.

Пример AJAX-обработчика в functions.php:

function wpdesk_load_events_ajax() {
    if (!isset($_POST['date'])) {
        wp_send_json_error('Дата не указана');
    }
    $date = sanitize_text_field($_POST['date']);
    $args = array(
        'post_type' => 'wpdesk_event',
        'meta_key' => 'wpdesk_event_date',
        'meta_value' => $date,
        'meta_compare' => '=',
        'posts_per_page' => -1
    );
    $events = get_posts($args);
    if (empty($events)) {
        wp_send_json_success('Событий нет');
    }
    $html = '<ul>';
    foreach ($events as $event) {
        $html .= '<li><strong>' . esc_html($event->post_title) . '</strong><br/>' . esc_html($event->post_content) . '</li>';
    }
    $html .= '</ul>';
    wp_send_json_success($html);
}
add_action('wp_ajax_wpdesk_load_events', 'wpdesk_load_events_ajax');
add_action('wp_ajax_nopriv_wpdesk_load_events', 'wpdesk_load_events_ajax');

И JavaScript для вызова AJAX (можно добавить через wp_enqueue_script или прямо в шаблоне):

document.addEventListener('DOMContentLoaded', function() {
    document.querySelectorAll('.wpdesk-event-calendar td[style*="cursor:pointer"]').forEach(function(td) {
        td.addEventListener('click', function() {
            var day = td.textContent.trim();
            var calendarDiv = td.closest('.wpdesk-event-calendar');
            var year = new URLSearchParams(window.location.search).get('year') || new Date().getFullYear();
            var month = new URLSearchParams(window.location.search).get('month') || (new Date().getMonth() + 1);
            var dateStr = year + '-' + (month < 10 ? '0' + month : month) + '-' + (day < 10 ? '0' + day : day);
            fetch(wpdesk_ajax_object.ajax_url, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
                },
                body: new URLSearchParams({
                    action: 'wpdesk_load_events',
                    date: dateStr
                })
            })
            .then(response => response.json())
            .then(data => {
                var container = calendarDiv.querySelector('.wpdesk-event-list');
                if (!container) {
                    container = document.createElement('div');
                    container.className = 'wpdesk-event-list';
                    calendarDiv.appendChild(container);
                }
                container.innerHTML = data.success ? data.data : '<p>Ошибка загрузки событий.</p>';
            });
        });
    });
});

Не забудьте локализовать скрипт и передать AJAX URL:

function wpdesk_enqueue_scripts() {
    wp_enqueue_script('wpdesk-event-calendar-js', get_template_directory_uri() . '/js/wpdesk-event-calendar.js', array('jquery'), null, true);
    wp_localize_script('wpdesk-event-calendar-js', 'wpdesk_ajax_object', array(
        'ajax_url' => admin_url('admin-ajax.php'),
    ));
}
add_action('wp_enqueue_scripts', 'wpdesk_enqueue_scripts');

Заключение и рекомендации

Таким образом, мы создали собственный динамический календарь событий с удобной админкой, отображением даты и AJAX-подгрузкой деталей. Это решение легко масштабируется и настраивается под любые задачи.

Если нужны расширенные функции, например, повторяющиеся события или интеграция с Google Calendar, можно рассмотреть плагины, но для базового функционала собственный код — оптимальный вариант.

Для удобства управления SEO и оптимизации скорости рекомендуем минимизировать запросы и кешировать результаты, например, используя transient API WordPress.

Дополнительно можно интегрировать с плагином Clearfy Pro для оптимизации загрузки и безопасности вашего сайта.

Как создать автоматический импорт продуктов из Excel в WooCommerce
19.12.2025
Как добавить настройки пользователя в админ-панель WordPress
18.03.2026
Как создать уникальный тип записи в WordPress с поддержкой метаданных
14.12.2025
Как создать динамический календарь событий в WordPress с примерами и кодом
24.01.2026
Как создать автоматический импорт контента из Telegram бота в WordPress
03.04.2026

Плагин службы технической поддержки для WordPress. Создание, просмотр и ответ на тикеты. Уведомление пользователей и другие функции.