In einem Shop-Projekt haben wir aus UX-Design-Gründen die beiden Seiten Warenkorb und Kasse auf einer zusammengefasst, so dass der Zahlungsprozess möglichst kurz gehalten werden kann. Auf der neuen Check-Out-Page kommt als Warenkorb die Woocommerce Mini-Cart zum Einsatz, da diese sowieso schon eingebaut war. Da diese Mini-Cart ihren Inhalt per AJAX empfängt, haben wir nun auch die Gutschein-Funktionalität per AJAX der Mini-Cart hinzugefügt.
1. Gutschein einlösen auf der Checkout-Seite
Zuerst fügen wir das Gutscheinformular an die gewünschte Stelle in der Checkout-Seite. Anstatt die Formularfelder für den Gutscheincode auf der Checkout-Seite direkt anzuzeigen, soll nur ein Hinweis mit Link erscheinen. Dafür kann die jQuery UI Dialog-Bibliothek von WordPress verwendet werden.
function ud_show_coupon_js() {
wc_enqueue_js('$("a.showcoupon").parent().hide();');
wc_enqueue_js('dialog = $("form.checkout_coupon").dialog({
autoOpen: false,
width: 381,
minHeight: 0,
modal: false,
appendTo: "#coupon-anchor",
position: { my: "left", at: "left", of: "#coupon-anchor"},
draggable: false,
resizable: false,
dialogClass: "coupon-special",
buttons: {}
});');
wc_enqueue_js('$("#show-coupon-form").click( function() {
if (dialog.dialog("isOpen")) {
$(".checkout_coupon").hide();
dialog.dialog( "close" );
} else {
$(".checkout_coupon").show();
dialog.dialog( "open" );
} // endif
return false;
});');
// apply coupon code via AJAX
wc_enqueue_js('$(".woocommerce-form-coupon .button").on("click", function() {
if( $( ".woocommerce-form-coupon #coupon_code").val() ) {
var coupon = $( ".woocommerce-form-coupon #coupon_code").val();
data = {
action: "apply_coupon_code",
coupon_code: coupon,
security: "' . wp_create_nonce("ajax_nonce") . '",
do_what: "apply"
};
$.ajax({
type: "POST",
url: wc_add_to_cart_params.ajax_url,
dataType: "html",
data: data,
success: function (response) {
$(".cart_list.product_list_widget").html(response);
},
error: function (errorThrown) {
$(".cart_list.product_list_widget").html(errorThrown);
}
});
} // endif
});');
// remove coupon code via AJAX
wc_enqueue_js('$( ".woocommerce-checkout" ).on( "click", ".remove-coupon", function(event) {
event.preventDefault();
var coupon = $(this).attr("data-coupon");
data = {
action: "apply_coupon_code",
coupon_code: coupon,
security: "' . wp_create_nonce("ajax_nonce") . '",
do_what: "remove"
};
$.ajax({
type: "POST",
url: wc_add_to_cart_params.ajax_url,
dataType: "html",
data: data,
success: function (response) {
$(".cart_list.product_list_widget").html(response);
},
error: function (errorThrown) {
$(".cart_list.product_list_widget").html(errorThrown);
}
});
});');
}
add_action('woocommerce_before_checkout_form', 'ud_show_coupon_js');
Falls die UI-Dialog-Bibliothek fehlen sollte, dann kann diese über die functions.php
eingebunden werden:
function ud_scripts() {
wp_enqueue_script('jquery-ui-dialog');
}
add_action('wp_enqueue_scripts', 'ud_scripts');
Ausführlich ist das Hinzufügen des Gutscheinformulars im Artikel «How To Move WooCommerce Coupon Field in Checkout Page» von Owais Alam beschrieben.
Der Hinweis mit Gutscheincode-Link fügen wird per Hook woocommerce_checkout_after_customer_details
ein. Soll der Link an einer anderen Stelle erscheinen, dann ist einfach ein anderer Hook oder Filter zu verwenden:
function ud_show_coupon() {
global $woocommerce;
if ($woocommerce->cart->needs_payment()) {
echo '<div class="gutschein">Sie haben einen Gutschein? <a href="#" id="show-coupon-form">Gutscheincode eingeben</a>.</div><div id="coupon-anchor"></div>';
}
}
add_action('woocommerce_checkout_after_customer_details', 'ud_show_coupon');
Das Eingabefeld für den Gutscheincode wird dabei erst nach angeklicktem Link «Gutscheincode eingeben» angezeigt:
2. Gutschein via AJAX hinzufügen
Das war der Teil um die Eingabe des Gutscheincodes auf der Checkout-Seite per UI Dialog zu implementieren. Im nächsten Schritt soll der Gutscheincode angewandt, sowie das Total erneut berechnet werden, ohne dass die ganze Checkout-Seite geladen werden muss. Dazu holen wir per jQuery den Gutscheincode vom Eingabefeld und übergeben diesen via AJAX an WordPress. War der Aufruf erfolgreich, wird die Mini-Cart mit eingelöstem Gutschein zurückgegeben:
$(".woocommerce-form-coupon .button").on("click", function() {
if( $( ".woocommerce-form-coupon #coupon_code").val() ) {
var coupon = $( ".woocommerce-form-coupon #coupon_code").val();
data = {
action: "apply_coupon_code",
coupon_code: coupon,
security: "<?php wp_create_nonce('ajax_nonce'); ?>",
do_what: "apply"
};
$.ajax({
type: "POST",
url: wc_add_to_cart_params.ajax_url,
dataType: "html",
data: data,
success: function (response) {
$(".cart_list.product_list_widget").html(response);
},
error: function (errorThrown) {
$(".cart_list.product_list_widget").html(errorThrown);
}
});
} // endif
});
2.1 Gutschein via AJAX entfernen
Der Gutschein soll per AJAX wieder entfernt werden können. Dafür hängen wir dem «Gutschein entfernen»-Link mit der Klasse .remove-coupon
per Event-Handler eine AJAX-Funktion an:
$( ".woocommerce-checkout" ).on( "click", ".remove-coupon", function(event) {
event.preventDefault();
var coupon = $(this).attr("data-coupon");
data = {
action: "apply_coupon_code",
coupon_code: coupon,
security: "<?php wp_create_nonce('ajax_nonce'); ?>",
do_what: "remove"
};
$.ajax({
type: "POST",
url: wc_add_to_cart_params.ajax_url,
dataType: "html",
data: data,
success: function (response) {
$(".cart_list.product_list_widget").html(response);
},
error: function (errorThrown) {
$(".cart_list.product_list_widget").html(errorThrown);
}
});
});
Auf Seite WordPress wird der Gutscheincode mit WC()->cart->apply_coupon($coupon_code);
hinzugefügt und mit WC()->cart->remove_coupon($coupon_code);
entfernt. Dafür ist die Abfrage des Werts von do_what
verantwortlich. Das Total soll neu gerechnet und die Mini-Cart mit woocommerce_mini_cart();
ausgegeben werden. Dafür sind die Hooks wp_ajax_apply_coupon_code
und wp_ajax_nopriv_apply_coupon_code
zuständig:
function ud_apply_coupon_code() {
if ( ! wp_verify_nonce($_POST['security'], 'ajax_nonce') ) {
wp_die();
} // endif
$do_what = $_POST['do_what'];
$coupon_code = isset( $_POST['coupon_code'] ) ? $_POST['coupon_code'] : '';
if ( $do_what == 'apply' ) {
WC()->cart->apply_coupon( $coupon_code );
} elseif ( $do_what == 'remove' ) {
WC()->cart->remove_coupon( $coupon_code );
} // endif
WC()->cart->calculate_totals();
woocommerce_mini_cart();
wp_die();
}
add_action( 'wp_ajax_apply_coupon_code', 'ud_apply_coupon_code' );
add_action( 'wp_ajax_nopriv_apply_coupon_code', 'ud_apply_coupon_code' );
Als nächstes muss noch das Template mini-cart.php entsprechend angepasst werden. Um die Änderungen beim nächsten WooCommerce Update nicht zu verlieren, ist vor der Anpassung die Template-Datei erst in das entsprechende Verzeichnis /themes/child-theme/woocommerce/cart/
zu kopieren.
Beim gemachten Beispiel soll der «remove Coupon»-Link am gleichen Ort wie bei den Produkten erscheinen:
Dem Mini-Cart Template fügen wir deshalb ein weiteres Listenelement mit Ausgabe der einzulösenden Gutscheine hinzu. Für den AJAX-Request ist die Klasse «remove-coupon» und das Attribut «data-coupon» des Links ausschlaggebend:
<li class="mini_cart total"><span>Total</span><span><?php echo $subtotal; ?></span></li>
<?php
// START Gutscheine ausgeben
foreach ( WC()->cart->get_coupons() as $code => $coupon ) : ?>
<li class="checkout coupon">
<span><a href="<?php echo esc_url( wc_get_checkout_url() ); ?>?remove_coupon=<?php echo esc_attr( sanitize_title( $code ) ); ?>" data-coupon="<?php echo esc_attr( sanitize_title( $code ) ); ?>" class="remove-coupon"><i class="far fa-plus-circle"></i></a>Gutschein: <?php echo esc_attr( sanitize_title( $code ) ); ?></span>
<span><?php wc_cart_totals_coupon_html( $coupon ); ?></span>
</li>
<?php
endforeach;
// END Gutscheine ausgeben ?>
<li class="checkout total"><span>Total</span><span>CHF <?php echo $betrag; ?></span></li>
<li class="checkout taxes"><span> </span><span><?php echo $mwst_eintrag; ?></span></li>
Da wir den Entfernen-Link an einer anderen Position ausgeben, entfernen wir die Default-Ausgabe des Links per Filter woocommerce_cart_totals_coupon_html
:
function ud_filter_woocommerce_cart_totals_coupon_html( $coupon_html, $coupon, $discount_amount_html ) {
// entferne den remove-Link, da dieser im Template mini-cart.php hinzugefügt
$coupon_html = $discount_amount_html;
return $coupon_html;
}
add_filter( 'woocommerce_cart_totals_coupon_html', 'ud_filter_woocommerce_cart_totals_coupon_html', 10, 3 );