Hide elements based on a specific element value - woocommerce

I have a woocommerce store and I’m importing custom fields like “color”, “length”, etc (around 10 fields) but not all product have values for these fields. Is there a way to hide the whole element of the value is empty or null. On the front end the elements show like this:
Length: 10cm
Height: 20cm
So basically if there is no length for a specific product I want to hide it.
Link to see: (check product extra details. In this example I only want to show the diameter and hide the rest since they are empty)
https://qadeemarabia.com/product/3d-bird-cookie-jar-off-white-matt/

You must use the woocommerce_display_product_attributes filter to delete empty items. My hypothesis for the empty condition is that the value is zero. You can change the condition according to what you need:
add_filter( 'woocommerce_display_product_attributes', 'ywp_hide_ptoperties_with_empty_values', 10, 2 );
function ywp_hide_ptoperties_with_empty_values( $attributes, $product ) {
// Loop to check values
foreach( $attributes as $attr ) {
$new_attr = array();
// Your condition for check value is empty
// You can use 'trim' etc.
$value = floatval( $attr['value'] );
// Check value is 0 here means value is empty
// and empty value skipped
if( $value != 0 ) {
$new_attr[] = $attr;
}
}
return $new_attr;
}
This code goes into the functions.php file of your active theme/child theme. Tested and works.

Related

Gravity Forms - Accessing field defined in shortcode

I'm writing a rating system using Gravity Forms. Next to each post is a "Vote" link which opens a lightbox with a Gravity Forms shortcode in it. The shortcode populates two hidden fields - the Post ID and the User ID:
[gravityform id="2" field_values="gf_rating_post=123&gf_rating_user=456" title="false" description="false" ajax="true" tabindex="49"]
Inside the form are dropdown menus to rate the various elements, from 1-10. I'm trying to write code to insert SELECTED with the previously selected value from the dropdown, but I need to be able to reference the Post ID in order to retrieve that previously selected value.
add_filter('gform_pre_render_2', 'ac_populate_post_ratings');
add_filter('gform_pre_validation_2', 'ac_populate_post_ratings');
add_filter('gform_pre_submission_filter_2', 'ac_populate_post_ratings');
add_filter('gform_admin_pre_render_2', 'ac_populate_post_ratings');
function ac_populate_post_ratings($form) {
foreach ( $form['fields'] as &$field ) {
if ( $field->type != "select" || strpos( $field->cssClass, 'populate-posts' ) ) {
continue;
}
$choices = $field->choices;
foreach ( $choices as $choice ) {
// echo "defaultValue: " . $field->defaultValue . "<br />";
$newchoices[] = array( 'text' => $choice['text'], 'value' => $choice['value'] );
}
$field->choices = $newchoices;
}
return $form;
}
It seems that because the Post ID value is dynamically added to the form, it isn't able to be referenced using the field's defaultValue, which is always empty even though when you view the source, the input value is set correctly.
Any ideas how I can reference that Post ID inside the ac_populate_post_ratings() function?
As a last ditch effect, I contacted Gravity Forms support, and they came through with the goods.
The field defaultValue property will only contain a value if you have configured that setting in the form editor. Values which are being dynamically populated are not available from the $form.
The gform_pre_render filter is passed the dynamic population values from the shortcode in its third param.
I needed to change this line:
add_filter('gform_pre_render_2', 'ac_populate_post_ratings');`
to this:
add_filter('gform_pre_render_2', 'ac_populate_post_ratings', 10, 3 );`
And this line:
function ac_populate_post_ratings($form) {
to this:
function ac_populate_post_ratings( $form, $ajax = false, $field_values = array() ) {
And now I can access the values like so:
$gf_rating_post = rgar( $field_values, 'gf_rating_post' );

Showing "Out of Stock" text next to variation in Woocommerce product with multuiple variations

I have been looking EVERYWHERE and I cannot seem to find a solution to a very simple problem. I have a Woocommerce store and I want to show to the user a message "Out of stock" next to the variation if it is out of stock. I do not want it grayed out, I want the user to be able to select it so they can view the price if they wish. Most snippets I find online only works when they product has ONE variation but I need it to work for at least two. My website sells mobile devices so for example:
If a user selects the storage as 64GB then the color list updates showing which colors are out of stock in 64GB. If all colors are out of stock then next to 64GB it shows "Out of stock" also.
If the color is selected first, then the storage - the color list is then updated with what is out of stock.
Can anyone help me out here? Going insane trying to get this working. The below code works to gray out out of stock products in the exact way I mentioned above (it works for multiple products) but I can't figure out how to modify it for the use case mentioned above.
add_filter( 'woocommerce_variation_is_active', 'grey_out_variations_when_out_of_stock', 10, 2 );
function grey_out_variations_when_out_of_stock( $grey_out, $variation ){
if ( ! $variation->is_in_stock() ){
return false;
}else{
print_r($option_class);
return $term_name . ' - Out of Stock';;
}
}
You can check the availability of a product variation only if all but one of the attributes have been selected, not before.
All the necessary data is present on the product page and therefore you can use a jQuery script to process it.
In the variation form there is the data-product_variations attribute which contains an array with all the details of the product variations (variation id, stock status, attributes it uses, etc ...).
You can then make a comparison between the selected attributes and possible product variations.
The idea is this:
Check that there is more than one attribute (dropdown) on the product page
If all attributes (dropdowns) have been selected except one, get the attribute slug and the attribute value of the selected options
It compares them with the attributes that each single variation uses and, if the selected attributes are the same, gets the stock status of the last attribute to be selected
Adds the text "Out of stock" to each option whose product variation is not in stock. To do this it will use the woocommerce_update_variation_values event which fires after updating the options via Ajax (otherwise the changes will be overwritten)
The following code will work for 2 or more attributes (dropdowns) in
the variable product page.
// add the text "Out of stock" to each option of the last unselected attribute dropdown
add_action( 'wp_footer', 'add_out_of_stock_text_to_the_last_unselected_attribute_dropdown' );
function add_out_of_stock_text_to_the_last_unselected_attribute_dropdown() {
?>
<script type="text/javascript">
// initializes a global variable that will contain the attribute values to be updated ("Out of stock")
let globalAttributesToUpdate;
jQuery(function($){
// check if only one attribute is missing to be selected
function isLastAttribute(){
// if there is only one dropdown it returns false
if ( $('form.variations_form select').length == 1 ) {
return false;
}
// counts all selected attributes (excluding "Choose an option")
let count = 0;
$('form.variations_form select').each(function(){
if ( $(this).find(':selected').val() ) {
count++;
}
});
// if an attribute has not yet been selected, it returns true
if ( $('form.variations_form select').length - count == 1 ) {
return true;
} else {
return false;
}
}
$('form.variations_form select').change(function() {
if ( isLastAttribute() ) {
// clear the global variable every time
globalAttributesToUpdate = [];
let attrToFind = {}; // contains an object with slug and value of the selected attributes
let attrToSet; // contains the slug of the attribute not yet selected
$('form.variations_form select').each(function(index,object){
if ( $(this).find(":selected").val() ) {
attrToFind[$(this).data('attribute_name')] = $(this).find(":selected").val();
} else {
attrToSet = $(this).data('attribute_name');
}
});
// gets the value of the "data-product_variations" attribute of the variations form
let variationData = $('form.variations_form').data("product_variations");
$(variationData).each(function(index,object) {
let attrVariation = object.attributes;
let attrVariationLenght = Object.keys(attrVariation).length;
let found = 0;
let toSet;
let valueToSet;
// check all possible combinations of attributes (for single variation)
// based on the selected attributes
$.each( attrVariation, function( attr, value ) {
if ( attr in attrToFind && attrToFind[attr] == value ) {
found++;
} else {
// if the variation is out of stock it gets slug and value to add the text "Out of stock"
if ( object.is_in_stock == false ) {
toSet = attr;
valueToSet = value;
}
}
});
// if only one attribute is missing
if ( attrVariationLenght - found == 1 ) {
if ( toSet == attrToSet ) {
let obj = {};
obj[toSet] = valueToSet;
globalAttributesToUpdate.push(obj);
}
}
});
}
});
// inserts the text "Out of stock" after updating the variations
// based on the "globalAttributesToUpdate" global variable
$('body').on('woocommerce_update_variation_values', function(){
if ( globalAttributesToUpdate !== undefined && globalAttributesToUpdate.length ) {
$.each( globalAttributesToUpdate, function( key, attribute ) {
$.each( attribute, function( attrName, attrValue ) {
$('select[name='+attrName+'] > option[value="'+attrValue+'"]').append( " (Out of stock)" );
});
});
}
});
});
</script>
<?php
}
The code has been tested and works. Add it to your active theme's functions.php.
RESULT
RELATED ANSWERS
How to add variation stock status to Woocommerce product variation dropdown
Show stock status next to each attribute value in WooCommerce variable products
Display variation stock status on single dropdown variable products in Wocommerce 3
add_filter('woocommerce_variation_option_name', 'display_price_in_variation_option_name');
function display_price_in_variation_option_name($term)
{
global $wpdb, $product;
$result = $wpdb->get_col("SELECT slug FROM {$wpdb->prefix}terms WHERE name = '$term'");
$term_slug = (!empty($result)) ? $result[0] : $term;
$query = "SELECT postmeta.post_id AS product_id
FROM {$wpdb->prefix}postmeta AS postmeta
LEFT JOIN {$wpdb->prefix}posts AS products ON ( products.ID = postmeta.post_id )
WHERE postmeta.meta_key LIKE 'attribute_%'
AND postmeta.meta_value = '$term_slug'
AND products.post_parent = $product->id";
$variation_id = $wpdb->get_col($query);
$parent = wp_get_post_parent_id($variation_id[0]);
if ($parent > 0) {
$_product = new WC_Product_Variation($variation_id[0]);
$_currency = get_woocommerce_currency_symbol();
$stock = $_product->is_in_stock() ? 'instock' : 'out of stock';
return $term . ' (' . $_product->get_price() . ' ' . $_currency . ') - ' . $stock;
}
return $term;
}

Insert a post meta in the product with variable

I state that I am not an expert! My function modifies the visibility of the product based on the presence of the price. It works well with simple products, but not with products that have variables. To be more precise, the visibility of the variable is changed in the variable product, but not the parent product.
My question is: how do I, in case of variables, set the visibility filter on the parent product? This is my current code:
if ($listinoWeb == "")
{
delete_post_meta($product_id, 'wwpp_product_wholesale_visibility_filter', 'all');
add_post_meta($product_id, 'wwpp_product_wholesale_visibility_filter', 'wholesale_customer', TRUE);
}
else
{
add_post_meta($product_id, 'wwpp_product_wholesale_visibility_filter', 'all', TRUE);
delete_post_meta($product_id, 'wwpp_product_wholesale_visibility_filter', 'wholesale_customer');
}
You can call the get_parent_id() function on the product object. Which will return 0 if you call it on a simple/parent product. So you can do something like this:
$product_id = $product->get_parent_id() ? $product->get_parent_id() : $product->get_id();
This way you're sure the $product_id variable always contains the parent id.

WordPress Shortcode with fallback

I'm building a simple plugin that uses the geoservices web service and what I'm trying to do is dynamically change the content on a WordPress page based on their location. I have it working somewhat but my issue is that it's returning both the location-specific text AND the default. I know it's because i'm using the shortcode instance more than once but I don't know how to change it to ONLY show the location specific content and if the location is not set or does not match the shortcode params then fall back to the default one. I don't want to add "default" as a shortcode param because it could contain HTML or something else.
Here is an example of my shortcode:
[geo city="Orlando"]555-123-6349[/geo][geo city="Raleigh"]919-999-9999[/geo][geo city="Default"]Default text here[/geo]
So based on the above, the desired result would show Orlando's phone number if the user is from Orlando or it would show Raleigh number if they are from Raleigh. Otherwise, if they are not from either of those places, it would use the default.
Here is my shortcode:
function geo_services( $atts , $content = null ) {
// Attributes
extract(shortcode_atts(array(
'city' => '',
'state' => '',
), $atts));
require_once('geoplugin.class.php');
$geoplugin = new geoPlugin();
$geoplugin->locate();
if($city === $geoplugin->city){
return $content;
} elseif ($state === $geoplugin->region){
return $content;
} elseif ($city === 'Default') {
return $content;
}
}
add_shortcode( 'geo', 'geo_services' );
And here is what is happening when I use the example shortcode above:
I believe you may be misunderstanding how shortcodes work in WP. In your example, you have added 3 shortcodes to the content. Each of those shortcodes is going to run. Not one or the other. So doing,
[geo city="Orlando"]555-123-6349[/geo][geo city="Raleigh"]919-999-9999[/geo][geo city="Default"]Default text here[/geo]
means that each of those will be called and evaluated. $geoplugin->city is always going to return the city of the user, regardless of what attributes you supplied. And since you are returning $content in all cases, it will always spit out the content that you added inside the shortcode. This is why you are seeing all 3 responses.
Instead, I would try the approach below. If your goal is to spit out content based on the city of the user, you really don't need to supply an attribute to the shortcode. See the following example:
//in your post/page content, simply use the shortcode geo
[geo]
//your function should be
function geo_services( $atts , $content = null ) {
//
require_once('geoplugin.class.php');
//
$geoplugin = new geoPlugin();
$geoplugin->locate();
//
switch( $geoplugin->city ) {
case 'Orlando':
return '555-123-6349';
break;
case 'Raleigh':
return '919-999-9999';
break;
default:
return 'Default text here';
break;
}
}
add_shortcode( 'geo', 'geo_services' );
Providing another answer based on OP comments. If you really need to manage the content via the WYSIWYG, then you could supply the content for each city as an attribute.
//add shortcode to post/page content
[geo orlando="555-123-6349" raleigh="919-999-9999" default="Custom default text here"]
//your function should be
function geo_services( $atts , $content = null ) {
//don't use extract since we expect X number of atts now
$atts = shortcode_atts(array(
'default' => 'Default text here'
), $atts);
//
require_once('geoplugin.class.php');
//
$geoplugin = new geoPlugin();
$geoplugin->locate();
//was the city provided as an attribute?
if( isset($atts[ strtolower($geoplugin->city) ]) ) {
return $atts[ strtolower($geoplugin->city) ];
}else {
return $atts['default'];
}
}
add_shortcode( 'geo', 'geo_services' );
You may have to get creative with the HTML portion of the content, but now you can include X number of cities, with their custom content, in the shortcode itself. If the city is not supplied, or does not match, it will fallback to the default.

Get custom field value but hide first 19 and last 2 characters

Geeks and code Gods,
I am having an issue with my wordpress code. I have added 3 extra columns to the dashboard's pages screen.
One of which displays the custom field 'scode'. The scode custom field holds the cart66 shortcode which adds an 'add cart' button to the page it is assigned to.
The shortcode looks like this:
[add_to_cart item="HD-NL-7010"]
Each page has a different shortcode.
Every shortcode is the same length, 31 characters long.
However Id prefer not to show the whole shortcode in the column, only the product code *HD-NL-7010* section of the code.
Is it possible to hide the first 19 and last 2 characters. Basically removing [add_to_cart item=" and "]
Below is the code I added to function.php to add the custom columns to the pages table:
function test_modify_post_table( $column ) {
$column['scode'] = 'Product Code';
$column['Price'] = 'Price';
$column['Product_Image'] = 'Image';
return $column;
}
add_filter( 'manage_pages_columns', 'test_modify_post_table' );
function test_modify_post_table_row( $column_name, $post_id ) {
$custom_fields = get_post_custom( $post_id );
switch ($column_name) {
case 'scode' :
echo $custom_fields['scode'][0];
break;
case 'Price' :
echo '£' . $custom_fields['Price'][0];
break;
case 'Product_Image' :
echo $custom_fields['Product_Image'][0];
break;
default:
}
}
add_filter( 'manage_pages_custom_column', 'test_modify_post_table_row', 10, 2 );
Thank you for reading this post. Any help would be greatly appreciated.
P.S. I'm going to ask this in another post but does anyone know how to get the Product_Image to show as an image in the page column rather than the image attachment ID?
I might be misunderstanding, does PHP's substr help? Something like:
case 'scode' :
echo substr( $custom_fields['scode'][0], 19, 10 );
break;
For what it's worth, I think I'd store just the code (HD-NL-7010) in the custom field, rather than the shortcode code, then apply the shortcode where needed (with do_shortcode).

Resources