В этой статье мы разберём, как создать динамический календарь событий в 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 для оптимизации загрузки и безопасности вашего сайта.