speakers-for-the-events-cal.../CHANGELOG.md
Laurence Horrocks-Barlow fef0766e67 v1.0.1 — security hardening, TEC integration fixes, and documentation
Security:
- Validate CSV upload MIME type server-side via finfo
- Deliver import notices via per-user transient (prevents GET-param spoofing)
- Sanitise translatable success string with wp_kses to block HTML injection
- Switch sanitize_url to esc_url_raw; wp_kses_post to sanitize_textarea_field for plain-text bio

Bug fixes:
- Guard preg_replace null return in normalise_name() to prevent TypeError on PHP 8
- Replace generic save_post hook with save_post_tec_speaker / save_post_tribe_events
  so saves no longer need a manual revision check and cannot interact with TEC's own
  save_post handler at priority 15

TEC integration:
- Check for tribe-select2 / tribe-select2-css handles first (TEC ships SelectWoo,
  not vanilla Select2); CDN was previously always loaded unnecessarily
- Type-specific save hooks make event/speaker save paths explicit and independent

Improvements:
- Add register_activation_hook to flush rewrite rules on activation
- Wrap instantiation in plugins_loaded so TEC is guaranteed loaded first
- Show admin notice and skip TEC-specific hooks when TEC is inactive
- Cap event picker query at PICKER_LIMIT = 200 (was unbounded -1)
- Register front-end CSS via wp_add_inline_style on wp_enqueue_scripts
- absint() on speaker IDs in option value attributes

Documentation:
- Write full README.md (was blank)
- Add CHANGELOG.md with detailed 1.0.0 and 1.0.1 entries

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 08:32:33 +01:00

4 KiB

Changelog

All notable changes to this project will be documented in this file.


[1.0.1] — 2026-05-17

Security

  • CSV MIME validation — the importer now checks the uploaded file's MIME type server-side via finfo before opening it. The browser-side accept=".csv" attribute is not a security control and was the only prior gate.
  • Admin notice spoofing — import result banners (success/error) are now delivered via a per-user transient rather than raw GET parameters. A crafted URL can no longer display false success or error messages to an admin.
  • HTML in translatable string — the success notice now passes through wp_kses() restricted to <strong>, preventing a tampered translation file from injecting arbitrary markup.
  • esc_url_raw over sanitize_url — switched to the canonical WordPress function for storing URLs (functionally equivalent; sanitize_url is an undocumented alias).
  • sanitize_textarea_field for CSV bio — the importer previously used wp_kses_post(), which permitted HTML in a field described to users as plain-text. Now consistently plain-text.

Bug fixes

  • normalise_name() null returnpreg_replace() returns null on failure (e.g. backtracking limit, invalid UTF-8). Both calls now fall back to the input string via ?? $name, preventing a TypeError on PHP 8.
  • Revision saves — the generic save_post hook was replaced with type-specific save_post_tec_speaker and save_post_tribe_events hooks. save_post_tribe_events does not fire for revisions (which have post type 'revision'), so the separate wp_is_post_revision() guard is no longer needed.

Integration

  • Correct SelectWoo handles — The Events Calendar ships SelectWoo (a Select2 fork) under the handles tribe-select2 (JS) and tribe-select2-css (CSS), not select2. The admin script loader now checks for tribe-select2 first, then select2, then falls back to a CDN copy. Previously, TEC's registration was never detected and the CDN was always loaded unnecessarily.
  • Type-specific save hooks — replaced the single generic save_post hook (priority 10) with save_post_tec_speaker and save_post_tribe_events. TEC hooks its own meta save to save_post at priority 15; using type-specific hooks eliminates any ordering dependency and makes intent explicit.

Improvements

  • Activation hook — added register_activation_hook to register the CPT and flush rewrite rules on activation, fixing the "Speaker archive returns 404 until Permalinks are re-saved" issue on first install.
  • plugins_loaded wrapper — the plugin is now instantiated inside add_action('plugins_loaded', …) instead of at file-include time, ensuring all plugins (including TEC) are loaded before the constructor runs.
  • TEC dependency notice — if The Events Calendar is not active, an admin notice is shown. TEC-specific hooks (event display, event meta box) are skipped; the Speaker CPT, admin menu, and shortcode remain functional.
  • Admin picker cap — the event speaker picker query is capped at 200 results (PICKER_LIMIT constant) instead of an unbounded posts_per_page => -1, preventing memory issues on large installs.
  • absint() on option values — speaker IDs written into <option value> attributes are now explicitly cast with absint().
  • Styles via wp_add_inline_style — front-end CSS is now registered through WordPress's style system (wp_register_style + wp_add_inline_style on wp_enqueue_scripts) rather than echoed as a raw <style> tag mid-content. Caching, minification, and CSP plugins can now manage the styles correctly.

[1.0.0] — 2026-05-16

Initial release.

  • tec_speaker custom post type with title, editor, excerpt, featured image, website URL, and email.
  • Searchable multi-select speaker picker on event edit screens (Select2/SelectWoo).
  • Automatic speaker display beneath event meta on single event pages.
  • [tec_speakers] shortcode with limit and search attributes.
  • CSV bulk importer with duplicate-name detection and honorific normalisation.