154 lines
7.3 KiB
PHP
154 lines
7.3 KiB
PHP
<?php
|
||
/**
|
||
* 后台:为混装产品提供配置界面(可混装商品、最小数量、分类)。
|
||
*/
|
||
defined('ABSPATH') || exit;
|
||
|
||
class Yoone_Product_Bundles_Admin {
|
||
protected static $instance = null;
|
||
|
||
public static function instance() {
|
||
if (null === self::$instance) self::$instance = new self();
|
||
return self::$instance;
|
||
}
|
||
|
||
private function __construct() {
|
||
// 添加一个产品数据标签页
|
||
add_filter('woocommerce_product_data_tabs', array($this, 'add_product_data_tab'));
|
||
// 对应的面板内容
|
||
add_action('woocommerce_product_data_panels', array($this, 'render_product_data_panel'));
|
||
// 保存配置
|
||
add_action('woocommerce_admin_process_product_meta', array($this, 'save_product_meta'));
|
||
add_action('woocommerce_process_product_meta', array($this, 'save_product_meta'));
|
||
add_action('save_post_product', array($this, 'save_product_meta'), 15);
|
||
|
||
// AJAX: 获取所有 simple product
|
||
add_action('wp_ajax_yoone_get_all_simple_products', array($this, 'ajax_get_all_simple_products'));
|
||
}
|
||
|
||
public function add_product_data_tab($tabs) {
|
||
$tabs['yoone_bundle'] = array(
|
||
'label' => __('混装产品', 'yoone-product-bundles'),
|
||
'target' => 'yoone_bundle_data',
|
||
'class' => array('show_if_yoone_bundle'), // 仅当类型为 yoone_bundle 时显示
|
||
'priority' => 70,
|
||
);
|
||
return $tabs;
|
||
}
|
||
|
||
public function render_product_data_panel() {
|
||
global $post;
|
||
$product = wc_get_product($post->ID);
|
||
$config = Yoone_Product_Bundles::get_bundle_config($product);
|
||
$allowed = $config['allowed_products'];
|
||
$min_qty = $config['min_qty'];
|
||
$cats = $config['categories'];
|
||
|
||
echo '<div id="yoone_bundle_data" class="panel woocommerce_options_panel show_if_yoone_bundle">';
|
||
wp_nonce_field('yoone-bundle-admin-nonce', 'yoone_bundle_admin_nonce_field');
|
||
|
||
echo '<div class="options_group">';
|
||
echo '<p>' . esc_html__('配置可混装的简单商品、最小混装数量以及前端展示的分类分组。', 'yoone-product-bundles') . '</p>';
|
||
|
||
// 可混装商品:使用 Woo 的产品搜索(select2),multiple
|
||
echo '<p class="form-field"><label>' . esc_html__('可混装商品', 'yoone-product-bundles') . '</label>';
|
||
echo '<button type="button" class="button yoone-add-all-simple-products" style="margin-left: 10px;">' . esc_html__('一键添加所有 Simple Product', 'yoone-product-bundles') . '</button>';
|
||
// 仅搜索产品,不含变体,避免误选导致前端不显示
|
||
echo '<select class="wc-product-search" multiple style="width: 90%;" name="yoone_bundle_allowed_products[]" data-placeholder="' . esc_attr__('选择可混装的简单商品…', 'yoone-product-bundles') . '" data-action="woocommerce_json_search_products">';
|
||
if (! empty($allowed)) {
|
||
foreach ($allowed as $pid) {
|
||
$p = wc_get_product($pid);
|
||
if ($p) {
|
||
printf('<option value="%d" selected>%s</option>', $pid, esc_html($p->get_formatted_name()));
|
||
}
|
||
}
|
||
}
|
||
echo '</select>';
|
||
echo '<span class="description">' . esc_html__('仅支持 simple product;变体商品可在后续版本支持。', 'yoone-product-bundles') . '</span>';
|
||
echo '</p>';
|
||
|
||
// 最小混装数量
|
||
woocommerce_wp_text_input(array(
|
||
'id' => 'yoone_bundle_min_quantity',
|
||
'label' => __('最小混装数量', 'yoone-product-bundles'),
|
||
'type' => 'number',
|
||
'desc_tip' => true,
|
||
'description' => __('顾客选择的总数量需不小于该值,方可加入购物车。', 'yoone-product-bundles'),
|
||
'value' => $min_qty,
|
||
'custom_attributes' => array('min' => '0'),
|
||
));
|
||
|
||
// 展示分类(product_cat)
|
||
echo '<p class="form-field"><label>' . esc_html__('前端展示分类', 'yoone-product-bundles') . '</label>';
|
||
echo '<select class="wc-enhanced-select" multiple style="width: 90%;" name="yoone_bundle_categories[]" data-placeholder="' . esc_attr__('选择用于分组展示的分类…', 'yoone-product-bundles') . '">';
|
||
$terms = get_terms(array('taxonomy' => 'product_cat', 'hide_empty' => false));
|
||
foreach ($terms as $t) {
|
||
$selected = in_array($t->term_id, $cats, true) ? 'selected' : '';
|
||
printf('<option value="%d" %s>%s</option>', $t->term_id, $selected, esc_html($t->name));
|
||
}
|
||
echo '</select>';
|
||
echo '<span class="description">' . esc_html__('用于在前端页面按分类分组展示可混装商品(仅展示与所选分类匹配的可混装商品)。', 'yoone-product-bundles') . '</span>';
|
||
echo '</p>';
|
||
|
||
echo '</div>'; // options_group
|
||
echo '</div>'; // panel
|
||
}
|
||
|
||
public function save_product_meta($post_id) {
|
||
// 无论当前 product 对象类型为何,只要提交了我们的字段,就进行保存。
|
||
// 这可以避免在首次切换产品类型时由于保存顺序问题导致配置未写入。
|
||
$has_fields = isset($_POST['yoone_bundle_allowed_products']) || isset($_POST['yoone_bundle_min_quantity']) || isset($_POST['yoone_bundle_categories']);
|
||
if (! $has_fields) return;
|
||
|
||
// 保存 allowed products
|
||
$allowed = isset($_POST['yoone_bundle_allowed_products']) ? (array) $_POST['yoone_bundle_allowed_products'] : array();
|
||
$allowed = array_values(array_filter(array_map('absint', $allowed)));
|
||
// 仅保留 simple 产品ID
|
||
if (! empty($allowed)) {
|
||
$simple_only = array();
|
||
foreach ($allowed as $aid) {
|
||
$p = wc_get_product($aid);
|
||
if ($p && $p->is_type('simple')) {
|
||
$simple_only[] = $aid;
|
||
}
|
||
}
|
||
$allowed = $simple_only;
|
||
}
|
||
update_post_meta($post_id, Yoone_Product_Bundles::META_ALLOWED_PRODUCTS, $allowed);
|
||
|
||
// 保存 min qty
|
||
$min_qty = isset($_POST['yoone_bundle_min_quantity']) ? absint($_POST['yoone_bundle_min_quantity']) : 0;
|
||
update_post_meta($post_id, Yoone_Product_Bundles::META_MIN_QTY, max(0, $min_qty));
|
||
|
||
// 保存 categories
|
||
$cats = isset($_POST['yoone_bundle_categories']) ? (array) $_POST['yoone_bundle_categories'] : array();
|
||
$cats = array_values(array_filter(array_map('absint', $cats)));
|
||
update_post_meta($post_id, Yoone_Product_Bundles::META_CATEGORIES, $cats);
|
||
}
|
||
|
||
/**
|
||
* AJAX handler: 获取所有已发布的 simple product
|
||
*/
|
||
public function ajax_get_all_simple_products() {
|
||
if (! current_user_can('edit_products')) {
|
||
wp_send_json_error('permission_denied', 403);
|
||
}
|
||
check_ajax_referer('yoone-bundle-admin-nonce', 'security');
|
||
|
||
$products = wc_get_products(array(
|
||
'type' => 'simple',
|
||
'status' => 'publish',
|
||
'limit' => -1,
|
||
));
|
||
|
||
$results = array();
|
||
foreach ($products as $product) {
|
||
$results[] = array(
|
||
'id' => $product->get_id(),
|
||
'text' => $product->get_formatted_name(),
|
||
);
|
||
}
|
||
|
||
wp_send_json_success($results);
|
||
}
|
||
} |