diff --git a/.gitignore b/.gitignore index a79ebc0..36a70d8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ notes/ phpcs-results.txt +tests/ diff --git a/.vscode/settings.json b/.vscode/settings.json index 36281d1..75358cb 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,6 +3,14 @@ "tree.indentGuidesStroke": "#3d92ec", "activityBar.background": "#123509", "titleBar.activeBackground": "#1A4A0D", - "titleBar.activeForeground": "#F5FDF3" + "titleBar.activeForeground": "#F5FDF3", + "titleBar.inactiveBackground": "#123509", + "titleBar.inactiveForeground": "#F5FDF3", + "statusBar.background": "#123509", + "statusBar.foreground": "#F5FDF3", + "statusBar.debuggingBackground": "#123509", + "statusBar.debuggingForeground": "#F5FDF3", + "statusBar.noFolderBackground": "#123509", + "statusBar.noFolderForeground": "#F5FDF3" } } diff --git a/README.md b/README.md index 7b0b30a..fcf7147 100644 --- a/README.md +++ b/README.md @@ -6,24 +6,25 @@ An approachable, theme‑friendly events plugin for WordPress. It adds an `Event - Event post type with archive at `/events`. - Two taxonomies: `Event Types` (hierarchical) and `Event Tags` (non‑hierarchical). -- Event details via ACF: date/time, cost, location (online URL vs in‑person address). +- Event details via ACF: occurrences, cost, location (online URL vs in‑person address). - Front‑end templates: archive list, single view, and a calendar page template. - Theme overrides for templates and styles with simple folder conventions. -- Sensible defaults: admin column for date, sortable by event date; taxonomy views sort upcoming first; main events archive sorts newest first. +- Sensible defaults: the admin date column shows and sorts by the earliest normalized occurrence. --- ## Requirements - WordPress 5.8+ (uses modern APIs like `wp_date()` and template filters). -- Advanced Custom Fields (free) is required for the event fields. The plugin will load without ACF, but the Event fields and related UI will not be available until ACF is active. +- PHP 7.4+. +- Advanced Custom Fields PRO is required for the event fields. **Occurrences** uses the Repeater field, which is an ACF PRO feature. The plugin will load without ACF PRO, but its built-in Event fields and related editing UI will not be available. --- ## Installation 1. Copy the `aa-events` folder into `wp-content/plugins/`. -2. (Required) Install and activate the “Advanced Custom Fields” plugin. +2. (Required) Install and activate **Advanced Custom Fields PRO** so the Occurrences repeater is available. 3. In WordPress Admin → Plugins, activate “AA Events”. 4. Visit Settings → Permalinks and click Save if your events archive doesn’t appear (activation also flushes rewrites). @@ -33,13 +34,28 @@ An approachable, theme‑friendly events plugin for WordPress. It adds an `Event 1. Create events: Admin → Events → Add New. 2. Fill in the “Event Details” fields: - - Event Date & Time (required) + - **Occurrences**: Add one row for each occurrence. A start date is required in every row; start time, end date, end time, and All Day are optional. + - **Event Date & Time** (optional compatibility field only; use Occurrences when creating or editing event dates) - Event Cost (optional) - - Online/In‑Person toggle (required) + - Online/In‑Person toggle (optional) - Event URL (required when Online) - Event Address (required when In‑Person) + - Contact Email (optional; displayed on the single-event page) 3. View your list of events at `/events` and single event pages at their permalinks. -4. For a calendar view, create a new Page and choose the “Events Calendar” template, then publish. +4. For a calendar view, create a new Page and choose the "Events Calendar" template, then publish. + +### Event Occurrences + +The **Occurrences** repeater is the primary schedule editor. Each row describes one continuous occurrence: + +1. Click **Add Occurrence** and enter its required Date. +2. Optionally add a Start Time. Add an End Date and/or End Time when the occurrence continues beyond its starting point; leaving the end blank is valid. +3. Enable **All Day** for an all-day occurrence. This hides the time controls, and saved time values are ignored. +4. Add another row when the event occurs again. Rows may freely mix single-day, multi-day, timed, and all-day occurrences; the plugin does not generate recurrence rules. + +For example, one event can have a row starting Friday at 6:00 PM and ending Sunday at 2:00 PM, plus a later row with a different date and **All Day** enabled. That is one continuous weekend occurrence followed by one separate all-day occurrence. + +**Backward compatibility:** Existing `event_dates` rows continue to work. The plugin also reads the optional legacy **Event Date & Time** (`event_datetime`) value and older standalone `date`/`start_time` fields when no occurrence rows are present. Saving a legacy-only event in the editor creates one equivalent occurrence row. No bulk migration is required, and later saves do not add duplicate rows. --- @@ -47,15 +63,11 @@ An approachable, theme‑friendly events plugin for WordPress. It adds an `Event - Post type: `event` - Public, has archive (`/events`), supports title, editor, author, thumbnail. - - Default sort: - - Admin list: ascending by Event Date & Time. - - Taxonomy views: ascending (upcoming first). - - Main events archive: descending (newest first). - Taxonomies - `event_type` (hierarchical, slug `event-type`) - `event_tag` (non‑hierarchical, slug `event-tag`) - Admin UX - - Adds a “Date & Time” column on Events list, sortable by the event date. + - Adds a “Date & Time” column on Events list, showing the earliest normalized occurrence and a count of additional occurrences; sorting uses the earliest occurrence. --- @@ -64,7 +76,13 @@ An approachable, theme‑friendly events plugin for WordPress. It adds an `Event - Archive: `/events` uses `templates/archive-event.php`. - Single: each event uses `templates/single-event.php`. - Calendar page: Page → Template → “Events Calendar” renders `templates/template-calendar.php` which includes `templates/calendar.php`. -- Calendar navigation: query args `?month=MM&year=YYYY` change the visible month; “Today” jumps back to the current month. +- Calendar navigation: query args `?aa_month=MM&aa_year=YYYY` change the visible month; “Today” jumps back to the current month. (`month`/`year` still work for legacy links.) +- Archive and single templates show each occurrence as a formatted date or date/time range. +- Single-event pages show a clickable Contact Email when a valid address is provided. +- On desktop and tablet, the calendar is a traditional month grid. Multi-day occurrences render as bars spanning each week they cross, with the event title repeated on each weekly segment. +- At `640px` wide and below, the calendar becomes a chronological agenda. +- Occurrences that cross into the visible month are included even when they start before it or end after it. +- Calendar dates use the site timezone and the week layout respects Settings → General → “Start of week”. --- @@ -82,6 +100,8 @@ Example: to override the archive, create `your-theme/aa-events/archive-event.php Page template in a theme: the “Events Calendar” page template also respects theme overrides at `your-theme/aa-events/template-calendar.php`. +An existing `your-theme/aa-events/calendar.php` remains authoritative. It does not automatically acquire the plugin template’s week-spanning bars or mobile agenda markup. Theme authors can update overrides using `aa_events_get_occurrences()`, `aa_events_format_occurrence()`, and `aa_events_occurrence_time_markup()`. A CSS override must also account for any new calendar and agenda markup it adopts. + --- ## Styling @@ -95,6 +115,10 @@ Note: The bundled CSS is intentionally minimal. Use the override to match your t ## Developer Notes +- Occurrence helpers: + - `aa_events_get_occurrences( $post_id )` returns chronologically sorted, normalized rows from the occurrence repeater or a legacy fallback. Rows include `source`, `start_inferred`, and `end_inferred`; the inference flags identify legacy-derived starts and defaulted ends. + - `aa_events_format_occurrence( $occurrence )` returns the localized visible range label. + - `aa_events_occurrence_time_markup( $occurrence )` returns escaped, accessible `