Using ACF in Woocommerce on the checkout page where I created a custom checkout field for selecting the delivery method.
How to make it so that when you click the "Confirm order" button, the selected select field is passed to the total order itself, and sent in the order letter.
I create this repeater field in checkout-form.php file:
/**
* Checkout Form
*
* #see https://docs.woocommerce.com/document/template-structure/
* #author WooThemes
* #package WooCommerce/Templates
* #version 2.3.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
wc_print_notices();
do_action( 'woocommerce_before_checkout_form', $checkout );
// If checkout registration is disabled and not logged in, the user cannot checkout
if ( ! $checkout->is_registration_enabled() && $checkout->is_registration_required() && ! is_user_logged_in() ) {
echo apply_filters( 'woocommerce_checkout_must_be_logged_in_message', __( 'You must be logged in to checkout.', 'woocommerce' ) );
return;
}
?>
<form name="checkout" method="post" class="checkout woocommerce-checkout" action="<?php echo esc_url( wc_get_checkout_url() ); ?>" enctype="multipart/form-data">
<?php if ( $checkout->get_checkout_fields() ) : ?>
<?php do_action( 'woocommerce_checkout_before_customer_details' ); ?>
<div class="col2-set" id="customer_details">
<div class="col-12">
<?php do_action( 'woocommerce_checkout_billing' ); ?>
</div>
<?php if( have_rows('shipping_methods') ): ?>
<div class="shipp-method">
<label for="shipping_method">Способ доставки:</label>
<select name="shipping_method" id="shipping_method" class="select_shipping">
<?php while( have_rows('shipping_methods') ): the_row();
$method = get_sub_field('shipping_method');
?>
<option><?php echo $method; ?></option>
<?php endwhile; ?>
</select>
</div>
<?php endif; ?>
<div class="col-12">
<?php do_action( 'woocommerce_checkout_shipping' ); ?>
</div>
</div>
<?php do_action( 'woocommerce_checkout_after_customer_details' ); ?>
<?php endif; ?>
<h3 id="order_review_heading"><?php _e( 'Your order', 'woocommerce' ); ?></h3>
<?php do_action( 'woocommerce_checkout_before_order_review' ); ?>
<div id="order_review" class="woocommerce-checkout-review-order">
<?php do_action( 'woocommerce_checkout_order_review' ); ?>
</div>
<?php do_action( 'woocommerce_checkout_after_order_review' ); ?>
</form>
<?php do_action( 'woocommerce_after_checkout_form', $checkout ); ?>
Creating an ACF field is not enough to add custom fields to Woocommerce checkout.
Woocommerce provide couple of filters so its checkout form fields can be modified, the most prominent one is: woocommerce_checkout_fields. While you can use ACF create a set of options for the additional select field you want to have in Woocommerce checkout form, you need to register them with the filter. For example:
add_filter( 'woocommerce_checkout_fields', function($fields) {
// Get the field you need here and mutate $fields
...
return $fields;
});
Doing so with make sure the data will be passed to the server. You also need to save them as an order meta to the database with the action woocommerce_checkout_update_order_meta. Example:
add_action( 'woocommerce_checkout_update_order_meta', function( $order_id) {
update_post_meta( $order_id, [Your custom field name], sanitize_text_field( $_POST['your_custom_field_name']));
});
Also, a note here is that by default, Woocommerce provide shipping function out of the box already, which mean you probably don't want to reinvent the wheel. If you want to add your own additional shipping methods, you may want to look into how to create custom shipping method.
More on how to custom Woocommerce checkout:
https://docs.woocommerce.com/document/tutorial-customising-checkout-fields-using-actions-and-filters/
And custom shipping:
https://code.tutsplus.com/tutorials/create-a-custom-shipping-method-for-woocommerce--cms-26098
Related
I am trying the move the shipping options in my woocommerce checkout out of review-order.php and into form-checkout.php
I have taken the code
<?php if ( WC()->cart->needs_shipping() && WC()->cart->show_shipping() ) : ?>
<?php do_action( 'woocommerce_review_order_before_shipping' ); ?>
<?php wc_cart_totals_shipping_html(); ?>
<?php do_action( 'woocommerce_review_order_after_shipping' ); ?>
<?php endif; ?>
And moved it to my themes form-checkout.php the problem is that it will now not update the shipping when I enter or change the address. This has been accepted as a solution online but I think woocommerce has updated since then.
I think the problem is that the shipping options are now not updating when update_checkout Ajax is called but I am unsure how to change this.
Thank You
EDIT: I think I have an idea of how to do this. I have created a template checkout/shipping-options.php with
<?php
defined( 'ABSPATH' ) || exit;
?>
<div class="card card-shipping mb-3 woocommerce-checkout-shipping-table">
<div class="card-header">
Select Shipping
</div>
<div class="card-body ">
<?php do_action( 'woocommerce_review_order_before_shipping' ); ?>
<?php wc_cart_totals_shipping_html(); ?>
<?php do_action( 'woocommerce_review_order_after_shipping' ); ?>
</div>
</div>
Then in my functions.php I have added
function woocommerce_checkout_shipping_options( $deprecated = false ) {
wc_get_template(
'checkout/shipping-options.php',
array(
'checkout' => WC()->checkout(),
)
);
}
add_action( 'woocommerce_checkout_shipping_option', 'woocommerce_checkout_shipping_options', 10 );
Then added
<?php do_action( 'woocommerce_checkout_shipping_option' ); ?>
into form-checkout.php
and updated the woocommerce/includes/class-wc-ajax.php update_order_review function to include
// Get order review fragment.
ob_start();
woocommerce_order_review();
$woocommerce_order_review = ob_get_clean();
// Get checkout payment fragment.
ob_start();
woocommerce_checkout_payment();
$woocommerce_checkout_payment = ob_get_clean();
// Get checkout shipping fragment.
ob_start();
woocommerce_checkout_shipping_options();
$woocommerce_checkout_shipping_options = ob_get_clean();
// Get messages if reload checkout is not true.
$reload_checkout = isset( WC()->session->reload_checkout );
if ( ! $reload_checkout ) {
$messages = wc_print_notices( true );
} else {
$messages = '';
}
unset( WC()->session->refresh_totals, WC()->session->reload_checkout );
wp_send_json(
array(
'result' => empty( $messages ) ? 'success' : 'failure',
'messages' => $messages,
'reload' => $reload_checkout,
'fragments' => apply_filters(
'woocommerce_update_order_review_fragments',
array(
'.woocommerce-checkout-review-order-table' => $woocommerce_order_review,
'.woocommerce-checkout-payment' => $woocommerce_checkout_payment,
'.woocommerce-checkout-shipping-table' => $woocommerce_checkout_shipping_options,
)
),
)
);
All I need to work out now is how to update the update_order_review ajax without editing the core files.
I had the exact same problem and found a solution.
Step 1: Copy and remove the following code in review-order.php
<?php if ( WC()->cart->needs_shipping() && WC()->cart->show_shipping() ) : ?>
<?php do_action( 'woocommerce_review_order_before_shipping' ); ?>
<?php wc_cart_totals_shipping_html(); ?>
<?php do_action( 'woocommerce_review_order_after_shipping' ); ?>
<?php endif; ?>
Step 2: Insert it wherever you want in form-checkout.php and add a div around it
<?php if ( WC()->cart->needs_shipping() && WC()->cart->show_shipping() ) : ?>
<?php do_action( 'woocommerce_review_order_before_shipping' ); ?>
<div class="my-custom-shipping-table">
<?php wc_cart_totals_shipping_html(); ?>
</div>
<?php do_action( 'woocommerce_review_order_after_shipping' ); ?>
<?php endif; ?>
Step 3: Open functions.php of your child theme and add following code
function my_custom_shipping_table_update( $fragments ) {
ob_start();
?>
<div class="my-custom-shipping-table">
<?php wc_cart_totals_shipping_html(); ?>
</div>
<?php
$woocommerce_shipping_methods = ob_get_clean();
$fragments['.my-custom-shipping-table'] = $woocommerce_shipping_methods;
return $fragments;
}
add_filter( 'woocommerce_update_order_review_fragments', 'my_custom_shipping_table_update');
And that's a wrap. 😉
Found the solution here: https://www.ibenic.com/customize-woocommerce-checkout-pages/
Currently trying to change the html structure of the checkout page in woocommerce. I was looking for the template file, so I could add a title here and there. Some re-ordering of the input fields, like e-mail address at the top. But I can't find the template or way how to do it.
I did find the checkout form php file, but that is not what I was looking for. The code of the file:
<?php
/**
* Checkout Form
*
* This template can be overridden by copying it to yourtheme/woocommerce/checkout/form-checkout.php.
*
* HOWEVER, on occasion WooCommerce will need to update template files and you
* (the theme developer) will need to copy the new files to your theme to
* maintain compatibility. We try to do this as little as possible, but it does
* happen. When this occurs the version of the template file will be bumped and
* the readme will list any important changes.
*
* #see https://docs.woocommerce.com/document/template-structure/
* #package WooCommerce\Templates
* #version 3.5.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
do_action( 'woocommerce_before_checkout_form', $checkout );
// If checkout registration is disabled and not logged in, the user cannot checkout.
if ( ! $checkout->is_registration_enabled() && $checkout->is_registration_required() && ! is_user_logged_in() ) {
echo esc_html( apply_filters( 'woocommerce_checkout_must_be_logged_in_message', __( 'You must be logged in to checkout.', 'woocommerce' ) ) );
return;
}
?>
<form name="checkout" method="post" class="checkout woocommerce-checkout" action="<?php echo esc_url( wc_get_checkout_url() ); ?>" enctype="multipart/form-data">
<?php if ( $checkout->get_checkout_fields() ) : ?>
<?php do_action( 'woocommerce_checkout_before_customer_details' ); ?>
<div class="col2-set" id="customer_details">
<div class="col-1">
<?php do_action( 'woocommerce_checkout_billing' ); ?>
</div>
<div class="col-2">
<?php do_action( 'woocommerce_checkout_shipping' ); ?>
</div>
</div>
<?php do_action( 'woocommerce_checkout_after_customer_details' ); ?>
<?php endif; ?>
<?php do_action( 'woocommerce_checkout_before_order_review_heading' ); ?>
<h3 id="order_review_heading"><?php esc_html_e( 'Your order', 'woocommerce' ); ?></h3>
<?php do_action( 'woocommerce_checkout_before_order_review' ); ?>
<div id="order_review" class="woocommerce-checkout-review-order">
<?php do_action( 'woocommerce_checkout_order_review' ); ?>
</div>
<?php do_action( 'woocommerce_checkout_after_order_review' ); ?>
</form>
<?php do_action( 'woocommerce_after_checkout_form', $checkout ); ?>
So the result I want is to re-order the input fields (e-mail at top for example), adding some text here and there and it would be amazing to add some custom classes.
The only thing I found online is to add some filters/hooks into the functions.php. But it feels a little bit hacky to do that.
Edit / additional info:
Sorry if my question wasn't clear. I'm trying to achieve this layout:
<div class="column">
<h2 class="title">Billing Details</h2>
<?php if ( $checkout->get_checkout_fields() ) : ?>
<?php do_action( 'woocommerce_checkout_before_customer_details' ); ?>
<h2> CONTACT INFO </h2>
<div class="field">
<label class="label">First Name</label>
<div class="control">
<input class="input" type="text" placeholder="First Name">
</div>
</div>
<h2> SHIPPING INFO </h2>
etc......
<?php do_action( 'woocommerce_checkout_after_customer_details' ); ?>
<?php endif; ?>
</div>
As you can see I want to re-order the field, but also adding some html tags in it for titles or additional texts. That's why I'm looking for changing the HTML structure/template, instead of the array order of the fields.
I'm using WooCommerce with Flatsome Theme.
I want to add a subtitle to my products.
I installed the WooCommerce Product Subtitle plugin and I see the subtitles only at the shop page, but NOT in the single product page.
I was looking much around the internet but not success.
In the plugin area, I see this help offer:
F.A.Q.s
1.Subtitle not visible in single product page?
This issue might be with the theme which you are using
Please do make sure that your theme has woocommerce_single_product_summary filter in the below files
woocommerce_single_product_summary filter file list :
your-theme/woocommerce/content-product.php
What do I have to do? Here is the page:
<?php
/**
* The template for displaying product content within loops
*/
defined( 'ABSPATH' ) || exit;
global $product;
// Ensure visibility.
if ( empty( $product ) || ! $product->is_visible() ) {
return;
}
// Check stock status.
$out_of_stock = get_post_meta( $post->ID, '_stock_status', true ) == 'outofstock';
// Extra post classes.
$classes = array();
$classes[] = 'product-small';
$classes[] = 'col';
$classes[] = 'has-hover';
if ( $out_of_stock ) $classes[] = 'out-of-stock';
?>
<div <?php fl_woocommerce_version_check( '3.4.0' ) ? wc_product_class( $classes ) : post_class( $classes ); ?>>
<div class="col-inner">
<?php do_action( 'woocommerce_before_shop_loop_item' ); ?>
<div class="product-small box <?php echo flatsome_product_box_class(); ?>">
<div class="box-image">
<div class="<?php echo flatsome_product_box_image_class(); ?>">
<a href="<?php echo get_the_permalink(); ?>">
<?php
/**
*
* #hooked woocommerce_get_alt_product_thumbnail - 11
* #hooked woocommerce_template_loop_product_thumbnail - 10
*/
do_action( 'flatsome_woocommerce_shop_loop_images' );
?>
</a>
</div>
<div class="image-tools is-small top right show-on-hover">
<?php do_action( 'flatsome_product_box_tools_top' ); ?>
</div>
<div class="image-tools is-small hide-for-small bottom left show-on-hover">
<?php do_action( 'flatsome_product_box_tools_bottom' ); ?>
</div>
<div class="image-tools <?php echo flatsome_product_box_actions_class(); ?>">
<?php do_action( 'flatsome_product_box_actions' ); ?>
</div>
<?php if ( $out_of_stock ) { ?><div class="out-of-stock-label"><?php _e( 'Out of stock', 'woocommerce' ); ?></div><?php } ?>
</div><!-- box-image -->
<div class="box-text <?php echo flatsome_product_box_text_class(); ?>">
<?php
do_action( 'woocommerce_before_shop_loop_item_title' );
echo '<div class="title-wrapper">';
do_action( 'woocommerce_shop_loop_item_title' );
echo '</div>';
echo '<div class="price-wrapper">';
do_action( 'woocommerce_after_shop_loop_item_title' );
echo '</div>';
do_action( 'flatsome_product_box_after' );
?>
</div><!-- box-text -->
</div><!-- box -->
<?php do_action( 'woocommerce_after_shop_loop_item' ); ?>
</div><!-- .col-inner -->
</div><!-- col -->
maybe the subtitle is not hooked anywhere in the single product page.
Can you try to add this snippet to your theme's functions.php file?
add_action('woocommerce_shop_loop_item_title', 'fc_single_product_subtitle');
function fc_single_product_subtitle() {
$subtitle = get_product_subtitle( get_the_ID() );
if( ! empty( $subtitle ) ) echo $subtitle;
}
Let me know and good luck!
finelly, after lot of hours...
my site using with Elementor pro, so i just edit the tamplate of single page product from the plugin:
Dashboard > Elementor Tamplates (can show diffrent on some versions).
click edit to my producte page tamplate.
when the elementor builder load my tamplate producte page i just insert shortcode widget and use shortcode [wc-ps] to use with my subtitles data.
Hi im creating my custom woocommerce theme and i want to display to user his order details like order id, total price etc. after checkout. Currently when user click on pay button on checkout page (shop.com/checkout/ where he can fill out billing information) my url change to shop.com/checkout/order-received/98/?key=wc_order_5a70a40f30bde and order appears in woocommerce admin panel so everything works fine, but the user still see checkout page (billing form etc), not the order details page. So the only thing that's change is url, not the page.
Here is my checkout page code:
https://pastebin.com/R3kyE6TW
<?php
$checkout = WC()->checkout;
do_action( 'woocommerce_before_checkout_form', $checkout );
if ( ! $checkout->is_registration_enabled() && $checkout->is_registration_required() && ! is_user_logged_in() ) {
echo apply_filters( 'woocommerce_checkout_must_be_logged_in_message', __( 'You must be logged in to checkout.', 'woocommerce' ) );
return;
}
?>
<form name="checkout" method="post" class="checkout woocommerce-checkout" action="<?php echo esc_url( wc_get_checkout_url() ); ?>" enctype="multipart/form-data">
<div class="row">
<div class="col-md-6">
<?php if ( $checkout->get_checkout_fields() ) : ?>
<?php do_action( 'woocommerce_checkout_before_customer_details' ); ?>
<div class="" id="customer_details">
<div class="">
<?php do_action( 'woocommerce_checkout_billing' ); ?>
</div>
<div class="clearfix"></div>
<div class="woocomerce_additional_custom">
<?php do_action( 'woocommerce_checkout_shipping' ); ?>
</div>
</div>
<?php do_action( 'woocommerce_checkout_after_customer_details' ); ?>
<?php endif; ?>
</div>
<div class="col-md-6">
<h3 id="order_review_heading"><?php _e( 'Your order', 'woocommerce' ); ?></h3>
<?php do_action( 'woocommerce_checkout_before_order_review' ); ?>
<div id="order_review" class="woocommerce-checkout-review-order">
<?php do_action( 'woocommerce_checkout_order_review' ); ?>
</div>
<?php do_action( 'woocommerce_checkout_after_order_review' ); ?>
</div>
</div>
</form>
<?php do_action( 'woocommerce_after_checkout_form', $checkout ); ?>
So how can display to user his order details? Is there any shortcode for order details page like there is for checkout page [woocommerce_checkout] where i can past woocommerce/order/order-details.php code?
I'm building a Woocommerce shop.
In the Checkout page, right over the Order Review (Your Order), it appears by default a duplicated select for the shipping method/costs.
This is redundant as the user already selects the method/cost on the Shopping Cart page. And not only that, every time the user changes the shipping option in the Checkout Page, the select duplicates itself.
You can see the effect if you add a product and go to the Cart here: http://cccctanger.com/openwalls/catalog/
Any idea of what might be going on?
The ideal would be to delete the selects in the Order Review altogether, as it is redundant, but I don't see it in the Checkout page code!
// filter hook for include new pages inside the payment method
$get_checkout_url = apply_filters( 'woocommerce_get_checkout_url', WC()->cart->get_checkout_url() ); ?>
<form name="checkout" method="post" class="checkout woocommerce-checkout" action="<?php echo esc_url( $get_checkout_url ); ?>" enctype="multipart/form-data">
<?php if ( sizeof( $checkout->checkout_fields ) > 0 ) : ?>
<?php do_action( 'woocommerce_checkout_before_customer_details' ); ?>
<div class="row" id="customer_details">
<div class="col-md-6">
<?php do_action( 'woocommerce_checkout_billing' ); ?>
</div>
<div class="col-md-6">
<?php do_action( 'woocommerce_checkout_shipping' ); ?>
</div>
</div>
<?php do_action( 'woocommerce_checkout_after_customer_details' ); ?>
<h3 id="order_review_heading"><?php _e( 'Your order', 'woocommerce' ); ?></h3>
<?php endif; ?>
<?php do_action( 'woocommerce_checkout_before_order_review' ); ?>
<div id="order_review" class="woocommerce-checkout-review-order">
<?php do_action( 'woocommerce_checkout_order_review' ); ?>
</div>
<?php do_action( 'woocommerce_checkout_after_order_review' ); ?>
</form>
<?php do_action( 'woocommerce_after_checkout_form', $checkout ); ?>
I've managed it around it!
First I hide with CSS the Select(s) from the Checkout page.
They are always the same ID, so it's pretty straight forward:
form.checkout select#shipping_method_0{
display: none;
}
Then, in review-order.php, I add a table row to display total shipping price between Subtotal and Total:
<tr class="order-total">
<th><?php _e( 'Shipping', 'woocommerce' ); ?></th>
<td><?php echo WC()->cart->get_cart_shipping_total(); ?></td>
</tr>
And voilà!