[WordPress] 代替え 営業日/休業日カレンダー プラグインなし

営業日/休業日カレンダーの需要は意外とあり、開発が終了してしまったXO Event CalendarやBiz Calendarにお世話になっていました。
代替え品を探しましたが、自作する事にしました。代替えとは言い難い程の極シンプルなカレンダーですが、皆さんの助けになれば嬉しいです。チャッピーさんに助けてもらいながら作りました。AIの進歩に驚くばかり、怖いくらいです。一人では何日もかかったはず。
月曜始まりと日曜始まりの2種を作りました。意味不明でもコピペでOKです。
INDEX
仕様

- 三角の月の送りボタンは、もう前の月/翌月に送れない場合はグレーで表示
- 日付の余ったセルには、前後の日付をグレーで表示
- ‘2026-01-01’ 表記で登録
- ショートコードを張り付けるだけ
JSファイルの作成
子テーマの中に「js」フォルダを作り中にcalendar.jsファイルを作成 js/calendar.js
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('.holiday-calendar-wrapper').forEach(wrapper => {
let current = wrapper.dataset.currentMonth;
const max = wrapper.dataset.maxMonth;
const min = wrapper.dataset.minMonth;
const body = wrapper.querySelector('.calendar-body');
const label = wrapper.querySelector('.current');
const updateNav = () => {
wrapper.querySelector('.prev').disabled = (current <= min);
wrapper.querySelector('.next').disabled = (current >= max);
};
const loadMonth = ym => {
const key = 'cal' + ym.replace('-', '');
if (!wrapper.dataset[key]) return;
body.innerHTML = wrapper.dataset[key];
const [y, m] = ym.split('-');
label.textContent = `${y}年${m}月`;
updateNav();
};
wrapper.querySelector('.prev').onclick = () => {
const d = new Date(current + '-01');
d.setMonth(d.getMonth() - 1);
const next = d.toISOString().slice(0, 7);
if (next < min) return;
current = next;
loadMonth(current);
};
wrapper.querySelector('.next').onclick = () => {
const d = new Date(current + '-01');
d.setMonth(d.getMonth() + 1);
const next = d.toISOString().slice(0, 7);
if (next > max) return;
current = next;
loadMonth(current);
};
loadMonth(current);
});
});
functon.phpにコードを書く
下へ下へとコードを追記してください。
functions.php
├─ファイルのリンク
├─ 日付設定
├─ HTML (日曜始まり、又は月曜始まりのどちらか)
├─ カレンダーの生成
└─ ショートコード
基本部分
先ほどのjsファイルをリンクします。
function enqueue_custom_scripts() {
wp_enqueue_script(
'custom-js',
get_stylesheet_directory_uri() . '/js/calendar.js',
array(),
null,
true
);
}
add_action('wp_enqueue_scripts', 'enqueue_custom_scripts');その下に、日付の設定を追記。編集するのはココだけです。
//日付の設定はココ
function my_holiday_dates() {
return [
'2026-01-01',
'2026-01-06',
'2026-02-11',
'2026-05-11',
'2026-06-20',
'2026-08-31',
'2026-09-30',
];
}日曜日から始まるカレンダー
日曜始まり、又は月曜始まりのどちらかをコピペしてください。
// HTML
function my_render_calendar_single_month($year, $month) {
$holidays = my_holiday_dates();
ob_start();
echo '<table class="holiday-calendar">';
echo '<tr class="week">';
echo '<th class="sun">日</th><th>月</th><th>火</th><th>水</th><th>木</th><th>金</th><th class="sat">土</th>';
echo '</tr><tr>';
$first_w = (int) date('w', strtotime("$year-$month-01"));
$prev = new DateTime("$year-$month-01");
$prev->modify('-1 month');
$prev_last = (int) $prev->format('t');
for ($i = $first_w - 1; $i >= 0; $i--) {
$day = $prev_last - $i;
$date = $prev->format('Y-m-') . sprintf('%02d', $day);
$class = ['other-month'];
if (in_array($date, $holidays, true)) {
$class[] = 'holiday';
}
echo '<td class="'.implode(' ', $class).'">'.$day.'</td>';
}
$days = (int) date('t', strtotime("$year-$month-01"));
for ($d = 1; $d <= $days; $d++) {
$date = sprintf('%04d-%02d-%02d', $year, $month, $d);
$class = [];
if (in_array($date, $holidays, true)) {
$class[] = 'holiday';
}
$w = (int) date('w', strtotime($date));
if ($w === 0) $class[] = 'sun';
if ($w === 6) $class[] = 'sat';
echo '<td class="'.implode(' ', $class).'">'.$d.'</td>';
if ((($d + $first_w) % 7) === 0) {
echo '</tr><tr>';
}
}
$last_w = (int) date('w', strtotime("$year-$month-$days"));
$next = new DateTime("$year-$month-01");
$next->modify('+1 month');
$next_day = 1;
for ($i = $last_w + 1; $i < 7; $i++) {
$date = $next->format('Y-m-') . sprintf('%02d', $next_day);
$class = ['other-month'];
if (in_array($date, $holidays, true)) {
$class[] = 'holiday';
}
echo '<td class="'.implode(' ', $class).'">'.$next_day.'</td>';
$next_day++;
}
echo '</tr></table>';
/* カレンダーの下の部分 */
echo '<div class="calendar-legend">';
echo '<span class="legend-item holiday">';
echo '<span class="legend-box"></span> 休業日';
echo '</span>';
echo '</div>';
return ob_get_clean();
}カレンダーの下の部分の「休業日」の部分は用途に応じて書き換えて下さい。
月曜から始まるカレンダー
// HTML
function my_render_calendar_single_month($year, $month) {
$holidays = my_holiday_dates();
ob_start();
echo '<table class="holiday-calendar">';
echo '<tr class="week">';
echo '<th>月</th><th>火</th><th>水</th><th>木</th><th>金</th><th class="sat">土</th><th class="sun">日</th>';
echo '</tr><tr>';
$first_w = (int) date('N', strtotime("$year-$month-01")) - 1;
$prev = new DateTime("$year-$month-01");
$prev->modify('-1 month');
$prev_last = (int) $prev->format('t');
for ($i = $first_w - 1; $i >= 0; $i--) {
$day = $prev_last - $i;
$date = $prev->format('Y-m-') . sprintf('%02d', $day);
$class = ['other-month'];
if (in_array($date, $holidays, true)) {
$class[] = 'holiday';
}
echo '<td class="'.implode(' ', $class).'">'.$day.'</td>';
}
$days = (int) date('t', strtotime("$year-$month-01"));
for ($d = 1; $d <= $days; $d++) {
$date = sprintf('%04d-%02d-%02d', $year, $month, $d);
$class = [];
if (in_array($date, $holidays, true)) {
$class[] = 'holiday';
}
$w = (int) date('N', strtotime($date)) - 1;
if ($w === 6) $class[] = 'sun';
if ($w === 5) $class[] = 'sat';
echo '<td class="'.implode(' ', $class).'">'.$d.'</td>';
if ((($d + $first_w) % 7) === 0) {
echo '</tr><tr>';
}
}
$last_w = (int) date('N', strtotime("$year-$month-$days")) - 1;
$next = new DateTime("$year-$month-01");
$next->modify('+1 month');
$next_day = 1;
for ($i = $last_w + 1; $i < 7; $i++) {
$date = $next->format('Y-m-') . sprintf('%02d', $next_day);
$class = ['other-month'];
if (in_array($date, $holidays, true)) {
$class[] = 'holiday';
}
echo '<td class="'.implode(' ', $class).'">'.$next_day.'</td>';
$next_day++;
}
echo '</tr></table>';
/* カレンダーの下の部分 */
echo '<div class="calendar-legend">';
echo '<span class="legend-item holiday">';
echo '<span class="legend-box"></span> 休業日';
echo '</span>';
echo '</div>';
return ob_get_clean();
}カレンダーの下の部分の「休業日」の部分は用途に応じて書き換えて下さい。
共通部分
//カレンダー生成
function my_holiday_calendar_with_nav() {
$holidays = my_holiday_dates();
$latest = max($holidays);
$max_month = date('Y-m', strtotime($latest));
$now_month = date('Y-m');
$min_month = date('Y-m'); // 今月
ob_start();
?>
<div class="holiday-calendar-wrapper"
data-min-month="<?php echo esc_attr($min_month); ?>"
data-max-month="<?php echo esc_attr($max_month); ?>"
data-current-month="<?php echo esc_attr($now_month); ?>">
<div class="calendar-nav">
<button class="prev">◀</button>
<span class="current"></span>
<button class="next">▶</button>
</div>
<div class="calendar-body"></div>
</div>
<?php
return ob_get_clean();
}
//JS用
add_action('wp_footer', function () {
$holidays = my_holiday_dates();
$latest = max($holidays);
$start = new DateTime('first day of this month');
$start->setTime(0, 0, 0);
$end = new DateTime(date('Y-m-01', strtotime($latest)));
$end->setTime(0, 0, 0);
echo '<script>';
while ($start <= $end) {
$key = 'cal' . $start->format('Ym');
echo "document.querySelectorAll('.holiday-calendar-wrapper')
.forEach(w => w.dataset.$key = `" .
my_render_calendar_single_month(
$start->format('Y'),
$start->format('m')
) .
"`);";
$start->modify('+1 month');
}
echo '</script>';
});ショートコードの設定
add_shortcode('holiday_calendar', 'my_holiday_calendar_with_nav');上記までをfunction.phpに追記
CSS
休業日の色を#2271b1とした例
.holiday-calendar {
width: 100%;
border-collapse: collapse;
font-size: 14px;
}
.holiday-calendar th,
.holiday-calendar td {
border: 1px solid #ddd;
padding: 6px 0;
text-align: center;
}
.holiday-calendar td.other-month {
color: #bbb;
}
.holiday-calendar .sun {
color: #d63638;
}
.holiday-calendar .sat {
color: #2271b1;
}
.holiday-calendar .holiday {
background: #2271b1;
color: #fff;
}
.calendar-legend {
margin-top: 8px;
font-size: 13px;
}
.legend-item {
display: inline-flex;
align-items: center;
}
.legend-box {
width: 14px;
height: 14px;
background: #2271b1;
display: inline-block;
margin-right: 6px;
}
.calendar-nav {
display: flex;
justify-content: center;
align-items: center;
gap: 12px;
margin-bottom: 6px;
}
.calendar-nav button {
background: none;
border: none;
cursor: pointer;
font-size: 16px;
}
.calendar-nav button:disabled {
opacity: 0.3;
cursor: default;
}
表示方法
先ほど、ショートコードの設定をしたので、ウィジェットや固定ページにショートコードを貼ります。
[holiday_calendar]

コメント ※ハンドルネームでお願いします