Skip to content

Instantly share code, notes, and snippets.

@zainaali
Last active April 15, 2019 18:47
Show Gist options
  • Save zainaali/c355a2b27a191daac72c16afb75b98fe to your computer and use it in GitHub Desktop.
Save zainaali/c355a2b27a191daac72c16afb75b98fe to your computer and use it in GitHub Desktop.
WooCommerce: Allow adding multiple products and set price to the cart via the add-to-cart query string
application/x-httpd-php functions.php ( PHP script, ASCII text )
<?php
/**
*
* 1. Bond Only - Expedia, Direct, HomeAway
* https://readysethost.co/checkout/?add-to-cart=772:1:2.00&rcode=TST2&fname=Mike&lname=Aubor&email=damiike%40gmail.com
* 2. Booking Only - Booking.com, Direct, HomeAway
* https://readysethost.co/checkout/?add-to-cart=1334:1:1.00&rcode=TST2&fname=Mike&lname=Aubor&email=damiike%40gmail.com
* 3. Booking Deposit Only - Direct, HomeAway
* https://readysethost.co/checkout/?add-to-cart=1437:1:1.00&rcode=TST2&fname=Mike&lname=Aubor&email=damiike%40gmail.com
* 4. Booking Deposit and Bond
* https://readysethost.co/checkout/?add-to-cart=1437:1:1.00,772:1:2.00&rcode=TST2&fname=Mike&lname=Aubor&email=damiike%40gmail.com
* 5. Reservation and Bond - Direct, HomeAway
* https://readysethost.co/checkout/?add-to-cart=1334:1:1.00,772:1:2.00&rcode=TST2&fname=Mike&lname=Aubor&email=damiike%40gmail.com
*
* Functions:
* A. Multiple Products - DONE
* B. Custom Price for multiple products - DONE
* C.1. Custom Billing Field - DONE
* C.2. Custom Billing Field in Orders - DONE
* D. Force 3D secure on optional cards - DONE
* E. Order status code - DONE
* F. Hidden billing fields - DONE
* G. Skip cart - DONE
* H. Hide order notes - DONE
* J. Custom fields to checkout - DONE
* K. Hide checkout add-to-cart message - DONE
* L. Thank you redirect
* M. 3D secure card check
* N. Clear cart parameter
* /
/**
* C.2. Custom Billing Field in Orders
*/
add_action( 'woocommerce_admin_order_data_after_billing_address', 'wc_custom_checkout_field_display_admin_order_meta', 10, 1 );
function wc_custom_checkout_field_display_admin_order_meta($order){
echo '<p><strong>'.__('Reservation Code').':</strong> ' . get_post_meta( $order->id, 'billing_reservationcode', true ) . '</p>';
}
add_action( 'woocommerce_checkout_update_order_meta', 'wc_custom_checkout_field_update_order_meta' );
function wc_custom_checkout_field_update_order_meta( $order_id ) {
if ( ! empty( $_POST['billing_reservationcode'] ) ) {
update_post_meta( $order_id, 'billing_reservationcode', sanitize_text_field( $_POST['billing_reservationcode'] ) );
}
}
/**
* D. Force 3D secure on optional cards
*/
add_filter( 'wc_stripe_require_3ds', '__return_true' );
/**
* F. Hidden billing fields
*/
add_filter( 'woocommerce_checkout_fields', 'remove_checkout_fields', 9999 );
function remove_checkout_fields( $woo_checkout_fields_array ) {
// unset( $woo_checkout_fields_array['billing']['billing_first_name'] );
// unset( $woo_checkout_fields_array['billing']['billing_last_name'] );
unset( $woo_checkout_fields_array['billing']['billing_phone'] );
// unset( $woo_checkout_fields_array['billing']['billing_email'] );
unset( $woo_checkout_fields_array['order']['order_comments'] );
// and to remove the fields below
unset( $woo_checkout_fields_array['billing']['billing_company'] );
unset( $woo_checkout_fields_array['billing']['billing_country'] );
unset( $woo_checkout_fields_array['billing']['billing_address_1'] );
unset( $woo_checkout_fields_array['billing']['billing_address_2'] );
unset( $woo_checkout_fields_array['billing']['billing_city'] );
unset( $woo_checkout_fields_array['billing']['billing_state'] );
unset( $woo_checkout_fields_array['billing']['billing_postcode'] );
return $woo_checkout_fields_array;
}
/**
* G. Skip cart
*/
add_filter ('add_to_cart_redirect', 'redirect_to_checkout');
function redirect_to_checkout() {
return WC()->cart->get_checkout_url();
}
/**
* H. Hide order notes
*/
add_filter('woocommerce_enable_order_notes_field', '__return_false');
/**
* K. Hide checkout add-to-cart message
*/
add_filter( 'wc_add_to_cart_message_html', '__return_false' );
/*
* A. Multiple products
*/
function woocommerce_maybe_add_multiple_products_to_cart( $url = false ) {
// if( !empty( $_REQUEST['add-to-cart'] ) && false === strpos( $_REQUEST['add-to-cart'], ',' ) ){
// return WC_Form_Handler::add_to_cart_action( $url );
// }
// Make sure WC is installed, and add-to-cart qauery arg exists, and contains at least one comma.
if ( ! class_exists( 'WC_Form_Handler' ) || empty( $_REQUEST['add-to-cart'] ) || false === strpos( $_REQUEST['add-to-cart'], ',' )){
return;
}
// Remove WooCommerce's hook, as it's useless (doesn't handle multiple products).
remove_action( 'wp_loaded', array( 'WC_Form_Handler', 'add_to_cart_action' ), 20 );
$product_ids = explode( ',', $_REQUEST['add-to-cart'] ); //var_dump($product_ids); exit;
$count = count( $product_ids );
$number = 0;
$skip_url = site_url( '/thank-you/', 'https' ); //Thank you page
if ( isset( $_GET['fname'] ) ) {
$fname = isset( $_GET['fname'] ) ? esc_attr( $_GET['fname'] ) : '';
}
if (isset( $_GET['lname'] )) {
$lname = isset( $_GET['lname'] ) ? esc_attr( $_GET['lname'] ) : '';
}
if (isset( $_GET['email'] )) {
$email = isset( $_GET['email'] ) ? esc_attr( $_GET['email'] ) : '';
}
if (isset( $_GET['rcode'] )) {
$rcode = isset( $_GET['rcode'] ) ? esc_attr( $_GET['rcode'] ) : '';
}
/*if (isset ($_GET['skip'] )) {
$skip = isset( $_GET['skip'] ) ? esc_attr( $_GET['skip'] ) : '';
if (!empty($skip)) {
wp_redirect($skip_url);
}
}*/
// Set the session data
WC()->session->set( 'custom_data', array( 'fname' => $fname, 'lname' => $lname, 'email' => $email, 'rcode' => $rcode) );
foreach ( $product_ids as $id_and_quantity ) { //var_dump($id_and_quantity); exit;
// Check for quantities defined in curie notation (<product_id>:<product_quantity>)
// https://dsgnwrks.pro/snippets/woocommerce-allow-adding-multiple-products-to-the-cart-via-the-add-to-cart-query-string/#comment-12236
$id_and_quantity = explode( ':', $id_and_quantity );
$product_id = $id_and_quantity[0];
$product_price = $id_and_quantity[2];
//var_dump(round($product_price));
if(round($product_price) <= 0 ){
continue;
}
$_REQUEST['quantity'] = ! empty( $id_and_quantity[1] ) ? absint( $id_and_quantity[1] ) : 1;
if ( ++$number === $count ) {
// Ok, final item, let's send it back to woocommerce's add_to_cart_action method for handling.
$_REQUEST['add-to-cart'] = $product_id;
return WC_Form_Handler::add_to_cart_action( $url );
}
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $product_id ) );
$was_added_to_cart = false;
$adding_to_cart = wc_get_product( $product_id );
if ( ! $adding_to_cart ) {
continue;
}
$add_to_cart_handler = apply_filters( 'woocommerce_add_to_cart_handler', $adding_to_cart->get_type(), $adding_to_cart );
// Variable product handling
if ( 'variable' === $add_to_cart_handler ) {
woo_hack_invoke_private_method( 'WC_Form_Handler', 'add_to_cart_handler_variable', $product_id );
// Grouped Products
} elseif ( 'grouped' === $add_to_cart_handler ) {
woo_hack_invoke_private_method( 'WC_Form_Handler', 'add_to_cart_handler_grouped', $product_id );
// Custom Handler
} elseif ( has_action( 'woocommerce_add_to_cart_handler_' . $add_to_cart_handler ) ){
do_action( 'woocommerce_add_to_cart_handler_' . $add_to_cart_handler, $url );
// Simple Products
} else {
woo_hack_invoke_private_method( 'WC_Form_Handler', 'add_to_cart_handler_simple', $product_id );
}
}
}
// Fire before the WC_Form_Handler::add_to_cart_action callback.
add_action( 'wp_loaded', 'woocommerce_maybe_add_multiple_products_to_cart', 15 );
/**
* Invoke class private method
*
* @since 0.1.0
*
* @param string $class_name
* @param string $methodName
*
* @return mixed
*/
function woo_hack_invoke_private_method( $class_name, $methodName ) {
if ( version_compare( phpversion(), '5.3', '<' ) ) {
throw new Exception( 'PHP version does not support ReflectionClass::setAccessible()', __LINE__ );
}
$args = func_get_args();
unset( $args[0], $args[1] );
$reflection = new ReflectionClass( $class_name );
$method = $reflection->getMethod( $methodName );
$method->setAccessible( true );
$args = array_merge( array( $reflection ), $args );
return call_user_func_array( array( $method, 'invoke' ), $args );
}
/**
* J. Autofill check-out
*/
// Autofill checkout fields from user data saved in Woocommerce session
add_filter( 'woocommerce_billing_fields' , 'prefill_billing_fields', 99999 );
function prefill_billing_fields ( $address_fields ) {
// Get the session data
$data = WC()->session->get('custom_data');
// First Name
if( isset($data['fname']) && ! empty($data['fname']) )
$address_fields['billing_first_name']['default'] = $data['fname'];
// Last Name
if( isset($data['lname']) && ! empty($data['lname']) )
$address_fields['billing_last_name']['default'] = $data['lname'];
//var_dump( $data['lname']);exit;
// Email
if( isset($data['email']) && ! empty($data['email']) )
$address_fields['billing_email']['default'] = $data['email'];
// reservationcode
if( isset($data['rcode']) && ! empty($data['rcode']) )
$address_fields['billing_reservationcode']['default'] = $data['rcode'];
return $address_fields;
}
/**
* C.1. Custom Billing Field
*/
add_filter( 'woocommerce_billing_fields' , 'wc_custom_fields' );
function wc_custom_fields( $fields ) {
$fields['billing_reservationcode'] = array(
'type' => 'text',
'required' => true,
'class' => array('reservationcode'),
'label' => 'Reservation Code',
'label_class' => 'reservation-code'
);
return $fields;
}
/*
* J. Autofill check-out
*/
// Get the custom "amount" from URL and save it as custom data to the cart item
add_filter( 'woocommerce_add_cart_item_data', 'add_pack_data_to_cart_item_data', 20, 2 );
function add_pack_data_to_cart_item_data( $cart_item_data, $product_id ){
if( ! isset($_GET['add-to-cart']) )
return $cart_item_data;
$amount = esc_attr( $_GET['add-to-cart'] );
if( empty($amount) )
return $cart_item_data;
// Set the custom amount in cart object
$products = explode( ',', $_GET['add-to-cart'] );
$count = count( $products );
foreach ($products as $product) {
$id_and_quantity = explode( ':', $product );
if ($product_id == $id_and_quantity[0]) {
$cart_item_data['custom_price'] = $id_and_quantity[2];
}
}
return $cart_item_data;
}
/*
* B. Custom Price for multiple products
*/
// Alter conditionally cart item price based on product ID and custom registered "amount"
add_action( 'woocommerce_before_calculate_totals', 'change_conditionally_cart_item_price', 30, 1 );
function change_conditionally_cart_item_price( $cart ) {
if ( is_admin() && !defined('DOING_AJAX') )
return;
// HERE set your targeted product ID
foreach ( $cart->get_cart() as $cart_item ) {
// Checking for the targeted product ID and the registered "amount" cart item custom data to set the new price
//$cart_item['data']->get_id() == $targeted_product_id &&
if( isset($cart_item['custom_price']) )
$cart_item['data']->set_price($cart_item['custom_price']);
}
}
/*
* E. Order status code
*/
//Method to set order status failed or completed based on Stripe 3D.
add_action( 'wc_gateway_stripe_process_response', 'prefix_wc_gateway_stripe_process_response', 20, 2 );
function prefix_wc_gateway_stripe_process_response( $response, $order ){
if($response->source->type == 'three_d_secure'){
$order->update_status('completed', 'order_note');
}elseif($response->source->type == 'card'){
$order->update_status('failed', 'order_note');
}
}
/*
* L. Thank you redirect
*/
add_action( 'woocommerce_thankyou', 'bbloomer_redirectcustom');
function bbloomer_redirectcustom( $order_id ){
$order = new WC_Order( $order_id );
$url = site_url( '/orders/thank-you/', 'https' ); //Thank you page
$mem_url = site_url( '/orders/next-step/', 'https' ); // denied page
/*if ( $order->status == 'failed' ) {
wp_redirect($mem_url);
}
else{
wp_redirect($url);
}*/
if ( $order->get_payment_method() == 'bacs') {
wp_redirect($bacs_url);
}
else {
if ( $order->status == 'failed' ) {
wp_redirect($mem_url);
}
else{
wp_redirect($url);
}
}
}
/*
* M. 3D secure card check
*/
add_filter('wc_stripe_generate_payment_request', 'prefix_wc_stripe_generate_payment_request', 20, 3);
function prefix_wc_stripe_generate_payment_request($post_data, $order, $prepared_source){
$data = WC()->session->get('custom_data');
$post_data['statement_descriptor'] = 'RSH ' . $data['rcode'];
$post_data['description'] = 'RSH ' . $data['rcode'];
if($response->source_object->type != 'three_d_secure'){
//$prepared_source->source_object->status = 'canceled';
$post_data['capture'] = 'false';
//WC_Stripe_Logger::log( 'wc_stripe_generate_payment_request canceled: ' . print_r( $prepared_source->source_object->status, true ) );
}
//WC_Stripe_Logger::log( 'wc_stripe_generate_payment_request response: ' . print_r( $prepared_source, true ) );
//WC_Stripe_Logger::log( 'post_data response: ' . print_r( $post_data, true ) );
return $post_data;
}
add_action('init', 'skip_param');
function skip_param(){
if($_GET['skip'] == 'T'){
$skip_url = site_url( '/thank-you/', 'https' ); //Thank you page
wp_redirect($skip_url);
exit();
}
}
/*
* N. Clear cart parameter
*/
/*empty cart if user come to homepage*/
add_action( 'init', 'woocommerce_clear_cart_url' );
function woocommerce_clear_cart_url() {
if ( isset( $_GET['clear-cart'] ) ) {
global $woocommerce;
$woocommerce->cart->empty_cart();
$skip_url = site_url( '/orders/clear/', 'https' );
wp_redirect($skip_url);
exit();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment