feat(2meet-data-optimizer): warn when HivePress / WooCommerce run without their AddOn

- TMDO_Compatibility::missing_integration_addons() reports active HivePress / WooCommerce whose AddOn bootstrap class is absent
- Surface it as Site Health test wpdo_missing_integration_addons (also on the admin Doctor tab) and an administrator notice (TMDO_Missing_Addons_Notice)
- Verify: MissingIntegrationAddonsTest (5, class stand-ins in separate processes); core unit 651 / integration 449, HP 148, WC 10 OK; read-only check: dev20/21 HivePress+WooCommerce, dev22 HivePress, others clean
- PR: PR-035
This commit is contained in:
2026-09-26 00:36:02 +08:00
parent 3d650eb848
commit c84d2409b7
7 changed files with 246 additions and 31 deletions
+11 -10
View File
@@ -2895,7 +2895,7 @@ wpdo.getListings({ per_page: 3 }).then(r => console.log(r));'
?>
<h2><?php esc_html_e( '健康檢查(Doctor)', '2meet-data-optimizer' ); ?></h2>
<p class="description">
<?php esc_html_e( '9 項自我診斷檢查:schema 完整性、錯誤預算、hook 衝突、autoload 大小、postmeta 爆量、orphan zone rows、缺少快照、實體群組名稱衝突、孤兒實體群組。', '2meet-data-optimizer' ); ?>
<?php esc_html_e( '10 項自我診斷檢查:schema 完整性、錯誤預算、hook 衝突、autoload 大小、postmeta 爆量、orphan zone rows、缺少快照、實體群組名稱衝突、孤兒實體群組、缺少對應 AddOn。', '2meet-data-optimizer' ); ?>
</p>
<p>
<a class="button" href="<?php echo esc_url( admin_url( 'site-health.php' ) ); ?>">
@@ -2909,15 +2909,16 @@ wpdo.getListings({ per_page: 3 }).then(r => console.log(r));'
}
$tests = array(
'wpdo_schema_drift' => array( 'check_schema_drift', __( 'Schema 完整性', '2meet-data-optimizer' ) ),
'wpdo_error_budget' => array( 'check_error_budget', __( '錯誤預算(過去 7 天)', '2meet-data-optimizer' ) ),
'wpdo_hook_conflicts' => array( 'check_hook_conflicts', __( 'Hook 衝突', '2meet-data-optimizer' ) ),
'wpdo_autoload_bloat' => array( 'check_autoload_bloat', __( 'Autoload 大小', '2meet-data-optimizer' ) ),
'wpdo_postmeta_explosion' => array( 'check_postmeta_explosion', __( 'wp_postmeta 爆量', '2meet-data-optimizer' ) ),
'wpdo_orphan_zone_rows' => array( 'check_orphan_zone_rows', __( 'Orphan zone rows', '2meet-data-optimizer' ) ),
'wpdo_missing_snapshot' => array( 'check_missing_snapshot', __( '缺少最近快照', '2meet-data-optimizer' ) ),
'wpdo_entity_group_collisions' => array( 'check_entity_group_collisions', __( '實體群組名稱衝突', '2meet-data-optimizer' ) ),
'wpdo_orphaned_entity_groups' => array( 'check_orphaned_entity_groups', __( '孤兒實體群組', '2meet-data-optimizer' ) ),
'wpdo_schema_drift' => array( 'check_schema_drift', __( 'Schema 完整性', '2meet-data-optimizer' ) ),
'wpdo_error_budget' => array( 'check_error_budget', __( '錯誤預算(過去 7 天)', '2meet-data-optimizer' ) ),
'wpdo_hook_conflicts' => array( 'check_hook_conflicts', __( 'Hook 衝突', '2meet-data-optimizer' ) ),
'wpdo_autoload_bloat' => array( 'check_autoload_bloat', __( 'Autoload 大小', '2meet-data-optimizer' ) ),
'wpdo_postmeta_explosion' => array( 'check_postmeta_explosion', __( 'wp_postmeta 爆量', '2meet-data-optimizer' ) ),
'wpdo_orphan_zone_rows' => array( 'check_orphan_zone_rows', __( 'Orphan zone rows', '2meet-data-optimizer' ) ),
'wpdo_missing_snapshot' => array( 'check_missing_snapshot', __( '缺少最近快照', '2meet-data-optimizer' ) ),
'wpdo_entity_group_collisions' => array( 'check_entity_group_collisions', __( '實體群組名稱衝突', '2meet-data-optimizer' ) ),
'wpdo_orphaned_entity_groups' => array( 'check_orphaned_entity_groups', __( '孤兒實體群組', '2meet-data-optimizer' ) ),
'wpdo_missing_integration_addons' => array( 'check_missing_integration_addons', __( '缺少對應 AddOn', '2meet-data-optimizer' ) ),
);
?>
<table class="widefat striped">
+2 -1
View File
@@ -183,7 +183,7 @@ class TMDO_Help_Tabs {
* @return string
*/
private static function content_doctor(): string {
return '<p>' . esc_html__( '9 項自動健康檢查:', '2meet-data-optimizer' ) . '</p>'
return '<p>' . esc_html__( '10 項自動健康檢查:', '2meet-data-optimizer' ) . '</p>'
. '<ol class="wpdo-list-disc">'
. '<li><strong>schema_drift</strong> — ' . esc_html__( '所有 v2 表是否存在', '2meet-data-optimizer' ) . '</li>'
. '<li><strong>error_budget</strong> — ' . esc_html__( '7 天內 wp_wpdo_errors 行數', '2meet-data-optimizer' ) . '</li>'
@@ -194,6 +194,7 @@ class TMDO_Help_Tabs {
. '<li><strong>missing_snapshot</strong> — ' . esc_html__( '在 cutover/cleanup/complete 但 7 天沒 snapshot', '2meet-data-optimizer' ) . '</li>'
. '<li><strong>entity_group_collisions</strong> — ' . esc_html__( '同名實體群組被不同外掛以不同欄位註冊(後者被忽略)', '2meet-data-optimizer' ) . '</li>'
. '<li><strong>orphaned_entity_groups</strong> — ' . esc_html__( '扁平表還在但已無外掛註冊的群組(已依保存的定義還原以維持可讀)', '2meet-data-optimizer' ) . '</li>'
. '<li><strong>missing_integration_addons</strong> — ' . esc_html__( 'HivePress / WooCommerce 已啟用但對應 AddOn 未啟用', '2meet-data-optimizer' ) . '</li>'
. '</ol>'
. '<p>' . esc_html__( '結果有 5 分鐘 transient cache,剛操作完想立刻看新值請等下個週期。', '2meet-data-optimizer' ) . '</p>';
}
@@ -0,0 +1,62 @@
<?php
/**
* Admin notice when HivePress / WooCommerce run without their AddOn.
*
* Core knows nothing about either plugin; their fields are only optimised by
* the matching AddOn. Without it, aeav_only data stays readable only through
* the orphan-group restore, and new data is not optimised at all.
*
* @package WP_Data_Optimizer
*/
declare(strict_types=1);
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Warns administrators about integrations whose AddOn is not active.
*/
final class TMDO_Missing_Addons_Notice {
/**
* Hook the notice.
*
* @return void
*/
public static function register(): void {
add_action( 'admin_notices', array( __CLASS__, 'render' ) );
}
/**
* Print the notice for administrators when an integration lacks its AddOn.
*
* @return void
*/
public static function render(): void {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$missing = TMDO_Compatibility::missing_integration_addons();
if ( empty( $missing ) ) {
return;
}
$lines = array();
foreach ( $missing as $plugin => $addon ) {
$lines[] = sprintf( '%s → %s', $plugin, $addon );
}
printf(
'<div class="notice notice-warning"><p><strong>%s</strong> %s</p></div>',
esc_html__( '2meet Data Optimizer:', '2meet-data-optimizer' ),
esc_html(
sprintf(
/* translators: %s: "Plugin → AddOn" pairs */
__( '以下外掛已啟用,但對應的 AddOn 沒有啟用,它們的欄位不會被優化:%s。請啟用對應的 AddOn。', '2meet-data-optimizer' ),
implode( ';', $lines )
)
)
);
}
}