From 4ff839b10a72a0a091e59445b43f43148f427418 Mon Sep 17 00:00:00 2001 From: Keith Solomon Date: Wed, 10 Dec 2025 10:45:42 -0600 Subject: [PATCH 1/4] =?UTF-8?q?=F0=9F=90=9E=20fix:=20Add=20missing=20varia?= =?UTF-8?q?bles=20to=20function=20call?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- templates/calendar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/calendar.php b/templates/calendar.php index d960e8a..fb38f25 100644 --- a/templates/calendar.php +++ b/templates/calendar.php @@ -103,7 +103,7 @@ $isTodayInCurrentMonth = ( $curMonth === $todayMonth && $curYear === $todayYear Date: Wed, 10 Dec 2025 11:29:41 -0600 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=90=9E=20fix:=20Update=20to=20correct?= =?UTF-8?q?=20year=20switch=20navigation=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- includes/class-aa-events.php | 14 ++++++ templates/calendar.php | 97 ++++++++++++++++++++++++------------ 3 files changed, 80 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 7b0b30a..dc88371 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ 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.) --- diff --git a/includes/class-aa-events.php b/includes/class-aa-events.php index 6e90fcb..f8261a1 100644 --- a/includes/class-aa-events.php +++ b/includes/class-aa-events.php @@ -63,6 +63,7 @@ final class AA_Events { add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_styles' ) ); // Ensure the active theme supports thumbnails for the event post type. add_action( 'after_setup_theme', array( $this, 'ensure_post_thumbnails_support' ) ); + add_filter( 'query_vars', array( $this, 'register_calendar_query_vars' ) ); } /** @@ -125,4 +126,17 @@ final class AA_Events { } // If theme support is boolean true (all types), nothing to do. } + + /** + * Allow custom AA Events calendar query vars to persist through canonical redirects. + * + * @param array $vars Public query vars. + * @return array + */ + public function register_calendar_query_vars( $vars ) { + $vars[] = 'aa_month'; + $vars[] = 'aa_year'; + + return $vars; + } } diff --git a/templates/calendar.php b/templates/calendar.php index fb38f25..41cdbe8 100644 --- a/templates/calendar.php +++ b/templates/calendar.php @@ -9,32 +9,65 @@ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } +// Use custom query vars (avoid WP date archive/canonical behavior on `year`) +$month_param = 'aa_month'; +$year_param = 'aa_year'; + // Get current month and year (read-only query vars; validate instead of nonce) $month_input = filter_input( - INPUT_GET, - 'month', - FILTER_VALIDATE_INT, - array( - 'options' => array( - 'min_range' => 1, - 'max_range' => 12, - ), - ) + INPUT_GET, + $month_param, + FILTER_VALIDATE_INT, + array( + 'options' => array( + 'min_range' => 1, + 'max_range' => 12, + ), + ) ); +// Back-compat for legacy `month` query arg if present. +if ( false === $month_input || null === $month_input ) { + $month_input = filter_input( + INPUT_GET, + 'month', + FILTER_VALIDATE_INT, + array( + 'options' => array( + 'min_range' => 1, + 'max_range' => 12, + ), + ) + ); +} + $year_input = filter_input( - INPUT_GET, - 'year', - FILTER_VALIDATE_INT, - array( - 'options' => array( - // Choose a sane range for years. - 'min_range' => 1970, - 'max_range' => 2200, - ), - ) + INPUT_GET, + $year_param, + FILTER_VALIDATE_INT, + array( + 'options' => array( + // Choose a sane range for years. + 'min_range' => 1970, + 'max_range' => 2200, + ), + ) ); +// Back-compat for legacy `year` query arg if present. +if ( false === $year_input || null === $year_input ) { + $year_input = filter_input( + INPUT_GET, + 'year', + FILTER_VALIDATE_INT, + array( + 'options' => array( + 'min_range' => 1970, + 'max_range' => 2200, + ), + ) + ); +} $curMonth = ( false !== $month_input && null !== $month_input ) ? (int) $month_input : (int) wp_date( 'n' ); $curYear = ( false !== $year_input && null !== $year_input ) ? (int) $year_input : (int) wp_date( 'Y' ); @@ -139,11 +172,11 @@ $calendarOutput = preg_replace( ?>
- +
" - >« + href="?aa_month=&aa_year=" + aria-label="" + >« -

+

- " - > » + " + > »
From b450b7329df9632625df67c4d6e3224bb78a4c4b Mon Sep 17 00:00:00 2001 From: Keith Solomon Date: Wed, 10 Dec 2025 11:44:32 -0600 Subject: [PATCH 3/4] =?UTF-8?q?=E2=9C=A8feature:=20Respect=20WordPress=20"?= =?UTF-8?q?Start=20of=20week"=20setting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +- templates/calendar.php | 72 +++++++++++++++++++++++++++++++++--------- 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index dc88371..6c6797e 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,8 @@ 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 `?aa_month=MM&aa_year=YYYY` change the visible month; “Today” jumps back to the current month. (`month`/`year` still work for legacy links.) +- 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.) +- Calendar week layout respects the site’s Settings → General → “Start of week” option. --- diff --git a/templates/calendar.php b/templates/calendar.php index 41cdbe8..2d2d37a 100644 --- a/templates/calendar.php +++ b/templates/calendar.php @@ -91,9 +91,55 @@ if ( $next_month > 12 ) { $days_in_month = cal_days_in_month( CAL_GREGORIAN, $curMonth, $curYear ); // Get the first day of the month in site timezone. -$tz = wp_timezone(); -$first_ts = ( new DateTimeImmutable( sprintf( '%04d-%02d-01 00:00:00', $curYear, $curMonth ), $tz ) )->getTimestamp(); -$first_day = (int) wp_date( 'N', $first_ts ); +$tz = wp_timezone(); +$first_ts = ( new DateTimeImmutable( sprintf( '%04d-%02d-01 00:00:00', $curYear, $curMonth ), $tz ) )->getTimestamp(); + +// Respect the site's chosen week start (0 = Sunday, 6 = Saturday). +$start_of_week = (int) get_option( 'start_of_week', 1 ); +if ( $start_of_week < 0 || $start_of_week > 6 ) { + $start_of_week = 0; +} + +// Calculate how many empty cells to prepend before day 1 based on the start day. +$first_weekday_of_month = (int) wp_date( 'w', $first_ts ); // 0 (Sun) - 6 (Sat). +$leading_empty_cells = ( $first_weekday_of_month - $start_of_week + 7 ) % 7; + +// Build weekday labels in the configured order. +$weekdays = array( + array( + 'abbr' => __( 'Sun', 'aa-events' ), + 'label' => __( 'Sunday', 'aa-events' ), + ), + array( + 'abbr' => __( 'Mon', 'aa-events' ), + 'label' => __( 'Monday', 'aa-events' ), + ), + array( + 'abbr' => __( 'Tue', 'aa-events' ), + 'label' => __( 'Tuesday', 'aa-events' ), + ), + array( + 'abbr' => __( 'Wed', 'aa-events' ), + 'label' => __( 'Wednesday', 'aa-events' ), + ), + array( + 'abbr' => __( 'Thu', 'aa-events' ), + 'label' => __( 'Thursday', 'aa-events' ), + ), + array( + 'abbr' => __( 'Fri', 'aa-events' ), + 'label' => __( 'Friday', 'aa-events' ), + ), + array( + 'abbr' => __( 'Sat', 'aa-events' ), + 'label' => __( 'Saturday', 'aa-events' ), + ), +); + +$ordered_weekdays = array_merge( + array_slice( $weekdays, $start_of_week ), + array_slice( $weekdays, 0, $start_of_week ) +); // Get events for the current month. $events = new WP_Query( @@ -156,10 +202,10 @@ $originalEchoDayCell = function ( $day, $firstDay, $eventsByDay ) use ( $isToday // Overwrite the default day cell output in the table loop. ob_start(); for ( $day = 1; $day <= $days_in_month; $day++ ) { - if ( ( $day + $first_day - 2 ) % 7 === 0 && $day > 1 ) { + if ( ( ( $day + $leading_empty_cells - 1 ) % 7 ) === 0 && $day > 1 ) { echo ''; } - $originalEchoDayCell( $day, $first_day, $events_by_day ); + $originalEchoDayCell( $day, $leading_empty_cells, $events_by_day ); } $calendarRows = ob_get_clean(); @@ -203,26 +249,22 @@ $calendarOutput = preg_replace( - - - - - - - + + + '; } // Loop through the days of the month. for ( $day = 1; $day <= $days_in_month; $day++ ) { - if ( ( $day + $first_day - 2 ) % 7 === 0 && $day > 1 ) { + if ( ( ( $day + $leading_empty_cells - 1 ) % 7 ) === 0 && $day > 1 ) { echo ''; } @@ -250,7 +292,7 @@ $calendarOutput = preg_replace( } // Add empty cells for the last week. - $remaining_days = 7 - ( ( $days_in_month + $first_day - 1 ) % 7 ); + $remaining_days = ( 7 - ( ( $days_in_month + $leading_empty_cells ) % 7 ) ) % 7; if ( $remaining_days < 7 ) { for ( $i = 0; $i < $remaining_days; $i++ ) { From 30c63e447988ff24abf8b62af4d478fe59f3bca3 Mon Sep 17 00:00:00 2001 From: Keith Solomon Date: Wed, 13 May 2026 15:35:56 -0500 Subject: [PATCH 4/4] =?UTF-8?q?=E2=9C=A8feature:=20Add=20ACF=20admin=20fie?= =?UTF-8?q?ld=20group=20support=20with=20plugin=20fallback?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .vscode/settings.json | 10 +++++++++- aa-events.php | 2 +- includes/acf-fields.php | 38 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 2 deletions(-) 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/aa-events.php b/aa-events.php index 053fe91..776243a 100644 --- a/aa-events.php +++ b/aa-events.php @@ -3,7 +3,7 @@ * Plugin Name: AA Events * Plugin URI: https://github.com/automattic/aa-events * Description: An Events management plugin for WordPress, with accessible calendar (WCAG 2.2AA) and card grid views. - * Version: 1.0.0 + * Version: 1.1.0 * Author: Keith Solomon * Author URI: https://vincentdesign.ca * License: GPL-2.0+ diff --git a/includes/acf-fields.php b/includes/acf-fields.php index 9eadef1..812e989 100644 --- a/includes/acf-fields.php +++ b/includes/acf-fields.php @@ -9,10 +9,48 @@ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } +/** + * Check whether an ACF field group created in the admin targets the event post type. + * + * @return bool True if an external field group is assigned to events. + */ +function events_has_admin_field_group() { + if ( ! function_exists( 'acf_get_field_groups' ) ) { + return false; + } + + $groups = acf_get_field_groups( array( 'post_type' => 'event' ) ); + + foreach ( $groups as $group ) { + if ( isset( $group['active'] ) && ! $group['active'] ) { + continue; + } + + if ( + isset( $group['key'], $group['local'] ) + && 'group_61b0c5f5a3e7e' === $group['key'] + && 'php' === $group['local'] + ) { + continue; + } + + return true; + } + + return false; +} + /** * Register the ACF field group. + * + * Skips registration when an admin-created field group is already + * assigned to the event post type, allowing full editorial control. */ function events_register_acf_fields() { + if ( events_has_admin_field_group() ) { + return; + } + if ( function_exists( 'acf_add_local_field_group' ) ) : acf_add_local_field_group(