Descrizione

Realizzazione tramite codice di un Box visibile nella scheda Prodotto che mostri le spedizioni e i suoi dettagli: dal costo e tipologia alle tempistiche di spedizione.

Codici

PHP | JQuery | CSS

Strumenti

Plugin Woocomerce

Competenze

Conoscenza WooUX - User ExperienceUI - User Interface

Premessa

Woocomerce non ha un vero e proprio Box per i costi di spedizione che hanno altri e-commerce, la spedizione viene calcolata nel carrello o pagamento in base all’indirizzo. Ci son numerosi plugin che implementano il calcolo spedizione o la vista automatica per spedizioni non dinamiche. Questa elaborazione è stata studiata appositamente per E-commerce in Dropshipping in cui i costi di spedizioni e le tempistiche vengono messe manualmente nei dati del prodotto.

Scopo

Creare un box visibile nella pagina singolo prodotto, visibile anche in parte nel carrello e nel pagamento con i dati di spedizione: Costo e Tempistiche.

Strumenti e Studi

  • Conoscenza Funzioni WP – Woo
  • UX UI Grafica in relazione al tema e alla comunicazione dati al cliente.
  • Codice PHP (funzioni WP e WooCommerce)
  • WP: 6.8
  • Plugin: Woocommerce 10
  • Layout Responsive: Desktop, Mobile, Tablet

Risultato Grafico

Codice realizzato

  • Codice Singolo Prodotto
  • Codice Carrello

Story map Codice Singolo Prodotto:

  • Richiamo classe spedizione prodotto
  • richiamo sessione carrello e richiamo dati Zona spedizione e metodi attivi
  • Richiamo dati dai metodi (titolo e costo)
  • richiamo campo “attributo prodotto” per tempistiche di spedizione
  • Controllo sui costi (classe o non classe) ed elaborazione delle formule matematiche se presenti.
  • Controllo sui costi base della tariffa ed elaborazioni eventuali formule matematiche se presenti
  • Estrazione della formula matematica per quantità (sia dal costo base che quello di classe/non classe)
  • Creazione di un box html con i dati per ogni metodo
  • creazione del template finale in HTML con tutti i dati

Per gestire al meglio il lavoro della funzione si sono create 2 funzioni di supporto : th_safe_math_eval() fa i processi matematici della formula e fa uscire il costo finale che risulterebbe da eventuale formula, th_get_calculated_shipping_cost() questa funzione pulisce la formula che troviamo nel campo dell costo e classe/non classe della spedizione, elabora quindi il calcolo matematico, ed estrapola il testo della formula da mostrare nel box. Infine abbiamo la creazione dello shortcode che richiama solo la seconda formula.

PHP
// Questo Shortcode mostra i dati della spedizione associata di Woocomerce, prende il costo della specifica classe di spedizione, controlla le formule associate dentro il costo finale, prende le tempistiche da un attributo creato e mette tutto assieme.
 

 
 
/** 1.0 Funzione per il calcolo sicuro di espressioni matematiche. _______________________
 * 	@param string $expression L'espressione matematica da calcolare.
 * 	@return float|string Il risultato del calcolo o 'N/A' in caso di errore.  */
function th_safe_math_eval($expression) {
    $expression = str_replace(' ', '', $expression); // Rimuovi spazi per una migliore gestione
    $expression = str_replace(',', '.', $expression); // Sostituisci la virgola con il punto per i decimali
	// Controlla che l'espressione contenga solo numeri, operatori matematici e parentesi
    if (preg_match('/[^0-9\.\+\-\*\/\(\)]/', $expression)) {  $result = 0; } // L'espressione non è valida
    
    // Calcola il risultato 
    $result = 0;
    try {
        // Usa una funzione sicura come `gmp_eval` se disponibile o crea un parser
        // Per semplicità e sicurezza, usiamo la logica base, ma un parser sarebbe ideale.
        // Qui si potrebbe usare una libreria come `math_eval` per una gestione più robusta.
        // Per ora, ci affidiamo a una logica di base che previene la maggior parte dei rischi.
        ob_start();
        $result = @eval("return $expression;");
        ob_end_clean();
        if (is_numeric($result)) {  return $result;	}
        else {            			$result = 0;    } 
	} catch (Throwable $e) {   		$result = 0;   }
} //end  th_safe_math_eval ______________________________________________



/** Calcola il costo di spedizione e la formula associata.
 * @param string $cost_string La stringa del costo da elaborare (es. "5 + (2 * [qty])").
 * @return array Un array contenente il 'costo' calcolato e la 'formula_qty'.   */
function th_get_calculated_shipping_cost($cost_string) {
    // Inizializza le variabili
    $calculated_cost = 0;
    $formula_qty = '';

    if (!empty($cost_string)) {
        // 1. ELIMINA le formule "+ [fee ...]" o "[fee ...]"
       		// Spiegazione della regex:
			//   \s*\+\s* -> Corrisponde a zero o più spazi, seguito da un +, seguito da zero o più spazi (opzionale)
			//   \[fee    -> Corrisponde alla stringa letterale '[fee'
			//   [^\]]* -> Corrisponde a qualsiasi carattere tranne ']' (zero o più volte)
			//   \]       -> Corrisponde alla stringa letterale ']'		
        $pattern = '/\s*\+\s*\[fee[^\]]*\]|\[fee[^\]]*\]/';
		    	// Sostituisci il pattern trovato con una stringa vuota
        $clean_cost_string = preg_replace($pattern, '', $cost_string);

        // 2. Calcola il risultato numerico con [qty] = 1
        $formula_with_qty = str_replace('[qty]', '1', $clean_cost_string); //mostriamo sempre il calcolo quantità aumentata per 1 prodotto
		
		    // 2.5 Sostituisce [cost] con 0 (essendo che il costo del carrello attuale non possiamo usarlo nella scheda prodotto, questo campo deve essere azzerato
        $formula_with_qty_and_cost = str_replace('[cost]', '0', $formula_with_qty); 
		
		   // TRASFORMA FORMULE impleentati nel campo come -> 4,5  + ( 0,5 * [qty] )  _________
					//Se sono presenti FORMULE - dai il risultato della formula considerando quantità 1
					// Prepara l'espressione matematica per il calcolo
		   $result_calc = th_safe_math_eval($formula_with_qty);
        if (is_numeric($result_calc)) {  $calculated_cost = $result_calc; } // Se il risultato non è numerico, mantieni il costo a 0.00
		
        // 3. Estrai la formula per la quantità (se presente) 
        // da mostrare poi nel box spedizione
        if (strpos($cost_string, '[qty]') !== false) { //esiste la formula quantità
        		//  \(: Il carattere letterale di una parentesi tonda aperta (.
				//  (.*?): Qualsiasi carattere (.) che si ripete zero o più volte (*), ma in modo "non avido" (?), cioè fermandosi al primo carattere di chiusura. Questo è il gruppo di cattura.
				//   \): Il carattere letterale di una parentesi tonda chiusa ).
				//  In pratica, se la stringa è 4.5 + (0.5 * [qty]), la regex estrarrà e salverà solo la porzione 0.5 * [qty].
			if (preg_match('/\((.*?)\)/', $cost_string, $matches)) {
                $formula_qty = trim($matches[1]);
            } else {
                $formula_qty = $clean_cost_string;
            }
        }
    }

	// riporta un array uno è il costo l'altro è la formula delle quantità da stampare
    return [  'calculated_cost' => $calculated_cost, 'formula_qty' => $formula_qty, ];
}//end  th_get_calculated_shipping_cost ______________________________________________

//*********** SHORTCODE ****************************

//  Add Shortcode - scrivi questo shortcode per mostrarlo  [shipping_cost_with_class_data] 
add_shortcode( 'shipping_cost_with_class_data', 'th_shipping_cost_with_class_data_function' );
function th_shipping_cost_with_class_data_function($atts = array(), $content = null ) {

	 // 1.0 Controllo essenziale: verificare che WooCommerce sia attivo.
    if (!function_exists('is_plugin_active') || ! is_plugin_active('woocommerce/woocommerce.php')) { return '';  }
	
	// 2.0 RICHIAMA Il prodotto ID  ---------------------
	global $product; 	
		// Assicurati che $product sia un oggetto WC_Product valido.
    if (!$product instanceof WC_Product) { 
        $product_id = get_the_ID(); // Se non è un oggetto prodotto valido, prova a recuperarlo dall'ID della query.
        if ($product_id) {  $product = wc_get_product($product_id); }
        if (!$product instanceof WC_Product) { return '';} // Nessun prodotto trovato, esci.
    }
	
	// 3.0  RICHIAMA LE VARIABILI NECESSARIE con condizioni-----------------------------	
	
	// 3.1 RECUPERO DATI PRODOTTO E CLASSE DI SPEDIZIONE
    $shipping_class_id = $product->get_shipping_class_id(); //es 22
    $id_class = !empty($shipping_class_id) ? $shipping_class_id : 'No_class'; //se non ha classe utilizza il testo No_class
	// 3.2 RECUPERO ATTRIBUTO TEMPI DI SPEDIZIONE
		// abbiamo messo manualmente i tempi di spedizione nell'atributo Market Giorni di Spedizione -> slug: market-giorni-spedizione
    $val_attribute = $product->get_attribute('pa_market-giorni-spedizione');
    $n_day_attribute = !empty($val_attribute) ? $val_attribute : __('10 - 24 Giorni', 'th-text-domain');
										//	var_dump('Attributo per-pa_market-giorni-spedizione__',$n_day_attribute,'<br><br>'); 
	// 3.3 RECUPERO DATI ZONA DI SPEDIZIONE ATTIVA (basata sulla sessione del carrello)
		//  ZONA ATTIVA della sessione visitatore: ---  è necessario richiamare dati sessione carrello
    $shipping_packages 		= WC()->cart->get_shipping_packages(); // Get cart shipping packages
    $shipping_zone 			= wc_get_shipping_zone(reset($shipping_packages)); // Get the WC_Shipping_Zones instance object for the first package
    //$zone_id 				= $shipping_zone->get_id();  // Get the zone ID
    $zone_name 				= $shipping_zone->get_zone_name(); // Get the zone name
    $zone_formatted_location= $shipping_zone->get_formatted_location();  //Elenco Paesi della zona
    $zone_shipping_methods 	= $shipping_zone->get_shipping_methods();
									//var_dump('__ZONA SESSIONE___ _','<p>Zone id: ' . $zone_id . ' | Zone name: ' . $zone_name ,'<br><br>'); 
	// --- 3.0 end Variabili e dati in condizione  -----------------------------
	
	
	$HTML  = '';
	$metodo_costo_var = '';
	
	// 4.0 Calcolo  VALORE COSTO --------------------------
	if (!empty($zone_shipping_methods)) { //il metodo deve esistere (non essere vuoto)
		 foreach ($zone_shipping_methods as $method) {
            if ($method->enabled === 'yes' && isset($method->instance_settings)) { //importante, il metodo deve essere attivo ($method->enabled), altrimenti si vedono metodi nascosti e disattivi che si gestiscono in lato admini!
				$settings = $method->instance_settings;
											//var_dump('$settings ___ ',$settings ,'<br><br>'); 
               
				// 4.1 Determina il costo in base alla classe di spedizione ________________________
					// richiamare il costo associato alla classe e a tutte le condizioni della tabella costi di spedizione, altrimenti prendere il costo normale senza class
               $costo_classe_prodotto = '';
                if ($id_class !== 'No_class' && isset($settings["class_cost_{$id_class}"])) {
                    $costo_classe_prodotto = $settings["class_cost_{$id_class}"]; //costo richiamato classe di spedizione
                } elseif (isset($settings["no_class_cost"])) {
                    $costo_classe_prodotto = $settings["no_class_cost"]; //costo richiamato senza classe spedizione
                }
				// ________________________
				
				// 4.2 Rielabora il costo della classe spedizione  che può avere una FORMULA
				$result_cost = 0; // Inizializza il costo totale a zero
                $cost_quantity = '';
				if (!empty($costo_classe_prodotto)) {
					// th_get_calculated_shipping_costformula esterna sopra, calcola da eventuale formula il costo e la formula quantità da mostrare
					// 4.2.1 Calcola il costo di classe (o senza classe)
					$class_cost_data = th_get_calculated_shipping_cost($costo_classe_prodotto); 
					$result_cost += $class_cost_data['calculated_cost']; //esce il numero del costo
					$cost_quantity = $class_cost_data['formula_qty']; //esce la formula quantità da stampare
					
                
					// 4.2.2 Calcola il costo base, se presente 
					// le classi si aggiungono sempre al costo base della spedizione , che può essere messo a 0 per essere ignorato
					if (isset($settings['cost']) && !empty($settings['cost'])) { // $settings['cost'] -> riga "Costo" mostrata nelle impostazioni della tarizza di costo
						$base_cost_data = th_get_calculated_shipping_cost($settings['cost']);
						if (is_numeric($base_cost_data['calculated_cost'])) {	$result_cost += $base_cost_data['calculated_cost'];}
						if (!empty($base_cost_data['formula_qty'])) { // Concatena la formula del costo base se esiste
							if (!empty($cost_quantity)) {
								// Se esiste già una formula, aggiungi un "+"
								$cost_quantity .= ' e ' . $base_cost_data['formula_qty'];
							} else {
								// Altrimenti, usa solo la formula del costo base
								$cost_quantity = $base_cost_data['formula_qty'];
							}
						}
					}
										
					// 4.2.3 Se il risultato totale è zero e non c'è una formula, gestiscilo come N/A
					if ($result_cost === 0 && empty($costo_classe_prodotto) && empty($settings['cost'])) {	$result_cost = 'N/A';}
					
                } // end 4.2  (!empty($costo_classe_prodotto)) 
				
				// 4.3 HTML per ogni METODO di spedizione (foreach) elencato_________________
				$metodo_costo_var .= '<div class="method-el">'
                   	              . '<div class="m-t-colum"><i class="fas fa-chevron-right"></i><span class="m-name">' . esc_html($settings["title"]) . '</span></div>'
                                  . '<div class="m-c-colum"><span class="qty">' . esc_html($cost_quantity) . '</span><span class="m-time">' . esc_html($n_day_attribute) . '</span><span class="cost">' . (is_numeric($result_cost) ? wc_price($result_cost) : esc_html($result_cost)) . '</span></div>'
                                  . '</div>';
				// end  4.3  HTML per ogni METODO ________________
				
				
			} //if ($method->enabled === 'yes
		} //foreach 
	}// end  4.0 Calcolo  VALORE COSTO --------------------------
	
	// TESTO INFORMATIVO
		$text_info = __("Se vuoi visualizzare le spedizioni per altri paesi, puoi cambiare l'indirizzo di spedizione nel Carrello. E visualizzare le nuove spedizioni.", 'th-text-domain') . ' ' . __("Per conoscere con maggior dettaglio i dati delle spedizioni e le tempistiche lunghe, guardare nel TAB spedizioni qui a seguire.", 'th-text-domain');

	
		// HTML da stampare nello shortcode
		$HTML .= '<div class="data-box-shipping-product style-box-vertical-left">';
		$HTML .=    '<div class="Box-flex">';
		$HTML .=        '<div class="left-column"><i class="icon fa fa-regular fa-truck"></i></div>';
		$HTML .=        '<div class="right-column">';
		$HTML .=            '<div class="method">' . $metodo_costo_var . '</div>';
		$HTML .=            '<div class="zone-box"><span class="subtitle">' . __('Zona:', 'th-text-domain') . '</span><span class="text">' . esc_html($zone_name) . '</span></div>';
		$HTML .=            '<details class="wp-block-details country-list"><summary>' . __('Paesi:', 'th-text-domain') . ' ' . '</summary><div class="state">' . esc_html($zone_formatted_location) . '</div></details>';
		$HTML .=            '<details class="wp-block-details info"><summary>' . __('Note informative:', 'th-text-domain') . ' ' . '</summary><div class="info-note">' . esc_html($text_info) . '</div></details>';
		$HTML .=        '</div>';
		$HTML .=    '</div>';
		$HTML .= '</div>';



	//--------------------------------------------
    return $HTML; 
} // END SHORTCODE _________________________________________


PHP
CSS

/* 10.0 Box Spedizioni (shortcode creato [shipping_cost_with_class_data] ) _________*/
.data-box-shipping-product {
	--box_shipP_colore: #09635a;
	--box_shipP_BG:#fafff18c; 
	
	border: 1px dashed var(--box_shipP_colore);
    padding: 0.5em 1em ;
    color: var(--box_shipP_colore);
	background: var(--box_shipP_BG);
    display: block;
    margin: 1em 0;
    line-height: normal;
	font-size: 1em;
}

.data-box-shipping-product p { display:none; }

 	/* prima parte titolo e zona*/
.data-box-shipping-product .box-title{
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    border-bottom: 3px solid;
	padding: 0 0 5px 0;
    margin: 0 0 8px 0;
}

.data-box-shipping-product .title-text{	width: 40%;}
.data-box-shipping-product .zone-title{ width: 60%;    display: flex;  justify-content: flex-end;    align-items: center;}

.data-box-shipping-product .title-text .icon{font-size:32px; margin-right: 15px; }
.data-box-shipping-product .title-text .title{ 	font-size:1.3em; text-transform:uppercase;}
.data-box-shipping-product .zone-box{ 
    display: inline-flex;
    justify-content: flex-end;
    align-items: center;
}
.data-box-shipping-product .zone-box .subtitle{
    
    font-style: italic;
    margin-right: 10px;
 }
.data-box-shipping-product .zone-box .text{
    font-weight: 600;
    font-size: 1.2em;
    vertical-align: middle;
	padding-bottom: 3px;
}
.data-box-shipping-product .zone-title .wp-block-details{
    display: inline-flex;
    text-align: right;
    width: auto;
    justify-content: flex-end;
    align-items: center;
}
.data-box-shipping-product .zone-title .wp-block-details summary{
	margin-left: 15px;
    border: 1px solid var(--box_shipP_colore);
    padding: 0px 8px;
}
.data-box-shipping-product .zone-title .wp-block-details .state{}
.data-box-shipping-product .zone-title .wp-block-details .state span{	   font-size: 0.9em; font-style: italic;}

.data-box-shipping-product .zone-title:has(.wp-block-details[open]) {    display: block;}	
.data-box-shipping-product .zone-title .wp-block-details[open]{
    margin-left: 15px;
    border: 1px solid var(--box_shipP_colore);
    padding: 2px 8px;
	display: block;
}
.data-box-shipping-product .zone-title .wp-block-details[open] summary{ 	 border: 0px;	}



	/* contenuto delle spedizioni e costo*/
.data-box-shipping-product .box-data {
    font-size: 0.9em;
     display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
}
.data-box-shipping-product .box-data p { display:none;} /* scappa un po nel codice non so come*/
.data-box-shipping-product .box-data .title{ 
    width: 40%;
    font-weight: 400;
    font-size: 1.2em;
    vertical-align: middle;
    letter-spacing: -0.03em;
}

.data-box-shipping-product .method {
    display: block;
    width: 60%;
}

.data-box-shipping-product .method .method-el {
    display: flex;
    justify-content: space-between;
    align-items: center;
	margin: 0 0 8px 0;
	font-size: 1.1em;
	line-height: normal;
}
.data-box-shipping-product .method .method-el i{ font-size:14px;     margin-right: 10px;}
/* .data-box-shipping-product .method .m-t-colum{} */
/* .data-box-shipping-product .method .m-c-colum{} */
.data-box-shipping-product .method .m-name {    font-weight: 600;}
.data-box-shipping-product .method .m-time {
	font-weight: 500;
    border: 1px solid;
    padding: 0px 6px;
	margin-right: 1em;
    text-align: right;
	background: white;
    font-style: italic;
}
.data-box-shipping-product .method .qty {
    font-size: 80%;
    text-align: right;
    display: inline-block;
    vertical-align: text-top;
    margin: 0 5px 0 0;	
}
.data-box-shipping-product .method .cost {
     font-weight: 500;
    border: 1px solid;
    padding: 0px 6px;
    min-width: 45px;
    display: inline-block;
    text-align: right;
	background: white;
    color: black;
}

.data-box-shipping-product .wp-block-details.info{   font-size: 0.9em}
.data-box-shipping-product .wp-block-details.info summary{}
.data-box-shipping-product .wp-block-details.info .info-note{font-style: italic;}
.data-box-shipping-product .wp-block-details.info[open]{
    border: 1px solid var(--box_shipP_colore);
    padding: 2px 8px;
}

/* 10.1 Box Spedizioni  MOBILE e TABLET */
@media all and  (min-width: 0) and  (max-width: 1024px) { 
		.data-box-shipping-product .box-title {border: 0px;  margin: 0; flex-direction: column;}
		.data-box-shipping-product .title-text {
			width: 100%;
			border-bottom: 3px solid;
			padding: 0 0 5px 0;
			margin: 0 0 8px 0;
		}
		.data-box-shipping-product .title-text .icon {    font-size: 20px;}
		.data-box-shipping-product .title-text .title { 	font-size: 1em; font-weight: bold;	}
		.data-box-shipping-product .zone-title {
			width: 100%;
			display: flex;
			justify-content: space-between;
			align-items: center;
		}
		.data-box-shipping-product .box-data {
			font-size: 1em;
			display: flex;
			align-items: flex-start;
			justify-content: space-between;
			flex-direction: column;
		}
		.data-box-shipping-product .box-data .title {   width: 100%;  margin:0 0 5px;    font-size: 0.9em; border-bottom: 1px solid; }
		.data-box-shipping-product .method {    width: 100%;    margin: 14px 0 0; }
		.data-box-shipping-product .method .method-el { 
			font-size: 1em;
			justify-content: space-between;
			flex-direction: column;
			align-items: stretch;
		}
		.data-box-shipping-product .method .m-time { border: 0; padding: 0px 4px;	font-size: 90%; 	text-align: right;  background: unset; margin: 0 0 0 12px;  display: flex;}
		.data-box-shipping-product .method .qty {    text-align: left;   float: right;    margin-top: -38px;    margin-right: 57px;}
		.data-box-shipping-product .method .cost {text-align: left;    float: right;         margin-top: -40px;}
		.data-box-shipping-product .wp-block-details.info { padding: 20px 0 10px 0;}
	
		
} /*@media 10.1 Box Spedizioni  MOBILE TABLET */	


/* end 10.0 Box Spedizioni  _________*/
CSS

Story map Codice su Carrello:

  • Richiamo classe spedizione prodotto
  • richiamo sessione carrello e richiamo dati Zona spedizione e metodi attivi (non da mostrare)
  • Richiamo dati dai metodi (titolo e costo)
  • richiamo campo “attributo prodotto” per tempistiche di spedizione
  • Controllo sui costi ed elaborazione delle formule matematiche se presenti.
  • Estrazione della formula matematica per quantità
  • Creazione di un box html con i dati per ogni metodo adatto alla posizione tabella

Essenzialmente nella versione per il carrello e pagamento quello che cambia essenzialmente dalla versione della scheda prodotto è il richiamo al filtro e non è uno shortcode (add_filter('woocommerce_add_cart_item_data') ) ; poi il codice HTML è più semplice perché prendiamo solo nome della spedizione, tempi e costo evitando di richiamare alcuni dati della zona del paese che saranno poi forniti in dettaglio nella parte finale della spedizione.

Quindi abbiamo la stessa logica, poi html nella variabile $Metodo_CostoVar che viene registrata con un identificativo specifico cart_item_data['_spedizione_costo_aoggetti']. Questo sarà l’identificativo chiamato poi nella funzione che mostra nelle informazioni la riga sulle spedizioni creata dal filtro add_filter( 'woocommerce_get_item_data').

Funzioni di supporto per il calcolo delle formule costo (es 5,00 * [qty])

identiche a quelle usate per la pagina prodotto, ma con nome differente per essere copiata nella stessa pagina codice da caricare nel carrello.
Queste formule vengono usate anche nel codice per l’alterazione del costo delle classi di spedizione (spiegato sotto)

PHP


/** 1.0  Funzione per il calcolo sicuro di espressioni matematiche.
 * @param string $expression L'espressione matematica da calcolare.
 * @return float|string Il risultato del calcolo o 'N/A' in caso di errore. */
function th_cart_safe_math_eval($expression) {
    $expression = str_replace(' ', '', $expression); // Rimuovi spazi per una migliore gestione
    $expression = str_replace(',', '.', $expression); // Sostituisci la virgola con il punto per i decimali
    // Controlla che l'espressione contenga solo numeri, operatori matematici e parentesi
    if (preg_match('/[^0-9\.\+\-\*\/\(\)]/', $expression)) { return 0; } // Restituisce 0 se l'espressione non è valida
    // Calcola il risultato
    $result = 0;
    try {
        ob_start();
        $result = @eval("return $expression;");
        ob_end_clean();
        if (is_numeric($result)) { return $result; }
        else { return 0; }
    } catch (Throwable $e) { return 0; }
	
}

/** 2.0 Calcola il costo di spedizione e la formula associata. Restituisce sempre un valore numerico per il costo.
 * @param string $cost_string La stringa del costo da elaborare (es. "5 + (2 * [qty])").
 * @return array Un array contenente il 'calculated_cost' e la 'formula_qty'.  */
function th_cart_get_calculated_shipping_cost($cost_string) {
    $calculated_cost = 0;
    $formula_qty = '';

    if (!empty($cost_string)) {
        // 1. ELIMINA le formule "+ [fee ...]" o "[fee ...]"
        $pattern = '/\s*\+\s*\[fee[^\]]*\]|\[fee[^\]]*\]/';
        $clean_cost_string = preg_replace($pattern, '', $cost_string);
        // 2. Calcola il risultato numerico con [qty] = 1
        $formula_with_qty = str_replace('[qty]', '1', $clean_cost_string);
        $result_calc = th_cart_safe_math_eval($formula_with_qty);
        if (is_numeric($result_calc)) { $calculated_cost = $result_calc; }       
        // 3. Estrai la formula per la quantità (se presente)
        if (strpos($cost_string, '[qty]') !== false) {
            if (preg_match('/\((.*?)\)/', $cost_string, $matches)) {
                $formula_qty = trim($matches[1]);
            } else {
                $formula_qty = $clean_cost_string;
            }
        }
    }
    return [ 'calculated_cost' => $calculated_cost, 'formula_qty' => $formula_qty ];
}
PHP

Funzioni Woo per mostrare nella tabella oggetto il costo spedizione e tempi identico alla pagina prodotto

Funzioni richiamate: add_filter('woocommerce_add_cart_item_data') e add_filter( 'woocommerce_get_item_data').

PHP
// AGGIUNGI elemento calcolo spedizione nelle informazioni prodotto in carrello e checkout! ___________________________________

	// Controllo essenziale: verificare che WooCommerce sia attivo.
    if (!function_exists('is_plugin_active') || ! is_plugin_active('woocommerce/woocommerce.php')) { return '';  }




// 3.0 Mostra i costi di spedizione nel carrello e nel pagamento (LEGATO A SHORTCODE [shipping_cost_with_class_data]  )  ------------
	/**   AGGIUNGERE - costi spedizione - informative carrello e pagamento ---------------------------- */
add_filter('woocommerce_add_cart_item_data', 'th_custom_data_shipping_cost_to_cart_checkout_item', 12, 3);
function th_custom_data_shipping_cost_to_cart_checkout_item($cart_item_data, $product_id, $variation_id) {
    // 3.1 RICHIAMO VARIABILI
    $product = wc_get_product($product_id); //importante che venga richiamato correttamente $product, e non solo la variabile generica global $product.	
    if (!$product instanceof WC_Product) { return $cart_item_data;  }
								
	// 3.1.1 RECUPERO DATI PRODOTTO E CLASSE DI SPEDIZIONE
    $shipping_class_id = $product->get_shipping_class_id(); //es 22
    $id_class = !empty($shipping_class_id) ? $shipping_class_id : 'No_class'; //se non 
	// 3.1.2 RECUPERO ATTRIBUTO TEMPI DI SPEDIZIONE
    $Val_attribute = $product->get_attribute('pa_market-giorni-spedizione'); //richiamo info tempistiche
    $N_Day_attribute = !empty($val_attribute) ? $val_attribute : __('10 - 24 Giorni', 'th-text-domain');
	// 3.1.3 RECUPERO DATI ZONA DI SPEDIZIONE ATTIVA (basata sulla sessione del carrello)
		//  ZONA ATTIVA della sessione visitatore: ---  è necessario richiamare dati sessione carrello
	$shipping_packages = WC()->cart->get_shipping_packages(); //dati Zona, necessario per chiamare i dati del costo
    $shipping_zone = wc_get_shipping_zone(reset($shipping_packages));
    $zone_shipping_methods = $shipping_zone->get_shipping_methods();
    
   
    $Metodo_CostoVar = '';
    
    // 3.2 CALCOLO COSTO E FORMULA 
    if (!empty($zone_shipping_methods)) {
        foreach ($zone_shipping_methods as $method) {
            if ($method->enabled === 'yes' && isset($method->instance_settings)) { //molto importante !! $method->enabled === 'yes', altrimenti vedi quelli disattivi accessibili solo in armin
                $settings = $method->instance_settings;
                
                // 3.2.1 Determina il costo in base alla classe di spedizione
                $costo_classe_prodotto = '';
                if ($id_class !== 'No_class' && isset($settings["class_cost_{$id_class}"])) {
                    $costo_classe_prodotto = $settings["class_cost_{$id_class}"]; //costo richiamato classe di spedizione
                } elseif (isset($settings["no_class_cost"])) {
                    $costo_classe_prodotto = $settings["no_class_cost"]; //costo richiamato senza classe spedizione
                }
                
                // 3.2.2 Inizializza il costo totale e la formula
                $result_Cost = 0;
                $cost_quantity = '';            
                // 3.2.3 Calcola il costo di classe (o senza classe)
                if (!empty($costo_classe_prodotto)) {
                    $class_cost_data = th_cart_get_calculated_shipping_cost($costo_classe_prodotto);
                    $result_Cost += $class_cost_data['calculated_cost'];
                    $cost_quantity = $class_cost_data['formula_qty'];
                }
                
                // 3.2.4 Calcola il costo base, se presente
                if (isset($settings['cost']) && !empty($settings['cost'])) { // $settings['cost'] -> riga "Costo" mostrata nelle impostazioni della tarizza di costo
						$base_cost_data = th_cart_get_calculated_shipping_cost($settings['cost']);
						if (is_numeric($base_cost_data['calculated_cost'])) {	$result_Cost += $base_cost_data['calculated_cost'];}
						if (!empty($base_cost_data['formula_qty'])) { // Concatena la formula del costo base se esiste
							if (!empty($cost_quantity)) {
								// Se esiste già una formula, aggiungi un "+"
								$cost_quantity .= ' e ' . $base_cost_data['formula_qty'];
							} else {
								// Altrimenti, usa solo la formula del costo base
								$cost_quantity = $base_cost_data['formula_qty'];
							}
						}
					}
										
					// 3.2.5 Se il risultato totale è zero e non c'è una formula, gestiscilo come N/A
					if ($result_Cost === 0 && empty($costo_classe_prodotto) && empty($settings['cost'])) {	$result_Cost = 'N/A';}
                
                // 3.2.6 Generazione dell'HTML
                $result_Cost_formatted = is_numeric($result_Cost) ? wc_price($result_Cost) : esc_html($result_Cost);
                $Metodo_CostoVar .= '<p class="method-el">'
                                  . '<span class="m-name">' . esc_html($settings["title"]) . '<b>' . $result_Cost_formatted . '</b>' . '<i>' . esc_html($cost_quantity) . '</i>' . '</span>'
                                  . '<em>' . esc_html($N_Day_attribute) . '</em>'
                                  . '</p>';
            }
        }
    }
    
    // 3.3 AGGIUNGI AL CARRELLO IL VALORE
    if (!empty($Metodo_CostoVar)) {
        $cart_item_data['_spedizione_costo_aoggetti'] = $Metodo_CostoVar;
    }
	//-----------------------------
	return $cart_item_data;
}
// end 3.0 Mostra i costi di spedizione nel carrello e nel pagamento  ------------ 


/* 4.0 COSTI SPEDIZIONE VISUALIZZARLI - carrello e pagamento ----------------------------*/
/** Mostra le informazioni personalizzate sulla spedizione per ogni articolo nel carrello.
 * @param array $item_data I dati correnti dell'articolo nel carrello.
 * @param array $cart_item L'array dell'articolo nel carrello.
 * @return array I dati dell'articolo con l'informazione aggiunta. */
add_filter( 'woocommerce_get_item_data', 'th_display_custom_data_shipping_cost', 12, 2 );
function th_display_custom_data_shipping_cost( $item_data, $cart_item ) {
   // Controlla se il dato personalizzato è stato impostato
  $elemento_spedizione = '_spedizione_costo_aoggetti';
	if ( ! isset( $cart_item[$elemento_spedizione]) || empty(  $cart_item[$elemento_spedizione])   ) {  return $item_data; } //questo previene un errore critico php
	else {
		$item_data[] = array(
            'key'     => __( 'Spedizione Dati', 'th-text-domain' ),
            'value'   => $cart_item[$elemento_spedizione],
            //'display' => '<span class="shipping-info spedizionebox">' . wp_kses_post( $cart_item[$elemento_spedizione] ) . '</span>',
        );
	}

	//-----------------
	return $item_data;
} 
/* end 4.0 COSTI SPEDIZIONE VISUALIZZARLI - carrello e pagamento ----------------------------*/
PHP
CSS

/* 2.0 Linea Tabella Varianti prodotti classica --*/
.shop_table .product-info .variation {
	font-size: 1rem;
	letter-spacing: -0.02em;
	line-height: 1.2;
	margin: 10px 0;
	border-radius: 10px;
	padding: 6px 6px;
	border: 1px dashed #4999a0;
	display: grid;
	grid-template-columns: 40% auto;
	grid-template-rows: max-content;
	column-gap: 8px;
	background: #fff;
}

.shop_table .product-info .variation dt {
	font-weight: 500;
	font-size: 0.9rem;
	color: #478abe;
	margin: 0;
	padding: 3px 0;
	border-bottom: 1px dotted #c0c8cc;
	line-height: 1;
}

.shop_table .product-info .variation dd {
	font-weight: 500;
	font-size: 0.9rem;
	margin: 0;
	padding: 3px 0;
	border-bottom: 1px dotted #c0c8cc;
	line-height: 1;
	width: 100%;
	vertical-align: bottom;
}

/*  -----------Tabella MOBILE  ----*/
@media all and (max-width:800px) {
  	  	.shop_table_responsive.woocommerce-cart-form__contents .product-info .variation {   margin: 10px 3% 10px; width: 94%;  background: #fff; display: block;   }
  	 	.shop_table_responsive.woocommerce-cart-form__contents .product-info .variation dt{ width: 100%; }
   		.shop_table .product-info .variation dd {         margin: 0 4px 0px 4px;       width: calc(100% - 8px);}  
	   		/*spedizioen plugin ALD (speciale mobile)*/
	  		.shop_table_responsive.woocommerce-cart-form__contents .product-info .variation-Shipping,
	  	.shop_table_responsive.woocommerce-cart-form__contents .product-info .variation dt.variation-Shipping {width: 100%;  } 
} /*@media 800*/

 /* end 2.0 Linea Tabella Varianti prodotti classica --*/

 

/* 3.0 Linea Tabella Varianti SPEDIZIONE BOX MANUALE (shortcode creato [shipping_cost_with_class_data]) --*/

.shop_table .product-info .variation-SpedizioneDati{   grid-column: 1 / 3;   font-size: 1rem;   }
.shop_table .product-info dt.variation-SpedizioneDati {
	border-top: 1px solid;
    padding: 5px 8px;
    grid-column: 1 / 3;
    margin-top: 5px;
    background: #f3f3f3;
    color: #0c7d72;
    width: 100%;
}
.shop_table .product-info dd.variation-SpedizioneDati{ border-bottom: 0;  }
 	

		/*stili spedizioni richiamti dal carrello tramite Php add_filter  ( 'woocommerce_get_item_data', 'th_display_custom_data_shipping_cost' */
.shop_table .product-info dd.variation-SpedizioneDati .method-el {
    font-size: 0.9em;
    display: flex;
    justify-content: space-between;
}
.shop_table .product-info dd.variation-SpedizioneDati .method-el {
    font-size: 0.9em;
    display: flex;
    justify-content: space-between;
    margin: 0 0 4px 0;
}
.shop_table .product-info dd.variation-SpedizioneDati .method-el b {  margin-left: 10px;}
.shop_table .product-info dd.variation-SpedizioneDati .method-el i { margin-left: 8px;   padding: 0 4px;   background: #dfdfdf52;   font-style: italic;}

/* end 3.0  Linea Tabella Varianti SPEDIZIONE BOX MANUALE --*/
CSS

Costo Classe di spedizione moltiplicato per ogni oggetto del carrello (variante per Woo)

A differenza del modello standard di Woocomerce, che applica il costo della classe spedizione 1 sola volta, con questa funzione viene applicato il costo per ogni elemento del carrello che possiede la classe. Le quantità prodotto nel carrello non influenzano il costo

NOTA! Funzioni di supporto qui richiamate th_cart_get_calculated_shipping_cost() (e quest’ultima usa dentro th_cart_safe_math_eval() ) definite nella sezione riguardante il carrello [Codice Carrello] sopra spiegato.

Questa alterazione dei prezzi, si rispecchia direttamente anche nella pagina Pagamento. E’ necessaria nel caso si usino plugin di dropshipping come ALD – Aliexpress Dropshipping and Fulfillment for WooCommerce, che comunque ogni oggetto dal venditore ha una sua classe spedizione. Se non si aggiunge il costo spedizione al costo prodotto e si vuole gestire le spedizioni manualmente, questo codice è necessario.

PHP

/* ALTERA COSTO TOT SPEDIZIONE aggiunge il costo classe di spedizione per ogni prodotto  ----------------------------*/
/* Di default WOO se trova una classe di spedizione aggiunge il costo 1 sola volta, ma se abbiamo 2 oggetti con la stessa classe di spedizione, il costo rimerrà sempre per 1 oggetto
 * Tramite questo codice, si va ad alterare il risultato finale, moltiplicando per ogni oggetto che ha quella classe di spedizione, il costo della classe di spedizione.
 *  Portachiavi A e B hanno (classe_3eu)(costo 3€). Normalmente Woo darebbe un costo spedizione 3€, contando una sola volta. Con questa modifica, il costo diventa 6€ perchè calcola per ogni oggetto.
 * NOTA: calcolo costo supplementare della classe spedizione per ogni oggetto del carrello e non per le quantità del singolo oggetto!
 * 
 */
add_filter( 'woocommerce_package_rates', 'th_costo_peroggetto_classe_spedizione', 40, 2 );
function th_costo_peroggetto_classe_spedizione( $rates, $package ) {
	
	//	/* DEBUG --> */ var_dump('RATE Iniziale__<pre>',$rates ,'</pre><br><br>');
	
	//variabili da impostare  -----------------
    $tariffe_aggiornate = $rates;
    $conteggio_prodotti_per_classe = array();
    $costo_extra_aggiuntivo_totale = 0;
    
    //  === 5.1 Conteggio Prodotti ==================
    // Contiamo la quantità totale di prodotti PER OGNI classe di spedizione , esce nella variabile : $conteggio_prodotti_per_classe
    foreach ( $package['contents'] as $cart_item_key => $cart_item ) {
        $product = $cart_item['data'];
        $classe_id = $product->get_shipping_class_id();
        
        if ( $classe_id ) {
            // Accumula il conteggio TOTALE dei prodotti per quella classe
            if( isset ($conteggio_prodotti_per_classe[ $classe_id ] ) ){$conteggio_prodotti_per_classe[ $classe_id ]++; 	} // Incrementa il valore esistente di 1 
			else { 														$conteggio_prodotti_per_classe[ $classe_id ] = 1; 	}
        }
		//	/* DEBUG --> */ var_dump('PRODOTTO:___<br>', 'Nome='. $product->get_name().'| Quantita singolo prodotto ='. $cart_item['quantity']. '| ClasseID='. $classe_id.'| ClasseSLUG=' .$product->get_shipping_class(). '| attuale conteggio questa classe per='.$conteggio_prodotti_per_classe[ $classe_id ] ,'<br><br>');
    
	} // end -- foreach ( $package['contents'] 
    
	
    // === 5.2 se nonci sono classi di spedizione segnate ai prodotti ritorna subit ==================
    if ( empty( $conteggio_prodotti_per_classe ) ) {   return $tariffe_aggiornate;    }
	// /* DEBUG --> */ var_dump(' QUANT.PRODOTTI per classe ___',  $conteggio_prodotti_per_classe ,'<br><br>');

    // === 5.3 Richiamiamo le impostazioni di ogini metodo ricaviamo così il costo per classe
    $settings = null;
    foreach ( $tariffe_aggiornate as $rate_id => $rate ) {
        if ( strpos( $rate_id, 'flat_rate' ) !== false ) { // ( solo se il metodo è flat_rate) - quindi non free ship o consegna in negozio
            $method_id = $rate->get_method_id();  // Es: 'flat_rate'
            $instance_id = $rate->get_instance_id(); // Es: 1, 2, 3...
            $settings = get_option( 'woocommerce_' . $method_id . '_' . $instance_id . '_settings');
            break; //abbiamo concluso il lavoro e possiamo chiudere il if ( strpos )
        }
    }

	// === 5.4 se i setting del metodo esistono sono leggibili procediamo
    if ( $settings && is_array( $settings )  ) { 
        
        // --- 5.4.1 Calcoliamo il costo aggiuntivo basato sull'eccedenza ( aggiungi il costo per i pezzi della classe che esistono)
        foreach ( $conteggio_prodotti_per_classe as $classe_id => $quantita_totale ) {
            
            $prodotti_aggiuntivi = max( 0, $quantita_totale - 1 );  //ES se ci sono 4 prodotti per classe, prodotti aggiuntivi = 3 (4 - 1)

			// --- 5.4.1.2  abbiamo più di 1 prodotto per classe (e quindi il calcolo standard Woo non va bene)
            if ( $prodotti_aggiuntivi > 0 ) {
                $chiave_costo = 'class_cost_' . $classe_id;  //richiamiamo il costo impostato per quella classe sped. ma dentro il metodo di spedizione richiamato.
                
                if ( isset( $settings[ $chiave_costo ] ) ) {
                    $costo_formula_originale = $settings[ $chiave_costo ];
					//	/* DEBUG --> */ var_dump('  $costo_formula_originale ___',  $costo_formula_originale ,'<br><br>');
                    
                    // --- 5.4.1.3  $costo_formula_originale -> può uscire con formul (5,00 + (0,5 *[qty])), qui viene elaborata la formula stessa in un prezzo finale
                    $calcolo_risultato = th_cart_get_calculated_shipping_cost( $costo_formula_originale );
                    $Costo_finale_classeSpedizione = $calcolo_risultato['calculated_cost'];
					//	/* DEBUG --> */ var_dump(' $Costo_finale_classeSpedizione ___',  $Costo_finale_classeSpedizione,'<br><br>');


                    // --- 5.4.1.4  Calcola il costo extra totale per QUESTA classe e lo aggiunge al totale generale
                    if ( $Costo_finale_classeSpedizione > 0 ) {
                        $costo_extra_classe = $Costo_finale_classeSpedizione * $prodotti_aggiuntivi; //costo della classe per metodo PER quantità prodotti aggiuntivi
                        $costo_extra_aggiuntivo_totale += $costo_extra_classe;
                    }
                }
            } //end --- 5.4.1.2 -- if ( $prodotti_aggiuntivi > 0 )
        } //end -- 5.4.1  -- foreach ( $conteggio_prodotti_per_classe-------------
    } //end -- 5.4 -- if ( $settings && is_array( $settings ) 
    
   
    
    // === 5.5 Applica il costo extra totale calcolato SOLO se maggiore di zero  ===
    if ( $costo_extra_aggiuntivo_totale > 0 ) {
        foreach ( $tariffe_aggiornate as $rate_id => $rate ) {
            if ( strpos( $rate_id, 'flat_rate' ) !== false ) {    // Applica il costo extra solo ai Flat Rate
                $tariffe_aggiornate[ $rate_id ]->set_cost( $rate->get_cost() + $costo_extra_aggiuntivo_totale );
            }
        }
    }
    // /* DEBUG --> */ var_dump('RATE FINALE__<pre>',$tariffe_aggiornate ,'</pre><br><br>');
	
	
	//------------------
    return $tariffe_aggiornate;
}
/* end  ALTERA COSTO TOT SPEDIZIONE aggiunge il costo classe di spedizione per ogni prodotto  ----------------------------*/

PHP

Il modello è stato utilizzato su più progetti:
https://gadgetstore.luccafan.com/

https://conigliosuloto.luccafan.com/
https://vestirelarp.luccafan.it/
https://kitsunecosplay.luccafan.com/
https://aischeck.luccafan.it/
https://bomboniere.luccafan.it/
https://adventurekit.luccafan.com/
https://gashapon.luccafan.com/
https://yoccastore.luccafan.it/

  • Sviluppo Wordpress

    (2)

  • Programmazione e Codici

    (2)

  • Grafiche Web

    (5)

  • Siti Web

    (7)

  • Grafiche Cartacee

    (0)

  • APP Mobile

    (1)

Contenuto