47288db826
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
239 lines
8.6 KiB
PHP
239 lines
8.6 KiB
PHP
<?php
|
||
/**
|
||
* TMDO_Admin_WC — admin dashboard panel for WooCommerce integration.
|
||
*
|
||
* URL: Tools → WP Data Optimizer (parent menu) → WooCommerce sub-page.
|
||
*
|
||
* Shows:
|
||
* - HPOS status + recommendation
|
||
* - WC tables registered (count + health)
|
||
* - Top vendors by commission (from wp_wpdo_wc_commissions)
|
||
*
|
||
* @package WP_Data_Optimizer
|
||
* @since 2.1.0
|
||
*/
|
||
|
||
if ( ! defined( 'ABSPATH' ) ) {
|
||
exit;
|
||
}
|
||
|
||
/**
|
||
* WC admin panel.
|
||
*/
|
||
final class TMDO_Admin_WC {
|
||
|
||
private const MENU_SLUG = 'wpdo-wc';
|
||
private const CAP = 'manage_options';
|
||
|
||
/**
|
||
* Wire the menu item — only when WC is active.
|
||
*
|
||
* @return void
|
||
*/
|
||
public static function register(): void {
|
||
if ( ! class_exists( 'TMDO_WooCommerce' ) || ! TMDO_WooCommerce::is_active() ) {
|
||
return;
|
||
}
|
||
add_action( 'admin_menu', array( __CLASS__, 'register_menu' ), 11 );
|
||
}
|
||
|
||
/**
|
||
* Add submenu under "WP Data Optimizer" (which lives under Tools).
|
||
*
|
||
* @return void
|
||
*/
|
||
public static function register_menu(): void {
|
||
add_submenu_page(
|
||
'tools.php',
|
||
__( 'WPDO WooCommerce', 'tmdo-woocommerce' ),
|
||
__( 'WPDO WC', 'tmdo-woocommerce' ),
|
||
self::CAP,
|
||
self::MENU_SLUG,
|
||
array( __CLASS__, 'render' )
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Render the dashboard.
|
||
*
|
||
* @return void
|
||
*/
|
||
public static function render(): void {
|
||
$hpos = class_exists( 'TMDO_WooCommerce' ) ? TMDO_WooCommerce::is_hpos_enabled() : false;
|
||
$wc_ver = class_exists( 'TMDO_WooCommerce' ) ? TMDO_WooCommerce::wc_version() : 'unknown';
|
||
$tables = class_exists( 'TMDO_Custom_Table_Registry' )
|
||
? TMDO_Custom_Table_Registry::instance()->for_provider( 'woocommerce' )
|
||
: array();
|
||
$vendors = self::top_vendors_by_commission( 10 );
|
||
$totals = self::global_commission_totals();
|
||
?>
|
||
<div class="wrap">
|
||
<h1><?php esc_html_e( 'WPDO × WooCommerce', 'tmdo-woocommerce' ); ?></h1>
|
||
|
||
<h2><?php esc_html_e( 'WC 環境', 'tmdo-woocommerce' ); ?></h2>
|
||
<table class="widefat" style="max-width:520px;">
|
||
<tr>
|
||
<th><?php esc_html_e( 'WC 版本', 'tmdo-woocommerce' ); ?></th>
|
||
<td><?php echo esc_html( $wc_ver ); ?></td>
|
||
</tr>
|
||
<tr>
|
||
<th><?php esc_html_e( 'HPOS 啟用', 'tmdo-woocommerce' ); ?></th>
|
||
<td>
|
||
<?php if ( $hpos ) : ?>
|
||
<span style="color:#2a5a2a;">✅ <?php esc_html_e( '是 — orders 走 wp_wc_orders 不污染 postmeta', 'tmdo-woocommerce' ); ?></span>
|
||
<?php else : ?>
|
||
<span style="color:#c44;">⚠️ <?php esc_html_e( '否 — orders 仍存於 wp_postmeta(建議啟用以加速)', 'tmdo-woocommerce' ); ?></span>
|
||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=wc-settings&tab=advanced§ion=features' ) ); ?>" class="button button-small"><?php esc_html_e( '前往設定', 'tmdo-woocommerce' ); ?></a>
|
||
<?php endif; ?>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th><?php esc_html_e( 'WPDO 註冊的 WC 表', 'tmdo-woocommerce' ); ?></th>
|
||
<td><?php echo (int) count( $tables ); ?> tables</td>
|
||
</tr>
|
||
</table>
|
||
|
||
<h2><?php esc_html_e( 'Vendor Commissions(marketplace 訂單)', 'tmdo-woocommerce' ); ?></h2>
|
||
<?php if ( $totals['order_count'] > 0 ) : ?>
|
||
<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:1rem;max-width:720px;margin:1rem 0;">
|
||
<div class="wpdo-card">
|
||
<div class="wpdo-card__num"><?php echo esc_html( number_format_i18n( $totals['order_count'] ) ); ?></div>
|
||
<div class="wpdo-card__lbl"><?php esc_html_e( '總訂單數', 'tmdo-woocommerce' ); ?></div>
|
||
</div>
|
||
<div class="wpdo-card">
|
||
<div class="wpdo-card__num">$<?php echo esc_html( number_format_i18n( $totals['total_subtotal'], 2 ) ); ?></div>
|
||
<div class="wpdo-card__lbl"><?php esc_html_e( '總交易額', 'tmdo-woocommerce' ); ?></div>
|
||
</div>
|
||
<div class="wpdo-card">
|
||
<div class="wpdo-card__num">$<?php echo esc_html( number_format_i18n( $totals['total_commission'], 2 ) ); ?></div>
|
||
<div class="wpdo-card__lbl"><?php esc_html_e( '平台抽成', 'tmdo-woocommerce' ); ?></div>
|
||
</div>
|
||
<div class="wpdo-card">
|
||
<div class="wpdo-card__num">$<?php echo esc_html( number_format_i18n( $totals['total_payout'], 2 ) ); ?></div>
|
||
<div class="wpdo-card__lbl"><?php esc_html_e( 'Vendor 應得', 'tmdo-woocommerce' ); ?></div>
|
||
</div>
|
||
</div>
|
||
|
||
<h3><?php esc_html_e( 'Top 10 Vendors', 'tmdo-woocommerce' ); ?></h3>
|
||
<table class="widefat striped">
|
||
<thead>
|
||
<tr>
|
||
<th><?php esc_html_e( 'Vendor', 'tmdo-woocommerce' ); ?></th>
|
||
<th><?php esc_html_e( '訂單數', 'tmdo-woocommerce' ); ?></th>
|
||
<th><?php esc_html_e( '交易額', 'tmdo-woocommerce' ); ?></th>
|
||
<th><?php esc_html_e( '平台抽成', 'tmdo-woocommerce' ); ?></th>
|
||
<th><?php esc_html_e( 'Vendor 應得', 'tmdo-woocommerce' ); ?></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php
|
||
foreach ( $vendors as $v ) :
|
||
$user = get_userdata( (int) $v['vendor_id'] );
|
||
?>
|
||
<tr>
|
||
<td><?php echo $user ? esc_html( $user->display_name ) : '#' . (int) $v['vendor_id']; ?></td>
|
||
<td><?php echo (int) $v['order_count']; ?></td>
|
||
<td>$<?php echo esc_html( number_format_i18n( (float) $v['subtotal'], 2 ) ); ?></td>
|
||
<td>$<?php echo esc_html( number_format_i18n( (float) $v['commission'], 2 ) ); ?></td>
|
||
<td>$<?php echo esc_html( number_format_i18n( (float) $v['payout'], 2 ) ); ?></td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
</tbody>
|
||
</table>
|
||
<?php else : ?>
|
||
<p style="opacity:.6;"><?php esc_html_e( '尚未有 marketplace 訂單。當客戶下訂並進入 processing/completed 狀態,commission 會自動寫入 wp_wpdo_wc_commissions。', 'tmdo-woocommerce' ); ?></p>
|
||
<?php endif; ?>
|
||
|
||
<h2><?php esc_html_e( '已註冊的 WC 表', 'tmdo-woocommerce' ); ?></h2>
|
||
<table class="widefat striped">
|
||
<thead>
|
||
<tr>
|
||
<th><?php esc_html_e( '表名', 'tmdo-woocommerce' ); ?></th>
|
||
<th><?php esc_html_e( '描述', 'tmdo-woocommerce' ); ?></th>
|
||
<th><?php esc_html_e( '健康', 'tmdo-woocommerce' ); ?></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php
|
||
foreach ( $tables as $t ) :
|
||
$probe = TMDO_WooCommerce::doctor_check( $t['table_name'] );
|
||
?>
|
||
<tr>
|
||
<td><code><?php echo esc_html( $t['table_name'] ); ?></code></td>
|
||
<td><?php echo esc_html( $t['description'] ?? '' ); ?></td>
|
||
<td>
|
||
<?php
|
||
// Sec-3 hardening: wrap literal ternary in wp_kses_post for pattern hygiene.
|
||
echo wp_kses_post( $probe['ok'] ? '✅ ' : '⚠️ ' );
|
||
echo esc_html( $probe['message'] );
|
||
?>
|
||
</td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
</tbody>
|
||
</table>
|
||
|
||
<style>
|
||
.wpdo-card { background:#fff; padding:1rem; border-radius:8px; border:1px solid #dcdcde; text-align:center; }
|
||
.wpdo-card__num { font-size:1.75rem; font-weight:700; color:#c08a5b; }
|
||
.wpdo-card__lbl { font-size:.8rem; opacity:.7; margin-top:.25rem; }
|
||
</style>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
/**
|
||
* Top N vendors by total commission.
|
||
*
|
||
* @param int $limit Limit.
|
||
* @return array
|
||
*/
|
||
private static function top_vendors_by_commission( int $limit = 10 ): array {
|
||
global $wpdb;
|
||
$table = TMDO_DB::table( 'wpdo_wc_commissions' );
|
||
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $table from TMDO_DB::table() (sanitised); aggregate query.
|
||
return $wpdb->get_results(
|
||
$wpdb->prepare(
|
||
"SELECT vendor_id, COUNT(*) AS order_count,
|
||
SUM(subtotal) AS subtotal,
|
||
SUM(commission) AS commission,
|
||
SUM(vendor_payout) AS payout
|
||
FROM `{$table}`
|
||
GROUP BY vendor_id
|
||
ORDER BY commission DESC
|
||
LIMIT %d",
|
||
$limit
|
||
),
|
||
ARRAY_A
|
||
) ?: array();
|
||
// phpcs:enable
|
||
}
|
||
|
||
/**
|
||
* Global commission summary across all vendors.
|
||
*
|
||
* @return array
|
||
*/
|
||
private static function global_commission_totals(): array {
|
||
global $wpdb;
|
||
$table = TMDO_DB::table( 'wpdo_wc_commissions' );
|
||
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared -- $table from TMDO_DB::table() (sanitised); aggregate query.
|
||
$row = $wpdb->get_row(
|
||
"SELECT
|
||
COUNT(*) AS order_count,
|
||
SUM(subtotal) AS total_subtotal,
|
||
SUM(commission) AS total_commission,
|
||
SUM(vendor_payout) AS total_payout
|
||
FROM `{$table}`",
|
||
ARRAY_A
|
||
);
|
||
// phpcs:enable
|
||
return array(
|
||
'order_count' => (int) ( $row['order_count'] ?? 0 ),
|
||
'total_subtotal' => (float) ( $row['total_subtotal'] ?? 0 ),
|
||
'total_commission' => (float) ( $row['total_commission'] ?? 0 ),
|
||
'total_payout' => (float) ( $row['total_payout'] ?? 0 ),
|
||
);
|
||
}
|
||
}
|