I'm facing a big problem with product variations and their attributes in woocommerce. I'm trying to display a table with each attribute for each availabe product variation. But Woocommerce saves the attributes in post meta complete in lowercase, replaces slashes and german special characters like ü,ö,ä etc. I get the attributes with $variation->get_variation_attributes().
I've searched the database for the save values you can see for example in the dropdown in the admin panel, but they are saved like this without a link to the variation they are assigned to:
a:5:{s:10:"bestell-nr";a:6:{s:4:"name";s:11:"Bestell-Nr.";s:5:"value";s:9:"1 | 2 | and so on...
How can I get the attributes in their correct format to display?
Actually product attributes are actually terms in custom taxonomies, so you just need to get the terms in that particular taxonomy. All attribute taxonomies are prefaced with 'pa_'. So a size attribute would be a 'pa_size' taxonomy. And the variation ID is the post ID for a variation.
But depending on how you want to display it, WooCommerce has a built-in function for displaying all a variation's attributes:
The following will display a definition list of all of a variations attributes.
echo wc_get_formatted_variation( $product->get_variation_attributes() );
And passing a second parameter of true will display a flat list:
echo wc_get_formatted_variation( $product->get_variation_attributes(), true );
This seems to work for me. Hope this helps.
$post = get_post();
$id = $post->ID;
$product_variations = new WC_Product_Variable( $id );
$product_variations = $product_variations->get_available_variations();
print_r($product_variations);
This can be found in the class-wc-product-variable.php
So basically if you look around on that page you can find a bunch of useful functions.
Here is something i put together.
$product_children = $product_variations->get_children();
$child_variations = array();
foreach ($product_children as $child){
$child_variations[] = $product_variations->get_available_variation($child);
}
print_r($child_variations);
I only wanted to publish one of the variation attributes rather than all of them; contributing this code in case it's helpful to anyone else.
get_variation_attributes() gets all the attributes
wc_get_formatted_variation() returns a formatted version of the array it's handed
$attributes = $productVariation->get_variation_attributes() ;
if ( $attributes [ 'attribute_pa_colour' ] ) {
$colour = [ 'attribute_pa_colour' => $attributes [ 'attribute_pa_colour'] ];
echo wc_get_formatted_variation ( $colour );
}
The way I do it is by using "get_post_meta":
echo get_post_meta( $variation_id, 'attribute_name_field', true);
Hopes this helps someone.
I used wp_get_post_terms to get correct variance attributes.
global $product;
$variations = $product->get_available_variations();
$var = [];
foreach ($variations as $variation) {
$var[] = $variation['attributes'];
}
var_dump($var);
//xxx to get attribute values with correct lower-upper-mixed-case
foreach ($var as $key => $arr) {
foreach ($arr as $orig_code => $lowercase_value) {
$terms_arr = wp_get_post_terms( $product->id, str_replace('attribute_','',$orig_code), array( 'fields' => 'names' ) );
foreach ($terms_arr as $term) {
if (strtolower($term) == $lowercase_value) {
$var[$key][$orig_code] = $term;
break;
}
}
}
}
var_dump($var);
The results:
Before hard code
array (size=1)
0 =>
array (size=2)
'attribute_pa_width' => string 'none' (length=4)
'attribute_pa_code' => string 'valancese' (length=9)
After hard code:
array (size=1)
0 =>
array (size=2)
'attribute_pa_width' => string 'None' (length=4)
'attribute_pa_code' => string 'ValanceSe' (length=9)
Just went through this ...here is my solution. It handles multiple attributes and all the variations. You just have to know the attribute slug.
$items = $order->get_items();
foreach( $items as $item_id => $product )
{
$ProductName = $product->get_name(); /
if($product->is_type( 'simple' ))
$CoreProductName = $ProductName; // No variance
else
{
list($CoreProductName, $ThrowAway) = explode(" - ",$ProductName, 2);
$variation_id = $product['variation_id'];
$variation = new WC_Product_Variation($variation_id);
$attributes = $variation->get_variation_attributes();
$SelectedAttribute1 = $attributes['attribute_YOUR_SLUG1_PER_PRODUCT'];
$SelectedAttribute2 = $attributes['attribute_YOUR_SLUG2_PER_PRODUCT'];
}
}
Related
I'm trying to display some order item meta data as checkboxes instead of plain text via the woocommerce_order_item_display_meta_value hook (hope my terminology is right. I'm new to this woocommerce game).
add_filter( 'woocommerce_order_item_display_meta_value', 'modify_order_item_display_value' , 10, 3 );
function modify_order_item_display_value( $display_value, $meta, $wc_order_item ) {
$meta_data = $meta->get_data();
if( $meta_data['key'] === '_Packed' ) {
$display_value = __('<input type="checkbox" name="mycheckbox" id="mycheckbox" value="1" />', 'woocommerce' );
}
return $display_value;
}
If I do something like $display_value = '<p>TEST</p>'; it comes out fine. When I try to use an input it doesn't show up. Looking at DOM in the browser I can get down to the <td> that should contain my input and the HTML just isn't there.
Does woocommerce_order_item_display_meta_value filter out input fields?
Is there another way to get a checkbox for order item meta data ?
I don't know if this is the right way to do it but it works. I'd love any feedback about the "woocommercyness" of it...
STEP1
Use woocommerce_hidden_order_itemmeta to hide my field so it doesn't get shown "the normal way"
add_filter( 'woocommerce_hidden_order_itemmeta', 'myplugin_hide_order_item_meta_fields' );
function myplugin_hide_order_item_meta_fields( $fields )
{
$fields[] = '_Packed';
return $fields;
}
STEP 2
Use woocommerce_after_order_itemmeta to display my field in a custom way after all of the other Meta data.
Note that I give the checkbox an ID based on the order item id. In other code I need to see if these IDs are passed in requests or not
add_action( 'woocommerce_after_order_itemmeta', 'myplugin_order_meta_customized_display',10, 3 );
function myplugin_order_meta_customized_display( $item_id, $item, $product )
{
$packed = $item->get_meta('_Packed') === 'Y';
echo "<div>";
woocommerce_form_field("packed_$item_id",
array(
'type' => 'checkbox',
'label' => __('Packed', 'woocommerce'),
'required' => false,
'class' => array('input-checkbox')
), $packed);
echo "</div>";
}
STEP 3
Use the REQUEST to set the meta datafunction myplugin_set_meta_from_post($order_id, $order)
I call a wrapper from the actions woocommerce_checkout_order_processed and save_post_shop_order. The actuions get the order id - I lookup the order (because I'm doing other stuff, not just the crazy meta display)
function myplugin_set_meta_from_post($order_id, $order)
{
// For each meta data in each order item
// If it is '_Packed' then see if a corresponding packed_<id> parameter
// is in the request and update the item's meta data accordingly.
//
foreach ($order->get_items() as $item_key => $item ) {
$item_meta = $item->get_meta_data();
foreach($item_meta as $meta)
{
if ($meta->__get('key') === '_Packed')
{
$k = 'packed_'.$item->get_id();
$packed = 'Y';
if ( ! isset( $_REQUEST[ $k ] ) || empty( $_REQUEST[ $k ] ) ) {
$packed = 'N';
}
if ($packed != $item->get_meta('_Packed'))
{
$item->update_meta_data('_Packed', $packed);
}
}
}
}
}
I need to limit the response's fields of woo commerce Rest API. For example. When I need to show the products of a specific category. I just need product id, image, and slug. So, I wanna get only specific fields. Any way to solve my problem?
You can use the filter hook woocommerce_rest_prepare_product_object to adjust the response.
$wc_rest_api->get('products', array('category' => '1234', 'fields_in_response' => array(
'id',
'images',
'slug'
) ) );
The argument fields_in_response is not there by default.
The following code must be placed on server-side (i.e. in functions.php) to work with it.
add_filter('woocommerce_rest_prepare_product_object', 'at_wc_rest_api_adjust_response_data', 10, 3);
function at_wc_rest_api_adjust_response_data( $response, $object, $request ) {
$params = $request->get_params();
if ( ! $params['fields_in_response'] ) {
return $response;
}
$data = $response->get_data();
$cropped_data = array();
foreach ( $params['fields_in_response'] as $field ) {
$cropped_data[ $field ] = $data[ $field ];
}
$response->set_data( $cropped_data );
return $response;
}
I am trying to get variations of a variable product on custom product page. I have two attributes, one for sizes as select and the other for colors as swatches. The problem that I cannot display the attribute that I need to display, and when I use the following code it returns a text names of sizes or colors not the select dropdown for sizes or the colors swatches. Any help please ?!
echo implode(', ', wc_get_product_terms( $product_id, 'pa_colors' ));
This is a brief code to solve your question, I let you entire code, you can use only that you need.
The first is check if get_product function exists, and check the product type, to create a correct product object with the id (in my case $idProduct).
It work on woocommerce 3.x, I don't test it on woocommerce < 3.x.
if( function_exists('get_product') ) {
$product = get_product( $idProduct );
if ( $product->is_type( 'variable' ) ) {
$product = new WC_Product_Variable( $idProduct );
$available_variations = $product->get_available_variations(); //get all child variations
$variation_variations = $product- >get_variation_attributes(); // get all attributes by variations
// taxonomy => terms
// pa_attribute-color => array('blue', 'red', green)
// Use ex: get_taxonomy('pa_attribute-color')->labels; to get the Name and not the slug to attributes, it can be the taxonomy
// Use ex: get_term_by('name', 'pa_attribute-color', 'pa_attribute-color); to get the Name/label
$result = array( $available_variations , $attributes); // only to see the result you can use var_dump, error_log, etc.
//...
//...
}elseif ( $product->is_type( 'bundle' ) && class_exists( 'WC_Product_Bundle' ) ) {
$product = new WC_Product_Bundle( $idProduct );
}else{
$product = new WC_Product( $idProduct );
}
}
Also you try with:
$product->get_attribute( $key );
wc_attribute_label($key);
where $key can be pa_color , pa_size, etc
I hope help you.
I've created a variable product using woocommerce plugin. In the variable product I've created a custom attribute "License Duration" with values "3 Months | 6 Months | 1 Year | Life Time".
Now I want to display this attribute on a custom single product template.
I've tried following solutions
1.
$licenseDurations = get_the_terms( $post->ID, 'attribute_license-duration' );
This shows following on var_dump($licenseDurations); `
object(WP_Error)[558]
public 'errors' =>
array (size=1)
'invalid_taxonomy' =>
array (size=1)
0 => string 'Invalid taxonomy' (length=16)
public 'error_data' =>
array (size=0)
empty`
and
2.
global $product;
$licenseDuration = $product->get_attribute( 'License Duration' ); // Here I also tried attribute slug `attribute_license-duration` instead of `License Duration` but no use
Ref: https://stackoverflow.com/a/13454788/2758870
and
3.
global $product;
$licenseDurations = get_the_terms( $product->id, 'License Duration');
foreach ( $licenseDurations as $licenseDuration )
{
echo $licenseDuration->name;
}
in both of above cases I got nothing because $product; is returning null on var_dump($product)
4. I've also tried this code http://isabelcastillo.com/woocommerce-product-attributes-functions
by directly calling isa_woo_get_one_pa() where I want to show values. but with no luck.
Anyone here please help...
You can try the following
1.get_post_meta to get the product attributes
$attr = get_post_meta( 123, '_product_attributes' ); // replace 123 with the actual product id
print_r( $attr );
2.Or you can create a product object and then using the get_attributes method
$p = new WC_Product( 123 ); // // replace 123 with the actual product id
print_r( $p->get_attributes() );
Not sure if there is changes in woocommerce, above did not give the attribute value. Following post from this page gave the correct answer
// replace pa_attribute with your attribute name, but keep the pa_ prefix
// e.g. pa_weight
$fabric_values = get_the_terms( $product->id, 'pa_attribute');
foreach ( $fabric_values as $fabric_value ) {
echo $fabric_value->name;
}
Here are all product attributes listing. Hope this helps you.
$product_attributes = get_post_meta( $post->ID, '_product_attributes' );
foreach ( $product_attributes as $group_attributes ) {
foreach ( $group_attributes as $attributes ) {
echo $attributes['name'].'=>'.$attributes['value'];
}
}
I have 2 custom content types created by Pods CMS: fights and events. In the fights content type there is a relationship field for the event. How would I select all fights from the database by a specific event id? I tried querying the pods relationships table manually but that gave me incorrect results.
$fights = pods( 'fights' );
$params = array(
'where' => 'event.id = 3'
);
$fights->find( $params );
// loop through a while( $fights->fetch() ) and use $fights->field() to get the values of each field
That should do it, but you'll want to look at the 'find' documentation for your specific content type case as event.id may not be what you want (you may want event.ID).
http://pods.io/docs/code/pods/
http://pods.io/docs/code/pods/find/
http://pods.io/docs/code/pods/field/
http://pods.io/docs/code/pods/display/
Using this function you can easily display all individual relational fields with shortcode:
function get_pod_fields($atts) {
$a = shortcode_atts( array('field' => '', 'pod'=> '', 'relation'=> '', 'type'=>'', 'as'=>'url'), $atts );
$pod = pods( $a['pod'], get_the_id() );
$related = $pod->field( $a['relation']);
$field = get_post_meta( $related['ID'], $a['field'], true );
if($a['type'] == "image") {
if($a['as'] == "image") {
$field = '<img src="'.$field = $field['guid'].'"></img>';
} else {
$field = $field['guid'];
}
} else {
$field = $field;
}
return $field;
}
add_shortcode( 'podfields', 'get_pod_fields' );
[podfields field="profile_picture" type="image" pod="therapy" as="image" relation="therapist"]