WooCommerce自定义产品属性价格开发


本篇文章主要介绍WooCommerce实现如下图的功能,让用户选择自定义属性,并且更新原产品价格。

主要代码如下:

① 添加js、css文件

add_action('wp_enqueue_scripts', function () {
    if (is_product()) {
        wp_enqueue_script('custom-attribute-js', plugins_url('/js/custom-attribute.js', __FILE__), array('jquery'), '0.0.1', true);
    }
    wp_register_style('custom-attribute-css', plugin_dir_url(__FILE__) . 'css/custom-attribute.css', false, '0.0.1');
    wp_enqueue_style('custom-attribute-css');
});

custom-attribute.css代码

.woocommerce div.product div.images .flex-control-thumbs img {
    max-height: 128px;
}

.wc-block-components-product-image img {
    max-height: 240px;
}

.custom-attribute-size-field, .custom-attribute-customized-field {
    margin-bottom: 20px;
}

.custom-attribute-size-field label, .custom-attribute-customized-field label {
    font-weight: bolder;
}

.custom-attribute-size-field .custom-attribute-field-ul, .custom-attribute-customized-field .custom-attribute-field-ul {
    list-style: none !important;
    padding: 0 !important;
    margin: 5px 0 !important;
}

.custom-attribute-size-field .custom-attribute-field-li, .custom-attribute-customized-field .custom-attribute-field-li {
    list-style: none !important;
    display: inline-block !important;
    padding: 5px 15px;
    border: 1px solid #E6E6E6;
    border-radius: 2px;
    margin-right: 5px;
    font-size: 14px;
    background-color: #ffffff;
    color: #000000;
    cursor: pointer;
}

.custom-attribute-size-field .custom-attribute-field-li span, .custom-attribute-customized-field .custom-attribute-field-li span {
    color: grey;
}

.custom-attribute-size-field .custom-attribute-field-li.active, .custom-attribute-customized-field .custom-attribute-field-li.active {
    background-color: #000000 !important;
    color: #ffffff !important;
    border: 1px solid #000000 !important;
}

.custom-attribute-size-field .custom-attribute-field-li.active span, .custom-attribute-customized-field .custom-attribute-field-li.active span {
    color: #ffffff !important;
}

.custom-attribute-customized-field .custom-attribute-customized-text {
    width: 100%;
    border: 1px solid #E9E9E9;
    margin-top: 10px;
    outline: none !important;
    padding: 10px;
    box-sizing: border-box;
    display: none;
}

custom-attribute.js代码

jQuery(document).ready(function ($) {
   $('.custom-attribute-size-field-ul .custom-attribute-field-li').click(function (){
      $('.custom-attribute-size-field-ul .custom-attribute-field-li').removeClass('active');
      $(this).addClass('active');
      $('#custom-attribute-size').val($(this).attr('data-value'));
   });

   $('.custom-attribute-customized-field-ul .custom-attribute-field-li').click(function (){
      $('.custom-attribute-customized-field-ul .custom-attribute-field-li').removeClass('active');
      $(this).addClass('active');
      $('#custom-attribute-customized').val($(this).attr('data-value'));
      let type = $(this).attr('data-type');
      if (type == 'customized'){
         $('#custom-attribute-customized-text').show();
      } else {
         $('#custom-attribute-customized-text').hide();
      }
   });
});

② 在产品页添加自定义表单

function ca_woocommerce_before_add_to_cart_button()
{
    $post_id = ca_get_post_id();
    if (empty($post_id)) {
        return;
    }
    $custom_attribute_data = get_custom_attribute_data($post_id);
    if (empty($custom_attribute_data)) {
        return;
    }
    $currency_symbol = get_woocommerce_currency_symbol();
    // 显示尺寸
    if (!empty($custom_attribute_data['size'])) {
        $sizes = json_decode($custom_attribute_data['size'], true);
        if (!empty($sizes)) {
            $first_value = $sizes[0]['name'];
            ?>
            <div class="custom-attribute-size-field">
                <input type="hidden" id="custom-attribute-size" name="custom_attribute_size" value="<?php echo esc_attr($first_value);?>">
                <label><?php _e('Size:', 'custom-attribute'); ?></label>
                <br>
                <ul class="custom-attribute-field-ul custom-attribute-size-field-ul">
                    <?php
                    foreach ($sizes as $k => $size) {
                        ?>
                        <li class="custom-attribute-field-li <?php if ($k == 0){echo 'active';}?>" data-value="<?php echo esc_attr($size['name']); ?>">
                            <?php
                            echo esc_html($size['name']);
                            if (!empty($size['price']) && $size['price'] > 0) {
                                echo '<span>(+ ' . esc_html($currency_symbol) . ' ' . $size['price'] . ')</span>';
                            }
                            ?>
                        </li>
                        <?php
                    }
                    ?>
                </ul>
            </div>
            <?php
        }
    }
    // 显示自定义属性
    if (!empty($custom_attribute_data['customized'])) {
        $customizeds = json_decode($custom_attribute_data['customized'], true);
        if (!empty($customizeds)) {
            $first_value = $customizeds[0]['name'];
            ?>
            <div class="custom-attribute-customized-field">
                <input type="hidden" id="custom-attribute-customized" name="custom_attribute_customized" value="<?php echo esc_attr($first_value);?>">
                <label><?php _e('Customized:', 'custom-attribute'); ?></label>
                <br>
                <ul class="custom-attribute-field-ul custom-attribute-customized-field-ul">
                    <?php
                    foreach ($customizeds as $k => $customized) {
                        $type = '';
                        if (preg_match('/Customized/i', $customized['name'])) {
                            $type = 'customized';
                        }
                        ?>
                        <li class="custom-attribute-field-li <?php if ($k ==0){echo 'active';}?>" data-type="<?php echo esc_attr($type); ?>"
                            data-value="<?php echo esc_attr($customized['name']); ?>">
                            <?php
                            echo esc_html($customized['name']);
                            if (!empty($customized['price']) && $customized['price'] > 0) {
                                echo '<span>(+ ' . esc_html($currency_symbol) . ' ' . $customized['price'] . ')</span>';
                            }
                            ?>
                        </li>
                        <?php
                    }
                    ?>
                </ul>
                <textarea rows="10" class="custom-attribute-customized-text" id="custom-attribute-customized-text"
                          name="custom_attribute_customized_text"></textarea>
            </div>
            <?php
        }
    }
}


add_action('woocommerce_before_add_to_cart_button', 'ca_woocommerce_before_add_to_cart_button', 60);

③ 保存自定义数据到购物车

function ca_woocommerce_add_cart_item_data($cart_item_data, $product_id, $variation_id)
{
    $custom_attribute_size = filter_input(INPUT_POST, 'custom_attribute_size');
    if (!empty($custom_attribute_size)) {
        $cart_item_data['custom_attribute_size'] = $custom_attribute_size;
    }

    $custom_attribute_customized = filter_input(INPUT_POST, 'custom_attribute_customized');
    if (!empty($custom_attribute_customized)) {
        $cart_item_data['custom_attribute_customized'] = $custom_attribute_customized;
        $custom_attribute_customized_text = filter_input(INPUT_POST, 'custom_attribute_customized_text');
        if (!empty($custom_attribute_customized_text)) {
            if (preg_match('/Customized/i', $custom_attribute_customized)) {
                $cart_item_data['custom_attribute_customized_text'] = $custom_attribute_customized_text;
            } else {
                $cart_item_data['custom_attribute_customized_text'] = '';
            }
        }
    }

    return $cart_item_data;
}

add_filter('woocommerce_add_cart_item_data', 'ca_woocommerce_add_cart_item_data', 10, 3);

④ 显示自定义数据

function ca_woocommerce_get_item_data($item_data, $cart_item)
{
    if (!empty($cart_item['custom_attribute_size'])) {
        $item_data[] = array(
            'key' => __('Size', 'custom-attribute'),
            'value' => wc_clean($cart_item['custom_attribute_size']),
            'display' => '',
        );
    }

    if (!empty($cart_item['custom_attribute_customized'])) {
        $item_data[] = array(
            'key' => __('Customized', 'custom-attribute'),
            'value' => wc_clean($cart_item['custom_attribute_customized']),
            'display' => '',
        );
        if (!empty($cart_item['custom_attribute_customized_text'])) {
            $item_data[] = array(
                'key' => __('Customized Name/Number', 'custom-attribute'),
                'value' => wc_clean($cart_item['custom_attribute_customized_text']),
                'display' => '',
            );
        }
    }

    return $item_data;
}

add_filter('woocommerce_get_item_data', 'ca_woocommerce_get_item_data', 10, 2);

⑤ 保存数据到订单

function ca_woocommerce_checkout_create_order_line_item($item, $cart_item_key, $values, $order)
{
    if (!empty($values['custom_attribute_size'])) {
        $item->add_meta_data(__('Size', 'custom-attribute'), $values['custom_attribute_size']);
    }
    if (!empty($values['custom_attribute_customized'])) {
        $item->add_meta_data(__('Customized', 'custom-attribute'), $values['custom_attribute_customized']);
        if (!empty($values['custom_attribute_customized_text'])) {
            $item->add_meta_data(__('Customized Name/Number', 'custom-attribute'), $values['custom_attribute_customized_text']);
        }
    }
}

add_action('woocommerce_checkout_create_order_line_item', 'ca_woocommerce_checkout_create_order_line_item', 10, 4);

⑥ 修改产品价格

function ca_woocommerce_before_calculate_totals($cart_object)
{
    foreach ($cart_object->cart_contents as $key => $value) {
        $post_id = $value['product_id'];
        $custom_attribute_data = get_custom_attribute_data($post_id);
        if (empty($custom_attribute_data)) {
            continue;
        }
        $custom_price = 0;
        if (!empty($custom_attribute_data['size']) && !empty($value['custom_attribute_size'])) {
            $sizes = json_decode($custom_attribute_data['size'], true);
            if (!empty($sizes)) {
                foreach ($sizes as $size) {
                    if (!empty($size['price']) && $size['price'] > 0 && $value['custom_attribute_size'] == $size['name']) {
                        $custom_price = bcadd($custom_price, $size['price'], 2);
                        break;
                    }
                }
            }
        }

        if (!empty($custom_attribute_data['customized']) && !empty($value['custom_attribute_customized'])) {
            $customizeds = json_decode($custom_attribute_data['customized'], true);
            if (!empty($customizeds)) {
                foreach ($customizeds as $customized) {
                    if (!empty($customized['price']) && $customized['price'] > 0 && $value['custom_attribute_customized'] == $customized['name']) {
                        $custom_price = bcadd($custom_price, $customized['price'], 2);
                        break;
                    }
                }
            }
        }
        if ($custom_price > 0) {
            $item_id = $value['data']->id;
            $product = wc_get_product($item_id);
            $price = $product->get_price();
//            $price = $value['data']->get_price();
            $value['data']->set_price(bcadd($price, $custom_price, 2));
        }
    }
}

add_action('woocommerce_before_calculate_totals', 'ca_woocommerce_before_calculate_totals');

以上就是开发自定义属性插件的核心代码,仅供参考。