A flight school keeps a file on every person who walks through the door: student, pilot, instructor, examiner. The first thing that file has to answer is who is who, and what each of them is allowed to do.
That is what this release answers. It shares its roles and its registry with the other Aero extensions of the same range, so a school running several of them sees one directory, not one per plugin. It also holds the credentials of those people and their expiry dates, and shows each pilot where they stand on a page of the site.
The directory
Every account of the site on one screen, with the roles each person holds, when they last signed in, and a drawer that edits those roles one person at a time. Views by role, a search on name and e-mail, sorting by first or last name, and a bulk gesture that adds a role to everybody ticked, or takes it back.
A role is added, never substituted. A pilot who goes back to being a student for a type rating keeps the booking rights of a pilot, and a school that has its own WordPress roles keeps them untouched.
Only the roles of the range are handed out here. The screen never offers to make somebody an administrator: that belongs to WordPress, where the gesture carries its own warnings. It follows the same rule WordPress does, and asks for the same permission.
The file of one person
Open a person from the directory and their file opens in this plugin, not in the WordPress profile: first and last name, badge number, e-mail address, phone, date of birth, postal address, town, the person to call in an emergency, a photo, and the roles they hold, all on one page and saved in one gesture.
The same screen adds a person. It creates the WordPress account and lays down everything else at once, so a school does not have to create an account first and come back to fill in the file. The login is derived from the e-mail address, the password is drawn at random, and the standard WordPress welcome e-mail is offered rather than imposed.
What WordPress already knows is written where WordPress keeps it. First name, last name and e-mail address stay in the account itself: a person edited here stays readable by the theme and by the other extensions of the site.
Fields the school defines
A school always follows something we did not foresee: a membership number, the date a subscription was paid, a helmet size, the employer of a student on a company scheme. It adds the field itself, on a screen of its own, with a name it writes, a kind, a place in the order of the file, a flag when the field is expected, and who is allowed to see it.
Expected flags, and never refuses. A file with an empty expected field still saves, and simply says what is missing.
A field kept to the school never reaches the public side of the site, not in the "My details" block and nowhere else the person concerned can read it, even when the block names it explicitly.
Switch a field off before deleting it. Switching off takes it out of every screen and keeps what people have entered; switch it back on and everything is there again. Deleting says how many values leave with it.
What expires, or has a history, is not a field: it is a credential, and it belongs in the catalogue of tracked credentials, where it gets dates, reminders and a document.
Roles and permissions
The roles of the site, each with what it is allowed to do, in the words a school uses rather than in technical identifiers. A school creates its own roles by naming them, the identifier being derived rather than asked for, and five regulatory roles are offered in one click, with a stable identifier so an export stays readable in an audit.
The grid is not written in advance. Each extension of the range declares what it brings, with a readable sentence for every permission. Install another one and its column appears here, without this plugin knowing anything about it beforehand.
Nothing disappears without a word. A role that came from WordPress or from another plugin carries no delete button at all, and deleting one of yours asks first, saying how many people hold it and will lose it.
Credentials and expiry dates
A medical certificate, a type rating, a language proficiency, an instructor certificate: a school has to know what each person holds, until when, and who to chase this month. Both dates of the document are entered as they are printed on it, the examination and the expiry, and the expiry entered is the truth everywhere.
Nothing is worked out: software that recalculates a date printed on a certificate is wrong the day the two differ, and it is wrong in front of an inspector.
A panel for the wide gesture, a column for the series. The panel opens beside the directory and holds one credential at a time: its two dates, its reference, who issued it, its class or level, the aircraft it is tied to, and its whole history. The pinned column of the directory takes an expiry in place, twenty in a row without leaving the list, which is how a school enters a batch of medicals with the paper in front of it.
Nothing is ever overwritten. Every entry adds an event and the previous one stays readable: a correction says why, replaces the effect of an earlier entry, and leaves it in the history. That is what makes the file answer the question an auditor actually asks, which is not "is this valid today" but "was this person qualified on the fourteenth of March".
Expiring is not the only state. A credential can be valid, coming up, inside its renewal window, expired, or suspended because something it depends on has expired: a medical certificate that has run out does not make a type rating expire, it suspends its exercise, and the two are not repaired in the same way at all. Unfold a row of the directory and each credential shows a band that runs from the last examination to the expiry, with the window marked and today on it.
Which credentials your school follows
The catalogue lists the types a school follows, with the family each belongs to, the word it uses when one comes up for renewal, what it depends on, and how many days before the expiry it wants to be reminded. Ten types come ticked for a helicopter school, and a school adds its own, renames what we ship, or unticks what it does not hold.
Unticking a type takes it off the screens, never out of a file. A school whose pilots keep their own medical certificates unticks that type and stops seeing its columns; the certificates already on file keep suspending what depends on them, because it is reality that suspends, not the display.
The documents at the file
A medical certificate, a licence, an attestation: a school keeps the scan of each at the file of the person it belongs to. Filing one is two clicks in the panel of a credential, and what is filed is shown back with its name, the day it was filed and its size, with two gestures, view and replace.
A filed document never leaves the media library, because it never goes in. A file of the media library is served by the web server at a public, stable, guessable address that nothing checks. A medical certificate carries a name, a date of birth and a licence number: it is not health data, it is a
named document, and a named document is not left at an address people try. Documents live in a folder of their own, outside the uploads directory where the hosting allows it, closed to the web server, and each carries a random name on disk that says nothing of what it is.
The plugin serves the file, never the web server. A request carries the identifier of the document and nothing else, no path anywhere: the plugin checks, reads and serves it. Two cases and two only: you are the person the document belongs to, or you hold the permission to keep licences. There is no shareable link, no link that expires, no third case, and every refused request is written down, because a repeated attempt is the only signal a school will get.
A date is saved without a document, always. A document is expected, never required: a school entering twenty dates after a group medical does not have the twenty scans in front of it, and it will have them next week, or never, and the twenty dates are worth more than nothing.
Nothing is ever deleted on its own. No document expires, none is cleaned up after a year or when somebody leaves: how long a school keeps a document is the school's call. Deleting the plugin keeps them too, unless the school asks otherwise beforehand, in one tick box on the catalogue screen.
Reminders by e-mail
A licence expires on a day nobody remembers. The plugin writes to the person before it does, and to the school every week, and it does both without ever becoming the sender everybody filters.
They are off until you switch them on, and the screen says what will go out first. Not a warning, a number: "switching them on: 22 people receive a message at the next pass, covering 37 expiry dates". A school of four hundred accounts gets to see that before anything leaves, and two buttons send you a sample of each message, to your own account and to nobody else.
One e-mail per person and per pass. Somebody whose four credentials cross a threshold on the same morning receives one message listing the four, never four messages. The thresholds are an attribute of each credential type, ninety, thirty and seven days as delivered, and a school that wants to be warned earlier on a badge changes one line of its catalogue. The day after an expiry has passed, one last message goes out, and then nothing: chasing somebody daily about a credential they know is expired is the shortest road to a mail filter.
A reminder never goes out twice, and it is the database that holds that, not the accuracy of a cron window. WordPress only runs its cron when somebody visits the site, so a pass that missed a day or two catches up; beyond that a missed threshold stays missed, because saying "expires in ninety days" about a credential expiring in forty-five would be worse than saying nothing.
The weekly summary is what keeps the pressure without the harassment. One message per recipient and per week, on the day the school picks, listing the expiry dates of the next ninety days and the expiries that have passed and have not been settled, grouped by person and sorted by urgency. An expired credential stays on that list until it is settled, and leaves it the day it is, never because somebody clicked.
Nothing leaves the school. The recipients are the person concerned and the accounts the school ticks, named on the screen and chosen by permission rather than by a free address field. There is no address field, and there will not be one. No message carries a filed document, nor a link to one: an e-mail gets forwarded.
The audit document
An inspection asks for the state of a given day, and the export answers it: every person, every credential, its reference, who issued it, both dates, its state on that day, the last event and the day the school actually recorded it. In CSV for a spreadsheet, or as a page made to print, both carrying the name of the school and the day they describe.
It is retrospective, and that is the whole point. An entry recorded after the date asked for does not count, even when it carries an earlier date: on the fourteenth of March, the school did not have it, and that is what an auditor wants to know.
Pages for pilots
Five blocks, each with a shortcode of the same name, put a pilot's own situation on a page of the site: whether they can fly and what is missing when they cannot, their credentials and the state of each, the dates coming up, their own details, and, for an instructor or the office, how a group stands.
A block only ever shows the person who is signed in. No attribute names anybody else, there is none, and there will be none: a public page that took an identifier as a parameter would let anyone read someone else's file by changing a digit in the address. Signed out, a block invites you to sign in rather than showing an empty box.
The answer never authorises a flight. Every "can I fly" block carries, and cannot be made to drop, the sentence that says so: the summary repeats what the school has recorded, it does not replace checking your credentials before the flight, and it authorises nothing by itself.
In your language
The plugin is written in English and translated into French by hand, in the words a flight school actually uses. Translations come through
translate.wordpress.org and install themselves; a school can also drop its own file in wp-content/languages/plugins/.
What it bundles, and what it never calls
The plugin calls no external service. Nothing about a school or its people leaves the site: no tracking, no usage reporting, no remote asset, no call to any address of ours or of anybody else's.
Its three type families, Archivo, Barlow Condensed and IBM Plex Mono, travel with it as WOFF2 files and are served from the site itself, never from a font network. All three are published under the SIL Open Font License 1.1, which is compatible with the GPL. Their licence and attribution are in
assets/fonts/LICENSE.txt.