How to override Schema 'availability' in Woocommerce? - php

I need to override Schema 'availability' option to Preorder for Woocommerce (3.9.2) products on backorder. Currently WC generates 'InStock' for them. Which filters and how do I apply? My current code (below) ruins Wordpress, seems like filter is wrong:
function tt_WC_change_schema_availability( $availability ) {
if ( is_product() && ! is_admin() ) {
$stock_status = $product->is_in_stock();
$output = 'OutOfStock'; // default, out of stock
if ($stock_status){
$output = 'InStock';
$qty = $product->get_stock_quantity();
if ( ! ($qty > 0) ) {
$output = 'PreOrder';
}
}
return 'http://schema.org/' . $output;
}
}
add_filter( 'woocommerce_structured_data_product_offer', 'tt_WC_change_schema_availability' );

It looks like you are close, but the $product object also has to be included in your function. It's the second parameter that can be passed to this filter. Also, you want to return part of the array that gets sent to the woocommerce_structured_data_product_offer filter. This would be $availability['availability'] since you're passing the variable as $availability
function tt_WC_change_schema_availability( $availability, $product ) {
if ( is_product() && ! is_admin() ) {
$stock_status = $product->get_stock_status();
$output = 'OutOfStock'; // default, out of stock
if ($stock_status){
$output = 'InStock';
$qty = $product->get_stock_quantity();
if ( ! ($qty > 0) ) {
$output = 'PreOrder';
}
}
return $availability['availability'] = 'http://schema.org/' . $output;
}
}
add_filter( 'woocommerce_structured_data_product_offer', 'tt_WC_change_schema_availability' , 10, 2 );

Many thanks to #Howard E! I've found out that $stock_status returns a string, also added extra check if product stock's managed. Here's working function:
function tt_WC_change_schema_availability( $markup_offer, $product ) {
if ( is_product() && ! is_admin() ) {
$managed = $product->managing_stock();
if ($managed === TRUE) {
$stock_status = $product->get_stock_status();
if ($stock_status == 'instock'){
$output = 'InStock';
}
if ($stock_status == 'onbackorder') {
$output = 'PreOrder';
}
if ($stock_status == 'outofstock') {
$output = 'OutOfStock';
}
}
$markup_offer['availability'] = 'http://schema.org/' . $output;
}
return $markup_offer;
}
add_filter( 'woocommerce_structured_data_product_offer', 'tt_WC_change_schema_availability' , 10, 2 );

Related

Add the min price difference in WooCommerce variable products attribute dropdown options

I have products with multiple attributes allowing for multiple dimensions of variations. I'd like to show the price difference in the dropdown, but it is not comparing the absolute minimum price, for each option.
This is the code I am using:
add_filter( 'woocommerce_variation_option_name','display_price_in_variation_option_name');
function display_price_in_variation_option_name( $term ) {
global $product;
if ( empty( $term ) ) {
return $term;
}
if ( empty( $product->id ) ) {
return $term;
}
$variation_id = $product->get_children();
$price_min = $product->get_variation_regular_price();
foreach ( $variation_id as $id ) {
$_product = new WC_Product_Variation( $id );
$variation_data = $_product->get_variation_attributes();
foreach ( $variation_data as $key => $data ) {
if ( $data == $term ) {
$html = $term;
$price_diff = $_product->get_price() - $price_min;
$price_html = '';
if ($price_diff > 0 ) { $price_html = ' (+£' . number_format((float)$price_diff, 2, '.', '') . ')';}
$html .= $price_html;
return $html;
}
}
}
return $term;
}
However, this is only showing the minimum price of the current attribute, not the product as a whole.
I hope this is clear - ideally in the above image for options that do not add cost, $price_html should be blank. The code works perfectly for variations with a single attribute option, but does not work for variations with multiple attribute options.
Your code can be simplified and optimized, but it can't work with multiple attribute dropdowns. It can only work if there is a unique attribute dropdown (see the alternative way after).
So this code works only with one attribute dropdown:
add_filter( 'woocommerce_variation_option_name','display_diff_price_in_attribute_option_name', 10, 4 );
function display_diff_price_in_attribute_option_name( $term_name, $term, $attribute, $product ) {
if ( ! is_a($product, 'WC_Product') || is_admin() ) {
return $term_name;
}
$price_min = $product->get_variation_regular_price('min', true); // Min price for display
foreach ( $product->get_children() as $variation_id ) {
$variation = wc_get_product($variation_id);
$term_value = $variation->get_attribute($attribute);
if ( $term_value == $term_name ) {
$price_diff = wc_get_price_to_display($variation) - $price_min;
if ($price_diff > 0 ) {
$term_name .= ' (+' . strip_tags( wc_price( $price_diff ) ) . ')';
}
break;
}
}
return $term_name;
}
So you need something different (when there is multiple attribute dropdowns).
The following code will display the price difference for the select variation, for example at the right of the selected variation price:
add_filter( 'woocommerce_available_variation', 'filter_available_variation_attributes', 10, 3 );
function filter_available_variation_attributes( $data, $product, $variation ){
$price_min = $product->get_variation_regular_price('min', true); // Min price for display
$price_diff = $data['display_price'] - $price_min;
if ($price_diff > 0 ) {
$data['price_html'] = '<span class="price">' . $variation->get_price_html() . ' <em>(+' . wc_price( $price_diff ) . ')</em></span>';
}
return $data;
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.

WooCommerce show on-sale badge only for logged in users

I want to display sale bubble in WooCommerce only for logged in users.
I have a function which hides sale-bubble for unlogged users but if I log in there is showing only value "1" instead of sale-bubble.
I know why, because I am returning a true, but I cant figure out how to return sale-bubble instead of true..
WooCommerce
add_filter('woocommerce_sale_flash', 'woo_custom_hide_sales_flash');
function woo_custom_hide_sales_flash()
{
if ( is_user_logged_in() ) {
return true;
}
return false;
}
You are not using this filter hook in the right way. Try the following:
add_filter( 'woocommerce_sale_flash', 'filter_sales_flash_callback', 100, 3 );
function filter_sales_flash_callback( $output_html, $post, $product )
{
if ( ! is_user_logged_in() ) {
$output_html = false;
}
return $output_html;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
function sales_badge() {
global $product;
if ( ! $product->is_on_sale() ) return;
if ( $product->is_type( 'simple' ) ) {
$max_percentage = ( ( $product->get_regular_price() - $product->get_sale_price() ) / $product->get_regular_price() ) * 100;
} elseif ( $product->is_type( 'variable' ) ) {
$max_percentage = 0;
foreach ( $product->get_children() as $child_id ) {
$variation = wc_get_product( $child_id );
$price = $variation->get_regular_price();
$sale = $variation->get_sale_price();
if ( $price != 0 && ! empty( $sale ) ) $percentage = ( $price - $sale ) / $price * 100;
if ( $percentage > $max_percentage ) {
$max_percentage = $percentage;
}
}
}
if ( $max_percentage > 0 ) { ?>
<span class="prinjal-sale-badge"><?php echo round($max_percentage) . "%"; ?></span>
<?php
}
}
// use shortcode instead of action and then use shortcode anywhere you want to ouptut it
add_shortcode( 'custom_sales_badge', 'sales_badge' );
my problem solve using this code you can place any ware you want to display sale badge
function sales_markup() {
if(!is_admin()) {
if(is_user_logged_in()) {
// Instead of outputting add the markup that you want to show
$output = '<div class="Sales_markup_here">
</div>';
return $output;
}
}
}
// use shortcode instead of action and then use shortcode anywhere you want to ouptut it
add_shortcode( 'sales_markup', 'sales_markup' );
Use the shortcode where you want to output the bubble. You can add the css in the global css file.

Customs product price on sale displayed with date limit in Woocommerce 3+

I have code which prints text after the price when on sale and I am now getting an error using this code, which I did not get before. It says: "PHP Warning: date() expects parameter 2 to be integer" and it refers to this line:
$sales_price_date_to = date( "j.M.Y", $sales_price_to );
Any ideas on how to fix it?
add_filter( 'woocommerce_get_price_html', 'custom_price_html', 100, 2 );
function custom_price_html( $price, $product ){
global $post;
$sales_price_to = get_post_meta( $product->id, '_sale_price_dates_to', true );
$sales_price_date_to = date( "j.M.Y", $sales_price_to );
if ( is_single() ) {
if($product->is_type( 'simple' ) && $sales_price_to != "" ) {
$sales_price_date_to = date("j.m.Y", $sales_price_to);
return str_replace( '</ins>', ' </ins> <span class="notice-price">(on offer until '.$sales_price_date_to.')</span>', $price );
} else if ( $product->is_type( 'variable' ) ){
$handle = new WC_Product_Variable( $product->id);
$variations1 = $handle->get_children();
$content_variations = "";
$count_each_var = 0;
foreach ($variations1 as $value) {
$count_each_var++;
$single_variation = new WC_Product_Variation($value);
$var_id = $single_variation->variation_id;
$sales_price_to_variable = get_post_meta($var_id, '_sale_price_dates_to', true);
if( $sales_price_to_variable != '' ){
$sales_price_date_to = date("j.m.Y", $sales_price_to_variable);
if($count_each_var == 1) {
$class_val = 'class="active"';
} else {
$class_val = "";
}
$content_variations .= "<i data-id='". $var_id ."' data-order='".$count_each_var."' $class_val >".$sales_price_date_to."</i>";
} else {
$content_variations .= "";
}
}
if( $content_variations != ''){
return str_replace( '</ins>', ' </ins> <span class="notice-price">(on offer until '.$content_variations.')</span>', $price );
} else {
return $price;
}
} else {
return apply_filters( 'woocommerce_get_price', $price );
}
}
}
Been trying to fix it, but I can't.
Your code is really outdated ans more since Woocommerce 3 as a lot of things have changed.
I have completely revisited your code making it up to date for Woocommerce 3+ versions:
add_filter( 'woocommerce_get_price_html', 'custom_price_html', 100, 2 );
function custom_price_html( $price, $product ){
if ( is_product() ) {
// Simple products and variations
if( $product->is_type( 'simple' ) || $product->is_type( 'variation' ) )
{
$sales_price_to = $product->get_date_on_sale_to();
if( ! empty($sales_price_to) ){
$replacement = ' </ins> <span class="notice-price">(on offer until ';
return str_replace( '</ins>', $replacement . date( 'j.M.Y', $sales_price_to->getTimestamp() ) . ')</span>', $price );
}
}
// Variable products
else if ( $product->is_type( 'variable' ) )
{
$content = '';
// Loop through variations
foreach ( $product->get_children() as $key => $variation_id ) {
$variation = wc_get_product($variation_id);
$sales_price_to = $variation->get_date_on_sale_to();
if( ! empty($sales_price_to) ){
$date_to = date( 'j.M.Y', $sales_price_to->getTimestamp() );
$class = $key == 0 ? 'class="active"' : '';
$content .= '<i data-id="'.$variation_id.'" data-order="'.($key + 1).'" '.$class.'>'. $date_to .'</i>';
}
}
if( ! empty($content) ){
return $price . ' <span class="notice-price">(on offer until ' . $content .')</span>';
}
}
}
return $price;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.

Conditional function that check if products are already in cart in Woocommerce 3

Hi solution provided here WooCommerce - Check if item's are already in cart working perfect. This is the function code:
function woo_in_cart($arr_product_id) {
global $woocommerce;
$cartarray=array();
foreach($woocommerce->cart->get_cart() as $key => $val ) {
$_product = $val['product_id'];
array_push($cartarray,$_product);
}
if (!empty($cartarray)) {
$result = array_intersect($cartarray,$arr_product_id);
}
if (!empty($result)) {
return true;
} else {
return false;
};
}
Usage
$my_products_ids_array = array(22,23,465);
if (woo_in_cart($my_products_ids_array)) {
echo 'ohh yeah there some of that products in!';
}else {
echo 'no matching products :(';
}
But I need use as if(in_array) but no luck so far. What i doing wrong?
$my_products_ids_array = array("69286", "69287",);
if (in_array("69286", $my_products_ids_array)) {
echo '<p>' . the_field ( 'cart_field', 'option' ) . '</p>';
}
if (in_array("69287", $my_products_ids_array)) {
echo '<p>' . the_field ( 'cart_field-1', 'option' ) . '</p>';
}
Thank you
Your main function code is outdated.
For Advanced custom fields (ACF):
you need to use get_field() (that return the field value) instead of the_field() (that echo the field value).
You may need to add a product ID as 2nd argument in get_field('the_slug', $product_id ).
So try:
function is_in_cart( $ids ) {
// Initialise
$found = false;
// Loop Through cart items
foreach( WC()->cart->get_cart() as $cart_item ) {
// For an array of product IDS
if( is_array($ids) && ( in_array( $cart_item['product_id'], $ids ) || in_array( $cart_item['variation_id'], $ids ) ) ){
$found = true;
break;
}
// For a unique product ID (integer or string value)
elseif( ! is_array($ids) && ( $ids == $cart_item['product_id'] || $ids == $cart_item['variation_id'] ) ){
$found = true;
break;
}
}
return $found;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
The custom conditional function is_in_cart( $ids ) accept a string (a unique product Id) or an array of product Ids.
Your revisited usage (ACF get_field may need a post ID (product ID)):
if ( is_in_cart( "69286" ) ) {
echo '<p>' . get_field ( 'cart_field' ) . '</p>'; // or get_field ( 'cart_field', "69286" )
}
if ( is_in_cart( "69287" ) ) {
echo '<p>' . get_field ( 'cart_field-1' ) . '</p>'; // or get_field ( 'cart_field', "69287" )
}

Woocommerce Is_Purchasable cause ajax error

I'm using the code below to modify the WooCommerce Is_Purchasable option so that, item Y is purchasable if item X is added to the cart.
But it gives ajax error when trying to add item Y to the cart.
Here's the code:
function aelia_get_cart_contents() {
$cart_contents = array();
/**
* Load the cart object. This defaults to the persistant cart if null.
*/
$cart = WC()->session->get( 'cart', null );
if ( is_null( $cart ) && ( $saved_cart = get_user_meta( get_current_user_id(), '_woocommerce_persistent_cart', true ) ) ) {
$cart = $saved_cart['cart'];
} elseif ( is_null( $cart ) ) {
$cart = array();
}
if ( is_array( $cart ) ) {
foreach ( $cart as $key => $values ) {
$_product = wc_get_product( $values['variation_id'] ? $values['variation_id'] : $values['product_id'] );
if ( ! empty( $_product ) && $_product->exists() && $values['quantity'] > 0 ) {
if ( $_product->is_purchasable() ) {
// Put session data into array. Run through filter so other plugins can load their own session data
$session_data = array_merge( $values, array( 'data' => $_product ) );
$cart_contents[ $key ] = apply_filters( 'woocommerce_get_cart_item_from_session', $session_data, $values, $key );
}
}
}
}
return $cart_contents;
}
// Step 1 - Keep track of cart contents
add_action('wp_loaded', function() {
// If there is no session, then we don't have a cart and we should not take
// any action
if(!is_object(WC()->session)) {
return;
}
// Product Y
global $y_cart_items;
$y_cart_items = 2986;
//Product X
global $x_cart_items;
$x_cart_items = array(
'297'
);
// Step 2
add_filter('woocommerce_is_purchasable', function($is_purchasable, $product) {
global $y_cart_items;
global $x_cart_items;
if( $product->id == $y_cart_items ) {
// make it false
$is_purchasable = false;
// get the cart items object
foreach ( aelia_get_cart_contents() as $key => $item ) {
// do your condition
if( in_array( $item['product_id'], $x_cart_items ) ) {
// Eligible product found on the cart
$is_purchasable = true;
break;
}
}
}
return $is_purchasable;
}, 10, 2);
}, 10);
// Step 3 - Explain customers why they can't add some products to the cart
add_filter('woocommerce_get_price_html', function($price_html, $product) {
if(!$product->is_purchasable() && is_product()) {
$price_html .= '<p>' . __('Add Product X to be able to purchase Product Y.', 'woocommerce') . '</p>';
}
return $price_html;
}, 10, 2);
How do I fix this? Thank you.

Categories