[英]Ajax Add to cart for simple and variable products on WooCommerce single products
The code below is working for add to cart with WooCommerce for simple products, but not for variable products.下面的代码适用于使用 WooCommerce 添加到购物车的简单产品,但不适用于可变产品。 Can someone help me out?有人可以帮我吗? Because this code works with the latest WC, please do not remove this question because there are lots of codes for this online that do not work at all.因为此代码适用于最新的 WC,请不要删除此问题,因为网上有很多代码根本不起作用。
The error I am getting that is says in a notice that I should choose a product option, even when I chose one.我得到的错误是在通知中说我应该选择一个产品选项,即使我选择了一个。
JS: JS:
jQuery(function($) {
$('form.cart').on('submit', function(e) {
e.preventDefault();
var form = $(this);
form.block({ message: null, overlayCSS: { background: '#fff', opacity: 0.6 } });
var formData = new FormData(form.context);
formData.append('add-to-cart', form.find('[name=add-to-cart]').val() );
var $thisbutton = form.find('.single_add_to_cart_button'); //
// Ajax action
$.ajax({
url: wc_add_to_cart_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'ace_add_to_cart' ),
data: formData,
type: 'POST',
processData: false,
contentType: false,
beforeSend: function (response) {
$thisbutton.removeClass('added').addClass('loading');
},
complete: function( response ) {
response = response.responseJSON;
if ( ! response ) {
return;
}
if ( response.error && response.product_url ) {
window.location = response.product_url;
return;
}
// Redirect to cart option
if ( wc_add_to_cart_params.cart_redirect_after_add === 'yes' ) {
window.location = wc_add_to_cart_params.cart_url;
return;
}
// Trigger event so themes can refresh other areas.
$( document.body ).trigger( 'added_to_cart', [ response.fragments, response.cart_hash, $thisbutton ] );
// Remove existing notices
$( '.woocommerce-error, .woocommerce-message, .woocommerce-info' ).remove();
// Add new notices
form.closest('.product').before(response.fragments.notices_html)
form.unblock();
}
});
});
});
PHP: PHP:
/* WOOCOMMERCE AJAX ADD TO CART
--------------------------------------------------- */
function ace_ajax_add_to_cart_handler() {
WC_Form_Handler::add_to_cart_action();
WC_AJAX::get_refreshed_fragments();
}
/* Add fragments for notices. */
function ace_ajax_add_to_cart_add_fragments( $fragments ) {
$all_notices = WC()->session->get( 'wc_notices', array() );
$notice_types = apply_filters( 'woocommerce_notice_types', array( 'error', 'success', 'notice' ) );
ob_start();
foreach ( $notice_types as $notice_type ) {
if ( wc_notice_count( $notice_type ) > 0 ) {
wc_get_template( "notices/{$notice_type}.php", array(
'messages' => array_filter( $all_notices[ $notice_type ] ),
'notices' => array_filter( $all_notices[ $notice_type ] ),
) );
}
}
$fragments['notices_html'] = ob_get_clean();
wc_clear_notices();
return $fragments;
}
add_action( 'wc_ajax_ace_add_to_cart', 'ace_ajax_add_to_cart_handler' );
add_action( 'wc_ajax_nopriv_ace_add_to_cart', 'ace_ajax_add_to_cart_handler' );
remove_action( 'wp_loaded', array( 'WC_Form_Handler', 'add_to_cart_action' ), 20 ); // Remove WC Core add to cart handler to prevent double-add
add_filter( 'woocommerce_add_to_cart_fragments', 'ace_ajax_add_to_cart_add_fragments' );
To enable Ajax add to cart for simple and variable products on Single product pages you need something different, building a custom Ajax add to cart function that handles also custom product fields and cart item data manipulation (what WooCommerce default Ajax add to cart doesn't allow) . To enable Ajax add to cart for simple and variable products on Single product pages you need something different, building a custom Ajax add to cart function that handles also custom product fields and cart item data manipulation (what WooCommerce default Ajax add to cart doesn't允许) 。
Try the following fully tested on WooCommerce version 4.9.0:在 WooCommerce 版本 4.9.0 上尝试以下完全测试:
add_action( 'wp_footer', 'single_product_ajax_add_to_cart_js_script' );
function single_product_ajax_add_to_cart_js_script() {
?>
<script>
(function($) {
$('form.cart').on('submit', function(e) {
e.preventDefault();
var form = $(this),
mainId = form.find('.single_add_to_cart_button').val(),
fData = form.serializeArray();
form.block({ message: null, overlayCSS: { background: '#fff', opacity: 0.6 } });
if ( mainId === '' ) {
mainId = form.find('input[name="product_id"]').val();
}
if ( typeof wc_add_to_cart_params === 'undefined' )
return false;
$.ajax({
type: 'POST',
url: wc_add_to_cart_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'custom_add_to_cart' ),
data : {
'product_id': mainId,
'form_data' : fData
},
success: function (response) {
$(document.body).trigger("wc_fragment_refresh");
$('.woocommerce-error,.woocommerce-message').remove();
$('input[name="quantity"]').val(1);
$('.content-area').before(response);
form.unblock();
// console.log(response);
},
error: function (error) {
form.unblock();
// console.log(error);
}
});
});
})(jQuery);
</script>
<?php
}
add_action( 'wc_ajax_custom_add_to_cart', 'custom_add_to_cart_handler' );
add_action( 'wc_ajax_nopriv_custom_add_to_cart', 'custom_add_to_cart_handler' );
function custom_add_to_cart_handler() {
if( isset($_POST['product_id']) && isset($_POST['form_data']) ) {
$product_id = $_POST['product_id'];
$variation = $cart_item_data = $custom_data = array(); // Initializing
$variation_id = 0; // Initializing
foreach( $_POST['form_data'] as $values ) {
if ( strpos( $values['name'], 'attributes_' ) !== false ) {
$variation[$values['name']] = $values['value'];
} elseif ( $values['name'] === 'quantity' ) {
$quantity = $values['value'];
} elseif ( $values['name'] === 'variation_id' ) {
$variation_id = $values['value'];
} elseif ( $values['name'] !== 'add_to_cart' ) {
$custom_data[$values['name']] = esc_attr($values['value']);
}
}
$product = wc_get_product( $variation_id ? $variation_id : $product_id );
// Allow product custom fields to be added as custom cart item data from $custom_data additional array variable
$cart_item_data = (array) apply_filters( 'woocommerce_add_cart_item_data', $cart_item_data, $product_id, $variation_id, $quantity, $custom_data );
// Add to cart
$cart_item_key = WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation, $cart_item_data );
if ( $cart_item_key ) {
// Add to cart successful notice
wc_add_notice( sprintf(
'<a href="%s" class="button wc-forward">%s</a> %d × "%s" %s' ,
wc_get_cart_url(),
__("View cart", "woocommerce"),
$quantity,
$product->get_name(),
__("has been added to your cart", "woocommerce")
) );
}
wc_print_notices(); // Return printed notices to jQuery response.
wp_die();
}
}
Code goes in functions.php file of the active child theme (or active theme).代码进入活动子主题(或活动主题)的functions.php文件。 Tested and works.测试和工作。
All notices are enable and displayed on the fly:所有通知都启用并即时显示:
This custom Ajax add to cart code handle product custom fields, allowing to add them as custom cart item data.此自定义 Ajax 添加到购物车代码处理产品自定义字段,允许将它们添加为自定义购物车项目数据。
For that we use woocommerce_add_cart_item_data
WooCommerce dedicated hook enabled in our custom Ajax add to cart code, allowing to add product custom fields as custom cart item data or manipulate cart data on the fly.为此,我们使用在我们的自定义 Ajax 添加到购物车代码中启用的woocommerce_add_cart_item_data
WooCommerce 专用挂钩添加到购物车代码,允许将产品自定义字段添加为自定义购物车项目数据或动态操作购物车数据。
If we add a product custom input text field with this code:如果我们使用以下代码添加产品自定义输入文本字段:
add_action( 'woocommerce_before_add_to_cart_button', 'product_additional_custom_fields' );
function product_additional_custom_fields() {
echo '<table class="variations" cellspacing="0" width="100px">
<tbody><tr>
<td class="label" style="width:100px"><label for="engraving">' . __("Engraving text") . '</label></td>
<td class="value">
<input type="text" name="engraving" id="engraving" value="" />
</td>
</tr></tbody>
</table>
</br>';
}
Then if you want to pass the field value as custom cart item data, you will use然后,如果您想将字段值作为自定义购物车项目数据传递,您将使用
add_filter( 'woocommerce_add_cart_item_data', 'add_cart_item_custom_data', 10, 5 );
function add_cart_item_custom_data( $cart_item_data, $product_id, $variation_id = 0, $quantity, $custom_data = array() ) {
if ( isset($custom_data['engraving']) && ! empty($custom_data['engraving']) ) {
$cart_item_data['engraving'] = sanitize_text_field($custom_data['engraving']);
}
return $cart_item_data;
}
And you can check with the following, that will display in cart and checkout that custom cart item data:您可以检查以下内容,这将显示在购物车中并结帐该自定义购物车项目数据:
add_filter( 'woocommerce_get_item_data', 'display_on_cart_and_checkout', 10, 2 );
function display_on_cart_and_checkout( $cart_data, $cart_item ) {
if ( isset($cart_item['engraving']) ) {
$cart_data[] = array(
"name" => __("Engraving text", "woocommerce"),
"value" => $cart_item['engraving']
);
}
return $cart_data;
}
Code goes in functions.php file of the active child theme (or active theme).代码进入活动子主题(或活动主题)的functions.php文件。 Tested and works.测试和工作。
Notes:笔记:
This code works on the fly as it is, but it's recommended to enqueue the jQuery code as an external file.此代码按原样即时运行,但建议将 jQuery 代码作为外部文件排队。
On some themes you should replace:在某些主题上,您应该替换:
$('.content-area').before(response);
with $('.products').before(response);
与$('.products').before(response);
to display the notices correctly…正确显示通知...
Thanks for the helpful snippet, but the above code was not working for guest uses, but only for logins.感谢您提供有用的代码段,但上面的代码不适用于访客使用,而仅适用于登录。 The wc_fragment_refresh does not trigger when you log out And use it as a guest user. wc_fragment_refresh 在您注销时不会触发并将其用作来宾用户。
$(document.body).trigger("wc_fragment_refresh");
Regards问候
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.