Tutorial: Hoe Woocommerce shopping cart aan te passen dmv hooks of override

In deze tutorial wil ik graag laten hoe zien hoe eenvoudig het is om in WordPress en Woocommerce functionaliteit toe te voegen dmv “hooks”.
Hooks bieden een eenvoudige en elegante methode om functionaliteit toe te voegen.

Woocommerce is een zeer populaire plugin die gebruikt word voor het beheren van webshops.

Hoe voeg je je nieuwe functionaliteit toe zonder het gevaar dat deze door een update word overschreven?”

Deze tutorial is vooral interessant voor diegenen die :

  • webshop beheerders die graag aanpassingen zien op hun website
  • code snippets kunnen lezen en begrijpen
  • functionaliteit van wordpress / woocommerce wil uitbreiden en deze wil behouden na een
    update
  • een beter begrip van hooks willen krijgen


Verzekering aanbieden bij de boodschappenwagen

Als voorbeeld zal ik een aanpassing gebruiken die ik voor een
webshop (online meubel verkoop) heb ontwikkeld. Zij wilden graag zien dat er bij de shopping cart een verzekering werd aangeboden.De hoogte van deze verzekering hing weer af van het totaal op dat moment in shopping cart.

Puntsgewijs de omschrijving :

  1. toevoegen van een drietal verzekerings producten producten in Woocommerce. Ieder product met dezelfde naam maar met een verschillende prijs. Daarbij voeg ik nog bij de prijs bandbreedte waar deze verzekering voor geld.
  2. via een wp “hook
    1. ophalen van alle verzekeringsproducten
    2. totaal ophalen van de boodschappenwagen ophalen ex BTW
    3. Selectie van de juiste verzekering op basis van dat totaal
    4. Een extra tabel  (HTML) toevoegen aan de shopping cart met het aanbod van die verzekering
  3. als de klant op ‘TOEVOEGEN klikt via een ajax / api call server-side het betreffende product toevoegen aan de cart
  4. server-side toevoegen van de verzekering aan de boodschappenwagen.
  5. opnieuw laden van de pagina (JQuery).
  6. de pagina met de aangepaste cart is nu in beeld.
  7. overige aanpassingen om ongewenste effecten van bovenstaande handelingen ongedaan te maken Bijvoorbeeld het voorkomen van de verzekeringsproducten ook in de webshop zichtbaar zijn

1. Toevoegen van een drietal producten in Woocommerce

Dit is heel eenvoudig om te doen. In dit geval hebben de drie producten dezelfde naam en heeft is alleen de prijs verschillend. Als voorbeeld gebruik ik hier €25, €30 en €35 euro.
Daarnaast moet er voor elk product 2 “custom fields” worden toegevoegd. Een “minimum_price” en een “maximum_price”. Deze geven bandbreedte weer voor de prijs van de verzekering :

  1. Verzekering “A” : 0 tot 50
  2. Verzekering “B” : 50 tot 100
  3. Verzekering “C” : 100 en meer (In casu heb ik 10.000 ingevuld).

Wat verder nog moest gebeuren is om te voorkomen dat deze producten in de webshop zichtbaar zijn , een extra categorie toegevoegd en deze dmv CSS (display:none) onzichtbaar gemaakt.

Creeëren van de plugin:

Om te voorkomen dat het aanbod van de verzekering verdwijnt na een update van
wordpress, het thema of Woocommerce staat alle code in een plugin.

Maak een folder “woocommerce_insurance_addon” in de plugins directory aan en zet daarin “woocommerce_insurance_addon.php” met de volgende code:

/*
Plugin Name: Woocommerce Insurance Add On
Description: module with a selected insurance depending on the cart's value
Version: 0.1
License: GPL
Author: Martijn Wip
Author URI: http://www.martijnwip.nl
*/
//Add the isurance to the product page
//Omdat we de Woocommerce API nodig hebben moeten we er zeker van zijn dat deze is geladen
add_action( 'plugins_loaded', 'wooinsurance_constructor_plugin', 11 );
function wooinsurance_constructor_plugin(){
//magic will happen here
}

Wat we ook al kunnen doen is het laden van een javascript bestand en stylsheet die we nodig hebben.
Zet deze in ‘assets’ welke we weer in woocommerce_insurance_addon folder zetten.

//we need javascript and css
function add_insurance_scripts(){
wp_enqueue_style( 'insurance', plugins_url( '/woocommerce_insurance_addon/assets/insurance.css') );
wp_enqueue_script( 'mooradian-insurance', plugins_url( '/woocommerce_insurance_addon/assets/insurance.js'), array(), '20130140', true );
}
add_action( 'wp_enqueue_scripts', 'add_insurance_scripts' );

2. via een hook het totaal ophalen van de cart

Het belangrijkste is om te bepalen welke hook gaan we gebruiken?
Dit is altijd wel een beetje en doolhof en een heuse queeste!

Zoals ik al zei wil de webshop eigenaar zien dat er onder de shopping cart een extra
tabel komt met daarin de aanbieding van de verzekering.

Als we de broncode van een pagina met boodschappen wagen kijken met daarin bijvoorbeeld één product, dan zien we dat het product in een table zit met de class “shop_table” en “cart”. Laten we eens gaan kijken in de bronbestanden van Woocommerce waar deze class zoal voorkomt om te kijken of we daar ‘custom hooks’ kunnen vinden.

Een snelle blik in de directory van woocommerce laat al zien dat daar een template voor de cart staat in templates/cart/cart.php

Open dit bestand en zoek op “shop_table”. Hier is de tabel van de shopping cart.
Scroll wat verder naar beneden om te kijken waar de tabel word afgesloten :

Daar vinden we de hook ‘woocommerce_after_cart_table’.

Dit is de ideale hook om de nieuwe tabel toe te voegen!

dus:

//add the action to add the HTML for the insurance module
add_action("woocommerce_after_cart_table","add_insurance_offer");
/*
* Method for adding an insurance to the cart page
*/
function add_insurance_offer(){
//magic happens here
}

A. Het ophalen van de verzekeringsproducten:

//first get products from insurance category
$args = array(
'post_type' => 'product',
//'product_cat' => 'insurance',
'post_status' => 'publish'
);
$insurance_products = query_posts($args);

B. Vervolgens het totaal ophalen van de boodschappenwagen ophalen ex BTW.:
Alle data van Woocommerce kunnen via de global worden opgehaald.

//Deze methode haalt de nummerieke waarde op van het subtotal.
//Dus geen toegvoegde euro tekens e.d. die get_cart_subtotal teruggeeft
//Zie https://docs.woothemes.com/wc-apidocs/source-class-WC_Cart.html#48-49
$cart_sub_total = $woocommerce->cart->subtotal;

C. Selectie van de juiste verzekering op basis van dat totaal:

Nu kunnen we de custom fields gebruiken die bij punt 1 aan het product zijn toegevoegd en
ingevuld:

  1. loop door de verzekeringsproducten
  2. haal van ieder product de onder en de bovengrens op
  3. Zodra er aan een voorwaarde word voldaan hebben we de juiste verzekering te pakken
//first get products from insurance category
$args = array(
'post_type' => 'product',
'product_cat' => 'insurance',
'post_status' => 'publish'
);
$insurance_products = query_posts($args);
//we need to acces woocomerce
global $woocommerce;
//now get total price of shopping cart
//subtotal is total without tax
$cart_sub_total = $woocommerce->cart->subtotal;
//we need
if(isset($cart_sub_total)){
//loop throug insurances
foreach($insurance_products as $insurance){
//get the minimum and the maximum from the custom fields
$minimum = intval(get_post_custom_values('minimum_price',$insurance->ID)[0]);
$maximum = intval(get_post_custom_values('maximum_price',$insurance->ID)[0]);
//catch the range
if($cart_sub_total > $minimum && $cart_sub_total <= $maximum){ //if($cart_sub_total > $minimum){
//return the product
$selected_insurance = $insurance;
// we can break the loop now
break;
}
}
}
?>
<table class="insurance_table cart" cellspacing="0">
<thead>
<tr>
<th class="product-name"><?php _e( 'Verzekering', 'woocommerce' ); ?></th>
<th class="product-price"><?php _e( 'Prijs', 'woocommerce' ); ?></th>
<th class="product-price"><?php _e( 'Toevoegen', 'woocommerce' ); ?></th>
</tr>
</thead>
<tr>
<td class="product-name" ><?php echo $selected_insurance->post_name; ?></td>
<td class="product-price"><?php echo get_post_meta( $selected_insurance->ID, '_regular_price')[0]; ?></td>
<td><button class="add_insurance" data-product-id="<?php echo $selected_insurance->ID; ?>">VOEG TOE</button></td>
</tr>
</table>

3.  Als de klant op ‘TOEVOEGEN klikt

Het serverside script bestaat uit 2 delen

  1. De pagina voor de API endpoint. Voor dit voorbeeld is dit een heel basic script. Voor degene die willen kunnen daar
    nog een foutafhandeling e.d. erin zetten. Voeg dit .php bestand toe aan je thema. Maak daarna een pagina met de titel
    ‘add insurance backend page’ en als template selecteer je ‘Add Insurance Backend Page’
  2. De functie om de verzekering toe te voegen. Deze zet je in je plugin.

Code voor de template:

/*
/*
* Template Name: Add Insurance Backend Page
*
* The template for adding an insurance product serverside
*/
$insurance_id = $_POST['insurance_id'];
wooinsurance_add_product_to_cart( $insurance_id );
$insurance .= 'now added to cart';
$data = array( 'result' => $insurance);
header('Content-Type: application/json');
echo json_encode($data);

Functie in de plugin:

function wooinsurance_add_product_to_cart( $product_id ) {
if ( ! is_admin() ) {
$found = false;
//check if product already in cart
if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->id == $product_id )
$found = true;
}
// if product not found, add it
if ( ! $found )
WC()->cart->add_to_cart( $product_id );
} else {
// if no products in cart, add it
WC()->cart->add_to_cart( $product_id );
}
}
}

Dan zetten we in “insurance.js” die we in het begin al hebben gemaakt:

jQuery(document).ready(function($) {
$( ".add_insurance").click(function(event) {
//cancel the default button event
event.preventDefault();
jQuery.ajax({
type: "POST",
url: "../add-insurance-backend-page",
dataType: "html",
data: "insurance_id=" + $(this).attr("data-product-id") ,
success: function (response) {
//trigger update cart button
$( ".button" ).trigger( "click" );
},
error: function (xhr, ajaxOptions, thrownError) {
console.log(xhr.status);
console.log(thrownError);
}
});
});
});

De routine is af en helemaal rond.
Doordat alle functionaliteit (muv van API endpoint) in een plugin staat
word deze na een update niet overschreven.

Override:
Wat ook zou kunnen is om ipv een hook de cart.php te ‘overriden’.
Dit heeft Woocommerce heel netjes geregeld.
Zet in je thema folder het volgende bestand “woocommerce/cart/cart.php”

Nu kun je nieuwe tabel in cart.php zetten bijvoorbeeld voor
“woocommerce_after_cart_table” hook (niet getest)

</table>
<!-- add the insurance -->
<?php
//first get products from insurance category
$args = array(
'post_type' => 'product',
'product_cat' => 'insurance',
'post_status' => 'publish'
);
$insurance_products = query_posts($args);
//we need to acces woocomerce
global $woocommerce;
//now get total price of shopping cart
//subtotal is total without tax
$cart_sub_total = $woocommerce->cart->subtotal;
//we need
if(isset($cart_sub_total)){
//get_post_custom_values($key, $post_id);
//loop throug insurances
foreach($insurance_products as $insurance){
//get the minimum and the maximum from the custom fields
$minimum = intval(get_post_custom_values('minimum_price',$insurance->ID)[0]);
$maximum = intval(get_post_custom_values('maximum_price',$insurance->ID)[0]);
//catch the range
if($cart_sub_total > $minimum && $cart_sub_total <= $maximum){
//if($cart_sub_total > $minimum){
//return the product
$selected_insurance = $insurance;

// we can break the loop now
break;
}
}
}
?>
<table class="insurance_table cart" cellspacing="0">
<thead>
<tr>
<th class="product-name"><?php _e( 'Verzekering', 'woocommerce' ); ?></th>
<th class="product-price"><?php _e( 'Prijs', 'woocommerce' ); ?></th>
<th class="product-price"><?php _e( 'Toevoegen', 'woocommerce' ); ?></th>
</tr>
</thead>
<tr>
<td class="product-name" ><?php echo $selected_insurance->post_name; ?></td>
<td class="product-price"><?php echo get_post_meta( $selected_insurance->ID, '_regular_price')[0]; ?></td>
<td><button class="add_insurance" data-product-id="<?php echo $selected_insurance->ID; ?>">VOEG TOE</button></td>
</tr>
</table>
<!-- end of add the insurance -->
<?php do_action( 'woocommerce_after_cart_table' ); ?>
</form>
<div class="cart-collaterals">
<?php do_action( 'woocommerce_cart_collaterals' ); ?>

Ook op deze manier word je code door een update niet overschreven.



Comments

comments