I'm building webpage on WP and Woocommerce - I would like to skip cart and also checkout page for free products (or products which ID-s I can specify). These products are free and virtual (no payment needed, no shipping needed). The webpage is only used by registered users - so all the customer info is present.
The result I would like to have is that if you press ORDER button on product page - the order is done and customer is redirected to Thank-You page.
BR,
Kaspar
I applied the same concept, but found a major issue when processing order on the checkout; fields were still required.
The primary issue was processing the order via AJAX ( was using is_ajax() ), and even though it was on the checkout page, it wasn't returning as true. It's possible there was a recent change, or it could be the site's environment (theme).
Here are some of the conditional tags: https://docs.woocommerce.com/document/conditional-tags/
Seeing how things change, the answer can be edited here, but the original concept is located at: https://www.skyverge.com/blog/how-to-simplify-free-woocommerce-checkout/
function wc_free_checkout_fields() {
// Bail we're not at checkout, or if we're at checkout OR AJAX (payment process) but payment is needed.
if ( function_exists( 'is_checkout' ) && ( ! ( is_checkout() || is_ajax() ) || ( ( is_checkout() || is_ajax() ) && WC()->cart->needs_payment() ) ) ) {
return;
}
// Remove coupon forms since it's irrelevant with a free cart?
remove_action( 'woocommerce_before_checkout_form', 'woocommerce_checkout_coupon_form', 10 );
// Remove the "Additional Info" order notes.
add_filter( 'woocommerce_enable_order_notes_field', '__return_false' );
// Unset the fields we don't want in a free checkout.
function wc_unset_unwanted_checkout_fields( $fields ) {
// Add or remove billing fields you do not want.
// #link http://docs.woothemes.com/document/tutorial-customising-checkout-fields-using-actions-and-filters/#section-2
$billing_keys = array(
'billing_company',
'billing_phone',
'billing_address_1',
'billing_address_2',
'billing_city',
'billing_postcode',
'billing_country',
'billing_state',
);
// For each unwanted billing key, unset.
foreach( $billing_keys as $key ) {
unset( $fields['billing'][$key] );
}
return $fields;
}
add_filter( 'woocommerce_checkout_fields', 'wc_unset_unwanted_checkout_fields' );
// A tiny CSS tweak for the account fields; this is optional.
function wc_print_custom_css() {
?>
<style>
.create-account {
margin-top: 6em;
}
</style>
<?php
}
add_action( 'wp_head', 'wc_print_custom_css' );
}
add_action( 'wp', 'wc_free_checkout_fields' );
Check if the checkout has no cost with the WC()->cart->needs_payment() check.
see this for more info:
https://www.skyverge.com/blog/how-to-simplify-free-woocommerce-checkout/
Related
I would like to add a function that is triggered every time that the stock quantity of a product will be changed in the admin product page, such that this function will not allow any reduce of the stock value - but only increase.
This is to prevent an admin user to reduce the stock quantity of the products.
Of course, this function should not be triggered if a product will be in an order, since then of course I would like the stock quantity to be reduced.
I tried the following function in the functions.php but unfortunately did not work.
Since I'm new to woocommerce and php, any ideas that could provide a solid solution to the problem?
// get old and new product stock quantity
function get_old_and_new_product_quantity_stock( $sql, $product_id_with_stock, $new_stock, $operation ) {
$product = wc_get_product( $product_id_with_stock );
$old_stock_quantity = $product->get_stock_quantity();
$new_stock_quantity = $new_stock;
echo $old_stock_quantity, $new_stock_quantity;
if ($new_stock_quantity < $old_stock_quantity) {
$new_stock = $old_stock_quantity;
$new_stock_quantity = $old_stock_quantity;
}
return $sql;
}
add_filter( 'woocommerce_update_product_stock_query', 'get_old_and_new_product_quantity_stock', 10, 4 );
You can use the update_post_meta action hook to check if the new value is less than the previous value and display error message.
This will work for quick edit and for product edit page. But the wp_die on product page will look bad so use the javascript to prevent submitting on product edit page (there was another question about it yesterday)
Be sure to test this snippet and create some orders that will reduce the stock automatically. I added is_admin() check but please do a good test.
add_action( 'update_post_meta', 'prevent_reducing_stock_metadata', 10, 4 );
function prevent_reducing_stock_metadata( $meta_id, $post_id, $meta_key, $meta_value ) {
// Check if the meta key is _stock and the new value is less than the previous value
if ( '_stock' == $meta_key && $meta_value < get_post_meta( $post_id, '_stock', true ) ) {
// Check if this is an update from the WordPress admin area
if ( is_admin() ) {
wp_die( __( 'Error: You cannot reduce the stock level for this product.' ), 'error' );
}
}
}
I'm using this simple code to add a 'buy now' button on a single product page.
add_action( 'woocommerce_after_add_to_cart_button', 'add_content_after_addtocart' );
function add_content_after_addtocart() {
// get the current post/product ID
$current_product_id = get_the_ID();
// get the product based on the ID
$product = wc_get_product( $current_product_id );
// get the "Checkout Page" URL
$checkout_url = WC()->cart->get_checkout_url();
// run only on simple products
if( $product->is_type( 'simple' ) ) {
echo 'Buy Now';
}
}
This code effectively redirects to the checkout page and add the product to the cart, but I want to add two little features to it:
After clicking on the button, I want it to clear the cart before taking the action.
After adding the product to the cart, I want it to redirect users to '/checkout' page. Right now it sends users on 'checkout/?add-to-cart=3122', which means that any refresh on the checkout page adds 1 product on the cart automatically.
Any advice?
Instead of using the add-to-cart param in your url, which will cause the product to be added (but also perform other actions in WooCommerce), you can use a custom url for your button and the template_redirect action hook
That way you get rid of the built-in functionality in WooCommerce and you can perform your own custom actions based on the GET parameters
So you get:
// Add new/extra button
function action_woocommerce_after_add_to_cart_button() {
global $product;
// Is a WC product
if ( is_a( $product, 'WC_Product' ) ) {
// Run only on simple products
if ( $product->is_type( 'simple' ) ) {
// Get product ID
$product_id = $product->get_id();
// Get permalink
$permalink = $product->get_permalink();
// Output url
echo ''. __ ( 'Buy Now', 'woocommerce' ) . '';
}
}
}
add_action( 'woocommerce_after_add_to_cart_button', 'action_woocommerce_after_add_to_cart_button', 10 );
// Redirect
function action_template_redirect() {
// Determines whether the current request is for an administrative interface page
if ( is_admin() ) return;
// Returns true when viewing a single product
if ( ! is_product() ) return;
// Get params
if ( isset( $_GET['product_id'] ) && isset( $_GET['redirect_checkout'] ) ) {
// Get param 1
$product_id = $_GET['product_id'];
// Get param 2
$boolean = $_GET['redirect_checkout'];
// WC Cart
if ( WC()->cart ) {
// 1. Empty cart
WC()->cart->empty_cart();
// 2. Add to cart
WC()->cart->add_to_cart( $product_id );
// 3. Redirect
// When true
if ( $boolean ) {
// Gets the url to the checkout page
$checkout_url = wc_get_checkout_url();
// Performs a safe (local) redirect
wp_safe_redirect( $checkout_url );
exit;
}
}
}
}
add_action( 'template_redirect', 'action_template_redirect' );
Here is code for clear cart before add item
add_filter( 'woocommerce_add_to_cart_validation', 'ji_remove_cart_item_before_add_to_cart', 20, 3 );
function ji_remove_cart_item_before_add_to_cart( $passed, $product_id, $quantity ) {
if( ! WC()->cart->is_empty() )
WC()->cart->empty_cart();
return $passed;}
After adding the product to the cart, I want it to redirect users to '/checkout' page. Right now it sends users on 'checkout/?add-to-cart=3122', which means that any refresh on the checkout page adds 1 product on the cart automatically.
add_filter( 'woocommerce_add_to_cart_redirect', 'ji_redirect_checkout_after_add_to_cart' );
function ji_redirect_checkout_after_add_to_cart() {
return wc_get_checkout_url();
}
Requirement :
I have a custom requirement where anyone can enroll for a single course.
The tool I have to use is woocommerce with a custom woocommerce payment plugin.
These are the steps that a user will go through:-
Step 1: User registers
Step 2: The user is redirected to the payment page once payment is completed.
Step 3: User gets enrolled.
Now the issue is that woocommerce by default has payment for a virtual and physical product.
Please suggest a suitable method to implement this in woocommerce.
function control_payment( $args ) {
if( !is_user_logged_in() ) {
// unset your payment
}
return $args;
}
add_action( 'woocommerce_available_payment_gateways', 'control_payment' );
Or you can use something like this
add_filter( 'woocommerce_available_payment_gateways', 'my_paypal_disable_manager' );
function my_paypal_disable_manager( $available_gateways ) {
if ( isset( $available_gateways['paypal'] ) && current_user_can( 'manage_woocommerce' ) ) {
unset( $available_gateways['paypal'] );
}
return $available_gateways;
}
(https://businessbloomer.com/disable-payment-gateway-specific-user-role-woocommerce/)
I have a custom function which i use to add/remove a custom fee to the Cart Totals. The fee works fine during the Cart Ajax Calculations, but for some reason the fee still gets charged to the order after checkout. How can I remove this before the order is processed? Here is what i currently have to calculate the fee:
function woo_add_cart_fee() {
global $woocommerce;
if ( ! $_POST || ( is_admin() && ! is_ajax() ) ) {
return;
}
$checkout = WC()->checkout()->checkout_fields;
parse_str( $_POST['post_data'], $post_data );
// Add Fee if no VAT Number is Provided
if($post_data['vat_number'] == '' OR strlen($post_data['vat_number']) < 1 OR empty($post_data['vat_number'])){
$vat_total = 25; // $25.00 fee
$woocommerce->cart->add_fee( __('VAT Fee', 'woocommerce'), $vat_total );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'woo_add_cart_fee' );
The problem is that once the user checks out, the fee is always added, even if they provide a VAT number (my custom field).
So I tried adding this snippet to remove the action completely before the order is processed, but this does not seem to work either:
function action_woocommerce_before_checkout_process( $array ) {
if($_POST['vat_number'] == '' OR strlen($_POST['vat_number']) < 1 OR empty($_POST['vat_number'])){
remove_action( 'woocommerce_cart_calculate_fees', 'woo_add_cart_fee', 1 );
}
}
// add the action
add_action( 'woocommerce_before_checkout_process', 'action_woocommerce_before_checkout_process');
I believe I may be using the wrong hook woocommerce_before_checkout_process because it doesn't seem to be firing.
Any Idea what could be happening? Thanks!
I was able to fix this by adding some control flow for $woocommerce->cart->add_fee It turns out that the calculate_totals function is run again before the thank you page
if(isset($_POST['vat_number'])){
if($_POST['vat_number'] == '' OR empty($_POST['vat_number'])){
$woocommerce->cart->add_fee( __($vat_label, 'woocommerce'), $vat_total );
}
} else {
$woocommerce->cart->add_fee( __($vat_label, 'woocommerce'), $vat_total );
}
on my baked goods site, I have WooCommerce installed and another plugin called Order Delivery Date for WooCommerce.
I installed the second plugin so my customers would be able to choose a delivery date for their items, however, I am trying to make the form field a required field. So far, I've just been able to make the field look like a required field, but have not figured out how to make sure that it is actually enforced. Any ideas?
Also, if anyone is familiar with WooCommerce, do you know how I would be able to make it so that customers receive this delivery date information in their order confirmation emails?
Thank you in advance!
My site: www.monpetitfour.com
You should try to had something like that :
add_action('woocommerce_checkout_process', 'my_custom_checkout_field_process');
function my_custom_checkout_field_process() {
// You can make your own control here
if ( ! $_POST[ 'e_deliverydate' ] )
wc_add_notice( __( 'Please select a delivery date' ), 'error' );
}
For the email, the easiest is to save the meta value ( I think it's already done by your plugin). Then you need to copy the template email (customer-processing-order.php) on your theme and change in the template :
<?php $delivery_date = get_post_meta( $order->id, 'custom_field_date', true);
// If the plugin is well developed, you can't directly use magic getters :
// $delivery_date = $order->e_deliverydate;
// Can only by use if the post meta start with _
?>
Your delivery date is <?php echo $delivery_date ?>
You can also use
date_i18n( woocommerce_date_format(), strtotime( $delivery_date ) );
In order to format the date correctly.
On the code above, you just need to find the name of the custom field used by the plugin ( you can search easily on the table wp_postmeta searching by an existing order (should be _e_deliverydate).
Add the following code to your theme's functions.php file
add_action('woocommerce_checkout_process', 'my_custom_checkout_field_process');
function my_custom_checkout_field_process() {
// Check if set, if its not set add an error.
if ( ! $_POST['e_deliverydate'] )
wc_add_notice( __( 'Please select a delivery date.' ), 'error' );
}
Now to get the email to show the custom field,
add_filter('woocommerce_email_order_meta_keys', 'my_woocommerce_email_order_meta_keys');
function my_woocommerce_email_order_meta_keys( $keys ) {
$keys['Delivery Date'] = '_e_deliverydate';
return $keys;
}
EDIT : Seems the field value isn't being saved to the database, try saving it explicitly
add_action( 'woocommerce_checkout_update_order_meta', 'my_custom_checkout_field_update_order_meta' );
function my_custom_checkout_field_update_order_meta( $order_id ) {
if ( ! empty( $_POST['e_deliverydate'] ) ) {
update_post_meta( $order_id, '_e_deliverydate', sanitize_text_field( $_POST['e_deliverydate'] ) );
}
}