chore: initial snapshot of 2meet-data-optimizer v0.1.0

Baseline before backporting wp-data-optimizer v3.0.1-v3.4.6.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TbG1keQQ7XBa7qMQY16KCY
This commit is contained in:
2026-07-31 05:06:36 +08:00
commit d36bb954d1
206 changed files with 66538 additions and 0 deletions
@@ -0,0 +1,236 @@
<?php
/**
* TMDO_Site_Metrics_Collector — daily EAV health snapshot writer.
*
* Writes structured rows to `wpdo_site_metrics` once per day (via
* `wpdo_collect_site_metrics` cron action, scheduled at 05:00 UTC).
*
* Metric keys written per run:
* eav.postmeta_rows / eav.usermeta_rows / eav.termmeta_rows / eav.commentmeta_rows
* flat.hot_rows / flat.cold_rows / flat.warm_rows
* custom_tables.total_rows / custom_tables.table_count
* errors.last_24h / shadow_diffs.last_24h
*
* Monthly Summary (`TMDO_Monthly_Summary`) reads these rows for the
* `zone_growth` section instead of querying live tables, so the monthly
* rollup is fast even on large databases.
*
* @package WP_Data_Optimizer
* @since 2.6.2
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Collects site-wide EAV health metrics and writes to wpdo_site_metrics.
*/
class TMDO_Site_Metrics_Collector {
/**
* Cron hook name.
*
* @var string
*/
public const CRON_HOOK = 'wpdo_collect_site_metrics';
/**
* How many days of daily rows to retain before pruning.
*
* @var int
*/
private const RETENTION_DAYS = 90;
/**
* Register the cron handler and return the instance for chaining.
*
* @return void
*/
public static function register(): void {
add_action( self::CRON_HOOK, array( __CLASS__, 'collect' ) );
}
/**
* Collect all site metrics and persist them to wpdo_site_metrics.
*
* Called by the daily cron. Safe to call manually (e.g., via WP-CLI).
*
* @param bool $dry_run When true, collect but do not write to the DB.
* @return array<string,int> Map of metric_key => metric_value collected.
*/
public static function collect( bool $dry_run = false ): array {
global $wpdb;
$now = TMDO_DB::now();
$metrics = array();
// ── EAV row counts ────────────────────────────────────────────────
$eav_tables = array(
'eav.postmeta_rows' => $wpdb->postmeta,
'eav.usermeta_rows' => $wpdb->usermeta,
'eav.termmeta_rows' => $wpdb->termmeta,
'eav.commentmeta_rows' => $wpdb->commentmeta,
);
foreach ( $eav_tables as $key => $table ) {
$count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM `{$table}`" ); // phpcs:ignore WordPress.DB
$metrics[ $key ] = $count;
}
// ── Flat-table row counts (hot + cold dynamic tables, warm) ───────
$hot_rows = 0;
$cold_rows = 0;
if ( class_exists( 'TMDO_Schema_Registry' ) ) {
$registry = TMDO_Schema_Registry::instance();
foreach ( $registry->get_hot_post_types() as $pt ) {
$ht = $wpdb->prefix . 'wpdo_hot_' . sanitize_key( $pt );
$exists = (int) $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = %s', $ht ) ); // phpcs:ignore WordPress.DB
if ( $exists ) {
$hot_rows += (int) $wpdb->get_var( "SELECT COUNT(*) FROM `{$ht}`" ); // phpcs:ignore WordPress.DB
}
}
foreach ( $registry->get_cold_post_types() as $pt ) {
$ct = $wpdb->prefix . 'wpdo_cold_' . sanitize_key( $pt );
$exists = (int) $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = %s', $ct ) ); // phpcs:ignore WordPress.DB
if ( $exists ) {
$cold_rows += (int) $wpdb->get_var( "SELECT COUNT(*) FROM `{$ct}`" ); // phpcs:ignore WordPress.DB
}
}
}
$warm_table = $wpdb->prefix . 'wpdo_warm';
$metrics['flat.hot_rows'] = $hot_rows;
$metrics['flat.cold_rows'] = $cold_rows;
$metrics['flat.warm_rows'] = (int) $wpdb->get_var( "SELECT COUNT(*) FROM `{$warm_table}`" ); // phpcs:ignore WordPress.DB
// ── Custom table row counts ───────────────────────────────────────
$custom_rows = 0;
$custom_count = 0;
if ( class_exists( 'TMDO_Custom_Table_Registry' ) ) {
foreach ( TMDO_Custom_Table_Registry::instance()->all() as $cfg ) {
$tbl = $wpdb->prefix . $cfg['table_name'];
$exists = (int) $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = %s', $tbl ) ); // phpcs:ignore WordPress.DB
if ( $exists ) {
$custom_rows += (int) $wpdb->get_var( "SELECT COUNT(*) FROM `{$tbl}`" ); // phpcs:ignore WordPress.DB
++$custom_count;
}
}
}
$metrics['custom_tables.total_rows'] = $custom_rows;
$metrics['custom_tables.table_count'] = $custom_count;
// ── Error / shadow-diff activity (last 24 h) ─────────────────────
$errors_table = $wpdb->prefix . 'wpdo_errors';
$metrics['errors.last_24h'] = (int) $wpdb->get_var(
"SELECT COUNT(*) FROM `{$errors_table}` WHERE created_at >= DATE_SUB(UTC_TIMESTAMP(), INTERVAL 24 HOUR)" // phpcs:ignore WordPress.DB
);
$shadow_table = $wpdb->prefix . 'wpdo_shadow_diffs';
$shadow_exists = (int) $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = %s', $shadow_table ) ); // phpcs:ignore WordPress.DB
$metrics['shadow_diffs.last_24h'] = $shadow_exists
? (int) $wpdb->get_var( "SELECT COUNT(*) FROM `{$shadow_table}` WHERE ts >= DATE_SUB(UTC_TIMESTAMP(), INTERVAL 24 HOUR)" ) // phpcs:ignore WordPress.DB
: 0;
if ( $dry_run ) {
return $metrics;
}
// ── Persist each metric to wpdo_site_metrics ─────────────────────
$dest = TMDO_DB::table( 'wpdo_site_metrics' );
foreach ( $metrics as $key => $value ) {
$wpdb->insert(
$dest,
array(
'collected_at' => $now,
'metric_key' => $key,
'metric_value' => $value,
'context' => null,
),
array( '%s', '%s', '%d', '%s' )
);
}
// ── Prune old rows beyond retention window ────────────────────────
$cutoff = gmdate( 'Y-m-d H:i:s', strtotime( '-' . self::RETENTION_DAYS . ' days' ) );
$wpdb->query( $wpdb->prepare( "DELETE FROM {$dest} WHERE collected_at < %s", $cutoff ) ); // phpcs:ignore WordPress.DB
if ( class_exists( 'TMDO_Logger' ) ) {
TMDO_Logger::info(
'site_metrics_collected',
array(
'metric_count' => count( $metrics ),
'postmeta_rows' => $metrics['eav.postmeta_rows'] ?? 0,
'hot_rows' => $metrics['flat.hot_rows'] ?? 0,
'custom_rows' => $metrics['custom_tables.total_rows'] ?? 0,
)
);
}
return $metrics;
}
/**
* Get the most recent snapshot (latest collected_at timestamp).
*
* @return array<string,int> metric_key => metric_value, or empty on miss.
*/
public static function get_latest_snapshot(): array {
global $wpdb;
$dest = TMDO_DB::table( 'wpdo_site_metrics' );
$latest_ts = $wpdb->get_var( "SELECT MAX(collected_at) FROM `{$dest}`" ); // phpcs:ignore WordPress.DB
if ( ! $latest_ts ) {
return array();
}
$rows = (array) $wpdb->get_results(
$wpdb->prepare(
"SELECT metric_key, metric_value FROM `{$dest}` WHERE collected_at = %s", // phpcs:ignore WordPress.DB
$latest_ts
),
ARRAY_A
);
$out = array();
foreach ( $rows as $r ) {
$out[ (string) $r['metric_key'] ] = (int) $r['metric_value'];
}
return $out;
}
/**
* Get daily metric history for a single key over the past N days.
*
* @param string $metric_key Metric key (e.g. 'eav.postmeta_rows').
* @param int $days Number of days of history to return (default 30).
* @return array<array{collected_at:string,value:int}> Oldest-first.
*/
public static function get_history( string $metric_key, int $days = 30 ): array {
global $wpdb;
$dest = TMDO_DB::table( 'wpdo_site_metrics' );
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $dest is a validated table name from TMDO_DB::table().
$rows = (array) $wpdb->get_results(
$wpdb->prepare(
"SELECT collected_at, metric_value AS value
FROM `{$dest}`
WHERE metric_key = %s
AND collected_at >= DATE_SUB(UTC_TIMESTAMP(), INTERVAL %d DAY)
ORDER BY collected_at ASC",
$metric_key,
$days
),
ARRAY_A
);
// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
return array_map(
static fn( $r ) => array(
'collected_at' => (string) $r['collected_at'],
'value' => (int) $r['value'],
),
$rows
);
}
}