fix: Defer DashboardProvider translations to avoid early textdomain loading (v0.4.8)
All checks were successful
Create Release Package / build-release (push) Successful in 54s

DashboardProvider constructor also had __() calls during plugins_loaded.
Applied same lazy-initialization pattern as Settings tab labels.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-02-07 11:44:06 +01:00
parent b605d0c299
commit 9bfed06466
3 changed files with 50 additions and 33 deletions

View File

@@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed `_load_textdomain_just_in_time` notice on admin pages (WordPress 6.7+ compatibility) - Fixed `_load_textdomain_just_in_time` notice on admin pages (WordPress 6.7+ compatibility)
- Deferred `load_plugin_textdomain()` to `init` action instead of `plugins_loaded` - Deferred `load_plugin_textdomain()` to `init` action instead of `plugins_loaded`
- Deferred Settings tab label initialization to avoid early translation loading - Deferred Settings tab label and DashboardProvider initialization to avoid early translation loading
## [0.4.7] - 2026-02-03 ## [0.4.7] - 2026-02-03

View File

@@ -295,9 +295,10 @@ add_action( 'wp_prometheus_collect_metrics', function( $collector ) {
- Fixed `_load_textdomain_just_in_time` warning on admin pages (WordPress 6.7+ compatibility) - Fixed `_load_textdomain_just_in_time` warning on admin pages (WordPress 6.7+ compatibility)
- Root cause: `load_plugin_textdomain()` was called during `plugins_loaded` in `Plugin::__construct()` - Root cause: `load_plugin_textdomain()` was called during `plugins_loaded` in `Plugin::__construct()`
- WordPress 6.7+ requires textdomain loading at the `init` action or later - WordPress 6.7+ requires textdomain loading at the `init` action or later
- Two changes made: - Three classes needed fixing:
- `Plugin.php`: Deferred `load_textdomain()` to `init` action hook, changed method visibility to public - `Plugin.php`: Deferred `load_textdomain()` to `init` action hook, changed method visibility to public
- `Settings.php`: Deferred tab label initialization (which uses `__()`) to a lazy `get_tabs()` method - `Settings.php`: Deferred tab label initialization (which uses `__()`) to a lazy `get_tabs()` method
- `DashboardProvider.php`: Deferred built-in dashboard definitions (with `__()` calls) to a lazy `get_builtin_dashboards()` method
- Cleared Known Bugs section — no remaining known issues - Cleared Known Bugs section — no remaining known issues
- **Key Learning**: WordPress 6.7 textdomain loading requirements - **Key Learning**: WordPress 6.7 textdomain loading requirements
- `load_plugin_textdomain()` must be called at `init` or later - `load_plugin_textdomain()` must be called at `init` or later

View File

@@ -53,7 +53,18 @@ class DashboardProvider {
*/ */
public function __construct() { public function __construct() {
$this->dashboard_dir = WP_PROMETHEUS_PATH . 'assets/dashboards/'; $this->dashboard_dir = WP_PROMETHEUS_PATH . 'assets/dashboards/';
}
/**
* Get built-in dashboard definitions.
*
* Lazily initializes dashboard labels to avoid triggering textdomain loading
* before the 'init' action (required since WordPress 6.7).
*
* @return array
*/
private function get_builtin_dashboards(): array {
if ( empty( $this->builtin_dashboards ) ) {
$this->builtin_dashboards = array( $this->builtin_dashboards = array(
'wordpress-overview' => array( 'wordpress-overview' => array(
'title' => __( 'WordPress Overview', 'wp-prometheus' ), 'title' => __( 'WordPress Overview', 'wp-prometheus' ),
@@ -78,6 +89,8 @@ class DashboardProvider {
), ),
); );
} }
return $this->builtin_dashboards;
}
/** /**
* Register a third-party dashboard. * Register a third-party dashboard.
@@ -106,7 +119,7 @@ class DashboardProvider {
} }
// Check for duplicate slugs (built-in takes precedence). // Check for duplicate slugs (built-in takes precedence).
if ( isset( $this->builtin_dashboards[ $slug ] ) ) { if ( isset( $this->get_builtin_dashboards()[ $slug ] ) ) {
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
error_log( "WP Prometheus: Dashboard slug '$slug' conflicts with built-in dashboard" ); error_log( "WP Prometheus: Dashboard slug '$slug' conflicts with built-in dashboard" );
@@ -273,7 +286,7 @@ class DashboardProvider {
$available = array(); $available = array();
// Add built-in dashboards (check file exists). // Add built-in dashboards (check file exists).
foreach ( $this->builtin_dashboards as $slug => $dashboard ) { foreach ( $this->get_builtin_dashboards() as $slug => $dashboard ) {
$file_path = $this->dashboard_dir . $dashboard['file']; $file_path = $this->dashboard_dir . $dashboard['file'];
if ( file_exists( $file_path ) ) { if ( file_exists( $file_path ) ) {
$available[ $slug ] = $dashboard; $available[ $slug ] = $dashboard;
@@ -306,8 +319,9 @@ class DashboardProvider {
$slug = sanitize_file_name( $slug ); $slug = sanitize_file_name( $slug );
// Check built-in dashboards first. // Check built-in dashboards first.
if ( isset( $this->builtin_dashboards[ $slug ] ) ) { $builtin = $this->get_builtin_dashboards();
$dashboard = $this->builtin_dashboards[ $slug ]; if ( isset( $builtin[ $slug ] ) ) {
$dashboard = $builtin[ $slug ];
$file_path = $this->dashboard_dir . $dashboard['file']; $file_path = $this->dashboard_dir . $dashboard['file'];
// Security: Ensure file is within dashboard directory. // Security: Ensure file is within dashboard directory.
@@ -377,8 +391,9 @@ class DashboardProvider {
$slug = sanitize_file_name( $slug ); $slug = sanitize_file_name( $slug );
if ( isset( $this->builtin_dashboards[ $slug ] ) ) { $builtin = $this->get_builtin_dashboards();
return $this->builtin_dashboards[ $slug ]; if ( isset( $builtin[ $slug ] ) ) {
return $builtin[ $slug ];
} }
if ( isset( $this->registered_dashboards[ $slug ] ) ) { if ( isset( $this->registered_dashboards[ $slug ] ) ) {
@@ -401,8 +416,9 @@ class DashboardProvider {
$slug = sanitize_file_name( $slug ); $slug = sanitize_file_name( $slug );
// Built-in dashboards have predefined filenames. // Built-in dashboards have predefined filenames.
if ( isset( $this->builtin_dashboards[ $slug ] ) ) { $builtin = $this->get_builtin_dashboards();
return $this->builtin_dashboards[ $slug ]['file']; if ( isset( $builtin[ $slug ] ) ) {
return $builtin[ $slug ]['file'];
} }
// Registered dashboards - use file basename or generate from slug. // Registered dashboards - use file basename or generate from slug.