Skip to content

v6.20.0

Choose a tag to compare

@github-actions github-actions released this 23 Aug 22:03
· 5 commits to main since this release
e01ed47

Added

  • Email texts hub — every plugin email editable in one place (#964, #965): a new Email texts hub lets an admin edit the global default subject + body of every token-based plugin email — the certificate email, recruitment convocation, the three reregistration emails, audience booking/cancellation, and (tokenized from former echo-partials) the self-scheduling booking confirmation, the five appointment lifecycle emails (approval, cancellation, reminder, waitlist-promotion, waitlisted) and the access-granted + calendar-deletion notices. Each is a wp_editor with {{token}} help, pre-rendered button/block tokens ({{receipt_button}}, {{cancel_button}}, {{waitlist_button}}, {{dashboard_button}}, {{cancellation_reason_block}}, …) and a "Restore Default Text" button. Built on a global-override store (ffc_email_bodies + EmailTemplates::effective_body() cascade, dormant when empty) and gated by a dedicated ffc_manage_email_templates capability (one-shot migration seeds it onto current Settings holders). Forms and per-calendar/audience bodies can still override; a per-form Global/Custom toggle decides whether a form follows the hub. Unconfigured installs render identically.
  • Two documentation hub pages + a Documentation-tab refresh (#976): adds Email texts hub and Document Templates hub pages, and brings the Documentation tab in line with the current plugin — Emails & Delivery (three tabs, all editable emails), the per-form Global/Custom toggle, pool-backed certificate/ficha/receipt templates, and Personal Calendars (custom calendars, waitlist/promotion, per-user block cap, ffc_bypass_appointment_capacity); the Developer page gains the ClientIpResolver filters, ffcertificate_ficha_template_html and the shared batched-CSV-export engine. Ten legacy "Section N / #141" docblocks migrated. Documentation-only.
  • Document Templates hub — pool-backed certificate, ficha & receipt templates (#945, #951): a read-only "Current assignments" overview plus editable/duplicable pool templates for the reregistration ficha (new ficha kind, seeded default, selected on a new Reregistration settings tab, resolves via ffcertificate_ficha_template_html) and the appointment receipt (a _ffc_template_kind discriminator — absent = certificate, fully retrocompatible; Regular + Custom defaults, per-mode selection on a new Scheduling → Receipt tab; adds {{appointment_end}} / {{appointment_time_range}} tokens). No data migration; unconfigured installs render exactly as before.
  • "All plugin emails" directory (#951): a read-only index listing every email the plugin can send, grouped by feature, each with a purpose, a personalisation state (Editable text / On-off only / System default) and an Open → deep-link. Discoverability only — no control or capability moves; each group gated by its view cap.
  • Self-scheduling: custom calendars, waitlist & per-user block cap (#941): calendars can use a custom schedule type — explicit date/time blocks with per-block vacancies — instead of the regular weekday pattern (mode locks once a calendar has bookings). A per-calendar waitlist (waitlist_enabled, optional capacity) queues bookings when a slot/block is full and auto-promotes the oldest queued entry (transactional FOR UPDATE, promotion email) when a spot frees; a max_blocks_per_user cap limits distinct blocks per user (counts active + waitlisted; admin overbook via ffc_bypass_appointment_capacity skips it) with a read-only Occupancy Report meta box. All off/empty by default; existing calendars unchanged.
  • IP Diagnostics detects Cloudflare behind a host proxy (#920): a new cloudflare_via_proxy verdict for the CF → host-LB → PHP topology — the secure strategy auto-trusts CF-Connecting-IP when the TCP peer is a private/reserved load balancer with a Cloudflare edge as the first public X-Forwarded-For hop. The tab is redesigned (Legacy×Secure comparison, a headers table with a Situation column incl. CF-Ray, and a warning against pasting Cloudflare ranges into the custom-proxy field).
  • Cloudflare page-cache safety check (#921): behind Cloudflare, the Cache tab runs a best-effort loopback probe of the edge cf-cache-status and warns if HTML is being cached (a "Cache Everything"/APO misconfiguration that can serve forms stale or leak the per-user dashboard), with guidance to exclude FFC URLs. Result cached up to 6h.

Changed

  • One consistent standard across all default emails + normalized subjects (#976): every plugin email now follows a single skeleton — an <h2> event title (no emoji, semantic colour: green = confirmed/approved, red = cancelled, amber = reminder, purple = waitlist, blue = informational), a greeting, one context line and a details box — and every subject the shared Event: {{reference}} shape (colon, no [{{site_name}}] prefix, no trailing dashes). The audience booking/cancellation emails gained their previously-missing subjects; admin notifications keep the visual pattern; audience emails drop their body-level sign-off for the shared Email Model footer; CTAs harmonised to brand blue. ⚠️ Because the shipped defaults changed, a per-form/schedule/calendar body still holding the old default now reads as Custom (keeps its text) until "Restore Default Text"; blank (Global-tracking) entities render the new standard automatically.
  • Email settings restructured into three tabs (#976): the overloaded SMTP tab is split into SMTP (transport + the global "Disable all emails" switch), Email Model (the shared chrome editor + preview + test-send) and Email texts (the per-email hub + directory), ordered SMTP → Email Model → Email texts. The Email texts hub edits one email at a time via a feature-grouped selector with TinyMCE initialized on demand instead of stacking ~15 editors; a single "Save email texts" persists all, degrading gracefully to plain textareas. Save flows unchanged — a relocation; every directory deep-link points at the new tab.
  • Recruitment convocation email absorbed into the hub (#964): its subject + body are edited in the Email texts hub with every other email instead of the bespoke Recruitment → Settings editor (retired, replaced by a link); the dispatcher resolves through EmailTemplates::effective_body('recruitment-convocation', …), and email_subject/email_body_html are removed from ffc_recruitment_settings. A one-shot migration (ffc_recruitment_email_hub_v1) moves any customised text into the hub. ⚠️ The convocation body now passes through wp_kses_post (previously arbitrary admin HTML) — an accepted, admin-cap-gated tightening.
  • Settings side-nav grouped into domain sections + soft-blue hover (#951): the 17-item Settings nav (page=ffc-settings) — previously flat alphabetical — now renders under seven subheadings (General · Content · Communication · Security & Access · Tools · Go to · System) via a new SettingsTab::get_group(), staying alphabetical within each and a single ARIA tablist (axe-clean). The Document Templates hub is reached from a Settings tab (the ffc_cert_template CPT relabelled kind-neutral, its standalone menu item dropped), and the Scheduling → Receipt tab is now a pure selector that links into that hub. Nav item hover/focus uses the theme-aware --ffc-primary-light tint. No tab content changes.
  • IP reads unified on one global strategy toggle (#927, #931): rate-limiting, geofencing, the public listing throttle and logging now resolve the client IP through the shared ClientIpResolver following the single legacy/secure strategy on the IP Diagnostics tab, with secure (unspoofable behind Cloudflare / a configured proxy) recommended; the rate-limit log's ip_address records the IP actually enforced, and public CSV-download audit logs use the same resolver (unresolvable → 0.0.0.0). ⚠️ Breaking: the client-spoofable ffc_trust_forwarded_headers filter and the interim ffc_rate_limit_ip_source filter/control are removed — set the strategy to secure instead.
  • Internal (#945, #949, #950) — code-reuse sweeps: consolidated wall-clock date/time validation onto DateFormatter::is_valid_time() / is_valid_date() (replacing ~6 hand-rolled regex copies); extracted the shared CodeMirror initializer into window.FFCCodeEditor (ffc-code-editor-core.js) used by the form-editor, cert-template and receipt editors (restoring the placeholder overlay / dark theme / disabled notice the receipt tab had lost); folded the Email Model logo picker into ffc-branding-media.js; migrated three $.post callers to FFC.request; and added RequestInput::is_truthy(), SettingsTab::should_enqueue_on() and Core\Utils::read_file_contents(). Behaviour unchanged; tests added.
  • Internal (#935) — comment-only cleanups: dropped the namespace-migration (Phase N) codename from ~50 class docblocks + the bootstrap (issue-anchored phase refs untouched), pointed DocumentFormatter::validate_phone() at the PHONE_REGEX constant, and removed 18 files' worth of auto-generated duplicate docblock summary lines (492 lines). No runtime change.

Removed

  • Dead-code sweep — orphaned AJAX handlers, helpers & constants (#935): removes ten admin-ajax actions with zero JS/template caller (each superseded by a live path) — the two audience placeholders ffc_audience_create_booking / ffc_audience_get_schedule_slots, the five URL-shortener row actions ffc_{delete,toggle,trash,restore,empty_trash}_short_url(s), ffc_audience_check_conflicts, ffc_generate_tickets and ffc_preview_date_format — plus two unused helpers (CsvExportTrait::extract_dynamic_values, SettingsTab::get_tab_url), several never-read constants (FFC_MIN_WP_VERSION, FFC_MIN_PHP_VERSION, FFC_JQUERY_UI_VERSION, RateLimitChecker::WEAK_SIGNALS, two ActivityLog::ACTION_*) and a vestigial no-op (SelfSchedulingEditor::display_save_errors()). No user-facing behaviour change.

Fixed

  • Settings-nav icons render uniformly monochrome (#951): the tab-nav glyphs are emoji (.ffc-icon-*), and some codepoints (🆔, 👤) render in colour in the admin's emoji font while most render flat — an inconsistency impossible to fix per-glyph without whack-a-mole. A single filter: grayscale(1) on .ffc-settings-tabs__icon desaturates every nav icon uniformly, so any glyph (present or future) reads monochrome regardless of platform. Supersedes the per-glyph icon swaps below. CSS-only.
  • Frontend accessibility: labelled honeypot + named environment filter (#951): the anti-spam honeypot input (ffc_honeypot_trap) on the certificate, self-scheduling and reregistration forms is now wrapped by its existing <label> (it was rendered off-screen — not display:none — so it stayed in the accessibility tree, meaning a screen-reader user could fill the "invisible" trap and be rejected as a bot); and the audience calendar's environment filter <select> gains an aria-label. Behaviour-preserving — the spam check keys on the field name, unchanged — and no new violations introduced (implicit label association, so no duplicate-id). Found via a one-off axe/WCAG 2.2 AA pass.
  • Reregistration settings-tab icon back to monochrome (#951): the new Recadastramento tab used the ffc-icon-id badge (🆔), which the admin emoji font renders as a solid colour and broke the flat/mono icon row in the Settings nav; switched to the ffc-icon-clipboard glyph, which that font renders monochrome (as the Activity-Log tab already does). CSS-class-only change; the ffc-icon-id badge stays where an ID connotation fits (CPF rate-limit heading, CPF-split migration card).
  • pt_BR translations for recent features (#951): the appointment-receipt / Document Templates hub UI, the self-scheduling waitlist and custom-calendar/occupancy strings (#941), and the new Settings "Document Templates" tab were showing in English — the pt_BR catalog is brought up to date (73 strings) and the runtime .mo / .l10n.php regenerated so they load. Translation assets only; no code change.
  • Submission auto-delete now works — and is explicitly opt-in (#936): the daily cleanup read a standalone ffc_cleanup_days option that was never written (the value lives in ffc_settings['cleanup_days']), so age-based deletion of old submissions never ran regardless of the configured retention — a silent data-retention gap. It now reads the real setting, gated behind a new "Auto-delete old submissions" toggle (default off) plus a day window (≥ 1, default 365). ⚠️ Because the feature was dormant, it ships off so upgrades change no behaviour; enabling it will permanently delete published submissions older than the window on the next daily run.
  • In-admin Documentation tab accuracy (#934): the Template Variables reference now describes {{date}} / {{fill_date}} as the submission date (alias of {{submission_date}}), not the PDF generation date, and drops {{nome}} (only satisfies save-time validation, never renders); Quiz {{score}} / {{max_score}} are documented as point sums, not answer/question counts; and a stale "Settings → Geofence" cross-reference now points to "Settings → Geolocation". pt_BR translations updated to match.

Security

  • Self-scheduling confirmation escapes its scalar tokens (#965): the booking-confirmation email now esc_html-escapes the user- and admin-supplied scalar values it substitutes ({{user_name}}, {{user_email}}, {{calendar_title}}, notes) and sanitises the per-calendar custom body with wp_kses_post (was sanitize_textarea_field), so an editable/tokenized body can never inject raw HTML from booking data.
  • Per-user dashboard kept off the Cloudflare edge cache (#921): the [user_dashboard_personal] page now also emits Cloudflare-CDN-Cache-Control: no-store / CDN-Cache-Control: no-store — Cloudflare ignores DONOTCACHEPAGE / X-LiteSpeed-Cache-Control, so these edge-specific directives keep per-user HTML from being shared across visitors under CDN cache rules that honour them.
  • Recruitment public listing throttle is now fail-closed (#927, #931): the per-IP rate limit on [ffc_recruitment_queue] resolves the client IP via the shared resolver (RequestInput::get_user_ip()) instead of a bespoke header walk, and no longer waves through a caller whose IP can't be identified — they share the 0.0.0.0 bucket. Closes the fail-open gap; header-rotation evasion is ineffective once the secure strategy is enabled.