Работното време на сайта на малка фирма обикновено е ред текст в долната част на страницата: „Пон до пет 8 до 19, съб 9 до 14“. През по-голямата част от годината е вярно. Грешно е на 3 март, по Великден, по Коледа, в понеделника, който замества празник, паднал се в събота, и всеки ден по обяд, ако магазинът затваря от 13:00 до 14:00. Клиентите, които идват и намират заключена врата, не се връщат, а търсачките повтарят каквото пише на страницата. Тук показваме как да опишете истинското работно време в WordPress, да включите българските празници, да показвате „отворено сега“, което е вярно дори от кеширана страница, и да дадете на търсачките същата информация като данни schema.org. Всички примери с код са пуснати на PHP 8.4 и Node.
#Описвайте времето като интервали, а не като текст
Всичко останало зависи от това. Денят е списък от интервали, а не низ: два интервала за обедна почивка, празен списък за почивен ден и интервал, чийто край е преди началото, за бар, който затваря след полунощ.
<?php
$week = [
'mon' => [['08:00', '13:00'], ['14:00', '19:00']],
'tue' => [['08:00', '13:00'], ['14:00', '19:00']],
'wed' => [['08:00', '13:00'], ['14:00', '19:00']],
'thu' => [['08:00', '13:00'], ['14:00', '19:00']],
'fri' => [['08:00', '13:00'], ['14:00', '19:00']],
'sat' => [['09:00', '14:00']],
'sun' => [],
];
function weekly_spec(array $week): array
{
$names = ['mon' => 'Monday', 'tue' => 'Tuesday', 'wed' => 'Wednesday', 'thu' => 'Thursday',
'fri' => 'Friday', 'sat' => 'Saturday', 'sun' => 'Sunday'];
$groups = [];
foreach ($names as $key => $name) {
foreach ($week[$key] ?? [] as [$opens, $closes]) {
$groups["$opens-$closes"][] = $name;
}
}
$out = [];
foreach ($groups as $span => $days) {
[$opens, $closes] = explode('-', $span);
$out[] = ['@type' => 'OpeningHoursSpecification', 'dayOfWeek' => $days,
'opens' => $opens, 'closes' => $opens === '00:00' && $closes === '00:00' ? '23:59' : $closes];
}
return $out;
}
weekly_spec() превръща седмицата в записи OpeningHoursSpecification на schema.org, като групира дните с еднакъв интервал. За пекарната по-горе дава два записа за понеделник до петък (сутрин и следобед) и един за събота; неделята просто липсва, което значи „затворено“. Функцията следва правилата в документацията на Google за местни фирми: нощ, която продължава след полунощ, остава един запис (петък, отваря 18:00, затваря 02:00), а денонощно отворен ден се пише от 00:00 до 23:59.
#Празници: решете правило, а датите да имат предимство
Българският календар има празници на постоянни дати, великденски празници по православната дата, почивни дни, които заместват празник в събота или неделя (Кодекс на труда, чл. 154, ал. 2), и дни, които правителството обявява. Обяснихме тези правила в ръководството ни за работните дни и празниците в България. Например през 2026 г. 26 декември се пада в събота, затова понеделник, 28 декември, е почивен.
Календарът казва кои дни са празници. Дали фирмата ви затваря, решавате вие и това е различно за всяка фирма: пекарна може да затвори на Коледа, но да работи кратко сутрин на Бъдни вечер; аптека може да работи обичайно; ресторант може да е отворен по-дълго. Затова пазете правило за официалните празници (затворено, обичайно време или празнично време) и списък със свои дати, който винаги има предимство:
<?php
// $policy for public holidays: 'closed', 'usual' or a list of intervals. Your own dates always win.
function special_days(array $holidays, string|array $policy, array $own, string $from, int $days): array
{
$out = [];
$day = new DateTimeImmutable($from);
for ($i = 0; $i < $days; $i++, $day = $day->modify('+1 day')) {
$date = $day->format('Y-m-d');
if (array_key_exists($date, $own)) {
$out[$date] = $own[$date];
} elseif (isset($holidays[$date]) && $policy !== 'usual') {
$out[$date] = $policy === 'closed' ? [] : $policy;
}
}
return $out;
}
function special_spec(array $special): array
{
$out = [];
foreach ($special as $date => $intervals) {
foreach ($intervals ?: [['00:00', '00:00']] as [$opens, $closes]) {
$out[] = ['@type' => 'OpeningHoursSpecification', 'validFrom' => $date,
'validThrough' => $date, 'opens' => $opens, 'closes' => $closes];
}
}
return $out;
}
За нашата пекарна, с правило „затворено“ и собствен кратък ден на 24 декември от 10:00 до 14:00, следващите шестдесет дни от 20 декември 2026 г. дават пет специални записа: 24 декември от 10:00 до 14:00, а 25, 26 и 28 декември и 1 януари затворено, записано като отваряне и затваряне в 00:00, както документацията на Google отбелязва ден, затворен през целия ден. Те отиват в specialOpeningHoursSpecification, свойството на schema.org за изключения, които заместват обичайното време.
Две практически неща. Генерирайте специалното време за период напред (шестдесет дни са разумни) и го обновявайте всеки ден, за да не свършват данните. А когато правителството обяви допълнителен почивен ден, след като сте настроили сайта, нищо няма да знае за него: добавете го като своя дата.
#„Отворено сега“, което оцелява в кеша
Редът „Отворено сега, затваря в 13:00“ е най-полезното нещо на страницата за контакти и най-лесното за объркване. Сметнат в PHP при изграждането на страницата, той се замразява от кеша: страницата, кеширана в 07:55, казва „Затворено“, докато кешът изтече. Сметнат в JavaScript по часовника на посетителя, той ползва часовата зона на посетителя, така че клиент в чужбина вижда магазина отворен в грешните часове.
Решението е работата да се раздели. PHP записва в страницата работните часове за следващите две седмици като Unix времена, които не зависят от часова зона, а няколко реда JavaScript избират изречението в момента, в който посетителят чете:
<?php
// Opening times from now on, as Unix timestamps, for the page to carry.
function spans(array $week, array $special, DateTimeImmutable $now, int $days = 14): array
{
$out = [];
for ($i = -1; $i < $days; $i++) {
$day = $now->modify("$i day");
$date = $day->format('Y-m-d');
$intervals = array_key_exists($date, $special) ? $special[$date] : ($week[strtolower($day->format('D'))] ?? []);
foreach ($intervals as [$opens, $closes]) {
$start = new DateTimeImmutable("$date $opens", $now->getTimezone());
$end = new DateTimeImmutable("$date $closes", $now->getTimezone());
if ($end <= $start) {
$end = $end->modify('+1 day'); // past midnight, or 00:00 to 00:00 = all day
}
if ($end > $now) {
$out[] = [$start->getTimestamp(), $end->getTimestamp()];
}
}
}
return $out;
}
function statusText(spans, now = Date.now(), timeZone = "Europe/Sofia") {
const time = (s) => new Intl.DateTimeFormat("en-GB", { timeZone, hour: "2-digit", minute: "2-digit" }).format(s * 1000);
const day = (ms) => new Intl.DateTimeFormat("en-CA", { timeZone }).format(ms); // YYYY-MM-DD
for (const [start, end] of spans) {
if (now >= start * 1000 && now < end * 1000) return `Open now, closes at ${time(end)}`;
if (start * 1000 > now) {
const days = Math.round((Date.parse(day(start * 1000)) - Date.parse(day(now))) / 86400000);
const when = days === 0 ? "today" : days === 1 ? "tomorrow"
: new Intl.DateTimeFormat("en-GB", { timeZone, weekday: "long" }).format(start * 1000);
return `Closed, opens ${when} at ${time(start)}`;
}
}
return "Closed";
}
Цикълът в PHP започва от вчера, защото нощ, започнала вчера, може още да тече. В WordPress му подайте current_datetime(), което носи часовата зона на сайта от Настройки, Общи; задайте я на града на фирмата, а не на UTC. JavaScript показва всеки час в часовата зона на фирмата, където и да е посетителят. За сайт на български сменете текстовете и езика на форматите, например bg-BG.
Пуснахме двете върху декември на пекарната. В 12:30 на 23 декември казва „Open now, closes at 13:00“ (отворено, затваря в 13:00); в 13:30 „отваря днес в 14:00“; в 20:00 „отваря утре в 10:00“ заради краткия Бъдни вечер; а в 15:00 на 24 декември „отваря във вторник в 08:00“, като прескача двата дни на Коледа, неделята и почивния понеделник. Бар, отворен от 18:00 в петък, проверен в 01:00 в събота, е „отворено, затваря в 02:00“. С компютър на посетителя, настроен на часа в Ню Йорк, всеки ред излезе същият.
#Как да го сложите в WordPress
Отпечатайте JSON-LD веднъж за всеки обект в wp_head, в елемент script от тип application/ld+json, кодиран с wp_json_encode(). Ползвайте най-точния тип LocalBusiness, който подхожда (Bakery, Dentist, AutoRepair), с името, пълния адрес, координатите и телефона точно както са на страницата. Сложете работните часове в атрибут с данни до реда със състоянието и пуснете скрипта при зареждане на страницата; редът, написан от PHP, остава като версия за посетителите без JavaScript.
След това проверете: Rich Results Test на Google и Schema Markup Validator четат JSON-LD и показват грешките. Две неща, които данните не правят. Не променят профила ви в Google Business Profile, който показват Картите, затова въведете същото празнично време и там. И дали търсачката ще покаже работното ви време изобщо, решава търсачката.
#Плъгин, който го прави
Вградихме това в Rabotno, плъгин за работно време в WordPress, който познава българския календар: седмично време с до два интервала на ден, нощи след полунощ и денонощни дни, официалните празници с православния Великден, заместващите и обявените почивни дни, правило за празниците за всеки обект и специални дати с предимство, ред „отворено сега“, който остава верен зад кеша, и блок schema.org LocalBusiness със специалното работно време за следващите 60 дни. Работи за един или много обекти, на български и английски. Тестван е с 21 автоматични теста, празниците от 2024 до 2031 г. срещу отделно тестван календар, пълно изпълнение на WordPress 7.1.3 и тест в браузър на скрипта за „отворено сега“ и е обявен като „Очаквайте скоро“.
#Често задавани въпроси
Как да отбележа затворен ден в работното време по schema.org?
За обичаен почивен ден просто го пропуснете в седмичното време. За празник, в който сте затворени, добавете специален запис за датата с отваряне и затваряне в 00:00.
Как да запиша време след полунощ?
Като един запис в деня, в който започва смяната, например петък, отваря 18:00, затваря 02:00. Не го разделяйте на два дни.
Защо „отворено сега“ показва грешно състояние?
Обикновено защото е сметнато, когато страницата е кеширана, или с часовата зона на посетителя. Пращайте работните часове като времена и избирайте текста в браузъра, в часовата зона на фирмата.
Длъжен ли съм да затварям на официалните празници?
Това зависи от фирмата и уговорките с персонала, а не от сайта; попитайте счетоводителя си или консултант по трудово право. Сайтът трябва просто да показва каквото решите.
Коментари
Коментари
Напишете първия коментар.
Оставете коментар