Диагностика задачи: зачем нужен встроенный календарь в теме 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 навыков |