This is a self Q&A
I need a way to neatly build a key=>value array of all the variations for an item in a cart. The available Woo functions all return a string.
This function takes a cart item, and returns a key=>value array.
Place it in functions.php
/*
* Get a cart product/item's variation as a key=>value pair
*/
function store_get_cart_product_variations($cart_item) {
$variations = WC()->cart->get_item_data($cart_item, true);
// Explode and trim
$parts = explode(PHP_EOL, $variations);
$parts = array_filter($parts);
// Build a key=>value pair, trim any extra whitespace
$variations = array();
foreach($parts as $part) {
list($key, $value) = explode(':', $part);
$variations[trim($key)] = trim($value);
}
return $variations;
}
And then it can be used like this:
$cart_items = WC()->cart->get_cart();
foreach ( $cart_items as $cart_item_key => $cart_item ) {
$variations = store_get_cart_product_variations($cart_item);
foreach($variations as $type => $value) {
echo $type . ': ' . '<span class="value">' . $value .'</span>';
}
}
Related
I found the following code in an older thread (Shortcode that display all product attributes set for a WooCommerce product) which basicly SHOULD be the solution to what im looking for
function get_product_attributes_shortcode($atts ) {
// Extract shortcode attributes
extract( shortcode_atts( array(
'id' => get_the_ID(),
), $atts, 'display-attributes' ) );
global $product;
if ( ! is_a($product, 'WC_Product') ) {
$product = wc_get_product( $id );
}
if ( is_a($product, 'WC_Product') ) {
$html = []; // Initializing
foreach ( $product->get_attributes() as $attribute => $values ) {
$attribute_name = wc_attribute_label($values->get_name());
$attribute_data = $values->get_data();
$is_taxonomy = $attribute_data['is_taxonomy'];
$option_values = array(); // Initializing
// For taxonomy product attribute values
if( $is_taxonomy ) {
$terms = $values->get_terms(); // Get attribute WP_Terms
// Loop through attribute WP_Term(s)
foreach ( $terms as $term ) {
$term_link = get_term_link( $term, $attribute );
$option_values[] = ''.$term->name.'';
}
}
// For "custom" product attributes values
else {
// Loop through attribute option values
foreach ( $values->get_options() as $term_name ) {
$option_values[] = $term_name;
}
}
$html[] = '<strong>' . $attribute_name . '</strong>: ' . implode(', ', $option_values);
}
return '<div class="product-attributes">' . implode(' | ', $html) . '<div>';
}
}
add_shortcode( 'display-attributes', 'get_product_attributes_shortcode' );
I modified the output part to display the attributes in a table
// Loop through attribute WP_Term(s)
foreach ( $terms as $term ) {
$option_values[] = $term->name;
}
}
// For "custom" product attributes values
else {
// Loop through attribute option values
foreach ( $values->get_options() as $term_name ) {
$option_values[] = $term_name;
}
}
$html[] = '<tr><td class="column-1">' . $attribute_name . '</td><td class="column-2">' . implode(', ', $option_values) . '</td></tr>';
}
return '<h4>Technische Daten</h4><table class="tablepress table produktdatenblatt tablepress-responsive"><tbody class="row-hover">' . implode($html) . '</tbody></table>';
}
}
add_shortcode( 'display_attributes', 'get_product_attributes_shortcode' );
Usage should be like this: [display-attributes] or with a defined product Id [display-attributes id="254"]
But its not showing the attributes from the respective ID i put into the shortcode. Its just showing attributes from one product. I want to use the shortcode on Wordpress Pages and Posts to enrich product descriptions i do.
I tried to figure out if i can fix it myself, but im realy bad when it comes to coding :)
Can somebody help me with this?
I got this code in my function.php which shows available sizes on all the products in the category view of woocommerce.
The problem is that it takes a lot of resources and makes the site slow.
My question is, if I should save the data for each product in a transient cache to speed up the site? But it would require a lot of transients, as each product should have a transitent – Is it a good way to do it like I think or is it bad pratice to have so many transients?
My thought was to make each product have a transient key like:
$key = 'my_transient_key' . $product->get_id();
The function code as it is now:
add_action( 'woocommerce_after_shop_loop_item_title', 'display_instock_sizes', 5 );
function display_instock_sizes() {
global $product;
if ( $product->is_type('variable') ) {
$taxonomy = 'stoerrelse'; // The product attribute taxonomy
$sizes_array = []; // Initializing
// Loop through available variation Ids for the variable product
foreach( $product->get_children() as $child_id ) {
$variation = wc_get_product( $child_id ); // Get the WC_Product_Variation object
if( $variation->is_purchasable() && $variation->is_in_stock() ) {
$term_name = $variation->get_attribute( $taxonomy );
$sizes_array[$term_name] = [$term_name => 'instock'];
}else{
$term_name = $variation->get_attribute( $taxonomy );
$sizes_array[$term_name] = [$term_name => 'outofstock'];
}
}
foreach ($sizes_array as $key => $value) {
if (empty($value)) {
unset($sizes_array[$key]);
}
}
if(empty($sizes_array)){
return;
}
ksort($sizes_array);
echo '<div class="attribute-size-wrapper">';
foreach ($sizes_array as $key => $value) {
foreach ($value as $key => $value) {
echo '<span class="attribute-size"><span class="'.$value.'">' . $key . '</span></span>';
}
}
echo '</div>';
}
}
I want to add a custom column, to display the product categories on the orders history table in wooCommerce
I found how to add a custom column but I can't seem to display the taxonomy's product linked to the order in this column.
For this example, I had just 1 product, but if I can display more than one tax, it will be better.
This is what I found (from : skyverge blog) to add a new column:
/**
* Adds a new column to the "My Orders" table in the account.
*
* #param string[] $columns the columns in the orders table
* #return string[] updated columns
*/
function sv_wc_add_my_account_orders_column( $columns ) {
$new_columns = array();
foreach ( $columns as $key => $name ) {
$new_columns[ $key ] = $name;
// add ship-to after order status column
if ( 'order-number' === $key ) {
$new_columns['order-ship-to'] = __( 'Catégorie', 'textdomain' );
}
}
return $new_columns;
}
add_filter( 'woocommerce_my_account_my_orders_columns', 'sv_wc_add_my_account_orders_column' );
Any pointers are welcome
With your current code you can add a column between the existing columns, however:
The woocommerce_my_account_my_orders_columns filter is deprecated since WooCommerce 2.6.0. and replaced with woocommerce_account_orders_columns
The part to add content in the column is missing
To add content you can use the woocommerce_my_account_my_orders_column_{$column_id} hook,
where $column_id need to be replaced by order-category in this particular case
So you get:
// Adds a new column to the "My Orders" table in the account.
function filter_woocommerce_account_orders_columns( $columns ) {
$new_columns = array();
foreach ( $columns as $key => $column ) {
$new_columns[ $key ] = $column;
// Add after order number column
if ( $key === 'order-number' ) {
$new_columns['order-category'] = __( 'Catégorie', 'woocommerce' );
}
}
return $new_columns;
}
add_filter( 'woocommerce_account_orders_columns', 'filter_woocommerce_account_orders_columns', 10, 1 );
// Adds data to the custom "order-category" column in "My Account > Orders"
function filter_woocommerce_my_account_my_orders_column_order( $order ) {
// Initialize
$categories = array();
// Loop through order items
foreach ( $order->get_items() as $item_key => $item ) {
// Get product ID
$product_id = $item->get_product_id();
// Get terms
$term_names = wp_get_post_terms( $product_id, 'product_cat', array( 'fields' => 'names' ) );
// Loop through term names
foreach ( $term_names as $term_name ) {
// NOT in array
if ( ! in_array( $term_name, $categories, true ) ) {
// Push one or more elements onto the end of array
array_push( $categories, $term_name );
}
}
}
// NOT empty
if ( ! empty( $categories ) ) {
echo implode( ', ', $categories );
}
}
add_action( 'woocommerce_my_account_my_orders_column_order-category', 'filter_woocommerce_my_account_my_orders_column_order', 10, 1 );
I'm using Stripe for Woocommerce https://wordpress.org/support/plugin/woo-stripe-payment/
I need to change the order description that appears in the stripe Dashboard so it includes the SKU of the product(s) in the order.
I have been able to edit the description with the below filter:
add_filter('wc_stripe_payment_intent_args', function($args, $order){
$args['description'] = sprintf('Order %s %s', $order->get_order_number(), $order->get_billing_last_name());
return $args;
},10, 2);
I have also found this for getting the SKU
$items = $order->get_items();
// Loop through ordered items
foreach ($items as $item) {
$product_id = $item['product_id'];
$product = new WC_Product($item['product_id']);
$sku = $product->get_sku();
}
However I can't workout how to now combine these so that in Stripe I get Order ID, Billing Last Name, SKU's.
I thought I'd solved this with the below but this will work but only if I have one product. I'm assigning the SKU variable in the loop but then creating the description outside of the loop which means I will only ever see the last SKU assigned in the loop.
I need a comma separated string that consists of the SKUs and then I can assign that outside of the loop but don't know what to do.
add_filter('wc_stripe_payment_intent_args', function($args, $order){
$items = $order->get_items();
// Loop through ordered items
foreach ($items as $item) {
$product_id = $item['product_id'];
$product = new WC_Product($item['product_id']);
$sku = $product->get_sku();
}
$args['description'] = sprintf('Order %s %s %s', $order->get_order_number(), $order->get_billing_last_name(), $product->get_sku());
return $args;
},10, 2);
Have been advised elsewhere so sharing in case anyone else comes across this.
add_filter('wc_stripe_payment_intent_args', function($args, $order){
$items = $order->get_items();
$skus = [];
// Loop through ordered items
foreach ($items as $item) {
$product_id = $item['product_id'];
$product = new WC_Product($item['product_id']);
$skus[] = $product->get_sku();
}
$args['description'] = sprintf('Order %s %s %s', $order->get_order_number(), $order->get_billing_last_name(), implode(',', $skus));
return $args;
},10, 2);
I already found a snippet to sort the checkout cart alphabetically. This works perfect but as mentioned I try to sort and group my products by category.
Is there anyone who could tweak the following snippet so it sorts the products by category?
add_action( 'woocommerce_cart_loaded_from_session', 'bbloomer_sort_cart_items_alphabetically' );
function bbloomer_sort_cart_items_alphabetically() {
global $woocommerce;
// READ CART ITEMS
$products_in_cart = array();
foreach ( $woocommerce->cart->cart_contents as $key => $item ) {
$products_in_cart[ $key ] = $item['data']->get_title();
}
// SORT CART ITEMS
natsort( $products_in_cart );
// ASSIGN SORTED ITEMS TO CART
$cart_contents = array();
foreach ( $products_in_cart as $cart_key => $product_title ) {
$cart_contents[ $cart_key ] = $woocommerce->cart->cart_contents[ $cart_key ];
}
$woocommerce->cart->cart_contents = $cart_contents;
}
In order to grouped cart items by categories, add follows code snippet -
function woocommerce_before_cart_contents(){
global $woocommerce;
$cat_wisw_pros = array();
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $cart_item ) {
$product_id = $cart_item['product_id'];
$cat_ids = wp_get_post_terms( $product_id, 'product_cat', array( 'fields' => 'ids' ) );
foreach ( $cat_ids as $id ) {
$cat_wisw_pros[$id][$cart_item_key] = $cart_item;
}
}
ksort( $cat_wisw_pros ); // Cat ID wise sort
$grouped_cart_items = array();
foreach ( $cat_wisw_pros as $cat_id => $cart_items ) {
foreach ( $cart_items as $cart_item_key => $cart_item ) {
if( !array_key_exists( $cart_item_key, $grouped_cart_items ) )
$grouped_cart_items[$cart_item_key] = $cart_item;
}
}
$woocommerce->cart->cart_contents = $grouped_cart_items;
}
add_action( 'woocommerce_before_cart_contents', 'woocommerce_before_cart_contents' );
You should be able to access the category ids with the method get_category_ids() as defined in the class WC_Product
$item['data']->get_category_ids()
but this gives you back an array, so you need to handle getting the id, e.g.
$ids = $item['data']->get_category_ids();
$id = $ids[ 0 ];
and transforming to a string, e.g.
$term_obj = get_term( $id, 'product_cat' );
$name = $term_obj->name;
you could then do
$products_in_cart[ $key ] = $name;
and by the same logic used in the code in your question sort by category.
There are several things to consider though, this does not handle items being in multiple categories, it just gets the first by using index 0. Additionally, this has no extra logic of sorting, if there are multiple products in the same category.
Please note, this is untested and merely an idea of an approach of how this could be handled.