Clonage de champs produits WooCommerce. Part. 2

4- Transmettre les données au tunnel d’achat

Le plus dur est fait ! A présent on a plus qu’à s’appuyer sur les fonctionnalités de WordPress et WooCommerce pour faire le boulot ! Ou presque…

Bibi.

A présent on a plus qu’à s’appuyer sur les fonctionnalités de WordPress et WooCommerce pour faire le boulot ! Ou presque…

Lorsqu’on clique sur le bouton “AJOUTER AU PANIER”, nos différents champs vont être transmis à l’enregistrement des données panier de WooCommerce. Pour qu’elles soient traitées et sauvegardées comme des données “variation produit”, nous allons faire appel au filtre ‘woocommerce_add_cart_item_data’.

Dans le moteur de WordPress, nous pouvons faire appel à des filtres, un peu comme l’appel de fonction sur des HOOK, pour changer la valeur des données associées. WooCommerce s’appuie sur ce même principe de hook et de filtres, forcément.

Voici le code complet pour l’ajout des données voyageurs au panier :

add_filter('woocommerce_add_cart_item_data','afa_add_item_data',10,3);

function afa_add_item_data($cart_item_data, $product_id, $variation_id)
{
    if(isset($_REQUEST['quantity'])) //teste si le formulaire est bien validé sur le champs quantity.
                                     //On peut compléter en testant l'existance des variables voyageurs attendues.
    {
        $cpt = $_REQUEST['quantity'];
        $voyageur = array();
        for($i=1;$i<=$cpt;$i++):
            $voyageur['Voyageur '.$i] = array(
                'Nom' => sanitize_text_field($_REQUEST['wdm_name_'.$i]),
                'Prénom' => sanitize_text_field($_REQUEST['wdm_lastname_'.$i]),
            );
        endfor;
        
        $cart_item_data['voyageur'] = serialize($voyageur);
    }

    return $cart_item_data;
}

Que ce passe-t-il dans la fonction afa_add_item_data() ?

Ces nouvelles données sont donc ajoutées à la variable $_REQUEST, il faut maintenant faire en sorte qu’elles soient consultable lors de l’affichage de notre panier et de la page commande. Pour cela nous allons utiliser le filtre ‘woocommerce_get_item_data’ qui est appelé pour récupérer les données des items/éléments de notre panier.

add_filter('woocommerce_get_item_data','afa_add_item_meta',10,2);

function afa_add_item_meta($item_data, $cart_item)  {
    if(array_key_exists('voyageur', $cart_item))      {

        $custom_details = unserialize($cart_item['voyageur']);

        foreach($custom_details as $key => $val) {
            $item_data[] = array(
                'key'   => $key,
                'value' => ''
            );
            foreach($val as $keyV => $valV) {
                $item_data[] = array(
                    'key'   => $keyV,
                    'value' => $valV
                );
            } //fin foreach $val
        } //fin foreach $custom_details
    } //fin if

    return $item_data;
}

Que se passe-t-il dans la fonction afa_add_item_meta() ?

Chaque item dans woocommerce est constitué d’un index, qui sera l’intitulé de la variation par exemple, et d’une valeur associée. Dans notre cas, et pour faire au plus simple encore une fois, l’intitulé Voyageur 1 sera une variation, suivi de nom et prénom qui le seront aussi. Cela nous évite d’avoir à intervenir à toutes les étapes d’affichage et de lecture des items data, du panier ou d’une commande.

En effet, WooCommerce traite chaque item comme une valeur unique. Alors que dans notre cas l’item voyageur est défini par plusieurs valeurs (nom, prénom, et possiblement plein d’autres comme ‘enfant de moins de 12 ans, etc.)

En testant votre tunnel d’achat, en arrivant au panier, vous devriez avoir le listing des voyageurs qui apparaît. Certes il n’est surement pas mis en forme, mais au moins ça fonctionne. En allant jusqu’à la page de commande, vous verrez également le récapitulatif des données de la réservation.

Affichage des données voyageurs dans le panier
Affichage dans le panier…
Affichage des données voyageurs dans le panier
…jusqu’à la page de commande !

5- Mettre en forme l’affichage des données

En inspectant le code de votre panier vous découvrirez la structure HTML suivante :

Inspecteur d'élément navigateur Web

Par défaut, WooCommerce utilise un structure de liste de définitions <DL> avec les termes <DT> et les définitions <DD>. Vous remarquerez également qu’il attribue automatiquement à chaque terme et définition, une classe CSS formée du mot “variation” suivi de l’index que vous avez défini lors de l’enregistrement des données.

Cette structure est également utilisée pour l’affichage des données dans le mini panier, celui positionné dans les en-têtes de vos pages.

Mini panier WooCommerce

Ainsi, grâce à l’inspecteur d’éléments de votre navigateur vous pourrez rapidement identifier les sélecteurs CSS qui vous permettront de mettre en forme comme vous souhaitez ces affichages.

Je vous conseille d’ajouter systématique un sélecteur de classe ou un ID supplémentaire, afin de rendre prioritaire votre définition par rapport au fichier CSS original de WooCommerce. Voici pour exemple, le code que j’ai utilisé pour la mise en forme dans mon fichier main.css :

/** Affichage panier  **/
body dl.variation dt, dl.variation dd {
    float:left;
    padding:0 0.2em;
}
body dl.variation dt {
    clear:left;
    /*margin-top:0.4em;*/
}
body dl.variation p, body dl.variation dt, body dl.variation dd {
    margin:0;
}
body li.mini_cart_item span.quantity {
    display: block;
    float: right;
    margin-top: 1.2em;
}
body li.mini_cart_item dl.variation {
    width: 75%;
}
body li.mini_cart_item dl.variation dt.variation-Nom, body li.mini_cart_item dl.variation dt.variation-Prnom,
body .product-name dl.variation dt.variation-Nom, body .product-name dl.variation dt.variation-Prnom {
    padding-left:1.2em;
}

Personnaliser la structure HTML de l’affichage

Toutefois vous pouvez changer, personnaliser cette structure en vous appropriant le modèle de présentation proposé par WooCommerce.

Tous les modèles de mise en page se trouve dans le dossier du plugin WooCommerce. Ils sont classés dans le dossier template. Pour modifier ces modèles, il vous faut créer un dossier “woocommerce” à la racine de votre thème enfant, puis dupliquer les fichiers PHP des modèles que vous souhaitez modifier, tout en respectant la structure des dossiers dans lesquels ils sont classés.

Dans ce cas, nous aurions besoin de modifier le fichier cart-item-data.php, par la suite nous aurons besoin d’effectuer une modification du fichier cart.php, afin d’empêcher le changement de quantité à l’étape du panier.

Commencer par dupliquer ces deux fichiers pour obtenir la structure suivante dans votre thème enfant :

Structure des modèles CART WooCommerce
Duplication des modèles WooCommerce dans un thème enfant

Ci-dessus à gauche la structure dans le plugin WooCommerce, à droite la structure que vous devez créer dans votre thème enfant.

Une fois fait ouvrez le fichier cart-item-data.php pour découvrir ce qu’il contient, faire les modifications nécessaires à votre mise en page CSS et proposer un affichage équilibré et original.

Bloquer le changement de la quantité dans le panier

Jusqu’ici tout fonctionne plutôt bien, mais nous avons un problème au niveau du panier. En effet WooCommerce n’est pas fait pour de la réservation à la base, on est donc confronté à la possibilité de changer la quantité des produits/réservations lors du récapitulatif de notre panier.

On pourrait continuer à développer notre système à ce niveau là pour permettre la saisi de nouvelles données à cette étape, ou la suppression de certains voyageurs. Mais pour cette fois on va faire au plus simple.

Il nous faut simplement transformer le champ modifiable en texte simple, pour empêcher sa modification lors de la mise à jour du panier.
Ouvrez le fichier cart.php que vous avez dupliqué dans votre thème enfant. Les données du panier sont organisées dans une structure en tableau HTML. A partir de la ligne 103 vous trouverez la cellule qui traite la quantité :

<td class="product-quantity" data-title="<?php esc_attr_e( 'Quantity', 'woocommerce' ); ?>">
	<?php
	if ( $_product->is_sold_individually() ) {
		$product_quantity = sprintf( '1 <input type="hidden" name="cart[%s][qty]" value="1" />', $cart_item_key );
	} else {
		$product_quantity = woocommerce_quantity_input(
			array(
			'input_name'   => "cart[{$cart_item_key}][qty]",
			'input_value'  => $cart_item['quantity'],
			'max_value'    => $_product->get_max_purchase_quantity(),
			'min_value'    => '0',
			'product_name' => $_product->get_name(),
			),
		        $_product,
			false
		);
	}
        echo apply_filters( 'woocommerce_cart_item_quantity', $product_quantity, $cart_item_key, $cart_item ); // PHPCS: XSS ok.
	?>
</td>

En gros WooCommerce teste si le produit peut être vendu uniquement seul ou par plusieurs. Puis en fonction il prépare la variable $product_quantity pour son affichage par le filtre « woocommerce_cart_item_quantity ».

Nous allons donc nous servir de ce qui est fait et modifier ces lignes par les suivantes :

<td class="product-quantity" data-title="<?php esc_attr_e( 'Quantity', 'woocommerce' ); ?>">
	<?php
		$product_quantity = sprintf( $cart_item['quantity'].'<input type="hidden" name="cart[%s][qty]" value="'.$cart_item['quantity'].'" />', $cart_item_key );
		echo apply_filters( 'woocommerce_cart_item_quantity', $product_quantity, $cart_item_key, $cart_item ); // PHPCS: XSS ok.
	?>
</td>

Et voilà, on profite du code de l’affichage en mode « vendu seul » pour dynamiser le texte avec $cart_item[‘quantity’], on conserve le champs caché pour transmettre la données au cas où, et on nettoie la structure conditionnelle if() et on laisse l’usage du filtre pour l’affichage.

6- Enregistrer les données voyageurs à la commande

La fin est proche !

Il ne vous reste plus qu’à sauvegarder ces données voyageurs lorsque l’utilisateur va procéder au paiement et que WooCommerce transformera ce panier en commande définitivement.

Ainsi toutes nos données pourront être consultées en administration, dans l’espace de commande.

Ajouter une ligne d’item à l’objet de commande de WooCommerce

Nous allons utiliser le HOOK ‘woocommerce_checkout_create_order_line_item’ de woocommerce, qui permet d’appeler une fonction au moment où les éléments d’un panier sont ajoutés à une commande après avoir été validée.

add_action( 'woocommerce_checkout_create_order_line_item', 'afa_add_custom_order_line_item_meta',10,4 );

function afa_add_custom_order_line_item_meta($item, $cart_item_key, $values, $order)  {
    if(array_key_exists('voyageur', $values))      {
        $infos = unserialize($values['voyageur']);
        
        $cpt = 1;
        foreach($infos as $info) {
            $intitule = "Voyageur ".$cpt;
            $voyageur = '';
            foreach($info as $key => $val) {
                $voyageur .= "$key : $val ";
            } //fin foreach $info
            $item->add_meta_data($intitule,$voyageur);
            $cpt++;
        } //fin foreach $infos
    } //fin if()
} //fin fonction

Que se passe-t-il dans la fonction afa_add_custom_order_line_item_meta() ?

Testez une commande complète jusqu’à validation et paiement. Vous devriez avoir les affichages suivants lors du récapitulatif de commande de l’utilisateur, et dans l’espace de gestion des commandes en administration.

Affichage à la confirmation de commande
Détails de commande à la page confirmation pour l’acheteur
Affichage en backoffice
Détails de commande en backoffice

Et c’est tout pour ce WikiWeb. En espérant qu’il vous aura été utile. N’hésitez pas à me faire part de vos remarques et/ou améliorations.

Bibi.