diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f7eaa7..2ab3015 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) - 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 diff --git a/CLAUDE.md b/CLAUDE.md index ad05f44..0798212 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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) - 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 -- Two changes made: +- Three classes needed fixing: - `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 + - `DashboardProvider.php`: Deferred built-in dashboard definitions (with `__()` calls) to a lazy `get_builtin_dashboards()` method - Cleared Known Bugs section — no remaining known issues - **Key Learning**: WordPress 6.7 textdomain loading requirements - `load_plugin_textdomain()` must be called at `init` or later diff --git a/src/Admin/DashboardProvider.php b/src/Admin/DashboardProvider.php index 81b91ff..e98ff80 100644 --- a/src/Admin/DashboardProvider.php +++ b/src/Admin/DashboardProvider.php @@ -53,30 +53,43 @@ class DashboardProvider { */ public function __construct() { $this->dashboard_dir = WP_PROMETHEUS_PATH . 'assets/dashboards/'; + } - $this->builtin_dashboards = array( - 'wordpress-overview' => array( - 'title' => __( 'WordPress Overview', 'wp-prometheus' ), - 'description' => __( 'General WordPress metrics including users, posts, comments, and plugins.', 'wp-prometheus' ), - 'file' => 'wordpress-overview.json', - 'icon' => 'dashicons-wordpress', - 'source' => 'builtin', - ), - 'wordpress-runtime' => array( - 'title' => __( 'Runtime Performance', 'wp-prometheus' ), - 'description' => __( 'HTTP request metrics, database query performance, and response times.', 'wp-prometheus' ), - 'file' => 'wordpress-runtime.json', - 'icon' => 'dashicons-performance', - 'source' => 'builtin', - ), - 'wordpress-woocommerce' => array( - 'title' => __( 'WooCommerce Store', 'wp-prometheus' ), - 'description' => __( 'WooCommerce metrics including products, orders, revenue, and customers.', 'wp-prometheus' ), - 'file' => 'wordpress-woocommerce.json', - 'icon' => 'dashicons-cart', - 'source' => 'builtin', - ), - ); + /** + * 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( + 'wordpress-overview' => array( + 'title' => __( 'WordPress Overview', 'wp-prometheus' ), + 'description' => __( 'General WordPress metrics including users, posts, comments, and plugins.', 'wp-prometheus' ), + 'file' => 'wordpress-overview.json', + 'icon' => 'dashicons-wordpress', + 'source' => 'builtin', + ), + 'wordpress-runtime' => array( + 'title' => __( 'Runtime Performance', 'wp-prometheus' ), + 'description' => __( 'HTTP request metrics, database query performance, and response times.', 'wp-prometheus' ), + 'file' => 'wordpress-runtime.json', + 'icon' => 'dashicons-performance', + 'source' => 'builtin', + ), + 'wordpress-woocommerce' => array( + 'title' => __( 'WooCommerce Store', 'wp-prometheus' ), + 'description' => __( 'WooCommerce metrics including products, orders, revenue, and customers.', 'wp-prometheus' ), + 'file' => 'wordpress-woocommerce.json', + 'icon' => 'dashicons-cart', + 'source' => 'builtin', + ), + ); + } + return $this->builtin_dashboards; } /** @@ -106,7 +119,7 @@ class DashboardProvider { } // 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 ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log error_log( "WP Prometheus: Dashboard slug '$slug' conflicts with built-in dashboard" ); @@ -273,7 +286,7 @@ class DashboardProvider { $available = array(); // 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']; if ( file_exists( $file_path ) ) { $available[ $slug ] = $dashboard; @@ -306,8 +319,9 @@ class DashboardProvider { $slug = sanitize_file_name( $slug ); // Check built-in dashboards first. - if ( isset( $this->builtin_dashboards[ $slug ] ) ) { - $dashboard = $this->builtin_dashboards[ $slug ]; + $builtin = $this->get_builtin_dashboards(); + if ( isset( $builtin[ $slug ] ) ) { + $dashboard = $builtin[ $slug ]; $file_path = $this->dashboard_dir . $dashboard['file']; // Security: Ensure file is within dashboard directory. @@ -377,8 +391,9 @@ class DashboardProvider { $slug = sanitize_file_name( $slug ); - if ( isset( $this->builtin_dashboards[ $slug ] ) ) { - return $this->builtin_dashboards[ $slug ]; + $builtin = $this->get_builtin_dashboards(); + if ( isset( $builtin[ $slug ] ) ) { + return $builtin[ $slug ]; } if ( isset( $this->registered_dashboards[ $slug ] ) ) { @@ -401,8 +416,9 @@ class DashboardProvider { $slug = sanitize_file_name( $slug ); // Built-in dashboards have predefined filenames. - if ( isset( $this->builtin_dashboards[ $slug ] ) ) { - return $this->builtin_dashboards[ $slug ]['file']; + $builtin = $this->get_builtin_dashboards(); + if ( isset( $builtin[ $slug ] ) ) { + return $builtin[ $slug ]['file']; } // Registered dashboards - use file basename or generate from slug.