Search code examples
phpjqueryajaxwoocommercecart

Get renamed cart item name via Ajax from cart items data in Woocommerce


I'm trying to retrieve (via Ajax) a custom name I've set on my product but so far I'm unable to retrieve it.

Here's my code to set the custom name;

add_action( 'woocommerce_before_calculate_totals', 'add_custom_price', 10, 1);
function add_custom_price( $cart_obj ) {

    // This is necessary for WC 3.0+
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    // Avoiding hook repetition (when using price calculations for example)
    if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
        return;

    // Loop through cart items
    foreach ( $cart_obj->get_cart() as $cart_item ) {
        $cart_item['data']->set_name( 'My Test Name' );
        $cart_item['data']->set_price( 40 );
    }
}

In my Javascript, I make my Ajax call when the checkout is updated:

$( document.body ).on( 'updated_checkout', function() {...

And from there I call this PHP function;

add_action( 'wp_ajax_retrieve_custom_product_name', 'retrieve_custom_product_name' );
function retrieve_custom_product_name() {

    //  This is necessary for WC 3.0+
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) 
        return;

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

    $items = WC()->cart->get_cart();

    foreach($items as $item => $cart_item) {
        $item_name = $cart_item['data']->get_name();
    }
    echo $item_name;
    wp_die();
}

I was expected $cart_item['data']->get_name(); to give me the custom name I have set, but it just returns the original product name.

Does anyone have any ideas as to what I'm doing wrong here?


Solution

  • You can't get the new cart item name via Ajax this way from the cart item, and you will need to use some tricks using WC_Sessions to make it work.

    Note that you can have many cart items and that you will be able to return only one new cart item name with your actual logic.

    The code:

    // Change cart item name and price
    add_action( 'woocommerce_before_calculate_totals', 'change_cart_item_name_and_price', 10, 1 );
    function change_cart_item_name_and_price( $cart ) {
        if ( is_admin() && ! defined( 'DOING_AJAX' ) )
            return;
    
        if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
            return;
    
        // Get new items names from WC_Session
        $session_data = (array) WC()->session->get( 'new_item_names' );
    
        // Loop through cart items
        foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
            $new_item_name = 'My Test Name';
    
            $cart_item['data']->set_name( 'My Test Name' );
            $cart_item['data']->set_price( 40 );
    
            // If item name doesn't exist in WC_Session for this cart item, we do it
            if( ! isset($session_data[$cart_item_key]) ) {
                $session_data[$cart_item_key] = $new_item_name;
                WC()->session->set( 'new_item_names', $session_data );
            }
        }
    }
    
    // PHP WP Ajax
    add_action( 'wp_ajax_get_cart_item_name', 'retrieve_custom_product_name' );
    add_action( 'wp_ajax_nopriv_get_cart_item_name', 'retrieve_custom_product_name' );
    function retrieve_custom_product_name() {
        $session_data = (array) WC()->session->get( 'new_item_names' );
    
        // Loop through cart items
        foreach( WC()->session->get('cart') as $cart_item_key => $cart_item ) {
            // Get the new item name from WC_Session
            if( isset($session_data[$cart_item_key]) ) {
                $item_name = $session_data[$cart_item_key];
                break; // We stop the loop to get one item name only (the first one)
            }
        }
        if( isset($item_name) ) {
            echo $item_name;
        }
        die();
    }
    
    // Jquery Ajax
    add_action('wp_footer', 'custom_ajax_checkout_script');
    function custom_ajax_checkout_script( $checkout ) {
        if ( is_checkout() && ! is_wc_endpoint_url() ) :
        ?>
        <script type="text/javascript">
        jQuery( function($){
            if (typeof wc_checkout_params === 'undefined')
                return false;
    
            // update cart on delivery location checkbox option
            $(document.body).on( 'updated_checkout', function() {
                $.ajax({
                    type: 'POST',
                    url: wc_checkout_params.ajax_url,
                    data: {
                        'action': 'get_cart_item_name',
                    },
                    success: function (result) {
                        console.log('response: '+result); // just for testing
                    },
                    error: function(error){
                        console.log(error); // just for testing
                    }
                });
            });
        });
        </script>
        <?php
        endif;
    }
    

    Code goes in function.php file of your active child theme (or active theme). Tested and works.