You've already forked wp-prometheus
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>
536 lines
25 KiB
Markdown
536 lines
25 KiB
Markdown
# WP Prometheus
|
|
|
|
**Author:** Marco Graetsch
|
|
**Author URL:** <https://src.bundespruefstelle.ch/magdev>
|
|
**Author Email:** <magdev3.0@gmail.com>
|
|
**Repository URL:** <https://src.bundespruefstelle.ch/magdev/wp-prometheus>
|
|
**Issues URL:** <https://src.bundespruefstelle.ch/magdev/wp-prometheus/issues>
|
|
|
|
## Project Overview
|
|
|
|
This plugin provides a Prometheus `/metrics` endpoint and an extensible way to add your own metrics in third-party plugins using hooks. It adds some default metrics like number of active accounts, number of articles, comments, and plugin status. The default metrics can be activated/deactivated in the plugin settings.
|
|
|
|
### Features
|
|
|
|
- Prometheus compatible authenticated `/metrics` endpoint
|
|
- Optional default metrics (users, posts, comments, plugins)
|
|
- Runtime metrics (HTTP requests, request duration, database queries)
|
|
- Cron job metrics (scheduled events, overdue, next run)
|
|
- Transient cache metrics (total, expiring, expired)
|
|
- WooCommerce integration (products, orders, revenue, customers)
|
|
- Custom metric builder with admin UI (gauges with static or option-based values)
|
|
- Metric export/import for backup and site migration
|
|
- Grafana dashboard templates for easy visualization
|
|
- Dedicated plugin settings under 'Settings/Metrics' menu
|
|
- Extensible by other plugins using `wp_prometheus_collect_metrics` action hook
|
|
- License management integration
|
|
|
|
### Key Fact: 100% AI-Generated
|
|
|
|
This project is proudly **"vibe-coded"** using Claude.AI - the entire codebase was created through AI assistance.
|
|
|
|
## Temporary Roadmap
|
|
|
|
**Note for AI Assistants:** Clean this section after the specific features are done or new releases are made. Effective changes are tracked in `CHANGELOG.md`. Do not add completed versions here - document them in the Session History section at the end of this file.
|
|
|
|
*No planned features at this time.*
|
|
|
|
## Technical Stack
|
|
|
|
- **Language:** PHP 8.3.x
|
|
- **PHP-Standards:** PSR-4
|
|
- **Framework:** Latest WordPress Plugin API
|
|
- **Styling:** Custom CSS
|
|
- **Dependency Management:** Composer
|
|
- **Internationalization:** WordPress i18n (.pot/.po/.mo files)
|
|
- **Canonical Plugin Name:** `wp-prometheus`
|
|
- **License Client:** `magdev/wc-licensed-product-client` Have a look at <https://src.bundespruefstelle.ch/magdev/wp-fedistream> for a working admin integration
|
|
- **Prometheus Client:** `promphp/prometheus_client_php` <https://github.com/PromPHP/prometheus_client_php>
|
|
|
|
### Security Best Practices
|
|
|
|
- All user inputs are sanitized (integers for quantities/prices)
|
|
- Nonce verification on form submissions
|
|
- Output escaping in templates (`esc_attr`, `esc_html`, `esc_js`)
|
|
- Direct file access prevention via `ABSPATH` check
|
|
- XSS-safe DOM construction in JavaScript (no `innerHTML` with user data)
|
|
- SQL injection prevention using `$wpdb->prepare()` throughout
|
|
|
|
### Translation Ready
|
|
|
|
All user-facing strings use:
|
|
|
|
```php
|
|
__('Text to translate', 'wp-prometheus')
|
|
_e('Text to translate', 'wp-prometheus')
|
|
```
|
|
|
|
Text domain: `wp-prometheus`
|
|
|
|
#### Translation Template
|
|
|
|
- Base `.pot` file created: `languages/wp-prometheus.pot`
|
|
- Ready for translation to any locale
|
|
- All translatable strings properly marked with text domain
|
|
|
|
#### Available Translations
|
|
|
|
- `en_US` - English (United States) [base language - .pot template]
|
|
- `de_CH` - German (Switzerland, formal)
|
|
|
|
To compile translations to .mo files for production:
|
|
|
|
```bash
|
|
for po in languages/*.po; do msgfmt -o "${po%.po}.mo" "$po"; done
|
|
```
|
|
|
|
### Create releases
|
|
|
|
- The `vendor/` directory MUST be included in releases (Dependencies required for runtime)
|
|
- **CRITICAL**: Build `vendor/` for the MINIMUM supported PHP version, not the development version
|
|
- Use `composer config platform.php 8.3.0` before building release packages
|
|
- Run `composer update --no-dev --optimize-autoloader` to rebuild dependencies
|
|
- **CRITICAL**: WordPress requires plugins in a subdirectory structure
|
|
- Run zip from the `plugins/` parent directory, NOT from within the plugin directory
|
|
- Package must extract to `wp-prometheus/` subdirectory with main file at `wp-prometheus/wp-prometheus.php`
|
|
- Correct command: `cd /wp-content/plugins/ && zip -r wp-prometheus/releases/wp-prometheus-x.x.x.zip wp-prometheus ...`
|
|
- Wrong: Running zip from inside the plugin directory creates files at root level
|
|
- **CRITICAL**: Exclude symlinks explicitly - zip follows symlinks by default
|
|
- Always use `-x "wp-prometheus/wp-core" -x "wp-prometheus/wp-core/*" -x "wp-prometheus/wp-plugins" -x "wp-prometheus/wp-plugins/*"` to exclude development symlinks
|
|
- Otherwise the entire linked directory contents will be included in the package
|
|
- Exclusion patterns must match the relative path structure used in zip command
|
|
- Always verify the package structure with `unzip -l` before distribution
|
|
- Check all files are prefixed with `wp-prometheus/`
|
|
- Verify main file is at `wp-prometheus/wp-prometheus.php`
|
|
- Check for duplicate entries (indicates multiple builds in same archive)
|
|
- Test installation on the minimum supported PHP version before final deployment
|
|
- Releases are stored in `releases/` including checksums
|
|
- Track release changes in a single `CHANGELOG.md` file
|
|
- Bump the version number to either bugfix release versions or on new features minor release versions
|
|
- **CRITICAL**: WordPress reads version from TWO places - BOTH must be updated:
|
|
1. Plugin header comment `Version: x.x.x` - WordPress uses THIS for admin display
|
|
2. PHP constant `WP_PROMETHEUS_VERSION` (line ~28) - Used internally by the plugin
|
|
- If only the constant is updated, WordPress will show the old version in Plugins list
|
|
|
|
**Important Git Notes:**
|
|
|
|
- Default branch while development is `dev`
|
|
- Create releases from branch `main` after merging branch `dev`
|
|
- Tags should use format `vX.X.X` (e.g., `v1.1.22`), start with v0.0.1
|
|
- Use annotated tags (`-a`) not lightweight tags
|
|
- Commit messages should follow the established format with Claude Code attribution
|
|
- `.claude/settings.local.json` changes are typically local-only (stash before rebasing)
|
|
|
|
**CRITICAL - Release Workflow:**
|
|
|
|
On every new version, ALWAYS execute this complete workflow:
|
|
|
|
```bash
|
|
# 1. Commit changes to dev branch
|
|
git add <files>
|
|
git commit -m "Description of changes (vX.X.X)"
|
|
|
|
# 2. Merge dev to main
|
|
git checkout main
|
|
git merge dev --no-edit
|
|
|
|
# 3. Create annotated tag
|
|
git tag -a vX.X.X -m "Version X.X.X - Brief description"
|
|
|
|
# 4. Push everything to origin
|
|
git push origin dev main vX.X.X
|
|
|
|
# 5. Switch back to dev for continued development
|
|
git checkout dev
|
|
```
|
|
|
|
Never skip any of these steps. The release is not complete until all branches and the tag are pushed to origin.
|
|
|
|
#### What Gets Released
|
|
|
|
- All plugin source files
|
|
- Compiled vendor dependencies
|
|
- Translation files (.mo compiled from .po)
|
|
- Assets (CSS, JS)
|
|
- Documentation (README, CHANGELOG, etc.)
|
|
|
|
#### What's Excluded
|
|
|
|
- Git metadata (`.git/`)
|
|
- Development files (`.vscode/`, `.claude/`, `CLAUDE.md`, `wp-core`, `wp-plugins`)
|
|
- Logs and cache files
|
|
- Previous releases
|
|
- `composer.lock` (but `vendor/` is included)
|
|
|
|
---
|
|
|
|
**For AI Assistants:**
|
|
|
|
When starting a new session on this project:
|
|
|
|
1. Read this CLAUDE.md file first
|
|
2. Semantic versioning follows the `MAJOR.MINOR.BUGFIX` pattern
|
|
3. Check git log for recent changes
|
|
4. Verify you're on the `dev` branch before making changes
|
|
5. Run `composer install` if vendor/ is missing
|
|
6. Test changes before committing
|
|
7. Follow commit message format with Claude Code attribution
|
|
8. Update this session history section with learnings
|
|
9. Never commit backup files (`*.po~`, `*.bak`, etc.) - check `git status` before committing
|
|
10. Follow markdown linting rules (see below)
|
|
|
|
Always refer to this document when starting work on this project.
|
|
|
|
### Markdown Linting Rules
|
|
|
|
When editing CLAUDE.md or other markdown files, follow these rules to avoid linting errors:
|
|
|
|
1. **MD031 - Blank lines around fenced code blocks**: Always add a blank line before and after fenced code blocks, even when they follow list items. Example of correct format:
|
|
|
|
- **Item label**:
|
|
|
|
(blank line here)
|
|
\`\`\`php
|
|
code example
|
|
\`\`\`
|
|
(blank line here)
|
|
|
|
2. **MD056 - Table column count**: Table separators must have matching column counts and proper spacing. Use consistent dash lengths that match column header widths.
|
|
3. **MD009 - No trailing spaces**: Remove trailing whitespace from lines
|
|
4. **MD012 - No multiple consecutive blank lines**: Use only single blank lines between sections
|
|
5. **MD040 - Fenced code blocks should have a language specified**: Always add a language identifier to code blocks (e.g., `txt`, `bash`, `php`). For shortcode examples, use `txt`.
|
|
6. **MD032 - Lists should be surrounded by blank lines**: Add a blank line before AND after list blocks, including after bold labels like `**Attributes:**`.
|
|
7. **MD034 - Bare URLs**: Wrap URLs in angle brackets (e.g., `<https://example.com>`) or use markdown link syntax `[text](url)`.
|
|
8. **Author section formatting**: Use a heading (`### Name`) instead of bold (`**Name**`) for the author name to maintain consistent document structure.
|
|
|
|
## Project Architecture
|
|
|
|
### Directory Structure
|
|
|
|
```txt
|
|
wp-prometheus/
|
|
├── .gitea/workflows/
|
|
│ └── release.yml # CI/CD pipeline
|
|
├── assets/
|
|
│ ├── css/ # Admin/Frontend styles
|
|
│ ├── dashboards/ # Grafana dashboard templates
|
|
│ │ ├── wordpress-overview.json
|
|
│ │ ├── wordpress-runtime.json
|
|
│ │ └── wordpress-woocommerce.json
|
|
│ └── js/
|
|
│ └── admin.js # Admin JavaScript
|
|
├── languages/ # Translation files
|
|
├── lib/
|
|
│ └── wc-licensed-product-client/ # Git submodule
|
|
├── releases/ # Release packages
|
|
├── src/
|
|
│ ├── Admin/
|
|
│ │ ├── DashboardProvider.php # Grafana dashboard provider
|
|
│ │ └── Settings.php # Settings page
|
|
│ ├── Endpoint/
|
|
│ │ └── MetricsEndpoint.php # /metrics endpoint
|
|
│ ├── License/
|
|
│ │ └── Manager.php # License management
|
|
│ ├── Metrics/
|
|
│ │ ├── Collector.php # Prometheus metrics collector
|
|
│ │ ├── CustomMetricBuilder.php # Custom metric CRUD
|
|
│ │ ├── RuntimeCollector.php # Runtime metrics collector
|
|
│ │ └── StorageFactory.php # Storage adapter factory
|
|
│ ├── Installer.php # Activation/Deactivation
|
|
│ ├── Plugin.php # Main plugin class
|
|
│ └── index.php
|
|
├── CHANGELOG.md
|
|
├── CLAUDE.md
|
|
├── composer.json
|
|
├── index.php
|
|
├── PLAN.md
|
|
├── README.md
|
|
├── uninstall.php
|
|
└── wp-prometheus.php # Plugin bootstrap
|
|
```
|
|
|
|
### Implementation Details
|
|
|
|
#### License Manager (`src/License/Manager.php`)
|
|
|
|
- Integration with `SecureLicenseClient` or `LicenseClient`
|
|
- Option storage for license key, server URL, server secret
|
|
- License validation with domain binding
|
|
- License activation with domain
|
|
- Status caching (24-hour transient)
|
|
- AJAX handlers for admin operations
|
|
- Exception handling for all license states
|
|
|
|
#### Metrics Endpoint Restriction Logic
|
|
|
|
```php
|
|
// In Plugin::init_components()
|
|
if ( LicenseManager::is_license_valid() ) {
|
|
$this->collector = new Collector();
|
|
new MetricsEndpoint( $this->collector );
|
|
}
|
|
```
|
|
|
|
Admin settings always work; metrics endpoint requires valid license.
|
|
|
|
#### Custom Metrics Extension
|
|
|
|
```php
|
|
// Third-party plugins can add custom metrics
|
|
add_action( 'wp_prometheus_collect_metrics', function( $collector ) {
|
|
$gauge = $collector->register_gauge(
|
|
'my_custom_metric',
|
|
'Description of my metric',
|
|
array( 'label1', 'label2' )
|
|
);
|
|
$gauge->set( 42, array( 'value1', 'value2' ) );
|
|
} );
|
|
```
|
|
|
|
---
|
|
|
|
## 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:
|
|
- **Endpoint**: Authentication token configuration
|
|
- **Selection**: Enable/disable individual metrics
|
|
- **Runtime**: Reset runtime metrics data
|
|
- **Advanced**: Early mode toggle and status
|
|
- Fixed early mode setting not being saved (was outside form element)
|
|
- Added CSS styling for horizontal sub-tab navigation
|
|
- **Key Learning**: WordPress Settings API form structure
|
|
- Settings must be inside `<form action="options.php">` with `settings_fields()` call
|
|
- Each sub-tab needs its own form wrapper for proper saving
|
|
- 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)
|
|
|
|
- Added option to disable early mode for users who need extensibility
|
|
- Implementation:
|
|
- Added `wp_prometheus_disable_early_mode` WordPress option
|
|
- Added `WP_PROMETHEUS_DISABLE_EARLY_MODE` environment variable support
|
|
- Option check in `wp_prometheus_early_metrics_check()` before early interception
|
|
- Environment variable accepts `1`, `true`, `yes`, `on` (case-insensitive)
|
|
- Admin UI in Metrics tab:
|
|
- "Early Mode" section with description of functionality
|
|
- Checkbox to disable early metrics interception
|
|
- Environment override notice when env var is set
|
|
- Current status indicator showing early mode state
|
|
- **Key Learning**: Balancing compatibility vs extensibility
|
|
- Early mode fixes memory issues but disables `wp_prometheus_collect_metrics` hook
|
|
- Users with custom metrics need the hook, so early mode must be optional
|
|
- Default remains enabled (safe) with explicit opt-out for advanced users
|
|
|
|
### 2026-02-02 - Plugin Compatibility Fix (v0.4.1)
|
|
|
|
- Fixed memory exhaustion (1GB limit) when wp-fedistream (Twig-based) plugin is active
|
|
- Root cause: Infinite recursion through WordPress hook system when content filters trigger Twig rendering
|
|
- Solution: Early metrics endpoint interception before full WordPress initialization
|
|
- Implementation changes:
|
|
- Added `wp_prometheus_early_metrics_check()` in bootstrap file (wp-prometheus.php)
|
|
- Checks REQUEST_URI for `/metrics` pattern before `plugins_loaded` fires
|
|
- Defines `WP_PROMETHEUS_EARLY_METRICS` constant to signal early mode
|
|
- Removes content filters (`the_content`, `the_excerpt`, `get_the_excerpt`, `the_title`)
|
|
- Collector skips `wp_prometheus_collect_metrics` action in early mode
|
|
- Changed MetricsEndpoint from `template_redirect` to `parse_request` hook
|
|
- **Key Learning**: WordPress plugin loading order and hook timing
|
|
- Plugins load alphabetically, so wp-fedistream ('f') loads before wp-prometheus ('p')
|
|
- `template_redirect` fires too late - after themes and Twig initialize
|
|
- `parse_request` fires earlier but still after plugin files load
|
|
- Earliest interception point: top-level code in plugin bootstrap file
|
|
- **Key Learning**: Content filter recursion in WordPress
|
|
- `get_the_excerpt()` internally triggers `apply_filters('the_content', ...)`
|
|
- This creates unexpected recursion vectors when Twig templates process content
|
|
- Solution: Remove all content-related filters before metrics collection
|
|
- **Key Learning**: Isolating metrics collection from WordPress template system
|
|
- Use `remove_all_filters()` to clear problematic filter chains
|
|
- Skip extensibility hooks (`do_action`) when in isolated early mode
|
|
- Exit immediately after output to prevent further WordPress processing
|
|
|
|
### 2026-02-02 - Persistent Storage (v0.4.0)
|
|
|
|
- Added persistent storage support for metrics:
|
|
- `StorageFactory.php` - Factory class for storage adapter instantiation
|
|
- Redis storage adapter for shared metrics across multiple instances
|
|
- APCu storage adapter for single-server high-performance caching
|
|
- Automatic fallback to In-Memory if configured adapter fails
|
|
- Added new "Storage" tab in admin settings:
|
|
- Storage adapter selection (In-Memory, Redis, APCu)
|
|
- Redis configuration (host, port, password, database, key prefix)
|
|
- APCu configuration (key prefix)
|
|
- Connection test button with detailed error messages
|
|
- Added environment variable support for Docker deployments:
|
|
- `WP_PROMETHEUS_STORAGE_ADAPTER` - Adapter selection
|
|
- `WP_PROMETHEUS_REDIS_HOST`, `_PORT`, `_PASSWORD`, `_DATABASE`, `_PREFIX`
|
|
- `WP_PROMETHEUS_APCU_PREFIX`
|
|
- Environment variables take precedence over admin settings
|
|
- Updated `Collector.php` to use `StorageFactory::get_adapter()`
|
|
- Updated Help tab with storage backends documentation
|
|
- Updated translation files with all new strings
|
|
- **Key Learning**: promphp/prometheus_client_php storage adapters
|
|
- Redis adapter requires options array with host, port, password, timeout
|
|
- APCu adapter just needs a prefix string
|
|
- Use `Redis::setPrefix()` before instantiation for custom key prefixes
|
|
- **Key Learning**: Docker environment variable configuration
|
|
- Use `getenv()` with explicit false check (`false !== getenv()`)
|
|
- Environment variables should override WordPress options for containerized deployments
|
|
|
|
### 2026-02-02 - Custom Metrics & Dashboards (v0.3.0)
|
|
|
|
- Added Custom Metric Builder with full admin UI:
|
|
- `CustomMetricBuilder.php` - CRUD operations, validation, export/import
|
|
- Support for static values and WordPress option-based values
|
|
- Label support (max 5 labels, 50 value combinations)
|
|
- Prometheus naming convention validation (`[a-zA-Z_:][a-zA-Z0-9_:]*`)
|
|
- Added Grafana Dashboard Templates:
|
|
- `DashboardProvider.php` - Dashboard file provider with path traversal protection
|
|
- `wordpress-overview.json` - General WordPress metrics
|
|
- `wordpress-runtime.json` - HTTP/DB performance metrics
|
|
- `wordpress-woocommerce.json` - WooCommerce store metrics
|
|
- Added export/import functionality:
|
|
- JSON-based configuration export
|
|
- Three import modes: skip, overwrite, rename duplicates
|
|
- Version tracking in export format
|
|
- Updated Settings page with new tabs:
|
|
- "Custom Metrics" tab with metric form and table
|
|
- "Dashboards" tab with download buttons
|
|
- "Reset Runtime Metrics" button in Metrics tab
|
|
- Updated `Collector.php` to integrate custom metrics
|
|
- Updated translation files with all new strings
|
|
- **Key Learning**: Dynamic form handling in WordPress admin
|
|
- Use `wp_create_nonce()` with unique nonce names per AJAX action
|
|
- Localize script with `wp_localize_script()` for nonces and AJAX URL
|
|
- Always verify `current_user_can('manage_options')` in AJAX handlers
|
|
- **Key Learning**: Grafana dashboard JSON format
|
|
- Use `${DS_PROMETHEUS}` for data source variable
|
|
- Schema version 39 for current Grafana compatibility
|
|
- Panels use `gridPos` for layout positioning
|
|
|
|
### 2026-02-02 - Extended Metrics (v0.2.0)
|
|
|
|
- Added WooCommerce integration metrics (only when WooCommerce is active):
|
|
- `wordpress_woocommerce_products_total` - Products by status and type
|
|
- `wordpress_woocommerce_orders_total` - Orders by status
|
|
- `wordpress_woocommerce_revenue_total` - Revenue (all time, today, month)
|
|
- `wordpress_woocommerce_customers_total` - Customers (registered, guest)
|
|
- Added cron job metrics:
|
|
- `wordpress_cron_events_total` - Scheduled cron events by hook (top 20)
|
|
- `wordpress_cron_overdue_total` - Number of overdue cron events
|
|
- `wordpress_cron_next_run_timestamp` - Unix timestamp of next scheduled cron
|
|
- Added transient cache metrics:
|
|
- `wordpress_transients_total` - Transients by type (total, with_expiration, persistent, expired)
|
|
- Updated Settings page with new metric categories
|
|
- Updated Help tab with new metrics reference
|
|
- **Key Learning**: WooCommerce HPOS (High-Performance Order Storage) requires different queries
|
|
- Check `OrderUtil::custom_orders_table_usage_is_enabled()` to determine storage type
|
|
- HPOS uses `wc_orders` table instead of `posts` and `postmeta`
|
|
- **Key Learning**: Cron event labeling requires cardinality control
|
|
- Limit to top 20 hooks to prevent label explosion
|
|
- Use `arsort()` to get most frequent hooks first
|
|
|
|
### 2026-02-02 - Runtime Metrics (v0.1.0)
|
|
|
|
- Implemented runtime metrics collection for HTTP requests and database queries
|
|
- Created `RuntimeCollector` class that hooks into WordPress request lifecycle
|
|
- Added new metrics:
|
|
- `wordpress_http_requests_total` - Counter by method, status, endpoint
|
|
- `wordpress_http_request_duration_seconds` - Histogram of request durations
|
|
- `wordpress_db_queries_total` - Counter by endpoint
|
|
- `wordpress_db_query_duration_seconds` - Histogram (requires SAVEQUERIES)
|
|
- Updated `Collector` class to expose stored runtime metrics
|
|
- Added new settings options in admin for enabling/disabling runtime metrics
|
|
- Created translation files (.pot, .po, .mo) for internationalization
|
|
- **Key Learning**: With InMemory Prometheus storage, counters/histograms reset per request
|
|
- Solution: Store aggregated data in WordPress options, read during metrics collection
|
|
- Histograms exposed as gauge metrics following Prometheus naming conventions (`_bucket`, `_sum`, `_count`)
|
|
- **Key Learning**: Endpoint normalization is important for cardinality control
|
|
- Group requests into categories (admin, ajax, cron, rest-api, frontend, etc.)
|
|
- Avoid high-cardinality labels like full URL paths
|
|
|
|
### 2026-02-01 - CI/CD Fixes (v0.0.2)
|
|
|
|
- Fixed composer.json dependency configuration for CI compatibility
|
|
- **Key Learning**: Git submodules with path repositories need explicit version aliases for CI:
|
|
|
|
```json
|
|
"repositories": [
|
|
{
|
|
"type": "path",
|
|
"url": "lib/wc-licensed-product-client",
|
|
"options": {
|
|
"symlink": false,
|
|
"versions": {
|
|
"magdev/wc-licensed-product-client": "0.2.2"
|
|
}
|
|
}
|
|
}
|
|
]
|
|
```
|
|
|
|
- Using `dev-main` constraints with `minimum-stability: dev` causes issues in CI
|
|
- Path repository with `symlink: false` and explicit `versions` mapping works reliably
|
|
- **Key Learning**: Gitea API returns "Release has no Tag" error when re-releasing existing tags
|
|
- Fixed release.yml to check for and delete existing releases before creating new ones
|
|
- Changed minimum-stability back to stable
|
|
|
|
### 2026-02-01 - Initial Setup (v0.0.1)
|
|
|
|
- Created initial plugin structure based on wp-fedistream blueprint
|
|
- Set up composer.json with promphp/prometheus_client_php and wc-licensed-product-client
|
|
- Implemented core classes: Plugin, Installer, License/Manager, Metrics/Collector, Endpoint/MetricsEndpoint, Admin/Settings
|
|
- Created authenticated /metrics endpoint with Bearer token support
|
|
- Added default metrics: wordpress_info, users_total, posts_total, comments_total, plugins_total
|
|
- Created extensibility via `wp_prometheus_collect_metrics` action hook
|
|
- Set up Gitea CI/CD pipeline for automated releases
|
|
- Created documentation: README.md, PLAN.md, CHANGELOG.md
|