增强 WooCommerce 产品定制功能,提供灵活的选项和字段
<?php /** * Plugin Name: BDFG WooCommerce Custom Options * Plugin URI: https://beiduofengou.net/2024/08/15/bdfg-woocommerce-custom-options/ * Description: Enhanced WooCommerce product customization with flexible options and fields * Version: 2.2.1 * Requires at least: 5.8 * Requires PHP: 7.4 * Author: beiduofengou * Author URI: https://beiduofengou.net * Text Domain: bdfg-woo-custom-options * Domain Path: /languages * WC requires at least: 5.0 * WC tested up to: 8.2 * License: GPL v2 or later * * @package BDFG_Woo_Custom_Options * @author beiduofengou * @link https://beiduofengou.net */ if (!defined('ABSPATH')) { exit; // Exit if accessed directly } if (!class_exists('BDFG_Woo_Custom_Options')) { /** * Main plugin class * * @since 2.0.0 */ class BDFG_Woo_Custom_Options { /** * Plugin version * @var string */ private $version = '2.2.1'; /** * The single instance of the class * @var BDFG_Woo_Custom_Options */ protected static $_instance = null; /** * Main BDFG_Woo_Custom_Options Instance * * Ensures only one instance of BDFG_Woo_Custom_Options is loaded * * @since 2.0.0 * @static * @return BDFG_Woo_Custom_Options - Main instance */ public static function instance() { if (is_null(self::$_instance)) { self::$_instance = new self(); } return self::$_instance; } /** * Constructor */ public function __construct() { $this->define_constants(); $this->includes(); $this->init_hooks(); // Load text domain for translations add_action('plugins_loaded', array($this, 'load_plugin_textdomain')); // Add settings link on plugins page add_filter('plugin_action_links_' . plugin_basename(__FILE__), array($this, 'add_settings_link')); } /** * Define plugin constants */ private function define_constants() { $this->define('BDFG_WCO_VERSION', $this->version); $this->define('BDFG_WCO_PLUGIN_DIR', plugin_dir_path(__FILE__)); $this->define('BDFG_WCO_PLUGIN_URL', plugin_dir_url(__FILE__)); $this->define('BDFG_WCO_PLUGIN_BASENAME', plugin_basename(__FILE__)); } /** * Define constant if not already defined */ private function define($name, $value) { if (!defined($name)) { define($name, $value); } } /** * Include required files */ private function includes() { // Core classes require_once BDFG_WCO_PLUGIN_DIR . 'includes/class-bdfg-custom-fields.php'; require_once BDFG_WCO_PLUGIN_DIR . 'includes/class-bdfg-order-handler.php'; require_once BDFG_WCO_PLUGIN_DIR . 'includes/class-bdfg-admin.php'; require_once BDFG_WCO_PLUGIN_DIR . 'includes/class-bdfg-advanced-features.php'; // Admin only includes if ($this->is_request('admin')) { require_once BDFG_WCO_PLUGIN_DIR . 'includes/admin/class-bdfg-admin-settings.php'; } } /** * Initialize hooks */ private function init_hooks() { // Check WooCommerce dependency add_action('admin_init', array($this, 'check_environment')); // Initialize components add_action('init', array($this, 'init'), 0); // Register activation hook register_activation_hook(__FILE__, array($this, 'activate')); // Register deactivation hook register_deactivation_hook(__FILE__, array($this, 'deactivate')); } /** * Load plugin text domain */ public function load_plugin_textdomain() { load_plugin_textdomain( 'bdfg-woo-custom-options', false, dirname(plugin_basename(__FILE__)) . '/languages/' ); } /** * Add settings link to plugin list */ public function add_settings_link($links) { $settings_link = sprintf( '<a href="%s">%s</a>', admin_url('admin.php?page=bdfg-custom-options'), __('Settings', 'bdfg-woo-custom-options') ); array_unshift($links, $settings_link); return $links; } /** * Check if request is admin */ private function is_request($type) { switch ($type) { case 'admin': return is_admin(); case 'ajax': return defined('DOING_AJAX'); case 'cron': return defined('DOING_CRON'); case 'frontend': return (!is_admin() || defined('DOING_AJAX')) && !defined('DOING_CRON'); } } /** * Check environment on admin initialization */ public function check_environment() { if (!class_exists('WooCommerce')) { add_action('admin_notices', function() { ?> <div class="error"> <p><?php _e('BDFG WooCommerce Custom Options requires WooCommerce to be installed and activated.', 'bdfg-woo-custom-options'); ?></p> </div> <?php }); return; } } /** * Initialize plugin */ public function init() { // Before init action do_action('before_bdfg_wco_init'); // Initialize components BDFG_Custom_Fields::init(); BDFG_Order_Handler::init(); BDFG_Advanced_Features::init(); if (is_admin()) { BDFG_Admin::init(); } // Init action do_action('bdfg_wco_init'); } /** * Activation hook */ public function activate() { // Create necessary database tables $this->create_tables(); // Set default options $this->set_default_options(); // Clear cache wp_cache_flush(); // Set activation flag set_transient('bdfg_wco_activation_redirect', true, 30); // Trigger action do_action('bdfg_wco_activated'); } /** * Create plugin tables */ private function create_tables() { global $wpdb; $charset_collate = $wpdb->get_charset_collate(); $tables = array( "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}bdfg_custom_fields ( id bigint(20) NOT NULL AUTO_INCREMENT, product_id bigint(20) NOT NULL, field_name varchar(255) NOT NULL, field_type varchar(50) NOT NULL, field_label varchar(255) NOT NULL, field_options text, required tinyint(1) DEFAULT 0, sort_order int(11) DEFAULT 0, price_adjustment decimal(10,2) DEFAULT 0.00, price_type varchar(20) DEFAULT 'fixed', created_at datetime DEFAULT CURRENT_TIMESTAMP, updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY product_id (product_id) ) $charset_collate;", "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}bdfg_field_conditions ( id bigint(20) NOT NULL AUTO_INCREMENT, field_id bigint(20) NOT NULL, depends_on_field bigint(20) NOT NULL, operator varchar(20) NOT NULL, value text, created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY field_id (field_id) ) $charset_collate;" ); require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); foreach ($tables as $table) { dbDelta($table); } } /** * Set default plugin options */ private function set_default_options() { $defaults = array( 'enable_custom_fields' => 'yes', 'field_position' => 'woocommerce_before_add_to_cart_button', 'display_in_emails' => 'yes', 'display_in_orders' => 'yes', 'enable_price_calc' => 'yes', 'enable_conditions' => 'yes', 'file_upload_path' => 'bdfg-uploads' ); foreach ($defaults as $key => $value) { if (get_option('bdfg_wco_' . $key) === false) { update_option('bdfg_wco_' . $key, $value); } } } /** * Deactivation hook */ public function deactivate() { // Clear any cached data wp_cache_flush(); // Trigger action do_action('bdfg_wco_deactivated'); } } } /** * Returns the main instance of BDFG_Woo_Custom_Options * * @since 2.0.0 * @return BDFG_Woo_Custom_Options */ function BDFG_Woo_Custom_Options() { return BDFG_Woo_Custom_Options::instance(); } // Global for backwards compatibility $GLOBALS['bdfg_woo_custom_options'] = BDFG_Woo_Custom_Options();
includes/class-bdfg-custom-fields.php
相关文章: WooCommerce 客户分析报告插件
<?php /** * BDFG Custom Fields Handler * * Handles all custom field operations for products * * @package BDFG_Woo_Custom_Options * @since 2.0.0 */ if (!defined('ABSPATH')) { exit; } class BDFG_Custom_Fields { /** * Instance of this class * @var BDFG_Custom_Fields */ private static $instance = null; /** * Cache key prefix for custom fields * @var string */ private $cache_prefix = 'bdfg_custom_fields_'; /** * Cache group * @var string */ private $cache_group = 'bdfg_wco'; /** * Field types supported by the plugin * @var array */ private $field_types = array(); /** * Initialize the class */ public static function init() { if (self::$instance === null) { self::$instance = new self(); } return self::$instance; } /** * Constructor */ private function __construct() { $this->setup_field_types(); $this->add_hooks(); } /** * Setup supported field types */ private function setup_field_types() { $this->field_types = array( 'text' => array( 'label' => __('Text Field', 'bdfg-woo-custom-options'), 'template' => 'text.php' ), 'textarea' => array( 'label' => __('Text Area', 'bdfg-woo-custom-options'), 'template' => 'textarea.php' ), 'select' => array( 'label' => __('Dropdown', 'bdfg-woo-custom-options'), 'template' => 'select.php' ), 'radio' => array( 'label' => __('Radio Buttons', 'bdfg-woo-custom-options'), 'template' => 'radio.php' ), 'checkbox' => array( 'label' => __('Checkbox', 'bdfg-woo-custom-options'), 'template' => 'checkbox.php' ) ); // Allow other plugins to add custom field types $this->field_types = apply_filters('bdfg_wco_field_types', $this->field_types); } /** * Add necessary hooks */ private function add_hooks() { // Display fields add_action('woocommerce_before_add_to_cart_button', array($this, 'display_product_fields'), 10); // Validate fields add_filter('woocommerce_add_to_cart_validation', array($this, 'validate_add_to_cart_fields'), 10, 3); // Add fields to cart add_filter('woocommerce_add_cart_item_data', array($this, 'add_cart_item_data'), 10, 3); // Display fields in cart add_filter('woocommerce_get_item_data', array($this, 'get_cart_item_data'), 10, 2); // Save fields to order add_action('woocommerce_checkout_create_order_line_item', array($this, 'save_order_item_fields'), 10, 4); } /** * Display custom fields on product page */ public function display_product_fields() { global $product; if (!$product || !$this->should_display_fields($product)) { return; } $fields = $this->get_product_fields($product->get_id()); if (empty($fields)) { return; } // Start custom fields wrapper echo '<div class="bdfg-custom-fields" data-product-id="' . esc_attr($product->get_id()) . '">'; echo '<h3>' . esc_html__('Additional Options', 'bdfg-woo-custom-options') . '</h3>'; foreach ($fields as $field) { $this->render_field($field, $product); } echo '</div>'; // Add necessary scripts $this->enqueue_frontend_assets(); } /** * Check if fields should be displayed for this product */ private function should_display_fields($product) { // Don't show fields for external products if ($product->get_type() === 'external') { return false; } // Allow filtering return apply_filters('bdfg_wco_should_display_fields', true, $product); } /** * Get custom fields for a product */ public function get_product_fields($product_id) { $cache_key = $this->cache_prefix . $product_id; $fields = wp_cache_get($cache_key, $this->cache_group); if ($fields === false) { global $wpdb; $fields = $wpdb->get_results($wpdb->prepare( "SELECT * FROM {$wpdb->prefix}bdfg_custom_fields WHERE product_id = %d ORDER BY sort_order ASC", $product_id ), ARRAY_A); wp_cache_set($cache_key, $fields, $this->cache_group, 3600); } return $fields; } /** * Render individual custom field */ private function render_field($field, $product) { $field_type = isset($this->field_types[$field['field_type']]) ? $field['field_type'] : 'text'; $template = $this->field_types[$field_type]['template']; $field_id = 'bdfg_custom_' . esc_attr($field['id']); // Common field attributes $field_data = array( 'id' => $field_id, 'name' => 'bdfg_custom[' . esc_attr($field['id']) . ']', 'label' => esc_html($field['field_label']), 'required' => !empty($field['required']), 'options' => maybe_unserialize($field['field_options']), 'price_adjustment' => isset($field['price_adjustment']) ? floatval($field['price_adjustment']) : 0, 'price_type' => isset($field['price_type']) ? $field['price_type'] : 'fixed' ); // Load field template $template_path = $this->locate_template($template); if ($template_path) { include $template_path; } } /** * Locate template file */ private function locate_template($template) { $locations = array( get_stylesheet_directory() . '/bdfg-woo-custom-options/', get_template_directory() . '/bdfg-woo-custom-options/', BDFG_WCO_PLUGIN_DIR . 'templates/fields/' ); foreach ($locations as $location) { if (file_exists($location . $template)) { return $location . $template; } } return false; } /** * Enqueue frontend assets */ private function enqueue_frontend_assets() { wp_enqueue_style( 'bdfg-custom-fields', BDFG_WCO_PLUGIN_URL . 'assets/css/frontend.css', array(), BDFG_WCO_VERSION ); wp_enqueue_script( 'bdfg-custom-fields', BDFG_WCO_PLUGIN_URL . 'assets/js/frontend.js', array('jquery'), BDFG_WCO_VERSION, true ); wp_localize_script('bdfg-custom-fields', 'bdfgWco', array( 'ajaxUrl' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('bdfg-wco-frontend'), 'i18n' => array( 'required' => __('This field is required.', 'bdfg-woo-custom-options'), 'invalid' => __('Please enter a valid value.', 'bdfg-woo-custom-options') ) )); } /** * Validate fields when adding to cart */ public function validate_add_to_cart_fields($passed, $product_id, $quantity) { if (!isset($_POST['bdfg_custom'])) { return $passed; } $fields = $this->get_product_fields($product_id); foreach ($fields as $field) { if ($field['required'] && (!isset($_POST['bdfg_custom'][$field['id']]) || empty($_POST['bdfg_custom'][$field['id']]))) { wc_add_notice( sprintf( __('"%s" is a required field.', 'bdfg-woo-custom-options'), $field['field_label'] ), 'error' ); $passed = false; } } return $passed; } /** * Add custom field data to cart item */ public function add_cart_item_data($cart_item_data, $product_id, $variation_id) { if (!isset($_POST['bdfg_custom'])) { return $cart_item_data; } $fields = $this->get_product_fields($product_id); $custom_data = array(); foreach ($fields as $field) { if (isset($_POST['bdfg_custom'][$field['id']])) { $value = $this->sanitize_field_value( $_POST['bdfg_custom'][$field['id']], $field['field_type'] ); $custom_data[$field['id']] = array( 'label' => $field['field_label'], 'value' => $value, 'type' => $field['field_type'], 'price_adjustment' => isset($field['price_adjustment']) ? floatval($field['price_adjustment']) : 0, 'price_type' => isset($field['price_type']) ? $field['price_type'] : 'fixed' ); } } if (!empty($custom_data)) { $cart_item_data['bdfg_custom_fields'] = $custom_data; } return $cart_item_data; } /** * Sanitize field value based on type */ private function sanitize_field_value($value, $type) { switch ($type) { case 'textarea': return sanitize_textarea_field($value); case 'email': return sanitize_email($value); case 'url': return esc_url_raw($value); case 'number': return is_numeric($value) ? floatval($value) : 0; default: return sanitize_text_field($value); } } /** * Display custom fields in cart */ public function get_cart_item_data($item_data, $cart_item) { if (isset($cart_item['bdfg_custom_fields'])) { foreach ($cart_item['bdfg_custom_fields'] as $field) { $item_data[] = array( 'key' => $field['label'], 'value' => $this->format_display_value($field['value'], $field['type']) ); } } return $item_data; } /** * Format field value for display */ private function format_display_value($value, $type) { switch ($type) { case 'file': $filename = basename($value); return sprintf( '<a href="%s" target="_blank">%s</a>', esc_url($value), esc_html($filename) ); case 'color': return sprintf( '<span class="bdfg-color-preview" style="background:%1$s"></span> %1$s', esc_attr($value) ); case 'date': return date_i18n(get_option('date_format'), strtotime($value)); default: return esc_html($value); } } /** * Save custom fields to order line item */ public function save_order_item_fields($item, $cart_item_key, $cart_item, $order) { if (isset($cart_item['bdfg_custom_fields'])) { foreach ($cart_item['bdfg_custom_fields'] as $field_id => $field) { $item->add_meta_data($field['label'], $field['value']); // Save additional field data for future reference $item->add_meta_data('_bdfg_field_' . $field_id, array( 'type' => $field['type'], 'price_adjustment' => $field['price_adjustment'], 'price_type' => $field['price_type'] ), true); } } } }
includes/class-bdfg-order-handler.php
<?php /** * BDFG Order Handler * * Handles all order-related operations for custom fields * * @package BDFG_Woo_Custom_Options * @since 2.0.0 */ if (!defined('ABSPATH')) { exit; } class BDFG_Order_Handler { /** * Instance of this class * @var BDFG_Order_Handler */ private static $instance = null; /** * Initialize the class */ public static function init() { if (self::$instance === null) { self::$instance = new self(); } return self::$instance; } /** * Constructor */ private function __construct() { // Add custom fields to order details add_action('woocommerce_admin_order_item_headers', array($this, 'add_order_item_header')); add_action('woocommerce_admin_order_item_values', array($this, 'add_order_item_values'), 10, 3); // Add custom fields to order emails add_action('woocommerce_order_item_meta_end', array($this, 'add_email_order_item_fields'), 10, 3); // Add custom fields to order API response add_filter('woocommerce_api_order_response', array($this, 'add_api_order_fields'), 10, 2); // Add order search by custom fields add_filter('woocommerce_shop_order_search_fields', array($this, 'add_custom_fields_to_order_search')); } /** * Add header to order items table */ public function add_order_item_header() { ?> <th class="bdfg-custom-options"> <?php esc_html_e('Custom Options', 'bdfg-woo-custom-options'); ?> </th> <?php } /** * Add custom field values to order items table */ public function add_order_item_values($product, $item, $item_id) { echo '<td class="bdfg-custom-options">'; $custom_fields = $this->get_order_item_fields($item); if (!empty($custom_fields)) { echo '<ul class="bdfg-order-fields">'; foreach ($custom_fields as $field) { printf( '<li><strong>%s:</strong> %s</li>', esc_html($field['label']), $this->format_field_value($field['value'], $field['type']) ); } echo '</ul>'; } echo '</td>'; } /** * Get custom fields from order item */ private function get_order_item_fields($item) { $fields = array(); foreach ($item->get_meta_data() as $meta) { if (strpos($meta->key, '_bdfg_field_') === 0) { $data = $meta->value; $field_id = str_replace('_bdfg_field_', '', $meta->key); $fields[$field_id] = array( 'label' => $item->get_meta($data['label']), 'value' => $item->get_meta($data['value']), 'type' => $data['type'], 'price_adjustment' => $data['price_adjustment'], 'price_type' => $data['price_type'] ); } } return $fields; } /** * Format field value for display */ private function format_field_value($value, $type) { switch ($type) { case 'file': $filename = basename($value); return sprintf( '<a href="%s" target="_blank" class="bdfg-file-link">%s</a>', esc_url($value), esc_html($filename) ); case 'color': return sprintf( '<span class="bdfg-color-swatch" style="background:%1$s"></span> <code>%1$s</code>', esc_attr($value) ); case 'date': return date_i18n(get_option('date_format'), strtotime($value)); default: return esc_html($value); } } /** * Add custom fields to order emails */ public function add_email_order_item_fields($item_id, $item, $order) { if (!get_option('bdfg_wco_display_in_emails', 'yes')) { return; } $custom_fields = $this->get_order_item_fields($item); if (!empty($custom_fields)) { echo '<br><strong>' . esc_html__('Custom Options:', 'bdfg-woo-custom-options') . '</strong><br>'; foreach ($custom_fields as $field) { printf( '%s: %s<br>', esc_html($field['label']), wp_kses_post($this->format_field_value($field['value'], $field['type'])) ); } } } /** * Add custom fields to API order response */ public function add_api_order_fields($order_data, $order) { foreach ($order_data['line_items'] as &$item) { $order_item = $order->get_item($item['id']); $custom_fields = $this->get_order_item_fields($order_item); if (!empty($custom_fields)) { $item['custom_fields'] = array_map(function($field) { return array( 'label' => $field['label'], 'value' => $field['value'], 'type' => $field['type'], 'price_adjustment' => array( 'amount' => $field['price_adjustment'], 'type' => $field['price_type'] ) ); }, $custom_fields); } } return $order_data; } /** * Add custom fields to order search */ public function add_custom_fields_to_order_search($search_fields) { $search_fields[] = '_bdfg_field_%'; return $search_fields; } }
includes/class-bdfg-advanced-features.php
相关文章: WordPress 智能缓存管理
<?php /** * BDFG Advanced Features Handler * * Handles advanced functionality like conditional logic and dynamic pricing * * @package BDFG_Woo_Custom_Options * @since 2.0.0 * @author beiduofengou */ if (!defined('ABSPATH')) { exit; } class BDFG_Advanced_Features { /** * Instance of this class * @var BDFG_Advanced_Features */ private static $instance = null; /** * Initialize the class */ public static function init() { if (self::$instance === null) { self::$instance = new self(); } return self::$instance; } /** * Constructor */ private function __construct() { // Add advanced field types add_filter('bdfg_wco_field_types', array($this, 'add_advanced_field_types')); // Handle conditional logic add_action('wp_enqueue_scripts', array($this, 'enqueue_conditional_logic_scripts')); add_filter('bdfg_wco_field_data', array($this, 'add_conditional_logic_data')); // Handle dynamic pricing add_filter('woocommerce_product_get_price', array($this, 'adjust_price_by_options'), 10, 2); add_filter('woocommerce_product_variation_get_price', array($this, 'adjust_price_by_options'), 10, 2); } /** * Add advanced field types */ public function add_advanced_field_types($field_types) { $advanced_types = array( 'date' => array( 'label' => __('Date Picker', 'bdfg-woo-custom-options'), 'template' => 'date-picker.php', 'assets' => array( 'css' => array('jquery-ui-datepicker'), 'js' => array('jquery-ui-datepicker') ) ), 'time' => array( 'label' => __('Time Picker', 'bdfg-woo-custom-options'), 'template' => 'time-picker.php', 'assets' => array( 'css' => array('jquery-ui-timepicker'), 'js' => array('jquery-ui-timepicker') ) ), 'color' => array( 'label' => __('Color Picker', 'bdfg-woo-custom-options'), 'template' => 'color-picker.php', 'assets' => array( 'css' => array('wp-color-picker'), 'js' => array('wp-color-picker') ) ), 'file' => array( 'label' => __('File Upload', 'bdfg-woo-custom-options'), 'template' => 'file-upload.php', 'assets' => array( 'js' => array('plupload-all') ), 'settings' => array( 'max_file_size' => '5mb', 'allowed_types' => array('jpg', 'jpeg', 'png', 'pdf') ) ) ); return array_merge($field_types, $advanced_types); } /** * Enqueue conditional logic scripts */ public function enqueue_conditional_logic_scripts() { if (!is_product() || !get_option('bdfg_wco_enable_conditions', 'yes')) { return; } wp_enqueue_script( 'bdfg-conditional-logic', BDFG_WCO_PLUGIN_URL . 'assets/js/conditional-logic.js', array('jquery'), BDFG_WCO_VERSION, true ); $conditions = $this->get_product_conditions(get_the_ID()); wp_localize_script('bdfg-conditional-logic', 'bdfgConditions', array( 'rules' => $conditions, 'i18n' => array( 'loading' => __('Loading...', 'bdfg-woo-custom-options') ) )); } /** * Get conditional logic rules for a product */ private function get_product_conditions($product_id) { global $wpdb; $conditions = wp_cache_get('bdfg_conditions_' . $product_id); if ($conditions === false) { $conditions = $wpdb->get_results($wpdb->prepare( "SELECT * FROM {$wpdb->prefix}bdfg_field_conditions WHERE field_id IN ( SELECT id FROM {$wpdb->prefix}bdfg_custom_fields WHERE product_id = %d )", $product_id ), ARRAY_A); wp_cache_set('bdfg_conditions_' . $product_id, $conditions, '', 3600); } return $conditions; } /** * Add conditional logic data to field */ public function add_conditional_logic_data($field_data) { if (!get_option('bdfg_wco_enable_conditions', 'yes')) { return $field_data; } $conditions = $this->get_field_conditions($field_data['id']); if (!empty($conditions)) { $field_data['conditions'] = array_map(function($condition) { return array( 'depends_on' => $condition['depends_on_field'], 'operator' => $condition['operator'], 'value' => $condition['value'] ); }, $conditions); } return $field_data; } /** * Adjust product price based on selected options */ public function adjust_price_by_options($price, $product) { if (!get_option('bdfg_wco_enable_price_calc', 'yes')) { return $price; } // Only adjust price in cart context if (!is_cart() && !is_checkout()) { return $price; } $cart = WC()->cart; if (!$cart) { return $price; } foreach ($cart->get_cart() as $cart_item) { if ($cart_item['product_id'] !== $product->get_id()) { continue; } if (isset($cart_item['bdfg_custom_fields'])) { foreach ($cart_item['bdfg_custom_fields'] as $field) { if (empty($field['price_adjustment'])) { continue; } $adjustment = $this->calculate_price_adjustment( $field['price_adjustment'], $field['price_type'], $price ); $price += $adjustment; } } } return $price; } /** * Calculate price adjustment */ private function calculate_price_adjustment($amount, $type, $base_price) { switch ($type) { case 'fixed': return floatval($amount); case 'percentage': return $base_price * (floatval($amount) / 100); default: return 0; } } }
includes/class-bdfg-admin.php
<?php /** * BDFG Admin Handler * * Handles all admin-related functionality * * @package BDFG_Woo_Custom_Options * @since 2.0.0 * @author beiduofengou */ if (!defined('ABSPATH')) { exit; } class BDFG_Admin { /** * Instance of this class * @var BDFG_Admin */ private static $instance = null; /** * Initialize the class */ public static function init() { if (self::$instance === null) { self::$instance = new self(); } return self::$instance; } /** * Constructor */ private function __construct() { // Add admin menu add_action('admin_menu', array($this, 'add_admin_menu')); // Add settings page add_filter('woocommerce_get_settings_pages', array($this, 'add_settings_page')); // Add product data tab add_filter('woocommerce_product_data_tabs', array($this, 'add_product_data_tab')); add_action('woocommerce_product_data_panels', array($this, 'add_product_data_panel')); // Save product data add_action('woocommerce_process_product_meta', array($this, 'save_product_fields')); // Add admin assets add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets')); } /** * Add admin menu item */ public function add_admin_menu() { add_submenu_page( 'woocommerce', __('Custom Options', 'bdfg-woo-custom-options'), __('Custom Options', 'bdfg-woo-custom-options'), 'manage_woocommerce', 'bdfg-custom-options', array($this, 'render_admin_page') ); } /** * Render admin page */ public function render_admin_page() { // Check permissions if (!current_user_can('manage_woocommerce')) { wp_die(__('You do not have sufficient permissions to access this page.')); } // Handle form submissions if (isset($_POST['bdfg_save_settings'])) { check_admin_referer('bdfg_admin_settings'); $this->save_admin_settings(); } // Get current settings $settings = $this->get_plugin_settings(); // Load admin template include BDFG_WCO_PLUGIN_DIR . 'templates/admin/settings-page.php'; } /** * Get plugin settings */ private function get_plugin_settings() { return array( 'enable_custom_fields' => get_option('bdfg_wco_enable_custom_fields', 'yes'), 'field_position' => get_option('bdfg_wco_field_position', 'woocommerce_before_add_to_cart_button'), 'display_in_emails' => get_option('bdfg_wco_display_in_emails', 'yes'), 'display_in_orders' => get_option('bdfg_wco_display_in_orders', 'yes'), 'enable_price_calc' => get_option('bdfg_wco_enable_price_calc', 'yes'), 'enable_conditions' => get_option('bdfg_wco_enable_conditions', 'yes'), 'file_upload_path' => get_option('bdfg_wco_file_upload_path', 'bdfg-uploads') ); } /** * Save admin settings */ private function save_admin_settings() { $settings = array( 'enable_custom_fields' => isset($_POST['enable_custom_fields']) ? 'yes' : 'no', 'field_position' => sanitize_text_field($_POST['field_position']), 'display_in_emails' => isset($_POST['display_in_emails']) ? 'yes' : 'no', 'display_in_orders' => isset($_POST['display_in_orders']) ? 'yes' : 'no', 'enable_price_calc' => isset($_POST['enable_price_calc']) ? 'yes' : 'no', 'enable_conditions' => isset($_POST['enable_conditions']) ? 'yes' : 'no', 'file_upload_path' => sanitize_text_field($_POST['file_upload_path']) ); foreach ($settings as $key => $value) { update_option('bdfg_wco_' . $key, $value); } WC_Admin_Settings::add_message(__('Settings saved successfully.', 'bdfg-woo-custom-options')); } /** * Add product data tab */ public function add_product_data_tab($tabs) { $tabs['bdfg_custom_options'] = array( 'label' => __('Custom Options', 'bdfg-woo-custom-options'), 'target' => 'bdfg_custom_options_data', 'class' => array('show_if_simple', 'show_if_variable'), 'priority' => 85 ); return $tabs; } /** * Add product data panel */ public function add_product_data_panel() { global $post; // Get existing custom fields for this product $custom_fields = $this->get_product_custom_fields($post->ID); // Get available field types $field_types = apply_filters('bdfg_wco_field_types', array( 'text' => __('Text Field', 'bdfg-woo-custom-options'), 'textarea' => __('Text Area', 'bdfg-woo-custom-options'), 'select' => __('Dropdown', 'bdfg-woo-custom-options'), 'radio' => __('Radio Buttons', 'bdfg-woo-custom-options'), 'checkbox' => __('Checkbox', 'bdfg-woo-custom-options'), 'date' => __('Date Picker', 'bdfg-woo-custom-options'), 'color' => __('Color Picker', 'bdfg-woo-custom-options'), 'file' => __('File Upload', 'bdfg-woo-custom-options') )); include BDFG_WCO_PLUGIN_DIR . 'templates/admin/product-panel.php'; } /** * Get custom fields for a product */ private function get_product_custom_fields($product_id) { global $wpdb; return $wpdb->get_results($wpdb->prepare( "SELECT * FROM {$wpdb->prefix}bdfg_custom_fields WHERE product_id = %d ORDER BY sort_order ASC", $product_id ), ARRAY_A); } /** * Save product custom fields */ public function save_product_fields($product_id) { if (!isset($_POST['bdfg_custom_fields_nonce']) || !wp_verify_nonce($_POST['bdfg_custom_fields_nonce'], 'bdfg_custom_fields')) { return; } global $wpdb; // Delete existing fields $wpdb->delete( $wpdb->prefix . 'bdfg_custom_fields', array('product_id' => $product_id), array('%d') ); // Add new fields if (isset($_POST['bdfg_field']) && is_array($_POST['bdfg_field'])) { foreach ($_POST['bdfg_field'] as $index => $field) { $wpdb->insert( $wpdb->prefix . 'bdfg_custom_fields', array( 'product_id' => $product_id, 'field_name' => sanitize_text_field($field['name']), 'field_type' => sanitize_text_field($field['type']), 'field_label' => sanitize_text_field($field['label']), 'field_options' => isset($field['options']) ? $this->sanitize_field_options($field['options']) : '', 'required' => isset($field['required']) ? 1 : 0, 'price_adjustment' => isset($field['price_adjustment']) ? floatval($field['price_adjustment']) : 0, 'price_type' => isset($field['price_type']) ? sanitize_text_field($field['price_type']) : 'fixed', 'sort_order' => intval($index) ), array( '%d', '%s', '%s', '%s', '%s', '%d', '%f', '%s', '%d' ) ); } } // Clear cache wp_cache_delete('bdfg_custom_fields_' . $product_id); do_action('bdfg_wco_after_save_product_fields', $product_id); } /** * Sanitize field options */ private function sanitize_field_options($options) { if (is_string($options)) { $options = explode("\n", $options); } $options = array_map('trim', $options); $options = array_filter($options); $options = array_map('sanitize_text_field', $options); return serialize($options); } /** * Enqueue admin assets */ public function enqueue_admin_assets($hook) { $screen = get_current_screen(); // Only load on product edit page or plugin settings page if ($hook === 'post.php' && $screen->post_type === 'product' || $hook === 'woocommerce_page_bdfg-custom-options') { // Styles wp_enqueue_style( 'bdfg-admin-style', BDFG_WCO_PLUGIN_URL . 'assets/css/admin.css', array(), BDFG_WCO_VERSION ); // Scripts wp_enqueue_script( 'bdfg-admin-script', BDFG_WCO_PLUGIN_URL . 'assets/js/admin.js', array('jquery', 'jquery-ui-sortable', 'wp-color-picker'), BDFG_WCO_VERSION, true ); // Localize script wp_localize_script('bdfg-admin-script', 'bdfgAdmin', array( 'ajaxurl' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('bdfg_admin_nonce'), 'i18n' => array( 'confirmDelete' => __('Are you sure you want to delete this field?', 'bdfg-woo-custom-options'), 'addField' => __('Add Field', 'bdfg-woo-custom-options'), 'fieldLabel' => __('Field Label', 'bdfg-woo-custom-options'), 'required' => __('Required', 'bdfg-woo-custom-options'), 'priceAdjustment' => __('Price Adjustment', 'bdfg-woo-custom-options'), 'options' => __('Options (one per line)', 'bdfg-woo-custom-options') ) )); } } }
assets/js/frontend.js
相关文章: WordPress 地图定位插件
/** * BDFG WooCommerce Custom Options - Frontend Scripts * * @author beiduofengou * @since 2.0.0 */ (function($) { 'use strict'; var BDFG_Frontend = { /** * Initialize frontend functionality */ init: function() { this.initializeFields(); this.bindEvents(); this.initializeConditions(); }, /** * Initialize custom fields */ initializeFields: function() { // Initialize date pickers $('.bdfg-date-field').datepicker({ dateFormat: 'yy-mm-dd', minDate: 0 }); // Initialize color pickers $('.bdfg-color-field').wpColorPicker(); // Initialize file uploads this.initializeFileUploads(); }, /** * Initialize file upload fields */ initializeFileUploads: function() { $('.bdfg-file-field').each(function() { var $field = $(this); var $button = $field.find('.upload-button'); var $preview = $field.find('.file-preview'); var $input = $field.find('input[type="hidden"]'); var uploader = new plupload.Uploader({ runtimes: 'html5,flash,silverlight,html4', browse_button: $button[0], url: bdfgWco.ajaxUrl, filters: { max_file_size: '5mb', mime_types: [ {title: "Image files", extensions: "jpg,jpeg,png"}, {title: "PDF files", extensions: "pdf"} ] }, multipart_params: { action: 'bdfg_upload_file', nonce: bdfgWco.nonce } }); uploader.init(); uploader.bind('FilesAdded', function(up, files) { uploader.start(); $button.prop('disabled', true); }); uploader.bind('FileUploaded', function(up, file, response) { var result = JSON.parse(response.response); if (result.success) { $input.val(result.data.url); $preview.html(result.data.html); } $button.prop('disabled', false); }); uploader.bind('Error', function(up, err) { alert(err.message); $button.prop('disabled', false); }); }); }, /** * Bind events */ bindEvents: function() { var self = this; // Update price when custom fields change $(document).on('change', '.bdfg-custom-field', function() { self.updatePrice(); }); // Validate required fields before add to cart $('form.cart').on('submit', function(e) { if (!self.validateFields()) { e.preventDefault(); return false; } }); }, /** * Initialize conditional logic */ initializeConditions: function() { if (typeof bdfgConditions === 'undefined') { return; } var self = this; $('.bdfg-custom-field').on('change', function() { self.evaluateConditions(); }); // Initial evaluation this.evaluateConditions(); }, /** * Evaluate conditional logic rules */ evaluateConditions: function() { var self = this; $.each(bdfgConditions.rules, function(index, rule) { var $targetField = $('#bdfg_custom_' + rule.field_id).closest('.bdfg-field-wrapper'); var $dependentField = $('#bdfg_custom_' + rule.depends_on); var value = $dependentField.val(); var show = self.evaluateCondition(value, rule.operator, rule.value); if (show) { $targetField.slideDown(); } else { $targetField.slideUp(); } }); }, /** * Evaluate a single condition */ evaluateCondition: function(fieldValue, operator, targetValue) { switch (operator) { case 'equals': return fieldValue === targetValue; case 'not_equals': return fieldValue !== targetValue; case 'contains': return fieldValue.indexOf(targetValue) !== -1; case 'not_contains': return fieldValue.indexOf(targetValue) === -1; case 'greater_than': return parseFloat(fieldValue) > parseFloat(targetValue); case 'less_than': return parseFloat(fieldValue) < parseFloat(targetValue); default: return true; } }, /** * Validate required fields */ validateFields: function() { var valid = true; $('.bdfg-custom-field[required]').each(function() { var $field = $(this); var value = $field.val(); if (!value) { valid = false; $field.addClass('error'); var $wrapper = $field.closest('.bdfg-field-wrapper'); var label = $wrapper.find('label').text(); alert('"' + label + '" ' + bdfgWco.i18n.required); } else { $field.removeClass('error'); } }); return valid; }, /** * Update product price based on selected options */ updatePrice: function() { var $form = $('form.cart'); var data = { action: 'bdfg_calculate_price', product_id: $form.find('input[name="product_id"]').val(), fields: {} }; $('.bdfg-custom-field').each(function() { var $field = $(this); data.fields[$field.attr('name')] = $field.val(); }); $.post(bdfgWco.ajaxUrl, data, function(response) { if (response.success) { $('.product-price .amount').html(response.data.formatted_price); } }); } }; // Initialize on document ready $(document).ready(function() { BDFG_Frontend.init(); }); })(jQuery);
assets/css/frontend.css
/** * BDFG WooCommerce Custom Options - Frontend Styles * @author beiduofengou * @since 2.0.0 */ .bdfg-custom-fields { margin: 20px 0; padding: 15px; border: 1px solid #e5e5e5; border-radius: 4px; background: #fff; } .bdfg-custom-fields h3 { margin: 0 0 15px; padding: 0 0 10px; border-bottom: 1px solid #e5e5e5; font-size: 16px; font-weight: 600; } .bdfg-field-wrapper { margin-bottom: 15px; padding-bottom: 15px; border-bottom: 1px solid #f5f5f5; } .bdfg-field-wrapper:last-child { margin-bottom: 0; padding-bottom: 0; border-bottom: none; } .bdfg-field-wrapper label { display: block; margin-bottom: 5px; font-weight: 600; } .bdfg-field-wrapper label .required { color: #e2401c; } .bdfg-custom-field { width: 100%; padding: 8px 12px; border: 1px solid #ddd; border-radius: 4px; background: #fff; box-shadow: inset 0 1px 2px rgba(0,0,0,.07); } .bdfg-custom-field:focus { border-color: #007cba; box-shadow: 0 0 0 1px #007cba; outline: none; } .bdfg-custom-field.error { border-color: #e2401c; } /* File Upload Field */ .bdfg-file-field { position: relative; } .bdfg-file-field .upload-button { display: inline-block; padding: 8px 15px; border: 1px solid #007cba; border-radius: 4px; background: #007cba; color: #fff; cursor: pointer; transition: all 0.2s ease; } .bdfg-file-field .upload-button:hover { background: #0070a7; } .bdfg-file-field .file-preview { margin-top: 10px; } .bdfg-file-field .file-preview img { max-width: 150px; height: auto; border: 1px solid #ddd; border-radius: 4px; } /* Color Picker Field */ .bdfg-color-field { width: auto !important; } .bdfg-color-preview { display: inline-block; width: 20px; height: 20px; margin-right: 5px; border: 1px solid #ddd; border-radius: 2px; vertical-align: middle; } /* Date Picker Field */ .bdfg-date-field { width: auto !important; } .ui-datepicker { padding: 10px; border: 1px solid #ddd; border-radius: 4px; background: #fff; box-shadow: 0 2px 5px rgba(0,0,0,.1); } /* Radio and Checkbox Fields */ .bdfg-radio-wrapper, .bdfg-checkbox-wrapper { margin: 5px 0; } .bdfg-radio-wrapper label, .bdfg-checkbox-wrapper label { display: inline-block; margin: 0 0 0 5px; font-weight: normal; } /* Price Adjustments */ .bdfg-price-note { margin-top: 5px; font-size: 0.9em; color: #666; } /* Loading State */ .bdfg-loading { opacity: 0.5; pointer-events: none; } .bdfg-loading::after { content: ""; position: absolute; top: 50%; left: 50%; width: 20px; height: 20px; margin: -10px 0 0 -10px; border: 2px solid #007cba; border-top-color: transparent; border-radius: 50%; animation: bdfg-spin 1s linear infinite; } @keyframes bdfg-spin { to { transform: rotate(360deg); } }
assets/css/admin.css
相关文章: WooCommerce 自定义”加入购物车”按钮
/** * BDFG WooCommerce Custom Options - Admin Styles * @author beiduofengou * @since 2.0.0 */ .bdfg-admin-wrapper { margin: 20px 0; } .bdfg-admin-header { margin-bottom: 20px; padding: 20px; background: #fff; border: 1px solid #ccd0d4; box-shadow: 0 1px 1px rgba(0,0,0,.04); } .bdfg-admin-header h1 { margin: 0; color: #23282d; font-size: 23px; font-weight: 400; } .bdfg-admin-content { margin-top: 20px; } /* Field Management */ .bdfg-fields-wrapper { margin: 15px 0; padding: 15px; background: #fff; border: 1px solid #ccd0d4; } .bdfg-field-item { position: relative; margin-bottom: 15px; padding: 15px; background: #f9f9f9; border: 1px solid #e5e5e5; } .bdfg-field-header { cursor: move; padding: 10px; background: #f1f1f1; border: 1px solid #e5e5e5; } .bdfg-field-header h4 { margin: 0; float: left; } .bdfg-field-actions { float: right; } .bdfg-field-actions a { margin-left: 10px; text-decoration: none; color: #0073aa; } .bdfg-field-content { padding: 15px 0; } .bdfg-field-row { margin-bottom: 15px; } .bdfg-field-row label { display: block; margin-bottom: 5px; font-weight: 600; } .bdfg-field-row input[type="text"], .bdfg-field-row textarea, .bdfg-field-row select { width: 100%; } .bdfg-field-options { margin-top: 15px; } .bdfg-field-options textarea { min-height: 100px; } /* Settings Page */ .bdfg-settings-form { max-width: 800px; } .form-table th { padding: 20px 10px 20px 0; width: 200px; } .form-table td { padding: 15px 10px; } .bdfg-settings-section { margin: 20px 0; padding: 20px; background: #fff; border: 1px solid #ccd0d4; } .bdfg-settings-section h2 { margin: 0 0 15px; padding: 0 0 15px; border-bottom: 1px solid #eee; } /* Help Tips */ .bdfg-help-tip { color: #666; display: inline-block; font-size: 1.1em; font-style: normal; height: 16px; line-height: 16px; margin: -4px 0 0 4px; padding: 0; position: relative; vertical-align: middle; width: 16px; } .bdfg-help-tip::after { content: "?"; font-family: Dashicons; font-weight: 400; text-align: center; } /* Price Adjustment Fields */ .bdfg-price-adjustment { display: flex; align-items: center; gap: 10px; } .bdfg-price-adjustment input { width: 100px !important; } .bdfg-price-type { width: 150px !important; } /* Conditional Logic UI */ .bdfg-conditions-wrapper { margin-top: 15px; padding: 15px; background: #f9f9f9; border: 1px solid #e5e5e5; } .bdfg-condition-row { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; } .bdfg-condition-row select { width: 200px; } .bdfg-condition-row input { width: 200px; } /* Responsive Tweaks */ @media screen and (max-width: 782px) { .form-table th { width: auto; } .bdfg-price-adjustment { flex-direction: column; align-items: flex-start; } .bdfg-condition-row { flex-direction: column; align-items: flex-start; } .bdfg-condition-row select, .bdfg-condition-row input { width: 100%; } }
templates/admin/product-panel.php
<?php /** * Admin product custom options panel * * @package BDFG_Woo_Custom_Options * @since 2.0.0 */ defined('ABSPATH') || exit; ?> <div id="bdfg_custom_options_data" class="panel woocommerce_options_panel"> <div class="bdfg-fields-wrapper"> <p class="toolbar"> <button type="button" class="button bdfg-add-field"> <?php _e('Add Custom Field', 'bdfg-woo-custom-options'); ?> </button> </p> <div class="bdfg-fields-container"> <?php if (!empty($custom_fields)) { foreach ($custom_fields as $index => $field) { include 'parts/field-row.php'; } } ?> </div> </div> <?php wp_nonce_field('bdfg_custom_fields', 'bdfg_custom_fields_nonce'); ?> </div> <!-- Field Template --> <script type="text/template" id="tmpl-bdfg-field-row"> <?php $field = array( 'id' => '{{data.id}}', 'name' => '', 'type' => 'text', 'label' => '', 'required' => false, 'options' => '', 'price_adjustment' => '', 'price_type' => 'fixed' ); include 'parts/field-row.php'; ?> </script>
templates/admin/parts/field-row.php
<div class="bdfg-field-item" data-field-id="<?php echo esc_attr($field['id']); ?>"> <div class="bdfg-field-header"> <h4><?php echo !empty($field['label']) ? esc_html($field['label']) : __('New Field', 'bdfg-woo-custom-options'); ?></h4> <div class="bdfg-field-actions"> <a href="#" class="bdfg-toggle-field"> <span class="dashicons dashicons-arrow-down"></span> </a> <a href="#" class="bdfg-remove-field"> <span class="dashicons dashicons-trash"></span> </a> </div> <div class="clear"></div> </div> <div class="bdfg-field-content"> <div class="bdfg-field-row"> <label><?php _e('Field Label', 'bdfg-woo-custom-options'); ?></label> <input type="text" name="bdfg_field[<?php echo esc_attr($field['id']); ?>][label]" value="<?php echo esc_attr($field['label']); ?>" class="widefat"> </div> <div class="bdfg-field-row"> <label><?php _e('Field Type', 'bdfg-woo-custom-options'); ?></label> <select name="bdfg_field[<?php echo esc_attr($field['id']); ?>][type]" class="bdfg-field-type"> <?php foreach ($field_types as $type => $label) : ?> <option value="<?php echo esc_attr($type); ?>" <?php selected($field['type'], $type); ?>> <?php echo esc_html($label); ?> </option> <?php endforeach; ?> </select> </div> <div class="bdfg-field-row"> <label> <input type="checkbox" name="bdfg_field[<?php echo esc_attr($field['id']); ?>][required]" value="1" <?php checked(!empty($field['required'])); ?>> <?php _e('Required Field', 'bdfg-woo-custom-options'); ?> </label> </div> <div class="bdfg-field-row bdfg-field-options" style="<?php echo in_array($field['type'], array('select', 'radio', 'checkbox')) ? '' : 'display:none;'; ?>"> <label><?php _e('Options (one per line)', 'bdfg-woo-custom-options'); ?></label> <textarea name="bdfg_field[<?php echo esc_attr($field['id']); ?>][options]" class="widefat"><?php echo esc_textarea($field['options']); ?></textarea> </div> <div class="bdfg-field-row"> <label><?php _e('Price Adjustment', 'bdfg-woo-custom-options'); ?></label> <div class="bdfg-price-adjustment"> <input type="number" name="bdfg_field[<?php echo esc_attr($field['id']); ?>][price_adjustment]" value="<?php echo esc_attr($field['price_adjustment']); ?>" step="0.01"> <select name="bdfg_field[<?php echo esc_attr($field['id']); ?>][price_type]" class="bdfg-price-type"> <option value="fixed" <?php selected($field['price_type'], 'fixed'); ?>> <?php _e('Fixed Amount', 'bdfg-woo-custom-options'); ?> </option> <option value="percentage" <?php selected($field['price_type'], 'percentage'); ?>> <?php _e('Percentage', 'bdfg-woo-custom-options'); ?> </option> </select> </div> </div> <div class="bdfg-field-row"> <label><?php _e('Conditional Logic', 'bdfg-woo-custom-options'); ?></label> <div class="bdfg-conditions-wrapper"> <label> <input type="checkbox" class="bdfg-enable-conditions" name="bdfg_field[<?php echo esc_attr($field['id']); ?>][enable_conditions]" value="1" <?php checked(!empty($field['enable_conditions'])); ?>> <?php _e('Enable Conditional Logic', 'bdfg-woo-custom-options'); ?> </label> <div class="bdfg-conditions-content" style="<?php echo !empty($field['enable_conditions']) ? '' : 'display:none;'; ?>"> <div class="bdfg-condition-row"> <select name="bdfg_field[<?php echo esc_attr($field['id']); ?>][condition_field]" class="bdfg-condition-field"> <option value=""><?php _e('Select Field', 'bdfg-woo-custom-options'); ?></option> <?php foreach ($custom_fields as $other_field) : if ($other_field['id'] !== $field['id']) : ?> <option value="<?php echo esc_attr($other_field['id']); ?>" <?php selected($field['condition_field'], $other_field['id']); ?>> <?php echo esc_html($other_field['label']); ?> </option> <?php endif; endforeach; ?> </select> <select name="bdfg_field[<?php echo esc_attr($field['id']); ?>][condition_operator]" class="bdfg-condition-operator"> <option value="equals" <?php selected($field['condition_operator'], 'equals'); ?>> <?php _e('Equals', 'bdfg-woo-custom-options'); ?> </option> <option value="not_equals" <?php selected($field['condition_operator'], 'not_equals'); ?>> <?php _e('Not Equals', 'bdfg-woo-custom-options'); ?> </option> <option value="contains" <?php selected($field['condition_operator'], 'contains'); ?>> <?php _e('Contains', 'bdfg-woo-custom-options'); ?> </option> <option value="not_contains" <?php selected($field['condition_operator'], 'not_contains'); ?>> <?php _e('Does Not Contain', 'bdfg-woo-custom-options'); ?> </option> </select> <input type="text" name="bdfg_field[<?php echo esc_attr($field['id']); ?>][condition_value]" value="<?php echo esc_attr($field['condition_value']); ?>" placeholder="<?php esc_attr_e('Value', 'bdfg-woo-custom-options'); ?>"> </div> </div> </div> </div> </div> </div>
templates/admin/settings-page.php
<?php /** * Admin settings page template * * @package BDFG_Woo_Custom_Options * @since 2.0.0 */ defined('ABSPATH') || exit; ?> <div class="wrap bdfg-admin-wrapper"> <div class="bdfg-admin-header"> <h1><?php _e('BDFG WooCommerce Custom Options Settings', 'bdfg-woo-custom-options'); ?></h1> </div> <div class="bdfg-admin-content"> <form method="post" action="" class="bdfg-settings-form"> <?php wp_nonce_field('bdfg_admin_settings'); ?> <div class="bdfg-settings-section"> <h2><?php _e('General Settings', 'bdfg-woo-custom-options'); ?></h2> <table class="form-table"> <tr> <th scope="row"> <label for="enable_custom_fields"> <?php _e('Enable Custom Fields', 'bdfg-woo-custom-options'); ?> </label> </th> <td> <label> <input type="checkbox" id="enable_custom_fields" name="enable_custom_fields" value="1" <?php checked($settings['enable_custom_fields'], 'yes'); ?>> <?php _e('Enable custom fields functionality', 'bdfg-woo-custom-options'); ?> </label> </td> </tr> <tr> <th scope="row"> <label for="field_position"> <?php _e('Field Position', 'bdfg-woo-custom-options'); ?> </label> </th> <td> <select id="field_position" name="field_position"> <option value="woocommerce_before_add_to_cart_button" <?php selected($settings['field_position'], 'woocommerce_before_add_to_cart_button'); ?>> <?php _e('Before Add to Cart Button', 'bdfg-woo-custom-options'); ?> </option> <option value="woocommerce_after_add_to_cart_button" <?php selected($settings['field_position'], 'woocommerce_after_add_to_cart_button'); ?>> <?php _e('After Add to Cart Button', 'bdfg-woo-custom-options'); ?> </option> <option value="woocommerce_before_add_to_cart_form" <?php selected($settings['field_position'], 'woocommerce_before_add_to_cart_form'); ?>> <?php _e('Before Add to Cart Form', 'bdfg-woo-custom-options'); ?> </option> <option value="woocommerce_after_add_to_cart_form" <?php selected($settings['field_position'], 'woocommerce_after_add_to_cart_form'); ?>> <?php _e('After Add to Cart Form', 'bdfg-woo-custom-options'); ?> </option> </select> </td> </tr> </table> </div> <div class="bdfg-settings-section"> <h2><?php _e('Display Settings', 'bdfg-woo-custom-options'); ?></h2> <table class="form-table"> <tr> <th scope="row"> <label for="display_in_emails"> <?php _e('Display in Emails', 'bdfg-woo-custom-options'); ?> </label> </th> <td> <label> <input type="checkbox" id="display_in_emails" name="display_in_emails" value="1" <?php checked($settings['display_in_emails'], 'yes'); ?>> <?php _e('Show custom fields in order emails', 'bdfg-woo-custom-options'); ?> </label> </td> </tr> <tr> <th scope="row"> <label for="display_in_orders"> <?php _e('Display in Orders', 'bdfg-woo-custom-options'); ?> </label> </th> <td> <label> <input type="checkbox" id="display_in_orders" name="display_in_orders" value="1" <?php checked($settings['display_in_orders'], 'yes'); ?>> <?php _e('Show custom fields in order details', 'bdfg-woo-custom-options'); ?> </label> </td> </tr> </table> </div> <div class="bdfg-settings-section"> <h2><?php _e('Advanced Settings', 'bdfg-woo-custom-options'); ?></h2> <table class="form-table"> <tr> <th scope="row"> <label for="enable_price_calc"> <?php _e('Price Calculations', 'bdfg-woo-custom-options'); ?> </label> </th> <td> <label> <input type="checkbox" id="enable_price_calc" name="enable_price_calc" value="1" <?php checked($settings['enable_price_calc'], 'yes'); ?>> <?php _e('Enable price adjustments based on custom fields', 'bdfg-woo-custom-options'); ?> </label> </td> </tr> <tr> <th scope="row"> <label for="enable_conditions"> <?php _e('Conditional Logic', 'bdfg-woo-custom-options'); ?> </label> </th> <td> <label> <input type="checkbox" id="enable_conditions" name="enable_conditions" value="1" <?php checked($settings['enable_conditions'], 'yes'); ?>> <?php _e('Enable conditional logic for custom fields', 'bdfg-woo-custom-options'); ?> </label> </td> </tr> <tr> <th scope="row"> <label for="file_upload_path"> <?php _e('File Upload Path', 'bdfg-woo-custom-options'); ?> </label> </th> <td> <input type="text" id="file_upload_path" name="file_upload_path" value="<?php echo esc_attr($settings['file_upload_path']); ?>" class="regular-text"> <p class="description"> <?php _e('Path relative to WordPress uploads directory where files will be stored.', 'bdfg-woo-custom-options'); ?> </p> </td> </tr> </table> </div> <p class="submit"> <input type="submit" name="bdfg_save_settings" class="button button-primary" value="<?php esc_attr_e('Save Changes', 'bdfg-woo-custom-options'); ?>"> </p> </form> </div> </div>
templates/fields/text.php
<?php /** * Text field template * * @package BDFG_Woo_Custom_Options */ defined('ABSPATH') || exit; ?> <div class="bdfg-field-wrapper bdfg-text-field-wrapper"> <label for="<?php echo esc_attr($field_data['id']); ?>"> <?php echo esc_html($field_data['label']); ?> <?php if ($field_data['required']) : ?> <span class="required">*</span> <?php endif; ?> </label> <input type="text" id="<?php echo esc_attr($field_data['id']); ?>" name="<?php echo esc_attr($field_data['name']); ?>" class="bdfg-custom-field bdfg-text-field" <?php echo $field_data['required'] ? 'required' : ''; ?>> <?php if ($field_data['price_adjustment'] > 0) : ?> <p class="bdfg-price-note"> <?php if ($field_data['price_type'] === 'fixed') : ?> <?php printf( __('Price adjustment: +%s', 'bdfg-woo-custom-options'), wc_price($field_data['price_adjustment']) ); ?> <?php else : ?> <?php printf( __('Price adjustment: +%s%%', 'bdfg-woo-custom-options'), number_format($field_data['price_adjustment'], 2) ); ?> <?php endif; ?> </p> <?php endif; ?> </div>
templates/fields/textarea.php
<?php /** * Textarea field template * * @package BDFG_Woo_Custom_Options * @author beiduofengou * @version 2.2.1 * @since 2.0.0 * @last-modified 2024-08-15 */ defined('ABSPATH') || exit; $placeholder = !empty($field_data['placeholder']) ? $field_data['placeholder'] : ''; $maxlength = !empty($field_data['maxlength']) ? (int) $field_data['maxlength'] : ''; $rows = !empty($field_data['rows']) ? (int) $field_data['rows'] : 4; ?> <div class="bdfg-field-wrapper bdfg-textarea-wrapper"> <label class="bdfg-field-label" for="<?php echo esc_attr($field_data['id']); ?>"> <?php echo esc_html($field_data['label']); ?> <?php if ($field_data['required']) : ?> <span class="required">*</span> <?php endif; ?> </label> <div class="bdfg-textarea-container"> <textarea id="<?php echo esc_attr($field_data['id']); ?>" name="<?php echo esc_attr($field_data['name']); ?>" class="bdfg-textarea-field bdfg-custom-field" rows="<?php echo esc_attr($rows); ?>" <?php echo $maxlength ? 'maxlength="' . esc_attr($maxlength) . '"' : ''; ?> <?php echo $placeholder ? 'placeholder="' . esc_attr($placeholder) . '"' : ''; ?> <?php echo $field_data['required'] ? 'required' : ''; ?> ></textarea> <?php if ($maxlength) : ?> <div class="bdfg-character-count"> <span class="bdfg-current-count">0</span> <span class="bdfg-max-count">/<?php echo esc_html($maxlength); ?></span> </div> <?php endif; ?> </div> <?php if (!empty($field_data['description'])) : ?> <p class="bdfg-field-description"> <?php echo wp_kses_post($field_data['description']); ?> </p> <?php endif; ?> <?php if (!empty($field_data['price_adjustment'])) : ?> <div class="bdfg-price-adjustment <?php echo $field_data['price_adjustment'] >= 0 ? 'bdfg-price-positive' : 'bdfg-price-negative'; ?>"> <?php if ($field_data['price_type'] === 'fixed') : ?> <?php printf( esc_html__('Price adjustment: %s%s', 'bdfg-woo-custom-options'), $field_data['price_adjustment'] >= 0 ? '+' : '', wc_price($field_data['price_adjustment']) ); ?> <?php else : ?> <?php printf( esc_html__('Price adjustment: %s%s%%', 'bdfg-woo-custom-options'), $field_data['price_adjustment'] >= 0 ? '+' : '', number_format($field_data['price_adjustment'], 2) ); ?> <?php endif; ?> </div> <?php endif; ?> <div class="bdfg-error-message" style="display: none;"></div> </div> <?php if ($maxlength) : ?> <script type="text/javascript"> jQuery(document).ready(function($) { var $textarea = $('#<?php echo esc_js($field_data['id']); ?>'); var $counter = $textarea.closest('.bdfg-textarea-wrapper').find('.bdfg-current-count'); $textarea.on('input', function() { var count = $(this).val().length; $counter.text(count); if (count >= <?php echo esc_js($maxlength); ?>) { $counter.addClass('bdfg-count-limit'); } else { $counter.removeClass('bdfg-count-limit'); } }); }); </script> <?php endif; ?>