BDFG Size Chart for WooCommerce是一个功能强大且灵活的插件,可让您为WooCommerce产品创建可自定义的尺寸图表。通过显示全面的尺寸信息,帮助您的客户选择合适的尺寸并降低回报率。
插件特征
相关文章: WooCommerce 产品比较工具
– 为您的产品创建无限尺寸图表
– 三个显示选项:选项卡,弹出窗口或直列
– 在产品页面上选择大小图表的位置
– 将尺寸图表分配给特定产品或产品类别
– 使用预定义的模板或创建自定义尺寸图表
– 易于使用的表构建器,带有添加/删除行和列
– 导入和导出大小图表,用于多个站点
– 在所有设备上都起作用的完全响应迅速的设计
– 短代码支持以在任何地方显示尺寸图表
<?php /** * Plugin Name: BDFG Size Chart for WooCommerce * Plugin URI: https://beiduofengou.net/2024/12/15/bdfg-size-chart-for-woocommerce/ * Description: Add customizable size charts to your WooCommerce products. Choose from available templates or create your own to improve your customers' shopping experience and reduce return rates. * Version: 2.3.0 * Author: beiduofengou * Author URI: https://beiduofengou.net * Text Domain: bdfg-size-chart * Domain Path: /languages * WC requires at least: 3.0.0 * WC tested up to: 7.0.0 * * @package BDFG_Size_Chart * @category Core * @author beiduofengou */ // Direct access protection if (!defined('ABSPATH')) { exit; // Exit if accessed directly } // Define plugin constants define('BDFG_SC_VERSION', '2.3.0'); define('BDFG_SC_PLUGIN_DIR', plugin_dir_path(__FILE__)); define('BDFG_SC_PLUGIN_URL', plugin_dir_url(__FILE__)); define('BDFG_SC_PLUGIN_BASENAME', plugin_basename(__FILE__)); /** * Main plugin class * * Handles initialization and core functionality of the plugin */ class BDFG_Size_Chart { /** * Single instance of the class * * @var object */ protected static $instance = null; /** * Main class constructor - sets up the plugin */ public function __construct() { // Load plugin text domain for translations add_action('plugins_loaded', array($this, 'load_plugin_textdomain')); // Check if WooCommerce is active before initializing if ($this->is_woocommerce_active()) { $this->init(); } else { // Show notice if WooCommerce is missing add_action('admin_notices', array($this, 'woocommerce_missing_notice')); } } /** * Check if WooCommerce is active * * @since 1.0.0 * @return boolean True if WooCommerce is active */ private function is_woocommerce_active() { // Get active plugins $active_plugins = (array) get_option('active_plugins', array()); // Check for multisite if (is_multisite()) { $active_plugins = array_merge($active_plugins, get_site_option('active_sitewide_plugins', array())); } // Check if WooCommerce is in the active plugins list return in_array('woocommerce/woocommerce.php', $active_plugins) || array_key_exists('woocommerce/woocommerce.php', $active_plugins); } /** * Admin notice for missing WooCommerce * * @since 1.0.0 */ public function woocommerce_missing_notice() { ?> <div class="notice notice-error"> <p><?php _e('BDFG Size Chart requires WooCommerce to be installed and active. You can download WooCommerce from the WordPress plugin repository.', 'bdfg-size-chart'); ?></p> </div> <?php } /** * Load plugin text domain * * @since 1.0.0 */ public function load_plugin_textdomain() { load_plugin_textdomain('bdfg-size-chart', false, dirname(plugin_basename(__FILE__)) . '/languages/'); } /** * Initialize plugin components * * @since 1.0.0 */ private function init() { // Include required files $this->includes(); // Register custom post type for size charts add_action('init', array($this, 'register_post_type')); // Register and enqueue admin scripts and styles add_action('admin_enqueue_scripts', array($this, 'admin_scripts')); // Register and enqueue frontend scripts and styles add_action('wp_enqueue_scripts', array($this, 'frontend_scripts')); // Add plugin action links add_filter('plugin_action_links_' . BDFG_SC_PLUGIN_BASENAME, array($this, 'add_action_links')); // Add meta boxes to size chart and product edit screens add_action('add_meta_boxes', array($this, 'add_meta_boxes')); // Save meta box data when post is saved add_action('save_post', array($this, 'save_meta_box_data')); // Display size chart on product page add_action('woocommerce_before_single_product_summary', array($this, 'display_size_chart'), 25); // Add plugin admin menu add_action('admin_menu', array($this, 'admin_menu')); // Register AJAX handler for template loading add_action('wp_ajax_bdfg_load_template', array($this, 'ajax_load_template')); // Register shortcode for displaying size charts add_shortcode('bdfg_size_chart', array($this, 'shortcode_size_chart')); } /** * Include required files * * @since 1.0.0 */ private function includes() { // Include template functions require_once BDFG_SC_PLUGIN_DIR . 'includes/bdfg-size-chart-template-functions.php'; // Include admin functions if in admin area if (is_admin()) { require_once BDFG_SC_PLUGIN_DIR . 'includes/admin/bdfg-size-chart-admin-functions.php'; } } /** * Register size chart post type * * @since 1.0.0 */ public function register_post_type() { $labels = array( 'name' => _x('Size Charts', 'post type general name', 'bdfg-size-chart'), 'singular_name' => _x('Size Chart', 'post type singular name', 'bdfg-size-chart'), 'menu_name' => _x('Size Charts', 'admin menu', 'bdfg-size-chart'), 'name_admin_bar' => _x('Size Chart', 'add new on admin bar', 'bdfg-size-chart'), 'add_new' => _x('Add New', 'size chart', 'bdfg-size-chart'), 'add_new_item' => __('Add New Size Chart', 'bdfg-size-chart'), 'new_item' => __('New Size Chart', 'bdfg-size-chart'), 'edit_item' => __('Edit Size Chart', 'bdfg-size-chart'), 'view_item' => __('View Size Chart', 'bdfg-size-chart'), 'all_items' => __('All Size Charts', 'bdfg-size-chart'), 'search_items' => __('Search Size Charts', 'bdfg-size-chart'), 'parent_item_colon' => __('Parent Size Charts:', 'bdfg-size-chart'), 'not_found' => __('No size charts found.', 'bdfg-size-chart'), 'not_found_in_trash' => __('No size charts found in Trash.', 'bdfg-size-chart') ); $args = array( 'labels' => $labels, 'description' => __('Size Charts for WooCommerce products.', 'bdfg-size-chart'), 'public' => false, 'publicly_queryable' => false, 'show_ui' => true, 'show_in_menu' => false, 'query_var' => true, 'rewrite' => false, 'capability_type' => 'post', 'has_archive' => false, 'hierarchical' => false, 'menu_position' => null, 'supports' => array('title', 'editor') ); register_post_type('bdfg_size_chart', $args); } /** * Enqueue admin scripts and styles * * @since 1.0.0 * @param string $hook Current admin page */ public function admin_scripts($hook) { $screen = get_current_screen(); // Only load on size chart edit screen or products page if (($hook == 'post.php' || $hook == 'post-new.php') && ($screen->post_type == 'bdfg_size_chart' || $screen->post_type == 'product')) { // Admin styles wp_enqueue_style( 'bdfg-size-chart-admin', BDFG_SC_PLUGIN_URL . 'assets/css/admin.css', array(), BDFG_SC_VERSION ); // Admin scripts wp_enqueue_script( 'bdfg-size-chart-admin', BDFG_SC_PLUGIN_URL . 'assets/js/admin.js', array('jquery', 'jquery-ui-sortable'), BDFG_SC_VERSION, true ); // Localize script with required data and translations wp_localize_script( 'bdfg-size-chart-admin', 'bdfg_size_chart_params', array( 'ajax_url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('bdfg_size_chart_nonce'), 'strings' => array( 'confirm_delete' => __('Are you sure you want to delete this chart?', 'bdfg-size-chart'), 'add_row' => __('Add Row', 'bdfg-size-chart'), 'add_column' => __('Add Column', 'bdfg-size-chart'), 'remove' => __('Remove', 'bdfg-size-chart'), 'loading' => __('Loading...', 'bdfg-size-chart'), 'save_success' => __('Size chart data saved successfully.', 'bdfg-size-chart'), 'save_error' => __('Error saving size chart data.', 'bdfg-size-chart'), ), ) ); } // Size chart list page if ($hook == 'woocommerce_page_bdfg-size-charts') { wp_enqueue_style( 'bdfg-size-chart-list', BDFG_SC_PLUGIN_URL . 'assets/css/admin-list.css', array(), BDFG_SC_VERSION ); } } /** * Enqueue frontend scripts and styles * * @since 1.0.0 */ public function frontend_scripts() { // Only load on product pages if (is_product()) { wp_enqueue_style( 'bdfg-size-chart-frontend', BDFG_SC_PLUGIN_URL . 'assets/css/frontend.css', array(), BDFG_SC_VERSION ); wp_enqueue_script( 'bdfg-size-chart-frontend', BDFG_SC_PLUGIN_URL . 'assets/js/frontend.js', array('jquery'), BDFG_SC_VERSION, true ); // Localize script wp_localize_script( 'bdfg-size-chart-frontend', 'bdfg_frontend_params', array( 'i18n_close' => __('Close', 'bdfg-size-chart') ) ); } } /** * Add custom action links on plugin page * * @since 1.0.0 * @param array $links Default plugin action links * @return array Modified plugin action links */ public function add_action_links($links) { $custom_links = array( '<a href="' . admin_url('admin.php?page=bdfg-size-charts') . '">' . __('Settings', 'bdfg-size-chart') . '</a>' ); return array_merge($custom_links, $links); } /** * Add meta boxes to size chart and product edit screens * * @since 1.0.0 */ public function add_meta_boxes() { // Size chart settings meta box add_meta_box( 'bdfg_size_chart_settings', __('Size Chart Settings', 'bdfg-size-chart'), array($this, 'render_settings_meta_box'), 'bdfg_size_chart', 'normal', 'high' ); // Size chart categories meta box add_meta_box( 'bdfg_size_chart_categories', __('Product Categories', 'bdfg-size-chart'), array($this, 'render_categories_meta_box'), 'bdfg_size_chart', 'side', 'default' ); // Product settings meta box add_meta_box( 'bdfg_product_size_chart', __('Size Chart', 'bdfg-size-chart'), array($this, 'render_product_meta_box'), 'product', 'side', 'default' ); } /** * Render settings meta box * * @since 1.0.0 * @param WP_Post $post Current post object */ public function render_settings_meta_box($post) { // Add a nonce field for security wp_nonce_field('bdfg_size_chart_settings_meta_box', 'bdfg_size_chart_settings_meta_box_nonce'); // Get current values $chart_type = get_post_meta($post->ID, '_bdfg_chart_type', true); $chart_position = get_post_meta($post->ID, '_bdfg_chart_position', true); $chart_label = get_post_meta($post->ID, '_bdfg_chart_label', true); // Set default values if empty if (empty($chart_type)) { $chart_type = 'tab'; } if (empty($chart_position)) { $chart_position = 'before_add_to_cart'; } if (empty($chart_label)) { $chart_label = __('Size Chart', 'bdfg-size-chart'); } ?> <table class="form-table"> <tr> <th scope="row"> <label for="bdfg_chart_type"><?php _e('Display Type', 'bdfg-size-chart'); ?></label> </th> <td> <select id="bdfg_chart_type" name="bdfg_chart_type"> <option value="tab" <?php selected($chart_type, 'tab'); ?>><?php _e('Tab', 'bdfg-size-chart'); ?></option> <option value="popup" <?php selected($chart_type, 'popup'); ?>><?php _e('Popup', 'bdfg-size-chart'); ?></option> <option value="inline" <?php selected($chart_type, 'inline'); ?>><?php _e('Inline', 'bdfg-size-chart'); ?></option> </select> <p class="description"><?php _e('Choose how to display the size chart on product pages.', 'bdfg-size-chart'); ?></p> </td> </tr> <tr> <th scope="row"> <label for="bdfg_chart_position"><?php _e('Chart Position', 'bdfg-size-chart'); ?></label> </th> <td> <select id="bdfg_chart_position" name="bdfg_chart_position"> <option value="before_add_to_cart" <?php selected($chart_position, 'before_add_to_cart'); ?>><?php _e('Before Add to Cart button', 'bdfg-size-chart'); ?></option> <option value="after_add_to_cart" <?php selected($chart_position, 'after_add_to_cart'); ?>><?php _e('After Add to Cart button', 'bdfg-size-chart'); ?></option> <option value="after_product_summary" <?php selected($chart_position, 'after_product_summary'); ?>><?php _e('After Product Summary', 'bdfg-size-chart'); ?></option> </select> <p class="description"><?php _e('Choose where to display the size chart on the product page.', 'bdfg-size-chart'); ?></p> </td> </tr> <tr> <th scope="row"> <label for="bdfg_chart_label"><?php _e('Button/Tab Label', 'bdfg-size-chart'); ?></label> </th> <td> <input type="text" id="bdfg_chart_label" name="bdfg_chart_label" value="<?php echo esc_attr($chart_label); ?>" class="regular-text"> <p class="description"><?php _e('Text that will appear on the button or tab.', 'bdfg-size-chart'); ?></p> </td> </tr> </table> <div class="bdfg-chart-builder"> <h3><?php _e('Size Chart Builder', 'bdfg-size-chart'); ?></h3> <p><?php _e('Build your size chart using the table below. Use the buttons to add or remove rows and columns as needed.', 'bdfg-size-chart'); ?></p> <?php // Get saved table data $table_data = get_post_meta($post->ID, '_bdfg_chart_table', true); // Default table if empty if (empty($table_data)) { $table_data = array( array('Size', 'Chest (inches)', 'Waist (inches)'), array('S', '36-38', '30-32'), array('M', '39-41', '33-35'), array('L', '42-44', '36-38'), array('XL', '45-47', '39-41') ); } ?> <div class="bdfg-table-controls"> <button type="button" class="button bdfg-add-row"><?php _e('Add Row', 'bdfg-size-chart'); ?></button> <button type="button" class="button bdfg-add-column"><?php _e('Add Column', 'bdfg-size-chart'); ?></button> </div> <div class="bdfg-table-container"> <table class="bdfg-chart-table"> <tbody> <?php foreach ($table_data as $row_index => $row) : ?> <tr class="bdfg-table-row"> <?php foreach ($row as $col_index => $cell) : ?> <td> <input type="text" name="bdfg_chart_table[<?php echo $row_index; ?>][<?php echo $col_index; ?>]" value="<?php echo esc_attr($cell); ?>"> <?php if ($row_index === 0 && $col_index === 0) : ?> <span class="bdfg-cell-actions"> <a href="#" class="bdfg-remove-row" title="<?php _e('Remove Row', 'bdfg-size-chart'); ?>">-</a> <a href="#" class="bdfg-remove-column" title="<?php _e('Remove Column', 'bdfg-size-chart'); ?>">-</a> </span> <?php elseif ($row_index === 0) : ?> <a href="#" class="bdfg-remove-column" title="<?php _e('Remove Column', 'bdfg-size-chart'); ?>">-</a> <?php elseif ($col_index === 0) : ?> <a href="#" class="bdfg-remove-row" title="<?php _e('Remove Row', 'bdfg-size-chart'); ?>">-</a> <?php endif; ?> </td> <?php endforeach; ?> </tr> <?php endforeach; ?> </tbody> </table> </div> <div class="bdfg-template-selection"> <h3><?php _e('Chart Templates', 'bdfg-size-chart'); ?></h3> <p><?php _e('Select a predefined template to get started quickly:', 'bdfg-size-chart'); ?></p> <select id="bdfg_chart_template" name="bdfg_chart_template"> <option value=""><?php _e('Custom Chart', 'bdfg-size-chart'); ?></option> <option value="mens_clothing"><?php _e("Men's Clothing", 'bdfg-size-chart'); ?></option> <option value="womens_clothing"><?php _e("Women's Clothing", 'bdfg-size-chart'); ?></option> <option value="shoes"><?php _e('Shoes', 'bdfg-size-chart'); ?></option> <option value="kids_clothing"><?php _e("Kid's Clothing", 'bdfg-size-chart'); ?></option> </select> <button type="button" class="button bdfg-load-template"><?php _e('Load Template', 'bdfg-size-chart'); ?></button> <span class="spinner bdfg-spinner"></span> </div> </div> <?php } /** * Render categories meta box * * @since 1.0.0 * @param WP_Post $post Current post object */ public function render_categories_meta_box($post) { wp_nonce_field('bdfg_size_chart_categories_meta_box', 'bdfg_size_chart_categories_meta_box_nonce'); // Get product categories $product_categories = get_terms(array( 'taxonomy' => 'product_cat', 'hide_empty' => false, )); // Get saved categories $selected_categories = get_post_meta($post->ID, '_bdfg_chart_categories', true); if (!is_array($selected_categories)) { $selected_categories = array(); } if (!empty($product_categories)) : ?> <p><?php _e('Select product categories to apply this size chart automatically:', 'bdfg-size-chart'); ?></p> <div class="bdfg-categories-wrapper"> <ul class="bdfg-categories-list"> <?php foreach ($product_categories as $category) : ?> <li> <label> <input type="checkbox" name="bdfg_chart_categories[]" value="<?php echo esc_attr($category->term_id); ?>" <?php checked(in_array($category->term_id, $selected_categories)); ?>> <?php echo esc_html($category->name); ?> </label> </li> <?php endforeach; ?> </ul> </div> <p class="howto"><?php _e('If no category is selected, this size chart will not be automatically applied to any product.', 'bdfg-size-chart'); ?></p> <?php else : ?> <p><?php _e('No product categories found. Create some categories first.', 'bdfg-size-chart'); ?></p> <?php endif; } /** * Render product meta box * * @since 1.0.0 * @param WP_Post $post Current post object */ public function render_product_meta_box($post) { wp_nonce_field('bdfg_product_size_chart_meta_box', 'bdfg_product_size_chart_meta_box_nonce'); // Get size charts $size_charts = get_posts(array( 'post_type' => 'bdfg_size_chart', 'posts_per_page' => -1, 'orderby' => 'title', 'order' => 'ASC', )); // Get selected chart $selected_chart = get_post_meta($post->ID, '_bdfg_product_size_chart', true); // Get product categories $product_categories = wp_get_post_terms($post->ID, 'product_cat', array('fields' => 'ids')); // Get default chart based on category $default_chart = 0; if (empty($selected_chart) && !empty($product_categories)) { foreach ($size_charts as $chart) { $chart_categories = get_post_meta($chart->ID, '_bdfg_chart_categories', true); if (!is_array($chart_categories)) { continue; } $intersect = array_intersect($product_categories, $chart_categories); if (!empty($intersect)) { $default_chart = $chart->ID; break; } } } if (empty($selected_chart) && !empty($default_chart)) { $selected_chart = $default_chart; } ?> <p><?php _e('Select a size chart for this product:', 'bdfg-size-chart'); ?></p> <select name="bdfg_product_size_chart" id="bdfg_product_size_chart"> <option value=""><?php _e('None', 'bdfg-size-chart'); ?></option> <?php foreach ($size_charts as $chart) : ?> <option value="<?php echo esc_attr($chart->ID); ?>" <?php selected($selected_chart, $chart->ID); ?>> <?php echo esc_html($chart->post_title); ?> </option> <?php endforeach; ?> </select> <?php if (empty($size_charts)) : ?> <p><?php _e('No size charts found.', 'bdfg-size-chart'); ?></p> <?php endif; ?> <p> <a href="<?php echo admin_url('post-new.php?post_type=bdfg_size_chart'); ?>" target="_blank"> <?php _e('Create new size chart', 'bdfg-size-chart'); ?> </a> </p> <?php if (!empty($selected_chart)) : ?> <p> <a href="<?php echo admin_url('post.php?post=' . $selected_chart . '&action=edit'); ?>" target="_blank"> <?php _e('Edit selected chart', 'bdfg-size-chart'); ?> </a> </p> <?php endif; ?> <?php } /** * Save meta box data * * @since 1.0.0 * @param int $post_id Post ID */ public function save_meta_box_data($post_id) { // Check if post is a size chart if (get_post_type($post_id) === 'bdfg_size_chart') { // Save size chart settings if (isset($_POST['bdfg_size_chart_settings_meta_box_nonce']) && wp_verify_nonce($_POST['bdfg_size_chart_settings_meta_box_nonce'], 'bdfg_size_chart_settings_meta_box')) { // Save chart type if (isset($_POST['bdfg_chart_type'])) { update_post_meta($post_id, '_bdfg_chart_type', sanitize_text_field($_POST['bdfg_chart_type'])); } // Save chart position if (isset($_POST['bdfg_chart_position'])) { update_post_meta($post_id, '_bdfg_chart_position', sanitize_text_field($_POST['bdfg_chart_position'])); } // Save chart label if (isset($_POST['bdfg_chart_label'])) { update_post_meta($post_id, '_bdfg_chart_label', sanitize_text_field($_POST['bdfg_chart_label'])); } // Save table data if (isset($_POST['bdfg_chart_table']) && is_array($_POST['bdfg_chart_table'])) { $table_data = array(); foreach ($_POST['bdfg_chart_table'] as $row) { $clean_row = array(); foreach ($row as $cell) { $clean_row[] = sanitize_text_field($cell); } $table_data[] = $clean_row; } update_post_meta($post_id, '_bdfg_chart_table', $table_data); } } // Save categories if (isset($_POST['bdfg_size_chart_categories_meta_box_nonce']) && wp_verify_nonce($_POST['bdfg_size_chart_categories_meta_box_nonce'], 'bdfg_size_chart_categories_meta_box')) { $categories = isset($_POST['bdfg_chart_categories']) ? array_map('intval', $_POST['bdfg_chart_categories']) : array(); update_post_meta($post_id, '_bdfg_chart_categories', $categories); } } // Check if post is a product if (get_post_type($post_id) === 'product') { // Save product size chart if (isset($_POST['bdfg_product_size_chart_meta_box_nonce']) && wp_verify_nonce($_POST['bdfg_product_size_chart_meta_box_nonce'], 'bdfg_product_size_chart_meta_box')) { $chart_id = isset($_POST['bdfg_product_size_chart']) ? intval($_POST['bdfg_product_size_chart']) : ''; update_post_meta($post_id, '_bdfg_product_size_chart', $chart_id); } } } /** * Display size chart on product page * * @since 1.0.0 */ public function display_size_chart() { global $product; if (!$product) { return; } $product_id = $product->get_id(); // Get assigned size chart for this product $size_chart_id = get_post_meta($product_id, '_bdfg_product_size_chart', true); // If no chart is assigned, try to find a chart based on product categories if (empty($size_chart_id)) { $product_categories = wp_get_post_terms($product_id, 'product_cat', array('fields' => 'ids')); if (!empty($product_categories)) { // Get all size charts $size_charts = get_posts(array( 'post_type' => 'bdfg_size_chart', 'posts_per_page' => -1, )); foreach ($size_charts as $chart) { $chart_categories = get_post_meta($chart->ID, '_bdfg_chart_categories', true); if (!is_array($chart_categories)) { continue; } $intersect = array_intersect($product_categories, $chart_categories); if (!empty($intersect)) { $size_chart_id = $chart->ID; break; } } } } if (empty($size_chart_id)) { return; } // Get chart data $chart_type = get_post_meta($size_chart_id, '_bdfg_chart_type', true); $chart_label = get_post_meta($size_chart_id, '_bdfg_chart_label', true); $chart_content = get_post_field('post_content', $size_chart_id); $chart_title = get_the_title($size_chart_id); $table_data = get_post_meta($size_chart_id, '_bdfg_chart_table', true); // Render chart based on type switch ($chart_type) { case 'popup': $this->render_popup_chart($size_chart_id, $chart_title, $chart_label, $chart_content, $table_data); break; case 'tab': $this->add_size_chart_tab($size_chart_id, $chart_title, $chart_label, $chart_content, $table_data); break; case 'inline': default: $this->render_inline_chart($size_chart_id, $chart_title, $chart_content, $table_data); break; } } /** * Render popup size chart * * @since 1.0.0 * @param int $chart_id Chart ID * @param string $chart_title Chart title * @param string $chart_label Chart label * @param string $chart_content Chart content * @param array $table_data Chart table data */ private function render_popup_chart($chart_id, $chart_title, $chart_label, $chart_content, $table_data) { if (empty($chart_label)) { $chart_label = __('Size Chart', 'bdfg-size-chart'); } // Check chart position $chart_position = get_post_meta($chart_id, '_bdfg_chart_position', true); if ($chart_position === 'after_add_to_cart') { add_action('woocommerce_after_add_to_cart_button', function() use ($chart_id, $chart_title, $chart_label, $chart_content, $table_data) { $this->output_popup_html($chart_id, $chart_title, $chart_label, $chart_content, $table_data); }, 10); } elseif ($chart_position === 'after_product_summary') { add_action('woocommerce_after_single_product_summary', function() use ($chart_id, $chart_title, $chart_label, $chart_content, $table_data) { $this->output_popup_html($chart_id, $chart_title, $chart_label, $chart_content, $table_data); }, 10); } else { // Default: before add to cart add_action('woocommerce_before_add_to_cart_button', function() use ($chart_id, $chart_title, $chart_label, $chart_content, $table_data) { $this->output_popup_html($chart_id, $chart_title, $chart_label, $chart_content, $table_data); }, 10); } } /** * Output popup HTML * * @since 1.0.0 * @param int $chart_id Chart ID * @param string $chart_title Chart title * @param string $chart_label Chart label * @param string $chart_content Chart content * @param array $table_data Chart table data */ private function output_popup_html($chart_id, $chart_title, $chart_label, $chart_content, $table_data) { ?> <div class="bdfg-size-chart-button-wrapper"> <button type="button" class="button bdfg-size-chart-button" data-chart-id="<?php echo esc_attr($chart_id); ?>"> <?php echo esc_html($chart_label); ?> </button> </div> <div id="bdfg-size-chart-popup-<?php echo esc_attr($chart_id); ?>" class="bdfg-size-chart-popup" style="display: none;"> <div class="bdfg-size-chart-popup-inner"> <div class="bdfg-size-chart-popup-header"> <h2><?php echo esc_html($chart_title); ?></h2> <button type="button" class="bdfg-size-chart-close">×</button> </div> <div class="bdfg-size-chart-popup-content"> <?php if (!empty($chart_content)) : ?> <div class="bdfg-size-chart-description"> <?php echo wp_kses_post($chart_content); ?> </div> <?php endif; ?> <?php if (!empty($table_data)) : ?> <div class="bdfg-size-chart-table-container"> <table class="bdfg-size-chart-table"> <tbody> <?php foreach ($table_data as $row_index => $row) : ?> <tr class="<?php echo $row_index === 0 ? 'bdfg-chart-heading' : 'bdfg-chart-row'; ?>"> <?php foreach ($row as $cell) : ?> <<?php echo $row_index === 0 ? 'th' : 'td'; ?>> <?php echo esc_html($cell); ?> </<?php echo $row_index === 0 ? 'th' : 'td'; ?>> <?php endforeach; ?> </tr> <?php endforeach; ?> </tbody> </table> </div> <?php endif; ?> </div> <div class="bdfg-size-chart-popup-footer"> <span class="bdfg-copyright"><?php _e('Size Chart by', 'bdfg-size-chart'); ?> <a href="https://beiduofengou.net" target="_blank">beiduofengou</a></span> </div> </div> </div> <?php } /** * Add size chart tab * * @since 1.0.0 * @param int $chart_id Chart ID * @param string $chart_title Chart title * @param string $chart_label Chart label * @param string $chart_content Chart content * @param array $table_data Chart table data */ private function add_size_chart_tab($chart_id, $chart_title, $chart_label, $chart_content, $table_data) { if (empty($chart_label)) { $chart_label = __('Size Chart', 'bdfg-size-chart'); } // Add a new tab to product tabs add_filter('woocommerce_product_tabs', function($tabs) use ($chart_id, $chart_title, $chart_label, $chart_content, $table_data) { $tabs['bdfg_size_chart'] = array( 'title' => $chart_label, 'callback' => function() use ($chart_id, $chart_title, $chart_content, $table_data) { $this->output_tab_content($chart_id, $chart_title, $chart_content, $table_data); }, 'priority' => 30 ); return $tabs; }); } /** * Output tab content * * @since 1.0.0 * @param int $chart_id Chart ID * @param string $chart_title Chart title * @param string $chart_content Chart content * @param array $table_data Chart table data */ private function output_tab_content($chart_id, $chart_title, $chart_content, $table_data) { ?> <div class="bdfg-size-chart-tab-content"> <h2><?php echo esc_html($chart_title); ?></h2> <?php if (!empty($chart_content)) : ?> <div class="bdfg-size-chart-description"> <?php echo wp_kses_post($chart_content); ?> </div> <?php endif; ?> <?php if (!empty($table_data)) : ?> <div class="bdfg-size-chart-table-container"> <table class="bdfg-size-chart-table"> <tbody> <?php foreach ($table_data as $row_index => $row) : ?> <tr class="<?php echo $row_index === 0 ? 'bdfg-chart-heading' : 'bdfg-chart-row'; ?>"> <?php foreach ($row as $cell) : ?> <<?php echo $row_index === 0 ? 'th' : 'td'; ?>> <?php echo esc_html($cell); ?> </<?php echo $row_index === 0 ? 'th' : 'td'; ?>> <?php endforeach; ?> </tr> <?php endforeach; ?> </tbody> </table> </div> <?php endif; ?> <div class="bdfg-size-chart-footer"> <span class="bdfg-copyright"><?php _e('Size Chart by', 'bdfg-size-chart'); ?> <a href="https://beiduofengou.net" target="_blank">beiduofengou</a></span> </div> </div> <?php } /** * Render inline size chart * * @since 1.0.0 * @param int $chart_id Chart ID * @param string $chart_title Chart title * @param string $chart_content Chart content * @param array $table_data Chart table data */ private function render_inline_chart($chart_id, $chart_title, $chart_content, $table_data) { // Check chart position $chart_position = get_post_meta($chart_id, '_bdfg_chart_position', true); if ($chart_position === 'after_add_to_cart') { add_action('woocommerce_after_add_to_cart_button', function() use ($chart_id, $chart_title, $chart_content, $table_data) { $this->output_inline_html($chart_id, $chart_title, $chart_content, $table_data); }, 10); } elseif ($chart_position === 'after_product_summary') { add_action('woocommerce_after_single_product_summary', function() use ($chart_id, $chart_title, $chart_content, $table_data) { $this->output_inline_html($chart_id, $chart_title, $chart_content, $table_data); }, 10); } else { // Default: before add to cart add_action('woocommerce_before_add_to_cart_button', function() use ($chart_id, $chart_title, $chart_content, $table_data) { $this->output_inline_html($chart_id, $chart_title, $chart_content, $table_data); }, 10); } } /** * Output inline HTML * * @since 1.0.0 * @param int $chart_id Chart ID * @param string $chart_title Chart title * @param string $chart_content Chart content * @param array $table_data Chart table data */ private function output_inline_html($chart_id, $chart_title, $chart_content, $table_data) { ?> <div class="bdfg-size-chart-inline" id="bdfg-size-chart-<?php echo esc_attr($chart_id); ?>"> <h3><?php echo esc_html($chart_title); ?></h3> <?php if (!empty($chart_content)) : ?> <div class="bdfg-size-chart-description"> <?php echo wp_kses_post($chart_content); ?> </div> <?php endif; ?> <?php if (!empty($table_data)) : ?> <div class="bdfg-size-chart-table-container"> <table class="bdfg-size-chart-table"> <tbody> <?php foreach ($table_data as $row_index => $row) : ?> <tr class="<?php echo $row_index === 0 ? 'bdfg-chart-heading' : 'bdfg-chart-row'; ?>"> <?php foreach ($row as $cell) : ?> <<?php echo $row_index === 0 ? 'th' : 'td'; ?>> <?php echo esc_html($cell); ?> </<?php echo $row_index === 0 ? 'th' : 'td'; ?>> <?php endforeach; ?> </tr> <?php endforeach; ?> </tbody> </table> </div> <?php endif; ?> <div class="bdfg-size-chart-footer"> <span class="bdfg-copyright"><?php _e('Size Chart by', 'bdfg-size-chart'); ?> <a href="https://beiduofengou.net" target="_blank">beiduofengou</a></span> </div> </div> <?php } /** * Admin menu * * @since 1.0.0 */ public function admin_menu() { add_submenu_page( 'woocommerce', __('Size Charts', 'bdfg-size-chart'), __('Size Charts', 'bdfg-size-chart'), 'manage_woocommerce', 'bdfg-size-charts', array($this, 'size_charts_page') ); } /** * Size charts admin page * * @since 1.0.0 */ public function size_charts_page() { include_once BDFG_SC_PLUGIN_DIR . 'includes/admin/views/html-size-charts-page.php'; } /** * AJAX handler for loading template data * * @since 1.0.0 */ public function ajax_load_template() { // Check nonce if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'bdfg_size_chart_nonce')) { wp_send_json_error(array('message' => __('Security check failed', 'bdfg-size-chart'))); } // Check if template ID is provided if (!isset($_POST['template_id']) || empty($_POST['template_id'])) { wp_send_json_error(array('message' => __('Invalid template ID', 'bdfg-size-chart'))); } $template_id = sanitize_text_field($_POST['template_id']); // Load template data from our template functions $template_data = bdfg_load_template_data($template_id); if (empty($template_data)) { wp_send_json_error(array('message' => __('Template not found', 'bdfg-size-chart'))); } wp_send_json_success($template_data); } /** * Shortcode handler for displaying size charts * * @since 1.0.0 * @param array $atts Shortcode attributes * @return string Shortcode output */ public function shortcode_size_chart($atts) { $atts = shortcode_atts(array( 'id' => 0, ), $atts); $chart_id = intval($atts['id']); if (empty($chart_id) || get_post_type($chart_id) !== 'bdfg_size_chart') { return ''; } // Get chart data $chart_title = get_the_title($chart_id); $chart_content = get_post_field('post_content', $chart_id); $table_data = get_post_meta($chart_id, '_bdfg_chart_table', true); // Start output buffer ob_start(); ?> <div class="bdfg-size-chart-shortcode" id="bdfg-size-chart-<?php echo esc_attr($chart_id); ?>"> <h3><?php echo esc_html($chart_title); ?></h3> <?php if (!empty($chart_content)) : ?> <div class="bdfg-size-chart-description"> <?php echo wp_kses_post($chart_content); ?> </div> <?php endif; ?> <?php if (!empty($table_data)) : ?> <div class="bdfg-size-chart-table-container"> <table class="bdfg-size-chart-table"> <tbody> <?php foreach ($table_data as $row_index => $row) : ?> <tr class="<?php echo $row_index === 0 ? 'bdfg-chart-heading' : 'bdfg-chart-row'; ?>"> <?php foreach ($row as $cell) : ?> <<?php echo $row_index === 0 ? 'th' : 'td'; ?>> <?php echo esc_html($cell); ?> </<?php echo $row_index === 0 ? 'th' : 'td'; ?>> <?php endforeach; ?> </tr> <?php endforeach; ?> </tbody> </table> </div> <?php endif; ?> <div class="bdfg-size-chart-footer"> <span class="bdfg-copyright"><?php _e('Size Chart by', 'bdfg-size-chart'); ?> <a href="https://beiduofengou.net" target="_blank">beiduofengou</a></span> </div> </div> <?php return ob_get_clean(); } /** * Return instance of this class * * @since 1.0.0 * @return BDFG_Size_Chart */ public static function get_instance() { if (null === self::$instance) { self::$instance = new self(); } return self::$instance; } } // Initialize the plugin function bdfg_size_chart_init() { return BDFG_Size_Chart::get_instance(); } // Start the plugin add_action('plugins_loaded', 'bdfg_size_chart_init'); // Create the necessary files and directories upon plugin activation register_activation_hook(__FILE__, 'bdfg_size_chart_activation'); /** * Plugin activation hook * * Creates necessary directories and files when plugin is activated * * @since 1.0.0 */ function bdfg_size_chart_activation() { // Create necessary directories $dirs = array( BDFG_SC_PLUGIN_DIR . 'includes/', BDFG_SC_PLUGIN_DIR . 'includes/admin/', BDFG_SC_PLUGIN_DIR . 'includes/admin/views/', BDFG_SC_PLUGIN_DIR . 'assets/', BDFG_SC_PLUGIN_DIR . 'assets/css/', BDFG_SC_PLUGIN_DIR . 'assets/js/', BDFG_SC_PLUGIN_DIR . 'languages/' ); foreach ($dirs as $dir) { if (!file_exists($dir)) { wp_mkdir_p($dir); } } } /** * Add shortcode for displaying size charts * * @since 1.0.0 */ add_shortcode('bdfg_size_chart', array(BDFG_Size_Chart::get_instance(), 'shortcode_size_chart'));
includes/bdfg-size-chart-template-functions.php
相关文章: WordPress 地图定位插件
<?php /** * BDFG Size Chart Template Functions * * Functions for the templating system. * * @package BDFG_Size_Chart * @version 2.3.0 * @since 1.0.0 * @author beiduofengou * @modified 2025-03-05 */ // Exit if accessed directly if (!defined('ABSPATH')) { exit; } /** * Get size chart for a product * * @param int $product_id The product ID * @return int|false Size chart ID or false if not found */ function bdfg_get_product_size_chart($product_id) { // Get assigned size chart for this product $size_chart_id = get_post_meta($product_id, '_bdfg_product_size_chart', true); // If no chart is assigned, try to find a chart based on product categories if (empty($size_chart_id)) { $product_categories = wp_get_post_terms($product_id, 'product_cat', array('fields' => 'ids')); if (!empty($product_categories)) { // Get all size charts $size_charts = get_posts(array( 'post_type' => 'bdfg_size_chart', 'posts_per_page' => -1, 'meta_query' => array( array( 'key' => '_bdfg_chart_status', 'value' => 'inactive', 'compare' => '!=', ), ), )); foreach ($size_charts as $chart) { $chart_categories = get_post_meta($chart->ID, '_bdfg_chart_categories', true); if (!is_array($chart_categories)) { continue; } $intersect = array_intersect($product_categories, $chart_categories); if (!empty($intersect)) { $size_chart_id = $chart->ID; break; } } } } return !empty($size_chart_id) ? intval($size_chart_id) : false; } /** * Get size chart table data * * @param int $chart_id The size chart ID * @return array Size chart table data */ function bdfg_get_size_chart_table($chart_id) { $table_data = get_post_meta($chart_id, '_bdfg_chart_table', true); if (empty($table_data) || !is_array($table_data)) { return array(); } return $table_data; } /** * Get size chart display type * * @param int $chart_id The size chart ID * @return string Display type (tab, popup, inline) */ function bdfg_get_size_chart_type($chart_id) { $chart_type = get_post_meta($chart_id, '_bdfg_chart_type', true); if (empty($chart_type)) { return 'tab'; } return $chart_type; } /** * Get size chart position * * @param int $chart_id The size chart ID * @return string Chart position */ function bdfg_get_size_chart_position($chart_id) { $chart_position = get_post_meta($chart_id, '_bdfg_chart_position', true); if (empty($chart_position)) { return 'before_add_to_cart'; } return $chart_position; } /** * Get size chart label * * @param int $chart_id The size chart ID * @return string Chart label */ function bdfg_get_size_chart_label($chart_id) { $chart_label = get_post_meta($chart_id, '_bdfg_chart_label', true); if (empty($chart_label)) { return __("Size Chart", "bdfg-size-chart"); } return $chart_label; } /** * Render size chart HTML * * @param int $chart_id The size chart ID * @param string $context Optional context (product, category, shortcode) * @return string HTML output */ function bdfg_render_size_chart($chart_id, $context = 'product') { if (empty($chart_id)) { return ''; } // Get chart data $chart_type = bdfg_get_size_chart_type($chart_id); $chart_title = get_the_title($chart_id); $chart_content = get_post_field('post_content', $chart_id); $table_data = bdfg_get_size_chart_table($chart_id); // Start output buffer ob_start(); if ($chart_type === 'popup' && $context === 'product') { $chart_label = bdfg_get_size_chart_label($chart_id); ?> <div class="bdfg-size-chart-button-wrapper"> <button type="button" class="button bdfg-size-chart-button" data-chart-id="<?php echo esc_attr($chart_id); ?>"> <?php echo esc_html($chart_label); ?> </button> </div> <div id="bdfg-size-chart-popup-<?php echo esc_attr($chart_id); ?>" class="bdfg-size-chart-popup" style="display: none;"> <div class="bdfg-size-chart-popup-inner"> <div class="bdfg-size-chart-popup-header"> <h2><?php echo esc_html($chart_title); ?></h2> <button type="button" class="bdfg-size-chart-close">×</button> </div> <div class="bdfg-size-chart-popup-content"> <?php if (!empty($chart_content)) : ?> <div class="bdfg-size-chart-description"> <?php echo wp_kses_post($chart_content); ?> </div> <?php endif; ?> <?php if (!empty($table_data)) : ?> <div class="bdfg-size-chart-table-container"> <table class="bdfg-size-chart-table"> <tbody> <?php foreach ($table_data as $row_index => $row) : ?> <tr class="<?php echo $row_index === 0 ? 'bdfg-chart-heading' : 'bdfg-chart-row'; ?>"> <?php foreach ($row as $cell) : ?> <<?php echo $row_index === 0 ? 'th' : 'td'; ?>> <?php echo esc_html($cell); ?> </<?php echo $row_index === 0 ? 'th' : 'td'; ?>> <?php endforeach; ?> </tr> <?php endforeach; ?> </tbody> </table> </div> <?php endif; ?> </div> <div class="bdfg-size-chart-popup-footer"> <span class="bdfg-copyright"><?php _e('Size Chart by', 'bdfg-size-chart'); ?> <a href="https://beiduofengou.net" target="_blank">beiduofengou</a></span> </div> </div> </div> <?php } else { // Inline display ?> <div class="bdfg-size-chart-inline" id="bdfg-size-chart-<?php echo esc_attr($chart_id); ?>"> <h3><?php echo esc_html($chart_title); ?></h3> <?php if (!empty($chart_content)) : ?> <div class="bdfg-size-chart-description"> <?php echo wp_kses_post($chart_content); ?> </div> <?php endif; ?> <?php if (!empty($table_data)) : ?> <div class="bdfg-size-chart-table-container"> <table class="bdfg-size-chart-table"> <tbody> <?php foreach ($table_data as $row_index => $row) : ?> <tr class="<?php echo $row_index === 0 ? 'bdfg-chart-heading' : 'bdfg-chart-row'; ?>"> <?php foreach ($row as $cell) : ?> <<?php echo $row_index === 0 ? 'th' : 'td'; ?>> <?php echo esc_html($cell); ?> </<?php echo $row_index === 0 ? 'th' : 'td'; ?>> <?php endforeach; ?> </tr> <?php endforeach; ?> </tbody> </table> </div> <?php endif; ?> <div class="bdfg-size-chart-footer"> <span class="bdfg-copyright"><?php _e('Size Chart by', 'bdfg-size-chart'); ?> <a href="https://beiduofengou.net" target="_blank">beiduofengou</a></span> </div> </div> <?php } return ob_get_clean(); } /** * Get default size chart templates * * @return array Default templates */ function bdfg_get_default_templates() { return array( 'mens_clothing' => array( 'title' => __("Men's Clothing Size Chart", "bdfg-size-chart"), 'table' => array( array('Size', 'Chest (inches)', 'Waist (inches)', 'Hips (inches)', 'Sleeve Length (inches)'), array('XS', '33-34', '27-28', '33-34', '31-32'), array('S', '35-37', '29-31', '35-37', '32-33'), array('M', '38-40', '32-34', '38-40', '33-34'), array('L', '41-43', '35-37', '41-43', '34-35'), array('XL', '44-46', '38-40', '44-46', '35-36'), array('XXL', '47-49', '41-43', '47-49', '36-37'), ), ), 'womens_clothing' => array( 'title' => __("Women's Clothing Size Chart", "bdfg-size-chart"), 'table' => array( array('Size', 'Bust (inches)', 'Waist (inches)', 'Hips (inches)'), array('XS (0-2)', '31-33', '23-25', '33-35'), array('S (4-6)', '34-36', '26-28', '36-38'), array('M (8-10)', '37-39', '29-31', '39-41'), array('L (12-14)', '40-42', '32-34', '42-44'), array('XL (16-18)', '43-45', '35-37', '45-47'), array('XXL (20-22)', '46-48', '38-40', '48-50'), ), ), 'shoes' => array( 'title' => __("Shoe Size Chart", "bdfg-size-chart"), 'table' => array( array('US Size', 'EU Size', 'UK Size', 'Inches', 'CM'), array('5', '35-36', '3', '8.5', '21.6'), array('6', '36-37', '4', '9', '22.9'), array('7', '37-38', '5', '9.5', '23.8'), array('8', '38-39', '6', '10', '24.8'), array('9', '39-40', '7', '10.5', '25.7'), array('10', '40-41', '8', '11', '26.7'), array('11', '41-42', '9', '11.5', '27.6'), array('12', '42-43', '10', '12', '28.6'), ), ), 'kids_clothing' => array( 'title' => __("Kid's Clothing Size Chart", "bdfg-size-chart"), 'table' => array( array('Size', 'Age', 'Height (inches)', 'Weight (lbs)', 'Chest (inches)', 'Waist (inches)'), array('2T', '2 years', '33-35', '30-32', '21', '20'), array('3T', '3 years', '36-38', '33-36', '22', '20.5'), array('4T', '4 years', '39-41', '37-41', '23', '21'), array('5', '5 years', '42-44', '42-46', '24', '21.5'), array('6', '6 years', '45-47', '47-53', '25', '22'), array('7', '7 years', '48-50', '54-61', '26', '22.5'), array('8', '8 years', '51-53', '62-71', '27', '23'), array('10', '10 years', '54-56', '72-85', '28', '24'), array('12', '12 years', '57-60', '86-100', '30', '25'), array('14', '14 years', '61-62', '101-114', '32', '26'), ), ), ); } /** * Load template data * * @param string $template_id Template ID * @return array Template data or empty array if not found */ function bdfg_load_template_data($template_id) { $templates = bdfg_get_default_templates(); if (isset($templates[$template_id])) { return $templates[$template_id]; } return array(); } /** * Check if a product has a size chart * * @param int $product_id Product ID * @return bool Whether product has a size chart */ function bdfg_product_has_size_chart($product_id) { $chart_id = bdfg_get_product_size_chart($product_id); return !empty($chart_id); } /** * Generate responsive size chart table HTML * * @param array $table_data Size chart table data * @return string HTML table markup */ function bdfg_generate_size_chart_table($table_data) { if (empty($table_data) || !is_array($table_data)) { return ''; } ob_start(); ?> <div class="bdfg-size-chart-table-container"> <table class="bdfg-size-chart-table"> <tbody> <?php foreach ($table_data as $row_index => $row) : ?> <tr class="<?php echo $row_index === 0 ? 'bdfg-chart-heading' : 'bdfg-chart-row'; ?>"> <?php foreach ($row as $cell) : ?> <<?php echo $row_index === 0 ? 'th' : 'td'; ?>> <?php echo esc_html($cell); ?> </<?php echo $row_index === 0 ? 'th' : 'td'; ?>> <?php endforeach; ?> </tr> <?php endforeach; ?> </tbody> </table> </div> <?php return ob_get_clean(); }
includes/admin/bdfg-size-chart-admin-functions.php
<?php /** * BDFG Size Chart Admin Functions * * Functions for the admin area. * * @package BDFG_Size_Chart * @version 2.3.0 * @since 1.0.0 * @author beiduofengou * @modified 2025-03-05 by beiduofengou */ // Exit if accessed directly if (!defined('ABSPATH')) { exit; } /** * Admin AJAX handler for loading template data */ function bdfg_admin_load_template() { // Check nonce if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'bdfg_size_chart_nonce')) { wp_send_json_error(array('message' => __("Security check failed", "bdfg-size-chart"))); } // Check if template ID is provided if (!isset($_POST['template_id']) || empty($_POST['template_id'])) { wp_send_json_error(array('message' => __("Invalid template ID", "bdfg-size-chart"))); } $template_id = sanitize_text_field($_POST['template_id']); // Load template data $template_data = bdfg_load_template_data($template_id); if (empty($template_data)) { wp_send_json_error(array('message' => __("Template not found", "bdfg-size-chart"))); } wp_send_json_success($template_data); } add_action('wp_ajax_bdfg_load_template', 'bdfg_admin_load_template'); /** * Get all size charts * * @return array Array of size chart posts */ function bdfg_get_all_size_charts() { return get_posts(array( 'post_type' => 'bdfg_size_chart', 'posts_per_page' => -1, 'orderby' => 'title', 'order' => 'ASC', )); } /** * Get the products assigned to a size chart * * @param int $chart_id The size chart ID * @return array Array of product posts */ function bdfg_get_products_by_chart($chart_id) { return get_posts(array( 'post_type' => 'product', 'posts_per_page' => -1, 'meta_key' => '_bdfg_product_size_chart', 'meta_value' => $chart_id, )); } /** * Get product categories assigned to a size chart * * @param int $chart_id The size chart ID * @return array Array of category terms */ function bdfg_get_categories_by_chart($chart_id) { $chart_categories = get_post_meta($chart_id, '_bdfg_chart_categories', true); if (empty($chart_categories) || !is_array($chart_categories)) { return array(); } return get_terms(array( 'taxonomy' => 'product_cat', 'include' => $chart_categories, 'hide_empty' => false, )); } /** * Check if a size chart is assigned to a category * * @param int $chart_id The size chart ID * @param int $category_id The category ID * @return bool Whether the chart is assigned to the category */ function bdfg_chart_is_assigned_to_category($chart_id, $category_id) { $chart_categories = get_post_meta($chart_id, '_bdfg_chart_categories', true); if (empty($chart_categories) || !is_array($chart_categories)) { return false; } return in_array($category_id, $chart_categories); } /** * Duplicate a size chart * * @param int $chart_id The size chart ID to duplicate * @return int|bool The new chart ID on success, false on failure */ function bdfg_duplicate_size_chart($chart_id) { // Get the original chart data $chart = get_post($chart_id); if (!$chart) { return false; } // Create the duplicate $new_chart_args = array( 'post_title' => sprintf(__('Copy of %s', 'bdfg-size-chart'), $chart->post_title), 'post_content' => $chart->post_content, 'post_status' => 'publish', 'post_type' => 'bdfg_size_chart', 'comment_status' => 'closed', 'ping_status' => 'closed', ); // Insert the new chart $new_chart_id = wp_insert_post($new_chart_args); if (is_wp_error($new_chart_id)) { return false; } // Copy all meta data $meta_keys = array( '_bdfg_chart_type', '_bdfg_chart_position', '_bdfg_chart_label', '_bdfg_chart_table', '_bdfg_chart_categories', ); foreach ($meta_keys as $meta_key) { $meta_value = get_post_meta($chart_id, $meta_key, true); update_post_meta($new_chart_id, $meta_key, $meta_value); } return $new_chart_id; } /** * Export size chart data as JSON * * @param int $chart_id The size chart ID to export * @return array Chart data for export */ function bdfg_export_size_chart($chart_id) { // Get chart post $chart = get_post($chart_id); if (!$chart) { return array(); } // Get chart meta data $chart_type = get_post_meta($chart_id, '_bdfg_chart_type', true); $chart_position = get_post_meta($chart_id, '_bdfg_chart_position', true); $chart_label = get_post_meta($chart_id, '_bdfg_chart_label', true); $chart_table = get_post_meta($chart_id, '_bdfg_chart_table', true); $chart_categories = get_post_meta($chart_id, '_bdfg_chart_categories', true); // Build export data $export_data = array( 'title' => $chart->post_title, 'content' => $chart->post_content, 'type' => $chart_type, 'position' => $chart_position, 'label' => $chart_label, 'table' => $chart_table, 'categories' => $chart_categories, 'version' => BDFG_SC_VERSION, 'exported' => date('Y-m-d H:i:s'), 'exported_by' => 'beiduofengou', ); return $export_data; } /** * Import size chart data from JSON * * @param array $import_data The chart data to import * @return int|bool The new chart ID on success, false on failure */ function bdfg_import_size_chart($import_data) { // Validate import data if (!isset($import_data['title']) || empty($import_data['title'])) { return false; } // Create new chart $new_chart_args = array( 'post_title' => sanitize_text_field($import_data['title']), 'post_content' => isset($import_data['content']) ? wp_kses_post($import_data['content']) : '', 'post_status' => 'publish', 'post_type' => 'bdfg_size_chart', 'comment_status' => 'closed', 'ping_status' => 'closed', ); // Insert the new chart $new_chart_id = wp_insert_post($new_chart_args); if (is_wp_error($new_chart_id)) { return false; } // Set chart meta data if (isset($import_data['type'])) { update_post_meta($new_chart_id, '_bdfg_chart_type', sanitize_text_field($import_data['type'])); } if (isset($import_data['position'])) { update_post_meta($new_chart_id, '_bdfg_chart_position', sanitize_text_field($import_data['position'])); } if (isset($import_data['label'])) { update_post_meta($new_chart_id, '_bdfg_chart_label', sanitize_text_field($import_data['label'])); } if (isset($import_data['table']) && is_array($import_data['table'])) { update_post_meta($new_chart_id, '_bdfg_chart_table', $import_data['table']); } if (isset($import_data['categories']) && is_array($import_data['categories'])) { $categories = array_map('intval', $import_data['categories']); update_post_meta($new_chart_id, '_bdfg_chart_categories', $categories); } // Add import note update_post_meta($new_chart_id, '_bdfg_import_info', array( 'imported_date' => current_time('mysql'), 'imported_by' => 'beiduofengou', 'version' => isset($import_data['version']) ? $import_data['version'] : 'unknown', )); return $new_chart_id; } /** * Get size chart usage statistics * * @return array Chart usage stats */ function bdfg_get_size_chart_stats() { $stats = array( 'total_charts' => 0, 'charts_in_use' => 0, 'products_with_charts' => 0, 'categories_with_charts' => 0, 'charts_by_type' => array( 'tab' => 0, 'popup' => 0, 'inline' => 0, ), ); // Get all charts $charts = bdfg_get_all_size_charts(); $stats['total_charts'] = count($charts); // Count charts in use and by type $used_chart_ids = array(); $category_ids_with_charts = array(); foreach ($charts as $chart) { // Count by type $chart_type = get_post_meta($chart->ID, '_bdfg_chart_type', true); if (!empty($chart_type) && isset($stats['charts_by_type'][$chart_type])) { $stats['charts_by_type'][$chart_type]++; } // Check if chart is used by products $products = bdfg_get_products_by_chart($chart->ID); if (!empty($products)) { $used_chart_ids[] = $chart->ID; $stats['products_with_charts'] += count($products); } // Check assigned categories $chart_categories = get_post_meta($chart->ID, '_bdfg_chart_categories', true); if (!empty($chart_categories) && is_array($chart_categories)) { $category_ids_with_charts = array_merge($category_ids_with_charts, $chart_categories); } } // Count unique charts in use $stats['charts_in_use'] = count(array_unique($used_chart_ids)); // Count unique categories with charts $stats['categories_with_charts'] = count(array_unique($category_ids_with_charts)); return $stats; }
includes/admin/views/html-size-charts-page.php
相关文章: WordPress优惠券提醒插件系统
<?php /** * Admin View: Size Charts Page * * @package BDFG_Size_Chart * @version 2.3.0 * @since 1.0.0 * @author beiduofengou * @updated 2025-03-05 15:32:54 */ // Exit if accessed directly if (!defined('ABSPATH')) { exit; } // Get all size charts $size_charts = bdfg_get_all_size_charts(); // Get stats $stats = bdfg_get_size_chart_stats(); ?> <div class="wrap bdfg-size-charts-page"> <h1 class="wp-heading-inline"><?php _e('BDFG Size Charts', 'bdfg-size-chart'); ?></h1> <a href="<?php echo admin_url('post-new.php?post_type=bdfg_size_chart'); ?>" class="page-title-action"><?php _e('Add New', 'bdfg-size-chart'); ?></a> <hr class="wp-header-end"> <?php // Display notices if (isset($_GET['imported']) && $_GET['imported'] == 1) { echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__('Size chart imported successfully.', 'bdfg-size-chart') . '</p></div>'; } elseif (isset($_GET['duplicated']) && $_GET['duplicated'] == 1) { echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__('Size chart duplicated successfully.', 'bdfg-size-chart') . '</p></div>'; } ?> <div class="bdfg-dashboard-stats"> <div class="bdfg-stats-card"> <h3><?php _e('Total Size Charts', 'bdfg-size-chart'); ?></h3> <span class="bdfg-stat-number"><?php echo esc_html($stats['total_charts']); ?></span> </div> <div class="bdfg-stats-card"> <h3><?php _e('Products With Charts', 'bdfg-size-chart'); ?></h3> <span class="bdfg-stat-number"><?php echo esc_html($stats['products_with_charts']); ?></span> </div> <div class="bdfg-stats-card"> <h3><?php _e('Categories With Charts', 'bdfg-size-chart'); ?></h3> <span class="bdfg-stat-number"><?php echo esc_html($stats['categories_with_charts']); ?></span> </div> </div> <?php if (empty($size_charts)) : ?> <div class="bdfg-no-charts"> <p><?php _e('No size charts found. Create your first size chart to get started.', 'bdfg-size-chart'); ?></p> <a href="<?php echo admin_url('post-new.php?post_type=bdfg_size_chart'); ?>" class="button button-primary"><?php _e('Create Size Chart', 'bdfg-size-chart'); ?></a> </div> <?php else : ?> <div class="bdfg-charts-list"> <table class="wp-list-table widefat fixed striped"> <thead> <tr> <th scope="col"><?php _e('Title', 'bdfg-size-chart'); ?></th> <th scope="col"><?php _e('Display Type', 'bdfg-size-chart'); ?></th> <th scope="col"><?php _e('Assigned Products', 'bdfg-size-chart'); ?></th> <th scope="col"><?php _e('Assigned Categories', 'bdfg-size-chart'); ?></th> <th scope="col"><?php _e('Actions', 'bdfg-size-chart'); ?></th> </tr> </thead> <tbody> <?php foreach ($size_charts as $chart) : $chart_type = get_post_meta($chart->ID, '_bdfg_chart_type', true); $products = bdfg_get_products_by_chart($chart->ID); $categories = bdfg_get_categories_by_chart($chart->ID); $display_type = ''; switch ($chart_type) { case 'tab': $display_type = __('Tab', 'bdfg-size-chart'); break; case 'popup': $display_type = __('Popup', 'bdfg-size-chart'); break; case 'inline': $display_type = __('Inline', 'bdfg-size-chart'); break; default: $display_type = __('Tab', 'bdfg-size-chart'); } ?> <tr> <td> <strong> <a href="<?php echo get_edit_post_link($chart->ID); ?>"><?php echo esc_html($chart->post_title); ?></a> </strong> <div class="row-actions"> <span class="edit"><a href="<?php echo get_edit_post_link($chart->ID); ?>"><?php _e('Edit', 'bdfg-size-chart'); ?></a> | </span> <span class="duplicate"><a href="<?php echo wp_nonce_url(admin_url('admin.php?page=bdfg-size-charts&action=duplicate&chart_id=' . $chart->ID), 'bdfg_duplicate_chart_' . $chart->ID); ?>"><?php _e('Duplicate', 'bdfg-size-chart'); ?></a> | </span> <span class="export"><a href="<?php echo wp_nonce_url(admin_url('admin.php?page=bdfg-size-charts&action=export&chart_id=' . $chart->ID), 'bdfg_export_chart_' . $chart->ID); ?>"><?php _e('Export', 'bdfg-size-chart'); ?></a> | </span> <span class="trash"><a href="<?php echo get_delete_post_link($chart->ID); ?>" class="submitdelete" onclick="return confirm('<?php _e('Are you sure you want to delete this size chart?', 'bdfg-size-chart'); ?>');"><?php _e('Delete', 'bdfg-size-chart'); ?></a></span> </div> </td> <td><?php echo esc_html($display_type); ?></td> <td> <?php if (!empty($products)) { echo count($products) . ' ' . __("products", "bdfg-size-chart"); if (count($products) <= 3) { echo '<div class="row-products">'; foreach ($products as $product) { echo '<a href="' . get_edit_post_link($product->ID) . '">' . esc_html($product->post_title) . '</a>, '; } echo '</div>'; } } else { _e("No products", "bdfg-size-chart"); } ?> </td> <td> <?php if (!empty($categories)) { $category_names = array(); foreach ($categories as $category) { $category_names[] = $category->name; } echo esc_html(implode(', ', $category_names)); } else { _e("No categories", "bdfg-size-chart"); } ?> </td> <td> <a href="<?php echo get_edit_post_link($chart->ID); ?>" class="button button-small"><?php _e('Edit', 'bdfg-size-chart'); ?></a> <a href="<?php echo get_permalink($chart->ID); ?>" class="button button-small" target="_blank"><?php _e('Preview', 'bdfg-size-chart'); ?></a> </td> </tr> <?php endforeach; ?> </tbody> </table> </div> <div class="bdfg-import-section"> <h2><?php _e('Import Size Chart', 'bdfg-size-chart'); ?></h2> <form method="post" enctype="multipart/form-data"> <?php wp_nonce_field('bdfg_import_chart', 'bdfg_import_chart_nonce'); ?> <input type="hidden" name="action" value="bdfg_import_chart"> <p> <input type="file" name="import_file" accept=".json"> <button type="submit" class="button"><?php _e('Import', 'bdfg-size-chart'); ?></button> </p> <p class="description"><?php _e('Import a size chart from a JSON file.', 'bdfg-size-chart'); ?></p> </form> </div> <?php endif; ?> <div class="bdfg-help-section"> <h2><?php _e('How to Use Size Charts', 'bdfg-size-chart'); ?></h2> <ol> <li><?php _e('Create a new size chart with your size information', 'bdfg-size-chart'); ?></li> <li><?php _e('Assign the size chart to specific products or product categories', 'bdfg-size-chart'); ?></li> <li><?php _e('Choose how to display the size chart (tab, popup, or inline)', 'bdfg-size-chart'); ?></li> <li><?php _e('The size chart will automatically appear on the product page', 'bdfg-size-chart'); ?></li> </ol> <h2><?php _e('Shortcode Usage', 'bdfg-size-chart'); ?></h2> <p><?php _e('You can also display a size chart anywhere on your site using the shortcode:', 'bdfg-size-chart'); ?></p> <code>[bdfg_size_chart id="123"]</code> <p class="description"><?php _e('Replace "123" with the ID of your size chart.', 'bdfg-size-chart'); ?></p> <div class="bdfg-footer"> <p> <?php /* translators: %s: beiduofengou.net URL */ printf(__('BDFG Size Chart for WooCommerce v%s by <a href="%s" target="_blank">beiduofengou</a>', 'bdfg-size-chart'), BDFG_SC_VERSION, 'https://beiduofengou.net' ); ?> </p> <p class="bdfg-updated-time"> <?php _e('Last updated:', 'bdfg-size-chart'); ?> 2025-03-05 15:34:42 by beiduofengou </p> </div> </div> </div>
assets/js/admin.js
/** * BDFG Size Chart Admin Scripts * * @package BDFG_Size_Chart * @version 2.3.0 * @author beiduofengou * @updated 2025-03-05 15:34:42 by beiduofengou */ (function($) { 'use strict'; // Size chart table builder var BDFGSizeChart = { init: function() { this.bindEvents(); this.initSortable(); }, bindEvents: function() { // Add row button $('.bdfg-add-row').on('click', this.addRow); // Add column button $('.bdfg-add-column').on('click', this.addColumn); // Remove row button $(document).on('click', '.bdfg-remove-row', this.removeRow); // Remove column button $(document).on('click', '.bdfg-remove-column', this.removeColumn); // Load template button $('.bdfg-load-template').on('click', this.loadTemplate); }, initSortable: function() { // Make rows sortable $('.bdfg-chart-table tbody').sortable({ axis: 'y', handle: 'td:first-child', helper: function(e, ui) { ui.children().each(function() { $(this).width($(this).width()); }); return ui; }, update: function(event, ui) { BDFGSizeChart.reindexTable(); } }); }, addRow: function(e) { e.preventDefault(); var $table = $('.bdfg-chart-table'); var columnCount = $table.find('tr:first td').length; var rowIndex = $table.find('tr').length; var $newRow = $('<tr class="bdfg-table-row"></tr>'); for (var i = 0; i < columnCount; i++) { var $cell = $('<td></td>'); var $input = $('<input type="text" name="bdfg_chart_table[' + rowIndex + '][' + i + ']" value="">'); $cell.append($input); // Add remove button to the first cell if (i === 0) { $cell.append('<a href="#" class="bdfg-remove-row" title="' + bdfg_size_chart_params.strings.remove + '">-</a>'); } $newRow.append($cell); } $table.find('tbody').append($newRow); }, addColumn: function(e) { e.preventDefault(); var $table = $('.bdfg-chart-table'); var $rows = $table.find('tr'); var columnIndex = $rows.first().find('td').length; $rows.each(function(rowIndex, row) { var $cell = $('<td></td>'); var $input = $('<input type="text" name="bdfg_chart_table[' + rowIndex + '][' + columnIndex + ']" value="">'); $cell.append($input); // Add remove button to the first row if (rowIndex === 0) { $cell.append('<a href="#" class="bdfg-remove-column" title="' + bdfg_size_chart_params.strings.remove + '">-</a>'); } $(row).append($cell); }); }, removeRow: function(e) { e.preventDefault(); if (confirm(bdfg_size_chart_params.strings.confirm_delete)) { var $row = $(this).closest('tr'); $row.remove(); BDFGSizeChart.reindexTable(); } }, removeColumn: function(e) { e.preventDefault(); if (confirm(bdfg_size_chart_params.strings.confirm_delete)) { var $cell = $(this).closest('td'); var columnIndex = $cell.index(); var $table = $('.bdfg-chart-table'); $table.find('tr').each(function() { $(this).find('td').eq(columnIndex).remove(); }); BDFGSizeChart.reindexTable(); } }, reindexTable: function() { var $table = $('.bdfg-chart-table'); var $rows = $table.find('tr'); $rows.each(function(rowIndex, row) { $(row).find('td').each(function(colIndex, cell) { var $input = $(cell).find('input'); $input.attr('name', 'bdfg_chart_table[' + rowIndex + '][' + colIndex + ']'); }); }); }, loadTemplate: function(e) { e.preventDefault(); var templateId = $('#bdfg_chart_template').val(); if (!templateId) { return; } var $spinner = $('.bdfg-spinner'); $spinner.addClass('is-active'); $.ajax({ url: bdfg_size_chart_params.ajax_url, type: 'POST', data: { action: 'bdfg_load_template', template_id: templateId, nonce: bdfg_size_chart_params.nonce }, success: function(response) { if (response.success && response.data) { // Update chart title if (response.data.title && !$('#title').val()) { $('#title').val(response.data.title); } // Update chart table if (response.data.table && Array.isArray(response.data.table)) { var $table = $('.bdfg-chart-table'); var $tbody = $table.find('tbody').empty(); // Add rows and cells $.each(response.data.table, function(rowIndex, row) { var $row = $('<tr class="bdfg-table-row"></tr>'); $.each(row, function(colIndex, cell) { var $cell = $('<td></td>'); var $input = $('<input type="text" name="bdfg_chart_table[' + rowIndex + '][' + colIndex + ']" value="' + cell + '">'); $cell.append($input); // Add action buttons to first row/column if (rowIndex === 0 && colIndex === 0) { $cell.append('<span class="bdfg-cell-actions"><a href="#" class="bdfg-remove-row" title="' + bdfg_size_chart_params.strings.remove + '">-</a><a href="#" class="bdfg-remove-column" title="' + bdfg_size_chart_params.strings.remove + '">-</a></span>'); } else if (rowIndex === 0) { $cell.append('<a href="#" class="bdfg-remove-column" title="' + bdfg_size_chart_params.strings.remove + '">-</a>'); } else if (colIndex === 0) { $cell.append('<a href="#" class="bdfg-remove-row" title="' + bdfg_size_chart_params.strings.remove + '">-</a>'); } $row.append($cell); }); $tbody.append($row); }); } } else { alert(response.data.message || 'Error loading template'); } }, error: function() { alert('Error loading template. Please try again.'); }, complete: function() { $spinner.removeClass('is-active'); } }); } }; $(document).ready(function() { BDFGSizeChart.init(); }); })(jQuery);
assets/js/frontend.js
相关文章: WordPress 智能缓存管理
/** * BDFG Size Chart Frontend Scripts * * @package BDFG_Size_Chart * @version 2.3.0 * @author beiduofengou * @updated 2025-03-05 15:34:42 by beiduofengou */ (function($) { 'use strict'; // Size chart popup functionality var BDFGSizeChartFrontend = { init: function() { this.bindEvents(); this.setupResponsiveTables(); }, bindEvents: function() { // Open popup on button click $(document).on('click', '.bdfg-size-chart-button', this.openPopup); // Close popup on close button click $(document).on('click', '.bdfg-size-chart-close', this.closePopup); // Close popup on background click $(document).on('click', '.bdfg-size-chart-popup', function(e) { if ($(e.target).hasClass('bdfg-size-chart-popup')) { BDFGSizeChartFrontend.closePopup(e); } }); // Close popup on ESC key press $(document).on('keyup', function(e) { if (e.key === "Escape" && $('.bdfg-size-chart-popup:visible').length) { BDFGSizeChartFrontend.closePopup(e); } }); }, openPopup: function(e) { e.preventDefault(); var chartId = $(this).data('chart-id'); var popup = $('#bdfg-size-chart-popup-' + chartId); // Show popup popup.fadeIn(300); // Add active class to body $('body').addClass('bdfg-size-chart-open'); // Add active class to button $(this).addClass('active'); }, closePopup: function(e) { e.preventDefault(); // Hide all popups $('.bdfg-size-chart-popup').fadeOut(200); // Remove active class from body $('body').removeClass('bdfg-size-chart-open'); // Remove active class from buttons $('.bdfg-size-chart-button').removeClass('active'); }, setupResponsiveTables: function() { $('.bdfg-size-chart-table').each(function() { var $table = $(this); var headerTexts = []; // Get header texts $table.find('tr:first-child th').each(function() { headerTexts.push($(this).text()); }); // Add data attributes for responsive labels $table.find('tr:not(:first-child)').each(function() { $(this).find('td').each(function(index) { if (headerTexts[index]) { $(this).attr('data-label', headerTexts[index]); } }); }); }); } }; $(document).ready(function() { BDFGSizeChartFrontend.init(); }); })(jQuery);
assets/css/admin.css
/** * BDFG Size Chart Admin Styles * * @package BDFG_Size_Chart * @version 2.3.0 * @author beiduofengou * @updated 2025-03-05 15:34:42 by beiduofengou */ /* Size Chart Builder */ .bdfg-chart-builder { margin-top: 20px; padding: 15px; background: #fff; border: 1px solid #ddd; border-radius: 4px; } .bdfg-table-controls { margin-bottom: 15px; } .bdfg-table-container { margin-bottom: 20px; overflow-x: auto; } .bdfg-chart-table { width: 100%; border-collapse: collapse; margin-top: 10px; } .bdfg-chart-table td { position: relative; padding: 8px; vertical-align: top; border: 1px solid #ddd; } .bdfg-chart-table input[type="text"] { width: 100%; padding: 6px; box-sizing: border-box; } .bdfg-remove-row, .bdfg-remove-column { position: absolute; top: 3px; right: 3px; display: block; width: 16px; height: 16px; line-height: 14px; font-size: 16px; text-align: center; background: #f1f1f1; color: #999; border-radius: 50%; text-decoration: none; z-index: 10; } .bdfg-remove-row:hover, .bdfg-remove-column:hover { background: #e14d43; color: #fff; } .bdfg-cell-actions { position: absolute; top: 3px; right: 3px; } .bdfg-cell-actions .bdfg-remove-column { right: 20px; } .bdfg-template-selection { margin-top: 20px; padding-top: 15px; border-top: 1px solid #eee; } .bdfg-spinner { float: none; margin: 0 0 0 5px; vertical-align: middle; } /* Categories Meta Box */ .bdfg-categories-wrapper { max-height: 200px; overflow-y: auto; border: 1px solid #ddd; padding: 10px; margin-bottom: 10px; background: #f9f9f9; } .bdfg-categories-list { margin: 0; } .bdfg-categories-list li { margin: 0; padding: 3px 0; } /* Size Chart Admin Page */ .bdfg-size-charts-page .wp-list-table th { font-weight: 600; } .bdfg-dashboard-stats { display: flex; flex-wrap: wrap; margin: 20px 0; gap: 20px; } .bdfg-stats-card { background-color: #fff; border: 1px solid #ddd; border-radius: 4px; padding: 15px; width: calc(33.333% - 14px); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); text-align: center; box-sizing: border-box; } .bdfg-stats-card h3 { margin-top: 0; color: #23282d; } .bdfg-stat-number { font-size: 32px; font-weight: 600; color: #0073aa; } .bdfg-no-charts { background: #fff; padding: 20px; border: 1px solid #ddd; border-radius: 4px; margin: 20px 0; text-align: center; } .bdfg-help-section { margin-top: 30px; background: #fff; padding: 20px; border: 1px solid #ddd; border-radius: 4px; } .bdfg-help-section h2 { margin-top: 0; padding-bottom: 10px; border-bottom: 1px solid #eee; } .bdfg-help-section code { display: inline-block; padding: 8px 12px; margin: 10px 0; background: #f5f5f5; border: 1px solid #ddd; border-radius: 3px; } .bdfg-import-section { margin: 20px 0; background: #fff; padding: 20px; border: 1px solid #ddd; border-radius: 4px; } .bdfg-footer { margin-top: 30px; padding-top: 15px; border-top: 1px solid #eee; color: #666; font-style: italic; } .bdfg-updated-time { margin: 5px 0 0; font-size: 12px; color: #888; } @media screen and (max-width: 782px) { .bdfg-stats-card { width: 100%; } }
assets/css/admin-list.css
/** * BDFG Size Chart Admin List Styles * * @package BDFG_Size_Chart * @version 2.3.0 * @author beiduofengou * @updated 2025-03-05 15:35:49 by beiduofengou */ .bdfg-charts-list .row-products { margin-top: 5px; font-size: 12px; color: #666; } .bdfg-charts-list .row-products a { text-decoration: none; } .bdfg-charts-list .column-actions { text-align: right; }
assets/css/frontend.css
/** * BDFG Size Chart Frontend Styles * * @package BDFG_Size_Chart * @version 2.3.0 * @author beiduofengou * @updated 2025-03-05 15:35:49 by beiduofengou */ /* Button Styles */ .bdfg-size-chart-button-wrapper { margin: 15px 0; } .bdfg-size-chart-button { background: #f7f7f7; border: 1px solid #ccc; color: #555; padding: 8px 15px; font-size: 14px; line-height: 1.5; cursor: pointer; border-radius: 3px; text-decoration: none; transition: all 0.2s ease; } .bdfg-size-chart-button:hover, .bdfg-size-chart-button:focus, .bdfg-size-chart-button.active { background: #ebebeb; border-color: #aaa; color: #333; } /* Popup Styles */ .bdfg-size-chart-popup { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); z-index: 999999; display: none; overflow-y: auto; } .bdfg-size-chart-popup-inner { position: relative; width: 90%; max-width: 900px; max-height: 90vh; margin: 30px auto; background: #fff; border-radius: 5px; box-shadow: 0 0 20px rgba(0, 0, 0, 0.2); overflow: hidden; display: flex; flex-direction: column; } .bdfg-size-chart-popup-header { padding: 15px 20px; border-bottom: 1px solid #eee; display: flex; align-items: center; justify-content: space-between; } .bdfg-size-chart-popup-header h2 { margin: 0; padding: 0; font-size: 18px; line-height: 1.4; color: #333; } .bdfg-size-chart-close { padding: 0; background: none; border: none; color: #999; font-size: 26px; line-height: 1; cursor: pointer; transition: color 0.2s ease; } .bdfg-size-chart-close:hover { color: #333; } .bdfg-size-chart-popup-content { padding: 20px; overflow-y: auto; flex: 1; } .bdfg-size-chart-popup-footer { padding: 10px 20px; border-top: 1px solid #eee; text-align: right; font-size: 12px; color: #999; } .bdfg-size-chart-popup-footer a { color: #0073aa; text-decoration: none; } /* Tab Styles */ .bdfg-size-chart-tab-content { padding: 20px 0; } .bdfg-size-chart-tab-content h2 { margin-top: 0; margin-bottom: 15px; } /* Inline Styles */ .bdfg-size-chart-inline { margin: 20px 0; padding: 20px; background: #f9f9f9; border: 1px solid #eee; border-radius: 3px; } .bdfg-size-chart-inline h3 { margin-top: 0; margin-bottom: 15px; } /* Common Styles */ .bdfg-size-chart-description { margin-bottom: 20px; } .bdfg-size-chart-description p:last-child { margin-bottom: 0; } .bdfg-size-chart-table-container { overflow-x: auto; margin-bottom: 20px; } .bdfg-size-chart-table { width: 100%; border-collapse: collapse; border: 1px solid #ddd; } .bdfg-size-chart-table th, .bdfg-size-chart-table td { padding: 10px; border: 1px solid #ddd; text-align: center; } .bdfg-size-chart-table th { background: #f5f5f5; font-weight: 600; } .bdfg-size-chart-table tr:nth-child(even) td { background: #fafafa; } .bdfg-size-chart-footer { margin-top: 20px; padding-top: 10px; border-top: 1px solid #eee; font-size: 12px; color: #999; text-align: right; } .bdfg-size-chart-footer a { color: #0073aa; text-decoration: none; } .bdfg-copyright { font-size: 12px; } /* Responsive Styles */ @media screen and (max-width: 600px) { .bdfg-size-chart-table, .bdfg-size-chart-table tbody, .bdfg-size-chart-table th, .bdfg-size-chart-table td, .bdfg-size-chart-table tr { display: block; } .bdfg-size-chart-table tr:first-child { position: absolute; top: -9999px; left: -9999px; } .bdfg-size-chart-table tr { border: 1px solid #ddd; margin-bottom: 5px; } .bdfg-size-chart-table td { border: none; border-bottom: 1px solid #eee; position: relative; padding-left: 50%; text-align: left; min-height: 30px; } .bdfg-size-chart-table td:before { position: absolute; left: 10px; width: 45%; padding-right: 10px; white-space: nowrap; font-weight: 600; content: attr(data-label); } .bdfg-size-chart-table td:last-child { border-bottom: none; } .bdfg-size-chart-popup-inner { width: 95%; margin: 20px auto; } } .bdfg-size-chart-shortcode { margin: 20px 0; padding: 15px; background: #f9f9f9; border: 1px solid #eee; border-radius: 3px; }