2 Commits

Author SHA1 Message Date
e5f2edbafa fix: Separate settings groups to prevent cross-tab overwrites (v0.4.5)
All checks were successful
Create Release Package / build-release (push) Successful in 1m2s
Split Metrics sub-tab settings into separate WordPress option groups:
- wp_prometheus_endpoint_settings for auth token
- wp_prometheus_selection_settings for enabled metrics
- wp_prometheus_advanced_settings for isolated mode

This fixes the bug where saving from one sub-tab would clear settings
from other sub-tabs due to all settings sharing a single option group.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 23:12:41 +01:00
7f0b6ec8a6 docs: Add version mismatch learning to CLAUDE.md
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 21:50:56 +01:00
6 changed files with 268 additions and 55 deletions

View File

@@ -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/), 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). 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 ## [0.4.3] - 2026-02-02
### Added ### Added

View File

@@ -291,6 +291,50 @@ add_action( 'wp_prometheus_collect_metrics', function( $collector ) {
## Session History ## 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) ### 2026-02-02 - Sub-tabs & Early Mode Fix (v0.4.3)
- Split Metrics tab into sub-tabs for better organization: - Split Metrics tab into sub-tabs for better organization:
@@ -304,6 +348,10 @@ add_action( 'wp_prometheus_collect_metrics', function( $collector ) {
- Settings must be inside `<form action="options.php">` with `settings_fields()` call - Settings must be inside `<form action="options.php">` with `settings_fields()` call
- Each sub-tab needs its own form wrapper for proper saving - Each sub-tab needs its own form wrapper for proper saving
- Sub-tabs use URL query parameter (`subtab`) within the main tab - Sub-tabs use URL query parameter (`subtab`) within the main tab
- **Key Learning**: WordPress plugin versioning requires TWO updates
- Plugin header comment `Version: x.x.x` (line ~6) - used by WordPress admin
- PHP constant `WP_PROMETHEUS_VERSION` (line ~133) - used internally
- CI/CD checks both must match the git tag, causing release failures if mismatched
### 2026-02-02 - Early Mode Toggle (v0.4.2) ### 2026-02-02 - Early Mode Toggle (v0.4.2)

View File

@@ -16,7 +16,7 @@
.wp-prometheus-subtab-nav { .wp-prometheus-subtab-nav {
display: flex; display: flex;
margin: 0 0 20px 0; margin: 0;
padding: 0; padding: 0;
list-style: none; list-style: none;
border-bottom: 1px solid #c3c4c7; border-bottom: 1px solid #c3c4c7;

View File

@@ -107,18 +107,20 @@ class Settings {
* @return void * @return void
*/ */
public function register_settings(): void { public function register_settings(): void {
// Register settings for metrics tab. // Register settings for endpoint sub-tab.
register_setting( 'wp_prometheus_metrics_settings', 'wp_prometheus_auth_token', array( register_setting( 'wp_prometheus_endpoint_settings', 'wp_prometheus_auth_token', array(
'type' => 'string', 'type' => 'string',
'sanitize_callback' => 'sanitize_text_field', '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', 'type' => 'array',
'sanitize_callback' => array( $this, 'sanitize_metrics' ), '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', 'type' => 'boolean',
'sanitize_callback' => 'rest_sanitize_boolean', 'sanitize_callback' => 'rest_sanitize_boolean',
'default' => false, 'default' => false,
@@ -484,7 +486,7 @@ class Settings {
private function render_metrics_endpoint_subtab(): void { private function render_metrics_endpoint_subtab(): void {
?> ?>
<form method="post" action="options.php"> <form method="post" action="options.php">
<?php settings_fields( 'wp_prometheus_metrics_settings' ); ?> <?php settings_fields( 'wp_prometheus_endpoint_settings' ); ?>
<h3><?php esc_html_e( 'Authentication', 'wp-prometheus' ); ?></h3> <h3><?php esc_html_e( 'Authentication', 'wp-prometheus' ); ?></h3>
<p class="description"><?php esc_html_e( 'Configure authentication for the /metrics endpoint.', 'wp-prometheus' ); ?></p> <p class="description"><?php esc_html_e( 'Configure authentication for the /metrics endpoint.', 'wp-prometheus' ); ?></p>
@@ -513,7 +515,7 @@ class Settings {
private function render_metrics_selection_subtab(): void { private function render_metrics_selection_subtab(): void {
?> ?>
<form method="post" action="options.php"> <form method="post" action="options.php">
<?php settings_fields( 'wp_prometheus_metrics_settings' ); ?> <?php settings_fields( 'wp_prometheus_selection_settings' ); ?>
<h3><?php esc_html_e( 'Enabled Metrics', 'wp-prometheus' ); ?></h3> <h3><?php esc_html_e( 'Enabled Metrics', 'wp-prometheus' ); ?></h3>
<p class="description"><?php esc_html_e( 'Select which metrics to expose on the /metrics endpoint.', 'wp-prometheus' ); ?></p> <p class="description"><?php esc_html_e( 'Select which metrics to expose on the /metrics endpoint.', 'wp-prometheus' ); ?></p>
@@ -566,57 +568,93 @@ class Settings {
* @return void * @return void
*/ */
private function render_metrics_advanced_subtab(): void { private function render_metrics_advanced_subtab(): void {
$disabled = get_option( 'wp_prometheus_disable_early_mode', false ); $isolated_mode = get_option( 'wp_prometheus_isolated_mode', false );
$env_override = false !== getenv( 'WP_PROMETHEUS_DISABLE_EARLY_MODE' ); $env_override = false !== getenv( 'WP_PROMETHEUS_ISOLATED_MODE' );
$early_active = defined( 'WP_PROMETHEUS_EARLY_METRICS' ) && WP_PROMETHEUS_EARLY_METRICS; $is_metrics_request = defined( 'WP_PROMETHEUS_METRICS_REQUEST' ) && WP_PROMETHEUS_METRICS_REQUEST;
$is_isolated = defined( 'WP_PROMETHEUS_ISOLATED_MODE' ) && WP_PROMETHEUS_ISOLATED_MODE;
?> ?>
<form method="post" action="options.php"> <form method="post" action="options.php">
<?php settings_fields( 'wp_prometheus_metrics_settings' ); ?> <?php settings_fields( 'wp_prometheus_advanced_settings' ); ?>
<h3><?php esc_html_e( 'Early Mode', 'wp-prometheus' ); ?></h3> <h3><?php esc_html_e( 'Metrics Collection Mode', 'wp-prometheus' ); ?></h3>
<p class="description">
<?php esc_html_e( 'Early mode intercepts /metrics requests before full WordPress initialization. This prevents memory exhaustion issues caused by some plugins (e.g., Twig-based themes/plugins) but disables the wp_prometheus_collect_metrics hook for custom metrics.', 'wp-prometheus' ); ?> <div class="notice notice-info inline" style="padding: 12px; margin: 15px 0;">
</p> <p><strong><?php esc_html_e( 'Safe Mode (Default)', 'wp-prometheus' ); ?></strong></p>
<p><?php esc_html_e( 'Content filters are removed early to prevent memory issues with Twig-based plugins, but WordPress loads normally. Third-party plugins can add custom metrics via the wp_prometheus_collect_metrics hook.', 'wp-prometheus' ); ?></p>
</div>
<?php if ( $env_override ) : ?> <?php if ( $env_override ) : ?>
<div class="notice notice-info inline" style="padding: 12px; margin: 15px 0;"> <div class="notice notice-warning inline" style="padding: 12px; margin: 15px 0;">
<strong><?php esc_html_e( 'Environment Override Active', 'wp-prometheus' ); ?></strong> <strong><?php esc_html_e( 'Environment Override Active', 'wp-prometheus' ); ?></strong>
<p><?php esc_html_e( 'Early mode is configured via WP_PROMETHEUS_DISABLE_EARLY_MODE environment variable. Admin settings will be ignored.', 'wp-prometheus' ); ?></p> <p><?php esc_html_e( 'Mode is configured via WP_PROMETHEUS_ISOLATED_MODE environment variable. Admin settings will be ignored.', 'wp-prometheus' ); ?></p>
</div> </div>
<?php endif; ?> <?php endif; ?>
<table class="form-table" role="presentation"> <table class="form-table" role="presentation">
<tr> <tr>
<th scope="row"><?php esc_html_e( 'Disable Early Mode', 'wp-prometheus' ); ?></th> <th scope="row"><?php esc_html_e( 'Isolated Mode', 'wp-prometheus' ); ?></th>
<td> <td>
<label> <label>
<input type="checkbox" name="wp_prometheus_disable_early_mode" value="1" <input type="checkbox" name="wp_prometheus_isolated_mode" value="1"
<?php checked( $disabled ); ?> <?php checked( $isolated_mode ); ?>
<?php disabled( $env_override ); ?>> <?php disabled( $env_override ); ?>>
<?php esc_html_e( 'Disable early metrics interception', 'wp-prometheus' ); ?> <?php esc_html_e( 'Enable isolated mode', 'wp-prometheus' ); ?>
</label> </label>
<p class="description"> <p class="description">
<?php esc_html_e( 'When disabled, metrics are collected through normal WordPress template loading. This enables the wp_prometheus_collect_metrics hook for custom metrics but may cause issues with some plugins.', 'wp-prometheus' ); ?> <?php esc_html_e( 'Isolated mode outputs metrics immediately before other plugins fully load. This provides maximum isolation but disables the wp_prometheus_collect_metrics hook. Use this only if you experience issues with Safe Mode.', 'wp-prometheus' ); ?>
</p> </p>
</td> </td>
</tr> </tr>
<tr> <tr>
<th scope="row"><?php esc_html_e( 'Current Status', 'wp-prometheus' ); ?></th> <th scope="row"><?php esc_html_e( 'Current Status', 'wp-prometheus' ); ?></th>
<td> <td>
<?php if ( $early_active ) : ?> <?php if ( $is_isolated ) : ?>
<span class="dashicons dashicons-lock" style="color: orange;"></span>
<?php esc_html_e( 'Isolated mode active - custom hooks are disabled', 'wp-prometheus' ); ?>
<?php elseif ( $is_metrics_request ) : ?>
<span class="dashicons dashicons-yes-alt" style="color: green;"></span> <span class="dashicons dashicons-yes-alt" style="color: green;"></span>
<?php esc_html_e( 'Early mode is active (this request was served via early interception)', 'wp-prometheus' ); ?> <?php esc_html_e( 'Safe mode active - custom hooks enabled with filter protection', 'wp-prometheus' ); ?>
<?php elseif ( $disabled || $env_override ) : ?> <?php elseif ( $isolated_mode ) : ?>
<span class="dashicons dashicons-dismiss" style="color: gray;"></span> <span class="dashicons dashicons-lock" style="color: orange;"></span>
<?php esc_html_e( 'Early mode is disabled', 'wp-prometheus' ); ?> <?php esc_html_e( 'Isolated mode enabled (active for /metrics requests)', 'wp-prometheus' ); ?>
<?php else : ?> <?php else : ?>
<span class="dashicons dashicons-yes-alt" style="color: green;"></span> <span class="dashicons dashicons-yes-alt" style="color: green;"></span>
<?php esc_html_e( 'Early mode is enabled (active for /metrics requests)', 'wp-prometheus' ); ?> <?php esc_html_e( 'Safe mode enabled (default) - custom hooks with filter protection', 'wp-prometheus' ); ?>
<?php endif; ?> <?php endif; ?>
</td> </td>
</tr> </tr>
</table> </table>
<hr style="margin: 20px 0;">
<h4><?php esc_html_e( 'Mode Comparison', 'wp-prometheus' ); ?></h4>
<table class="widefat striped" style="max-width: 700px;">
<thead>
<tr>
<th><?php esc_html_e( 'Feature', 'wp-prometheus' ); ?></th>
<th><?php esc_html_e( 'Safe Mode', 'wp-prometheus' ); ?></th>
<th><?php esc_html_e( 'Isolated Mode', 'wp-prometheus' ); ?></th>
</tr>
</thead>
<tbody>
<tr>
<td><?php esc_html_e( 'Custom metrics hook', 'wp-prometheus' ); ?></td>
<td><span class="dashicons dashicons-yes" style="color: green;"></span></td>
<td><span class="dashicons dashicons-no" style="color: red;"></span></td>
</tr>
<tr>
<td><?php esc_html_e( 'Plugin compatibility', 'wp-prometheus' ); ?></td>
<td><?php esc_html_e( 'High', 'wp-prometheus' ); ?></td>
<td><?php esc_html_e( 'Maximum', 'wp-prometheus' ); ?></td>
</tr>
<tr>
<td><?php esc_html_e( 'Memory usage', 'wp-prometheus' ); ?></td>
<td><?php esc_html_e( 'Normal', 'wp-prometheus' ); ?></td>
<td><?php esc_html_e( 'Minimal', 'wp-prometheus' ); ?></td>
</tr>
</tbody>
</table>
<?php submit_button(); ?> <?php submit_button(); ?>
</form> </form>
<?php <?php

View File

@@ -121,14 +121,62 @@ class Collector {
/** /**
* Fires after default metrics are collected. * Fires after default metrics are collected.
* *
* Skip in early metrics mode to avoid triggering third-party hooks * In isolated mode, skip custom hooks to avoid any potential issues.
* that may cause recursion issues (e.g., Twig-based plugins). * In safe mode (default), fire hooks with protection against recursion.
* *
* @param Collector $collector The metrics collector instance. * @param Collector $collector The metrics collector instance.
*/ */
if ( ! defined( 'WP_PROMETHEUS_EARLY_METRICS' ) || ! WP_PROMETHEUS_EARLY_METRICS ) { if ( defined( 'WP_PROMETHEUS_ISOLATED_MODE' ) && WP_PROMETHEUS_ISOLATED_MODE ) {
do_action( 'wp_prometheus_collect_metrics', $this ); // Isolated mode: skip all third-party hooks for maximum safety.
return;
} }
// Safe mode: fire custom hooks with protection.
$this->fire_custom_metrics_hook();
}
/**
* Fire custom metrics hook with protection against recursion.
*
* Removes potentially problematic filters, uses output buffering,
* and catches any errors from third-party plugins.
*
* @return void
*/
private function fire_custom_metrics_hook(): void {
// Remove content filters again (in case any plugin re-added them).
if ( function_exists( 'wp_prometheus_remove_content_filters' ) ) {
wp_prometheus_remove_content_filters();
} else {
// Fallback if function doesn't exist.
remove_all_filters( 'the_content' );
remove_all_filters( 'the_excerpt' );
remove_all_filters( 'get_the_excerpt' );
remove_all_filters( 'the_title' );
}
// Use output buffering to prevent any accidental output from plugins.
ob_start();
try {
/**
* Fires after default metrics are collected.
*
* Third-party plugins can use this hook to add custom metrics.
*
* @param Collector $collector The metrics collector instance.
*/
do_action( 'wp_prometheus_collect_metrics', $this );
} catch ( \Throwable $e ) {
// Log the error but don't let it break metrics output.
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
error_log( 'WP Prometheus: Error in custom metrics hook: ' . $e->getMessage() );
}
}
// Discard any output from plugins.
ob_end_clean();
} }
/** /**

View File

@@ -3,7 +3,7 @@
* Plugin Name: WP Prometheus * Plugin Name: WP Prometheus
* Plugin URI: https://src.bundespruefstelle.ch/magdev/wp-prometheus * Plugin URI: https://src.bundespruefstelle.ch/magdev/wp-prometheus
* Description: Prometheus metrics endpoint for WordPress with extensible hooks for custom metrics. * Description: Prometheus metrics endpoint for WordPress with extensible hooks for custom metrics.
* Version: 0.4.3 * Version: 0.4.5
* Requires at least: 6.4 * Requires at least: 6.4
* Requires PHP: 8.3 * Requires PHP: 8.3
* Author: Marco Graetsch * Author: Marco Graetsch
@@ -22,11 +22,16 @@ if ( ! defined( 'ABSPATH' ) ) {
} }
/** /**
* Early metrics endpoint handler. * Early metrics request detection.
* *
* Intercepts /metrics requests before full WordPress initialization to avoid * Detects /metrics requests early and removes problematic content filters
* conflicts with other plugins that may cause issues during template loading. * to prevent recursion issues with Twig-based plugins. Unlike the previous
* This runs at plugin load time, before plugins_loaded hook. * "early mode", this allows WordPress to continue loading so that third-party
* plugins can register their wp_prometheus_collect_metrics hooks.
*
* Two modes are available:
* - Safe mode (default): Removes filters early, lets WP load, fires custom hooks
* - Isolated mode: Outputs metrics immediately without custom hooks (legacy early mode)
*/ */
function wp_prometheus_early_metrics_check(): void { function wp_prometheus_early_metrics_check(): void {
// Only handle /metrics requests. // Only handle /metrics requests.
@@ -37,18 +42,58 @@ function wp_prometheus_early_metrics_check(): void {
return; return;
} }
// Check if early mode is disabled via environment variable. // Set flag to indicate we're handling a metrics request.
$env_disable = getenv( 'WP_PROMETHEUS_DISABLE_EARLY_MODE' ); define( 'WP_PROMETHEUS_METRICS_REQUEST', true );
if ( false !== $env_disable && in_array( strtolower( $env_disable ), array( '1', 'true', 'yes', 'on' ), true ) ) {
return; // Check if isolated mode is enabled via environment variable.
$env_isolated = getenv( 'WP_PROMETHEUS_ISOLATED_MODE' );
$isolated_mode = false !== $env_isolated && in_array( strtolower( $env_isolated ), array( '1', 'true', 'yes', 'on' ), true );
// Check if isolated mode is enabled via option (legacy "early mode" setting).
if ( ! $isolated_mode && ! get_option( 'wp_prometheus_disable_early_mode', false ) ) {
// Check for legacy isolated mode option.
$isolated_mode = (bool) get_option( 'wp_prometheus_isolated_mode', false );
} }
// Check if early mode is disabled via option. // Remove all content filters immediately to prevent recursion with Twig-based plugins.
// We can use get_option() here because WordPress core is already loaded. // This is done for BOTH safe mode and isolated mode.
if ( get_option( 'wp_prometheus_disable_early_mode', false ) ) { add_action( 'plugins_loaded', 'wp_prometheus_remove_content_filters', 0 );
return;
// Also remove filters now in case they were added by mu-plugins.
wp_prometheus_remove_content_filters();
// If isolated mode is enabled, handle metrics immediately without waiting for plugins.
if ( $isolated_mode ) {
wp_prometheus_isolated_metrics_handler();
}
} }
/**
* Remove content filters that can cause recursion.
*
* Called early during metrics requests to prevent infinite loops
* with Twig-based plugins that hook into content filters.
*
* @return void
*/
function wp_prometheus_remove_content_filters(): void {
remove_all_filters( 'the_content' );
remove_all_filters( 'the_excerpt' );
remove_all_filters( 'get_the_excerpt' );
remove_all_filters( 'the_title' );
remove_all_filters( 'the_content_feed' );
remove_all_filters( 'comment_text' );
}
/**
* Handle metrics in isolated mode (no custom hooks).
*
* This is the legacy "early mode" that outputs metrics immediately
* without allowing third-party plugins to add custom metrics.
*
* @return void
*/
function wp_prometheus_isolated_metrics_handler(): void {
// Check if autoloader exists. // Check if autoloader exists.
$autoloader = __DIR__ . '/vendor/autoload.php'; $autoloader = __DIR__ . '/vendor/autoload.php';
if ( ! file_exists( $autoloader ) ) { if ( ! file_exists( $autoloader ) ) {
@@ -99,14 +144,8 @@ function wp_prometheus_early_metrics_check(): void {
exit; exit;
} }
// Set flag to indicate early metrics mode - Collector will skip extensibility hooks. // Set flag to indicate isolated mode - Collector will skip extensibility hooks.
define( 'WP_PROMETHEUS_EARLY_METRICS', true ); define( 'WP_PROMETHEUS_ISOLATED_MODE', true );
// Remove all content filters to prevent recursion with Twig-based plugins.
remove_all_filters( 'the_content' );
remove_all_filters( 'the_excerpt' );
remove_all_filters( 'get_the_excerpt' );
remove_all_filters( 'the_title' );
// Output metrics and exit immediately. // Output metrics and exit immediately.
$collector = new \Magdev\WpPrometheus\Metrics\Collector(); $collector = new \Magdev\WpPrometheus\Metrics\Collector();
@@ -130,7 +169,7 @@ wp_prometheus_early_metrics_check();
* *
* @var string * @var string
*/ */
define( 'WP_PROMETHEUS_VERSION', '0.4.3' ); define( 'WP_PROMETHEUS_VERSION', '0.4.5' );
/** /**
* Plugin file path. * Plugin file path.