I have found two bits of code that are really useful for setting "backorder" text on our website, however they need to be combined to work properly:
The first simply changes the text for all backorders
And the second works when a meta_value is present by displaying the custom meta_value text, however displays nothing if no meta_value is present.
Ideally the way i would want it to work, is for it to display the custom text if there is something present, or some pre-defined text if the meta_value is unavailable for that product.
Any help would be GREATLY appreciated!!
FIRST SAMPLE CODE I FOUND:
function backorder_text($available) {
foreach($available as $i) {
$available = str_replace('Available on backorder', 'Will ship in March', $available);
}
return $available;
}
add_filter('woocommerce_get_availability', 'backorder_text');
SECOND SAMPLE CODE I FOUND:
add_filter( 'woocommerce_get_availability' , 'revised_woocommerce_get_availability' , 10, 2 );
function revised_woocommerce_get_availability( $available_array , $product) {
if ( $product->managing_stock() ) {
if ( !($product->is_in_stock() && $product->get_stock_quantity() > get_option( 'woocommerce_notify_no_stock_amount' )) && ($product->backorders_allowed() && $product->backorders_require_notification()) ) {
$custom_meta_value = get_post_meta( $product->id, 'Out_of_stock_message', true );
$available_array["availability"] = $custom_meta_value;
}
}
return $available_array;
}
Related
I am using on of the Widgets included with WooCommerce called Filter products by attribute. I created a widgetized area on the category page in my Storefront-child-theme functions.php (see code below).
But when I filter by attribue size M for example, it lists products where size M is out of stock...
Any idea how to fix this?
EXAMPLE: Filtering by size M displays this product, which is not available:
/* FILTER BY SIZE WIDGET */
// Adding the widget area.
if (function_exists('register_sidebar')) {
register_sidebar(array(
'name' => 'Below category title',
'id' => 'extra-widget-area',
'description' => 'Below category title',
'before_widget' => '<div class="widget below-cat-title-widget">',
'after_widget' => '</div>',
'before_title' => '<h6 class="below-cat-title-widget-title">',
'after_title' => '</h6>'
));
}
// placing the widget
add_action( 'woocommerce_archive_description', 'add_my_widget_area', 31 );
function add_my_widget_area() {
if (function_exists('dynamic_sidebar')) {
dynamic_sidebar('Below category title');
}
}
add_action( 'woocommerce_archive_description', 'filter_button_function', 21 );
function filter_button_function() {
// if ( is_product_category() ) {
// global $wp_query;
// $cat_id = $wp_query->get_queried_object_id();
// $cat_desc = term_description( $cat_id, 'product_cat' );
if (get_locale() == 'fr_FR') {
$filter_html = '<div class="filter_by_size" class="subtitle">'.'FILTRE PAR TAILLE'.' <span class="filter-icon"></span>'.'</div>';
} else {
$filter_html = '<div class="filter_by_size" class="subtitle">'.'FILTER BY SIZE'.' <span class="filter-icon"></span>'.'</div>';
}
echo $filter_html;
// }
}
I'll be direct : by default, you can't. It's not related to a certain theme or plugin, but to Woocommerce itself. This is a problem that exists in woocommerce for a very long time. It's not possible by default in woocommerce to handle variable products stock visibility (stock status) based on it's variations visibility as it's something necessary and needed by Woocommerce1.
A way of doing this is to add this action function :
add_action('woocommerce_before_shop_loop_item', 'out_of_stock_variations_loop');
function out_of_stock_variations_loop()
{
global $product;
$filter = 'size';
if ($product->product_type === 'variable') {
$available = $product->get_available_variations();
if ($available) {
foreach ($available as $instockvar) {
if (isset($instockvar[ 'attributes' ][ 'attribute_pa_' . $filter ])) {
if ($_GET[ 'filter_' . $filter ]) {
if ( !in_array( $instockvar[ 'attributes' ][ 'attribute_pa_' . $filter ], explode(',', $_GET[ 'filter_' . $filter ]) , true ) || ($instockvar[ 'max_qty' ] <= 0) ) {
echo "<style>.post-" . $product->get_id() . " {display: none}</style>";
} else {
echo "<style>.post-" . $product->get_id() . " {display: list-item !important}</style>";
}
}
}
}
}
}
}
?>
Which will only show the list of products in stock. The problem with this is that it will leave blank spaces where the not-in-stock products are deleted by this query, and it can be difficult to circumvent this problem only with css because, on each row, first and last products have first and last classes that determines their layout in CSS. To overcome this, add this jQuery to your child-theme js script:
function openLayeredNavFilterIfSelected() {
if (jQuery('.wc-layered-nav-term').hasClass('woocommerce-widget-layered-nav-list__item--chosen')) {
/*keep layered nav filter open, if at least an attribute is selected*/
jQuery('.woocommerce-widget-layered-nav-list__item--chosen').parent().parent().show();
if (!jQuery('.filter-icon').hasClass('arrow_up')) {
jQuery('.filter-icon').addClass('arrow_up');
}
/*redistribute products rows to avoid missing spaces*/
jQuery('.site-main ul.products.columns-3 li.product').removeClass('first').removeClass('last');
jQuery('.site-main ul.products.columns-3 li.product:visible').each(function(i) {
if (i % 3 == 0) jQuery(this).addClass('first'); //add class first to firsts products of rows
if (i % 3 == 2) jQuery(this).addClass('last'); //add class last to lasts products of rows
});
}
}
openLayeredNavFilterIfSelected();
jQuery(window).resize(openLayeredNavFilterIfSelected);
And you should be good to go.
1 WOOF Products Filter plugin and out of stock variations issue in Woocommerce
Related :
- filter products by attribute and hide out of stock items of variable products
- How to prevent `out of stock` items to show as a filter option in the sidebar (layered nav widget ) in WooCommerce?
- https://wordpress.org/support/topic/hide-out-of-stock-variations-when-filtering/#post-7718128
- https://xtemos.com/forums/topic/filter-attributes-dont-show-out-of-stock-variations/
- https://wordpress.org/support/topic/exclude-out-of-stock-products-from-filter/
Not a really good answer here.
As #Islam Elshobokshy said, it's a bit complex to edit the product loop query to remove out of stock variations.
Still, you can trick using CSS to "hide" out of stock variations from the list. But it may "break" your product list/grid: if there is enough product for 2 pages (10 items/page), but one product is hidden on page 1 by this filter, page 1 will only have 9 products. We are after the product query.
I quickly tested and wrote something inspired from this:
this works for a size attribute (it could be adapted to handle all attributes from Woocommerce, or URL parameters "filter_*", or hardcoded for every attribute used)
Code:
add_action('woocommerce_before_shop_loop_item', 'out_of_stock_variations_loop');
function out_of_stock_variations_loop()
{
global $product;
$filter = 'size'; //to edit
if ($product->product_type === 'variable') {
$available = $product->get_available_variations();
if ($available) {
foreach ($available as $instockvar) {
if (isset($instockvar[ 'attributes' ][ 'attribute_pa_' . $filter ])) {
if (($instockvar[ 'attributes' ][ 'attribute_pa_' . $filter ] === $_GET[ 'filter_' . $filter ]) && ($instockvar[ 'max_qty' ] <= 0)) {
//sadly echo some inline CSS :(
echo "<style>.post-" . $product->get_id() . " {display: none}</style>";
//some tests using is_visible() filters, but we are too late here
//add_filter( 'woocommerce_product_is_visible', function($visible, $id) use ($the_id) {return $id === $the_id ? false : $visible;}, 50, 2);
}
}
}
}
}
}
To achieve the same without inline CSS, you can:
override /woocommerce/template/content-product.php to your-theme/woocommerce/content-product.php
move the code below in a method($product), edit it a bit to return true/false only for required products
Call it in the "Ensure visibility" block like if ( empty( $product ) || ! $product->is_visible() || !$method($product) )
this will prevent outputting the product, but will not resolve the grid/list issue.
In the end, updating the loop query to match your need may be complex, and negatively impact performance. But, to explore more, I would start something like:
add a query_var by detecting GET filter parameter (or directly detecting wp_query parameter matching the filter/attribute you know that will filter)
find and hook around the woocommerce product wp_query
hook a method that will detect your custom query_var
edit the query, but if it comes to raw SQL, it may be painful..
I need to set a custom text like 'Free Download' instead of the 0 price for Easy Digital Download on both single and variable pricing.
I found the code snippet below that has the necessary functions for variable pricing but it only works for single prices:
function sumobi_edd_free_download_text_args( $args ) {
// Enter the button text for a free download
$free_download_text = 'Free download';
$variable_pricing = edd_has_variable_prices( $args['download_id'] );
if ( $args['price'] && $args['price'] !== 'no' && ! $variable_pricing ) {
$price = edd_get_download_price( $args['download_id'] );
if ( 0 == $price ) {
$args['text'] = $free_download_text;
}
}
return $args;
}
add_filter( 'edd_purchase_link_args', 'sumobi_edd_free_download_text_args' );
How is it even possible ? I mean I can clearly see the part $variable_pricing = edd_has_variable_prices but instead it changes the single price.
Edit: now I'm pretty sure that it all has something to do with the string $args['text'] = $free_download_text; if I could add "price" to this string, then it would overwrite the 0 prices. I tried this but it didn't work : $args['text'] && $args['price'] = $free_download_text;
I would like:
http://www.gadgetgogo.co.uk/?s=ipod
to return as:
http://www.gadgetgogo.co.uk/?s=ipod&post_type=product
So when using searches (slider banner and default WordPress search) it produces the second URL.
I was looking for similar solution as you but couldn't find any and at last I combined last few answers that I read here and got this working fine as I wanted.
Add below code in your theme's functions.php file
function wpb_change_search_url() {
if ( is_search() && ! empty( $_GET['s'] ) && ($_GET['post_type'] != 'product') ) {
wp_redirect( home_url( "/?s=" ) . urlencode( get_query_var( 's' ) ) . "&post_type=product" );
exit();
}
}
add_action( 'template_redirect', 'wpb_change_search_url' );
hope it will help you and others.
Apparently current WooCommerce versions only consider a search query a product search (and render using the appropriate template), if $query->is_post_type_archive( 'product' ) is true, so the key is to set not only the post_type, but the is_post_type_archive property as well, and to do it before WooCommerce loads its filter (default priority of 10), so with a priority of 9 or smaller.
Example to add into funtions.php:
function my_search_filter($query) {
if ( $query->is_search && ! is_admin() ) {
$query->set( 'post_type', 'product' );
$query->is_post_type_archive = true;
}
}
add_filter('pre_get_posts','my_search_filter', 9);
Please note, that this code will override all searches as product serach, so if you have other searches as well, implement appropriate checks at the begining of my_search_filter.
Just add this line to top of search.php
$_GET['post_type'] = 'product'
This can be done using pre_get_posts filter. Add below code in your theme's functions.php file
add_filter( 'pre_get_posts', 'search_by_product_only' );
function search_by_product_only( $query ) {
// check if search query only
if ( $query->is_search ) {
$query->set( 'post_type', array( 'product') ); // here you can add multiple post types in whcih you want to search
}
return $query;
}
I have created a short code to display short description in woo commerce but it is not working on all posts. It is displaying the short description on some posts and not on others.
Function to create that short code in functions.php
function product_shortdesc_shortcode( $atts ){
// use shortcode_atts() to set defaults then extract() to variables
extract( shortcode_atts( array( 'id' => false ), $atts ) );
// if an $id was passed, and we could get a Post for it, and it's a product....
if ( ! empty( $id ) && null != ( $product = get_post( $id ) ) && $product->post_type = 'product' ){
// apply woocommerce filter to the excerpt
echo apply_filters( 'woocommerce_short_description', $product->post_excerpt );
}
}
// process [product_shortdesc] using product_shortdesc_shortcode()
add_shortcode( 'product_shortdesc', 'product_shortdesc_shortcode' );
The way i am getting the data in my single.php file
$custom = get_post_custom(get_the_ID());
$my_custom_field = $custom['woo_id'];
foreach ( $my_custom_field as $key => $value ) {
echo do_shortcode('[product_shortdesc id='.$value.']');
}
PS: in my normal post i have a custom field which has the value of product id of the product in woo commerece.
Your issue is that you are expecting shortcodes to function which no longer exist. On new installs, these pages won't be created, but if you are updating you may already have those pages in place.
Although the upgrade script does attempt to trash them for you, this might not have happened if they were customised. Delete them. Delete edit-account and change password, then go to your 'my account' page and click the change password/edit account links. You'll be taken to and endpoint which offers the same functionality.
Thanks
Short Code must not echo code instead return the things that needs to be rendered
Change this
echo apply_filters( 'woocommerce_short_description', $product->post_excerpt );
to
return apply_filters( 'woocommerce_short_description', $product->post_excerpt );
I am trying to get Wordpress to show a 1 column layout when adding a new post using the following code in my functions file.
function wpsnippy_one_columns_posts_layout( $columns ) {
$columns['vehicle'] = 1;
return $columns; } add_filter( 'screen_layout_columns', 'wpsnippy_one_columns_posts_layout' ); function wpsnippy_screen_layout_posts() {
return 1; } add_filter( 'get_user_option_screen_layout_post', 'wpsnippy_screen_layout_posts' );
This is working fine if logged in as admin, however I have a user type 'seller' and it is not working for seller, I actually need it to be the other way around, 1 column if seller 2 if anything else.
Your input will be greatly appreciated, many thanks.
We can filter the function get_user_option() and force 1 column:
add_filter( 'get_user_option_screen_layout_post', function( $result, $option, $user )
{
if( in_array( 'seller', $user->roles ) )
$result = '1';
return $result;
}, 10, 3 );
Note that the option is defined like: "screen_layout_$page".