WooCommerce 自定义选项 插件

增强 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; ?>

Leave a Comment