I am trying to implement the code below when a discount is applied to an order on my Woocommerce store. Right now, it shows every time a product is added. I am discounting all orders 15% when 5 or more products are added to the cart. But if I only add 2 products the table row still shows (and it shows $40 which is odd). It works great when 5 or more items are added to the cart. Any help would be much appreciated.
<tr class="cart-subtotal">
<th><?php esc_html_e( '15% Discount', 'beaux' ); ?></th>
<td><?php esc_html_e( '-', 'beaux' ); ?><?php echo apply_filters( 'woocommerce_cart_item_price', WC()->cart->get_product_price( $_product ), $cart_item, $cart_item_key ); ?></td>
</tr>
I think you did it using woocommerce templates, it's better to use hooks:
add_filter( 'woocommerce_cart_totals_order_total_html', 'ywp_custom_total_message_html' );
function ywp_custom_total_message_html( $value ) {
global $woocommerce;
$cart_item_count = $woocommerce->cart->cart_contents_count;
if( $cart_item_count >= 5 ) {
$value .= esc_html_e( '15% Discount', 'beaux' ) . '<br />';
}
return $value;
}
Code goes in functions.php of your active theme/child theme. Tested and works.
You can check the number of items in the cart using WC()->cart->get_cart_contents_count().
<?php if ( WC()->cart->get_cart_contents_count() >= 5 ): ?>
<tr class="cart-subtotal">
<th><?php esc_html_e( '15% Discount', 'beaux' ); ?></th>
<td><?php esc_html_e( '-', 'beaux' ); ?><?php echo apply_filters( 'woocommerce_cart_item_price', WC()->cart->get_product_price( $_product ), $cart_item, $cart_item_key ); ?></td>
</tr>
<?php endif; ?>
Just replace your snippet by this one. If less than 5 items are in the cart, the discount won't show.
Related
i am using this following code to show the option to add an additional fee (product) to the cart on the "cart" page. It is working great but it is now showing on the cart page, but how do i get it to show on the checkout page additionally:
<?php
/* ADD custom theme functions here */
add_filter( 'woocommerce_price_trim_zeros', 'wc_hide_trailing_zeros', 10, 1 );
function wc_hide_trailing_zeros( $trim ) {
return true;
}
add_action('woocommerce_cart_totals_after_shipping', 'wc_shipping_insurance_note_after_cart');
function wc_shipping_insurance_note_after_cart() {
global $woocommerce;
$product_id = 971;
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->id == $product_id )
$found = true;
}
// if product not found, add it
if ( ! $found ):
?>
<tr class="shipping">
<th><?php _e( 'Gift wrapper', 'woocommerce' ); ?></th>
<td><?php _e( 'Add ($3)' ); ?> </td>
</tr>
<?php else: ?>
<tr class="shipping">
<th><?php _e( 'Gift wrapper', 'woocommerce' ); ?></th>
<td>$3</td>
</tr>
<?php endif;
}
I have tried different methods, and it should be pretty basic but i am rusty on my Functions.php skills.
You could try copying the function and giving it a new name. Then change the hook depending on where you want it on the checkout page.
Here is a great visual guide to the hooks on the checkout page: https://www.businessbloomer.com/woocommerce-visual-hook-guide-checkout-page/
Try something like this:
Notice how I changed the hook from woocommerce_cart_totals_after_shipping to woocommerce_before_checkout_form here you can experiment using the hooks on the guide I linked to. I also changed the name of the function from wc_shipping_insurance_note_after_cart to wc_shipping_insurance_note_after_checkout to avoid conflicts.
add_action('woocommerce_before_checkout_form', 'wc_shipping_insurance_note_after_checkout');
function wc_shipping_insurance_note_after_checkout() {
global $woocommerce;
$product_id = 971;
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->id == $product_id )
$found = true;
}
// if product not found, add it
if ( ! $found ):
?>
<tr class="shipping">
<th><?php _e( 'Gift wrapper', 'woocommerce' ); ?></th>
<td><?php _e( 'Add ($3)' ); ?> </td>
</tr>
<?php else: ?>
<tr class="shipping">
<th><?php _e( 'Gift wrapper', 'woocommerce' ); ?></th>
<td>$3</td>
</tr>
<?php endif;
}
Edit per comment. You could try something like this if you only want to add the table row if a product in the cart has a certain category.
You will have to change "example-category" in $categories = array('example-category'); to your category slug.
add_action('woocommerce_before_checkout_form','wc_shipping_insurance_note_after_checkout');
function wc_shipping_insurance_note_after_checkout() {
global $woocommerce;
$categories = array('example-category');
$found = false;
//loop trough cart items
foreach ( WC()->cart->get_cart_contents() as $cart_item_key => $cart_item ) {
$product_id = $cart_item['product_id'];
//Check if product has category
if ( has_term( $categories, 'product_cat', $product_id ) ) {
$found = true;
}
}
// Do this if product has category
if ( $found ) {
?>
<tr class="shipping">
<th><?php _e( 'Gift wrapper', 'woocommerce' ); ?></th>
<td><?php _e( 'Add ($3)' ); ?> </td>
</tr>
<?php
} else {
//If product does not have category do this instead
?>
<tr class="shipping">
<th><?php _e( 'Gift wrapper', 'woocommerce' ); ?></th>
<td>$3</td>
</tr>
<?php
}
}
I'm using a coupon for a calculation in the Woocommerce cart. It automatically adds a discount to the total so the right amount can be sent to payments gateways.
I'd like to hide all infos about this coupons/discount from visitors.
Problem: The only method I've found (see below) hides the coupon field, row (from totals) and messages, but also disable the coupon...
add_filter( 'woocommerce_coupons_enabled', 'hide_coupon_field' );
function hide_coupon_field( $enabled ) {
if ( is_cart() || is_checkout() ) {
$enabled = false;
}
return $enabled;
}
Is there a hook allowing to hide everything related to the discount without canceling the coupon?
EDIT:
Looks like it's impossible to simply remove the discount line in the order-details. So a simple solution, inspired by helgatheviking suggestion, might be to remove all the totals generated by this part
<?php if ( $totals = $order->get_order_item_totals() ) foreach ( $totals as $total ) : ?>
<tr>
<th scope="row"><?php echo $total['label']; ?></th>
<td><?php echo $total['value']; ?></td>
</tr>
<?php endforeach; ?>
And then to echo them one by one the way I need it. I'm already able to show the order total with this
<td><?php echo number_format($order->get_total(),2,'.','')."€"; ?></td>
but now I'm trying to retrieve the order subtotal, and this code
<td><?php echo number_format($order->get_item_subtotal(),2,'.','')."€"; ?></td>
gives me a Warning: Missing argument 1 for WC_Order::get_item_subtotal().
I'm not sure if get_item_subtotal() is the right way to get the order subtotal. And if so, what argument is missing? Or should I search around get_line_subtotal or get_subtotal_to_display?
No, there does not seem to be as there is no filter in the get_coupons() method of the cart class. If you went to the WooCommerce git repo and sent a pull request with a filter here and an explanation as to why it should be there, they might consider merging it in. I've done that a few times.
You could also, copy the checkout/review-order.php and cart/cart-totals.php templates into your theme and remove the following two blocks of code:
<?php foreach ( WC()->cart->get_coupons( 'cart' ) as $code => $coupon ) : ?>
<tr class="cart-discount coupon-<?php echo esc_attr( $code ); ?>">
<th><?php wc_cart_totals_coupon_label( $coupon ); ?></th>
<td><?php wc_cart_totals_coupon_html( $coupon ); ?></td>
</tr>
<?php endforeach; ?>
and
<?php foreach ( WC()->cart->get_coupons( 'order' ) as $code => $coupon ) : ?>
<tr class="order-discount coupon-<?php echo esc_attr( $code ); ?>">
<th><?php wc_cart_totals_coupon_label( $coupon ); ?></th>
<td><?php wc_cart_totals_coupon_html( $coupon ); ?></td>
</tr>
<?php endforeach; ?>
Keep in mind that this prevents the display of ALL coupon discounts and will end up looking like the following screenshots:
I'm not a fan of overriding the more complex WC templates... especially not the ones pertaining to the checkout process. I've had to fix many sites that stopped working when their theme template overrides became obsolete as WooCommerce develops.
Edit
I tracked down the Discount row in the order/order-details.php template. It is from the function $order->get_order_item_totals()... this returns an array of rows and can be filtered. So, this removes the row from the order received page:
function so_25714509_get_order_item_totals( $total_rows ){
unset( $total_rows['order_discount'] );
return $total_rows;
}
add_filter( 'woocommerce_get_order_item_totals', 'so_25714509_get_order_item_totals' );
I tried to call in the mini cart woocommerce_cart_totals() to get a coupon discount. But in mini cart it's not working. It's working only when I go to the cart page and refresh the page.
After this, discount in mini cart is working fine. But now I want to know, why it's not working in another page? And not working without cart page refresh?
<?php foreach ( WC()->cart->get_coupons() as $code => $coupon ) : ?>
<tr class="cart-discount coupon-<?php echo esc_attr( sanitize_title( $code ) ); ?>">
<th><?php wc_cart_totals_coupon_label( $coupon ); ?></th>
<td data-title="<?php echo esc_attr( wc_cart_totals_coupon_label( $coupon, false ) ); ?>"><?php wc_cart_totals_coupon_html( $coupon ); ?></td>
</tr>
<?php endforeach; ?>
I have built a custom plugin and I need to be able to add custom meta to the user profile screen.
I have the meta showing but they don't seem to update. This is the first instance of this meta so it doesn't exist in the DB already.
The files are located in my plugin dir and not in my theme.
<?php
add_action( 'show_user_profile', 'add_extra_social_links' );
add_action( 'edit_user_profile', 'add_extra_social_links' );
function add_extra_social_links( $user )
{
?>
<h3>Web App Information</h3>
<table class="form-table">
<tr>
<th><label for="companyname">Company Name</label></th>
<td>
<?php
$args = array(
'post_type' => array('operators','clients'),
'posts_per_page' => -1,
'orderby' => 'title',
);
$myposts = get_posts( $args );
echo '<select id="companyname"name="companyname">';
echo '<option value="' . esc_attr(get_the_author_meta( 'companyname', $user->ID )) . '">';
foreach ( $myposts as $post ) : setup_postdata( $post ); ?>
<option value="<?php echo $post->post_title; ?>">
<?php echo $post->post_title; ?>
</option>
<?php endforeach;
echo '</select>';
wp_reset_postdata();?>
</td>
</tr>
<tr>
<th><label for="companyadmin">Is this user a company admin.</label></th>
<td>
<?php
echo '<select id="companyadmin" name="companyadmin">';
echo '<option value="' . esc_attr(get_the_author_meta( 'companyadmin', $user->ID )) . '">';
echo '<option value="Y">Yes, is admin.</option>';
echo '<option value="N">No, is not admin.</option>';
echo '</select>';
?>
</td>
</tr>
</table>
<?php
}
add_action( 'personal_options_update', 'save_extra_social_links' );
add_action( 'edit_user_profile_update', 'save_extra_social_links' );
function save_extra_social_links( $user_id )
{
update_user_meta( $user_id,'companyname', $_POST['companyname'] );
update_user_meta( $user_id,'companyadmin', $_POST['companyadmin'] );
}
?>
try use function get_current_user_id in $user_id
i think you use parameter but not send in hook
I'm trying to get some data from an order in a woocommerce email template, but get_post_meta just returns false. This code works on the thankyou page. I have spent too much time on this. Any help would be appreciated. Thanks!
global $post;
echo "test!!!<br />";
$x = get_post_meta( $order->id, 'attendee_data', true );
$y = get_post_meta( $order->id, 'attendee_test', true );
echo $order->id . '<br />';
echo $x;
echo $y;
I've attached a picture of the sql as well as an email.
SQL: http://i.stack.imgur.com/zUFBa.png
Email: http://i.stack.imgur.com/Uqtih.png
The whole email template:
<?php do_action('woocommerce_email_header', $email_heading); ?>
<p><?php _e( "Your order has been received and is now being processed. Your order details are shown below for your reference:", 'woocommerce' ); ?></p>
<?php do_action( 'woocommerce_email_before_order_table', $order, $sent_to_admin, $plain_text ); ?>
<h2><?php echo __( 'Order:', 'woocommerce' ) . ' ' . $order->get_order_number(); ?></h2>
<table cellspacing="0" cellpadding="6" style="width: 100%; border: 1px solid #eee;" border="1" bordercolor="#eee">
<thead>
<tr>
<th scope="col" style="text-align:left; border: 1px solid #eee;"><?php _e( 'Product', 'woocommerce' ); ?></th>
<th scope="col" style="text-align:left; border: 1px solid #eee;"><?php _e( 'Quantity', 'woocommerce' ); ?></th>
<th scope="col" style="text-align:left; border: 1px solid #eee;"><?php _e( 'Price', 'woocommerce' ); ?></th>
</tr>
</thead>
<tbody>
<?php echo $order->email_order_items_table( $order->is_download_permitted(), true, ( $order->status=='processing' ) ? true : false ); ?>
</tbody>
<tfoot>
<?php
if ( $totals = $order->get_order_item_totals() ) {
$i = 0;
foreach ( $totals as $total ) {
$i++;
?><tr>
<th scope="row" colspan="2" style="text-align:left; border: 1px solid #eee; <?php if ( $i == 1 ) echo 'border-top-width: 4px;'; ?>"><?php echo $total['label']; ?></th>
<td style="text-align:left; border: 1px solid #eee; <?php if ( $i == 1 ) echo 'border-top-width: 4px;'; ?>"><?php echo $total['value']; ?></td>
</tr><?php
}
}
?>
</tfoot>
</table>
<?php
global $post;
echo "test!!!<br />";
$x = get_post_meta( $order->id, 'attendee_data', true );
$y = get_post_meta( $order->id, 'attendee_test', true );
echo $order->id . '<br />';
echo $x;
echo $y;
foreach ( $x as $k => $p ) {
echo $k ." ... ". $p;
} ?>
<?php // attendee_order_details($order->get_order_number()) ?>
<?php do_action( 'woocommerce_email_after_order_table', $order, $sent_to_admin, $plain_text ); ?>
<?php do_action( 'woocommerce_email_order_meta', $order, $sent_to_admin, $plain_text ); ?>
<h2><?php _e( 'Customer details', 'woocommerce' ); ?></h2>
<?php if ($order->billing_email) : ?>
<p><strong><?php _e( 'Email:', 'woocommerce' ); ?></strong> <?php echo $order->billing_email; ?></p>
<?php endif; ?>
<?php if ($order->billing_phone) : ?>
<p><strong><?php _e( 'Tel:', 'woocommerce' ); ?></strong> <?php echo $order->billing_phone; ?></p>
<?php endif; ?>
<?php wc_get_template( 'emails/email-addresses.php', array( 'order' => $order ) ); ?>
<?php do_action( 'woocommerce_email_footer' ); ?>
I did some testing based on your info and tried to reproduce your problems.
First I created a function which inserts the post meta (attendee_test and attendee_data) when placing an order (using the woocommerce_checkout_update_order_meta hook like you do).
I added this in my themes functions.php (Note that the values are based on your input (image from db) and are not dynamic, just for testing):
add_action('woocommerce_checkout_update_order_meta', 'add_meta_values', 2);
function add_meta_values($order_id){
// array with attendee data
$attendee_data = array(
array(
'edit' => 'false',
'company' => 'get',
)
);
add_post_meta( $order_id, 'attendee_data', $attendee_data );
add_post_meta( $order_id, 'attendee_test', 'test' );
}
Then I added the following code to the template customer-processing-order.php:
<?php
$attendee_data = get_post_meta( $order->id, 'attendee_data', true );
$attendee_test = get_post_meta( $order->id, 'attendee_test', true );
echo 'Order ID: ' . $order->id . '<br />';
echo 'Attendee Test: ' . $attendee_test . '<br />';
echo 'Attendee Data:<br />';
foreach ( $attendee_data as $k => $data ) {
foreach ($data as $key => $value){
echo $key . ' .. ' . $value . '<br />';
}
} ?>
As you can see I modified it a bit to make it more clear. Also changed the $attendee_data loop because I think that wasn't completely right (needed an extra foreach). Of course this isn't related to the real problem.
Making a testorder will show the following data in the email:
This result demonstrate that get_post_meta is working in the email template based on the code above. (I used Wordpress 4.0.1 and WooCommerce 2.2.10).
If the test above is working fine also in your case then I think that the values are inserted in your database after the email is sent (they are inserted right, but to late).
Another thing you might want to check is resending the confirmation email. You can do this from the Wordpress admin. When you edit an order you have a dropdown 'Actions' on the right side. You can select 'Processing order' under 'Resend order emails'. Then click the refresh icon next to the dropdown and you will receive the order confirmation email again. See screenshot below:
This time you know for sure the values are already in the database before you're sending the email.
Hope this information is helping you to solve the problem.
Well, 'attendee_data' is a serialized object so the third argument passed on the function get_post_meta must be set to false (or omitted).
$x = get_post_meta( $order->id, 'attendee_data', false );