WooCommerce: usare AJAX per gestire le maggiorazioni sui prezzi

Short link

Per evitare di dover creare variazioni per ogni maggiorazione o usare un plugin di terze parti per questo scopo possiamo gestire questa feature usando le variabili di sessione e le action di WooCommerce.

Partiamo dalla nostra action AJAX di aggiunta di un prodotto al carrello:

function my_add_to_cart() {
    $product_id = (int) $_POST['product_id'];
    $quantity = (int) $_POST['quantity'];
    $variation_id = 0;
    $variation = array();
    $cart_item_data = array();
    WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation, $cart_item_data );
     wp_send_json( array( 'ok' => true ) );
     
}

add_action( 'wp_ajax_my_addtocart', 'my_add_to_cart' );
add_action( 'wp_ajax_nopriv_my_addtocart', 'my_add_to_cart' );

A questo punto possiamo associare la maggiorazione ai prodotti usando un custom field che chiameremo maggiorazione (se non lo avete già installato, si consiglia vivamente di usare il plugin Advanced Custom Fields che semplifica enormemente la gestione dei custom field).

Se questo custom field ha un valore numerico, assoceremo l’ID del prodotto al valore nella sessione di WooCommerce:

function my_add_to_cart() {
    $product_id = (int) $_POST['product_id'];
    $quantity = (int) $_POST['quantity'];
    $variation_id = 0;
    $variation = array();
    $cart_item_data = array();
$value = get_post_meta( $product_id, 'maggiorazione', true );
if( is_numeric( $value ) && intval( $value ) > 0 ) {
        $data = WC()->session->get( 'maggiorazione' );
        if( $data === null ) {
            WC()->session->set( 'maggiorazione', json_encode( array( array( 'prodotto' => $product_id, 'maggiorazione' => intval( $value ) ) ) ) );
        } else {
            $meta = json_decode( $data, true );
            $update = array( 'prodotto' => $product_id, 'maggiorazione' => intval( $value ) );
            $in = false;
            foreach( $meta as $m ) {
                if( $m['product'] == $product_id ) {
                    $in = true;
                }
            }
            if( !$in ) {
                $meta[] = $update;
                WC()->session->set( 'maggiorazione', json_encode( $meta ) );
            }
        }
}

    WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation, $cart_item_data );
     wp_send_json( array( 'ok' => true ) );
     
}

add_action( 'wp_ajax_my_addtocart', 'my_add_to_cart' );
add_action( 'wp_ajax_nopriv_my_addtocart', 'my_add_to_cart' );

Se nella sessione non è già presente alcuna maggiorazione, salviamo l’associazione valore/prodotto come stringa JSON. Altrimenti aggiorniamo l’array associativo ottenuto con la funzione json_decode() con i nuovi dati stando attenti a non inserire valori duplicati e quindi salviamo i dati aggiornati nella sessione.

A questo punto entra in gioco la action di WooCommerce woocommerce_calculate_fees che serve appunto a calcolare eventuali aggiunte al totale finale del carrello:

function my_add_charge() {
  $charge = 0.00;
  $data = WC()->session->get( 'maggiorazione' );
  $meta = json_decode( $data, true );
  foreach( WC()->cart->cart_contents as $key => $product_in_cart ) {
      $id = $product_in_cart['product_id'];
      foreach( $meta as $d ) {
          if( intval( $d['prodotto'] ) === intval( $id ) ) {
              $add = (int) $d['maggiorazione'];
              $charge += $add;
          }
      }
  }
  if( $charge > 0.00 ) { 
      WC()->cart->add_fee( 'Maggiorazione', $charge, true, 'standard' );
  }    
}

add_action( 'woocommerce_cart_calculate_fees', 'my_add_charge' );

Eseguiamo un loop sui prodotti presenti nel carrello e se c’è una corrispondenza tra un prodotto nel carrello e un prodotto dell’array associativo della sessione incrementiamo il valore numerico della variabile $charge che poi verrà usata con il metodo add_fee().

Infine non ci resta che resettare la nostra variabile di sessione quando il carrello è vuoto:

function my_empty_cart_action() {
    $data = WC()->session->get( 'maggiorazione' ); 
    if( $data !== null ) {
        $meta = json_decode( $data, true );
        if( count( $meta ) > 0 ) {
          WC()->session->set( 'maggiorazione', json_encode( array() ) );
        }  
    }     
}

add_action( 'woocommerce_cart_emptied', 'my_empty_cart_action' );

L'autore

Gabriele Romanato, sviluppatore web full stack specializzato in siti, applicativi web ed e-commerce con Node.js e PHP.