﻿== Changelog ==

= 1.9.11 =
* WordPress.org review follow-up (external-services disclosure, Guideline 7): audited the bundled Freemius WordPress SDK (v2.13.4, the current latest release) at the source level to confirm what it actually sends and when. Confirmed no request to Freemius is made automatically on activation — the SDK's own connectivity/"ping" check was removed from the SDK itself in v2.5.4 and was not present in this build; the one-time opt-in screen renders and nothing is transmitted until the site admin explicitly clicks "Skip" or "Allow & Continue" (or later connects a license from the Account page). Since the plugin's own `fs_dynamic_init()` call was already correct and required no change, the fix here is to the `readme.txt` "External services" section itself: the previous wording said data was sent "when the plugin is activated," which overstated what the code does and is what the review quoted back at us. The section now accurately describes the verified opt-in-gated behavior.
* Patched a confirmed upstream bug in the bundled Freemius SDK (`vendor/freemius/includes/managers/class-fs-debug-manager.php`, `FS_DebugManager::delete_user()`): it referenced the undeclared static property `self::$_accounts` instead of the `Freemius::get_accounts()` accessor used by every other call site in the same file, fataling with "Access to undeclared static property" when deleting an account from the (super-admin-only, hidden) Freemius debug page. This page is not part of the normal WordPress.org review/activation flow. No newer SDK release fixes this as of this writing; the one-line patch is documented inline and should be re-checked against future official SDK updates.

= 1.9.10 =
* WordPress.org review follow-up (activation fatal + notice): `WorkflowSchema::maybe_upgrade()` (called from `Schema::maybe_upgrade()`'s counterpart on `plugins_loaded`) called `wp_insert_post()` via `ensure_portal_page()` before `$wp_rewrite` exists, fataling with "Call to a member function get_page_permastruct() on null" on the first admin load after activation on a clean install. Both `Schema::maybe_upgrade()` and `WorkflowSchema::maybe_upgrade()` are now deferred to `init` instead of running directly on `plugins_loaded`. Also fixed an "Undefined array key" notice on activation in `Schema.php` (default assessment-component seeding read `$row[5]` on a 5-element array instead of `$row[4]`), and the identical off-by-one in `migrate_third_term_components()`.
* Supplied Plugin Check CSV review: the 80 reported `WordPress.Security.NonceVerification.Recommended` findings are read-only `GET` parameter reads or inputs already protected by nonce-verified state-changing handlers. No meaningless nonces or PHPCS suppressions were added; state-changing admin requests continue to use `check_admin_referer()`/AJAX nonce verification in accordance with WordPress security guidance.
* WordPress.org compliance follow-up: the results deletion action now verifies its nonce before reading the action GET parameters, using one stable nonce action for the delete URL and handler. This is a real CSRF-protection fix, not a Plugin Check suppression.
* Latest WordPress.org review follow-up: fixed the remaining confirmed escaping, input-sanitization, CSV-upload, prepared-SQL placeholder-count, and dynamic-SQL findings from the supplied Plugin Check CSV without changing the plugin version. State-changing admin handlers retain nonce and capability checks; read-only query/filter parameters were not given meaningless nonces solely to silence the analyzer.
* WordPress.org compliance follow-up: fixed the remaining SQL identifier interpolation and input-handling findings from the supplied review CSV without changing the plugin version; kept all database values on `$wpdb->prepare()` and converted internal table identifiers to `%i` placeholders.
* WordPress.org compliance follow-up: added the missing nonce verification to the Advanced Workflow bulk-results and CSV-export admin-post handlers, and sanitizes structured report/bulk input before processing.
* WordPress.org compliance follow-up: the free build no longer uses Freemius license state to unlock result-template functionality; Classic is the only live result-template option in this build.
* Result template settings: replaced the "Five additional designs are previewed below and available in Classynt Pro" copy and its non-functional per-template preview banners (Academic, Comprehensive, Transcript, Progress, Competency) with a single "More result template designs are coming soon." notice — those five designs have no rendering implementation in any build yet, so naming and mock-previewing them was inaccurate rather than a genuine upsell.
* WordPress.org review (Round 3, SQL): the single-line `phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared` comments added in 1.9.9 for identifier-only queries (26 call sites across `includes/Database/*Repository.php`, `Schema.php`, `WorkflowSchema.php`, and the Admin controllers) have been replaced with actual prepared statements, using the `%i` identifier placeholder added to `$wpdb->prepare()` in WordPress 6.2 — a suppression comment was still a suppression, not a fix, and the review explicitly rejected that same reasoning for `AdvancedWorkflowController.php`. `Requires at least` is raised from 6.0 to 6.2 accordingly.
* Follow-up review pass: corrected the remaining sanitize/validate, escaping, prepared-SQL, placeholder-count, and nonce-handler findings identified by the latest supplied Plugin Check CSV, including structured array input, CSV upload handling, and identifier placeholders.
* Removed the now-empty `includes/Pro/` directory left behind after 1.9.9 moved the Pro implementation out of this build; nothing in the codebase references it.
* Compatibility metadata: `Tested up to` now uses the WordPress.org-supported major.minor format (`7.1`) without changing the plugin version.

= 1.9.9 =
* Students admin screen (and the other CRUD-style admin screens — Classes, Sessions, Class & Subjects): form fields now use the same rounded, larger field styling as the teacher dashboard instead of the tighter default used by the results-entry grids.
* Teacher dashboard: added a "Swipe right to see..." hint above the four horizontally-scrolling tables (results-entry roster, Psychomotor ratings, Affective ratings, and the result preview table) so it's clear on narrow screens that there are more columns/fields to the right.
* Removed every blanket, whole-file `phpcs:disable` suppression of WordPress security sniffs (`Security.EscapeOutput`, `Security.NonceVerification`, `Security.ValidatedSanitizedInput`, `DB.PreparedSQL`) that a previous pass had added instead of fixing the underlying code. Every one of the ~40 affected files was re-audited by hand with the suppressions off; genuine gaps found in that audit are listed below, and every identifier-only query (no user-supplied value, only an internally generated table name) now carries a single targeted, justified `phpcs:ignore` comment on that exact line instead of a file-wide disable.
* Fee-based result access control, result locking (Advanced Workflow), section promotion, the "Keep class/session history" preference, subject/class positions, and the audit trail/staff-accountability panel are no longer Pro-gated code paths at all — every one of these was a real, callable handler (AJAX action, admin-post action, or settings write) sitting behind a `LicenseGate::premium_code_available()` check, which is exactly the WordPress.org "trialware" pattern regardless of whether the check itself worked correctly. Each has been reduced to the existing static `ProUpgradeTeaser`/`ComingSoonTeaser` preview banner with no functional implementation behind it in this build; the corresponding AJAX/admin-post actions now return a clean "this is a Pro feature" response instead of processing any request data. Teacher/student management from the teacher dashboard (add/edit student, promote from the dashboard) is fully removed the same way. Report templates other than Classic are presented only as static preview banners, never as a selectable option in a live dropdown.
* `ProUpgradeTeaser`'s decorative preview markup is now passed through `wp_kses()` with an explicit, narrow tag/attribute allowlist instead of being echoed with a `phpcs:ignore` comment suppressing the escaping check.
* `parse_optional_date()` (report-card date fields: class-teacher date, head-teacher date, school-resumes-on) now validates the value is an actual, real calendar date in `Y-m-d` form and discards anything else, instead of only sanitizing it as text.
* CSV bulk-import file uploads (Advanced Workflow and the teacher dashboard) now also verify the file's MIME type via `wp_check_filetype()` alongside the existing extension check and `is_uploaded_file()` validation.
* Every `$_FILES['bulk_csv']['error']`/`['name']` read is explicitly cast/sanitized before use, and the uploaded filename is unslashed before `sanitize_file_name()`.
* Plugin Check: resolved false-positive "input not unslashed" and "nonce verification missing" warnings in the report-card save handler and the Pro audit-trail/fee-status AJAX handlers — the nonce/unslashing was already happening (in the calling method or a shared helper) where the static checker couldn't see it; added explanatory `phpcs:ignore`/`phpcs:disable` comments rather than changing the logic.

= 1.9.8 =
* Fixed a display bug where several admin screens (Results, Report Details, Classes, Sessions, Class Subjects, Students, and the report preview/entry partials) printed a stray `// phpcs:enable` line at the bottom of the page — the comment sat after the closing PHP tag instead of inside it.
* Fixed the public result page failing to render/print on mobile browsers (blank white page, including when saved as PDF) while working correctly on desktop.
* Teacher dashboard: added a "Report card & result access" workspace so a class teacher can now complete a student's full report card (attendance, psychomotor and affective ratings, extracurricular activities, and their own sign-off comment) and see the same read-only calculated-result preview the admin Results screen shows — not just enter subject scores.
* Teacher dashboard: fee-based result access control (mark a student Paid/Outstanding to allow/block their public result) is now available from the teacher dashboard as well as the admin Results screen. This remains a Classynt Pro feature; a free install shows a teacher-audience upgrade teaser instead of a working control.
* The head teacher's sign-off (name, comment, date) is shown to the teacher as read-only — visible as soon as the head teacher enters it from wp-admin, but there is no form field for a teacher to change it, and the save handler never reads those three fields from the teacher's request.
* Internal: extracted the report-context, calculated-result-preview, and fee-status lookup logic out of Admin\ResultsController into a shared Reporting\ReportContextService so the admin and teacher screens use the exact same calculations instead of duplicated copies.
* Re-added the "Early-Bird Launch Offer" notice as a static promo card (coupon code + upgrade link) with no external status check or API call of any kind.
* Moved the working implementation behind section promotion, result locking, and fee-based result access control into `__premium_only`-suffixed methods so they are stripped from the free build, matching how report templates are already handled.
* Explicitly enabled the Freemius Account/license page in the plugin menu configuration.

= 1.9.7 =
* Removed the "Early-Bird Launch Offer" notice and its external status check entirely.
* Moved all inline `<script>`/`<style>` output to properly enqueued assets via `wp_enqueue_script()`/`wp_enqueue_style()` and `wp_add_inline_script()`/`wp_add_inline_style()`.
* Removed the `load_plugin_textdomain()` call (unneeded for WordPress.org-hosted plugins since WP 4.6).
* Hardened nonce/capability checks and input sanitization on several admin and AJAX handlers.

= 1.9.5 =
* Added a dismissible "Classynt Early-Bird Launch Offer" notice on the Classynt dashboard, promoting the 40%-off launch coupon (CLASSYNT30, first 30 qualifying purchases) for schools not yet on Classynt Pro. The notice links to the plugin's existing Freemius upgrade page and does not process payments, coupons, or licenses itself.
* The notice can optionally show a live "N / 30 schools claimed" count and automatically switch to a "fully claimed" message once the coupon is exhausted, if a `classynt_early_bird_status_url` filter has been set pointing at a Classynt-controlled status endpoint (see readme "External services"). Without that filter set, the offer displays without a counter — this is never a hard dependency, and any failure/timeout reaching the endpoint is treated the same as it not being configured at all.

= 1.9.4 =
* Bulk import placeholders (both the "paste rows" box and its instructions) now show the actual assessment components and max scores configured for the selected term — e.g. "Classwork (max 10), Test (max 20)" — instead of a generic "score 1, score 2, score 3". Updates live as the term changes, on the admin's Advanced Workflow page and the teacher dashboard.

= 1.9.3 =
* Result-access fee control (marking students Paid/Outstanding to gate their public result) is now a Classynt Pro feature, along with the matching "Result access" message setting — both are clearly marked and explained on a free install, with an upgrade path.
* Locking results for a session/term/class (Advanced Workflow) is now a Classynt Pro feature, clearly explained on a free install. Existing single-student result saving is unaffected.
* The "Keep class/session history when promoting" setting is now grouped with, and gated the same way as, the Promote a section feature it controls, since one is meaningless without the other.
* Removed the unused Role field/column from the Teachers screen — staff accounts no longer use WordPress roles at all, so this was legacy UI with no effect.
* Teachers can now import results by CSV or pasted rows, and export results to CSV, directly from their own dashboard — scoped to their assigned classes and subjects, using the class/subject/session/term already selected in the result workspace.
* CSV upload fields (Advanced Workflow bulk import and the new teacher dashboard import) now show a Remove button once a file is chosen, so a selected file can be cleared without reopening the file picker.
* Every "Upgrade to Classynt Pro" button across the plugin now links to the plugin's actual in-plugin Pricing page (via the Freemius SDK) instead of the Settings screen. On the teacher dashboard, where staff have no wp-admin access, these now read "Ask your school administrator to upgrade" instead of showing a link they can't use.

= 1.9.2 =
* Renamed the plugin from "Classynt School Results" to "Classynt Schools" (display name, admin menu label, and dashboard headings only — the plugin slug, database tables and option names are unchanged for compatibility).
* Repositioned the plugin description as a full school management platform (students, staff, classes, results, grading, attendance, student/teacher portals) rather than just a results tool, reflecting everything the plugin now does.
* Added a required "External services" disclosure to readme.txt, describing what the bundled Freemius SDK sends and when.
* Trimmed the short description to fit WordPress.org's ~150-character display limit without truncating mid-word.
* Added the directory-listing guard (`index.php`) to two folders that were missing it (`includes/Pro`, `includes/Admin/views`), matching every other folder in the plugin.

= 1.9.1 =
* The per-class section picker on the Teachers screen is now multi-select — a teacher can be assigned to several specific sections of the same class (not just "all" or "one"). "All sections" and specific sections are mutually exclusive within a class.

= 1.9.0 =
* Fixed the teacher dashboard's "Active students" count not updating after adding a student until a manual page refresh.
* The bookshelf loading animation in the teacher result workspace no longer plays for every Class/Subject/Session selection — it now only shows when the Term is selected (the point where the result table actually loads), so stepping through the filters feels instant instead of waiting through an animation at every step.
* Added per-section teacher access control (Pro): on the Teachers screen, admins can now restrict a teacher's class assignment to one specific section (using the class's real section names) instead of always granting the whole class.
* Added a full "Edit teacher" screen so admins can revise an existing teacher's classes, sections and subject assignments — previously these could only be set once, at creation.
* Added an "Edit student" card to the teacher dashboard (Pro): teachers can now update a student's admission number, name, gender, date of birth, club/society, class, section, session, status and admission date, scoped server-side to only the classes and sections they're assigned to.

= 1.8.9 =
* Fixed the grading scale "Apply preset" button on School Setup clearing the hidden row IDs of existing grade bands, which caused the preset to be saved as duplicate rows instead of replacing the existing ones — the old band (e.g. "Standard A–F") could then reappear ahead of the one you just saved. Saving now also cleans up any duplicate grade rows left behind by this from an earlier save.
* Fixed the Academic, Comprehensive, and Progress/Competency report templates showing the original component names (e.g. "CA1"/"CA2") in the printed/portal report even after renaming those components in School Setup's assessment structure (e.g. to "Coursework"/"Midterm"). Column headers are now read from the current assessment structure, matching the Classic template and the Results entry screen.

= 1.8.8 =
* Fixed the School Setup tab showing the "School settings saved successfully" notice twice after saving.
* Admin notices with a decorative header (Teachers, Settings, Advanced Workflow, School Setup) are now more reliably relocated below the header instead of appearing inside it.
* Fixed the class/section dropdowns on the Advanced Workflow "Promote a section" tool giving no feedback while loading, which could look stuck; added a loading state and error handling (same fix applied to the teacher dashboard's promote tool).
* The Teacher screen's role field now shows an explicit default of "Teacher".
* Student and staff portal sign-in no longer triggers a full page reload — the bookshelf loading animation now covers the entire sign-in, and the result / dashboard view is swapped in silently once it's ready.

= 1.8.0 =
* Added a global result-template library with Academic, Comprehensive, Transcript, Progress and Competency layouts.
* Added template selection while keeping assessment and grading data separate from presentation.
* Improved responsive and print styling for global report layouts.


== Upgrade Notice ==

= 1.8.8 =
Fixes a duplicate settings notice, improves admin-notice placement, fixes a slow/stuck-looking promote-section dropdown, and makes student/staff portal sign-in reload-free.

= 1.8.0 =
Added the Phase 3 global result-template library and presentation improvements.


