Skip to content

Require OpenStation — the desktop is the product - #14

Merged
AllTerrainDeveloper merged 13 commits into
mainfrom
require/openstation
Aug 19, 2026
Merged

AllTerrainDeveloper merged 13 commits into
mainfrom
require/openstation

Conversation

@AllTerrainDeveloper

Copy link
Copy Markdown
Owner

What

A deliberate product pivot: OpenStation goes from optional to required.

  • Requires Plugins: desktop-mode in the plugin header (+ Requires at least: 6.5, the version that introduced plugin dependencies). WordPress now installs/activates OpenStation alongside this plugin, refuses activation without it, and blocks deactivating the shell underneath us.
  • The function_exists() gates in shell-api.php stay — reframed as defense in depth, not a supported mode: on an older WordPress or a site that force-removed the shell, admins with activate_plugins get an error notice linking to the fix, and published forms keep rendering on the front end — a missing admin dependency must never take down a visitor-facing form.
  • README, readme.txt (header, "Built on OpenStation" section, FAQ), PLAN.md non-negotiable, and the plugin-header prose all updated in the same change; the PLAN entry records the date and prior policy.

Why

The builder was never anything except an OpenStation window; the drag-between-forms, media-onto-choice, entries-onto-other-apps interactions are the product. Shipping a quietly lesser shell-less version taught users the wrong thing about what this plugin is.

Tests

  • 4 new PHPUnit tests (requiresOpenstation.php): the header declares the dependency, the notice renders for admins on shell-less sites, stays silent for non-admins, and is actually hooked.
  • Full suite green (571 on this branch), PHPCS 0 errors.

🤖 Generated with Claude Code

https://claude.ai/code/session_0119U4sRRWGcTQdwYreTwpAp

AllTerrainDeveloper and others added 13 commits August 19, 2026 13:47
The plugin was built shell-optional, but the builder was never anything
except an OpenStation window, and a plugin that quietly ships a lesser
version of itself teaches nobody what it actually is. `Requires Plugins:
desktop-mode` lets WordPress 6.5+ enforce the dependency at activation
and keep the shell from being deactivated underneath us. The
function_exists gates in shell-api.php stay as defense in depth: an
older WordPress or a force-removed shell gets an admin notice naming
the fix, and published forms keep rendering — a missing admin
dependency must never take down somebody's front end.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0119U4sRRWGcTQdwYreTwpAp
A fork that stripped the dependency header used to inherit a quietly
lesser builder mounted on a plain admin page — misrepresenting what this
plugin is. The builder, entries, analytics and Theme Studio pages now
render an explanation and an install link when no shell is on the site;
Import keeps working, and published forms never stopped rendering for
visitors.

And one product wears one name: the windows are AllTerrain Forms,
AllTerrain Forms — Entries, — Analytics, — Theme Studio; the commands
and the admin menu say AllTerrain Forms too. The dock tile's flyout rows
stay short — they already sit under the branded tile.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0119U4sRRWGcTQdwYreTwpAp
The directory listing now leads with the phrases people actually type —
contact form, drag and drop form builder, multi-step forms, conditional
logic, surveys, quizzes — in the title, the tags, and a heading per
feature, with an FAQ phrased as the questions get asked. Everything it
claims stays true, which is the part of SEO nobody can take away.

Four screenshots are new, captured live off the OpenStation desktop:
the builder window, the Theme tab wearing Neon with its instant
preview, Entries with a submission open, and Analytics with its NPS
panel. The conditional-logic and merge-tag shots stay, renumbered.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0119U4sRRWGcTQdwYreTwpAp
An empty themeOverrides map serialises from PHP as [], so the schema
arrived holding a real Array. Every token written into it by name was a
stray expando property JSON.stringify silently drops — the preview
showed the override, the autosave lost it, and the control snapped back
the moment the saved schema was adopted. Repaired at the API layer, the
single door every form response walks through, so no caller can meet
the Array again. Four regression tests pin the shape.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0119U4sRRWGcTQdwYreTwpAp
The first captures used whatever positions the session had left the
windows in, which put them in a corner and made the desktop look like an
accident. Recaptured with each window placed deliberately: builder
centred, entries cascaded over it with a submission open, the Theme tab
wearing Neon, analytics on its own.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0119U4sRRWGcTQdwYreTwpAp
…re/openstation

# Conflicts:
#	assets/js/analytics.min.js
#	assets/js/builder.min.js
#	assets/js/entries.min.js
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0119U4sRRWGcTQdwYreTwpAp
The Theme tab's server re-render is gone. It existed to "reconcile" what
the inline paint had already shown, and what it actually did was blink
the preview, reset both scrollbars and wipe anything typed into the test
form — to arrive at the same pixels. Every token is either a custom
property or one of two structural classes (atf-labels-*, atf-fields-*),
and a theme switch adds only atf-theme-* and the dark flag; all of it is
known client-side, so all of it is painted in place, the same tick it is
clicked. The server renders the preview once, at mount.

The dials stopped rebuilding themselves too: a click now flips is-on in
place instead of replacing the very button under the pointer, the
69-token Advanced list syncs off the click's critical path with its
scroll preserved, and the builder's post-autosave rebind — which was
remounting the whole studio for the benefit of field cards the Theme tab
does not have — no longer runs outside the Build tab.

Verified against the reported sequence with a MutationObserver on the
preview: two edits spanning two autosaves, zero structural mutations,
zero preview round trips.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0119U4sRRWGcTQdwYreTwpAp
WordPress's Abilities API is how a site describes what it can do to AI
agents and MCP clients; this registers the forms' whole working surface
there. An agent can list forms and read their questions, learn the
field-type vocabulary, build a form from a loose description and get
its shortcode back, apply a theme, submit answers through the same
validated anti-spam pipeline a visitor uses, query entries with the
labels resolved, and pull the analytics report as structured data.

None of them grows logic of its own — each is a thin adapter over the
functions the windows and the REST API already call, so an agent and a
human clicking the same button get the same behaviour, the same
validation and the same capability checks. The descriptions are written
for the agent that reads them: what it returns, and when to prefer it.

One honest liberty, documented where it happens: submit-form mints a
valid time-trap signature stamped a minute in the past. The trap hunts
bots that post faster than a human reads; an authenticated agent
invoking a described ability is not that traffic. Everything else —
honeypot, rate limit, blocklist, Akismet, validation — runs untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0119U4sRRWGcTQdwYreTwpAp
The abilities existed in docs/abilities.md and as a paragraph of prose;
neither readme said their names or what each one does. Now both do: the
directory listing gets the named list, and the repository README gets
the table, so an agent's owner can see what their assistant will call
before installing anything.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0119U4sRRWGcTQdwYreTwpAp
Floating positioned every label absolutely — including a radio group's
legend, a scale's heading and a signature pad's label, none of which
have a field to float into — so choosing it painted questions straight
across their own answers. And the lift never fired for anyone: the
selector expected the label after the input, and the renderer has
always emitted it before.

Floating is now scoped to the twelve types a label can sit inside of.
Text-shaped inputs lift on focus or value, told apart by
:placeholder-shown against a reserved single-space placeholder the
renderer now actually emits (the stylesheet had been promising it for
some time). Selects and date inputs, which are never visually empty,
keep their label permanently lifted — the only honest float for them.
The lift rises into headroom reserved above the input rather than
straddling its top border, because a border-straddling label needs a
background mask and no one mask survives ten themes of gradients and
glass. Every other type keeps its label on top, untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0119U4sRRWGcTQdwYreTwpAp
The canvas paints the form's theme tokens onto the field previews, but
a dark theme's text colours assume the theme's own background — and the
cards are builder-white, so Midnight's near-white labels vanished into
them. The server marks dark themes on the form it renders; the canvas
previews are builder-built and never carry that class, so the flag is
hoisted onto the builder root and every preview paints its ground from
it — the same #101418 the Theme tab's frame already uses.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0119U4sRRWGcTQdwYreTwpAp
@AllTerrainDeveloper
AllTerrainDeveloper merged commit 35bd04e into main Aug 19, 2026
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.

1 participant