Woocommerce使用ajax对购物车的总价施加折扣

时间:2020-07-31 08:36:20

标签: ajax wordpress woocommerce cart hook-woocommerce

我的目标:使用AJAX对购物车总价应用10%的折扣。

上下文:此折扣必须仅适用于来自给定网站的特定用户。我的想法是在我在购物车页面中添加的输入字段中获取其会员编号。使用API​​时,我将检查此号码并是否应用折扣(考虑到进一步解释的问题,在此我将不详细介绍此检查部分,而仅关注问题)。

想法:

  1. 创建一个插件,该插件将在购物车页面上添加带有验证按钮的输入字段。
  2. 单击按钮时拨打AJAX呼叫
  3. 如果用户会员编号正确,请应用折扣(由于这不是问题,因此我不会在此进行API检查)

问题:因此,我使用AJAX验证此数字,然后对购物车总价施加10%的折扣。问题是我找不到如何更新总数。

我的JS:

(function($) {
    $("body").on("click", ".updateCart", function(e) {
        e.preventDefault();
        var form = $('#cartAjaxTcs');
        var value = form.serialize();
        $.ajax({
            type:'POST',
            data: {
                action: 'test',
                number: value
            },
            url: ajaxurl,
            success: function(value) {
                jQuery("[name='update_cart']").removeAttr('disabled');
                jQuery("[name='update_cart']").trigger("click");
                console.log(value);
            },
            error:function(){
                console.log('error');
            }
        });
    });
})( jQuery );

我的PHP:


<?php

/*
  Plugin Name: discount Plugin
  Description: Apply 10% discount on cart's price
  Author: Aurélien
  Version: 1.0.0
 */

/**
* Check if WooCommerce is active
**/
if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {

    class Discount_Plugin{

        public static function init() {

            add_action('wp_enqueue_scripts',  __CLASS__ .'::callback_for_setting_up_scripts');

            //Add input field
            add_action('woocommerce_cart_collaterals', __CLASS__.'::order_comments_custom_cart_field');

        }

        public static function callback_for_setting_up_scripts() {
            $path = '/wp-content/plugins/discount-plugin/assets/css/style.css';
            wp_register_style( 'discountStyle', $path );
            wp_enqueue_style( 'discountStyle' );
            wp_enqueue_script( 'ajax-script', plugins_url( 'assets/js/discount-plugin.js', __FILE__ ), array('jquery'), '1.0', true );
            wp_localize_script( 'ajax-script', 'ajaxurl', admin_url( 'admin-ajax.php' ) );
        }

        public static function order_comments_custom_cart_field() {
            ?>
            <form id="cartAjaxTcs" class="discount_input_wrapper" method="post" action="/wp-admin/admin-post.php">
                <div class="discount_form_field">
                    <input type="text" name="number" id="number" placeholder="<?php echo 'My number, ie : 4GG524G42';?>">
                    <label for="number"><?php echo 'Membership number';?></label>
                </div>
                <button class="updateCart" type="submit"><?php echo 'Update cart';?></button>
            </form>
            <?php

        }

 

    Discount_Plugin::init();
    add_action( 'wp_ajax_test', 'test' );
    add_action( 'wp_ajax_nopriv_test', 'test' );

    function test()
    {
      //Solution 1 or solution 2
    }

}

我的第一个解决方案:我试图像这样直接降低总价格。即使在后端购物车的报告中总价格仍然与折扣前的价格相同,它会更改总价格但不显示总价格。

function test()
{
    //This is displayed in console
    echo 'test-init';

    if (!DOING_AJAX){
        return;
    }

    $total = (int) WC()->cart->get_totals()['total']; 
    $total *= 0.9;
    WC()->cart->set_total($total);

    wp_die();
}


我的第二个解决方案: 我试图触发“更新购物车”按钮(已在页面上显示),并使用 woocommerce_before_calculate_totals 挂钩来更新价格,但甚至没有调用它。

很明显,我的AJAX的动作函数内部没有钩子或过滤器。我用一个简单的过滤器进行了测试,该过滤器向人体添加了一个类,它在我的动作函数中不起作用,但在外部却完美。我放了一些标志,以查看我的函数是否被AJAX调用了!

//This works well! If I put the same filter in my 'test' function it doesn't work
add_filter( 'body_class', function( $classes ) {
    return array_merge( $classes, array( 'test-class' ) );
} );

function test()
{
    //This is displayed in console
    echo'test-init';

    if (!DOING_AJAX){
        return;
    }
    
    //This does't work
    add_filter( 'body_class', function( $classes ) {
      return array_merge( $classes, array( 'test-class2' ) );
    } );
    
    //The callback function isn't called
    add_action( 'woocommerce_before_calculate_totals', 'update_price' );

    //This is displayed in console
    echo 'test';

    wp_die();
}

//Not called
function update_price(){
    echo 'update';
}

编辑:

我重新编写了自己的解释,以便通过附加代码使它们更易理解:

以下是一些尝试使用woocommerce_cart_calculate_fees挂钩的负费用尝试:

如果我在 AJAX动作函数之外使用 add_action woocommerce_cart_calculate_fees 钩子的回调函数将非常有效:

add_action( 'wp_ajax_test', 'test' );
add_action( 'wp_ajax_nopriv_test', 'test' );

add_action( 'woocommerce_cart_calculate_fees','woocommerce_custom_surcharge' );
function woocommerce_custom_surcharge() {
    global $woocommerce;

    if ( ( is_admin() && ! defined( 'DOING_AJAX' )))
        return;

    $percentage = 0.1;
    $surcharge = ( $woocommerce->cart->cart_contents_total + $woocommerce->cart->shipping_total ) * $percentage;
    $woocommerce->cart->add_fee( 'discount', -$surcharge, true, '' );

}

function test(){
   
   //My AJAX action function

}

因此,这项工作需要支付negatif费用,但是在加载页面时,这并不是我想要的,因为我想在触发更新购物车按钮时应用负费用,所以这个想法是将 add_action 集成到我的 AJAX动作函数中,如下所示:

add_action( 'wp_ajax_test', 'test' );
add_action( 'wp_ajax_nopriv_test', 'test' );

function woocommerce_custom_surcharge() {
    global $woocommerce;

    if ( ( is_admin() && ! defined( 'DOING_AJAX' )))
        return;

    $percentage = 0.1;
    $surcharge = ( $woocommerce->cart->cart_contents_total + $woocommerce->cart->shipping_total ) * $percentage;
    $woocommerce->cart->add_fee( 'discount', -$surcharge, true, '' );

}

//My AJAX action function
function test(){

   echo 'test1'; //flag 1
   add_action( 'woocommerce_cart_calculate_fees','woocommerce_custom_surcharge' );
   echo 'test2'; //flag 2
}

根本没有调用回调函数 woocommerce_custom_surcharge 。我的两个标志都显示在chrome控制台中,因此这意味着我的动作函数已正确调用。所以我的问题是:如何使这个add_action在我的action函数中起作用?

1 个答案:

答案 0 :(得分:1)

您错过了使用WC Session变量设置某些数据并将其用于折扣函数的用法……下面的第一个函数可处理您的设置,并且已在其他函数的任何地方加载。

// Settings
function get_membership_settings(){
    $discount_percentage = 1; // the discount percentage: 1% here

    return array(
        'percentage'       => $discount_percentage,
        'field_key'        => 'membership_number', // Field "name" key (or id)
        'field_type'       => 'text',
        'field_label'      =>  __('Membership number', 'woocommerce'),
        'button_text'      =>  __('Apply membership number', 'woocommerce'),
        'discount_text'    =>  sprintf( __('Membership discount%s', 'woocommerce'), ' ('.$discount_percentage.' %)' ), // for negative fee
        'valid_message'    => __('Number is valid (text message).', 'woocommerce'),
        'unvalid_message'  => __('Number not valid (text message).', 'woocommerce'),
        'empty_field_text' => __('Please enter your membership number.', 'woocommerce'),
     );
}

// Settings + Membership number
function get_membership_data(){
    $settings      = get_membership_settings();// Load settings
    $field_key     = $settings['field_key']; // The field Id

    $user_value    = get_user_meta( get_current_user_id(), $field_key, true ); // Get "membership number" from user data
    $session_value = WC()->session->get($field_key); // Get "membership number" from session variable

    // Set "membership number" in the array
    $settings['field_value'] = empty($session_value) ? $user_value : $session_value;

    return $settings;
}

购物车上显示的字段(请参见最后的屏幕截图):

// Display a text input field on cart (+ javascript)
add_action('woocommerce_cart_contents', 'display_field_membership_number', 100 );
function display_field_membership_number(){
    extract(get_membership_data()); // Load data and settings

    echo '<tr><td colspan="6" class="membership" style="padding:0;border-top:16px solid #FFF;">
        <style>.message.off,label.hidden{display:none}.membership .message{margin-left:20px}</style>
        <div id="'.$field_key.'-wrapper">
            <label for="'.$field_key.'" class="hidden"> '.$field_label.'&nbsp;<abbr class="required" title="required">*</abbr></label>
            <input type="'.$field_type.'" class="input-'.$field_type.'" name="'.$field_key.'" id="'.$field_key.'" placeholder="'.$field_label.'" value="'.$field_value.'">
            <button type="button" class="button">'.$button_text.'</button>
            <span class="message off"></span>
        </div>
    </td></tr>
    <tr><td colspan="6" style="padding:0"></td></tr>';
}

jQuery / Ajax代码:

// Function that send the Ajax request | jQuery + Ajax
add_action('wp_footer', 'membership_number_js_script');
function membership_number_js_script() {
    if( ! is_cart() ) return; // Only on cart

    $field_key = get_membership_settings()['field_key']; // Load field key id

    // jQuery Ajax code
    ?>
    <script type="text/javascript">
    jQuery( function($){
        if (typeof woocommerce_params === 'undefined')
            return false;

        var s = '#<?php echo $field_key; ?>-wrapper';

        $(s+' button').click( function(){
            var value = $(s+' input').val();

            // Function that handle the display of the message
            function handleDisplayMessage( selector, response, error = false ) {
                if ( ! error ) {
                    $.each( $.parseJSON(response), function(index, value){
                        displayMessage( selector, value, index );
                    });
                } else {
                    displayMessage( selector, response, 0 );
                }
            }

            // Function that display a message
            function displayMessage( selector, response, type ) {
                $(selector).hide('0').removeClass('off').html(response).css('color', (type == 1 ? '#03C03C' : '#DC143C')).show();
                setTimeout(function() {
                    $(selector).hide();
                }, 3000 );
            }

            $.ajax({
                type: 'POST',
                url: wc_cart_params.ajax_url,
                data: {
                    'action': '<?php echo $field_key; ?>',
                    '<?php echo $field_key; ?>': value,
                },
                success: function (response) {
                    handleDisplayMessage( (s+' .message'), response );
                    $(document.body).trigger("added_to_cart"); // refresh cart
                },
                error:function(error){
                    handleDisplayMessage( (s+' .message'), ('A problem occured (error: '+error+')'), true );
                }
            });
        });
    });
    </script>
    <?php
}

PHP WordPress Ajax接收器功能:

// Get the ajax request and set value to WC session (and the field validation)
add_action( 'wp_ajax_membership_number', 'set_membership_number_and_validation' );
add_action( 'wp_ajax_nopriv_membership_number', 'set_membership_number_and_validation' );
function set_membership_number_and_validation() {
    extract(get_membership_settings()); // Load and extract settings

    if( isset($_POST[$field_key]) && ! empty($_POST[$field_key]) ) {

        ## HERE BELOW, SET YOUR CODE (that checks membership number for validation)

        $validation = true; // "true" when validated (or false if not)

        // Set membership number to a WC session variable
        WC()->session->set($field_key, $_POST[$field_key]);

        // Send response back
        echo json_encode( ($validation ? [1 => $valid_message] : [0 => $unvalid_message]) );
    } else {
        // Send response back
        echo json_encode( [0 => $empty_field_text] );
    }
    die();
}

折扣部分:

有多种折扣方法 (以下是两种,使用不同的挂钩)

1。基于折扣的购物车小计+运输费用(负费用)

// 1. Percentage discount for Membership (with a negative fee)
add_action( 'woocommerce_cart_calculate_fees', 'add_membership_discount' );
function add_membership_discount( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    extract(get_membership_data()); // Load and extract settings + membership numver

    if( ! empty($field_value) ) {
        // Calculation
        $discount = ( $cart->get_cart_contents_total() + $cart->get_shipping_total() ) * $percentage / 100;

        $cart->add_fee( $discount_text, -$discount ); // Add a discount
    }
}

2。购物车项目价格折扣:

// 2. Percentage discount for Membership (on cart items price)
add_action( 'woocommerce_before_calculate_totals', 'add_membership_cart_item_discount' );
function add_membership_cart_item_discount( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
        return;

    extract(get_membership_data()); // Load and extract settings + membership numver

    if( ! empty($field_value) ) {

        // Loop through cart items
        foreach( $cart->get_cart() as $cart_item ){
            // Get the real WC_Product Object
            $product = wc_get_product($cart_item['data']->get_id());

            $price = $product->get_price(); // The real product price

            $discounted_price = $price * ( 1 - ( $percentage / 100 ) ); // Calculation

            $cart_item['data']->set_price($discounted_price); // Set the discounted price
        }
    }
}

所有代码都放在活动子主题(或活动主题)的functions.php文件中。经过测试,可以正常工作。

enter image description here


相似线程: