📄 Plugin Documentation

Business Hours &
Holiday Schedule Manager

Show your opening hours, a live Open / Closed badge, holidays and special dates, and Schema.org markup — with a weekly schedule builder, Gutenberg block, widget, shortcode and Elementor widget. Lightweight, jQuery-free, and no external services.

● GPL v2 or later ● WordPress 6.2+ ● PHP 7.4+ ● Elementor Ready ● Block Themes Ready ● HPOS Compatible
01 — Introduction

What is Business Hours & Holiday Schedule Manager?

Business Hours & Holiday Schedule Manager is a complete opening-hours system for WordPress: a weekly schedule builder, a holiday and special-dates manager, a live Open / Closed status badge, and automatic Schema.org markup so search engines can read your hours too. It suits local shops, restaurants, clinics, and any service business — no coding required.

It is entirely self-hosted: your schedule lives in two WordPress options and one small database table, there is no jQuery dependency, no external service, and the plugin never contacts a remote server. Front-end CSS and JavaScript only load on pages that actually display your hours.

✨
New in 1.0.4One-click temporary closure from the admin bar, and [webtend_if_open] / [webtend_if_closed] shortcodes to show content only while you are open or closed. 1.0.3 added multi-day and yearly holidays, compact layouts and the closed-notice bar. See the changelog on WordPress.org for the full list.
🗓️
Weekly Schedule Builder
Toggle each day on or off, add up to 4 time slots per day, or start from a one-click quick-fill preset.
Free
🟢
Live Open / Closed Badge
Shows the current state and the next change ("Closes at 1:00 PM"), refreshed over AJAX without a page reload.
Free
🎄
Holiday & Special Dates
Mark dates closed or give them custom hours: one day, a date range, or every year. Search and filter your list.
Free
🌍
Timezone Support
All open/closed calculations use the timezone you choose, not the server clock.
Free
🔎
Schema.org Markup
Outputs JSON-LD with your business type, address, phone, openingHours and holiday hours — set up in Settings, no code.
Free
🧱
Block, Widget, Shortcode, Elementor
Four ways to place your hours anywhere on your site — pick whichever fits your theme.
Free
Business Hours → Weekly Schedule
Weekly schedule builder in the Business Hours admin screen

The weekly schedule builder — Quick fill presets above the list, and Wednesday open for editing with the copy buttons.

02 — Requirements

System Requirements

The plugin checks its requirements when you activate it. If PHP or WordPress is too old, it deactivates itself and explains why instead of failing. WooCommerce and Elementor are not required.

ComponentMinimumNotes
WordPress6.2Tested up to 7.0
PHP7.4Checked on activation and on every load
WooCommerceOptionalRuns alongside it with no conflicts; HPOS declared compatible
ElementorOptionalThe Business Hours widget only registers if Elementor 3.5+ is active
🧱
Block Editor
Native block with live server-side preview
🎨
Block Themes (FSE)
Block, shortcode and widget all supported
📐
Classic Themes
Shortcode and widget areas supported
🧩
Elementor
Optional — Free or Pro, 3.5+
🛒
WooCommerce
Optional — HPOS declared compatible
🌐
Translations
Full .pot file included
03 — Installation

Installation

Method A — WordPress Plugin Directory (Recommended)

1

Search in WordPress Admin

Go to Plugins → Add New and search for Business Hours & Holiday Schedule Manager.

2

Install & Activate

Click Install Now, then Activate. Activation creates a small holidays table and sets a default Mon–Fri, 9:00 AM–5:00 PM schedule.

3

Open the Admin Screen

Click Business Hours in the admin sidebar to set up your real hours.

Method B — Manual Upload

1

Upload

Download webtend-business-hours.zip, then go to Plugins → Add New → Upload Plugin and install the ZIP. Or unzip it into /wp-content/plugins/.

2

Activate

Click Activate Plugin. The Business Hours menu appears in the admin sidebar.

3

Set Your Hours

Use the Weekly Schedule, Holidays and Settings tabs, then add the hours to a page.

💡
Nothing is contacted on activationActivation only creates a database table and default options. The plugin makes no external requests, now or later.
04 — Quick Start

Quick Start

After activation you will find Business Hours in your WordPress admin menu.

  • On Settings, choose your timezone first — every open/closed calculation depends on it
  • On Weekly Schedule, pick a Quick fill preset or toggle the days you are open and click the edit icon to set times or add a split shift, then Save schedule
  • On Holidays, add any closed dates or reduced-hours days
  • Add the hours to a page with the Business Hours block, the widget, or [webtend_business_hours]
  • Check the Shortcodes & Usage tab any time for copy-ready usage examples
05 — Feature

Weekly Schedule

Each day has an on/off toggle and a list of time slots. A day that is switched off shows as Closed everywhere. Today's row carries a Today chip so you can see at a glance which day the status badge is reporting on.

Split shifts and lunch breaks

Click the edit icon on a day to open its slot editor. Set the first open and close times, then use + Add split shift to add another slot — up to 4 per day. A morning slot of 09:00–12:00 plus an afternoon slot of 13:00–17:00 gives you a lunch break. Remove any extra slot with its ✕ button.

Quick-fill presets

Above the day list, the Quick fill bar sets up a standard week in one click: Mon–Fri 9–5, Mon–Sat 10–6 or 7 Days 9–9. A preset fills the form only — nothing is stored until you click Save schedule, so you can tweak any day afterwards.

Copy hours to other days

When a day’s editor is open, Apply to all days copies that day’s slots to every day, and Copy to Mon–Fri copies them to the weekdays only. It saves retyping when several days share the same hours.

Saving

Changes are saved over AJAX when you click Save schedule — no page reload. The time chips on each row reflect your edits as you make them.

06 — Feature

Holidays & Special Dates

Holidays always override the weekly schedule for their date. Use them for public holidays, staff days, or reduced hours.

Adding a holiday

Pick a Date, give it an optional Label, and leave Closed all day on. Switch it off to reveal opening and closing times for a custom-hours day (for example Christmas Eve, 10:00–14:00). Each date holds one entry — saving the same date again updates it.

Business Hours → Holidays
Holiday manager showing the add-holiday form and upcoming holidays

The holiday manager — end date and “Repeat every year” on the add form, and multi-day and yearly entries in the list.

Multi-day closures

Add an optional End date to close for several days, such as a winter break. Every day from the start date to the end date (inclusive) uses the holiday setting, and the end date can never be before the start date. The list shows “Through …” on those entries.

Repeat every year

Switch on Repeat every year so a holiday applies to the same dates each year, for example Christmas, so you only enter it once. A range that runs across New Year works too (24 Dec – 2 Jan). A 29 February entry falls on 28 February in non-leap years. A dated entry for a specific day always wins over a yearly one.

Searching and filtering

Use Search by label… to find a holiday by name and the month picker to show a single month (matched on the entry’s start date). Clear resets both. Lists longer than 20 entries are paged, with controls at the bottom of the list. Search and paging update over AJAX, without reloading the screen.

If you pick a date in the past, a warning appears under the date field so you do not add a holiday that will never show.

Removing a holiday

Click the trash icon next to any entry in Upcoming holidays.

07 — Feature

Live Status & Timezone

The status badge says whether you are open right now and when that will change. It is rendered on the server, then kept fresh by a lightweight AJAX poll so a visitor who leaves a tab open still sees the right answer.

Refresh interval

The default is 60 seconds. Set it under Settings → Live status refresh interval; enter 0 to turn automatic refresh off entirely.

Opening-time text around holidays

The “Opens …” text looks ahead up to 60 days and skips closed holidays and multi-day closures, so it never says “Opens tomorrow” when tomorrow is a holiday. During a holiday it shows the next real opening time.

Compact layouts

For headers, footers and sidebars you do not need the whole week. Use display="today" for one line with today’s hours (with the badge unless show_status="false"), or display="status" for just the live badge. The block, widget and Elementor widget have a Layout option with the same three choices: full weekly table, today only, status badge only. Both update live like the full table.

Temporary closure (“Close now”)

Power cut, bad weather, someone off sick? Click the Business Hours menu in the WordPress admin bar (or go to Settings → Temporary Closure) and choose:

  • Close for the rest of today — closed until your next scheduled opening, which ends the closure by itself
  • Close until I reopen — stays closed until you click Reopen now

The badge, “Today” line, notice bar and live refresh all switch to Closed straight away and show your optional Closure message (for example “Closed due to bad weather”). A closure for the rest of today also shows when you reopen. Your weekly schedule and holidays are not changed, so nothing needs undoing. Only administrators (users who can manage options) see the menu or can use the action, and every switch is protected by a nonce.

Closed notice bar

Turn on Settings → Closed Notice Bar to show a thin bar at the top of every page only while you are closed, for example “We’re currently closed. Opens tomorrow at 9:00 AM”. It is off by default and prints nothing while you are open. You can write your own message (the next opening time is added after it) and let visitors dismiss it for the rest of their browser session (no cookies are used). Themes that do not call wp_body_open() get a fixed bar at the bottom of the screen instead. The bar is rendered on the server, so with full-page caching it reflects the time the page was cached. During a temporary closure it shows your closure message.

Labels and time format

Rename the badge text with Open label and Closed label. Leave either blank to use the translated defaults ("Open Now" / "Closed") in your site language. Choose 12-hour, 24-hour, or 12-hour lowercase display.

Business Hours → Settings
Settings panel

Timezone, labels, schema options, Business Details, Address, Temporary Closure and the Closed Notice Bar.

yourstore.com → Visit us
Front-end hours table with live open badge

The front-end status badge and hours table, with today highlighted.

08 — Feature

Schema.org Markup

On every front-end page the plugin prints one JSON-LD script describing your business, built from your settings and weekly schedule. Turn it off with Settings → Schema.org markup.

Business Details

Fill in Settings → Business Details and Address: business type (restaurant, dentist, store and 18 more), business name (blank uses your site title), phone number, price range, and address. Only fields you fill in are output. The theme’s custom logo is added automatically when one is set.

Holiday hours

Upcoming holidays (up to 100 periods, within the next 400 days; multi-day closures and yearly entries are expanded into dated periods) are added as specialOpeningHoursSpecification. A closed day uses 00:00–00:00, the schema.org convention for closed all day; a custom-hours day uses its own times. Switch this off with Include holiday hours. Multi-day closures and yearly entries are expanded into dated periods, and the list is cached and refreshed when you add, change or delete a holiday.

Example output
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Restaurant",
  "name": "Harbor Street Café",
  "url": "https://example.com",
  "telephone": "+1 800 555 0100",
  "priceRange": "$$",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "123 Main St",
    "addressLocality": "Springfield",
    "addressRegion": "IL",
    "postalCode": "62701",
    "addressCountry": "US"
  },
  "openingHours": ["Mo 09:00-13:00", "Mo 14:00-18:00", …],
  "specialOpeningHoursSpecification": [{
    "@type": "OpeningHoursSpecification",
    "validFrom": "2026-12-25",
    "validThrough": "2026-12-25",
    "opens": "00:00",
    "closes": "00:00",
    "name": "Christmas Day"
  }]
}
</script>
💡
No code neededAddress, phone and business type are now ordinary settings. The webtend_bh_schema_data filter is still there for anything extra, such as social profile links.
09 — Feature

Block, Widget & Elementor

Gutenberg block

1

Insert

In the editor, click + and search Business Hours.

2

Preview

The block renders a live server-side preview of your real hours.

3

Options

In the block sidebar, Display Options → Show live status badge toggles the badge. The block also supports wide/full alignment, colors and spacing.

Classic widget

Go to Appearance → Widgets and add Business Hours to any widget area. Set a Title and choose whether to Show live open/closed status. It works in both the block-based widget editor and the classic widgets screen.

Elementor widget

If Elementor 3.5+ is active, a Business Hours widget appears in the Elementor panel. Content controls the status badge toggle. Style adds color controls for the Open and Closed badge (text and background), badge and row typography, day-name, hours, today-highlight and divider colors, and row padding.

Layout (all four placements): choose Full weekly table, Today only or Status badge only.

10 — Reference

Shortcode

[webtend_business_hours]
The full weekly hours table with the live status badge.
[webtend_business_hours display="today"]
One line with today’s hours, plus the badge.
[webtend_business_hours display="status"]
The live Open / Closed badge only.
[webtend_business_hours show_status="false"]
Hours table only — hides the badge.
AttributeDefaultNotes
displayfullfull, today or status
show_statustruetrue or false — show the live status badge (always shown for display="status")
show_tabletruefalse hides the weekly table (same as display="status" with the badge); kept for older pages
class—Extra CSS class on the wrapper

Paste the shortcode into any page, post, sidebar, or template via do_shortcode(). Assets load only on pages where the shortcode, block or widget actually appears.

Show content only when open or closed

[webtend_if_open]Call us now on 555-0100[/webtend_if_open]
Shown only while you are open.
[webtend_if_closed]We are closed. Leave a message and we will reply tomorrow.[/webtend_if_closed]
Shown only while you are closed (including holidays and temporary closures).

They use the same status as the badge. Other shortcodes inside them work, but a conditional shortcode cannot contain another of the same name (a WordPress limitation). The content is decided on the server, so with full-page caching it reflects the moment the page was cached.

11 — Reference

All Settings

Everything on the Settings tab, plus where the data is stored.

SettingDefaultNotes
Timezonesite timezone at installAny PHP timezone or fixed offset such as +06:00; used for all open/closed calculations
Time display formatg:i Ag:i A (9:00 AM), H:i (09:00) or g:i a (9:00 am)
Open labelOpen NowLeave blank to use the translated default
Closed labelClosedLeave blank to use the translated default
Schema.org markuponPrints the JSON-LD block
Include holiday hoursonAdds upcoming holidays to the Schema.org markup
Live status refresh interval60Seconds, 0–3600; 0 turns refresh off
Business typeGeneral local businessA schema.org type such as Restaurant, Dentist or Store
Business namesite titleName used in the Schema.org markup
Phone number—Digits, spaces and + - ( ) only
Price range—For example $$
Street, City, State/region, Postal code—Output as a PostalAddress when any is filled in
Country code—Two-letter ISO code such as US, GB or BD
Show a notice while closedoffShows the closed-notice bar at the top of every page while you are closed
Notice messageWe’re currently closed.Custom text; the next opening time is added after it (max 160 characters)
Allow visitors to dismiss itonAdds a dismiss button; remembered for the browser session
Closure message—Text shown during a temporary closure (max 160 characters); the Close now buttons are on the same screen

Stored data

ItemTypeContains
wbh_scheduleoptionWeekly schedule: enabled flag and time slots per day
wbh_settingsoptionThe settings above
wbh_versionoptionInstalled version, used for upgrades
wbh_closureoptionWhether a temporary closure is active, until when, and its message
wbh_db_erroroptionSet only if the holidays table could not be created; triggers an admin notice
{prefix}wbh_holidaystableHoliday dates, labels, closed flag and custom hours
💡
Clean uninstallDeleting the plugin from the Plugins screen removes all of the options above and drops the holidays table (on every site of a multisite network).
12 — Reference

Hooks & Filters

For developers and agencies who need to customize output without editing plugin files.

HookTypePurpose
webtend_bh_output_schemafilterReturn false to skip the JSON-LD block (for example on specific pages)
webtend_bh_schema_typefilterChange the Schema.org type from LocalBusiness to any other type
webtend_bh_schema_datafilterAdd or change any property — for example sameAs or geo — before output
webtend_bh_is_openfilterChange the open/closed decision used by [webtend_if_open] and [webtend_if_closed]; receives the decision and the status
webtend_bh_show_notice_barfilterReturn false to hide the closed-notice bar on specific pages; receives the default decision and the status
wbh_get_statusAJAX actionPublic (wp_ajax_nopriv_) endpoint the live badge polls; nonce-protected
Example — add social profiles to the schema
add_filter( 'webtend_bh_schema_data', function( $schema ) {
    $schema['sameAs'] = array(
        'https://www.facebook.com/yourpage',
        'https://www.instagram.com/yourpage',
    );
    return $schema;
} );
Example — disable the schema on the contact page
add_filter( 'webtend_bh_output_schema', function( $output ) {
    return is_page( 'contact' ) ? false : $output;
} );
Example — use a more specific Schema.org type
add_filter( 'webtend_bh_schema_type', function() {
    return 'Restaurant';
} );

CSS custom properties (theming)

Every visual token is a custom property on .wbh-widget, so you can restyle the block, widget and shortcode from your theme stylesheet without !important.

PropertyDefaultControls
--wbh-open#16a34aOpen status colour
--wbh-open-bg#dcfce7Open badge background
--wbh-closed#dc2626Closed status colour
--wbh-closed-bg#fee2e2Closed badge background
--wbh-accent#4f46e5Accent and today highlight
--wbh-today-bg#eef2ffToday row background
--wbh-today-colorinheritToday row text colour
--wbh-textinheritPrimary text colour
--wbh-text-muted#64748bSecondary text colour
--wbh-border#e2e8f0Table row border colour
--wbh-fontinheritFont family
--wbh-font-size0.9remBase font size
--wbh-radius6pxBorder radius
--wbh-row-padding8px 0Table row padding
--wbh-badge-radius999pxStatus badge border radius
Example — brand colours and larger text
.wbh-widget {
    --wbh-accent:     #be123c;
    --wbh-today-bg:   #ffe4e6;
    --wbh-font-size:  1rem;
}

The notice bar has two colour tokens on .wbh-notice-bar:

Example — notice bar colours
.wbh-notice-bar {
    --wbh-notice-bg:   #7c2d12;
    --wbh-notice-text: #ffffff;
}
13 — FAQ

Frequently Asked Questions

Does this work with WooCommerce?
Yes. It runs alongside WooCommerce with no conflicts and declares HPOS compatibility. WooCommerce is not required.
How does the live status update?
A lightweight AJAX poll refreshes the badge every 60 seconds by default. Change the interval on the Settings tab, or set it to 0 to disable automatic refresh.
Can I show a lunch break?
Yes. Each day supports up to 4 time slots — for example 09:00–12:00 and 13:00–17:00.
What happens on a holiday?
The holiday replaces the weekly schedule for that date. Mark it closed all day, or set custom opening and closing times.
Does it help my SEO?
The plugin outputs structured data (business type, address, phone, opening hours and holiday hours) that search engines can use to understand your business. Fill in Settings → Business Details for the fullest markup. It cannot guarantee any particular ranking or rich result.
Are my holidays included in the Schema.org markup?
Yes. Upcoming holidays are added as special opening hours. Closed days use 00:00–00:00. Turn it off with Include holiday hours in Settings.
Is it compatible with block themes?
Yes. The block, widget and shortcode all work with block themes, classic themes and page builders.
Does it need Elementor?
No. The Elementor widget registers only if Elementor 3.5+ is active; everything else works without it.
Does it contact any external server?
No. There are no remote requests, no tracking and no external fonts or scripts.
Is the plugin translation ready?
Yes. All strings use the webtend-business-hours text domain, and a .pot file is included in /languages.
What is removed when I delete the plugin?
Its options and the wbh_holidays table. Your pages are not modified, but any shortcode left in content will show as plain text.
Can I manage hours for more than one location?
Not currently. The plugin manages one schedule per site; each site in a multisite network has its own.
Is it accessible?
Yes. The status badge is announced to screen readers, hours tables use proper row headers, and the admin controls have visible keyboard focus and labels.
How do I change the colours or fonts?
Override the --wbh-* custom properties on .wbh-widget in your theme CSS. See Hooks & Filters for the full list.
Can I add a holiday that lasts several days?
Yes. Set the date and an optional End date on the Holidays screen. Every day in the range uses the holiday setting.
Do I have to re-enter holidays every year?
No. Switch on Repeat every year and the holiday applies to the same dates each year.
How do I show only today’s hours or just the Open Now badge?
Use [webtend_business_hours display="today"] or display="status", or pick a Layout in the block, widget or Elementor widget.
How do I show a message when the business is closed?
Turn on Settings → Closed Notice Bar. It appears only while you are closed and includes the next opening time. With full-page caching it reflects the time the page was cached.
How do I close the business quickly without adding a holiday?
Use the Business Hours menu in the admin bar: Close for the rest of today or Close until I reopen. Add a message under Settings → Temporary Closure. Click Reopen now to end it. Your schedule and holidays are not changed.
How do I show a phone number or button only while I am open?
Wrap it in [webtend_if_open]…[/webtend_if_open], and use [webtend_if_closed]…[/webtend_if_closed] for the closed version. With full-page caching the result reflects the moment the page was cached.
Can I put one conditional shortcode inside another?
Not one of the same name; WordPress does not support that for shortcodes. Other shortcodes, including [webtend_business_hours], work inside them.
How do I get support?
Free support is on the WordPress.org support forum. Please include your WordPress version, PHP version, active theme, and a clear description of the issue.