0 ) : ?>
·
= 0.5 ) {
++$actionable_count;
}
}
}
}
if ( $actionable_count > 0 ) :
$ms_url = add_query_arg( 'tab', 'module-suggestions', $page_url );
?>
🤖
false );
if ( ! empty( $attn['needs'] ) && 'running' !== ( $attn['job_state'] ?? '' ) ) :
$wizard_url = add_query_arg( 'tab', 'migration-wizard', $page_url );
?>
🔴
%1$s 行 wp_usermeta EAV 殘留橫跨 %2$s 個 entity group(當前 ratio 1:%3$s)—', '2meet-data-optimizer' );
printf(
wp_kses( $msg, array( 'strong' => array() ) ),
esc_html( number_format_i18n( (int) $attn['eav_rows'] ) ),
esc_html( (string) (int) $attn['groups_with_residue'] ),
esc_html( (string) $attn['ratio'] )
);
?>
⏳
0 );
if ( ! empty( $gc['total'] ) && (int) $gc['total'] > 0 ) :
$confirm_msg = sprintf(
/* translators: %s: total garbage row count */
esc_html__( '即將從 wp_postmeta 刪除 %s 行垃圾資料(transients + _wp_old_date + 過期 _edit_lock)。確認執行?', '2meet-data-optimizer' ),
number_format_i18n( (int) $gc['total'] )
);
?>
🧹
%1$s 行可清理垃圾(transients %2$s + _wp_old_date %3$s + 過期 _edit_lock %4$s)—', '2meet-data-optimizer' );
printf(
wp_kses( $gc_msg, array( 'strong' => array() ) ),
esc_html( number_format_i18n( (int) $gc['total'] ) ),
esc_html( number_format_i18n( (int) $gc['transients'] ) ),
esc_html( number_format_i18n( (int) $gc['wp_old_date'] ) ),
esc_html( number_format_i18n( (int) $gc['edit_locks'] ) )
);
?>
0 ) :
$total_eav = 0;
foreach ( $post_diag['groups'] as $g ) {
$total_eav += (int) $g['eav_rows'];
}
$post_color = $total_eav > 0 ? '#dba617' : '#46b450';
$post_bg = $total_eav > 0 ? '#fffbe5' : '#ecf7ed';
$post_label = $total_eav > 0
? sprintf(
/* translators: 1: total EAV rows, 2: ratio */
__( 'Post Entity:偵測到 %1$s 行 wp_postmeta EAV 殘留(當前 ratio 1:%2$s,mode=%3$s)—', '2meet-data-optimizer' ),
'%1$s',
'%2$s',
'%3$s'
)
: sprintf(
/* translators: 1: ratio */
__( 'Post Entity:無 EAV 殘留(ratio 1:%1$s,mode=%2$s)', '2meet-data-optimizer' ),
'%1$s',
'%2$s'
);
?>
📦
0 ) {
printf(
wp_kses(
/* translators: 1: total EAV rows, 2: ratio, 3: mode */
__( 'Post Entity:偵測到 %1$s 行 wp_postmeta EAV 殘留(當前 ratio 1:%2$s,mode=%3$s)— v2.9.5 將提供一鍵遷移 UI。', '2meet-data-optimizer' ),
array( 'strong' => array() )
),
esc_html( number_format_i18n( $total_eav ) ),
esc_html( (string) $post_diag['ratio'] ),
esc_html( $post_diag['mode'] )
);
} else {
printf(
wp_kses(
/* translators: 1: ratio, 2: mode */
__( 'Post Entity:✓ 無 EAV 殘留(ratio 1:%1$s,mode=%2$s)', '2meet-data-optimizer' ),
array( 'strong' => array() )
),
esc_html( (string) $post_diag['ratio'] ),
esc_html( $post_diag['mode'] )
);
}
?>
0 ) {
$level = 'critical';
$msg = sprintf( /* translators: %d: count */ __( '%d 項 critical 警告', '2meet-data-optimizer' ), $crit );
} elseif ( $rec > 0 ) {
$level = 'warn';
$msg = sprintf( /* translators: %d: count */ __( '%d 項 recommended 提示', '2meet-data-optimizer' ), $rec );
} else {
$level = 'good';
$streak = TMDO_Health_Cron::consecutive_green_days();
}
$msg .= ' · ' . sprintf(
/* translators: %s: timestamp */
__( '最後執行:%s', '2meet-data-optimizer' ),
(string) $last['ran_at']
);
} else {
$msg = __( '尚未執行過健康檢查', '2meet-data-optimizer' );
}
// Last snapshot age.
$snap_table = $wpdb->prefix . 'wpdo_snapshots';
$snap_exists = (int) $wpdb->get_var(
$wpdb->prepare( // phpcs:ignore WordPress.DB
'SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = %s',
$snap_table
)
);
$last_snapshot = __( '從未', '2meet-data-optimizer' );
if ( 1 === $snap_exists ) {
$ts = (string) $wpdb->get_var( "SELECT created_at FROM `{$snap_table}` ORDER BY created_at DESC LIMIT 1" ); // phpcs:ignore WordPress.DB
if ( '' !== $ts ) {
$diff = time() - strtotime( $ts . ' UTC' );
$last_snapshot = $diff < 0 ? $ts : self::human_time_diff( $diff );
}
}
// Largest zone table by row count (rough sample).
$largest = '—';
if ( 1 === $snap_exists ) {
$row_count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM `{$wpdb->prefix}wpdo_warm`" ); // phpcs:ignore WordPress.DB
if ( $row_count > 0 ) {
$largest = sprintf( 'wpdo_warm (%s)', number_format_i18n( $row_count ) );
}
}
// Conflict count (cheap — uses cached summary).
$conflicts = 0;
if ( class_exists( 'TMDO_Conflict_Monitor' ) ) {
$summary = TMDO_Conflict_Monitor::get_summary();
$conflicts = (int) ( $summary['total'] ?? 0 );
}
// wp_postmeta size (informational).
$pm_count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM `{$wpdb->postmeta}`" ); // phpcs:ignore WordPress.DB
$result = array(
'level' => $level,
'summary_msg' => $msg,
'streak' => $streak,
'last_snapshot' => $last_snapshot,
'largest_zone' => $largest,
'conflicts' => $conflicts,
'postmeta_human' => number_format_i18n( $pm_count ),
);
set_transient( 'wpdo_dashboard_widget_status', $result, self::CACHE_TTL );
return $result;
}
/**
* Map level → CSS class + label.
*
* @param string $level Level slug.
* @return array {class:string,label:string}
*/
private static function traffic_light( string $level ): array {
switch ( $level ) {
case 'good':
return array(
'class' => 'good',
'label' => __( '正常', '2meet-data-optimizer' ),
);
case 'warn':
return array(
'class' => 'warn',
'label' => __( '注意', '2meet-data-optimizer' ),
);
case 'critical':
return array(
'class' => 'crit',
'label' => __( '警告', '2meet-data-optimizer' ),
);
default:
return array(
'class' => 'gray',
'label' => __( '未知', '2meet-data-optimizer' ),
);
}
}
/**
* Human-readable time-diff (seconds → "5 minutes ago" style). Uses WP
* `human_time_diff` when available; falls back to simple math otherwise.
*
* @param int $seconds Seconds delta (>=0).
* @return string
*/
private static function human_time_diff( int $seconds ): string {
if ( $seconds < 60 ) {
return $seconds . 's';
}
if ( function_exists( 'human_time_diff' ) ) {
return sprintf(
/* translators: %s: human-readable time difference */
__( '%s 前', '2meet-data-optimizer' ),
human_time_diff( time() - $seconds, time() )
);
}
if ( $seconds < 3600 ) {
return floor( $seconds / 60 ) . 'm';
}
if ( $seconds < 86400 ) {
return floor( $seconds / 3600 ) . 'h';
}
return floor( $seconds / 86400 ) . 'd';
}
}