Using a woocommerce hook to retrieve the sales information after the payment has been received. I can find the product name, the fact that it is a subscription, but I need to retrieve the subscription variation that was selected by the customer. I can get a list OF the variations, but not the exact one selected.
Everything works EXCEPT the ability to discover what variation the customer choose,
I even tried getting the meta data, only to not be able to gain access to it.
$meta_data = $product->get_formatted_meta_data('_', true);
foreach( $items as $item_id => $product )
{
$ProductName = $product->get_name(); // readable name of
product
$ProductId = $product->get_product_id(); // woocommerce id of
product
$PaymentAmount = $product->get_total(); // Get Payment of subscription item,
$ProductIndex = wc_get_product($ProductId);
if(! WC_Subscriptions_Product::is_subscription( $ProductIndex ) )
continue;
if(!$product->is_type( 'simple' ))
{
// THIS CRASHES WITH INTERNAL SERVICE ERROR
$variation_attributes = $product->get_variation_attributes();
foreach($variation_attributes as $attribute_taxonomy => $term_slug)
{
$taxonomy = str_replace('attribute_', '', $attribute_taxonomy );
$attribute_name = get_taxonomy( $taxonomy )->labels->singular_name;
$BusinessSpeciality = get_term_by( 'slug', $term_slug, $taxonomy )->name;
}
}
Found the solution..simple:
foreach( $items as $item_id => $product )
{
if(!$product->is_type( 'simple' ) && $product->is_virtual())
{
$variation_id = $product['variation_id'];
$variation = new WC_Product_Variation($variation_id);
$BusinessSpeciality = current($variation->get_variation_attributes());
}
else
$BusinessSpeciality = 'Default';
}`
Related
Time to time we change SKU in a product. But we want to keep old SKU in order tables. Woocommerce change old orders' SKU's one you update the product.
So we had below code and was working great. But after new updates it doesn't work anymore. What can we do?
add_action('woocommerce_thankyou', 'add_current_sku', 4);
function add_current_sku($order_id)
{
$order = wc_get_order($order_id);
$product = $order->get_items();
$skus = array();
global $wpdb;
foreach ($order->get_items() as $item_id => $item) {
$product = $item->get_product();
$product_id = $item->get_product_id();
if ($product->is_type('composite')) {
$skus[] = array(
"sku" => $product->sku,
"product_id" => $product_id,
);
}
}
update_post_meta($order_id, "erp_productcode", $skus);
}
I'm using this code to generate an iframe if a customer has bought product 13372 and it works great:
<?php
// Get the current user data:
$user = wp_get_current_user();
$user_id = $user->ID; // Get the user ID
$customer_email = $user->user_email; // Get the user email
// OR
// $customer_email = get_user_meta( $user->ID, 'billing_email', true ); // Get the user billing email
// The conditional function (example)
// IMPORTANT: $product_id argument need to be defined
$product_id = 13372;
if( wc_customer_bought_product( $customer_email, $user_id, $product_id ) ) {
echo "You have additional listings!";
//iFrame goes here
} else {
echo "You have no additional listings.";
}
?>
Now I need to modify this to check how many times a user bought product ID 13372 and output that many number of iframes. If bought 3 times, output 3 iframes. I'm assuming a foreach loop, but what I've tried doesn't work. I followed this post: How to check how many times a product has been bought by a customer
But the example it doesn't return anything for me, not sure why!
Please try the following. We're looping through each completed shop order of a specific customer and putting all IDs of purchased products into an array. We then loop through that array to see how many times a specific ID appears. We store that value in a $count variable, which is used to determine how many times to output an iframe.
I've commented the code and made function and variable names as clear as possible.
<?php
function so58032512_get_product_purchase_quantity( $product_id ) {
// Array to hold ids of all products purchased by customer
$product_ids = [];
// Get all customer orders
$customer_orders = get_posts( array(
'numberposts' => - 1,
'meta_key' => '_customer_user',
'meta_value' => get_current_user_id(),
'post_type' => 'shop_order', // WC orders post type
'post_status' => 'wc-completed' // Only orders with status "completed"
) );
// Loop through each of this customer's order
foreach ( $customer_orders as $customer_order ) {
$order = wc_get_order( $customer_order );
$items = $order->get_items();
// Loop through each product in order and add its ID to $product_ids array
foreach ( $items as $item ) {
$id = $item['product_id'];
array_push( $product_ids, $id );
}
}
// Variable to count times an ID exists in the $product_ids array
$count = 0;
// Loop through all of the IDs in our $product_ids array
foreach ( $product_ids as $key => $value ) {
// Every time the ID that we're checking against appears in the array
if ( $value == $product_id ) {
// Increment our counter
$count ++;
}
}
// Return the counter value that represents the number of times the
// customer bought a product with our passed in ID ($product_id)
return $count;
}
// Get the current user data:
$user = wp_get_current_user();
$user_id = $user->ID; // Get the user ID
$customer_email = $user->user_email; // Get the user email
// IMPORTANT: $product_id argument need to be defined
$product_id = 13372;
if ( wc_customer_bought_product( $customer_email, $user_id, $product_id ) ) {
$x = 1;
$number_of_iframes_to_show = so58032512_get_product_purchase_quantity( $product_id );
echo 'The customer bought product with ID ' . $product_id . ' ' . $number_of_iframes_to_show . ' time(s).<br>';
while ( $x <= $number_of_iframes_to_show ) {
echo "<br>Here's an iframe!<br>";
$x ++;
}
} else {
echo "You have no additional listings.";
}
?>
I have the function below which works to change the role of a user when they buy certain products, but instead of listing out specific product IDs, I'd like to just use the category name or id of those products. That way, if we add a new product in that category, I don't have to remember to add it to this function. This function is specific to a certain category, so it doesn't matter if people have other products from other categories in the order.
function lgbk_add_member( $order_id ) {
$order = new WC_Order( $order_id );
$items = $order->get_items();
foreach ( $items as $item ) {
$product_name = $item['name'];
$product_id = $item['product_id'];
$product_variation_id = $item['variation_id'];
if ( $order->user_id > 0 && $product_id == '7' ) {
update_user_meta( $order->user_id, 'paying_customer', 1 );
$user = new WP_User( $order->user_id );
// Remove role
$user->remove_role( 'expired' );
// Add role
$user->add_role( 'customer' );
}
}
}
add_action( 'woocommerce_order_status_completed', 'lgbk_add_member' );
You have to use wp_get_post_terms to get category id of any product like this :
$term_list = wp_get_post_terms($product_id, 'product_cat', array('fields' => 'ids'));
I am just fetching id's of categories assigned to this particular product, you can fetch name also.
You can get product category name using this function -
function get_product_category_name_by_id( $category_id ) {
$term = get_term_by( 'id', $category_id, 'product_cat', 'ARRAY_A' );
return $term['name'];
}
$product_category = get_product_category_name_by_id( $your_category_id );
Thanks!
I have seen several posts relating to adding a service fee to a WooCommerce item based on Category. Tickets in my case. I have had success with several of the codes presented. However In all cases Sales Tax was not applied to the new sub total. I'm stuck trying to make that happen. So with the code below I am not taxing the up charge resulting in under collection of taxes.
Here is the code I'm currently using:
/* Service fee for tickets */
function df_add_ticket_surcharge( $cart_object ) {
global $woocommerce;
$specialfeecat = 23; // category id for the special fee
$spfee = 0.00; // initialize special fee
$spfeeperprod = 0.214; //special fee per product
foreach ( $cart_object->cart_contents as $key => $value ) {
$proid = $value['product_id']; //get the product id from cart
$quantiy = $value['quantity']; //get quantity from cart
$itmprice = $value['data']->price; //get product price
$terms = get_the_terms( $proid, 'product_cat' ); //get taxonamy of the prducts
if ( $terms && ! is_wp_error( $terms ) ) :
foreach ( $terms as $term ) {
$catid = $term->term_id;
if($specialfeecat == $catid ) {
$spfee = $spfee + $itmprice * $quantiy * $spfeeperprod;
}
}
endif;
}
if($spfee > 0 ) {
$woocommerce->cart->add_fee( 'Service Fee', $spfee, true, $taxable = true, $tax_class = 'standard' );
}
Is there a way to add a default shipping class to all products? I have one shipping class and need an automated way to add that class to all products when they are created vs. having to constantly add the shipping class.
Many solutions
There is two solutions :
First add the term dynamically before the cart totals (add to your functions.php)
add_action('woocommerce_before_calculate_totals' , 'add_shipping_terms_before_totals' , 10, 1);
function add_shipping_terms_before_totals(WC_Cart $wc_cart){
if( count($wc_cart->get_cart()) == 0 ){
return;
}
// Here you need to edit the slug_to_edit with your custom slug
$shipping_terms = get_term_by( 'slug', 'slug_to_edit', 'product_shipping_class' );
// If can't find the terms, return
if( empty($shipping_terms) ){
return;
}
foreach( $wc_cart->get_cart() as $item){
$product = new WC_Product( $item['product_id'] );
$product_shipping_class = $product->get_shipping_class();
if( !empty($product_shipping_class) ){
continue;
}
wp_set_post_terms( $product->id, array( $shipping_terms->term_id ), 'product_shipping_class' );
}
}
Or, you can add a function that you can manually trigger when you add a products :
if( isset($_GET['update_products']) && is_super_admin() ){
add_action( 'init', 'add_shipping_terms_on_all_products' );
}
function add_shipping_terms_on_all_products(){
global $wpdb;
// Here you need to edit the slug_to_edit with your custom slug
$shipping_terms = get_term_by( 'slug', 'slug_to_edit', 'product_shipping_class' );
// If can't find the terms, return
if( empty($shipping_terms) ){
return;
}
// Request all product
$products = $wpdb->get_results( "
SELECT p.ID as ID
FROM wp_posts AS p
WHERE p.post_status = 'publish'
AND p.post_type = 'product'
" );
foreach($products as $_product){
$product = new WC_Product($_product->ID);
$product_shipping_class = $product->get_shipping_class();
if( !empty($product_shipping_class) ){
continue;
}
wp_set_post_terms( $product->id, array( $shipping_terms->term_id ), 'product_shipping_class' );
}
}
Then you just have to trigger :
http://yoururl?update_products
as admin.
Don't forget to edit slug_to_edit with your shipping class slug