Is there a way to create columns for woocommerce, I want it to be 3 columns, column 1(step1) the billing information, column 2(step2) shipping method and payment method, column 3(step3) item details and checkout button, all in one checkout page, or is there a plugin for this?
<?php
/**
* Checkout Form
*
* #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->enable_signup && ! $checkout->enable_guest_checkout && ! is_user_logged_in() ) {
echo apply_filters( 'woocommerce_checkout_must_be_logged_in_message', __( 'You must be logged in to checkout.', 'woocommerce' ) );
return;
}
// 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="onecheckout">
<div class="step-1">Step One</div>
<?php do_action( 'woocommerce_checkout_billing' ); ?>
</div>
<div class="onecheckoutmid">
<div class="step-2">Step Two</div>
<h6>Delivery Method</h6>
<div class="col-2">
<?php do_action( 'woocommerce_checkout_shipping' ); ?>
</div>
</div>
<div class="onecheckout">
<div class="step-3">Step Three</div>
<h6>Confirm Order</h6>
</form>
WooCommerce provides the ability to override their checkout template files by adding a woocommerce directory into your WordPress theme and making any adjustments you need there.
It would require overriding several template files, but with some custom HTML and CSS, you could probably achieve the results you are looking for.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed last month.
Improve this question
I've been struggling to change the layout of my woocommerce checkout page. I'd like to move the Shipping details to the right, so it's side-by-side with the billing. I was able to move the order details section to the right side via CSS but I also want the shipping to move there, just above the order summary and I can't seem to do it in CSS.
You have to override the WooCommerce checkout form.
How to override:
Copy the checkout form from the path plugins/woocommerce/templates/checkout/form-checkout.php and paste in your activated theme (for e.g. here I'm pasting it inside my customized child theme of WordPress official theme twentytwenty) in the following path themes/twentytwenty-child/woocommerce/checkout/form-checkout.php
Override the content like this:
<?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>
<?php do_action( 'woocommerce_checkout_after_customer_details' ); ?>
<?php endif; ?>
<?php do_action( 'woocommerce_checkout_before_order_review_heading' ); ?>
<div class="col2-set">
<div class="col-1">
<h3 id="cus-shipping-heading">Shipping Details</h3>
<?php do_action( 'woocommerce_checkout_shipping' ); ?>
</div>
</div>
<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 ); ?>
Explaination of the changes:
Removed the shipping section from the div#customer_details
Add that section next to the action hook <?php do_action( 'woocommerce_checkout_before_order_review_heading' ); ?>
Here is the snippet of the section we added:
<div class="col2-set">
<div class="col-1">
<h3 id="cus-shipping-heading">Shipping Details</h3>
<?php do_action( 'woocommerce_checkout_shipping' ); ?>
</div>
</div>
After the change the checkout page will look like this:
I created a post_type "Case Studies", created a category template over-ride page and call a Post Grid Shortcode in that category template over-ride but it always ommits the latest post of the type... The post grid shortcode correctly displays all 'Case Studies'.
It is like it has an offset=1...
Code - page named 'category-case-studies.php':
<?php
get_header();
?>
<div <?php echo apply_filters('shrk-page-cover-atts', 'page-cover'); ?> >
<div class="container">
<header class="page-header">
<h1 class="page-title">Case Studies</h1>
</header>
</div><!-- .entry-header -->
<?php do_action('shrk-page-cover-after'); ?>
</div>
<div class="container container-main-content">
<div class="row">
<div class="main-content-inner">
<div class="col-xs-12 col-sm-12 breadcrumb-inner">
<?php
if (function_exists('yoast_breadcrumb')) {
yoast_breadcrumb('<nav id="woocommerce-breadcrumb">', '</nav>');
}
?>
</div>
</div>
</div>
</div>
<div class="container container-main-content">
<div class="row after-breadcrumb">
<div class="main-content-inner col-12 <?php echo esc_attr(shrk_get_main_inner_class()); ?>">
<?php
echo do_shortcode('[vc_row][vc_column][vc_basic_grid post_type="post" max_items="10" element_width="6" grid_id="vc_gid:1575382949300-f7c10d1d-4924-6" taxonomies="96" offset="0"][/vc_column][/vc_row]');
?>
<?php get_sidebar(); ?>
</div><!-- close .*-inner (main-content or sidebar, depending if sidebar is used) -->
</div><!-- close .row -->
</div><!-- close .container .container-main-content -->
<?php get_footer(); ?>
REEALLY odd though... Other category types display all posts of that category type (just checked and yes it does...)
I have a feeling (though I am clutching at straws) that it is something to do with being on a category page of the same name/type as the category type...
Any advice appreciated.
## UPDATE TO INCLUDE do_shortcode()
/**
* Search content for shortcodes and filter shortcodes through their hooks.
*
* If there are no shortcode tags defined, then the content will be returned
* without any filtering. This might cause issues when plugins are disabled but
* the shortcode will still show up in the post or content.
*
* #since 2.5.0
*
* #global array $shortcode_tags List of shortcode tags and their callback hooks.
*
* #param string $content Content to search for shortcodes.
* #param bool $ignore_html When true, shortcodes inside HTML elements will be skipped.
* #return string Content with shortcodes filtered out.
*/
function do_shortcode( $content, $ignore_html = false ) {
global $shortcode_tags;
if ( false === strpos( $content, '[' ) ) {
return $content;
}
if ( empty( $shortcode_tags ) || ! is_array( $shortcode_tags ) ) {
return $content;
}
// Find all registered tag names in $content.
preg_match_all( '#\[([^<>&/\[\]\x00-\x20=]++)#', $content, $matches );
$tagnames = array_intersect( array_keys( $shortcode_tags ), $matches[1] );
if ( empty( $tagnames ) ) {
return $content;
}
$content = do_shortcodes_in_html_tags( $content, $ignore_html, $tagnames );
$pattern = get_shortcode_regex( $tagnames );
$content = preg_replace_callback( "/$pattern/", 'do_shortcode_tag', $content );
// Always restore square braces so we don't break things like <!--[if IE ]>
$content = unescape_invalid_shortcodes( $content );
return $content;
}
After implementing and doing design changes locally on a project, the woocommerce messages are not showing anymore on the single product page. I don't get any console errors, so I don't think it has anything to do with that. And the request is processed since when I go to see the cart from another page, then the item that I was trying to add is on the list, it is just that the message doesn't show on a singe product page. I am not sure where to go about?
This is the add-to-cart/variable file:
<?php
/**
* Variable product add to cart
*
* #author WooThemes
* #package WooCommerce/Templates
* #version 2.4.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
global $product;
$attribute_keys = array_keys( $attributes );
do_action( 'woocommerce_before_add_to_cart_form' ); ?>
<form class="variations_form cart" method="post" enctype='multipart/form-data' data-product_id="<?php echo absint( $product->id ); ?>" data-product_variations="<?php echo esc_attr( json_encode( $available_variations ) ) ?>">
<?php do_action( 'woocommerce_before_variations_form' ); ?>
<?php if ( empty( $available_variations ) && false !== $available_variations ) : ?>
<p class="stock out-of-stock"><?php _e( 'This product is currently out of stock and unavailable.', 'woocommerce' ); ?></p>
<?php else : ?>
<div class="variations" cellspacing="0">
<?php foreach ( $attributes as $attribute_name => $options ) : ?>
<div class="row">
<div class="small-3 columns">
<label for="<?php echo sanitize_title( $attribute_name ); ?>" class="text-left middle">
<strong><?php echo wc_attribute_label( $attribute_name ); ?></strong>
</label>
</div>
<div class="small-9 columns">
<?php
$selected = isset( $_REQUEST[ 'attribute_' . sanitize_title( $attribute_name ) ] ) ? wc_clean( $_REQUEST[ 'attribute_' . sanitize_title( $attribute_name ) ] ) : $product->get_variation_default_attribute( $attribute_name );
wc_dropdown_variation_attribute_options( array( 'options' => $options, 'attribute' => $attribute_name, 'product' => $product, 'selected' => $selected ) );
echo end( $attribute_keys ) === $attribute_name ? '<a class="reset_variations" href="#">' . __( 'Clear selection', 'woocommerce' ) . '</a>' : '';
?>
</div>
</div>
<?php endforeach;?>
</div>
<?php do_action( 'woocommerce_before_add_to_cart_button' ); ?>
<div class="row single_variation_wrap" style="display:none;">
<div class="small-9 small-offset-3 columns">
<?php
/**
* woocommerce_before_single_variation Hook
*/
do_action( 'woocommerce_before_single_variation' );
/**
* woocommerce_single_variation hook. Used to output the cart button and placeholder for variation data.
* #since 2.4.0
* #hooked woocommerce_single_variation - 10 Empty div for variation data.
* #hooked woocommerce_single_variation_add_to_cart_button - 20 Qty and cart button.
*/
do_action( 'woocommerce_single_variation' );
/**
* woocommerce_after_single_variation Hook
*/
do_action( 'woocommerce_after_single_variation' );
?>
</div>
</div>
<?php do_action( 'woocommerce_after_add_to_cart_button' ); ?>
<?php endif; ?>
<?php do_action( 'woocommerce_after_variations_form' ); ?>
</form>
<?php do_action( 'woocommerce_after_add_to_cart_form' ); ?>
This looks like quite an old version of the variable.php template, if you have anything higher than WooCommerce 2.4.0 installed (i checked against the 2.5.0 version of this template) there are enough significant changes that might break certain parts of WooCommerce.
One difference that immediately stood out to me was that the data-product_variations attribute on the form in later versions uses htmlspecialchars instead of esc_attr.
Hope this helps!
I have been searching on the web, reading docs & stuff but I can't figure out on replacing product in Checkout Page.
For your information, my main product page is in the Home Page and each product that have been selected, will redirected to Checkout Page. Now here, there is a problem. Let me explain....
You see, I have a carousel slider in Checkout Page which user can change/replace their product (which already been added into their cart) before they pay.
form-checkout.php
global $woocommerce;
global $product;
$items = $woocommerce->cart->get_cart();
foreach ($items as &$item){
$id = $item['product_id'];
}
echo $id;
<div id="carousel-example-generic" class="carousel slide" data-ride="carousel" data-interval="false">
<div class="carousel-inner" role="listbox">
<?php
// Querying of product information retrieval
$args = array( 'post_type' => 'product', 'posts_per_page' => 4, 'orderby' =>'menu_order', 'order' =>'ASC');
$loop = new WP_Query( $args );
// Display each retrieved product
while ( $loop->have_posts() ) :
$loop->the_post();
// WooCommerce global product variable. Refer: https://docs.woothemes.com/document/class-reference/
global $product;
global $woocommerce;
?>
<div class="item <?php if ($product->id == $id) { ?> active <?php } ?>">
<div class="p-big" id="p-custom-color">
<strong><?php the_title(); ?></strong>
</div>
<div class="p-light-black">CANDIDATES</div>
<input type="hidden" id="product" name="productid" value="<?php echo $product->id; ?>">
</div>
<?php
endwhile;
wp_reset_query(); // After the loop ended, quit the custom loop and reset back the main loop
?>
</div>
</div>
<!-- Upon form submission -->
if (isset($_POST['woocommerce_checkout_place_order'])){
global $woocommerce;
$woocommerce->cart->empty_cart(); // Empty the cart
$selectedproduct = $_POST['selectedproductid']; // Get the selected product
do_shortcode('[add_to_cart id="' . $selectedproduct . '"]'); // Insert the selected product in the the cart
return esc_url( wc_get_checkout_url() ); // Redirect to Payment Gateway Page
}
<form name="checkout" method="post" class="checkout woocommerce-checkout" action="" enctype="multipart/form-data">
<?php if ( sizeof( $checkout->checkout_fields ) > 0 ) : ?>
<?php do_action( 'woocommerce_checkout_before_customer_details' ); ?>
<?php do_action( 'woocommerce_checkout_billing' ); ?>
<?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">
<!-- Checkout Review -->
<input type="hidden" id="selectedproduct" name="selectedproductid" value="">
<?php do_action( 'woocommerce_checkout_order_review' ); ?>
</div>
<?php do_action( 'woocommerce_checkout_after_order_review' ); ?>
</form>
As you can see, in the carousel, I have included <input type="hidden" id="product" name="productid" value="<?php echo $product->id; ?>"> to get each product ID and with my jQuery (I didn't show here), I took any product ID that the product is currently on the active slide and fill it in the <input type="hidden" id="selectedproduct" name="selectedproductid" value=""> in the form.
By that, I can replace the product that have been added to cart with the selected/chosen product based on the active slide with these code (Located above the form):-
<!-- Upon form submission -->
if (isset($_POST['woocommerce_checkout_place_order'])){
global $woocommerce;
$woocommerce->cart->empty_cart(); // Empty the cart
$selectedproduct = $_POST['selectedproductid']; // Get the selected product
do_shortcode('[add_to_cart id="' . $selectedproduct . '"]'); // Insert the selected product in the the cart
return esc_url( wc_get_checkout_url() ); // Redirect to Payment Gateway Page
}
The problem here is, it failed to replace the old product with the current chosen product and it just redirect to the payment gateway page with the old product.
I want it to replace the product with the new selected ones upon placing order. Is it possible? I hope it is, because I have been playing with WooCommerce for weeks now and I don't want my effort to be futile. Help me guys.....
After few days of figuring this out, with 30+ Chrome tabs, 50+ of purchases test & 10 gallons of coffee, finally I found the answer...
add_action('woocommerce_checkout_process', 'change_product_upon_submission');
function change_product_upon_submission() {
if ( !empty( $_POST['_wpnonce'] ) && !empty($_POST['selectedproductid']) ) {
$selectedproduct = $_POST['selectedproductid']; // Get the selected product
WC()->cart->empty_cart(); //Empty the cart
WC()->cart->add_to_cart( $selectedproduct ); // Insert the selected product in the cart
}
}
The hook required to trigger this function is within the WC_Checkout process_checkout() class in includes/class-wc-checkout.php. This woocommerce_checkout_process doesn't exist WooCommerce template files, we're gonna be thorough. So to do whatever custom stuff before sending data to the payment gateway upon place order submission, we're gonna need to manipulate the woocommerce_checkout_process hook as process_checkout() function processes the checkout after the confirm order button is pressed.
Hope this save someone's lives as I don't have any because I need to sleep after few days of burning midnight oil figuring this abomination.
I am having Issue in my checkout page. I am getting Two Place order button(click here). I tried to fix it in form-checkout.php even I checked in form-pay.php, in wp-content/themes/mytheme/woocommerce/checkout.
I checked in wordpress forum I got solution to remove two checkout button from cart page, there is no solution for my problem
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
global $woocommerce;
wc_print_notices();
do_action( 'woocommerce_before_checkout_form', $checkout );
// 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" action="<?php echo esc_url( $get_checkout_url ); ?>">
<?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_order_review' ); ?>
</form>
<?php do_action( 'woocommerce_after_checkout_form' ); ?>
Go to wp-content/themes/mytheme/woocommerce/checkout/view-order.php. In View-order.php remove id="payment" completle
This issue is because of theme version
Please check your configuration in your WordPress admin.
Woocommers->settings on the Payment Tab check your information details if you have miss an HTML tags.
I have experience on this when I customized or add some html tags on the details text area with closing "div" tag.