=== Luzid Content Scheduler ===
Contributors: luzidmedia
Tags: scheduler, content, banner, shortcode, pagebuilder
Requires at least: 6.0
Tested up to: 6.9
Requires PHP: 7.4
Stable tag: 1.4.4
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Show/hide frontend content blocks (banners, alerts, divs) with schedules, recurring rules and exceptions — via CSS class or shortcode.

== Description ==

**Luzid Content Scheduler** controls *when* a specific frontend block is visible — and can also *output* the next scheduled date(s) via shortcode.

This gives you two complementary ways to use a scheduler:

1. **Show / hide a block** (banner, alert, section, popup wrapper, …)  
   Add the generated CSS class `luzid-cs-<slug>` to the element. The plugin adds body classes and a tiny frontend helper so the block is only displayed while the schedule is active.

2. **Display dates in the frontend**  
   Use the shortcode to print the next event (or a list of upcoming events) anywhere in your content.

= Typical Use Cases =

* **Maintenance banners**: Show a "We're updating our systems" notice only during scheduled maintenance windows.
* **Seasonal content**: Display holiday greetings, special offers, or seasonal menus during specific date ranges.
* **Event announcements**: Print "Next event: Saturday, March 15th at 7 PM" dynamically on any page.
* **Recurring schedules**: Show "Happy Hour specials" every Friday from 5 PM to 8 PM.
* **Multi-stage visibility**: Use Event Classes to show a popup 4 days before an event, the full content 2 weeks before, and a menu item 11 days before — all independently controlled.
* **Event calendars**: Generate a table of all upcoming events across multiple schedulers.

= Core Concepts =

* A scheduler becomes **active** when **at least one** rule matches (single dates/ranges *or* recurring rules).
* **Exceptions override everything**: if "now" is inside an exception range, the block is hidden even if other rules match.
* **Event Classes** (new in 1.4) allow multiple independent visibility windows with different offsets — each generating its own CSS class.
* The shortcode reads the same event logic and outputs formatted dates with full control over separators and formatting.

== Features ==

= Scheduling =

* **Single dates & date ranges**: Define specific days or periods when content should be visible.
* **Recurring rules**: Weekly (every Monday), Monthly (every 15th), Weekday in month (2nd Thursday), Yearly (February 14th).
* **Exceptions**: Override all rules — content stays hidden during exception periods.
* **Event Classes**: Create multiple CSS classes per scheduler, each with independent visibility offsets.

= Shortcode Output =

* **Flexible date/time formatting**: Choose from short, medium, long, or full date formats.
* **Separators**: Control exactly what appears between date, time, and text parts.
* **Lists**: Output multiple upcoming events with customizable separators.
* **Event Table**: Generate a sortable table of all upcoming events from multiple schedulers.
* **Time offset**: Shift the displayed time (e.g., "doors open 30 minutes before").

= Administration =

* **Card-based UI**: Clean, modern interface for managing rules.
* **Live preview**: See upcoming events and visibility windows instantly.
* **Bilingual**: Full German and English support with one-click language switching.

== Installation ==

1. Upload the plugin folder to `/wp-content/plugins/` or install via the WordPress Plugins screen.
2. Activate **Luzid Content Scheduler**.
3. Go to **WP Admin → Luzid Content Scheduler**.
4. Create a scheduler, define rules, and save.
5. Add the generated CSS class `luzid-cs-<slug>` to your frontend block.

== Usage ==

= Adding CSS Classes to Blocks =

* **Gutenberg**: Select block → "Advanced" → "Additional CSS class(es)" → `luzid-cs-<slug>`
* **Elementor**: Widget → "Advanced" → "CSS Classes" → `luzid-cs-<slug>`
* **Divi/others**: Module settings → "CSS Class" → `luzid-cs-<slug>`

= Basic Shortcode =

`[luzid_cs slug="your-scheduler"]`

Outputs: The next event date in the default format.

= Shortcode Parameters =

| Parameter | Default | Description |
|-----------|---------|-------------|
| `slug` | (required) | Scheduler slug |
| `date` | (empty) | Date format: `short`, `medium`, `long`, `full` |
| `time` | (empty) | Time format: `auto`, `raw`, `prefix`, `range`, `range_long` |
| `list` | `false` | Output as list: `true` or `false` |
| `count` | `10` | Number of events for lists (max 200) |
| `text` | `false` | Include event text: `true` or `false` |
| `sep1` | (space) | Separator between date and time |
| `sep2` | (space) | Separator between time and text |
| `sep3` | (empty) | Separator between list items |
| `timeoffset` | `0` | Time offset in minutes (can be negative) |
| `lang` | (current) | Force language: `de` or `en` |

= Date Formats =

| Value | Output Example |
|-------|----------------|
| `short` | 14.02.2026 |
| `medium` | Sat, 14.02.2026 |
| `long` | Saturday, 14.02.2026 |
| `full` | Saturday, 14 February 2026 |

= Time Formats =

| Value | Output Example |
|-------|----------------|
| (empty) | No time output |
| `raw` | 18:00 |
| `prefix` | from 18:00 |
| `range` | 18:00 to 20:00 |
| `range_long` | from 18:00 to 20:00 |
| `auto` | Intelligent format based on data |

= Shortcode Examples =

**Simple date output:**
`[luzid_cs slug="maintenance" date="long"]`
→ Saturday, 15.03.2026

**Date with time:**
`[luzid_cs slug="event" date="long" time="auto"]`
→ Saturday, 15.03.2026 from 18:00 to 20:00

**Only time output:**
`[luzid_cs slug="event" time="raw"]`
→ 18:00

**Multi-line output:**
`[luzid_cs slug="event" date="long" time="auto" text="true" sep1="<br>" sep2="<br>"]`
→ Saturday, 15.03.2026
   from 18:00 to 20:00
   Valentine's Dinner

**List of next 5 events:**
`[luzid_cs slug="concert" date="long" text="true" list="true" count="5" sep2="<br>" sep3="<br><br>"]`

**With custom separators:**
`[luzid_cs slug="event" date="long" time="raw" text="true" sep1=" | " sep2=" – "]`
→ Saturday, 15.03.2026 | 18:00 – Valentine's Dinner

= Event Table Shortcode =

`[luzid_cs_eventtable]`

Outputs a table of all upcoming events from schedulers with "Include in Event Table" enabled.

| Parameter | Default | Description |
|-----------|---------|-------------|
| `cols` | `date_medium,time_auto,text` | Columns (comma-separated) |
| `count` | `30` | Maximum number of events |
| `headers` | (automatic) | Custom column headers |
| `noheaders` | `false` | Hide table headers |
| `class` | (empty) | Additional CSS class |
| `empty` | "No events" | Text when no events found |
| `order` | `asc` | Sort order: `asc` or `desc` |

**Available columns:**
`date_short`, `date_medium`, `date_long`, `date_full`, `weekday_short`, `weekday_long`, `time_raw`, `time_auto`, `time_prefix`, `time_range`, `time_range_long`, `text`, `scheduler`

**Example with custom columns:**
`[luzid_cs_eventtable cols="weekday_short,date_short,time_range,text" count="10" headers="Day,Date,Time,Event"]`

= Event Classes (New in 1.4) =

Event Classes allow you to create multiple independent visibility windows for a single scheduler. Each class has its own CSS class and offset settings.

**Example setup:**

| Class | CSS Class | Days Before | Use Case |
|-------|-----------|-------------|----------|
| Standard | `.luzid-cs-dinner` | 14 | Main content |
| popup | `.luzid-cs-dinner-popup` | 4 | Announcement popup |
| menu | `.luzid-cs-dinner-menu` | 11 | Navigation menu item |

This allows you to control when different elements appear, all based on the same event schedule.

= CSS Hooks =

**Shortcode output:**
* `.luzid-cs` — Wrapper (plus `.luzid-cs--single` / `.luzid-cs--list`)
* `.luzid-cs-item` — Single event in list
* `.luzid-cs-date` — Date part
* `.luzid-cs-time` — Time part
* `.luzid-cs-text` — Event text
* `.luzid-cs-sep` / `.luzid-cs-sep1` / `.luzid-cs-sep2` — Separators

**Event table:**
* `.luzid-cs-eventtable` — Table wrapper
* `.luzid-cs-eventtable__head` / `__body` / `__row` / `__cell`

**Body classes (for conditional CSS):**
* `.luzid-cs-active-<slug>` — Added when scheduler is active
* `.luzid-cs-active-<slug>-<classname>` — Added when specific event class is active

== Frequently Asked Questions ==

= How are multiple recurring rules combined? =

They are combined with OR-logic: if **any** rule matches, the scheduler is considered active (unless an exception matches).

= Do exceptions also affect the frontend, or only the preview? =

Exceptions affect **everything** (frontend visibility, next event calculation, and preview). If "now" is inside an exception range, the block stays hidden.

= What's the difference between Event Offset (old) and Event Classes (new)? =

Event Classes replaced the old Event Offset feature in version 1.4. The key difference: you can now create **multiple classes** with independent offsets, allowing different content to appear at different times before/after an event.

= Can I use multiple Event Classes for one block? =

Each Event Class generates a separate CSS class. You can only apply one class per block, but you can have multiple blocks, each with a different Event Class.

= Does the plugin require a specific theme? =

No. It works with any theme/page builder that lets you set a custom CSS class on a block/element.

= Can I output only the time without the date? =

Yes! Use `[luzid_cs slug="your-slug" time="raw"]` to output only the time. Leave out the `date` parameter.

= How do I create a line break between date and text? =

Use `sep2="<br>"`: `[luzid_cs slug="event" date="long" text="true" sep2="<br>"]`

== Screenshots ==

1. Setup tab: Create a scheduler and copy the CSS class / shortcode.
2. Dates tab: Add single dates or date ranges with times and event text.
3. Recurring tab: Define weekly, monthly, or yearly patterns.
4. Exceptions tab: Block specific dates from showing content.
5. Event Classes tab: Create multiple CSS classes with independent visibility windows.
6. Preview tab: See all upcoming events at a glance.

== License ==

This plugin is licensed under the **GNU General Public License v2.0 or later**.

All code in this plugin is GPLv2-or-later compatible.

Assets:
* Luzid Logo and Flag icons are SVG assets shipped with the plugin (assets/img/).

== Changelog ==

= 1.4.4 =
* Fixed: List output with `list="true"` now works correctly again.
* Fixed: Event Classes CSS generation now includes all custom classes (e.g., `.luzid-cs-slug-menu`), not just the standard class.
* New: Date ranges for single dates — new "Date to" field allows multi-day events.
* Improved: Shortcode `text="true"` now outputs only the event text without automatic date fallback.
* Improved: Panel description updated to explain date range functionality.

= 1.4.2 =
* Fixed: Version number display in admin header.
* Improved: Event Classes UI with copy button for CSS classes and consistent icon styling.

= 1.4.1 =
* Fixed: WordPress Plugin Check escaping warnings for Event Classes panel.

= 1.4.0 =
* **New: Event Classes** — Replace single Event Offset with unlimited named classes, each with independent visibility offsets.
* New: Each Event Class generates its own CSS class (`luzid-cs-<slug>-<classname>`).
* New: Live preview of visibility windows per class.
* New: Standard class (non-deletable) maintains backward compatibility.
* Changed: Tab renamed from "Event-Offset" to "Event-Klassen".
* Improved: Card-based UI consistent with other tabs.
* Migration: Existing Event Offset settings are automatically converted to the new Event Classes structure.

= 1.3.12 =
* Fixed: Shortcode now outputs exactly what is specified — no hidden defaults.
* Fixed: `date` parameter defaults to empty (not "long"). Only when neither `date` nor `time` is set, `date="long"` is used as fallback.
* Fixed: Using only `time="raw"` now correctly outputs only the time, not date + time.

= 1.3.11 =
* Fixed: Auto-padding removed from separators. `&nbsp;` now outputs exactly one non-breaking space.

= 1.3.10 =
* Fixed: Single space separator handling — WordPress trims `sep1=" "`, now uses default fallback.

= 1.3.9 =
* **New: Separator system refactored** — `sep` replaced by `sep1`, `sep2`, `sep3` for precise control.
* New: `sep1` controls separator between date and time.
* New: `sep2` controls separator between time and text (or date and text if no time).
* New: `sep3` controls separator between list items.
* Changed: `time` parameter now defaults to empty (no time output unless explicitly requested).
* Breaking: Old `sep` parameter removed. Use `sep1`/`sep2`/`sep3` instead.

= 1.3.8 =
* Fixed: Preview table now shows actual saved event text per date.

= 1.3.7 =
* Fixed: Yearly recurrence calculation for events spanning year boundaries.

= 1.3.6 =
* New: `[luzid_cs_eventtable]` shortcode for tabular event output.
* New: "Include in Event Table" checkbox per scheduler.
* New: Customizable columns, headers, and sorting for event tables.

= 1.3.5 =
* Improved: Card-based layout unified across all tabs.

= 1.3.4 =
* New: Dual-prefix system for Termine tab (CSS class prefix options).

= 1.3.0 =
* New: "Time to" field for time ranges (e.g., 18:00 – 20:00) in single dates and recurring rules.
* New: Yearly recurring rule type (e.g., every February 14th at 16:00).
* New: Card-based layout for Termine and Wiederholungen tabs.
* Changed: Shortcode renamed from `[lz-cs]` to `[luzid_cs]` for WordPress.org compliance.
* Changed: CSS classes renamed from `lz-cs-*` to `luzid-cs-*`.

= 1.2.9 =
* Changed: List wrapper from `<span>` to `<div>` for better HTML structure.

= 1.2.7 =
* Fix: Prevent "phantom" events from incomplete recurring rules.
* New: Preview table shows event source (Single vs Recurring).

= 1.2.6 =
* New: Shortcode output wrapped in styled span classes.
* Improved: `sep` parameter can output `<br>` for line breaks.

= 1.2.5 =
* Fix: Separator spacing preserved correctly.
* Improvement: Single dates sorted chronologically.
* New: Optional event text for recurring rules.

= 1.2.3 =
* Added: Optional event text field for single dates.
* Changed: Shortcode supports `list`, `count`, `text` and `sep` parameters.

= 1.2.0 =
* Initial release.
