Move Checkout Shipping Options in Woocommerce - php

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/

Related

Insert highlighted products div in middle of Woocommerce loop

I want to insert a featured product area in the middle of the normal woocommerce loop.
The code for the woocommerce loop is
<?php
if ( woocommerce_product_loop() ) {
do_action( 'woocommerce_before_shop_loop' );
woocommerce_product_loop_start();
if ( wc_get_loop_prop( 'total' ) ) {
while ( have_posts() ) {
the_post();
do_action( 'woocommerce_shop_loop' );
wc_get_template_part( 'content', 'product' );
}
}
woocommerce_product_loop_end();
do_action( 'woocommerce_after_shop_loop' );
} else {
do_action( 'woocommerce_no_products_found' );
}
do_action( 'woocommerce_after_main_content' );
?>
The shortcode I want to insert after 8 products is
<div class="cart-upsell hide-on-desktop clear">
<h3 class="centered">You May Also Like...</h3>
<?php echo do_shortcode('[products limit="2" columns="2" orderby="rand" order="DESC"]')?>
</div>
Currently this is shown at the end of the loop but think it will work better in the middle - only displaying on mobile devices.
So how can I get this into the middle of the loop?
This should work:
<?php
if ( woocommerce_product_loop() ) {
do_action( 'woocommerce_before_shop_loop' );
woocommerce_product_loop_start();
if ( wc_get_loop_prop( 'total' ) ) {
$i = 1;
while ( have_posts() ) {
the_post();
do_action( 'woocommerce_shop_loop' );
wc_get_template_part( 'content', 'product' );
if(8 === $i){
?>
<div class="cart-upsell hide-on-desktop clear">
<h3 class="centered">You May Also Like...</h3>
<?php echo do_shortcode('[products limit="2" columns="2" orderby="rand" order="DESC"]')?>
</div>
<?php
}
$i++;
}
}
woocommerce_product_loop_end();
do_action( 'woocommerce_after_shop_loop' );
} else {
do_action( 'woocommerce_no_products_found' );
}
do_action( 'woocommerce_after_main_content' );
?>

How to add feed ads in WooCommerce

I try to add feed ads in product thumbnails of my website
There is no error and website is running fine. But No ads has been comeup in my website. How to achieve this in feed ads in WooCommerce product thumbnail.
I have edited my woocommerce-teplate.php as
if ( ! function_exists( 'woocommerce_content' ) ) {
/**
* Output WooCommerce content.
*
* This function is only used in the optional 'woocommerce.php' template.
* which people can add to their themes to add basic woocommerce support.
* without hooks or modifying core templates.
*/
function woocommerce_content() {
$i=1;
if ( is_singular( 'product' ) ) {
while ( have_posts() ) :
the_post();
if($i==5||$i==7||$i==10){?>
#my adsense code
<?php }
wc_get_template_part( 'content', 'single-product' );
$i++;
endwhile;
} else {
?>
<?php if ( apply_filters( 'woocommerce_show_page_title', true ) ) : ?>
<h1 class="page-title"><?php woocommerce_page_title(); ?></h1>
<?php endif; ?>
<?php do_action( 'woocommerce_archive_description' ); ?>
<?php if ( woocommerce_product_loop() ) : ?>
<?php do_action( 'woocommerce_before_shop_loop' ); ?>
<?php woocommerce_product_loop_start(); ?>
<?php if ( wc_get_loop_prop( 'total' ) ) : ?>
<?php $i++; while ( have_posts() ) : ?>
<?php the_post(); ?>
<?php if($i==5||$i==7||$i==10){?>
#my adsense code
<?php }?>
<?php wc_get_template_part( 'content', 'product' ); ?>
<?php $i++;?>
<?php endwhile; ?>

Subtitle not shown in single product page using WooCommerce Product Subtitle plugin

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.

Custom select on checkout page Woocommerce

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

Wordpress php can't show custom meta info on post listings page for each post

I have created a custom post type within WordPress, and for that custom post type I have custom meta boxes where I can input the price of a product rental either per day or per week (there are 2 meta boxes).
I want to display these prices on the page that displays all the posts from my custom post type. My theme has an action hook just after the title of the post which is where I want to display the meta info.
I have managed to hook into the action, however, my information only shows on the first post, not on all of them.
Here is the code I am using to echo out the meta info:
function add_prices_to_products() {
global $post;
$price_per_day = get_post_meta($post->ID, "_per_day", true);
$price_per_week = get_post_meta($post->ID, "_per_week", true);
echo '<span class="sl_product_price per_day">£' . $price_per_day . '/day</span>';
echo '<span class="sl_product_price per_week">£' . $price_per_week . '/wk</span>';
}
add_action('layers_after_list_post_title', 'add_prices_to_products');
Can anyone tell me why it is just adding to the first post and not to all of them (I can confirm that the meta info is saving correctly)?
Here is the code of the page from the theme (index.php):
<?php get_header(); ?>
<div class="container content-main archive clearfix">
<?php get_sidebar( 'left' ); ?>
<?php if( have_posts() ) : ?>
<div <?php layers_center_column_class(); ?>>
<?php while( have_posts() ) : the_post(); ?>
<?php get_template_part( 'partials/content' , 'list' ); ?>
<?php endwhile; // while has_post(); ?>
<?php the_posts_pagination(); ?>
</div>
<?php endif; // if has_post() ?>
<?php get_sidebar( 'right' ); ?>
</div>
<?php get_footer();
it references the file content-list.php which is what contains the hook.
global $post, $layers_post_meta_to_display; ?>
<article id="post-<?php the_ID(); ?>" <?php post_class( 'push-bottom-large' ); ?>>
<?php do_action('layers_before_list_post_title'); ?>
<header class="section-title large">
<?php do_action('layers_before_list_title'); ?>
<h1 class="heading"><?php the_title(); ?></h1>
<?php do_action('layers_after_list_title'); ?>
</header>
<?php do_action('layers_after_list_post_title'); ?>
<?php /**
* Display the Featured Thumbnail
*/
echo layers_post_featured_media( array( 'postid' => get_the_ID(), 'wrap_class' => 'thumbnail push-bottom', 'size' => 'large' ) ); ?>
<?php if( '' != get_the_excerpt() || '' != get_the_content() ) { ?>
<?php do_action('layers_before_list_post_content'); ?>
<?php do_action('layers_list_post_content'); ?>
<?php do_action('layers_after_list_post_content'); ?>
<?php } ?>
<?php do_action('layers_before_list_post_meta'); ?>
<?php /**
* Display the Post Meta
*/
layers_post_meta( get_the_ID(), NULL, 'footer', 'meta-info push-bottom' ); ?>
<?php do_action('layers_after_list_post_meta'); ?>
<?php do_action('layers_before_list_read_more'); ?>
<?php do_action('layers_list_read_more'); ?>
<?php do_action('layers_after_list_read_more'); ?>
</article>
It's also worth mentioning that I am hooking in from a plugin
UPDATE
Using the hook "the_post" I am able to echo out plain text on each post in the list, however, I can't get my meta box info to echo yet. Here is what I'm using now:
add_action( 'the_post', 'my_custom_loop_start' );
function my_custom_loop_start( $query )
{
echo 'hello';
add_action( 'loop_end', 'my_custom_loop_end' );
}
function my_custom_loop_end()
{
remove_action( 'layers_after_list_post_title', 'add_prices_to_products' );
}
You need to hook into each item in the loop, try something like this...
// Hook into the main loop
add_action( 'loop_start', 'my_custom_loop_start' );
// Add two filters in that loop - your existing function and one to clear it out
function my_custom_loop_start( $query )
{
if( $query->is_main_query() )
{
add_filter( 'layers_after_list_post_title', 'add_prices_to_products' );
add_action( 'loop_end', 'my_custom_loop_end' );
}
}
// This will just remove your action once each loop is done so you get the correct data for each loop
function my_custom_loop_end()
{
remove_action( 'layers_after_list_post_title', 'add_prices_to_products' );
}
You may need to tweak this to work properly, but the logic is adding your function to each loop, running it, then removing it.

Categories