=== Leadovation Aero Courses ===
Contributors: wptechnology
Tags: bookings, calendar, events, school, aviation
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 2.3.4
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Theory course scheduling and booking for flight schools: catalogue, session planner, calendar views and built-in bookings.

== Description ==

A flight school plans its ground school twice a year, and then spends the next six months answering the same three questions: when is the next Air Law session, is there a seat left, and who is actually coming on Saturday.

**Aero Courses answers all three by itself.** You build the semester once, publish it on your own site, and students book their own seats. No spreadsheet, no reply-all, no third-party booking service holding your roster.

It is not a general-purpose events plugin bent into shape for aviation. Modules, sessions, capacity, booking windows and cancellation deadlines are modelled on how a school actually runs a syllabus: PPL, CPL, ATPL, IR.

= Free, and genuinely usable =

The free version is not a demo. A school can run a full semester on it, with no cap on sessions, students or bookings.

* **Build the semester.** Course modules with their code, colour, duration and default schedule. A planner that lays the term out, flags a clash before you publish, and keeps everything as a draft until you say so. Mark the days the school is closed and it plans around them.
* **Publish it where your students already are.** Two front-end views: a dense operations board showing the whole semester at a glance, and a booking agenda grouped by day. Each comes three ways, shortcode, Gutenberg block or Avada element, and all three render exactly the same thing.
* **Take the bookings.** Seats are enforced, the booking window opens and closes when you say, and students cancel themselves up to a deadline you set. Confirmation e-mail to them, notification to you.
* **Keep the register.** An attendee screen that opens on a period (the next 30 days, the quarter, a past year) showing every session with who is on it. Add or remove someone by hand, export a session to CSV.
* **Give people the right hat.** Four roles (Student, Pilot, FI, FE) assigned one at a time or in bulk. A role is *added* to the WordPress roles an account already has, never substituted.
* **Speak your students' language.** English and French, the whole interface, translated by hand in the words a flight school actually uses. The *content* travels too: course titles, descriptions, locations and e-mail templates are written language by language, and each student is written to in their own. No multilingual plugin required; if Polylang or WPML is running, Aero Courses follows their lead.
* **Move in from Events Manager, free.** The import screen reads the events already on your site, works out one module per title prefix, and tells you what it will do before writing anything. Nothing is touched in Events Manager, the import can be replayed without doubling, and no student account is ever invented.

= Upgrade to Aero Courses Premium =

[Aero Courses Premium](https://www.wptechnology.com/plugins/aero-courses/) is a separate plugin, installed on top of this one, for the school that has outgrown doing it by hand. Nothing described below is present in this plugin: what you install here is complete on its own and runs without a licence.

* **A whole semester in one gesture.** Pick a course, a rhythm and an end date; the plugin proposes the dates for you to review before a single one is written, skipping closures and flagging clashes.
* **A waiting list that works while you sleep.** A full session keeps taking names, and the moment a seat frees up the queue is told. First to book gets it.
* **Reminders that go out on their own.** The student seven days and two days before, the instructor the day before with the list of who is coming. Never twice for the same session.
* **Attendance, and a training record.** Mark present, absent or excused for a whole session in one click; each student gets a page showing module by module what they have attended, what they are booked on and what is still open.
* **An instructor on every session.** Chosen among the accounts allowed to sign the sheet. The planner refuses to publish a semester that gives one instructor two sessions at once.
* **The paperwork, in the shape it is asked for.** Bookings with their status, an attendance register naming who signed it and when, or one row per session with seats offered, taken, cancelled and people turned away. Over any period, not one session at a time.
* **Add to calendar.** A student picks Google, Outlook or Apple and the session lands in their own calendar. The confirmation e-mail carries the `.ics` file for whoever does not click.
* **A theme editor.** Start from one of four presets, then set each of the nineteen colours and lengths it is made of, with the board rendering live as you change them.

Nothing you have already is ever switched off after the fact. [See what Premium adds and what it costs](https://www.wptechnology.com/plugins/aero-courses/).

= Part of the Aero range =

Aero Courses is one of the WPTechnology plugins written for flight schools and flying clubs. They share the same look and the same idea: one job each, done properly, and they talk to each other when installed side by side.

* [Aero Weather (METAR/TAF)](https://www.wptechnology.com/plugins/aero-weather/): the field's METAR and TAF on your site, raw or decoded, with the flight category at a glance.
* **Aero Users**: the school's roster (students, pilots, instructors, examiners) shared by the whole range. In review.

= Translations =

The plugin ships in English and French. To translate it into your language, or to improve the French, join the project on [translate.wordpress.org](https://translate.wordpress.org/projects/wp-plugins/leadovation-aero-courses/). Every string is prepared for it and the `.pot` file is bundled.

= What this plugin does not claim =

Attending a course is not passing a module. Authorities such as the DGAC certify on an examination, which this plugin knows nothing about. It records attendance (who was marked present, by whom, and when) and never claims more. A module counts as attended only where someone signed the sheet: a booking on a past session nobody signed off is not attendance, and that is precisely what an auditor comes to check.

= Third-party services =

The plugin itself contacts nothing to do its work: your schedule, your students and your bookings never leave your site.

It bundles the Freemius SDK, which handles licensing for the Premium version and, if you agree to it on activation, anonymous usage statistics. You are asked, you may decline, and declining changes nothing about how the plugin works. Freemius is contacted only to check a licence or, with your consent, to send those statistics. Service: [Freemius](https://freemius.com/) · [terms](https://freemius.com/terms/) · [privacy](https://freemius.com/privacy/).

== Screenshots ==

1. The booking agenda on the school's own site: sessions grouped by day, seats left on each, and a button that books the student in one click.
2. The operations board: a whole semester at a glance, one row per month, colour per module, with the sessions that are full and the days the school is closed.
3. The planner, where the semester is built: modules dropped onto days, closures marked with the mouse, and clashes flagged before anything is published.
4. The home dashboard: the semester at a glance, seats taken, the next ten sessions, and what still needs attention.
5. The attendee screen, opened on a period: every session with the people booked on it, ready to export.
6. The course catalogue: one table per programme, each module with its code, colour, duration and default schedule.

== Installation ==

1. In your WordPress admin, go to Plugins → Add New and search for **Aero Courses**, then click "Install Now" and activate. (Or upload the zip from Plugins → Add New → Upload Plugin.)
2. Open the **Aero Courses** menu and create your training programme and its modules.
3. Build the semester in the planner, then publish it.
4. Put the schedule on a page: the `[aero_board]` or `[aero_agenda]` shortcode, the "Operations board" and "Agenda" blocks in the block editor, or the same two elements in Avada Builder under "WPTechnology". Nothing to configure: the Avada elements appear only when Fusion Builder is active.

== Frequently Asked Questions ==

= Does it work with Polylang or WPML? =

Yes, and it steps aside for them. On a site running either one, aero-courses follows the language they decide for the request, not the one the visitor happens to have in their profile, and course, location and programme texts are translated in their own string translation screen, alongside the rest of the site. The plugin registers those strings for you; you will find them under the "aero-courses" group.

Translations you had already typed into the plugin's own language tabs are not lost: they keep being used wherever Polylang or WPML has nothing yet. If you would rather keep using the built-in tabs, the `aero_courses_delegate_translations` filter turns the delegation off without uninstalling anything.

E-mail templates stay in the plugin's own editor: a message body is a document with placeholders, not a string, and a string translation screen is a poor place to write one.

Without either plugin, aero-courses translates content on its own, with nothing to install.

= Does it work with Avada? =

Yes. When Fusion Builder is active, aero-courses registers two elements, "Operations board" and "Booking agenda", in the "WPTechnology" category, with the same options as the shortcode attributes. They are not a second implementation: each element hands its options straight to the shortcode, so what Avada renders is what the shortcode renders. If Fusion Builder is not installed, nothing is registered and nothing is loaded.

= Do I need another events or calendar plugin? =

No. aero-courses is self-contained: it stores its own data in dedicated database tables and does not depend on Events Manager, The Events Calendar or any other calendar plugin.

= Can students book more than one course at a time? =

Booking is per session. A student can book any number of sessions across any number of modules, as long as each session still has room.

= What happens when a session is full? =

The booking endpoint refuses the request as soon as capacity is reached; the front-end views show the session as full rather than letting a student attempt to book it.

= Can I run more than one training programme (e.g. PPL and CPL)? =

Yes, as many as the school teaches. PPL(H), PPL(A), CPL, ATPL and IR can run side by side, each with its own modules, semesters and students, and there is no cap on how many are active at once.

= Is the interface available in languages other than English? =

The interface strings are fully translatable with standard WordPress tools (Loco Translate, or community translations on translate.wordpress.org). Course, location and e-mail content can be translated language by language directly in the plugin, independently of the interface language.

= Does this plugin send any data to an external service? =

Your schedule, your students and your bookings never leave your site. Nothing about your school is sent anywhere.

The plugin bundles the Freemius SDK, which contacts freemius.com for two things and two only: checking a Premium licence and, if you agreed to it when you activated the plugin, anonymous usage statistics such as your WordPress version. You are asked before anything is sent, you may decline, and declining changes nothing about how the plugin works. On the free version with no licence, the plugin runs without contacting anyone.

See https://freemius.com/privacy/.

== Changelog ==

= 2.3.4 =
* The Freemius product slug now matches the plugin's directory name, leadovation-aero-courses, so licence data and the paid extension are filed under the published name.
* Simpler readme tags.

= 2.3.3 =
* Every value written to a screen now goes through an escaping function at the point of output, including the fragments the paid add-on may render and the "Coming" badges of the Premium page.
* Author URI points to wptechnology.com, the brand the plugin is published under.

= 2.3.2 =
* **Housekeeping, with nothing to see on screen.** The free plugin carried the plumbing of a licence gate it never used: a named list of the paid extension's features, and a lookup that answered no for each of them. Nothing in the free plugin ever asked it, so nothing was switched off, but the plumbing had no business being there. It has moved to the separate Premium extension, where the features it governs actually live. The free plugin reads the licence for one purpose only, saying whether this site has one.
* The Premium page keeps its own list of what the separate extension adds, with its labels and its "coming" marks, and it is unchanged.

= 2.3.1 =
* Plugin URI now points straight at the plugin page rather than at the site root.

= 2.3.0 =
* **The shared core no longer starves a newer copy of itself.** Installing a second plugin of the Aero range beside this one could leave the shared registry unloaded, and the site fell over on activation with a fatal error. Each class of the core is now looked for on its own, the newest copy present is the one that loads, and a half loaded core completes itself instead of giving up.
* **The Aero range moves to the top of the admin menu**, right under the Dashboard and above Posts, with Aero Users first and Aero Courses under it. A school that would rather have it elsewhere moves the whole range with the `aero_core_menu_base` filter.
* The checkout now shows its prices in euros for everyone. The currency was only preselected, so the checkout was free to swap it for dollars from the buyer's country or from the Freemius account they were already signed in with. The inline currency selector is untouched: the displayed currency is imposed, the paid one is still the buyer's choice.

= 2.2.0 =
* The plugin is now called Leadovation Aero Courses, after its publisher. The name in the admin menu is unchanged, and a school can still rename it to whatever it likes.
* **Training programmes are no longer capped.** PPL(H), PPL(A), CPL, ATPL and IR can run side by side on the free version, each with its own modules, semesters and students. Nothing you had is switched off, and nothing new needs buying.
* The Premium features are no longer part of this package. They ship in a separate extension, installed on top of this one; the Premium screen describes what it adds instead of showing controls that refuse to work. What this plugin installs is complete and runs on its own, with no licence.
* The dark theme of the back office is applied from the document head rather than from a script written into the page, and the theme preview goes through the stylesheet queue. Nothing changes on screen.
* Six e-mail templates were falling back to English in French: their translation still carried a punctuation mark the wording had dropped. Fixed.

= 2.1.36 =
* An account can now hold several aero roles at once. A head of training is ordinarily both FI and FE, and a licensed pilot becomes a student again for a type rating without ceasing to be a pilot. Until now the second role drove out the first.
* Assigning a role in bulk adds it; it no longer replaces what the account already had. Clearing every aero role is still possible, but it is now a deliberate choice rather than a side effect. Roles the school already uses are never touched, as before.
* Each role shows as its own pill with a cross to remove just that one, and the per-row selector offers only the roles the account does not already hold.

= 2.1.35 =
* The admin menu now reads "Aero Courses" instead of the slug "aero-courses", and the name is no longer offered for translation: a brand name reads the same in every language.
* A school can rename that menu entry from the settings, free of charge. Call it "Courses", or whatever your school calls it; the real product name stays visible in the settings, under the field, for the day you need to look for help.
* A new menu icon, and a rule for the whole range behind it: the trade at the top left, the same small aeroplane at the bottom right, sitting in a notch cut out of the glyph. The notch is not decoration: WordPress paints a menu icon as a background image and never recolours it, so empty space is the only way to separate the two.

= 2.1.34 =
* A tick box in the header selects every account on the page, so assigning a role to a few hundred students no longer takes a few hundred clicks. It shows a partial state when only some rows are ticked, and never touches a row the screen refuses to change.
* The Name column can be sorted, both ways, and the order lives in the address so it can be bookmarked. The two role columns are deliberately not sortable: roles live in a serialised option that cannot be ordered in the database, and the role filter answers the same need in one query.
* The bulk button now reads "Assign role in bulk" rather than "Change role in bulk". An aero role is added to an account and replaces only a previous aero role; the roles the school already uses are never touched, and the button now says so.

= 2.1.33 =
* The users screen now shows the WordPress role each account already had, and lets you filter on it. A school installing the plugin on a live site already has its own roles and hundreds of accounts carrying them; the aero role column reads "None" for everyone on day one, so nothing told a student apart from an instructor. Filter on the school's own role, tick the page, apply the aero role in one go.

= 2.1.32 =
* Clicking a programme, a location or a module opens its editing window straight away. It used to send a request to the server only to come back to the same screen with one attribute changed. The "new" button stopped doing that two versions ago; the rows had been left behind.
* Editing still works with JavaScript turned off, exactly as before: the row is a link, and the server opens the right window.

= 2.1.31 =
* Table headers keep their shape whatever the theme does. The real cause turned out to be a float: a stylesheet on the site floats the first header cell, and a floated element computes to display:block no matter what any other rule says, !important included. That is the specification, not the cascade, which is why restating the display could never have worked. Our tables now refuse to float.

= 2.1.30 =
* The planner opens on the semester that contains today, not on the oldest one. A school that had just imported ten years of history landed on July 2017: two sessions on an empty grid, and the impression the import had done nothing. Failing a current semester it opens the next one, then the latest past one.
* The semester picker now sits at the top of the grid it governs, in place of the fixed title, instead of at the bottom of the left column.
* The two columns that carried a fixed width now carry a minimum width instead. On one site those two, and only those two, showed a header that stopped short of its column. A minimum keeps the intent without pinning a used width that another stylesheet can desynchronise.

= 2.1.29 =
* Activating the plugin opens its home screen again on busy sites. Not every admin request is a screen: admin-ajax.php fires the same hook, and on a site running other plugins one of their background calls arrived first, used up the one-time flag and sent the redirect to a request nobody was looking at. The plugin now only redirects a real page view.

= 2.1.28 =
* The import now creates the semesters its sessions need, and attaches every session to the one that contains it. A school that had just brought in 362 sessions opened the planner and saw nothing: the planner works by semester, none existed, and the screen told it no course existed either. Running the import again also repairs sessions brought in by earlier versions, without touching any session you placed yourself.
* The planner no longer claims a programme has no courses when it has some and only lacks a semester. It says how many there are and what to do next.
* After an import, the proposal panel is gone. It used to sit under the report with its boxes still ticked, asking again for what had just been done.

= 2.1.27 =
* The import no longer needs your events to be named "T1 - Air law". A school that calls them "Communications" or "Theory class: Navigation" now sees them proposed as modules, grouped by identical title, with a short code worked out from the title.
* Those deduced modules arrive unticked, and say so. Events Manager cannot tell a theory class from a sightseeing flight, so both are shown, counted, and left for you to choose.
* The deduced code can be corrected before anything is written, because a course code cannot be changed once the course exists.
* "No module code in the title" is no longer a reason to leave an event out. The only events set aside now are those in the trash, awaiting approval, or without a usable date.

= 2.1.26 =
* Creating a programme no longer asks for a code. The identifier a shortcode uses is built from the name, made unique on its own, and shown read-only when you edit the programme so you can still copy it. It was never editable anyway, which is reason enough not to ask for it.
* The Save button of an editing window now says it is saving. Saving posts to the server and replaces the page; until now the window sat there saying nothing, and people clicked twice.
* Table headers hold their shape against a theme stylesheet. The previous fix restated our own layout but carried the same weight as the theme rule that broke it, so whichever loaded last won. Measured in a browser: without the fix six columns out of seven were misaligned; with it, all seven line up.

= 2.1.25 =
* "New programme", "New location" and "New course" now open their form straight away. They used to send a request to the server only to come back to the same screen with one attribute changed, on a window whose contents were already in the page: on a busy site that meant a second or two of waiting in front of a screen that had not moved. Editing an existing row still reloads, because only the server knows what to put in the fields, and the whole screen still works with JavaScript turned off.

= 2.1.24 =
* Buttons that are links no longer lose their label on hover. The base rule for links repainted them in the accent colour, which is the very colour of their background: text and background were both rgb(217, 79, 26), so the label vanished. Every button variant now holds its own colour through hover and keyboard focus.
* On the first-run invitation, the sentence under the button no longer runs the full width of the panel.

= 2.1.23 =
* Typography: the em dash is gone from every line a school reads. It sat in 53 interface strings, in the e-mail templates, in the empty cells of the tables and throughout this page. Each one is now the punctuation the sentence actually asked for: a colon where what follows explains, commas around an aside, brackets around a list, a full stop between two sentences. Label separators and empty cells take the middle dot the plugin already uses in its own name.
* A test holds the rule on all four surfaces (the translation template, the French catalogue, the literal markup of the templates, and this page), so it cannot come back unnoticed.

= 2.1.22 =
* A school opening the plugin for the first time no longer lands on four zeroes. When Events Manager holds events nobody has brought in and no session exists yet, the gauges and the empty semester strip give way to a single invitation saying how many events are waiting and what the import does. It leaves on its own the moment the school has a session. No popup, nothing to dismiss.

= 2.1.21 =
* Activating the plugin now opens its home screen, once. Never on a bulk activation, and never for someone who cannot open it.
* The home screen tells a school what to do next: when Events Manager holds events nobody has brought in, it says how many and points at the one thing standing in the way: a training programme, or the import itself. It falls silent once the import has run.
* After an import, the form below the report no longer calls itself "step 1 of 3". The page read 3, then 1, then 2, and looked as though everything had to be redone.

= 2.1.20 =
* Tables in the plugin's screens now assert their own layout. On a real site, another plugin's admin stylesheet was setting `th { display: block }`, which takes a header cell out of the table's column algorithm: seven clean headers and seven clean cells rendered as nine columns, three of them empty. You do not get to choose the plugins a school installs, so the tables no longer rely on the browser default alone.

= 2.1.19 =
* Deleting the plugin after deactivating it from the command line left its tables behind. The uninstall hook is now registered on activation as well, so the cleanup runs whichever way the plugin is switched off.

= 2.1.18 =
* The import now brings in the description and the excerpt your events already carry. It was reading six columns of the Events Manager table and never the posts table, where the text actually lives, so a school got its modules back with their code and their title, and had to retype eight descriptions it had already written.
* An installation of Events Manager old enough to have no `post_id` column no longer reports an empty site: the column is looked for before it is asked for. A failed query returns nothing, which the screen would have read as "nothing to import".

= 2.1.17 =
* A semester is a window, not a container. The planner selected its sessions by semester id while the home dashboard selected them by date range, so a school that imported its history saw the sessions on one screen and an empty grid on the other. Worse, clash detection read the same narrow set: the planner announced "no clash" over a window full of sessions, and placing a module on an occupied day warned nobody. The planner, the dashboard, the live recount and publication now read the same rule.

= 2.1.16 =
* Table header cells that carried no label now carry one, readable by a screen reader and invisible on screen. A column you act in (a checkbox, a button) was announcing a position and nothing else. It also stops a page optimiser from dropping the cell as empty, which shifted a whole header one column across.

= 2.1.15 =
* The plugin and author addresses in the plugin header were the same. They describe different things (this plugin's page, and its publisher's site) and the WordPress plugin directory rightly refuses a submission that confuses them.

= 2.1.14 =
* The plugin now ships in French as well as English: the whole interface, 779 strings, translated by hand in the words a flight school uses.
* A sentence in the planner told you something was not built yet without saying what. It only appeared that way on a licensed site, where the sentence that named the feature (the one that sells it) correctly stays silent. It names it now.
* Every finding of the official WordPress Plugin Check is cleared: escaping, prepared statements, direct file access, block API version. Three of them were real exposures in the date, time and timezone reported by an invalid-schedule exception.
* Six screenshots for the plugin directory.

= 2.1.13 =
* Freemius SDK updated from 2.13.2 to 2.13.4, vendored from the published distribution build rather than the development repository: 197 files instead of 284, and none of the tooling used to build the SDK itself.
* The plugin icon now shows on the Freemius pricing, account and checkout screens. It is declared through the `plugin_icon` filter and lives in the plugin's own assets, so it survives every SDK update.
* Uninstall no longer runs from `uninstall.php`. WordPress executes that file *instead of* the uninstall hook, which left Freemius believing the plugin was still installed. The cleanup is unchanged; only where it hangs from.

= 2.1.12 =
* First public release. Course catalogue and training programmes, semester planner with closures and clash detection, bookings with strict capacity and self-service cancellation, the operations board and booking agenda as shortcodes, Gutenberg blocks and Avada elements, shared aero roles, confirmation and cancellation e-mails, the register of students turned away from a full session, and a one-off import from Events Manager.
* Premium: training records, attendance, instructors, several programmes, theme editor, waiting list, automatic reminders, session series, advanced exports, and add-to-calendar. (Several programmes became free in 2.2.0.)
