Woocommerce - Calculate Exta Fee Based on Amount of People - woocommerce

I've added in a function for a custom field on the product general options:
// Add Custom Field to Product under General
function create_extra_fee_field() {
$args = array(
'id' => 'park_fee',
'label' => __( 'Natl Park Entrance Fee', 'tranq-lsx-child' ),
'class' => 'tranq-custom-field',
'desc_tip' => true,
'description' => __( 'This sets the Fee that will be added to the car.', 'tranq-lsx-child' ),
);
woocommerce_wp_text_input( $args );
}
add_action( 'woocommerce_product_options_general_product_data', 'create_extra_fee_field' );
// Save Custom Field Data
function save_extra_fee_field( $post_id ) {
$product = wc_get_product( $post_id );
$title = isset( $_POST['park_fee'] ) ? $_POST['park_fee'] : '';
$product->update_meta_data( 'park_fee', sanitize_text_field( $title ) );
$product->save();
}
add_action( 'woocommerce_process_product_meta', 'save_extra_fee_field' );
I would like to add this as an extra fee to the Cart Totals which multiplied based on the amount of Person/People that were selected from the Woocommerce Bookings.
Something like this:
// Calculate Extra Fee Based on Amount of People.
add_action('woocommerce_cart_calculate_fees' , 'add_custom_fees');
function add_custom_fees( WC_Cart $cart ){
$park_fee = get_post_meta($item['product_id'] , 'park_fee', true);
foreach( $cart->get_cart() as $item ){
$fees += $item[ 'park_fee' ] * 14706;
}
if( $fees != 0 ){
$cart->add_fee( 'Park Fee', $fees);
}
}
How do I go about in achieving this? Any Links to a walkthrough would be greatly appreciated.

I've added this and it seems to work:
// Add Custom Field to Cart Totals
function woo_add_cart_fee() {
global $woocommerce;
foreach( WC()->cart->get_cart() as $cart_item ){
// Get the WC_Product object (instance)
$product = $cart_item['data'];
$product_id = $product->get_id(); // get the product ID
$custom_field_value = get_post_meta( $product->get_id(), 'park_fee', true );
$person = array_sum( $cart_item['booking']['_persons'] );
}
$additional_fee_name = "Natl Park Entrance Fee";
$extra_fee = $custom_field_value * $person;
$addedFee = false;
// first check to make sure it isn’t already there
foreach ( $woocommerce->cart->get_fees() as $_fee )
{
if ($_fee->id == sanitize_title($additional_fee_name) )
{
$_fee->amount = (float) esc_attr( $extra_fee );
}
}
if (!$addedFee)
{
$woocommerce->cart->add_fee( __($additional_fee_name, "woocommerce"),
$extra_fee, $additional_fee_taxable );
}
}
add_action( "woocommerce_before_calculate_totals", "woo_add_cart_fee" );

Related

How to add ACF field to custom column on WooCommerce admin orders list

ACF is set up for post type on WooCommerce products. However, I am trying to add a custom column to WooCommerce orders list within Admin dashboard and add the products ACF field.
I have added the column to display after order_status, but I'm having problems getting the ACF field to display.
// ADD NEW COLUMN
add_filter( 'manage_edit-shop_order_columns', 'custom_shop_order_column', 20 );
function custom_shop_order_column($columns)
{
$reordered_columns = array();
foreach( $columns as $key => $column){
$reordered_columns[$key] = $column;
if( $key == 'order_status' ){
$reordered_columns['my-column'] = __( 'Location','theme_domain');
}
}
return $reordered_columns;
}
Here, adding ACF to new colum.
// ADD ACF FIELD TO COLUMN
add_action( 'manage_shop_order_posts_custom_column' , 'custom_orders_list_column_content', 20, 2 );
function custom_orders_list_column_content( $column, $post_id )
{
if ( 'Location' == $column_name ){
$product_id = method_exists( $product, 'get_id' ) ? $product->get_id() : $product->id;
echo get_field( 'location', $product_id );
}
return true;
}
Still learning and not sure how to do this, any advice?
An order generally consists of several products, therefore you cannot use $product_id directly, but you have to loop through the order items.
So you get:
/**
* Add columns
*/
function filter_manage_edit_shop_order_columns( $columns ) {
$reordered_columns = array();
foreach ( $columns as $key => $column ) {
$reordered_columns[$key] = $column;
if ( $key == 'order_status' ) {
$reordered_columns['my-column'] = __( 'Location','theme_domain' );
}
}
return $reordered_columns;
}
add_filter( 'manage_edit-shop_order_columns', 'filter_manage_edit_shop_order_columns', 10, 1 );
/**
* Populate columns
*/
function filter_manage_shop_order_posts_custom_column( $column, $post_id ) {
// Compare
if ( $column == 'my-column' ) {
// Get order
$order = wc_get_order( $post_id );
// Is a WC_Order
if ( is_a( $order, 'WC_Order' ) ) {
// Get items
$items = $order->get_items();
// Loop through
foreach ( $items as $key => $item ) {
// Product ID
$product_id = $item->get_variation_id() > 0 ? $item->get_variation_id() : $item->get_product_id();
// Get field
$address = get_field( 'location', $product_id );
// Output
echo ($address) ? '<div>Address: ' . $address . '</div>' : '<div>Address: No address found!</div>';
}
}
}
}
add_filter( 'manage_shop_order_posts_custom_column', 'filter_manage_shop_order_posts_custom_column', 10, 2 );

Create a custom hidden field in backend product pages and use value in WooCommerce products sort by

I am making an e-commerce website using WooCommerce. With the help of this forum, I was able to code some useful snippets. However, I am stuck at a certain code now.
I have pieced together codes from various sections, but I am unable to get it to work.
What I want to do - create a custom hidden field programmatically for discount percent & then use the field to allow sorting by discount.
But it looks like the meta does not save in the backend.
When I sort by discount, all I get is this 'No products were found matching your selection.' even though there are some products on sale.
This is my code:
//add_action ('woocommerce_process_product_meta', 'mycode_product_save_discount');
add_action ('woocommerce_admin_process_product_object', 'mycode_product_save_discount');
function mycode_product_save_discount ($product)
{
$product = wc_get_product ($product);
$regular_price = (float) $product->get_regular_price();
$sale_price = (float) $product->get_sale_price();
if (!empty($sale_price))
{
$discount_percent = round (100 - ($sale_price / $regular_price * 100), 4);
$discount_percent = $_POST['_discount_percent'][$product];
//update_post_meta ($post_id, '_discount_percent', $discount_percent);
$product->update_meta_data ('discount_percent', $discount_percent);
$product->save();
}
}
add_filter ('woocommerce_get_catalog_ordering_args', 'mycode_add_discount_to_ordering_args');
function mycode_add_discount_to_ordering_args ($args)
{
$orderby_value = isset ($_GET['orderby']) ? wc_clean ($_GET['orderby']) : apply_filters ('woocommerce_default_catalog_orderby', get_option ('woocommerce_default_catalog_orderby'));
if (!is_post_type_archive ('product') && !is_shop() && isset($args['orderby']))
{
$orderby_value = $sort_args['orderby'];
}
if ('discount' == $orderby_value)
{
$args['orderby'] = 'meta_value_num';
$args['order'] = 'DESC';
$args['meta_key'] = '_discount_percent';
}
return $args;
}
add_filter ('woocommerce_default_catalog_orderby_options', 'mycode_add_discount_to_orderby');
add_filter ('woocommerce_catalog_orderby', 'mycode_add_discount_to_orderby');
function mycode_add_discount_to_orderby ($sortby)
{
$sortby['discount'] = 'Sort by discount';
return $sortby;
}
What do I need to change to make it work?
You are close, but your code contains some minor mistakes.
This should suffice:
/*** For debugging purposes, remove this action hook if everything works!! ***/
function action_woocommerce_product_options_general_product_data() {
// Text field
woocommerce_wp_text_input( array(
'id' => '_discount_percent',
'label' => __( 'Discount percent', 'woocommerce' ),
'placeholder' => '',
'description' => __( 'For debugging purposes, remove this action hook if everything works', 'woocommerce' ),
'desc_tip' => true,
'custom_attributes' => array( 'readonly' => true ),
));
}
add_action( 'woocommerce_product_options_general_product_data', 'action_woocommerce_product_options_general_product_data', 10, 0 );
/*** From here on the code below is needed so that everything would work smoothly ***/
// Save value
function action_woocommerce_admin_process_product_object( $product ) {
// Getters
$regular_price = (float) $product->get_regular_price();
$sale_price = (float) $product->get_sale_price();
// NOT empty
if ( ! empty( $sale_price ) ) {
// Calculate
$discount_percent = round( 100 - ( $sale_price / $regular_price * 100 ), 4 );
// Update
$product->update_meta_data( '_discount_percent', $discount_percent );
}
}
add_action( 'woocommerce_admin_process_product_object', 'action_woocommerce_admin_process_product_object', 10, 1 );
// Ordering products based on the selected values
function filter_woocommerce_get_catalog_ordering_args( $args, $orderby, $order ) {
switch( $orderby ) {
case 'discount':
$args['orderby'] = 'meta_value';
$args['order'] = 'ASC';
$args['meta_key'] = '_discount_percent';
break;
}
return $args;
}
add_filter( 'woocommerce_get_catalog_ordering_args', 'filter_woocommerce_get_catalog_ordering_args', 10, 3 );
// Orderby setting
function filter_orderby( $orderby ) {
$orderby['discount'] = __( 'Sort by discount', 'woocommerce' );
return $orderby;
}
add_filter( 'woocommerce_default_catalog_orderby_options', 'filter_orderby', 10, 1 );
add_filter( 'woocommerce_catalog_orderby', 'filter_orderby', 10, 1 );
This shows the value after it has been saved. This is not actually necessary, but can be useful for debug purposes.

Add custom select field with validation to WooCommerce checkout page if certain products are in cart

I wish to add a custom select field with validation to the WooCommerce checkout page if certain products are in cart.
With my current code I retrieve the value of my custom WooCommerce form field. However, it display "array" at the order page.
I have an select field which have an option of 1 and 0. Upon selection of the select field, i want it to display either 1 or 0 at the order page but im unable to do so.
Please guide me on what should i do with my current codes:
//AMBASSADOR CUSTOM CHECKOUT FIELDS, CONTENT add marketplace for sameday TEST
add_action( 'woocommerce_after_checkout_billing_form', 'aym_custom_checkout_field' );
function aym_custom_checkout_field( $checkout ) {
//Check if Product in Cart
$prod_in_cart_17563 = aym_is_conditional_product_in_cart_17563( 212 );
if ( $prod_in_cart_17563 === true ) {
$domain = 'wocommerce';
$default = 'Y';
woocommerce_form_field( '_my_field_name', array(
'type' => 'select',
'class' => array( 'form-row-wide' ),
'label' => __( 'Market Place - Please Select Y to complete this order' ),
'required' => true,
'options' => array(
'Y' => __('1'),
'N' => __('0')
),'default' => $default),
$checkout->get_value( '_my_field_name' ) );
}
}
//AMBSSADOR BUNDLE add marketplace for same day pa rt 2
function aym_is_conditional_product_in_cart_17563( $product_id ) {
//Check to see if user has product in cart
global $woocommerce;
//flag no product in cart
$prod_in_cart_17563 = false;
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->id === $product_id ) {
//product is in cart!
$prod_in_cart_17563 = true;
}
}
return $prod_in_cart_17563;
}
//process orders in order page
// Custom checkout fields validation
add_action( 'woocommerce_checkout_process', 'custom_checkout_field_process' );
function custom_checkout_field_process() {
if ( isset($_POST['_my_field_name']) && empty($_POST['_my_field_name']) )
wc_add_notice( __( 'Please fill in "My 1st new field".' ), 'error' );
}
// Save custom checkout fields the data to the order
add_action( 'woocommerce_checkout_create_order', 'custom_checkout_field_update_meta', 10, 2 );
function custom_checkout_field_update_meta( $order, $data ){
if( isset($_POST['_my_field_name']) && ! empty($_POST['_my_field_name']) )
$order->update_meta_data( '_my_field_name', sanitize_text_field( $_POST['_my_field_name'] ) );
}
/**
* Update the order meta with field value
**/
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 ($_POST['_my_field_name']) update_post_meta( $order_id, 'My Field', esc_attr($_POST['_my_field_name']));
}
// View fields in Edit Order Page
add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_custom_fields_value_admin_order', 10, 1 );
function display_custom_fields_value_admin_order( $order ){
// Display the delivery option
if( $delivery_option = $order->get_meta('_my_field_name') )
echo '<p><strong>'.__('Delivery type').':</strong> ' . $delivery_option . '</p>';
}
// Display field value on the order edit page
add_action( 'woocommerce_admin_order_data_after_billing_address', 'my_custom_checkout_field_display_admin_order_meta', 10, 1 );
function my_custom_checkout_field_display_admin_order_meta( $order ) {
if( $selectoption = $order->get_meta('_my_field_name') ) {
//$value = wc_get_hearaboutus_options()[$selectoptions];
$meta= get_post_meta( $post->ID, $selectoption, true );
$myvalues = unserialize( $meta );
echo '<p><strong>'.__('Market_Place').':</strong> ' . $myvalues . '</p>';
}
}
I have partly rewritten / modified your code with some (extra) features
The ability to check for multiple product IDs in the shopping cart
The custom field is only added if a certain product id is in the shopping cart
The possibility to check out if the custom field is not present (product ID is NOT in cart)
No possibility to checkout as long as the value 'Y' is not selected from the custom select menu (Product ID is IN cart)
Explanation via comment tags added in the code
// Add custom 'select' field after checkout billing form (if product ID is in cart)
function action_woocommerce_after_checkout_billing_form( $checkout ) {
// Check if Product in Cart
// Multiple product IDs can be entered, separated by a comma
$product_in_cart = is_product_in_cart( array( 212, 30, 815 ) );
// True
if ( $product_in_cart ) {
$domain = 'woocommerce';
$default = 'Y';
woocommerce_form_field( '_my_field_name', array(
'type' => 'select',
'class' => array( 'form-row-wide' ),
'label' => __( 'Market Place - Please Select Y to complete this order', $domain ),
'required' => true,
'options' => array(
'Y' => __( 'Y', $domain ),
'N' => __( 'N', $domain ),
),
'default' => $default,
), $checkout->get_value( '_my_field_name' ) );
}
}
add_action( 'woocommerce_after_checkout_billing_form', 'action_woocommerce_after_checkout_billing_form', 10, 1 );
// Function to check if a certain product ID is in cart
function is_product_in_cart( $targeted_ids ) {
// Flag no product in cart
$flag = false;
// WC Cart NOT null
if ( ! is_null( WC()->cart ) ) {
// Loop through cart items
foreach( WC()->cart->get_cart() as $cart_item ) {
// Check cart item for defined product Ids
if ( in_array( $cart_item['product_id'], $targeted_ids ) ) {
// Product is in cart
$flag = true;
// Break loop
break;
}
}
}
return $flag;
}
// Custom checkout 'select' field validation
function action_woocommerce_checkout_process() {
// Isset
if ( isset( $_POST['_my_field_name'] ) ) {
$domain = 'woocommerce';
$my_field_name = $_POST['_my_field_name'];
// Empty
if ( empty ( $my_field_name ) ) {
wc_add_notice( __( 'Please Select Y to complete this order', $domain ), 'error' );
}
// NOT empty but value is 'N'
if ( ! empty ( $my_field_name ) && $my_field_name == 'N' ) {
wc_add_notice( __( 'Please Select Y to complete this order', $domain ), 'error' );
}
}
}
add_action( 'woocommerce_checkout_process', 'action_woocommerce_checkout_process', 10, 0 );
// Save custom checkout 'select' field
function action_woocommerce_checkout_create_order( $order, $data ) {
// Isset
if ( isset( $_POST['_my_field_name'] ) ) {
$my_field_name = $_POST['_my_field_name'];
// NOT empty & equal to 'Y'
if ( ! empty( $my_field_name ) && $my_field_name == 'Y' ) {
$order->update_meta_data( '_my_field_name', sanitize_text_field( $my_field_name ) );
}
}
}
add_action( 'woocommerce_checkout_create_order', 'action_woocommerce_checkout_create_order', 10, 2 );
// Display the custom 'select' field value on admin order pages after billing adress
function action_woocommerce_admin_order_data_after_billing_address( $order ) {
$domain = 'woocommerce';
// Get meta
$my_field_name = $order->get_meta( '_my_field_name' );
// NOT empty
if ( ! empty ( $my_field_name ) ) {
echo '<p><strong>' . __( 'Delivery type', $domain ) . ':</strong> ' . $order->get_meta( '_my_field_name' ) . '</p>';
}
}
add_action( 'woocommerce_admin_order_data_after_billing_address', 'action_woocommerce_admin_order_data_after_billing_address', 10, 1 );
// Display the custom 'select' field value on 'order received' and 'order view' pages (frontend)
function action_woocommerce_order_details_after_order_table( $order ) {
$domain = 'woocommerce';
// Get meta
$my_field_name = $order->get_meta( '_my_field_name' );
// NOT empty
if ( ! empty ( $my_field_name ) ) {
echo '<p><strong>' . __( 'Delivery type', $domain ) . ':</strong> ' . $order->get_meta( '_my_field_name' ) . '</p>';
}
}
add_action( 'woocommerce_order_details_after_order_table', 'action_woocommerce_order_details_after_order_table', 10, 1 );

Show order details in a new column on My account / order table

In WooCommerce, I would like to add a new column to the "My Account" orders table and show the order details.
I have this code, which adds the column, but the values don't show (e.g. get_formatted_meta_data).
Can anyone help rewrite the code to make it work?
function wc_add_my_account_orders_column( $columns ) {
$new_columns = array();
foreach ( $columns as $key => $name ) {
$new_columns[ $key ] = $name;
if ( 'order-status' === $key ) {
$new_columns['order-details'] = __( 'Order details', 'textdomain' );
}
}
return $new_columns;
}
add_filter( 'woocommerce_my_account_my_orders_columns', 'wc_add_my_account_orders_column' );
function wc_my_orders_order_details_column( $order ) {
$order_details = get_post_meta( $order->get_id(), 'order_details', true );
echo ! empty( $order_details ) ? $order_details : '–';
}
add_action( 'woocommerce_my_account_my_orders_column_order_details', 'wc_my_orders_order_details_column' );
The woocommerce_my_account_my_orders_columns filter has been deprecated since WooCommerce 2.6.0. So although it still functions you should use the woocommerce_account_orders_columns filter to add an additional column.
To populate the column with your data you can use the woocommerce_my_account_my_orders_column_ action which expects you to append the column ID of your custom column. So in your case that would be order-details. In your example you've used order_details (with an underscore instead of a hyphen). That is why your data doesn't show up.
Also it is best practice to retrieve order meta data via the internal WooCommerce getter function get_meta() instead of using get_post_meta().
add_filter( 'woocommerce_account_orders_columns', 'wc_add_my_account_orders_column', 10, 1 );
function wc_add_my_account_orders_column( $columns ) {
$new_columns = array();
foreach ( $columns as $key => $name ) {
$new_columns[ $key ] = $name;
if ( 'order-status' === $key ) {
$new_columns['order-details'] = __( 'Order details', 'textdomain' );
}
}
return $new_columns;
}
add_action( 'woocommerce_my_account_my_orders_column_order-details', 'wc_my_orders_order_details_column', 10, 1 );
function wc_my_orders_order_details_column( $order ) {
$item_meta = '';
foreach ( $order->get_items() as $item ) {
$item_meta .= wc_display_item_meta( $item, array( 'echo' => false ) );
}
echo !empty( $item_meta ) ? $item_meta : '-';
}

WooCommerce function to display total product sales on site homepage

I am trying to find a function and shortcode to display the total amount of products sold as simply as possible on our website.
Don't want to show product names or any info just a count.
I found this function / shortcode that displays total orders. Just wondering fo anyone can help adapt it to display total products sold?
Thanks so much..
function display_woocommerce_order_count( $atts, $content = null ) {
$args = shortcode_atts( array(
'status' => 'completed',
), $atts );
$statuses = array_map( 'trim', explode( ',', $args['status'] ) );
$order_count = 0;
foreach ( $statuses as $status ) {
// if we didn't get a wc- prefix, add one
if ( 0 !== strpos( $status, 'wc-' ) ) {
$status = 'wc-' . $status;
}
$order_count += wp_count_posts( 'shop_order' )->$status;
}
ob_start();
echo number_format( $order_count );
return ob_get_clean();
}
add_shortcode( 'wc_order_count', 'display_woocommerce_order_count' );

Resources