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() ?
- Les variables passées en argument sont celles attendues et utilisées par le filtre auquel nous faisons appel. Cela nous permet de récupérer le tableau $cart_item_data pour y ajouter nos nouvelles données, ainsi que l’id du produit et l’id des variations, si il y en a.
- On intègre ensuite une structure conditionnelle if() pour s’assurer que le formulaire à bien été validé et que la variable $_REQUEST, qui contient nos données, existe.
- On en profite pour récupérer la quantité de produit commandée dans une variable $cpt, pour effectuer un comptage de voyageurs et créer une structure de tableaux imbriqués.
- On initialise le tableau $voyageur qui va accueillir ,dans chacun de ses index, un tableau contenant le nom et le prénom de chaque voyageur saisi.
- On effectue une boucle de comptage for() à partir de la valeur de la quantité et on affecte les valeurs à $voyageur en construisant son index à partir de $i.
- $i nous permet également d’interroger correctement la variable $_REQUEST, pour reconstituer fidèlement les index attendus des noms et prénoms voyageurs.
- Vous noterez que les valeurs saisies par l’utilisateur sont traitées par la fonction sanitize_text_field() qui sert à assainir les données en provenance de champs de formulaire ou de la base de données.
- Pour finir, nous mettons en série (fonction serialize() en PHP) les données de nos tableaux pour les sauvegarder dans une nouvelle case du tableau $cart_item_data, avant de le retourner dans le filtre.
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() ?
- La structure conditionnelle if() vérifie si l’index voyageur est bien présent dans les items de notre panier. C’est la variable tableau PHP $cart_item.
- Afin de traiter les données que nous avons stocker sous forme de tableau mis en série, nous allons recréer cette structure tableau via la fonction unserialize() de PHP, en l’affectant dans $custom_details.
- Il ne nous reste plus qu’à utiliser la fonction foreach() de PHP pour parcourir notre tableau voyageur et distribuer ses données dans $item_data qui est un tableau à une seule dimension, avant de le retourner.
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.
5- Mettre en forme l’affichage des données
En inspectant le code de votre panier vous découvrirez la structure HTML suivante :
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.
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 :
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() ?
- Même principe que les fonctions précédentes, on vérifie si l’index voyageur existe dans $values.
- On recrée notre tableau voyageur pour le parcourir et enregistrer successivement les lignes d’information de chaque voyageur dans la commande.
- On utilise une variable $cpt pour créer un compteur et utiliser sa valeur pour l’intitulé de nos lignes d’items de commande. Cette fois ci nous concaténerons les nom et prénom pour les enregistrer en une seule ligne. Cela aurait pu être fait lors de l’affichage du panier, mais au moins vous avez les deux aspects.
- L’enregistrement des lignes se fait grâce à l’objet $item et sa méthode $add_meta_data(), dans laquelle nous passons en argument l’intitulé de l’item et sa valeur.
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.
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.