我的目标是:使用AJAX在购物车的总价格上打10%的折扣。
上下文:此折扣仅适用于来自给定网站的特定用户。想法是在我添加到购物车页面的输入字段中获取他们的会员编号。使用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\u before\u calculate\u 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\u cart\u calculate\u fees
hook的负费用尝试:
如果我在AJAX操作函数之外使用add\u操作,那么woocommerce\u cart\u calculate\u fees hook的回调函数将非常有效,如下所示:
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
}
所以这项工作,应用了否定费,但当页面加载时,这不是我想要的,因为我想在触发更新购物车按钮时应用否定费,所以想法是将add_操作集成到我的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在我的动作函数中工作?
您错过了使用WC会话变量来设置一些数据并在折扣函数中使用它...下面的第一个函数处理您的设置,它会加载到其他函数的任何地方。
// 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.' <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. 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. 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活动子主题(或活动主题)的文件中。测试和工作。
类似的线程: