diff --git a/CHANGELOG.md b/CHANGELOG.md index 868fa1f..a801d59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,46 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.4.5] - 2026-02-02 + +### Fixed + +- Settings now persist correctly across Metrics sub-tabs +- Auth token no longer gets cleared when saving from Selection sub-tab +- Enabled metrics no longer get cleared when saving from Endpoint sub-tab +- Isolated mode setting no longer gets cleared when saving from other sub-tabs + +### Changed + +- Split Metrics settings into separate WordPress option groups per sub-tab +- Each sub-tab now uses its own settings group to prevent cross-tab overwrites + +## [0.4.4] - 2026-02-02 + +### Added + +- Safe mode for metrics collection (default): + - Removes problematic content filters early + - Allows third-party plugins to register `wp_prometheus_collect_metrics` hooks + - Wraps custom hooks in output buffering and try-catch for protection +- Isolated mode option for maximum compatibility: + - Outputs metrics before other plugins fully load + - Use only if Safe mode causes issues +- `WP_PROMETHEUS_ISOLATED_MODE` environment variable support +- Mode comparison table in admin settings + +### Changed + +- Replaced "early mode" with two clear modes: Safe (default) and Isolated +- Custom metrics hooks now fire by default with protection against recursion +- Filter removal now also includes `the_content_feed` and `comment_text` +- Updated admin UI with clearer explanations of each mode + +### Fixed + +- Third-party plugins can now add custom metrics without memory issues +- Twig-based plugins (like wp-fedistream) no longer cause recursion + ## [0.4.3] - 2026-02-02 ### Added diff --git a/CLAUDE.md b/CLAUDE.md index 4639080..68d8252 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -291,6 +291,50 @@ add_action( 'wp_prometheus_collect_metrics', function( $collector ) { ## Session History +### 2026-02-02 - Settings Persistence Fix (v0.4.5) + +- Fixed critical bug where settings would get cleared when saving from different Metrics sub-tabs +- Root cause: All settings were registered under single `wp_prometheus_metrics_settings` group + - When saving from "Endpoint" sub-tab, only auth token was in POST data + - WordPress Settings API would process all registered settings in the group + - Missing fields (enabled_metrics, isolated_mode) would receive null/undefined + - Sanitize callbacks returned empty values, overwriting existing settings +- Solution: Split into separate settings groups per sub-tab: + - `wp_prometheus_endpoint_settings` for auth token + - `wp_prometheus_selection_settings` for enabled metrics + - `wp_prometheus_advanced_settings` for isolated mode +- **Key Learning**: WordPress Settings API and multiple forms + - When multiple forms share the same settings group, saving one form can clear settings from another + - Each form with `settings_fields()` should use a unique option group + - `register_setting()` group name must match `settings_fields()` group name + +### 2026-02-02 - Safe Mode & Custom Hooks Fix (v0.4.4) + +- Redesigned metrics collection to support both plugin compatibility AND custom metrics: + - **Safe Mode (default)**: Removes content filters early but lets WordPress load normally + - **Isolated Mode**: Legacy early mode that skips custom hooks entirely +- Implementation: + - `WP_PROMETHEUS_METRICS_REQUEST` constant set for any /metrics request + - Content filters removed via `plugins_loaded` hook at priority 0 + - Collector fires `wp_prometheus_collect_metrics` with protection (output buffering, try-catch) + - `wp_prometheus_isolated_mode` option replaces `wp_prometheus_disable_early_mode` + - `WP_PROMETHEUS_ISOLATED_MODE` environment variable for containerized deployments +- Collector now wraps custom hooks in `fire_custom_metrics_hook()` method: + - Removes content filters again before hook (in case re-added) + - Uses output buffering to discard accidental output + - Catches exceptions to prevent breaking metrics output + - Logs errors when WP_DEBUG is enabled +- Updated admin UI with mode comparison table +- **Key Learning**: Hybrid approach for plugin compatibility + - The memory issue comes from content filter recursion, not just plugin loading + - Removing filters early (before any plugin can trigger them) prevents recursion + - Plugins still load and can register their `wp_prometheus_collect_metrics` hooks + - Hooks fire after filters are removed, in a protected context +- **Key Learning**: Defense in depth for custom hooks + - Remove filters again right before hook fires (plugins may re-add them) + - Output buffering catches any echo/print from misbehaving plugins + - Try-catch prevents one broken plugin from breaking metrics entirely + ### 2026-02-02 - Sub-tabs & Early Mode Fix (v0.4.3) - Split Metrics tab into sub-tabs for better organization: diff --git a/assets/css/admin.css b/assets/css/admin.css index 54b908e..cb552e5 100644 --- a/assets/css/admin.css +++ b/assets/css/admin.css @@ -16,7 +16,7 @@ .wp-prometheus-subtab-nav { display: flex; - margin: 0 0 20px 0; + margin: 0; padding: 0; list-style: none; border-bottom: 1px solid #c3c4c7; diff --git a/src/Admin/Settings.php b/src/Admin/Settings.php index 9b37afb..dd527ac 100644 --- a/src/Admin/Settings.php +++ b/src/Admin/Settings.php @@ -107,18 +107,20 @@ class Settings { * @return void */ public function register_settings(): void { - // Register settings for metrics tab. - register_setting( 'wp_prometheus_metrics_settings', 'wp_prometheus_auth_token', array( + // Register settings for endpoint sub-tab. + register_setting( 'wp_prometheus_endpoint_settings', 'wp_prometheus_auth_token', array( 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field', ) ); - register_setting( 'wp_prometheus_metrics_settings', 'wp_prometheus_enabled_metrics', array( + // Register settings for selection sub-tab. + register_setting( 'wp_prometheus_selection_settings', 'wp_prometheus_enabled_metrics', array( 'type' => 'array', 'sanitize_callback' => array( $this, 'sanitize_metrics' ), ) ); - register_setting( 'wp_prometheus_metrics_settings', 'wp_prometheus_disable_early_mode', array( + // Register settings for advanced sub-tab. + register_setting( 'wp_prometheus_advanced_settings', 'wp_prometheus_isolated_mode', array( 'type' => 'boolean', 'sanitize_callback' => 'rest_sanitize_boolean', 'default' => false, @@ -484,7 +486,7 @@ class Settings { private function render_metrics_endpoint_subtab(): void { ?>