Skip to content

Release 0.36.1 - #2446

Merged
mauteri merged 37 commits into
mainfrom
version-0.36.1
Oct 24, 2026
Merged

mauteri merged 37 commits into
mainfrom
version-0.36.1

Conversation

@mauteri

@mauteri mauteri commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

The 0.36.1 patch release. Fixes are born on develop and cherry-picked here (git cherry-pick -x), per the patch flow in docs/contributor/release-process.md.

Merge with a merge commit, never squash.

In this release

Twenty-six fixes, each cherry-picked from its develop squash commit with its changelog entry file. All but #2472, #2481, #2500, #2501, #2520 and #2521 applied cleanly, and apart from #2497 and #2521 (below), git range-diff shows each is byte-identical to the develop commit apart from the (cherry picked from …) line. #2472 conflicted because develop names the event edit capability Event::edit_capability() (#2417), while 0.36 still has Event::EDIT_CAPABILITY. It was resolved to the fix's own lines with the 0.36 name, plus 0.36's wording on a neighboring test docblock, and the range-diff shows only those two differences. #2481 conflicted because develop's Query::get_events_list() takes an args array, while 0.36 still takes positional parameters. On this branch has_password is an optional fifth parameter, the feed passes false positionally and the test calls it that way, and the REST check uses Event::EDIT_CAPABILITY where develop has Capability::EDIT_POST (both are edit_post). Those are the only differences from the develop commit. #2497 applied cleanly but called develop's args-array get_events_list(), which would throw on 0.36, so its one call was changed to the positional form #2481's feed call uses here ('upcoming', $count, array(), array(), false). The range-diff shows only that line. #2500 conflicted in Event\Meta, where it replaces an inline password check with its new Event::is_hidden_by_password(); that check used Event::EDIT_CAPABILITY here and Capability::EDIT_POST on develop. It was resolved to #2500's line, and the new helper uses self::EDIT_CAPABILITY where develop has self::edit_capability() (all three are edit_post). Those are the only differences from the develop commit. #2501 conflicted on Has_Capabilities, a trait 0.36 doesn't have: on develop, #2501 puts is_hidden_by_password() in that trait, which Venue and Event share. Here Event keeps its own from #2500, and Venue gets the same method (edit_post, as the trait's edit_capability() is on develop), tested in Venue\Test_Venue in place of the trait's test. Venue\Setup uses Event::EDIT_CAPABILITY where develop has Event::edit_capability(). Those are the only differences from the develop commit. #2520 conflicted only on a neighboring test in Test_Rest_Api that 0.36 still has, and both are kept. #2521 conflicted because 0.36 names get_events_list()'s query args $args rather than $query_args, and its test calls the positional get_events_list( 'upcoming', 2 ) where develop passes an args array; the range-diff shows only those four calls.

The branch also carries five non-fix commits, apart from the version bump below:

PR Fixes What it does On this branch From develop
#2444 #2443 Stops calling the private apply_block_hooks_to_content() when a new venue is seeded from the venue template. 8f681a007 67e3b2358
#2447 #2428 Keeps keyboard focus on screen after an RSVP change: Attend on a full event opens the waiting list dialog, and focus moves only once the new state is shown. 327322eb1 8d3094e89
#2463 #2462 Screen readers name the RSVP and Login dialogs after their visible title, such as "RSVP to this event" or "Login Required", and read the instructions below it. cba6ca7f0 e77cd577d
#2450 #2448 Two RSVP forms with the same layout on one event each submit against their own fields. Before, the second used the first form's fields, so it rejected submissions or dropped answers. e9611c0a5 b34462a37
#2461 #2449 The venue address search starts with no suggestion active, so ArrowDown then Enter picks the first suggestion. 143c9594b 38b681b99
#2467 #2466 Screen readers read the date on the event's start and end date buttons, such as "Date & time start October 21, 2026 6:00 pm". befea6e00 bd802fc69
#2465 Removes the RSVP block's Login dialog for logged-in viewers. Its class in the template did not match the one the removal checked, so it stayed in the page, hidden and unused. 59f02ec2b 76c50e6a4
#2475 Compares RSVP confirmation tokens with hash_equals() instead of ===. Hardening only, no behavior change. 91136847d b347ef567
#2473 Caches calendar feeds per viewer scope, so a feed with private events loaded by an Administrator is never served to other viewers. Unpublished and password-protected events' calendars go out with Cache-Control: private. 00ae9a6cb 569815632
#2479 #2477 Makes strings that stayed in English translatable: the Venue block placeholders, the required field marker, the Dropdown block title, the Modal Content width settings, the RSVP list date, the Credits list (now joined with core's wp_sprintf_l()), and the Venues column's screen reader text. ce87a733d 2c0ac5174
#2472 Sending an event email to All Members now also takes the event post type's edit_others_posts (Editors and Administrators). Anyone who can edit an event can still email its own attendees, and the email dialog hides All Members from users who can't use it. 73174e798 c9b1f7237
#2481 Leaves password-protected events out of calendar feeds, makes their single-event calendar links (iCal, Outlook, Google, Yahoo) require the password, and blanks their date and place in the REST API for viewers without the password, on every event post type. 2b270f265 aca935e41
#2474 The RSVP Response, RSVP Template and RSVP Count blocks follow the same rule as the REST attendee list, so a password-protected event's attendees and count stay hidden, for example in a Query Loop on another page, until the viewer enters the password. ff256014f 38daf1534
#2478 #2476 With "Display event date instead of publish date" on, the Post Date block keeps the event date's first digit and its <time> tag when the date format starts with a number, such as d/m/Y. 7ae83d764 190dd4866
#2489 Calendar endpoints step aside when the requested calendar slug isn't theirs, so URLs such as an event's /outlook/ with junk page and feed parameters, or an unknown gatherpress_calendar value, no longer cause a fatal error. bd86299f1 bcbf39f03
#2496 #2495 Opening the editor no longer rewrites an Event Query Loop when the event post type loads late. The loop keeps its order, upcoming or past setting and name, the editor no longer shows unsaved changes, and a name the author gave a loop now stays when its settings change. 6005f9df5 7f3430167
#2499 Event RSS feeds no longer add a password-protected event's date and venue to its excerpt and content, which core had already replaced with its protected-post text. 0dccf9e83 82d83471e
#2497 The public upcoming events ability (gatherpress/get-upcoming-events, over REST and MCP) leaves out password-protected events, so it no longer returns their start, end and timezone. dfbda4423 d003170a9
#2510 The event email dialog mentions "All Members" in its help text only when the All Members checkbox is offered. A follow-up to #2472, from Matt's review of this release. c24691584 74ec27120
#2509 #2505 The RSVP Template block declares state.posts in its own store, so its list no longer fails with a TypeError when its view script runs before the other RSVP blocks have loaded, as seen on an events archive in iOS Safari. 10ac3118a 11cc6e51e
#2498 The Event Date, Add to Calendar, Online Event and Venue blocks hide a password-protected event's date, calendar links, online status and venue until the viewer enters the password, including in a Query Loop on another page. dc0fb9e11 c98ea91e3
#2500 A password-protected event's venue stays hidden until the viewer enters the password or can edit the event: the event's REST venue field, the venue terms endpoint, its post classes, the Post Terms block, the venue feed link in its head, and venue-filtered event lists. 20ab4c325 756370c97
#2501 A password-protected venue's details and its link to events stay private, as the Venue block already did: its REST record, calendars, RSS feeds, and its events' location fields, REST records and feed links. Its name stays public. New venue terms no longer start with "Protected: ". A venue that stops being public clears the location its events copied and keeps the copies, and gives each event its own back once it is public again. 495a045ca d97febccf
#2519 Saving an event rechecks whether its location is public, past events included, so a past event that gets a password or is unpublished is no longer marked public. Its location is kept. Found while testing this release; GatherPress/gatherpress-alpha#112 covers past events already saved. ed9ca8bab e672421d6
#2520 A password-protected event's RSVP and RSVP Form blocks stay hidden until the viewer enters its password, including in a block template outside the event's content, and the RSVP form's REST route refuses a response for it without the password, as wp-comments-post.php already did. Found while testing this release with the blocks in a template. fbaaf573a e69210413
#2521 Events lists from get_events_list() (the events calendar feed, the upcoming events ability, get_upcoming_events() and get_past_events()) are ordered by event date again, not by publish date as they had been since 0.34.0, so a limit keeps the soonest events. Found through a flaky test on #2520. 83fa7ee9e 42ec2f286

.github/changelog/ on this branch holds the twenty-six matching entries: 2443-private-block-hooks-call, 2428-rsvp-focus-after-status-change, 2462-rsvp-dialog-names, 2448-rsvp-form-schema-id, 2449-address-suggestion-active-option, 2466-date-button-names, login-modal-logged-in, rsvp-token-compare, calendar-feed-cache-logged-in, 2477-untranslatable-strings, event-email-all-members, calendar-password-protected-events, rsvp-blocks-post-password, 2476-post-date-leading-digit, 2489-calendar-endpoint-unknown-slug, 2495-event-query-loop-on-open, feed-password-protected-events, abilities-upcoming-events-password, email-all-members-help-text, 2505-rsvp-template-state-posts, blocks-password-protected-event-details, protected-event-venue protected-venue-details, protected-event-geo-public, rsvp-password-protected-events and events-list-date-order, plus #2506's docs-settings-and-requirements.

Verification on this branch

Version bump

Still to come

🤖 Generated with Claude Code

…mplates (#2444)

Venue\Setup::maybe_apply_venue_template() ran the venue template pattern's
content through apply_block_hooks_to_content(), which core marks private.
WP_Block_Patterns_Registry::get_registered() already applies hooked blocks
to a pattern's content before returning it (WordPress 7.0 included), and
leaves ignoredHookedBlocks metadata that made the second pass a no-op, so
the content can be used as returned.

Adds a test that a block hooked into the venue template still lands in the
seeded content exactly once.

Fixes #2443.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 67e3b23)
@coderabbitai

coderabbitai Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

mattcowan and others added 5 commits October 17, 2026 10:58
* fix: keep RSVP focus on screen after an RSVP change

After an RSVP change, the success callback of updateRsvp() opened the next state's modal and closed the current one after a fixed 10 ms. On a full event, Attend returns waiting_list, but the callback always opened the attending modal, which stays hidden, so focus fell to the page body. On other events, the renderRsvpBlock watch sometimes showed the new state after the 10 ms, so focus again fell to the page body, now and then with the attending modal open.

Use the status in the server response to pick the next modal, so Attend on a full event opens the waiting list modal. Add whenStatusShown(), which waits one animation frame at a time, for up to about a second, until the new state's container is shown, and only then opens the next modal or closes the current one. A missing or never-shown container still ends in a full close (#1719).

Add Jest tests for the waiting list, Attend and Not Attending when the new state shows late, and a state that never shows. Add a changelog entry.

Fixes #2428

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: wait for the no_status fallback before closing the RSVP modal

When the RSVP block has no container for the status the server returns (partial block markup, #1719), whenStatusShown() got a null container and called back at once. closeModal() then ran before renderRsvpBlock hid the old state and showed its no_status fallback, so from the not attending state focus went to a trigger that was hidden a frame later. Wait for the same no_status container that renderRsvpBlock shows, and open a modal only for a real container of the new status.

Say in the whenStatusShown() docblock that the wait is 60 animation frames, about a second only at 60 Hz, and that animation frames pause in a background tab.

Add a Jest test for not attending to waiting list in a block that has no waiting_list container. Make the simulated watch fall back to no_status the same way renderRsvpBlock does, and make the not attending button request attending.

Co-Authored-By: Claude <noreply@anthropic.com>

* test: cover the RSVP modal close when no status container exists

Add a Jest test for a block that has neither the container of the returned status nor a no_status container. whenStatusShown() gets no container and gives up at once, so updateRsvp() must fully close the modal without opening another one.

Co-Authored-By: Claude <noreply@anthropic.com>

* test: assert where focus lands with the real modal actions

The #2428 tests swap openModal and closeModal for spies, so they could
pass while the real transition focused the wrong control. Run updateRsvp
against the real modal-manager actions, with a modal manager in each
status container, and assert document.activeElement after Attend on a full
event (waiting list modal), Attend with room (number of guests), and Not
Attending (the not attending state's Edit RSVP trigger).

jsdom has no layout, so these pin the focus target rather than reproduce
focus dropping to the page body. Against develop's view.js the waiting
list and Not Attending cases fail; the attending case passes there because
jsdom focuses the hidden input.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Mike Auteri <mauteri@gmail.com>
(cherry picked from commit 8d3094e)
* fix: name RSVP and Login dialogs after their visible title

Screen readers announced the RSVP block's dialogs as "RSVP Modal" and "Login Modal". These are the editor names from the block templates. The visible title ("RSVP to this event", "You're Attending", "Login Required") and the instructions below it were not read when the dialog opened.

For modals with an RSVP template class (gatherpress-modal--type-rsvp, gatherpress-modal--login, gatherpress-modal--type-login), Modal::apply_modal_attributes() now points aria-labelledby at the title, the first paragraph or heading, and aria-describedby at the next paragraph. A title that a site owner changed to a Heading block still names the dialog, and the instructions do not become its name. An element keeps an id it already has; otherwise it gets a unique one. The editor name stays as the aria-label fallback. Other modals keep the #2366 behavior.

The RSVP block renders its saved templates with do_blocks() on each request, so existing events change without an edit, and the templates do not change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: add changelog entry for #2462

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit e77cd57)
…2450)

* fix: tell apart RSVP forms with the same layout when finding a schema id

Rsvp_Form::blocks_match() identified the rendered form in the post
content by comparing innerHTML. A block's innerHTML holds only its wrapper
and one blank line per inner block, so two forms with the same wrapper and
number of fields matched each other, and the second rendered the first
one's schema id. Its submissions were then validated and saved against the
first form's fields: rejected for a required field it does not have, or
with its own answers dropped.

blocks_match() now also compares the inner blocks' names, attributes and
markup, recursively. The form's own attributes stay out of it, because they
can be filtered at render. Two truly identical forms still share the first
id, but their schemas are identical.

Fixes #2448.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test: cover RSVP forms that differ by inner block name, markup or depth

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: match RSVP forms by their fields so hooked blocks don't break it

A block added inside a form by Block Hooks is in the rendered form but
not in the saved one, so comparing every inner block failed to find the
form and every form fell back to form_0, whose schema rejected each
submission. Compare the form's own markup and the fields its inner
blocks hold instead. Forms with the same fields store the same schema,
so either one's id fits both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit b34462a)
* fix: start the address search with no suggestion active

The venue address search made the first suggestion active as soon as the list appeared. The first ArrowDown then moved to the second suggestion, so ArrowDown and Enter saved the second address, not the first. This differs from the ARIA combobox pattern, where no option is active until an arrow key is pressed.

Start activeIndex at -1 and reset it to -1 when the suggestions change. ArrowDown from -1 goes to the first suggestion and ArrowUp to the last. Enter with no active suggestion closes the list and keeps the typed address. fetchAddressSuggestions() now leaves out a row whose label repeats an earlier one, so each address shows once.

Add Jest tests for no active option before an arrow key, Enter keeping the typed text, ArrowUp from no active option, the reset on new suggestions, and duplicate labels. Update three tests that expected the first suggestion to be active from the start. Add a changelog entry.

Fixes #2449

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: fill five address suggestions and keep a closed list closed

The server asked Photon for 5 results when no country filter was set and kept up to 5, so a repeated label used up a place, and the client then showed fewer than 5 suggestions. Ask Photon for 10 candidates in every search (SEARCH_CANDIDATE_LIMIT), and skip a label that an earlier suggestion already has before the 5-row cap. Keep the client-side check for results cached before this change.

closeSuggestions() aborted only a request already in flight. A search still waiting for its 400 ms debounce ran after Enter or Escape and opened the list again. Cancel the debounced search too.

Add PHPUnit coverage for repeated labels and change the search URL test to expect limit=10. Add Jest tests that use the real debounce for Enter and Escape before the search runs, and give the pass-through debounce mock in the field tests a cancel method.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
(cherry picked from commit 38b681b)
Screen readers named the "Date & time start" and "Date & time end" buttons in the event settings only by their heading label. The heading's <label for> replaced the button text, so the date on the button was not read. NVDA said "DATE and TIME START, button, focused, collapsed".

The label and the date text in the button now each have an id, and the button's aria-labelledby points at both. The name is the label and the date, for example "Date & time start October 21, 2026 6:00 pm", or "Date start October 21, 2026" for an all-day event. aria-labelledby points at the date span, not at the button, because a referenced button still takes its name from its <label> first. htmlFor stays, so a click on the heading still opens the picker, and the button ids stay.

Add Jest tests for both buttons: the name with and without All day, and the label click. Add the changelog entry.

Fixes #2466

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit bd802fc)
@mauteri mauteri added this to the 0.36.1 milestone Oct 21, 2026
mauteri and others added 9 commits October 20, 2026 21:54
* fix: remove the Login modal for logged-in users

The RSVP block template gives the Login modal gatherpress-modal--login,
but filter_login_modal() only looked for gatherpress-modal--type-login,
which the class was renamed to everywhere else in c7c4ca3. The modal
stayed in the page for logged-in users, hidden and unused.

is_login_modal() matches both classes, since saved events keep the
template's, and filter_login_modal() and is_rsvp_block_modal() share it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* doc_update: say which code uses each Login modal class

Only class-modal.php uses gatherpress-modal--type-login. The template,
the e2e helper and saved events use gatherpress-modal--login, so the
docblock no longer reads as if --login were the old name. The changelog
says logged-in viewers, since member is a site role.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 76c50e6)
* Skip the shared calendar feed cache for logged-in viewers

* fix: call is_feed() inside the ICS renderer

The renderer runs in the same request, right away for logged-in viewers
or inside remember(), so copying is_feed() into a variable first added
nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: cache calendar feeds per viewer scope instead of skipping the cache

Skipping the cache for every logged-in request meant any account,
Subscribers included, could make the site render every upcoming event on
each feed request. The events query only differs by which private events
a viewer may read, so the cache key now carries that scope instead:
public for viewers who see no private events, private for viewers who
read all of them, and a per-user scope only for a viewer whose own
private events set their feed apart. Every request is cached again, and
only the public scope is sent with Cache-Control: public.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: move the viewer scope into Cache to keep Setup under PHPMD's limit

The scope method took Calendar\Setup to a class complexity of 152, over
PHPMD's threshold of 150. It is about cache scope, so it lives on Cache
as get_viewer_scope() now, with its tests in Test_Cache. No behavior
change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: return early from get_viewer_scope()

Bail out for logged-out viewers and for viewers who read every private
event, instead of wrapping the rest of the method in the logged-in
check. Three returns, same behavior.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: assert the Cache-Control visibility in a unit test

- Move the public/private choice into Cache::get_cacheability().
- Call it from Setup::send_ics_headers(); the header is unchanged.
- Add test_get_cacheability() for anonymous, Subscriber,
  Administrator and Author viewers.

Addresses PR feedback.

Refs #2473

* fix: give an unpublished queried event a per-viewer calendar scope

* fix: send a password-protected event's calendar as private

A visitor who entered an event's password can be in the public scope,
so the event's .ics went out with Cache-Control: public. A shared cache
could then hand it to people without the password. get_cacheability()
returns private for any queried post with a password.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: decide an unpublished event's calendar privacy in get_cacheability()

An unpublished or password-protected queried post only changes who
outside WordPress may store the response, not what the body holds:
every viewer who can reach it gets the same body, because WordPress
answers anyone else with a 404 before the cache is read. Both cases now
live in get_cacheability(), and get_viewer_scope() is back to describing
which events a viewer's feed lists, so those viewers share one cache
entry instead of one each.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Mike Auteri <mauteri@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 5698156)
* fix: make strings shown in the editor and admin translatable

* chore: add changelog entry for #2477

* fix: join the Credits list with core's wp_sprintf_l()

Core already ships translated list separators for this, in every locale
WordPress supports, so the Credits list uses wp_sprintf_l() instead of
three new GatherPress strings that start or end with spaces. The closing
period becomes a translatable string too, for languages with a different
full stop. The link partial no longer takes a separator.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Mike Auteri <mauteri@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 2c0ac51)
…ts (#2472)

* Limit the All Members email option to users who can edit others' events

* test: cover the All Members option in the email modal

(cherry picked from commit c9b1f72)
…he REST API (#2481)

* fix: keep password-protected events out of calendar feeds and links

A calendar feed is shared by every viewer, so it now leaves out
password-protected events instead of listing their date, time and
location. The single-event calendar links (iCal, Outlook, Google,
Yahoo) only answer a viewer who has entered the event's password; the
check runs before the cache is read, so the cached body is only served
to viewers allowed to see it.

get_events_list() takes an optional has_password argument for this.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* doc_update: say calendar feeds leave out password-protected events

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: blank a password-protected event's date and place in REST responses

The event's date, time and timezone meta and the venue geo fields copied
onto it are registered with show_in_rest, and core only hides a
protected post's content and excerpt, so the REST API handed them to
anyone. prepare_event_data() now blanks them unless the viewer can edit
the event or has its password, as a cookie or as the REST password
argument, the way core gates the content. The rest_prepare filter now
receives the request for that.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: hide a protected event's date and place on every event post type

The REST blanking ran on rest_prepare_gatherpress_event, so a companion
post type with gatherpress-event-date support, which gets the same date
and geo meta, still handed a protected post's date and place to anyone.
Event\Meta now hooks hide_password_protected_meta() on rest_prepare_ for
every event-date post type, next to the read-only meta filter it already
adds there. Rest_Api::prepare_event_data() is back to handling the
online link only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: blank a protected event's place after the geo refresh

Geo_Sync::maybe_refresh_on_rest() runs on the same rest_prepare hook and
writes refreshed geo_* values back into the response when an event's stored
location is out of date. Both filters sat at priority 10 and the blanking
filter was added first, so the first read after a venue change showed the
address and coordinates. Run hide_password_protected_meta() at priority 20.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit aca935e)
#2474)

* Respect post passwords in the RSVP Response, Template and Count blocks

* test: cover the RSVP blocks once the viewer has the event password

* test: assert RSVP data in the password-protected block tests

The with-password tests checked markup each block emits even with no
responses. Save an attending RSVP and assert the count, the response
counts and the attendee's roster entry instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Mike Auteri <mauteri@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 38daf15)
* fix: keep the leading digit of the event date in the Post Date block

* chore: add changelog entry for #2476

(cherry picked from commit 190dd48)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
(cherry picked from commit 7e0faec)
@mauteri
mauteri marked this pull request as ready for review October 22, 2026 01:36
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs.

Unlinked Accounts

The following contributors have not linked their GitHub and WordPress.org accounts: @hifarrer.

Contributors, please read how to link your accounts to ensure your work is properly credited in WordPress releases.

Core Committers: Use this line as a base for the props when committing in SVN:

Props mauteri, matthewneilcowan, faisalahammad, camaleaun, raicem.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.


Props Bot commands

You can trigger Props Bot actions by commenting on this PR:

  • @propsbot add <username> to give props to a GitHub user. Requires write access.
  • @propsbot remove <username> to leave a user out of the props. Requires write access.
  • @propsbot refresh to refresh this list. Adding the props-bot label works too.

@mattcowan
mattcowan self-requested a review October 22, 2026 19:39
mattcowan
mattcowan previously approved these changes Oct 22, 2026

@mattcowan mattcowan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One note to make here:

#2472 hides the All Members checkbox from users who can't use it, but the help text above it still says "All Members" includes site users only (src/modals/email-communication/index.js:148). Do you want a develop fix that shows that sentence only with the checkbox in this release, or can it wait for 0.37?

* Skip calendar endpoints when the requested slug is not theirs

Every calendar endpoint shares the gatherpress_calendar query var and
hooks template_redirect. Endpoint::template_redirect() looked up the
type matching that slug and called activate() on the result without
checking it, so an endpoint whose validation passed but which has no
type for the slug crashed with "Call to a member function activate()
on false".

Two requests reach that state:

- /event/my-event/outlook/?page=<junk>&feed=<junk>: the page value
  404s the singular query, set_404() keeps is_feed but clears
  is_singular, and the sitewide feed endpoint (ical only) validates
  while the slug is still "outlook". Vulnerability scanners send this
  shape.
- /event/my-event/outlook/?gatherpress_calendar=nope: the query string
  value overrides the rewrite value.

Bail when no type matches, so WordPress handles the request as it
would without the endpoint.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Prefix the changelog entry with its PR number

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit bcbf39f)
mauteri and others added 4 commits October 23, 2026 20:08
…2507)

After an RSVP change, updateRsvp opens the new state's modal, which
focuses its first control on a 10 ms timer, and closes the starting modal
on its own 10 ms timer scheduled just after. The waiting list and
attending tests waited only for focus, then checked at once that the
starting modal was hidden, so a check between the two timers failed
(seen on CI for #2496). Check both inside waitFor().

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 02ceb80)
* fix: keep an Event Query Loop unchanged when the editor opens

The naming and query cleanup effects read usePostTypeSupports(), which is false until getPostType() resolves. On the first render they treated an event loop as a plain loop: the cleanup removed gatherpress_event_query and include_unfinished and set orderBy to date desc, and the naming effect replaced the name with "" and then "Upcoming Events". Both effects now wait for the new useIsPostTypeLoaded() hook.

The naming effect also keeps the other metadata keys, and it replaces only an empty name or a name it generates: for the current post type, for the post type before a switch, or for the fallback "Events" label. A name that the author gave the loop stays.

Add a changelog entry, and note in AGENTS.md that an effect that acts on a missing support must wait for the post type to load.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: keep the event query panel's naming from dirtying the post

Naming a loop that has no name now uses __unstableMarkNextChangeAsNotPersistent, as core's Query block does for its defaults, so opening a loop saved without a name no longer shows unsaved changes. The name is saved with the next save. Renames after a mode or post type switch stay normal edits.

When the panel clears a name, it now removes the name key, as core's rename modal does, and removes metadata that has no keys left, so the block no longer saves "name":"". A comment also says that a name generated in another locale counts as an author's name.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: count a post type as loaded only once its record is in the store

useIsPostTypeLoaded() also returned true when the getPostType() request
finished without a record. A failed request does that, for example the 403
core sends for /wp/v2/types/<type>?context=edit to a user who can edit the
page but not posts of that type. Its supports are unknown then, but the
cleanup read them as missing and stripped the loop on every open: the
#2495 symptom, every time instead of on a race.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Mike Auteri <mauteri@gmail.com>
(cherry picked from commit 7f34301)
Feed::get_default_event_excerpt() and get_default_event_content() added
"Date:" and the venue to every event in an RSS feed, including a
password-protected one, whose excerpt and content core already replaces.
Leave those untouched when the post password is required.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 82d8347)
…2497)

* fix: leave password-protected events out of the upcoming events ability

The gatherpress/get-upcoming-events ability is public (REST and MCP) and
returned a protected event's start, end and timezone. Query with
has_password false, as the calendar feeds do since #2481.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* doc_update: Say the upcoming events ability leaves out protected events

The permission comment still said the ability adds no gate of its own,
but the callback now drops password-protected events itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit d003170)
#2506's docs updates ship in 0.36.1, so the credit goes on the patch
branch rather than develop.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs: update settings names, RSVP mode values and requirements

Bring the docs back in line with the code after the settings renames:

- RSVP mode values are enabled, per_event_enabled and per_event_disabled
  (were all_on, per_event_on, per_event_off), with the labels shown on
  the settings screen.
- "Maximum Attendance Limit" is now "Capacity".
- Venue map defaults: drop "Default Width" (removed), add "Default Map
  Type" (Google Maps only).
- Developer settings tables: enable_rsvp_cleanup defaults to 'disabled',
  the RSVP tab class is Settings\Rsvp, add event_archive, and list
  venues_url under the Venues tab where it lives.

Also fix two other outdated statements: the installation page now says
WordPress 7.0 (the plugin's minimum), and the FAQ no longer calls iCal
"planned", since the Add to Calendar block offers iCal and Outlook.

* doc_update: add the changelog entry for the settings docs update

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* doc_update: rename the RSVP Mode values and Capacity in two more docs

The features list still named the per-event modes "default on" and
"default off", and the event settings list still called Capacity
"Maximum attendance limit", which is no longer the editor's label.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Mike Auteri <mauteri@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit e473fa2)
@mauteri

mauteri commented Oct 24, 2026

Copy link
Copy Markdown
Contributor Author

@mattcowan Good catch on the All Members help text. It's going into this release: #2510 shows that sentence only when the checkbox is, and I'll cherry-pick it here once it merges.

mauteri and others added 7 commits October 23, 2026 22:24
…2510)

#2472 hides the All Members checkbox from users who can't send to all
members, but the help text above the checkboxes still explained the
option to everyone. Show that sentence only with the checkbox, and keep
both versions whole strings for translators.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 74ec271)
RSVP Count, Form and Response declare `state: { posts: {} }` in their
store() calls, but RSVP Template read `state.posts[ postId ]` without
declaring it. When renderBlocks ran before another RSVP block had
registered, `state.posts` was undefined and the list failed to render
with a TypeError, seen on an events archive in iOS Safari.

Fixes #2505

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 11cc6e5)
…#2498)

* fix: keep a protected event's date, calendar links and venue out of blocks

The Event Date and Add to Calendar blocks, and the Venue block's lookup of
an event's venue, checked only Event::is_viewable(), which ignores the post
password. In a Query Loop on another page they showed a protected event's
date, calendar links and venue to anyone. Add the password check the
Online Event block already makes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: keep a protected online event's Online Event block behind its password

Online_Event::render_block() checked the password only for a postId
override. In a Query Loop the block reads the event from the loop with no
override, so a password-protected online event still said it was online
while its date, calendar links and venue were hidden. Return '' there too
until the viewer has the password.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit c98ea91)
* fix: keep a password-protected event's venue hidden

The venue taxonomy is public, so core listed a protected event's venue term
in REST, in /wp/v2/_gatherpress_venue?post=<id>, in its post classes and
REST class_list, and in the venue feed link in its head. Lists filtered by
venue also showed the protected event under its venue.

- Event::is_hidden_by_password() holds the rule: the viewer needs the
  password and can't edit the event; a REST request's right `password`
  argument counts. Event\Meta's date and place meta now use it.
- Venue\Setup blanks the venue field on event REST responses, returns no
  term from the venue terms endpoint for such a post, drops the venue
  classes, and leaves protected events out of venue-filtered queries for
  anyone who can't edit others' events (not in wp-admin).
- Calendar\Setup leaves the venue feed link out of a protected event's head.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test: register the venue REST hooks in the REST test

rest_api_init only fires for the first REST server a test run creates, and
hooks added during an earlier test are removed after it, so a run where
another test creates the server first would miss the filters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: keep a protected event's venue out of the Post Terms block

Core adds a Post Terms variation for each public taxonomy, and the block
prints terms with get_the_term_list(), which none of the venue filters
reach, so a Query Loop or template still named a protected event's venue
and linked to it. Empty the block when its term is the event's venue
taxonomy and the event's password hides it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: run the venue list filter at priority 11

It only has to run after Event\Query::prepare_event_query_before_execution(),
which adds the venue clause on the default priority 10, so stay just after
the default rather than at an arbitrary 20.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: honor the password in the venue terms endpoint and keep an empty taxonomy list out of get_terms()

The venue terms endpoint now passes the request to the password check,
so the right password lists a protected event's venue, as the event
endpoint already does. When dropping the venue taxonomy leaves no
taxonomy, the head's term links return early, since get_terms() with an
empty list matches every term on the event, the venue's included. Cover
a set rest_base, a response without the venue field and a terms request
without a post.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 756370c)
…ate (#2501)

* fix: keep a password-protected event's venue hidden

The venue taxonomy is public, so core listed a protected event's venue term
in REST, in /wp/v2/_gatherpress_venue?post=<id>, in its post classes and
REST class_list, and in the venue feed link in its head. Lists filtered by
venue also showed the protected event under its venue.

- Event::is_hidden_by_password() holds the rule: the viewer needs the
  password and can't edit the event; a REST request's right `password`
  argument counts. Event\Meta's date and place meta now use it.
- Venue\Setup blanks the venue field on event REST responses, returns no
  term from the venue terms endpoint for such a post, drops the venue
  classes, and leaves protected events out of venue-filtered queries for
  anyone who can't edit others' events (not in wp-admin).
- Calendar\Setup leaves the venue feed link out of a protected event's head.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test: register the venue REST hooks in the REST test

rest_api_init only fires for the first REST server a test run creates, and
hooks added during an earlier test are removed after it, so a run where
another test creates the server first would miss the filters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: keep a password-protected venue's name and details private

Only the Venue block checked a venue's password. The venue's REST record
still exposed its address, contact, structured address, geo and static map
meta; Geo_Sync copied its address onto its events; calendars and RSS feeds
named it with its address; its events' REST records, post classes and head
feed links named it; and its taxonomy term was named "Protected: <title>".

- Has_Capabilities::is_hidden_by_password() replaces Event's copy, so Event
  and Venue share the rule.
- Venue\Meta blanks the details on rest_prepare_<venue type>.
- Geo_Sync treats a password-protected post as not public.
- Event::get_public_venue_information() blanks such a venue for calendars
  and RSS unless the viewer can edit it; emails keep get_venue_information().
- Venue\Setup::is_event_venue_hidden() hides the venue for either password,
  for the REST field, the terms endpoint, the post classes and the head link.
- Shadow_Source names terms with the_title on post_title, without the
  "Protected: " or "Private: " prefix get_the_title() adds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: address review on protected venue details

- Whoever can edit an event keeps its venue in REST. An Author editing
  their own event at another user's protected venue got an empty venue
  field, and the online-event toggle then saved the event without it.
- Calendars and RSS blank a protected venue for everyone. The edit
  exception let a venue's Author fill the public calendar cache, since
  Calendar\Cache gives an Author the public scope.
- The event REST filter blanks the copied geo_* fields whenever the
  event's venue is hidden, not only when the event is protected, so a
  past event's stored copy stays out of REST.
- Saving a venue that isn't public clears the location its events copied,
  past events included, writing what maybe_refresh() would.
- The changelog says the venue's details and its link to events stay
  private; its name stays public, as for any protected post.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: hide a protected venue's copied location from the event's editor

hide_password_protected_meta() reused is_event_venue_hidden(), whose
event-editor exception exists so the editor doesn't drop the venue term on
save. That exception also let an event's Author see geo_* copied from a
protected venue they can't see. The geo_* fields are read-only, so they
now use is_venue_hidden_by_password(), which checks only the venue's own
password. clear_event_copies() also primes the events' meta in one query.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: keep a protected event's venue out of the Post Terms block

Core adds a Post Terms variation for each public taxonomy, and the block
prints terms with get_the_term_list(), which none of the venue filters
reach, so a Query Loop or template still named a protected event's venue
and linked to it. Empty the block when its term is the event's venue
taxonomy and the event's password hides it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: run the venue list filter at priority 11

It only has to run after Event\Query::prepare_event_query_before_execution(),
which adds the venue clause on the default priority 10, so stay just after
the default rather than at an arbitrary 20.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: honor the password in the venue terms endpoint and keep an empty taxonomy list out of get_terms()

The venue terms endpoint now passes the request to the password check,
so the right password lists a protected event's venue, as the event
endpoint already does. When dropping the venue taxonomy leaves no
taxonomy, the head's term links return early, since get_terms() with an
empty list matches every term on the event, the venue's included. Cover
a set rest_base, a response without the venue field and a terms request
without a post.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: give events back the location a venue cleared once it is public again

A venue set to draft, private or a password clears the location its
events copied, past events included. When it became public again,
upcoming events got the location back on their next view, but past
events stayed blank for good, since maybe_refresh() skips them.

clear_event_copies() now keeps the locations it clears on the venue
(_gatherpress_geo_cleared_copies), keeping the first copy if the venue
is saved again while hidden. A public venue save writes them back with
restore_event_copies(), to events still at the venue, with geo_public
from each event's own status. The exact copy comes back rather than the
venue's current address, so a past event keeps where it happened, as

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit d97febc)
The bump resolves every credited username on WordPress.org, and
hifarrer's GitHub username has no WordPress.org profile (404), so the
bump would fail. They haven't shared their WordPress.org username on
#2506, so they can be credited in a later release once they do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ran npm run version:bump -- --version=0.36.1 with credits/0.36.1.json
copied from 0.36.0.json, then refreshed the lockfile. It folds
camaleaun in from unreleased.json and resolves the fixes' @SInCE TBD
tags to 0.36.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mauteri and others added 2 commits October 24, 2026 12:49
Only viewing an event refreshed its geo_* meta, and maybe_refresh()
skips events that already happened, so a past event that was
password-protected or unpublished kept geo_public 1 with the location
it copied. REST already blanks that location for a protected event, but
anything reading the meta directly and following geo_public treated it
as public.

Geo_Sync::on_event_saved() runs on wp_after_insert_post and writes only
geo_public, from the same rule maybe_refresh() uses, now shared as
is_event_public(): the event, and its venue if it has one, must be
published without a password. A past event keeps its location.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit e672421)
Picked after the 0.36.1 bump, so its six tags were still TBD. Reran
npm run version:bump -- --version=0.36.1, which changed only those.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mauteri and others added 4 commits October 24, 2026 13:46
…2520)

The RSVP and RSVP Form blocks checked only Event::is_viewable(), which
ignores the post password. In the event's content the password form
hides them, but in a block template they render outside it, so a
protected event showed its RSVP button and form. Add the
post_password_required() check the Event Date and Add to Calendar
blocks make.

The RSVP form's REST route also accepted a response for a protected
event without its password. Without JavaScript the form posts to
wp-comments-post.php, which refuses a password-protected post, but
process_rsvp() inserts the comment directly and skips that check. The
route now refuses it with a 403 until the password is entered. The
account RSVP route already requires it through Event::can_read_rsvps().

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit e692104)
Picked after the 0.36.1 bump, so its three test tags were still TBD.
Reran npm run version:bump -- --version=0.36.1, which changed only
those.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ec186e5 ("Cleanup switch statement", 0.34.0) moved adjust_event_sql()'s
default arm from ordering by datetime_start_gmt to leaving the order
alone, so custom column sorts keep their own clause. get_events_list()
never set an orderby, so since then it fell to that default and listed
events in WordPress's publish-date order. With a limit it kept the
events published first rather than the soonest. That affects the events
calendar feed, the upcoming events ability, and get_upcoming_events()
and get_past_events().

get_events_list() now asks for the datetime order explicitly. This also
makes Test_Abilities::test_get_upcoming_events_orders_chronologically
deterministic: its two events are published in the same second, so it
passed or failed on how the database broke the tie.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 42ec2f2)
Picked after the 0.36.1 bump, so its two test tags were still TBD.
Reran npm run version:bump -- --version=0.36.1, which changed only
those.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mauteri and others added 2 commits October 24, 2026 14:45
…est (#2524)

test_handle_rsvp_form_submission_password_protected_event (#2520)
checked that a refused submission saved no RSVP with get_comments(),
but comment queries leave RSVPs out by default
(gatherpress_rsvp_comment_query_exclusion), so the count was 0 whether
or not one was saved. The test still caught the bug through its 403
check, but that assertion proved nothing.

count_rsvp_comments() turns the exclusion off for its own query, and
the test now also expects a count of 1 after the accepted submission,
which shows the count can see an unapproved RSVP.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 51890f0)
Picked after the 0.36.1 bump, so its test helper's tag was still TBD.
Reran npm run version:bump -- --version=0.36.1, which changed only
that.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Preview changes with Playground

Customize PR Playground

To customize the Playground preview for this specific PR, create a file at:

.github/playground/PR-2446-blueprint-override.json

The override is merged into the generated blueprint and can be used to:

  • Enable Playground features
  • Install additional plugins
  • Change site options
  • Run steps before or after the GatherPress' default steps

Example:

{
	"$schema": "https://gatherpress.org/playground-preview/pr-override-schema.json",
	"landingPage": "/wp-admin/edit.php?post_type=gatherpress_venue",
	"siteOptions": {
		"show_on_front": "page"
	},
	"features": {
		"networking": true
	},
	"prependSteps": [
		{
			"step": "installPlugin",
			"pluginData": {
				"resource": "wordpress.org/plugins",
				"slug": "simple-location"
			},
			"options": {
				"activate": true
			}
		}
	],
	"appendSteps": [
		{
			"step": "runPHP",
			"code": ""
		}
	]
}

Go to Playground PR preview customization for more details.

You can preview the recent changes for PR#2446 with the following PHP versions:

PHP Version 8.4

PHP Version 8.2

PHP Version 8.1

Download .zip with build changes

Made with 💙 from GatherPress & a little bit of WordPress Playground. Changes will not persist between sessions.

@mauteri
mauteri merged commit 4dd773d into main Oct 24, 2026
27 checks passed
@mauteri
mauteri deleted the version-0.36.1 branch October 24, 2026 19:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants