Search code examples
phpjqueryajaxwoocommerceproduct

Custom WooCommerce Ajax add to cart functionality issue


I try to add products (I have only simple products) to cart using JavaScript and PHP. I send Product ID(s) then I call WC_Cart add_to_cart() method in funcions.php.

This is the HTML (and JavaScript) code that I am using:

<button onclick="f1()" style="margin-block:100px;margin-inline:auto;">✅</button>
<script>
    function f1(){
        // const cartItems=[9660, 9568, 8625]
        const cartItems=9568
        const data = {
            action: 'AddtocartF',
            ProductsToPay: JSON.stringify(cartItems)
        };
        fetch('https://9effa.ma/wp-admin/admin-ajax.php', {
            method: 'POST',
            body: new URLSearchParams(data),
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
            }
        })
            .then(response => response.json())
            .then(data => {
                console.log(data)
            })
            .catch(error => {
                console.error('Error:', error);
            });
    }
</script>

The PHP code:

add_action('wp_ajax_AddtocartF', 'AddtocartFunction');
add_action('wp_ajax_nopriv_AddtocartF', 'AddtocartFunction');

function AddtocartFunction(){
    if (!isset($_POST['ProductsToPay'])) {
        wp_send_json_error(['message' => "Veuillez ajouter les produits au panier avant de passer au paiement."]);
    }
    $product_id = $_POST['ProductsToPay'];
    $quantity = 1;
    $WC_Cart = new WC_Cart();
    $result = $WC_Cart->add_to_cart($product_id, $quantity);
    if (is_wp_error($result)) {
        // Handle the error case
        wp_send_json_error(['message' => $result->get_error_message()]);
    } else {
        // Product added successfully
        $response = ['success' => true, 'message' => 'Product added to cart', 'id' => $product_id, 'result value: ' => $result];
        wp_send_json_success($response);
    }
    wp_die();
}

The issue I have is that it returns true (product added to cart), but in fact it doesn't: The cart is empty and in checkout I don't see any products as well.

This is the message that I get in the console:

{
    "success": true,
    "data": {
        "success": true,
        "message": "Product added to cart",
        "id": "9568",
        "result value: ": "621d187a8e1a345cc07422a61c669654"
    }
}

I have the latest WooCommerce and Elementor versions and I use Hello Elementor theme. In WooCommerce status tab everything looks fine, there isn't any issues and I can add to cart via the normal way, I mean if I go to shop page or product page and clicked on add to cart button.

I tried disabling all plugins except Elementor and WooCommerce. I tested a lot of different product Ids.


Solution

  • It seems that you are trying in fact to add multiple products at once:

    // const cartItems=[9660, 9568, 8625]
    

    The following based on Add to cart multiple variations via JQuery and Ajax in WooCommerce answer thread, will handle adding to cart one or multiple products with your custom button via Ajax.

    It also handles different quantities for each product (optionally).

    I have embedded your custom button HTML as a shortcode (see usage at the end).

    The code:

    add_shortcode( 'multi_atc', 'multi_add_to_cart_button_html');
    function multi_add_to_cart_button_html( $atts ) {
        extract( shortcode_atts( array(
            'data'  => '',
            'text'  => '✅',
            'class' => 'multi-atc-btn'
        ), $atts, 'multi_atc' ) );
    
        if( $data ):
    
        ob_start();
    
        wc_enqueue_js("const products = \"{$data}\";
        $(document.body).on('click', '.{$class}', function(e) {
            e.preventDefault();
            
            $.ajax({
                type: 'POST',
                url: '" . admin_url('/admin-ajax.php') . "',
                data: {
                    'action': 'multi_add_to_cart',
                    'nonce': '" . wp_create_nonce('multi_atc') . "',
                    'products': products
                },
                success: function(response) {
                    $(document.body).trigger('wc_fragment_refresh');
                    console.log(response);
                },
                error: function (error) {
                    console.log(error);
                }
            });
        });");
    
        echo "<style>.{$class}{margin-block:100px; margin-inline:auto;}</style>
        <button class=\"{$class}\">{$text}</button>";
    
        return ob_get_clean();
        endif;
    }
    
    add_action('wp_ajax_multi_add_to_cart', 'multi_add_to_cart');
    add_action('wp_ajax_nopriv_multi_add_to_cart', 'multi_add_to_cart');
    function multi_add_to_cart() {
        if ( isset($_POST['nonce']) 
        && wp_verify_nonce($_POST['nonce'], 'multi_atc')
        && isset($_POST['products']) && !empty($_POST['products']) ) {
            $response  = array();
    
            foreach( explode(',',esc_attr($_POST['products'])) as $values ) {
                $values = (array) explode(':',$values);
                if ( is_array($values) ) {
                    $product_id = absint(current($values));
                    $quantity   = count($values) == 2 ? end($values) : 1;
                    $product    = wc_get_product( $product_id );
    
                    $not_added  = array( 
                        'key'   => null,
                        'added' => 0,
                        'id'    => $product_id,
                    );
    
                    if ( ! is_a($product, 'WC_Product') ) {
                        $response[] = $not_added;
                        continue;
                    }
    
                    $quantity     = wc_stock_amount( wp_unslash( $quantity ) );
                    $variation_id = 0;
                    $variation    = array();
    
                    if ( $product && 'variation' === $product->get_type() ) {
                        $variation_id = $product_id;
                        $product_id   = $product->get_parent_id();
                        $variation    = $product->get_variation_attributes(); 
                    }
                    
                    if ( 'publish' !== get_post_status( $product_id ) ) {
                        $response[] = $not_added;
                        continue;
                    }
                    
                    if ( $variation_id && 'publish' !== $product->get_status() ) {
                        $response[] = $not_added;
                        continue;
                    }
    
                    $cart_item_key = WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation );
                    
                    $response[] = array( 
                        'key'   => $cart_item_key,
                        'added' => $cart_item_key ? $quantity : '0',
                        'id'    => $variation_id ?: $product_id,
                    );
                }
            }
    
            if ( ! empty($response) ) {
                wp_send_json($response);
            }
        }
        wp_die('Something went wrong.');
    }
    

    Code goes in functions.php file of your child theme (or in a plugin). Tested and work with all product types.


    USAGE Examples (product IDs are comma separated):

    You can use the shortcode in the WordPress Text Editor, in some blocks, in some widgets, in Elementor…

    • No quantities defined (default 1 by product):
      [multi_atc data='9660,9568,8625']
      
    • With different quantities (2 of first product and 4 of the last product):
      [multi_atc data='9660:2,9568,8625:4']
      

    To use the shortcode inside PHP code, use do_shortcode() function like:

    echo do_shortcode("[multi_atc data='9660:2,9568,8625:4']");