From 78b4b6ee1a2f8fbe6d7e899e603d00f74d479771 Mon Sep 17 00:00:00 2001
From: navin10sharma <3096611+navin10sharma@users.noreply.github.com>
Date: Fri, 25 Sep 2026 13:30:17 +0530
Subject: [PATCH] Docs: specific README intro; public release guide without
local paths or internal notes
---
README.md | 12 +-
RELEASE.md | 485 +++++++++++++----------------------------------------
2 files changed, 126 insertions(+), 371 deletions(-)
diff --git a/README.md b/README.md
index a2807d4..1813dc6 100644
--- a/README.md
+++ b/README.md
@@ -6,12 +6,12 @@
[](https://wordpress.org/plugins/seatlayer-seating-charts/)
[](LICENSE)
-SeatLayer is interactive seating chart software built for stadium scale. Platforms embed the white-label seat picker with their own checkout; organizers sell seated events on their own website with their own payment gateway.
-
-The official SeatLayer plugin adds interactive seating charts and seat maps to
-WordPress for event ticket sales with reserved seats. Buyers choose exact seats
-or find a group with Best Available, explore 3D on supported devices, and check
-out through the payment gateway the organizer connects to SeatLayer.
+The official WordPress seating chart plugin for SeatLayer. It adds interactive
+seating charts and seat maps to WordPress for event ticket sales with reserved
+seats. Buyers choose exact seats or find a group with Best Available, explore 3D
+on supported devices, and check out through the payment gateway the organizer
+connects to SeatLayer. SeatLayer is seating chart and reserved-seat ticketing
+software built for venues up to stadium scale.
Create theatre, auditorium, concert and dinner-show layouts in SeatLayer, then
publish them on WordPress with a Gutenberg block or shortcode.
diff --git a/RELEASE.md b/RELEASE.md
index b69d0a0..2388a80 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -1,434 +1,189 @@
# Releasing
Two destinations: **GitHub** is the source of truth and **wordpress.org** is where
-users install the plugin. The normal release path is automated by
-`.github/workflows/release-wordpress.yml`; the detailed manual steps below are
-the recovery procedure.
-
-> **Status, 2026-08-12.** `0.2.0` is published at
-> https://wordpress.org/plugins/seatlayer-seating-charts/. GitHub release
-> automation is configured for subsequent versions.
->
-> Two questions below are settled and must not be re-opened. **The slug is
-> `seatlayer-seating-charts`** — wp.org assigned it, it is permanent, and the
-> "short slug `seatlayer`" reversal block before 0.1 is dead. **The contributor is
-> `navincse`**, which resolves; `seatlayer` never existed as a wordpress.org
-> account, so 0.1 is history rather than work. Every other URL the plugin declares
-> was re-checked on 2026-08-12 and resolves.
-
-Read Part 0 first; everything after it is meant to be run start to finish without
-stopping to decide anything.
-
-**The whole sweep, in order:**
-
-| | |
-|---|---|
-| **0** | Two account facts to confirm, and one optional asset call. Nothing to code. |
-| **1** | Verify locally: syntax → Plugin Check → click through it by hand. |
-| **2** | GitHub: verify the public repository, push, and tag the release. |
-| **3** | wp.org: build the zip → submit → *(wait for approval)* → SVN trunk + tag → listing assets. |
+users install the plugin (https://wordpress.org/plugins/seatlayer-seating-charts/).
+The normal release path is automated by `.github/workflows/release-wordpress.yml`.
+The manual SVN steps further down are the recovery procedure.
-## Normal automated release
-
-1. Update the version in `seatlayer.php`, `SEATLAYER_VERSION`, and the
- `Stable tag` in `readme.txt` to the same semantic version.
-2. Merge the verified change to `main`.
-3. Create and publish a GitHub Release whose tag is that version, preferably
- `v0.3.0` style.
-4. GitHub Actions verifies the tag and focused tests, deploys it to the permanent
- WordPress.org SVN repository, and attaches the installable ZIP to the GitHub
- Release.
-
-The workflow intentionally rejects prereleases and mismatched versions. It needs
-the repository secrets `SVN_USERNAME` and `SVN_PASSWORD`. WordPress.org still
-uses SVN as its publishing backend; GitHub Actions performs that SVN operation
-for maintainers.
-
-The manual process below remains available if GitHub Actions or WordPress.org is
-unavailable.
-
----
-
-## Part 0 — confirm these BEFORE you submit anything
-
-Two account facts and one optional call, all cheap now and awkward later.
-
-The slug/text-domain question that used to head this list is **settled and
-applied in code** — kept here only so the decision is reversible, not because
-anything is pending.
-
-### 0.0 The slug and text domain — SETTLED, no action needed
-
-wordpress.org derives the plugin slug from the **Plugin Name** header, and the
-slug it assigns is permanent. The text domain has to equal that slug or the
-language packs built on translate.wordpress.org never load, and Plugin Check
-reports the mismatch as an error.
-
-These used to disagree. They now agree:
-
-| | value |
-|---|---|
-| Plugin Name | `SeatLayer Seating Charts` |
-| Expected wp.org slug | `seatlayer-seating-charts` |
-| Text Domain | `seatlayer-seating-charts` |
-
-The **name** was kept and the **domain** was lengthened to match it, rather than
-the other way round: the name is already public-facing in `readme.txt` and on
-seatlayer.io, and a text domain is invisible to everyone except the translation
-tooling. Churning the branding to save nine characters in a URL is the wrong
-trade.
-
-So: **do nothing here.** Use `seatlayer-seating-charts` as the slug everywhere
-below — it is already the `--prefix` in Part 3.1 and the SVN path in Part 3.3.
-
-
-Only if you would rather have the short slug seatlayer — the full reversal
-
-Worth doing only if `seatlayer` is actually available (check that
-https://wordpress.org/plugins/seatlayer/ returns 404) and only **before** the
-first submission — after wp.org assigns a slug it is permanent.
-
-This renames the plugin so the name-derived slug becomes `seatlayer`, and puts
-the text domain back to `seatlayer`.
-
-```sh
-cd /Users/paiteq/projects/seatlayer-sdks/wordpress
-
-# 1. The public name, in both places it appears.
-sed -i '' 's/^ \* Plugin Name: SeatLayer Seating Charts$/ * Plugin Name: SeatLayer/' seatlayer.php
-sed -i '' 's/^=== SeatLayer Seating Charts ===$/=== SeatLayer ===/' readme.txt
-
-# 2. The text domain: 62 call sites + the header.
-grep -rl "'seatlayer-seating-charts'" seatlayer.php includes assets/js \
- | xargs sed -i '' "s/'seatlayer-seating-charts'/'seatlayer'/g"
-sed -i '' 's/^ \* Text Domain: seatlayer-seating-charts$/ * Text Domain: seatlayer/' seatlayer.php
-
-# 3. The slug in this file's own commands (Parts 1.2, 3.1, 3.3).
-sed -i '' 's/seatlayer-seating-charts/seatlayer/g' RELEASE.md
-```
-
-Then verify — expect **62** hits, and confirm the two non-gettext domain
-registrations came along:
-
-```sh
-grep -rc "'seatlayer'" seatlayer.php includes assets/js
-grep -n "load_plugin_textdomain" seatlayer.php
-grep -n "wp_set_script_translations" includes/class-seatlayer-block.php
-```
-
-**One thing the blanket `sed` in step 2 is safe about, and you must keep safe if
-you hand-edit instead:** `includes/class-seatlayer-settings.php` line ~126 holds
-a bare `'seatlayer'` that is **not** a text domain — it is the `add_options_page()`
-**menu slug**, which is what puts the settings screen at
-`options-general.php?page=seatlayer`. Changing it would move the settings page
-and break any bookmark or documentation link to it. The step-2 command only
-matches `'seatlayer-seating-charts'`, so it cannot touch that line; a reversed
-search-and-replace (`'seatlayer'` → something else) would.
+Run every command below from the root of this repository. The examples use a
+shell variable for the version being released:
```sh
-# The menu slug must still read 'seatlayer' after any of this.
-sed -n '122,128p' includes/class-seatlayer-settings.php
+VERSION=0.3.0
```
-Re-lint afterwards (Part 1.1), then re-run Plugin Check (1.2).
-
-
-
-### 0.1 `Contributors: seatlayer` must be a real wordpress.org account
-
-Not a GitHub account — a wordpress.org one. Confirm
-https://profiles.wordpress.org/seatlayer/ resolves; if it does not, register it
-(or list the account that will actually own the plugin) before submitting. A
-non-existent contributor is a stall in the review queue.
-
-### 0.2 `Tested up to:` must name the current WordPress release
-
-`readme.txt` says `6.8`. Check the current version at
-https://wordpress.org/download/ and set it to that. A stale value shows users a
-"may not be compatible" warning on the plugin page.
-
-### 0.3 Screenshots — the readme no longer promises any. Optional, recommended.
-
-`readme.txt` used to carry a `== Screenshots ==` section listing three images
-that have never existed. **That section has been removed**, deliberately.
-
-The reasoning, so it can be overruled knowingly: screenshot files do not live in
-this repository and are not in the plugin zip — wp.org reads them from the SVN
-`assets/` directory, which you only get **after** approval (Part 3.4, which comes
-after 3.3). A readme that names three screenshots renders three broken images on
-the public plugin page for as long as the files are missing, and the natural
-order of the steps below guarantees a window where they are. Between a listing
-with no screenshots (unremarkable — plenty of good plugins have none) and a
-listing with three broken images (looks abandoned), the empty one is the honest
-default, and it is the one that stays correct if this step is never done.
-
-They are still worth adding, and adding them is four lines. To do it:
-
-**1. Capture them.** Needs a running WordPress with the plugin active and a real
-event — the same throwaway install from 1.2/1.3 is fine. Requirements:
-
-| | |
-|---|---|
-| Location | SVN `assets/` (sibling of `trunk/`, **not** shipped to users) |
-| Filenames | `screenshot-1.png`, `screenshot-2.png`, … — lowercase, numbered from 1, no gaps |
-| Formats | PNG, JPG, or GIF. PNG for UI. |
-| Size | No hard limit is enforced. wp.org displays them about 772px wide, so shoot **1544px wide or more** (2× for high-DPI) and keep every shot the same aspect ratio — mismatched ratios make the gallery jump. |
-
-Shoot the frontend chart on a desktop viewport with real seat colours visible —
-that one is the reason someone installs this — and crop out browser chrome and
-any test data that reads as placeholder.
-
-**2. Put the captions back** in `readme.txt`, immediately above `== Changelog ==`.
-The list is positional: item *N* captions `screenshot-N.png`, so the order must
-match the filenames exactly and a gap silently shifts every caption after it.
-
-```
-== Screenshots ==
+## Normal automated release
-1. A seating chart on a WordPress page, with live availability.
-2. Choosing the event in the block editor.
-3. The settings screen, including the optional in-page checkout.
-```
+1. Bump the version in **three** places, which must agree or wordpress.org serves
+ the wrong code:
+ - the `Version:` header in `seatlayer.php`
+ - `SEATLAYER_VERSION` in `seatlayer.php`
+ - `Stable tag:` in `readme.txt`
+2. Add a `== Changelog ==` entry in `readme.txt`, and check that `Tested up to:`
+ names the current WordPress release (https://wordpress.org/download/).
+3. Verify locally (next section), then merge the change to `main`.
+4. Create and publish a GitHub Release whose tag is that version, in `v0.3.0`
+ style.
+5. GitHub Actions verifies the tag and the focused tests, deploys the release to
+ the WordPress.org SVN repository, and attaches the installable ZIP to the
+ GitHub Release.
-**3. Commit them to SVN** in the same session as the `trunk/` commit that
-contains the matching readme (Part 3.4), so the captions and the files are never
-live without each other.
+The workflow rejects prereleases and mismatched versions. It needs the repository
+secrets `SVN_USERNAME` and `SVN_PASSWORD`. WordPress.org still uses SVN as its
+publishing backend; GitHub Actions performs that SVN operation for maintainers.
----
+`Stable tag` is what decides what users download. A tag that does not exist in
+SVN, or a `Stable tag` still pointing at the old version, ships the old code to
+everyone with no error anywhere.
-## Part 1 — verify locally
+## Verify locally
-### 1.1 Syntax and logic — no WordPress needed
+### Syntax and logic (no WordPress needed)
```sh
-cd /Users/paiteq/projects/seatlayer-sdks/wordpress
-
-# Syntax.
for f in seatlayer.php uninstall.php includes/*.php; do php -l "$f"; done
node --check assets/js/frontend.js
node --check assets/js/block.js
-# Logic. Both print ALL PASS and exit 0; anything else is a blocker.
+# Both print ALL PASS and exit 0. Anything else blocks the release.
php tests/settings-logic.php
node tests/frontend-options.js
```
-The two harnesses stub only what the code under test actually touches, so what
-they exercise is the **real** file rather than a copy that can drift. They are
-`export-ignore`d, so they are not in the zip.
-
-- `tests/settings-logic.php` — the settings class's pure logic: the checkbox
- sanitizer (an unchecked box arrives as `null` and must mean OFF), the secret-key
- sanitizer (empty submission KEEPS the stored key, `__remove__` clears it, a bad
- shape keeps it), the base-URL sanitizer refusing `javascript:`/`data:`/`ftp:`,
- and `site_origin()` against the exact shape the server stores embed domains in.
-- `tests/frontend-options.js` — runs `frontend.js` against a stub SDK and asserts
- what a `SeatPicker` is actually constructed with: `returnUrl` sent **only**
- under hosted checkout and carrying path and query verbatim, never sent in
- handoff mode, the handoff fallback still wired in both modes, and the
- no-SDK-on-page path showing one error without marking the container mounted.
-
-**What they cannot prove**, and why 1.2 and 1.3 are not optional: nothing here
-loads WordPress. Hook registration, block registration, the REST route and its
-`edit_posts` gate, `wp_options` round-trips, `uninstall.php` (which only ever
-runs inside WordPress's uninstall path), and every rendered admin screen are all
-untested until an actual install runs them.
-
-### 1.2 Plugin Check — the real gate
-
-This is the tool the wp.org review team runs first, and it is the only check
-here that exercises the plugin inside WordPress. It needs a WordPress install;
-if you do not have one to hand, `wp-env` gives you a throwaway in one command.
+The two harnesses stub only what the code under test touches, so they exercise
+the real files. They are `export-ignore`d and are not in the ZIP.
+
+- `tests/settings-logic.php` covers the settings class's pure logic: the checkbox
+ sanitizer, the secret-key sanitizer (an empty submission keeps the stored key,
+ `__remove__` clears it, a bad shape keeps it), the base-URL sanitizer refusing
+ `javascript:`, `data:` and `ftp:`, and `site_origin()`.
+- `tests/frontend-options.js` runs `frontend.js` against a stub SDK and checks
+ what a `SeatPicker` is constructed with, including when `returnUrl` is sent.
+
+These harnesses do not load WordPress. Hook and block registration, the REST
+route and its `edit_posts` gate, option round-trips, `uninstall.php` and the admin
+screens are only exercised by the next two steps.
+
+### Plugin Check
+
+Plugin Check is the tool the wordpress.org review team runs first. `wp-env` gives
+you a throwaway WordPress in Docker with this plugin mounted:
```sh
-# Throwaway WordPress in Docker, this plugin mounted into it.
-cd /Users/paiteq/projects/seatlayer-sdks/wordpress
npx @wordpress/env start
npx @wordpress/env run cli wp plugin install plugin-check --activate
-# wp-env mounts the plugin under THIS REPOSITORY'S DIRECTORY NAME (`wordpress`),
-# not under the wp.org slug — so confirm what to call it before checking it.
+# wp-env mounts the plugin under this repository's directory name,
+# not under the wordpress.org slug, so confirm the name first.
npx @wordpress/env run cli wp plugin list
-npx @wordpress/env run cli wp plugin check wordpress
+npx @wordpress/env run cli wp plugin check
npx @wordpress/env stop
```
-Plugin Check's "plugin slug does not match text domain" test reads the *folder*
-name, so under wp-env it will flag `wordpress` vs `seatlayer-seating-charts`.
-That is an artefact of the mount, not a real defect. To see the result the
-reviewers will see, check the built zip instead — unzip it into the wp-env
-plugins directory under the real slug, or simply confirm by hand that
-`Text Domain:` equals the `--prefix` used in Part 3.1.
+Under wp-env, the "plugin slug does not match text domain" test compares against
+the folder name, so it can flag a mismatch that is only an artefact of the mount.
+The real slug and the `Text Domain:` header are both `seatlayer-seating-charts`.
Fix every **ERROR**. Read every **WARNING** and either fix it or be able to say
-why not — the one already knowingly left is the CDN script's missing version,
-which is annotated in `class-seatlayer-render.php`.
+why not. The one known warning is the CDN script's missing version, which is
+annotated in `includes/class-seatlayer-render.php`.
-### 1.3 Try it by hand
+### Try it by hand
-Code review does not tell you whether a buyer lands on a working page. On that
-same throwaway install:
+On the same throwaway install:
-- Activate, then **Settings → SeatLayer**: save a bad key (expect the shape
- warning, and that the previous key survives), then save nothing (expect the
- key to survive), then tick Remove.
-- Put the block on a page, pick an event, view the page as a logged-out visitor.
+- Activate, then open **Settings, SeatLayer**: save a bad key (expect the shape
+ warning, and the previous key survives), save nothing (the key survives), then
+ tick Remove.
+- Put the block on a page, pick an event, and view the page as a logged-out
+ visitor.
- Select seats and check out against an event with a **test-mode** gateway.
-- Tick the Checkout setting and repeat. Confirm the fallback: with an account
- that does not have in-page checkout, the buyer must still get the redirect.
-- **The return trip, both ways round.** This is the one behaviour that cannot be
- proven without a real gateway, so prove it here. With the Checkout setting on
- and a **test-mode Stripe** event:
- - First declare this site under **Embed domains** in the SeatLayer dashboard,
- copying the address the settings screen prints verbatim. Buy a seat. The
- buyer must land back on the WordPress page, with `?order=…&status=success`
- appended and any query string the page already had still intact.
- - Then remove that embed domain and buy again. The buyer must still complete
- the purchase and still receive tickets — finishing on SeatLayer's own page.
- A failed payment, or an error, means the fallback is broken and is a release
- blocker; finishing on SeatLayer's page is the correct degraded behaviour.
- - Razorpay is unaffected by either — it never navigates away. Confirm it still
- completes in place.
-- Delete the plugin from the Plugins screen and confirm the options are gone:
- `npx @wordpress/env run cli wp option get seatlayer_secret_key` → error.
-
----
-
-## Part 2 — GitHub
-
-The public source repository is
-https://github.com/seatlayer/seatlayer-wordpress. `origin` is already configured.
-For recovery releases, confirm the intended commit and push it before creating
-the version tag.
+- Tick the Checkout setting and repeat. With an account that does not have
+ in-page checkout, the buyer must still get the redirect.
+- Check the return trip with the Checkout setting on and a test-mode Stripe event:
+ - Declare this site under **Embed domains** in the SeatLayer dashboard, copying
+ the address the settings screen prints. Buy a seat. The buyer lands back on
+ the WordPress page with `?order=…&status=success` appended and any existing
+ query string intact.
+ - Remove that embed domain and buy again. The buyer must still complete the
+ purchase and receive tickets, finishing on SeatLayer's own page. A failed
+ payment or an error here blocks the release.
+ - Razorpay never navigates away. Confirm it still completes in place.
+- Delete the plugin from the Plugins screen and confirm its options are gone:
+ `npx @wordpress/env run cli wp option get seatlayer_secret_key` returns an
+ error.
+
+## Manual recovery release
+
+Use this only if GitHub Actions or the automated deployment is unavailable. Do
+not also publish the GitHub Release while following these steps, or the same
+version is deployed twice.
+
+### Tag on GitHub
```sh
-cd /Users/paiteq/projects/seatlayer-sdks/wordpress
-
-# Confirm what you are about to publish.
-git log --oneline
git status --short # expect: clean
-
-git push -u origin main
-
-# Tag the release; replace 0.3.0 with the version being released.
-git tag -a v0.3.0 -m "0.3.0"
-git push origin v0.3.0
-```
-
-Publishing the GitHub Release normally starts the automated WordPress.org
-deployment. Do not publish it while following the manual SVN recovery path,
-because that would deploy the same version twice.
-
-```sh
-gh release create v0.3.0 \
- --title "0.3.0" \
- --notes "See readme.txt changelog."
+git log --oneline -5 # confirm the commit being released
+git tag -a "v$VERSION" -m "$VERSION"
+git push origin "v$VERSION"
```
----
-
-## Part 3 — wordpress.org
-
-### 3.1 Build the zip
+### Build the ZIP
-`.gitattributes` marks the repo-only files `export-ignore`, so `git archive`
-produces exactly the tagged commit minus those — no manual deleting, and no risk
-of shipping something that was not reviewed.
-
-**The `--prefix` is the folder name users end up with, so it must be the slug —
-and it must equal the `Text Domain:` header.** Both are `seatlayer-seating-charts`
-(0.0); if you took the reversal in 0.0, both become `seatlayer`.
+`.gitattributes` marks the repository-only files `export-ignore`, so `git archive`
+produces exactly the tagged commit minus those files. The `--prefix` is the folder
+name users end up with, so it must be the slug, which equals the `Text Domain:`
+header.
```sh
-cd /Users/paiteq/projects/seatlayer-sdks/wordpress
git archive --format=zip \
--prefix=seatlayer-seating-charts/ \
- -o seatlayer-seating-charts-0.2.0.zip v0.2.0
+ -o "seatlayer-seating-charts-$VERSION.zip" "v$VERSION"
-# Check what is in it before uploading anything.
-unzip -l seatlayer-seating-charts-0.2.0.zip
+unzip -l "seatlayer-seating-charts-$VERSION.zip"
```
-Expect: `seatlayer.php`, `uninstall.php`, `readme.txt`, `LICENSE`, `includes/`,
-`assets/js/`, `assets/css/`. Expect NOT to see `.gitignore`, `.gitattributes`,
-`CONTRIBUTING.md`, `RELEASE.md`.
-
-### 3.2 Submit for review
-
-Manual, and only once:
-
-1. Sign in at https://wordpress.org/plugins/developers/ with the account from 0.1.
-2. Go to https://wordpress.org/plugins/developers/add/ and upload
- `seatlayer-seating-charts-0.2.0.zip`.
-3. Wait. Review is a human reading the source, typically days to a few weeks.
- They will email the account in 0.1 with anything they want changed; reply to
- that thread with a corrected zip rather than resubmitting through the form.
+Expect `seatlayer.php`, `uninstall.php`, `readme.txt`, `LICENSE`, `includes/`,
+`assets/js/` and `assets/css/`. Expect **not** to see `.gitignore`,
+`.gitattributes`, `CONTRIBUTING.md`, `RELEASE.md` or `tests/`.
-**Expect them to ask about the CDN script.** Loading executable code from
-`cdn.seatlayer.io` is the one thing in this plugin that gets a second look.
-The answer is that the renderer is the service's own SDK and the plugin is
-useless without it — the same footing as `stripe.js` — and that this is
-disclosed in the `== External services ==` section of `readme.txt`, per host,
-naming what is sent. Point at that section; do not argue the general principle.
-
-### 3.3 After approval — SVN
-
-wp.org gives you an SVN repository, not a Git one. You get the URL by email.
+### Commit to SVN
```sh
-cd ~ # anywhere outside this Git repo
-svn checkout https://plugins.svn.wordpress.org/seatlayer-seating-charts/ seatlayer-svn
-cd seatlayer-svn
+ZIP="$PWD/seatlayer-seating-charts-$VERSION.zip"
+WORK="$(mktemp -d)"
+
+svn checkout https://plugins.svn.wordpress.org/seatlayer-seating-charts/ "$WORK/svn"
+unzip -o "$ZIP" -d "$WORK/unpacked"
-# Unpack the same zip's contents into trunk.
+cd "$WORK/svn"
rm -rf trunk/*
-unzip -o /Users/paiteq/projects/seatlayer-sdks/wordpress/seatlayer-seating-charts-0.2.0.zip -d /tmp/sl
-cp -R /tmp/sl/seatlayer-seating-charts/. trunk/
+cp -R "$WORK/unpacked/seatlayer-seating-charts/." trunk/
svn add --force trunk
svn status # read this before committing
-svn commit -m "0.2.0"
+svn commit -m "$VERSION"
-# Tag it. `Stable tag` in readme.txt points here — this is what users install.
-svn copy trunk tags/0.2.0
-svn commit -m "Tag 0.2.0"
+# `Stable tag` in readme.txt points here. This is what users install.
+svn copy trunk "tags/$VERSION"
+svn commit -m "Tag $VERSION"
```
-### 3.4 Listing assets
+## Listing assets
-Banners, icon, and any screenshots go in `assets/`, which is a sibling of
-`trunk/` and is **not** shipped to users.
+Banners, the icon and any screenshots live in the SVN `assets/` directory, a
+sibling of `trunk/` that is **not** shipped to users:
-```sh
-cd ~/seatlayer-svn
-# assets/banner-1544x500.png, assets/banner-772x250.png
-# assets/icon-256x256.png, assets/icon-128x128.png
-svn add --force assets
-svn commit -m "Listing assets"
-```
+- `assets/banner-1544x500.png`, `assets/banner-772x250.png`
+- `assets/icon-256x256.png`, `assets/icon-128x128.png`
+- `assets/screenshot-1.png`, `assets/screenshot-2.png`, … (optional)
The icon is what shows in wp-admin's plugin search, so it is the one asset worth
not skipping.
-**Screenshots are optional and the readme currently promises none** — see 0.3. If
-you are adding them, put the `screenshot-N.png` files here **and** the matching
-`== Screenshots ==` captions in `trunk/readme.txt` in the same visit, so the
-listing never renders a caption without its image.
-
----
-
-## Subsequent releases
-
-1. Land the change on `main`.
-2. Bump the version in **three** places, which must agree or wp.org serves the
- wrong code: the `Version:` header in `seatlayer.php`, `SEATLAYER_VERSION` in
- the same file, and `Stable tag:` in `readme.txt`.
-3. Add a `== Changelog ==` entry.
-4. Push the tag and publish its GitHub Release. The release workflow performs the
- SVN update and attaches the installable ZIP. Use Part 3 manually only to
- recover from an automation outage.
-
-`Stable tag` is what actually decides what users download. A tag that does not
-exist in SVN, or a `Stable tag` still pointing at the old version, ships the old
-code to everyone with no error anywhere.
+`readme.txt` currently lists no screenshots. If you add them, commit the
+`screenshot-N.png` files and the matching `== Screenshots ==` captions in
+`trunk/readme.txt` in the same visit. The captions are positional (item *N*
+captions `screenshot-N.png`), so a gap shifts every caption after it. Shoot at
+1544px wide or more and keep one aspect ratio across the set.