Enhance CZL Express for WooCommerce Plugin Functionality

- Updated plugin URI for better branding consistency.
- Added environment checks to ensure WooCommerce is installed and meets version requirements.
- Improved AJAX handling for shipment creation and tracking updates, including enhanced error messages.
- Streamlined order management with new custom order statuses and improved logging for better tracking.
- Removed deprecated API test page and updated admin interface for clarity.
- Enhanced localization by ensuring all translatable strings use esc_html functions for security.

These changes improve the robustness, usability, and maintainability of the CZL Express plugin.
This commit is contained in:
wood chen 2025-01-15 00:08:34 +08:00
parent 7b7f41d0cc
commit 16965b29e1
21 changed files with 672 additions and 600 deletions

View File

@ -9,10 +9,10 @@ $tab = isset($_GET['tab']) ? sanitize_text_field($_GET['tab']) : 'settings';
<nav class="nav-tab-wrapper"> <nav class="nav-tab-wrapper">
<a href="?page=czl-express&tab=settings" class="nav-tab <?php echo $tab === 'settings' ? 'nav-tab-active' : ''; ?>"> <a href="?page=czl-express&tab=settings" class="nav-tab <?php echo $tab === 'settings' ? 'nav-tab-active' : ''; ?>">
<?php _e('基本设置', 'czlexpress-for-woocommerce'); ?> <?php esc_html_e('基本设置', 'czlexpress-for-woocommerce'); ?>
</a> </a>
<a href="?page=czl-express&tab=test" class="nav-tab <?php echo $tab === 'test' ? 'nav-tab-active' : ''; ?>"> <a href="?page=czl-express&tab=test" class="nav-tab <?php echo $tab === 'test' ? 'nav-tab-active' : ''; ?>">
<?php _e('接口测试', 'czlexpress-for-woocommerce'); ?> <?php esc_html_e('接口测试', 'czlexpress-for-woocommerce'); ?>
</a> </a>
</nav> </nav>

View File

@ -74,12 +74,12 @@ $settings = array(
</form> </form>
<div class="czl-api-test"> <div class="czl-api-test">
<h2><?php _e('API Connection Test', 'czlexpress-for-woocommerce'); ?></h2> <h2><?php esc_html_e('API Connection Test', 'czlexpress-for-woocommerce'); ?></h2>
<button type="button" class="button" id="czl-test-connection"> <button type="button" class="button" id="czl-test-connection">
<?php _e('Test Connection', 'czlexpress-for-woocommerce'); ?> <?php esc_html_e('Test Connection', 'czlexpress-for-woocommerce'); ?>
</button> </button>
<button type="button" class="button" id="czl-test-shipping-rate"> <button type="button" class="button" id="czl-test-shipping-rate">
<?php _e('Test Shipping Rate', 'czlexpress-for-woocommerce'); ?> <?php esc_html_e('Test Shipping Rate', 'czlexpress-for-woocommerce'); ?>
</button> </button>
<div id="czl-test-result"></div> <div id="czl-test-result"></div>
</div> </div>
@ -92,11 +92,11 @@ jQuery(function($) {
var $result = $('#czl-test-result'); var $result = $('#czl-test-result');
$button.prop('disabled', true); $button.prop('disabled', true);
$result.html('<?php _e('Testing...', 'czlexpress-for-woocommerce'); ?>'); $result.html('<?php esc_html_e('Testing...', 'czlexpress-for-woocommerce'); ?>');
$.post(ajaxurl, { $.post(ajaxurl, {
action: 'czl_test_connection', action: 'czl_test_connection',
nonce: '<?php echo wp_create_nonce('czl_test_api'); ?>' nonce: '<?php echo esc_attr(wp_create_nonce('czl_test_api')); ?>'
}, function(response) { }, function(response) {
$button.prop('disabled', false); $button.prop('disabled', false);
if (response.success) { if (response.success) {
@ -112,15 +112,15 @@ jQuery(function($) {
var $result = $('#czl-test-result'); var $result = $('#czl-test-result');
$button.prop('disabled', true); $button.prop('disabled', true);
$result.html('<?php _e('Testing...', 'czlexpress-for-woocommerce'); ?>'); $result.html('<?php esc_html_e('Testing...', 'czlexpress-for-woocommerce'); ?>');
$.post(ajaxurl, { $.post(ajaxurl, {
action: 'czl_test_shipping_rate', action: 'czl_test_shipping_rate',
nonce: '<?php echo wp_create_nonce('czl_test_api'); ?>' nonce: '<?php echo esc_attr(wp_create_nonce('czl_test_api')); ?>'
}, function(response) { }, function(response) {
$button.prop('disabled', false); $button.prop('disabled', false);
if (response.success) { if (response.success) {
var html = '<div class="notice notice-success"><p><?php _e('Shipping rates retrieved successfully:', 'czlexpress-for-woocommerce'); ?></p>'; var html = '<div class="notice notice-success"><p><?php esc_html_e('Shipping rates retrieved successfully:', 'czlexpress-for-woocommerce'); ?></p>';
html += '<pre>' + wp.escapeHtml(JSON.stringify(response.data, null, 2)) + '</pre></div>'; html += '<pre>' + wp.escapeHtml(JSON.stringify(response.data, null, 2)) + '</pre></div>';
$result.html(html); $result.html(html);
} else { } else {

View File

@ -1,69 +0,0 @@
<?php
defined('ABSPATH') || exit;
?>
<div class="czl-api-test">
<h2><?php _e('API连接测试', 'czlexpress-for-woocommerce'); ?></h2>
<p class="description">
<?php _e('点击下面的按钮测试与CZL Express API的连接。', 'czlexpress-for-woocommerce'); ?>
</p>
<div class="test-buttons">
<button type="button" class="button" id="czl-test-connection">
<?php _e('测试连接', 'czlexpress-for-woocommerce'); ?>
</button>
<button type="button" class="button" id="czl-test-shipping-rate">
<?php _e('测试运费查询', 'czlexpress-for-woocommerce'); ?>
</button>
</div>
<div id="czl-test-result"></div>
</div>
<script>
jQuery(function($) {
$('#czl-test-connection').on('click', function() {
var $button = $(this);
var $result = $('#czl-test-result');
$button.prop('disabled', true);
$result.html('<?php _e('测试中...', 'czlexpress-for-woocommerce'); ?>');
$.post(ajaxurl, {
action: 'czl_test_connection',
nonce: '<?php echo wp_create_nonce('czl_test_api'); ?>'
}, function(response) {
$button.prop('disabled', false);
if (response.success) {
$result.html('<div class="notice notice-success"><p>' + wp.escapeHtml(response.data.message) + '</p></div>');
} else {
$result.html('<div class="notice notice-error"><p>' + wp.escapeHtml(response.data.message) + '</p></div>');
}
});
});
$('#czl-test-shipping-rate').on('click', function() {
var $button = $(this);
var $result = $('#czl-test-result');
$button.prop('disabled', true);
$result.html('<?php _e('测试中...', 'czlexpress-for-woocommerce'); ?>');
$.post(ajaxurl, {
action: 'czl_test_shipping_rate',
nonce: '<?php echo wp_create_nonce('czl_test_api'); ?>'
}, function(response) {
$button.prop('disabled', false);
if (response.success) {
var html = '<div class="notice notice-success"><p><?php _e('运费查询成功:', 'czlexpress-for-woocommerce'); ?></p>';
html += '<pre>' + wp.escapeHtml(JSON.stringify(response.data, null, 2)) + '</pre></div>';
$result.html(html);
} else {
$result.html('<div class="notice notice-error"><p>' + wp.escapeHtml(response.data.message) + '</p></div>');
}
});
});
});
</script>

View File

@ -23,8 +23,8 @@ foreach ($supported_currencies as $code => $name) {
<div class="czl-page-description"> <div class="czl-page-description">
<p> <p>
<?php _e('在这里设置人民币(CNY)与其他货币的汇率。运费将根据这些汇率自动转换。', 'czlexpress-for-woocommerce'); ?> <?php esc_html_e('在这里设置人民币(CNY)与其他货币的汇率。运费将根据这些汇率自动转换。', 'czlexpress-for-woocommerce'); ?>
<?php printf(__('当前商店使用的货币是: %s', 'czlexpress-for-woocommerce'), '<strong>' . $current_currency . '</strong>'); ?> <?php printf(esc_html__('当前商店使用的货币是: %s', 'czlexpress-for-woocommerce'), '<strong>' . esc_html($current_currency) . '</strong>'); ?>
</p> </p>
</div> </div>
@ -35,9 +35,9 @@ foreach ($supported_currencies as $code => $name) {
<table class="widefat czl-exchange-rates" id="czl-exchange-rates"> <table class="widefat czl-exchange-rates" id="czl-exchange-rates">
<thead> <thead>
<tr> <tr>
<th class="column-currency"><?php _e('货币', 'czlexpress-for-woocommerce'); ?></th> <th class="column-currency"><?php esc_html_e('货币', 'czlexpress-for-woocommerce'); ?></th>
<th class="column-rate"><?php _e('汇率 (1 CNY =)', 'czlexpress-for-woocommerce'); ?></th> <th class="column-rate"><?php esc_html_e('汇率 (1 CNY =)', 'czlexpress-for-woocommerce'); ?></th>
<th class="column-actions"><?php _e('操作', 'czlexpress-for-woocommerce'); ?></th> <th class="column-actions"><?php esc_html_e('操作', 'czlexpress-for-woocommerce'); ?></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -79,7 +79,7 @@ foreach ($supported_currencies as $code => $name) {
<td colspan="3"> <td colspan="3">
<button type="button" class="button add-rate"> <button type="button" class="button add-rate">
<span class="dashicons dashicons-plus-alt2"></span> <span class="dashicons dashicons-plus-alt2"></span>
<?php _e('添加汇率', 'czlexpress-for-woocommerce'); ?> <?php esc_html_e('添加汇率', 'czlexpress-for-woocommerce'); ?>
</button> </button>
</td> </td>
</tr> </tr>

View File

@ -51,24 +51,24 @@ wp_enqueue_script('jquery');
?> ?>
<script type="text/javascript"> <script type="text/javascript">
var czl_ajax = { var czl_ajax = {
ajax_url: '<?php echo admin_url('admin-ajax.php'); ?>', ajax_url: '<?php echo esc_url(admin_url('admin-ajax.php')); ?>',
nonce: '<?php echo wp_create_nonce('czl_ajax_nonce'); ?>', nonce: '<?php echo esc_attr(wp_create_nonce('czl_ajax_nonce')); ?>',
creating_text: '<?php _e('正在创建运单...', 'czlexpress-for-woocommerce'); ?>', creating_text: '<?php esc_html_e('正在创建运单...', 'czlexpress-for-woocommerce'); ?>',
success_text: '<?php _e('运单创建成功', 'czlexpress-for-woocommerce'); ?>', success_text: '<?php esc_html_e('运单创建成功', 'czlexpress-for-woocommerce'); ?>',
error_text: '<?php _e('运单创建失败', 'czlexpress-for-woocommerce'); ?>' error_text: '<?php esc_html_e('运单创建失败', 'czlexpress-for-woocommerce'); ?>'
}; };
</script> </script>
<div class="wrap"> <div class="wrap">
<h1><?php _e('CZL Express 订单管理', 'czlexpress-for-woocommerce'); ?></h1> <h1><?php esc_html_e('CZL Express 订单管理', 'czlexpress-for-woocommerce'); ?></h1>
<div class="tablenav top"> <div class="tablenav top">
<div class="alignleft actions"> <div class="alignleft actions">
<select id="bulk-action-selector-top"> <select id="bulk-action-selector-top">
<option value="-1"><?php _e('批量操作', 'czlexpress-for-woocommerce'); ?></option> <option value="-1"><?php esc_html_e('批量操作', 'czlexpress-for-woocommerce'); ?></option>
<option value="create_shipment"><?php _e('创建运单', 'czlexpress-for-woocommerce'); ?></option> <option value="create_shipment"><?php esc_html_e('创建运单', 'czlexpress-for-woocommerce'); ?></option>
</select> </select>
<button class="button" id="doaction"><?php _e('应用', 'czlexpress-for-woocommerce'); ?></button> <button class="button" id="doaction"><?php esc_html_e('应用', 'czlexpress-for-woocommerce'); ?></button>
</div> </div>
</div> </div>
@ -78,19 +78,19 @@ wp_enqueue_script('jquery');
<td class="manage-column column-cb check-column"> <td class="manage-column column-cb check-column">
<input type="checkbox" id="cb-select-all-1"> <input type="checkbox" id="cb-select-all-1">
</td> </td>
<th><?php _e('订单号', 'czlexpress-for-woocommerce'); ?></th> <th><?php esc_html_e('订单号', 'czlexpress-for-woocommerce'); ?></th>
<th><?php _e('日期', 'czlexpress-for-woocommerce'); ?></th> <th><?php esc_html_e('日期', 'czlexpress-for-woocommerce'); ?></th>
<th><?php _e('状态', 'czlexpress-for-woocommerce'); ?></th> <th><?php esc_html_e('状态', 'czlexpress-for-woocommerce'); ?></th>
<th><?php _e('收件人', 'czlexpress-for-woocommerce'); ?></th> <th><?php esc_html_e('收件人', 'czlexpress-for-woocommerce'); ?></th>
<th><?php _e('配送方式', 'czlexpress-for-woocommerce'); ?></th> <th><?php esc_html_e('配送方式', 'czlexpress-for-woocommerce'); ?></th>
<th><?php _e('运单信息', 'czlexpress-for-woocommerce'); ?></th> <th><?php esc_html_e('运单信息', 'czlexpress-for-woocommerce'); ?></th>
<th><?php _e('操作', 'czlexpress-for-woocommerce'); ?></th> <th><?php esc_html_e('操作', 'czlexpress-for-woocommerce'); ?></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<?php <?php
if (empty($orders)) { if (empty($orders)) {
echo '<tr><td colspan="8">' . __('没有找到订单', 'czlexpress-for-woocommerce') . '</td></tr>'; echo '<tr><td colspan="8">' . esc_html__('没有找到订单', 'czlexpress-for-woocommerce') . '</td></tr>';
} else { } else {
foreach ($orders as $order): foreach ($orders as $order):
$order_id = $order->get_id(); $order_id = $order->get_id();
@ -115,7 +115,7 @@ wp_enqueue_script('jquery');
<?php <?php
$status_name = wc_get_order_status_name($order->get_status()); $status_name = wc_get_order_status_name($order->get_status());
$status_class = sanitize_html_class('status-' . $order->get_status()); $status_class = sanitize_html_class('status-' . $order->get_status());
echo "<mark class='order-status {$status_class}'><span>" . esc_html($status_name) . "</span></mark>"; echo wp_kses_post("<mark class='order-status {$status_class}'><span>" . esc_html($status_name) . "</span></mark>");
?> ?>
</td> </td>
<td> <td>
@ -128,40 +128,40 @@ wp_enqueue_script('jquery');
</td> </td>
<td> <td>
<?php if ($shipment && !empty($shipment->tracking_number)): ?> <?php if ($shipment && !empty($shipment->tracking_number)): ?>
<strong><?php _e('运单号:', 'czlexpress-for-woocommerce'); ?></strong> <strong><?php esc_html_e('运单号:', 'czlexpress-for-woocommerce'); ?></strong>
<a href="https://exp.czl.net/track/?query=<?php echo esc_attr($shipment->tracking_number); ?>" target="_blank"> <a href="https://exp.czl.net/track/?query=<?php echo esc_attr($shipment->tracking_number); ?>" target="_blank">
<?php echo esc_html($shipment->tracking_number); ?> <?php echo esc_html($shipment->tracking_number); ?>
</a> </a>
<button type="button" class="button button-small edit-tracking-btn" <button type="button" class="button button-small edit-tracking-btn"
data-order-id="<?php echo $order_id; ?>" data-order-id="<?php echo esc_attr($order_id); ?>"
data-tracking-number="<?php echo esc_attr($shipment->tracking_number); ?>" data-tracking-number="<?php echo esc_attr($shipment->tracking_number); ?>"
style="margin-left: 5px;"> style="margin-left: 5px;">
<span class="dashicons dashicons-edit" style="font-size: 16px; height: 16px; width: 16px;"></span> <span class="dashicons dashicons-edit" style="font-size: 16px; height: 16px; width: 16px;"></span>
</button><br> </button><br>
<strong><?php _e('CZL订单号:', 'czlexpress-for-woocommerce'); ?></strong> <strong><?php esc_html_e('CZL订单号:', 'czlexpress-for-woocommerce'); ?></strong>
<?php echo esc_html($shipment->czl_order_id); ?><br> <?php echo esc_html($shipment->czl_order_id); ?><br>
<strong><?php _e('参考号:', 'czlexpress-for-woocommerce'); ?></strong> <strong><?php esc_html_e('参考号:', 'czlexpress-for-woocommerce'); ?></strong>
<?php echo esc_html($shipment->reference_number); ?><br> <?php echo esc_html($shipment->reference_number); ?><br>
<strong><?php _e('运单状态:', 'czlexpress-for-woocommerce'); ?></strong> <strong><?php esc_html_e('运单状态:', 'czlexpress-for-woocommerce'); ?></strong>
<?php echo esc_html($shipment->shipment_status); ?> <?php echo esc_html($shipment->shipment_status); ?>
<?php else: ?> <?php else: ?>
<?php _e('未创建运单', 'czlexpress-for-woocommerce'); ?> <?php esc_html_e('未创建运单', 'czlexpress-for-woocommerce'); ?>
<?php endif; ?> <?php endif; ?>
</td> </td>
<td> <td>
<?php if (!$shipment || empty($shipment->tracking_number)): ?> <?php if (!$shipment || empty($shipment->tracking_number)): ?>
<button type="button" class="button czl-create-btn" <button type="button" class="button czl-create-btn"
data-order-id="<?php echo $order_id; ?>"> data-order-id="<?php echo esc_attr($order_id); ?>">
<?php _e('创建运单', 'czlexpress-for-woocommerce'); ?> <?php esc_html_e('创建运单', 'czlexpress-for-woocommerce'); ?>
</button> </button>
<?php elseif (!empty($shipment->czl_order_id)): ?> <?php elseif (!empty($shipment->czl_order_id)): ?>
<button type="button" class="button" <button type="button" class="button"
onclick="printLabel('<?php echo $shipment->czl_order_id; ?>')"> onclick="printLabel('<?php echo esc_js($shipment->czl_order_id); ?>')">
<?php _e('打印标签', 'czlexpress-for-woocommerce'); ?> <?php esc_html_e('打印标签', 'czlexpress-for-woocommerce'); ?>
</button> </button>
<button type="button" class="button update-tracking-btn" <button type="button" class="button update-tracking-btn"
data-order-id="<?php echo $order_id; ?>"> data-order-id="<?php echo esc_attr($order_id); ?>">
<?php _e('更新轨迹', 'czlexpress-for-woocommerce'); ?> <?php esc_html_e('更新轨迹', 'czlexpress-for-woocommerce'); ?>
</button> </button>
<?php endif; ?> <?php endif; ?>
</td> </td>
@ -178,17 +178,17 @@ wp_enqueue_script('jquery');
<div style="padding:20px;"> <div style="padding:20px;">
<div class="form-field" style="margin-bottom:15px;"> <div class="form-field" style="margin-bottom:15px;">
<label for="new-tracking-number" style="display:block;margin-bottom:8px;font-weight:600;"> <label for="new-tracking-number" style="display:block;margin-bottom:8px;font-weight:600;">
<?php _e('新跟踪单号:', 'czlexpress-for-woocommerce'); ?> <?php esc_html_e('新跟踪单号:', 'czlexpress-for-woocommerce'); ?>
</label> </label>
<input type="text" id="new-tracking-number" style="width:100%;padding:5px;"> <input type="text" id="new-tracking-number" style="width:100%;padding:5px;">
<input type="hidden" id="edit-order-id" value=""> <input type="hidden" id="edit-order-id" value="">
</div> </div>
<div style="text-align:right;margin-top:20px;"> <div style="text-align:right;margin-top:20px;">
<button type="button" class="button" onclick="self.parent.tb_remove();" style="margin-right:5px;"> <button type="button" class="button" onclick="self.parent.tb_remove();" style="margin-right:5px;">
<?php _e('取消', 'czlexpress-for-woocommerce'); ?> <?php esc_html_e('取消', 'czlexpress-for-woocommerce'); ?>
</button> </button>
<button type="button" class="button button-primary" id="save-tracking-number"> <button type="button" class="button button-primary" id="save-tracking-number">
<?php _e('保存', 'czlexpress-for-woocommerce'); ?> <?php esc_html_e('保存', 'czlexpress-for-woocommerce'); ?>
</button> </button>
</div> </div>
</div> </div>
@ -208,7 +208,7 @@ jQuery(document).ready(function($) {
// 打开对话框 // 打开对话框
tb_show( tb_show(
'<?php _e('修改跟踪单号', 'czlexpress-for-woocommerce'); ?>', '<?php esc_html_e('修改跟踪单号', 'czlexpress-for-woocommerce'); ?>',
'#TB_inline?width=300&height=180&inlineId=edit-tracking-dialog' '#TB_inline?width=300&height=180&inlineId=edit-tracking-dialog'
); );
@ -296,7 +296,7 @@ jQuery(document).ready(function($) {
// 处理创建运单按钮点击 // 处理创建运单按钮点击
$(document).on('click', '.czl-create-btn', function() { $(document).on('click', '.czl-create-btn', function() {
var $button = $(this); var $button = $(this);
var orderId = $button.data('order-id'); var orderId = $(this).data('order-id');
// 如果按钮已经在处理中,则返回 // 如果按钮已经在处理中,则返回
if ($button.hasClass('processing')) { if ($button.hasClass('processing')) {

View File

@ -10,7 +10,7 @@ $groups = get_option('czl_product_groups', array());
<?php settings_errors(); ?> <?php settings_errors(); ?>
<div class="czl-page-description"> <div class="czl-page-description">
<p><?php _e('在这里管理运输方式的分组显示。相同分组的运输方式将合并显示,并显示最低价格。', 'czlexpress-for-woocommerce'); ?></p> <p><?php esc_html_e('在这里管理运输方式的分组显示。相同分组的运输方式将合并显示,并显示最低价格。', 'czlexpress-for-woocommerce'); ?></p>
</div> </div>
<form method="post" action=""> <form method="post" action="">
@ -20,10 +20,10 @@ $groups = get_option('czl_product_groups', array());
<table class="widefat czl-product-groups" id="czl-product-groups"> <table class="widefat czl-product-groups" id="czl-product-groups">
<thead> <thead>
<tr> <tr>
<th class="column-enabled"><?php _e('启用', 'czlexpress-for-woocommerce'); ?></th> <th class="column-enabled"><?php esc_html_e('启用', 'czlexpress-for-woocommerce'); ?></th>
<th class="column-name"><?php _e('分组名称', 'czlexpress-for-woocommerce'); ?></th> <th class="column-name"><?php esc_html_e('分组名称', 'czlexpress-for-woocommerce'); ?></th>
<th class="column-prefixes"><?php _e('匹配前缀', 'czlexpress-for-woocommerce'); ?></th> <th class="column-prefixes"><?php esc_html_e('匹配前缀', 'czlexpress-for-woocommerce'); ?></th>
<th class="column-actions"><?php _e('操作', 'czlexpress-for-woocommerce'); ?></th> <th class="column-actions"><?php esc_html_e('操作', 'czlexpress-for-woocommerce'); ?></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -41,7 +41,7 @@ $groups = get_option('czl_product_groups', array());
<td class="column-prefixes"> <td class="column-prefixes">
<textarea name="groups[<?php echo esc_attr($key); ?>][prefixes]" rows="3" class="large-text" <textarea name="groups[<?php echo esc_attr($key); ?>][prefixes]" rows="3" class="large-text"
><?php echo esc_textarea(implode("\n", $group['prefixes'])); ?></textarea> ><?php echo esc_textarea(implode("\n", $group['prefixes'])); ?></textarea>
<p class="description"><?php _e('每行输入一个前缀,运输方式名称以此前缀开头将被归入此分组', 'czlexpress-for-woocommerce'); ?></p> <p class="description"><?php esc_html_e('每行输入一个前缀,运输方式名称以此前缀开头将被归入此分组', 'czlexpress-for-woocommerce'); ?></p>
</td> </td>
<td class="column-actions"> <td class="column-actions">
<button type="button" class="button remove-group" title="<?php esc_attr_e('删除此分组', 'czlexpress-for-woocommerce'); ?>"> <button type="button" class="button remove-group" title="<?php esc_attr_e('删除此分组', 'czlexpress-for-woocommerce'); ?>">
@ -52,7 +52,7 @@ $groups = get_option('czl_product_groups', array());
<?php endforeach; ?> <?php endforeach; ?>
<?php else: ?> <?php else: ?>
<tr class="no-items"> <tr class="no-items">
<td colspan="4"><?php _e('没有找到分组配置', 'czlexpress-for-woocommerce'); ?></td> <td colspan="4"><?php esc_html_e('没有找到分组配置', 'czlexpress-for-woocommerce'); ?></td>
</tr> </tr>
<?php endif; ?> <?php endif; ?>
</tbody> </tbody>
@ -61,7 +61,7 @@ $groups = get_option('czl_product_groups', array());
<td colspan="4"> <td colspan="4">
<button type="button" class="button add-group"> <button type="button" class="button add-group">
<span class="dashicons dashicons-plus-alt2"></span> <span class="dashicons dashicons-plus-alt2"></span>
<?php _e('添加分组', 'czlexpress-for-woocommerce'); ?> <?php esc_html_e('添加分组', 'czlexpress-for-woocommerce'); ?>
</button> </button>
</td> </td>
</tr> </tr>
@ -83,7 +83,7 @@ $groups = get_option('czl_product_groups', array());
</td> </td>
<td class="column-prefixes"> <td class="column-prefixes">
<textarea name="groups[{{index}}][prefixes]" rows="3" class="large-text" placeholder="<?php esc_attr_e('每行输入一个前缀', 'czlexpress-for-woocommerce'); ?>"></textarea> <textarea name="groups[{{index}}][prefixes]" rows="3" class="large-text" placeholder="<?php esc_attr_e('每行输入一个前缀', 'czlexpress-for-woocommerce'); ?>"></textarea>
<p class="description"><?php _e('每行输入一个前缀,运输方式名称以此前缀开头将被归入此分组', 'czlexpress-for-woocommerce'); ?></p> <p class="description"><?php esc_html_e('每行输入一个前缀,运输方式名称以此前缀开头将被归入此分组', 'czlexpress-for-woocommerce'); ?></p>
</td> </td>
<td class="column-actions"> <td class="column-actions">
<button type="button" class="button remove-group" title="<?php esc_attr_e('删除此分组', 'czlexpress-for-woocommerce'); ?>"> <button type="button" class="button remove-group" title="<?php esc_attr_e('删除此分组', 'czlexpress-for-woocommerce'); ?>">
@ -187,7 +187,7 @@ jQuery(function($) {
$row.fadeOut(300, function() { $row.fadeOut(300, function() {
$row.remove(); $row.remove();
if ($table.find('tbody tr').length === 0) { if ($table.find('tbody tr').length === 0) {
$table.find('tbody').append('<tr class="no-items"><td colspan="4"><?php _e('没有找到分组配置', 'czlexpress-for-woocommerce'); ?></td></tr>'); $table.find('tbody').append('<tr class="no-items"><td colspan="4"><?php esc_html_e('没有找到分组配置', 'czlexpress-for-woocommerce'); ?></td></tr>');
} }
}); });
}); });

View File

@ -65,9 +65,10 @@ jQuery(document).ready(function($) {
}, },
success: function(response) { success: function(response) {
if (response.success) { if (response.success) {
alert(response.data.message);
location.reload(); location.reload();
} else { } else {
alert(response.data); alert(response.data.message);
} }
}, },
error: function() { error: function() {
@ -109,9 +110,10 @@ jQuery(document).ready(function($) {
}, },
success: function(response) { success: function(response) {
if (response.success) { if (response.success) {
alert('轨迹更新成功');
location.reload(); location.reload();
} else { } else {
alert(response.data); alert(response.data.message || '更新失败');
} }
}, },
error: function() { error: function() {

View File

@ -1,7 +1,7 @@
<?php <?php
/** /**
* Plugin Name: CZL Express for WooCommerce * Plugin Name: CZL Express for WooCommerce
* Plugin URI: https://github.com/woodchen-ink/woocommerce-czlexpress * Plugin URI: https://github.com/woodchen-ink/czlexpress-for-woocommerce
* Description: CZL Express shipping integration for WooCommerce. Provides real-time shipping rates, shipment creation, and package tracking for CZL Express delivery service. * Description: CZL Express shipping integration for WooCommerce. Provides real-time shipping rates, shipment creation, and package tracking for CZL Express delivery service.
* Version: 1.0.0 * Version: 1.0.0
* Requires at least: 6.7 * Requires at least: 6.7
@ -44,52 +44,22 @@ define('CZL_EXPRESS_VERSION', '1.0.0');
define('CZL_EXPRESS_PATH', plugin_dir_path(__FILE__)); define('CZL_EXPRESS_PATH', plugin_dir_path(__FILE__));
define('CZL_EXPRESS_URL', plugin_dir_url(__FILE__)); define('CZL_EXPRESS_URL', plugin_dir_url(__FILE__));
// 在插件激活时创建数据表 // 加载核心类文件
register_activation_hook(__FILE__, 'czl_express_activate'); require_once CZL_EXPRESS_PATH . 'includes/class-czl-logger.php';
function czl_express_activate() {
// 确保加载安装类
require_once CZL_EXPRESS_PATH . 'includes/class-czl-install.php';
// 创建数据表和默认选项
CZL_Install::init();
// 记录版本号
update_option('czl_express_version', CZL_EXPRESS_VERSION);
// 注册定时任务
if (!wp_next_scheduled('czl_sync_tracking_numbers_hook')) {
wp_schedule_event(time(), 'hourly', 'czl_sync_tracking_numbers_hook');
}
}
// 在插件停用时清理
register_deactivation_hook(__FILE__, function() {
// 清理定时任务
wp_clear_scheduled_hook('czl_sync_tracking_numbers_hook');
});
// 在插件卸载时清理数据
register_uninstall_hook(__FILE__, array('CZL_Install', 'uninstall'));
// 声明支持HPOS
add_action('before_woocommerce_init', function() {
if (class_exists('\Automattic\WooCommerce\Utilities\FeaturesUtil')) {
\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility('custom_order_tables', __FILE__, true);
}
});
// 检查环境 // 检查环境
function czl_express_check_environment() { function czl_express_check_environment() {
if (!class_exists('WooCommerce')) { // 检查WooCommerce是否已安装并激活
if (!class_exists('WC_Shipping_Method')) {
add_action('admin_notices', function() { add_action('admin_notices', function() {
echo '<div class="error"><p>' . echo '<div class="error"><p>' .
esc_html__('CZL Express requires WooCommerce to be installed and active', 'czlexpress-for-woocommerce') . esc_html__('CZL Express requires WooCommerce to be installed and activated', 'czlexpress-for-woocommerce') .
'</p></div>'; '</p></div>';
}); });
return false; return false;
} }
// 检查WooCommerce版本
if (version_compare(WC_VERSION, '6.0.0', '<')) { if (version_compare(WC_VERSION, '6.0.0', '<')) {
add_action('admin_notices', function() { add_action('admin_notices', function() {
echo '<div class="error"><p>' . echo '<div class="error"><p>' .
@ -102,23 +72,49 @@ function czl_express_check_environment() {
return true; return true;
} }
// 在插件激活时创建数据表
register_activation_hook(__FILE__, 'czl_express_activate');
function czl_express_activate() {
// 确保加载安装类
require_once CZL_EXPRESS_PATH . 'includes/class-czl-install.php';
// 创建数据表和默认选项
CZL_Install::init();
// 记录版本号
update_option('czl_express_version', CZL_EXPRESS_VERSION);
}
// 在插件停用时清理
register_deactivation_hook(__FILE__, function() {
// 清理定时任务
wp_clear_scheduled_hook('czl_update_tracking_info');
});
// 声明支持HPOS
add_action('before_woocommerce_init', function() {
if (class_exists('\Automattic\WooCommerce\Utilities\FeaturesUtil')) {
\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility('custom_order_tables', __FILE__, true);
}
});
// 初始化插件 // 初始化插件
function czl_express_init() { function czl_express_init() {
if (czl_express_check_environment()) { if (czl_express_check_environment()) {
// 加载语言文件 CZL_Logger::info('Plugin initialization started');
load_plugin_textdomain(
'czlexpress-for-woocommerce',
false,
dirname(plugin_basename(__FILE__)) . '/languages'
);
// 加载必要的类文件 // 加载必要的类文件
require_once CZL_EXPRESS_PATH . 'includes/class-czlexpress.php'; require_once CZL_EXPRESS_PATH . 'includes/class-czlexpress.php';
require_once CZL_EXPRESS_PATH . 'includes/class-czl-api.php'; require_once CZL_EXPRESS_PATH . 'includes/class-czl-api.php';
require_once CZL_EXPRESS_PATH . 'includes/class-czl-order.php'; require_once CZL_EXPRESS_PATH . 'includes/class-czl-order.php';
require_once CZL_EXPRESS_PATH . 'includes/class-czl-ajax.php';
CZLExpress::instance(); CZLExpress::instance();
// 初始化AJAX处理器
new CZL_Ajax();
// 添加AJAX处理 // 添加AJAX处理
add_action('wp_ajax_czl_create_shipment', 'czl_ajax_create_shipment'); add_action('wp_ajax_czl_create_shipment', 'czl_ajax_create_shipment');
add_action('wp_ajax_czl_update_tracking_number', 'czl_ajax_update_tracking_number'); add_action('wp_ajax_czl_update_tracking_number', 'czl_ajax_update_tracking_number');
@ -129,6 +125,17 @@ function czl_express_init() {
// 注册自定义订单状态 // 注册自定义订单状态
add_action('init', 'register_czl_order_statuses'); add_action('init', 'register_czl_order_statuses');
// 在init钩子中加载翻译文件
add_action('init', function() {
load_plugin_textdomain(
'czlexpress-for-woocommerce',
false,
dirname(plugin_basename(__FILE__)) . '/languages'
);
});
CZL_Logger::info('Plugin initialization completed');
} }
} }
@ -226,14 +233,14 @@ function czl_ajax_update_tracking_number() {
check_ajax_referer('czl_ajax_nonce', 'nonce'); check_ajax_referer('czl_ajax_nonce', 'nonce');
if (!current_user_can('edit_shop_orders')) { if (!current_user_can('edit_shop_orders')) {
wp_send_json_error('Permission denied'); wp_send_json_error(array('message' => '权限不足'));
} }
$order_id = isset($_POST['order_id']) ? intval($_POST['order_id']) : 0; $order_id = isset($_POST['order_id']) ? intval($_POST['order_id']) : 0;
$tracking_number = isset($_POST['tracking_number']) ? sanitize_text_field($_POST['tracking_number']) : ''; $tracking_number = isset($_POST['tracking_number']) ? sanitize_text_field($_POST['tracking_number']) : '';
if (!$order_id || !$tracking_number) { if (!$order_id || !$tracking_number) {
wp_send_json_error('Invalid parameters'); wp_send_json_error(array('message' => '参数无效'));
} }
try { try {
@ -241,7 +248,7 @@ function czl_ajax_update_tracking_number() {
// 获取运单信息 // 获取运单信息
$shipment = $wpdb->get_row($wpdb->prepare( $shipment = $wpdb->get_row($wpdb->prepare(
"SELECT id FROM {$wpdb->prefix}czl_shipments WHERE order_id = %d", "SELECT * FROM {$wpdb->prefix}czl_shipments WHERE order_id = %d",
$order_id $order_id
)); ));
@ -270,7 +277,7 @@ function czl_ajax_update_tracking_number() {
// 添加订单备注 // 添加订单备注
$order->add_order_note(sprintf( $order->add_order_note(sprintf(
'Tracking number updated to: %s', '运单号已更新为: %s',
$tracking_number $tracking_number
)); ));
} }
@ -280,30 +287,42 @@ function czl_ajax_update_tracking_number() {
$tracking->clear_tracking_cache($shipment->id, $tracking_number, $order_id); $tracking->clear_tracking_cache($shipment->id, $tracking_number, $order_id);
wp_send_json_success(array( wp_send_json_success(array(
'message' => '运单号更新成功' 'message' => '运单号更新成功',
'tracking_number' => $tracking_number
)); ));
} catch (Exception $e) { } catch (Exception $e) {
wp_send_json_error($e->getMessage()); wp_send_json_error(array('message' => $e->getMessage()));
} }
} }
// 更新轨迹信息的AJAX处理函数 // 更新轨迹信息的AJAX处理函数
function czl_ajax_update_tracking_info() { function czl_ajax_update_tracking_info() {
check_ajax_referer('czl_ajax_nonce', 'nonce'); try {
// 验证nonce
if (!check_ajax_referer('czl_update_tracking_info', 'nonce', false)) {
throw new Exception('无效的请求');
}
// 验证权限
if (!current_user_can('edit_shop_orders')) { if (!current_user_can('edit_shop_orders')) {
wp_send_json_error('权限不足'); throw new Exception('权限不足');
} }
$order_id = isset($_POST['order_id']) ? intval($_POST['order_id']) : 0; $tracking_number = isset($_POST['tracking_number']) ? sanitize_text_field($_POST['tracking_number']) : '';
if (!$order_id) { if (empty($tracking_number)) {
wp_send_json_error('订单ID无效'); throw new Exception('运单号不能为空');
} }
// 使用 wp_schedule_single_event 来异步处理更新 $tracking = new CZL_Tracking();
wp_schedule_single_event(time(), 'czl_do_update_tracking_info', array($order_id)); $result = $tracking->update_tracking_info($tracking_number);
wp_send_json_success(array('message' => 'Update scheduled'));
wp_send_json_success($result);
} catch (Exception $e) {
CZL_Logger::error('Error updating tracking info', array('error' => $e->getMessage()));
wp_send_json_error(array('message' => $e->getMessage()));
}
} }
// 异步处理轨迹更新 // 异步处理轨迹更新
@ -312,7 +331,10 @@ function czl_do_update_tracking_info($order_id) {
$czl_order = new CZL_Order(); $czl_order = new CZL_Order();
$czl_order->update_tracking_info($order_id); $czl_order->update_tracking_info($order_id);
} catch (Exception $e) { } catch (Exception $e) {
error_log('CZL Express: Error updating tracking info - ' . $e->getMessage()); CZL_Logger::error('Error updating tracking info', array(
'order_id' => $order_id,
'error' => $e->getMessage()
));
} }
} }
add_action('czl_do_update_tracking_info', 'czl_do_update_tracking_info'); add_action('czl_do_update_tracking_info', 'czl_do_update_tracking_info');
@ -325,7 +347,10 @@ add_action('woocommerce_order_status_processing', function($order_id) {
try { try {
$czl_order->create_shipment($order_id); $czl_order->create_shipment($order_id);
} catch (Exception $e) { } catch (Exception $e) {
error_log('CZL Express: Auto create shipment failed - ' . $e->getMessage()); CZL_Logger::error('Auto create shipment failed', array(
'order_id' => $order_id,
'error' => $e->getMessage()
));
} }
}); });
@ -384,8 +409,14 @@ function czl_sync_tracking_numbers() {
// 更新最后同步时间 // 更新最后同步时间
update_option('czl_last_tracking_sync', $current_time); update_option('czl_last_tracking_sync', $current_time);
CZL_Logger::info('Tracking sync scheduled', array(
'shipment_count' => count($shipments)
));
} catch (Exception $e) { } catch (Exception $e) {
error_log('CZL Express: Tracking number sync failed - ' . $e->getMessage()); CZL_Logger::error('Tracking number sync failed', array(
'error' => $e->getMessage()
));
} }
} }
@ -424,13 +455,15 @@ function czl_do_sync_single_tracking($order_id, $current_tracking, $czl_order_id
$order->save(); $order->save();
$tracking_link = sprintf( $tracking_link = sprintf(
'<a href="https://exp.czl.net/track/?query=%s" target="_blank">Track Your Package</a>', '<a href="https://exp.czl.net/track/?query=%s" target="_blank">%s</a>',
$response['tracking_number'] $response['tracking_number'],
__('查看物流', 'czlexpress-for-woocommerce')
); );
$order->add_order_note( $order->add_order_note(
sprintf( sprintf(
'Tracking number updated to: %s\n%s', /* translators: 1: tracking number 2: tracking link */
__('运单号已更新为: %1$s\n%2$s', 'czlexpress-for-woocommerce'),
$response['tracking_number'], $response['tracking_number'],
$tracking_link $tracking_link
), ),
@ -439,10 +472,9 @@ function czl_do_sync_single_tracking($order_id, $current_tracking, $czl_order_id
} }
} }
} catch (Exception $e) { } catch (Exception $e) {
error_log(sprintf( CZL_Logger::error('Failed to sync tracking number', array(
'CZL Express: Failed to sync tracking number for order %d: %s', 'order_id' => $order_id,
$order_id, 'error' => $e->getMessage()
$e->getMessage()
)); ));
} }
} }

View File

@ -46,10 +46,10 @@ class CZL_API {
} }
$this->country_mapping = $mapping; $this->country_mapping = $mapping;
set_transient('czl_country_mapping', $mapping, DAY_IN_SECONDS); set_transient('czl_country_mapping', $mapping, DAY_IN_SECONDS);
error_log('CZL Express: Country mapping updated'); CZL_Logger::info('Country mapping updated');
} }
} catch (Exception $e) { } catch (Exception $e) {
error_log('CZL Express Error: Failed to get country mapping - ' . $e->getMessage()); CZL_Logger::error('Failed to get country mapping', array('error' => $e->getMessage()));
$this->country_mapping = array(); $this->country_mapping = array();
} }
} }
@ -58,7 +58,7 @@ class CZL_API {
* 转换国家代码 * 转换国家代码
*/ */
private function convert_country_code($wc_country) { private function convert_country_code($wc_country) {
error_log('CZL Express: Converting country code ' . $wc_country); CZL_Logger::debug('Converting country code', array('country' => $wc_country));
// 获取WooCommerce国家名称 // 获取WooCommerce国家名称
$countries = WC()->countries->get_countries(); $countries = WC()->countries->get_countries();
@ -67,13 +67,16 @@ class CZL_API {
// 在映射中查找 // 在映射中查找
foreach ($this->country_mapping as $name => $code) { foreach ($this->country_mapping as $name => $code) {
if (stripos($name, $country_name) !== false || stripos($country_name, $name) !== false) { if (stripos($name, $country_name) !== false || stripos($country_name, $name) !== false) {
error_log('CZL Express: Found country mapping ' . $wc_country . ' => ' . $code); CZL_Logger::debug('Found country mapping', array(
'from' => $wc_country,
'to' => $code
));
return $code; return $code;
} }
} }
// 如果没找到映射,返回原始代码 // 如果没找到映射,返回原始代码
error_log('CZL Express: No mapping found for ' . $wc_country . ', using original code'); CZL_Logger::debug('No mapping found, using original code', array('country' => $wc_country));
return $wc_country; return $wc_country;
} }
@ -94,13 +97,13 @@ class CZL_API {
)); ));
if (is_wp_error($response)) { if (is_wp_error($response)) {
throw new Exception($response->get_error_message()); throw new Exception(esc_html($response->get_error_message()));
} }
$body = json_decode(wp_remote_retrieve_body($response), true); $body = json_decode(wp_remote_retrieve_body($response), true);
if (empty($body['success'])) { if (empty($body['success'])) {
throw new Exception(!empty($body['message']) ? esc_html($body['message']) : esc_html__('认证失败', 'woocommerce-czlexpress')); throw new Exception(!empty($body['message']) ? esc_html($body['message']) : esc_html__('认证失败', 'czlexpress-for-woocommerce'));
} }
$this->token = $body['data']['token']; $this->token = $body['data']['token'];
@ -115,33 +118,55 @@ class CZL_API {
/** /**
* 发送API请求 * 发送API请求
*/ */
private function request($endpoint, $method = 'GET', $data = null) { private function send_request($endpoint, $params = array(), $method = 'GET') {
try {
$url = $this->get_api_url($endpoint);
$headers = $this->get_headers();
$args = array( $args = array(
'method' => $method, 'method' => $method,
'headers' => array( 'headers' => $headers,
'Authorization' => $this->get_token(), 'timeout' => 30,
'Content-Type' => 'application/json' 'sslverify' => false
),
'timeout' => 30
); );
if ($data !== null) { if ($method === 'POST') {
$args['body'] = wp_json_encode($data); $args['body'] = json_encode($params);
CZL_Logger::debug('API request', array(
'url' => $url,
'method' => $method,
'params' => $params
));
} }
$response = wp_remote_request($this->api_url . $endpoint, $args); $response = wp_remote_request($url, $args);
if (is_wp_error($response)) { if (is_wp_error($response)) {
throw new Exception($response->get_error_message()); throw new Exception($response->get_error_message());
} }
$body = json_decode(wp_remote_retrieve_body($response), true); $body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
if (empty($body['success'])) { CZL_Logger::debug('API response', array(
throw new Exception(!empty($body['message']) ? esc_html($body['message']) : esc_html__('请求失败', 'woocommerce-czlexpress')); 'url' => $url,
'response' => $data
));
if (!$data) {
throw new Exception('Invalid JSON response');
} }
return $body['data']; return $data;
} catch (Exception $e) {
CZL_Logger::error('API request failed', array(
'url' => $url,
'error' => $e->getMessage(),
'params' => $params
));
throw $e;
}
} }
/** /**
@ -165,7 +190,7 @@ class CZL_API {
'postcode' => $params['postcode'] 'postcode' => $params['postcode']
); );
error_log('CZL Express: Shipping rate request - ' . print_r($query, true)); CZL_Logger::debug('Shipping rate request', $query);
// 发送请求 // 发送请求
$response = wp_remote_post($api_url . '?' . http_build_query($query), array( $response = wp_remote_post($api_url . '?' . http_build_query($query), array(
@ -180,7 +205,7 @@ class CZL_API {
} }
$body = wp_remote_retrieve_body($response); $body = wp_remote_retrieve_body($response);
error_log('CZL Express: API raw response - ' . $body); CZL_Logger::debug('API raw response', $body);
$data = json_decode($body, true); $data = json_decode($body, true);
if (empty($data)) { if (empty($data)) {
@ -195,7 +220,7 @@ class CZL_API {
return $data; return $data;
} catch (Exception $e) { } catch (Exception $e) {
error_log('CZL Express API Error: ' . esc_html($e->getMessage())); CZL_Logger::error('API Error', array('message' => $e->getMessage()));
throw $e; throw $e;
} }
} }
@ -225,7 +250,7 @@ class CZL_API {
public function create_order($order_data) { public function create_order($order_data) {
try { try {
// 添加请求前的日志 // 添加请求前的日志
error_log('CZL Express: Creating order with data - ' . print_r($order_data, true)); CZL_Logger::debug('Creating order', array('data' => $order_data));
$response = wp_remote_post('https://tms.czl.net/createOrderApi.htm', array( $response = wp_remote_post('https://tms.czl.net/createOrderApi.htm', array(
'body' => array( 'body' => array(
@ -235,7 +260,7 @@ class CZL_API {
)); ));
// 添加响应日志 // 添加响应日志
error_log('CZL Express: Raw API response - ' . print_r($response, true)); CZL_Logger::debug('API response received', array('response' => $response));
if (is_wp_error($response)) { if (is_wp_error($response)) {
throw new Exception('API请求失败: ' . $response->get_error_message()); throw new Exception('API请求失败: ' . $response->get_error_message());
@ -247,14 +272,16 @@ class CZL_API {
} }
if (empty($result['ack']) || $result['ack'] !== 'true') { if (empty($result['ack']) || $result['ack'] !== 'true') {
throw new Exception(!empty($result['message']) ? esc_html($result['message']) : esc_html__('未知错误', 'woocommerce-czlexpress')); throw new Exception(!empty($result['message']) ? esc_html($result['message']) : esc_html__('未知错误', 'czlexpress-for-woocommerce'));
} }
return $result; return $result;
} catch (Exception $e) { } catch (Exception $e) {
error_log('CZL Express Error: Create order failed - ' . esc_html($e->getMessage())); CZL_Logger::error('Create order failed', array(
error_log('CZL Express Error Stack Trace: ' . $e->getTraceAsString()); 'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
));
throw $e; throw $e;
} }
} }
@ -284,7 +311,7 @@ class CZL_API {
return $result[0]['data'][0]; return $result[0]['data'][0];
} catch (Exception $e) { } catch (Exception $e) {
error_log('CZL Express API Error: ' . esc_html($e->getMessage())); CZL_Logger::error('Failed to get tracking', array('error' => $e->getMessage()));
throw $e; throw $e;
} }
} }
@ -338,7 +365,7 @@ class CZL_API {
); );
} catch (Exception $e) { } catch (Exception $e) {
error_log('CZL Express API Error: ' . esc_html($e->getMessage())); CZL_Logger::error('Authentication test failed', array('error' => $e->getMessage()));
throw $e; throw $e;
} }
} }
@ -365,14 +392,14 @@ class CZL_API {
return $result['data']; return $result['data'];
} catch (Exception $e) { } catch (Exception $e) {
error_log('CZL Express API Error: ' . esc_html($e->getMessage())); CZL_Logger::error('Failed to get countries list', array('error' => $e->getMessage()));
throw $e; throw $e;
} }
} }
private function ensure_logged_in() { private function ensure_logged_in() {
try { try {
error_log('CZL Express: Starting authentication'); CZL_Logger::info('Starting authentication');
$auth_url = 'https://tms.czl.net/selectAuth.htm'; $auth_url = 'https://tms.czl.net/selectAuth.htm';
$auth_data = array( $auth_data = array(
@ -380,7 +407,7 @@ class CZL_API {
'password' => $this->password 'password' => $this->password
); );
error_log('CZL Express: Auth request data - ' . print_r($auth_data, true)); CZL_Logger::debug('Auth request data', array('data' => $auth_data));
$ch = curl_init($auth_url); $ch = curl_init($auth_url);
curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POST, 1);
@ -394,7 +421,7 @@ class CZL_API {
curl_setopt($ch, CURLOPT_TIMEOUT, 30); curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$response = curl_exec($ch); $response = curl_exec($ch);
error_log('CZL Express: Auth raw response - ' . $response); CZL_Logger::debug('Auth raw response', array('response' => $response));
if (curl_errno($ch)) { if (curl_errno($ch)) {
throw new Exception('认证请求失败'); throw new Exception('认证请求失败');
@ -404,7 +431,7 @@ class CZL_API {
// 解析响应 // 解析响应
$result = json_decode(str_replace("'", '"', $response), true); $result = json_decode(str_replace("'", '"', $response), true);
error_log('CZL Express: Auth decoded response - ' . print_r($result, true)); CZL_Logger::debug('Auth decoded response', array('result' => $result));
if (empty($result) || !isset($result['customer_id'])) { if (empty($result) || !isset($result['customer_id'])) {
throw new Exception('认证失败'); throw new Exception('认证失败');
@ -415,7 +442,7 @@ class CZL_API {
$this->customer_userid = $result['customer_userid']; $this->customer_userid = $result['customer_userid'];
} catch (Exception $e) { } catch (Exception $e) {
error_log('CZL Express Error: Authentication failed - ' . esc_html($e->getMessage())); CZL_Logger::error('Authentication failed', array('error' => $e->getMessage()));
throw new Exception('认证失败请联系CZL Express'); throw new Exception('认证失败请联系CZL Express');
} }
} }
@ -441,7 +468,6 @@ class CZL_API {
$args['body'] = is_array($data) ? $data : wp_json_encode($data); $args['body'] = is_array($data) ? $data : wp_json_encode($data);
} }
// 使用wp_remote_request替代curl
$response = wp_remote_request($url, $args); $response = wp_remote_request($url, $args);
if (is_wp_error($response)) { if (is_wp_error($response)) {
@ -454,25 +480,25 @@ class CZL_API {
throw new Exception('请求失败: 空响应'); throw new Exception('请求失败: 空响应');
} }
// 记录响应日志 CZL_Logger::debug('API raw response', array('response' => $body));
if (defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {
error_log('CZL Express: Raw response - ' . $body);
}
$result = json_decode($body, true); $result = json_decode($body, true);
if (json_last_error() !== JSON_ERROR_NONE) { if (json_last_error() !== JSON_ERROR_NONE) {
if (defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) { CZL_Logger::error('JSON decode error', array('error' => json_last_error_msg()));
error_log('CZL Express: JSON decode error - ' . json_last_error_msg());
}
throw new Exception('响应数据格式错误'); throw new Exception('响应数据格式错误');
} }
CZL_Logger::debug('API decoded response', array('result' => $result));
// 检查API错误信息
if (isset($result['message']) && !empty($result['message'])) {
CZL_Logger::warning('API returned error message', array('message' => $result['message']));
}
return $result; return $result;
} catch (Exception $e) { } catch (Exception $e) {
if (defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) { CZL_Logger::error('Request failed', array('error' => $e->getMessage()));
error_log('CZL Express Error: Request failed - ' . esc_html($e->getMessage()));
}
throw $e; throw $e;
} }
} }
@ -544,74 +570,53 @@ class CZL_API {
} }
} }
public function create_shipment($params) { /**
* 获取运单轨迹
*/
public function get_tracking_info($tracking_number) {
try { try {
if (defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) { $response = $this->send_request('/tracking/query', array(
error_log('CZL Express: Starting create shipment'); 'tracking_number' => $tracking_number
} ), 'POST');
// 先进行认证 CZL_Logger::debug('Tracking info retrieved', array(
$auth_result = $this->authenticate(); 'tracking_number' => $tracking_number,
if (!$auth_result['ack']) { 'response' => $response
throw new Exception('认证失败: ' . $auth_result['message']);
}
// 添加认证信息到参数
$params['customer_id'] = $auth_result['customer_id'];
$params['customer_userid'] = $auth_result['customer_userid'];
// 准备请求数据
$request_data = array(
'param' => wp_json_encode($params)
);
if (defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {
error_log('CZL Express: Create shipment request data - ' . print_r($request_data, true));
}
// 发送请求
$response = wp_remote_post('https://tms.czl.net/createOrderApi.htm', array(
'body' => $request_data,
'timeout' => 30,
'headers' => array(
'Accept' => '*/*',
'Accept-Language' => 'zh-cn',
'Cache-Control' => 'no-cache',
'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8'
)
)); ));
if (is_wp_error($response)) { return $response;
throw new Exception('CURL错误: ' . $response->get_error_message());
}
$body = wp_remote_retrieve_body($response);
if (defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {
error_log('CZL Express: Raw response - ' . $body);
}
$result = json_decode($body, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new Exception('JSON解析错误: ' . json_last_error_msg());
}
if (defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {
error_log('CZL Express: Create shipment response - ' . print_r($result, true));
}
// 检查API错误信息
if (isset($result['message']) && !empty($result['message'])) {
if (defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {
error_log('CZL Express: API error message - ' . $result['message']);
}
}
return $result;
} catch (Exception $e) { } catch (Exception $e) {
if (defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) { CZL_Logger::error('Failed to get tracking info', array(
error_log('CZL Express API Error: ' . esc_html($e->getMessage())); 'tracking_number' => $tracking_number,
'error' => $e->getMessage()
));
throw $e;
} }
}
/**
* 创建运单
*/
public function create_shipment($order_data) {
try {
CZL_Logger::debug('Creating shipment', array(
'order_data' => $order_data
));
$response = $this->send_request('/shipment/create', $order_data, 'POST');
CZL_Logger::debug('Shipment created', array(
'response' => $response
));
return $response;
} catch (Exception $e) {
CZL_Logger::error('Failed to create shipment', array(
'order_data' => $order_data,
'error' => $e->getMessage()
));
throw $e; throw $e;
} }
} }
@ -646,95 +651,4 @@ class CZL_API {
throw new Exception('获取跟踪单号失败: ' . esc_html($e->getMessage())); throw new Exception('获取跟踪单号失败: ' . esc_html($e->getMessage()));
} }
} }
/**
* 获取运单跟踪信息
*/
public function get_tracking_info($tracking_number) {
try {
$response = wp_remote_post('https://tms.czl.net/selectTrack.htm', array(
'body' => array(
'documentCode' => $tracking_number
),
'timeout' => 30,
'headers' => array(
'Accept-Encoding' => '',
'Accept-Language' => 'zh-CN,zh;q=0.9'
)
));
if (is_wp_error($response)) {
throw new Exception($response->get_error_message());
}
$body = wp_remote_retrieve_body($response);
error_log('CZL Express: Track raw response - ' . $body);
// 处理中文编码问题
$body = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $body);
$result = json_decode($body, true);
if (json_last_error() !== JSON_ERROR_NONE) {
error_log('CZL Express: JSON decode error - ' . json_last_error_msg());
throw new Exception('JSON解析失败: ' . json_last_error_msg());
}
error_log('CZL Express: Track decoded response - ' . print_r($result, true));
if (empty($result) || !isset($result[0])) {
throw new Exception('无效的API响应');
}
if (empty($result[0]['ack']) || $result[0]['ack'] !== 'true') {
throw new Exception('获取跟踪信息失败: ' . ($result[0]['message'] ?? '未知错误'));
}
if (empty($result[0]['data']) || !is_array($result[0]['data'])) {
return array(
'success' => true,
'data' => array(
'status' => 'pending',
'track_content' => '暂无轨迹信息',
'track_time' => current_time('mysql'),
'track_location' => ''
),
'message' => ''
);
}
// 获取最新的轨迹状态
$latest_track = $result[0]['data'][0];
$track_details = $latest_track['trackDetails'] ?? array();
$latest_detail = !empty($track_details) ? $track_details[0] : array();
// 根据轨迹内容判断状态
$status = 'in_transit'; // 默认状态
$track_content = strtolower($latest_detail['track_content'] ?? '');
if (strpos($track_content, 'delivered') !== false || strpos($track_content, 'signed') !== false) {
$status = 'delivered';
} elseif (strpos($track_content, 'pickup') !== false || strpos($track_content, 'picked up') !== false) {
$status = 'picked_up';
}
return array(
'success' => true,
'data' => array(
'status' => $status,
'track_content' => $latest_detail['track_content'] ?? '',
'track_time' => $latest_detail['track_date'] ?? current_time('mysql'),
'track_location' => $latest_detail['track_location'] ?? ''
),
'message' => ''
);
} catch (Exception $e) {
error_log('CZL Express API Error: ' . esc_html($e->getMessage()));
return array(
'success' => false,
'data' => null,
'message' => esc_html($e->getMessage())
);
}
}
} }

View File

@ -23,6 +23,7 @@ class CZL_Install {
is_residential varchar(10), is_residential varchar(10),
shipping_method varchar(50), shipping_method varchar(50),
status varchar(20), status varchar(20),
label_url text,
last_sync_time datetime DEFAULT NULL, last_sync_time datetime DEFAULT NULL,
created_at datetime NOT NULL, created_at datetime NOT NULL,
updated_at datetime NOT NULL, updated_at datetime NOT NULL,
@ -47,30 +48,6 @@ class CZL_Install {
public static function deactivate() { public static function deactivate() {
// 只清理定时任务 // 只清理定时任务
wp_clear_scheduled_hook('czl_sync_tracking_numbers_hook'); wp_clear_scheduled_hook('czl_sync_tracking_numbers_hook');
} wp_clear_scheduled_hook('czl_update_tracking_info');
public static function uninstall() {
global $wpdb;
// 只有在卸载时才删除数据
if (!defined('WP_UNINSTALL_PLUGIN')) {
return;
}
// 删除数据表
$wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}czl_shipments");
$wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}czl_tracking_history");
$wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}czl_shipping_rules");
$wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}czl_product_groups");
// 删除选项
delete_option('czl_express_api_url');
delete_option('czl_express_api_key');
delete_option('czl_express_api_secret');
delete_option('czl_express_test_mode');
delete_option('czl_express_version');
delete_option('czl_last_tracking_sync');
delete_option('czl_express_db_version');
delete_option('czl_product_groups');
} }
} }

View File

@ -11,37 +11,50 @@ class CZL_Label {
*/ */
public static function get_label_url($order_id) { public static function get_label_url($order_id) {
try { try {
$order = wc_get_order($order_id); $czl_order_id = get_post_meta($order_id, '_czl_order_id', true);
if (!$order) { if (!$czl_order_id) {
throw new Exception('Order not found'); throw new Exception('未找到CZL订单号');
} }
// 获取运单号和订单号 $api = new CZL_API();
$tracking_number = $order->get_meta('_czl_tracking_number'); $url = $api->get_label($czl_order_id);
$czl_order_id = $order->get_meta('_czl_order_id');
// 构建标签URL if (empty($url)) {
$base_url = 'https://tms.czl.net/printOrderLabel.htm'; throw new Exception('获取标签URL失败');
$params = array(); }
// 优先使用订单号
if (!empty($czl_order_id)) {
$params['order_id'] = $czl_order_id;
$url = add_query_arg($params, $base_url);
return $url; return $url;
}
// 如果没有订单号但有运单号,使用运单号
if (!empty($tracking_number)) {
$params['documentCode'] = $tracking_number;
$url = add_query_arg($params, $base_url);
return $url;
}
throw new Exception('No tracking number or order ID found');
} catch (Exception $e) { } catch (Exception $e) {
error_log('CZL Express Error: Failed to get label URL - ' . $e->getMessage()); CZL_Logger::error('Failed to get label URL', array(
'order_id' => $order_id,
'error' => $e->getMessage()
));
throw $e;
}
}
/**
* 打印运单标签
*/
public static function print_label($order_id) {
try {
$url = self::get_label_url($order_id);
if (empty($url)) {
throw new Exception('标签URL为空');
}
// 保存标签URL
update_post_meta($order_id, '_czl_label_url', $url);
return $url;
} catch (Exception $e) {
CZL_Logger::error('Failed to print label', array(
'order_id' => $order_id,
'error' => $e->getMessage()
));
throw $e; throw $e;
} }
} }
@ -60,7 +73,10 @@ class CZL_Label {
); );
} }
} catch (Exception $e) { } catch (Exception $e) {
error_log('CZL Express Error: ' . $e->getMessage()); CZL_Logger::error('Label print action error', array(
'order_id' => $order->get_id(),
'error' => $e->getMessage()
));
} }
return $actions; return $actions;
} }
@ -70,19 +86,19 @@ class CZL_Label {
*/ */
public static function handle_print_request() { public static function handle_print_request() {
if (!current_user_can('edit_shop_orders')) { if (!current_user_can('edit_shop_orders')) {
wp_die(__('您没有权限执行此操作', 'czlexpress-for-woocommerce')); wp_die(esc_html__('您没有权限执行此操作', 'czlexpress-for-woocommerce'));
} }
check_admin_referer('czl_print_label'); check_admin_referer('czl_print_label');
$order_id = isset($_GET['order_id']) ? absint($_GET['order_id']) : 0; $order_id = isset($_GET['order_id']) ? absint($_GET['order_id']) : 0;
if (!$order_id) { if (!$order_id) {
wp_die(__('订单ID无效', 'czlexpress-for-woocommerce')); wp_die(esc_html__('订单ID无效', 'czlexpress-for-woocommerce'));
} }
$label_url = self::get_label_url($order_id); $label_url = self::get_label_url($order_id);
if (!$label_url) { if (!$label_url) {
wp_die(__('未找到运单标签', 'czlexpress-for-woocommerce')); wp_die(esc_html__('未找到运单标签', 'czlexpress-for-woocommerce'));
} }
wp_redirect($label_url); wp_redirect($label_url);

View File

@ -0,0 +1,76 @@
<?php
/**
* CZL日志处理类
*/
class CZL_Logger {
/**
* 记录日志
*
* @param string $message 日志消息
* @param mixed $data 额外数据
* @param string $level 日志级别 (error, warning, info, debug)
*/
public static function log($message, $data = null, $level = 'info') {
if (!defined('WP_DEBUG') || !WP_DEBUG) {
return;
}
$logger = wc_get_logger();
if (!$logger) {
return;
}
$context = array('source' => 'czlexpress-for-woocommerce');
if ($data !== null) {
if (is_array($data) || is_object($data)) {
$message .= ' Data: ' . wp_json_encode($data);
} else {
$message .= ' Data: ' . strval($data);
}
}
switch ($level) {
case 'error':
$logger->error($message, $context);
break;
case 'warning':
$logger->warning($message, $context);
break;
case 'info':
$logger->info($message, $context);
break;
case 'debug':
$logger->debug($message, $context);
break;
}
}
/**
* 记录错误日志
*/
public static function error($message, $data = null) {
self::log($message, $data, 'error');
}
/**
* 记录警告日志
*/
public static function warning($message, $data = null) {
self::log($message, $data, 'warning');
}
/**
* 记录信息日志
*/
public static function info($message, $data = null) {
self::log($message, $data, 'info');
}
/**
* 记录调试日志
*/
public static function debug($message, $data = null) {
self::log($message, $data, 'debug');
}
}

View File

@ -62,7 +62,10 @@ class CZL_Order_Handler {
return $response; return $response;
} }
} catch (Exception $e) { } catch (Exception $e) {
error_log('CZL Express Error: Failed to create shipment - ' . $e->getMessage()); CZL_Logger::error('Failed to create shipment', array(
'order_id' => $order_id,
'error' => $e->getMessage()
));
throw $e; throw $e;
} }
@ -114,18 +117,24 @@ class CZL_Order_Handler {
$e->getMessage() $e->getMessage()
); );
$order->add_order_note($error_message); $order->add_order_note($error_message);
error_log('CZL Express Error: ' . $error_message); CZL_Logger::error('Shipment cancellation failed', array(
'order_id' => $order_id,
'error' => $e->getMessage()
));
} }
} }
public function process_order_action($order) { public function process_order_action($order) {
try { try {
error_log('CZL Express: Processing order action for order ' . $order->get_id()); CZL_Logger::info('Processing order action', array('order_id' => $order->get_id()));
// 检查是否已经创建过运单 // 检查是否已经创建过运单
$tracking_number = $order->get_meta('_czl_tracking_number'); $tracking_number = $order->get_meta('_czl_tracking_number');
if (!empty($tracking_number)) { if (!empty($tracking_number)) {
error_log('CZL Express: Order already has tracking number: ' . $tracking_number); CZL_Logger::info('Order already has tracking number', array(
'order_id' => $order->get_id(),
'tracking_number' => $tracking_number
));
return; return;
} }
@ -133,10 +142,16 @@ class CZL_Order_Handler {
$czl_order = new CZL_Order(); $czl_order = new CZL_Order();
$result = $czl_order->create_shipment($order->get_id()); $result = $czl_order->create_shipment($order->get_id());
error_log('CZL Express: Create shipment result - ' . print_r($result, true)); CZL_Logger::info('Create shipment result', array(
'order_id' => $order->get_id(),
'result' => $result
));
} catch (Exception $e) { } catch (Exception $e) {
error_log('CZL Express Error: Failed to process order action - ' . $e->getMessage()); CZL_Logger::error('Failed to process order action', array(
'order_id' => $order->get_id(),
'error' => $e->getMessage()
));
} }
} }
} }

View File

@ -15,7 +15,7 @@ if (!class_exists('CZL_Order')) {
global $wpdb; global $wpdb;
try { try {
error_log('CZL Express: Starting create shipment for order ' . $order_id); CZL_Logger::info('Starting create shipment', array('order_id' => $order_id));
// 更新订单备注以显示处理状态 // 更新订单备注以显示处理状态
$order = wc_get_order($order_id); $order = wc_get_order($order_id);
@ -70,7 +70,10 @@ if (!class_exists('CZL_Order')) {
// 调用API创建运单 // 调用API创建运单
$result = $this->api->create_shipment($shipment_data); $result = $this->api->create_shipment($shipment_data);
error_log('CZL Express: API response - ' . print_r($result, true)); CZL_Logger::info('API response for shipment creation', array(
'order_id' => $order_id,
'response' => $result
));
// 检查API响应状态 // 检查API响应状态
if ($result['ack'] !== 'true') { if ($result['ack'] !== 'true') {
@ -131,8 +134,11 @@ if (!class_exists('CZL_Order')) {
} }
} catch (Exception $e) { } catch (Exception $e) {
error_log('CZL Express Error: Create shipment failed - ' . esc_html($e->getMessage())); CZL_Logger::error('Create shipment failed', array(
error_log('CZL Express Error Stack Trace: ' . esc_html($e->getTraceAsString())); 'order_id' => $order_id,
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
));
// 添加错误提示到订单备注 // 添加错误提示到订单备注
if (isset($order)) { if (isset($order)) {
@ -217,7 +223,10 @@ if (!class_exists('CZL_Order')) {
// 获取轨迹信息 // 获取轨迹信息
$api = new CZL_API(); $api = new CZL_API();
$tracking_info = $api->get_tracking_info($shipment->tracking_number); $tracking_info = $api->get_tracking_info($shipment->tracking_number);
error_log('CZL Express: Tracking API response - ' . print_r($tracking_info, true)); CZL_Logger::info('Tracking API response', array(
'tracking_number' => $shipment->tracking_number,
'response' => $tracking_info
));
// 处理API响应 // 处理API响应
if (!empty($tracking_info) && isset($tracking_info['success']) && $tracking_info['success'] == 1) { if (!empty($tracking_info) && isset($tracking_info['success']) && $tracking_info['success'] == 1) {

View File

@ -50,20 +50,56 @@ class CZL_Product_Fields {
* 保存自定义字段 * 保存自定义字段
*/ */
public function save_custom_fields($post_id) { public function save_custom_fields($post_id) {
// 保存中文品名 // 验证nonce
$name_cn = isset($_POST['_czl_name_cn']) ? sanitize_text_field($_POST['_czl_name_cn']) : ''; if (!isset($_POST['czl_product_fields_nonce']) ||
update_post_meta($post_id, '_czl_name_cn', $name_cn); !wp_verify_nonce($_POST['czl_product_fields_nonce'], 'czl_save_product_fields')) {
return;
}
// 保存海关编码 // 检查自动保存
$hs_code = isset($_POST['_czl_hs_code']) ? sanitize_text_field($_POST['_czl_hs_code']) : ''; if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
update_post_meta($post_id, '_czl_hs_code', $hs_code); return;
}
// 保存用途 // 检查权限
$usage = isset($_POST['_czl_usage']) ? sanitize_text_field($_POST['_czl_usage']) : ''; if (!current_user_can('edit_product', $post_id)) {
update_post_meta($post_id, '_czl_usage', $usage); return;
}
// 保存材质 // 中文品名
$material = isset($_POST['_czl_material']) ? sanitize_text_field($_POST['_czl_material']) : ''; if (isset($_POST['_czl_name_cn'])) {
update_post_meta($post_id, '_czl_material', $material); update_post_meta(
$post_id,
'_czl_name_cn',
sanitize_text_field(wp_unslash($_POST['_czl_name_cn']))
);
}
// HS编码
if (isset($_POST['_czl_hs_code'])) {
update_post_meta(
$post_id,
'_czl_hs_code',
sanitize_text_field(wp_unslash($_POST['_czl_hs_code']))
);
}
// 用途
if (isset($_POST['_czl_usage'])) {
update_post_meta(
$post_id,
'_czl_usage',
sanitize_text_field(wp_unslash($_POST['_czl_usage']))
);
}
// 材质
if (isset($_POST['_czl_material'])) {
update_post_meta(
$post_id,
'_czl_material',
sanitize_text_field(wp_unslash($_POST['_czl_material']))
);
}
} }
} }

View File

@ -154,16 +154,15 @@ class CZL_Rate_Calculator {
$rate = $operator === '+' ? $rate + $amount : $rate - $amount; $rate = $operator === '+' ? $rate + $amount : $rate - $amount;
} }
error_log(sprintf( CZL_Logger::debug('Rate adjustment', array(
'CZL Express: Adjusted rate from %f to %f using formula: %s', 'original_rate' => $original_rate,
$original_rate, 'adjusted_rate' => $rate,
$rate, 'formula' => $adjustment
$adjustment
)); ));
return max(0, $rate); return max(0, $rate);
} catch (Exception $e) { } catch (Exception $e) {
error_log('CZL Express: Rate adjustment error - ' . $e->getMessage()); CZL_Logger::error('Rate adjustment error', array('error' => $e->getMessage()));
return $rate; return $rate;
} }
} }
@ -197,13 +196,16 @@ class CZL_Rate_Calculator {
return $chargeable_weight * $quantity; return $chargeable_weight * $quantity;
} }
/**
* 计算运费
*/
public function calculate_shipping_rate($package) { public function calculate_shipping_rate($package) {
try { try {
error_log('CZL Express: Calculating shipping rate for package: ' . print_r($package, true)); CZL_Logger::debug('Calculating shipping rate for package', array('package' => $package));
// 基本验证 // 基本验证
if (empty($package['destination']['country'])) { if (empty($package['destination']['country'])) {
error_log('CZL Express: Empty destination country'); CZL_Logger::warning('Empty destination country');
return array(); return array();
} }
@ -229,11 +231,11 @@ class CZL_Rate_Calculator {
'height' => 10 // 添加固定尺寸 'height' => 10 // 添加固定尺寸
); );
error_log('CZL Express: API params with chargeable weight: ' . print_r($api_params, true)); CZL_Logger::debug('API params with chargeable weight', array('params' => $api_params));
// 调用API获取运费 // 调用API获取运费
$api_rates = $this->api->get_shipping_rate($api_params); $api_rates = $this->api->get_shipping_rate($api_params);
error_log('CZL Express: API response: ' . print_r($api_rates, true)); CZL_Logger::debug('API response', array('rates' => $api_rates));
if (empty($api_rates)) { if (empty($api_rates)) {
return array(); return array();
@ -305,12 +307,15 @@ class CZL_Rate_Calculator {
return $show_all_rates === 'yes' ? array_values($all_rates) : array_values($grouped_rates); return $show_all_rates === 'yes' ? array_values($all_rates) : array_values($grouped_rates);
} catch (Exception $e) { } catch (Exception $e) {
error_log('CZL Express Error: ' . $e->getMessage()); CZL_Logger::error('Failed to calculate shipping rate', array('error' => $e->getMessage()));
wc_add_notice($e->getMessage(), 'error'); wc_add_notice($e->getMessage(), 'error');
return array(); return array();
} }
} }
/**
* 翻译配送时间
*/
private function translate_delivery_time($delivery_time) { private function translate_delivery_time($delivery_time) {
// 获取当前语言环境 // 获取当前语言环境
$locale = determine_locale(); $locale = determine_locale();
@ -369,9 +374,7 @@ class CZL_Rate_Calculator {
// 如果经过翻译后与原文相同,说明没有匹配到任何规则 // 如果经过翻译后与原文相同,说明没有匹配到任何规则
if ($translated === $delivery_time) { if ($translated === $delivery_time) {
// 添加调试日志 CZL_Logger::warning('Unable to translate delivery time', array('delivery_time' => $delivery_time));
error_log('CZL Express: Unable to translate delivery time - ' . $delivery_time);
return $delivery_time;
} }
return $translated; return $translated;

View File

@ -106,7 +106,7 @@ class WC_CZL_Shipping_Method extends WC_Shipping_Method {
} }
try { try {
error_log('CZL Express: Starting shipping calculation'); CZL_Logger::info('Starting shipping calculation');
$calculator = new CZL_Rate_Calculator(); $calculator = new CZL_Rate_Calculator();
$rates = $calculator->calculate_shipping_rate($package); $rates = $calculator->calculate_shipping_rate($package);
@ -131,13 +131,13 @@ class WC_CZL_Shipping_Method extends WC_Shipping_Method {
)); ));
} }
error_log('CZL Express: Added ' . count($rates) . ' shipping rates'); CZL_Logger::info('Added shipping rates', array('count' => count($rates)));
} else { } else {
error_log('CZL Express: No shipping rates available'); CZL_Logger::info('No shipping rates available');
} }
} catch (Exception $e) { } catch (Exception $e) {
error_log('CZL Express Error: Failed to calculate shipping - ' . $e->getMessage()); CZL_Logger::error('Failed to calculate shipping', array('error' => $e->getMessage()));
} }
} }

View File

@ -35,80 +35,72 @@ class CZL_Tracking {
* 更新单个运单的轨迹信息 * 更新单个运单的轨迹信息
*/ */
public function update_tracking_info($tracking_number) { public function update_tracking_info($tracking_number) {
global $wpdb;
try { try {
// 获取运单信息 $api = new CZL_API();
$shipment = $wpdb->get_row($wpdb->prepare( $tracking_info = $api->get_tracking_info($tracking_number);
"SELECT * FROM {$wpdb->prefix}czl_shipments WHERE tracking_number = %s",
$tracking_number
));
if (!$shipment) { if (!$tracking_info['success']) {
throw new Exception($tracking_info['message']);
}
// 更新跟踪记录
$this->update_tracking_record($tracking_number, $tracking_info['data']);
return $tracking_info;
} catch (Exception $e) {
CZL_Logger::error('Failed to update tracking info', array(
'tracking_number' => $tracking_number,
'error' => $e->getMessage()
));
throw $e;
}
}
/**
* 更新订单状态
*/
public function update_order_status($order_id, $tracking_info) {
try {
$order = wc_get_order($order_id);
if (!$order) {
return; return;
} }
// 获取轨迹信息 $status = $tracking_info['status'];
$tracking_info = $this->api->get_tracking($tracking_number); $content = $tracking_info['track_content'];
$location = $tracking_info['track_location'];
$time = $tracking_info['track_time'];
if (!empty($tracking_info['trackDetails'])) { // 添加订单备注
foreach ($tracking_info['trackDetails'] as $detail) { $order->add_order_note(sprintf(
// 检查是否已存在该轨迹记录 /* translators: 1: status 2: location 3: time 4: details */
$exists = $wpdb->get_var($wpdb->prepare( __('包裹状态: %1$s, 位置: %2$s, 时间: %3$s, 详情: %4$s', 'czlexpress-for-woocommerce'),
"SELECT id FROM {$wpdb->prefix}czl_tracking_history $status,
WHERE shipment_id = %d AND track_date = %s AND track_content = %s", $location,
$shipment->id, $time,
$detail['track_date'], $content
$detail['track_content']
)); ));
if (!$exists) { // 更新订单状态
// 插入新的轨迹记录 switch ($status) {
$wpdb->insert( case 'delivered':
$wpdb->prefix . 'czl_tracking_history', $order->update_status('completed');
array( break;
'shipment_id' => $shipment->id, case 'in_transit':
'tracking_number' => $tracking_number, $order->update_status('in_transit');
'track_date' => $detail['track_date'], break;
'track_location' => $detail['track_location'], case 'picked_up':
'track_content' => $detail['track_content'], $order->update_status('processing');
'created_at' => current_time('mysql') break;
),
array('%d', '%s', '%s', '%s', '%s', '%s')
);
}
}
// 更新运单状态
$latest = reset($tracking_info['trackDetails']);
$new_status = 'in_transit';
if (strpos($latest['track_content'], '已签收') !== false ||
strpos($latest['track_content'], 'Delivered') !== false) {
$new_status = 'delivered';
}
// 更新运单状态
$wpdb->update(
$wpdb->prefix . 'czl_shipments',
array('status' => $new_status),
array('id' => $shipment->id),
array('%s'),
array('%d')
);
// 更新WooCommerce订单状态
$order = wc_get_order($shipment->order_id);
if ($order) {
$order->update_status($new_status, esc_html__('Package status updated from tracking info', 'czlexpress-for-woocommerce'));
}
// 清除相关缓存
$this->clear_tracking_cache($shipment->id, $tracking_number, $shipment->order_id);
} }
} catch (Exception $e) { } catch (Exception $e) {
error_log('CZL Express Error: Failed to update tracking info - ' . $e->getMessage()); CZL_Logger::error('Tracking error', array(
'order_id' => $order_id,
'error' => $e->getMessage()
));
throw $e;
} }
} }
@ -180,7 +172,10 @@ class CZL_Tracking {
echo '</div>'; echo '</div>';
} }
} catch (Exception $e) { } catch (Exception $e) {
error_log('CZL Express Tracking Error: ' . $e->getMessage()); CZL_Logger::error('Tracking display error', array(
'tracking_number' => $tracking_number,
'error' => $e->getMessage()
));
} }
} }
@ -256,7 +251,7 @@ class CZL_Tracking {
} }
if ($remote_text) { if ($remote_text) {
echo '<p><strong>' . esc_html__('地区类型:', 'czlexpress-for-woocommerce') . '</strong> ' . echo '<p><strong>' . esc_html__('地区类型:', 'czlexpress-for-woocommerce') . '</strong> ' .
$remote_text . '</p>'; esc_html($remote_text) . '</p>';
} }
} }

View File

@ -153,15 +153,15 @@ class CZLExpress {
public function render_product_groups_page() { public function render_product_groups_page() {
// 处理表单提交 // 处理表单提交
if ($_SERVER['REQUEST_METHOD'] === 'POST' && if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST' &&
check_admin_referer('czl_save_product_groups', 'czl_product_groups_nonce')) { check_admin_referer('czl_save_product_groups', 'czl_product_groups_nonce')) {
$groups = array(); $groups = array();
if (!empty($_POST['groups'])) { if (!empty($_POST['groups'])) {
foreach ($_POST['groups'] as $key => $group) { foreach (wp_unslash($_POST['groups']) as $key => $group) {
if (empty($group['groupName'])) continue; if (empty($group['groupName'])) continue;
$prefixes = array_filter(array_map('trim', explode("\n", $group['prefixes']))); $prefixes = array_filter(array_map('sanitize_text_field', array_map('trim', explode("\n", $group['prefixes']))));
if (empty($prefixes)) continue; if (empty($prefixes)) continue;
$groups[sanitize_key($group['groupName'])] = array( $groups[sanitize_key($group['groupName'])] = array(
@ -333,7 +333,7 @@ class CZLExpress {
public function render_exchange_rates_page() { public function render_exchange_rates_page() {
// 处理表单提交 // 处理表单提交
if ($_SERVER['REQUEST_METHOD'] === 'POST' && if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST' &&
check_admin_referer('czl_save_exchange_rates', 'czl_exchange_rates_nonce')) { check_admin_referer('czl_save_exchange_rates', 'czl_exchange_rates_nonce')) {
// 删除所有现有汇率 // 删除所有现有汇率
@ -342,9 +342,8 @@ class CZLExpress {
// 保存新的汇率 // 保存新的汇率
if (!empty($_POST['rates'])) { if (!empty($_POST['rates'])) {
foreach ($_POST['rates'] as $data) { foreach (wp_unslash($_POST['rates']) as $data) {
if (empty($data['currency']) || !isset($data['rate'])) continue; if (empty($data['currency']) || !isset($data['rate'])) continue;
$currency = sanitize_text_field($data['currency']); $currency = sanitize_text_field($data['currency']);
$rate = (float) $data['rate']; $rate = (float) $data['rate'];
@ -470,15 +469,33 @@ class CZLExpress {
* 定时更新所有运输中订单的轨迹 * 定时更新所有运输中订单的轨迹
*/ */
public function schedule_tracking_updates() { public function schedule_tracking_updates() {
$orders = wc_get_orders(array( global $wpdb;
'status' => array('shipping'),
'limit' => -1,
'meta_key' => '_czl_tracking_number',
'meta_compare' => 'EXISTS'
));
foreach ($orders as $order) { // 从自定义表中获取需要更新的运单
$this->order_handler->update_tracking_info($order->get_id()); $shipments = $wpdb->get_results(
$wpdb->prepare(
"SELECT order_id FROM {$wpdb->prefix}czl_shipments
WHERE status NOT IN ('delivered', 'cancelled', 'failed')
AND tracking_number IS NOT NULL
ORDER BY last_sync_time ASC
LIMIT %d",
50 // 每次处理的最大数量
)
);
if (empty($shipments)) {
return;
}
foreach ($shipments as $shipment) {
try {
$this->order_handler->update_tracking_info($shipment->order_id);
} catch (Exception $e) {
CZL_Logger::error('Failed to update tracking info', array(
'order_id' => $shipment->order_id,
'error' => $e->getMessage()
));
}
} }
} }
@ -543,7 +560,10 @@ class CZLExpress {
} }
} catch (Exception $e) { } catch (Exception $e) {
error_log('CZL Express Error: ' . $e->getMessage()); CZL_Logger::error('Shipment creation error', array(
'error' => $e->getMessage(),
'order_id' => isset($order) ? $order->get_id() : null
));
if (isset($order)) { if (isset($order)) {
$order->add_order_note( $order->add_order_note(
sprintf( sprintf(

View File

@ -25,7 +25,7 @@ defined('ABSPATH') || exit;
<?php if ($rate->remote_fee > 0): ?> <?php if ($rate->remote_fee > 0): ?>
<div class="remote-fee-notice"> <div class="remote-fee-notice">
<?php <?php
/* translators: %s: Remote area fee amount */ /* translators: %s: Remote area fee amount in the site's currency format */
printf( printf(
esc_html__('Remote Area Fee: %s', 'czlexpress-for-woocommerce'), esc_html__('Remote Area Fee: %s', 'czlexpress-for-woocommerce'),
wp_kses_post(wc_price($rate->remote_fee)) wp_kses_post(wc_price($rate->remote_fee))

46
uninstall.php Normal file
View File

@ -0,0 +1,46 @@
<?php
// 如果没有通过WordPress调用则退出
if (!defined('WP_UNINSTALL_PLUGIN')) {
exit;
}
// 删除数据表
global $wpdb;
// 删除所有相关的数据表
$tables = array(
'czl_shipments',
'czl_tracking_history',
'czl_shipping_rules',
'czl_product_groups'
);
foreach ($tables as $table) {
$wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}{$table}");
}
// 删除所有相关的选项
$options = array(
'czl_express_api_url',
'czl_express_api_key',
'czl_express_api_secret',
'czl_express_test_mode',
'czl_express_version',
'czl_last_tracking_sync',
'czl_express_db_version',
'czl_product_groups',
'czl_username',
'czl_password',
'czl_rate_adjustment'
);
foreach ($options as $option) {
delete_option($option);
}
// 删除所有订单的相关元数据
$wpdb->query("DELETE FROM {$wpdb->postmeta} WHERE meta_key LIKE '_czl_%'");
// 清理定时任务
wp_clear_scheduled_hook('czl_sync_tracking_numbers_hook');
wp_clear_scheduled_hook('czl_update_tracking_info');