Woocommerce subscriptions: Updating order meta data from subscription meta - php

I've written the following code to take Stripe payment details from a Woocommerce subscription and update the related order with those details.
It's grabbing the details fine but the update_post_meta code doesn't seem to fire and just leaves those fields blank in the post meta, what am I missing? The rest of the code works as intended.
$order_id = wc_get_order( '143025' );
$subscriptions = wcs_get_subscriptions_for_order($order_id, array( 'order_type' => 'any' ));
foreach( $subscriptions as $subscription_id => $subscription_obj ){
$current_subs_id = $subscription_obj->get_id(); // This is current subscription id
$stripe_cus = get_post_meta( $current_subs_id, '_stripe_customer_id' );
$stripe_cus = $stripe_cus[0];
$stripe_src = get_post_meta( $current_subs_id, '_stripe_source_id' );
$stripe_src = $stripe_src[0];
update_post_meta( $order_id, '_stripe_customer_id', $stripe_cus );
update_post_meta( $order_id, '_stripe_source_id', $stripe_src );
}
The two strings look like cus_Hjgys757 and src_1nHyyin75 for $stripe_cus and $stripe_src.

It seems that you make a confuncion between order object and order ID in your code. Also you could try using CRUD methods instead like:
$order_id = 143025;
$order = wc_get_order( $order_id ); // Order Object
$subscriptions = wcs_get_subscriptions_for_order( $order_id, array( 'order_type' => 'any' ) ); // Array of subscriptions Objects
foreach( $subscriptions as $subscription_id => $subscription ){
$stripe_cust_id = $subscription->get_meta( '_stripe_customer_id');
$stripe_src_id = $subscription->get_meta( '_stripe_source_id' );
$order->update_meta_data( '_stripe_customer_id', $stripe_cust_id );
$order->update_meta_data( '_stripe_source_id', $stripe_src_id );
$order->save();
}
Or the old way using WordPress get_post_meta() and update_post_meta() functions:
$order_id = 143025;
$order = wc_get_order( $order_id ); // Order Object
$subscriptions = wcs_get_subscriptions_for_order( $order_id, array( 'order_type' => 'any' ) ); // Array of subscriptions Objects
foreach( $subscriptions as $subscription_id => $subscription ){
$stripe_cust_id = get_post_meta( $subscription_id, '_stripe_customer_id', true );
$stripe_src_id = get_post_meta( $subscription_id, '_stripe_source_id', true );
update_post_meta( $order_id, '_stripe_customer_id', $stripe_cust_id );
update_post_meta( $order_id, '_stripe_source_id', $stripe_src_id );
}
Both should work.

Related

Update Post Meta for WooCommerce Stock Quantity Using Get Post Meta

I need to modify the stock levels for inventory per product using a custom field.
These are the code snippets i have tried and modified.
The goal is to manually modify the inventory levels even when they're in stock so orders cannot be placed when stock is low and the add to cart button is removed.
add_action( 'woocommerce_process_product_meta', 'custom_product_inventory_settings' );
function custom_product_inventory_settings( $post_id ) {
// if ( isset( $_POST['_custom'] ) ) :
$product = wc_get_product( $post_id );
$stock_threshold = get_post_meta( $product->get_id(), '_custom', true );
if ( ! empty( $stock_threshold ) ) {
$new_stock_quantity = $product->get_stock_quantity() - $stock_threshold;
update_post_meta( $post_id, '_stock', $new_stock_quantity );
wc_delete_product_transients( $post_id );
}
// endif;
}
// Save custom field
add_action( 'woocommerce_admin_process_product_object', 'action_woocommerce_admin_process_product_object', 10, 1 );
function action_woocommerce_admin_process_product_object( $product ) {
// if ( isset( $_POST['_out_of_stock_threshold'] ) ) {
$product->update_meta_data( 'custom_field', sanitize_text_field( $_POST['custom_field'] ) );
$stock_threshold = get_post_meta( $product->get_id(), 'custom_field', true );
if ( ! empty( $stock_threshold ) ) {
$new_stock_quantity = $product->get_stock_quantity() - $stock_threshold;
// update_post_meta( $post_id, '_stock', $new_stock_quantity );
$product->update_meta_data( 'custom_field', sanitize_text_field( $_POST['custom_field'] ) );
update_post_meta( $post_id, '_stock', $new_stock_quantity );
$post_id = $product->get_id();
wc_delete_product_transients( $post_id );
}
}
Maybe i need to use a different hook like woocommerce_get_availability or something else?
Not sure what your problem is, or what is happening when you run the code, but at first glance you are using a variable before declaring it:
update_post_meta( $post_id, '_stock', $new_stock_quantity );
$post_id = $product->get_id();
Also, is the custom field you are using really supposed to be called custom_field?

Auto-assign custom order status to WooCommerce on non-native order import

I'm using a plugin on my WooCommerce site called Codisto. The purpose of the plugin is to consolidate orders from sales channels such as Amazon and eBay into my WooCommerce dashboard for better visibility and order management.
Upon order import into my WooCommerce dashboard I would like my Amazon orders to automatically be assigned a status of "Amazon". I have created the custom status however have been unable to properly code a solution that can correctly recognize the order and auto assign the custom status.
Here is my code:
if ( 'processing' && ( 'on-hold' === $order->status || 'pending' === $order->status || 'failed' === $order->status ) ) {
$has_amazon_order = false;
foreach ( $order->get_order_id() as $order_id ) {
$order = $order_id->get_order_id();
$amazon_order = get_post_meta( $order_id, '_codisto_amazonorderid', true );
if ( $amazon_order == 'yes' ) {
$has_amazon_order = true;
break;
}
}
if ( $has_amazon_order == 'yes' ) {
$status = 'amazon';
}
}
return $status;
}
add_action( 'woocommerce_payment_complete_order_status', 'rb_wc_set_amazon_order_status_on_import', 20, 3 );
I've been looking at the developer's code and I believe the function is related to the $amazonorderid and $createdby param as referenced here:
if ( ! $order_id ) {
$new_order_data_callback = array( $this, 'order_set_date' );
add_filter( 'woocommerce_new_order_data', $new_order_data_callback, 1, 1 );
$createdby = 'eBay';
if ( $amazonorderid ) {
$createdby = 'Amazon';
}
$order = wc_create_order( array( 'customer_id' => $customer_id, 'customer_note' => $customer_note, 'created_via' => $createdby ) );
remove_filter( 'woocommerce_new_order_data', $new_order_data_callback );
$order_id = $order->get_id();
update_post_meta( $order_id, '_codisto_orderid', (int)$ordercontent->orderid );
update_post_meta( $order_id, '_codisto_merchantid', (int)$ordercontent->merchantid );
if ( $amazonorderid ) {
update_post_meta( $order_id, '_codisto_amazonorderid', $amazonorderid );
Any and all suggestions are greatly appreciated!

Update Custom product meta when order completed

I am trying to update a product meta for all products of each order that gets completed. Can you have a look at my approach below? Any help on why it is not working will be appreciated. I am new to all this php customizing.
add_action( 'woocommerce_order_status_completed', 'update_product_meta', 20, 2 );
function update_product_meta ( $order_id, $order ) {
// GET USER ORDERS (COMPLETED + PROCESSING)
$args = array(
'post_status' => array('wc-completed')
);
$done_orders = wc_get_orders( $args );
// LOOP THROUGH ORDERS AND GET PRODUCT IDS
if ( $done_orders ) {
$product_ids = array();
foreach ( $done_orders as $done_order ) {
$order = wc_get_order( $done_order->ID );
$items = $order->get_items();
foreach ( $items as $item ) {
$product_id = $item->get_product_id();
}
}
add_action( 'woocommerce_process_product_meta', 'action_save_product_meta' );
function action_save_product_meta( $product_id ) {
update_post_meta($product_id, 'Stav', 'Vypůjčeno' );
}
}
}
Well you're pretty close, you just have to remove the nonsense at the end.
Something along the lines of:
<?php
add_action( 'woocommerce_order_status_completed', function ( $order_id, $order ) {
$args = array(
'post_status' => array('wc-completed')
);
$done_orders = wc_get_orders( $args );
if ( ! empty( $done_orders ) ) {
foreach ( $done_orders as $done_order ) {
$order = wc_get_order( $done_order->ID );
$items = $order->get_items();
foreach ( $items as $item ) {
$product_id = $item->get_product_id();
update_post_meta( $product_id, 'Stav', 'Vypůjčeno' );
};
};
};
}, 20, 2 );
You should think of limiting it to a specific amount because right now your query will request ALL items ever completed. be careful.

WooCommerce Subscriptions hook: Get Order Items

WooCommerce 3.0 broke my app and I cannot figure out how to fix it now.
I have an action for when a subscription is added/changed running here:
Inside the function I was getting the order details and finding the line item for a variable subscription to update my custom DB with the option as well as getting custom order meta that I added via woocommerce_form_field:
This no longer works and everything appears protected? How can I update this to work with 3.0?
add_action( 'woocommerce_subscription_status_changed', 'update_subscription', 10, 3 );
function update_subscription( $id, $old_status, $new_status ) {
$sitelink_db = new SSLA_DB_Sitelink();
$order = new WC_Order( $id );
$items = $order->get_items();
$subscription_type = '';
$user_id = $order->get_user_id();
$sitelink_domain = get_post_meta( $order->id, 'ssla_sitelink_url', true );
foreach ($items as $item) {
if( "SiteLink Subscription" === $item['name'] ) {
$subscription_type = $item['brand'];
}
}
$customer_data = array(
'user_id' => $user_id,
'subscription_type' => $subscription_type,
'domain_referrer' => $sitelink_domain,
'active_subscription' => $new_status,
'date_modified' => date( 'Y-m-d H:i:s' ),
);
$sitelink_db->add( $customer_data );
}
Basically I need to get that variation name of the subscription to store in my DB, as well as that custom meta field I made. Which does not work anymore either
Here's my best guess. It's impossible to test since I don't have the same setup as you.
Few notes:
The $subscription object is passed to the woocommerce_subscription_status_changed hook so let's use it.
$order->id should be replaced by $order->get_id() in WC3.0, but we're going to use the the $subscription object (the subscription order class extends the order class so it's similar).
getters must be used on the WC_Order_Item_Product object that is returned when looping through get_items() so $item['name'] becomes $item->get_name()
Here's the full code block:
add_action( 'woocommerce_subscription_status_changed', 'update_subscription', 10, 4 );
function update_subscription( $subscription_id, $old_status, $new_status, $subscription ) {
$match_this_id = 99; // Change this to the product ID of your special subscription
$sitelink_db = new SSLA_DB_Sitelink();
$items = $subscription->get_items();
$subscription_type = '';
$user_id = $subscription->get_user_id();
$sitelink_domain = $subscription->get_meta( 'ssla_sitelink_url' );
foreach ($items as $item) {
if( $match_this_id === $item->get_product_id() ) {
$product = $item->get_product();
if( $product->is_type( 'variation' ) ){
$subscription_type = $product->get_attribute( 'brand' );
}
}
}
$customer_data = array(
'user_id' => $user_id,
'subscription_type' => $subscription_type,
'domain_referrer' => $sitelink_domain,
'active_subscription' => $new_status,
'date_modified' => date( 'Y-m-d H:i:s' ),
);
$sitelink_db->add( $customer_data );
}

Avoiding action Being Triggered Twice in woocommerce_thankyou hook

I am using the woocommerce action below to call a custom function, but for some reason it's being triggered twice on every order. Does anyone know why this could be or how to fix it so that it only calls once per order?
add_action( 'woocommerce_thankyou', 'parent_referral_for_all', 10, 1 );
function parent_referral_for_all( $order_id ) {
....
}
UPDATE
I thought the action was being triggered twice but I'm not so sure now. I'm using this action to add another referral inside the affiliatewp plugin, which is adding twice, yet my echo of "Thank You" only appears once.
Everything is working as intended except that the referral (and it's associated order note) are being added twice.
Any help would be greatly appreciated.
That full function:
function parent_referral_for_all( $order_id ) {
//Direct referral
$existing = affiliate_wp()->referrals->get_by( 'reference', $order_id );
$affiliate_id = $existing->affiliate_id;
//Total amount
if( ! empty( $existing->products ) ) {
$productsarr = maybe_unserialize( maybe_unserialize( $existing->products ) );
foreach( $productsarr as $productarr ) {
$bigamount = $productarr['price'];
}
}
//Parent amount
$parentamount = $bigamount * .1;
$affiliate_id = $existing->affiliate_id;
$user_info = get_userdata( affwp_get_affiliate_user_id( $existing->affiliate_id ) );
$parentprovider = $user_info->referral;
//Affiliate id by username
$userparent = get_user_by('login',$parentprovider);
$thisid = affwp_get_affiliate_id($userparent->ID);
$args = array(
'amount' => $parentamount,
'reference' => $order_id,
'description' => $existing->description,
'campaign' => $existing->campaign,
'affiliate_id' => $thisid,
'visit_id' => $existing->visit_id,
'products' => $existing->products,
'status' => 'unpaid',
'context' => $existing->context
);
$referral_id2 = affiliate_wp()->referrals->add( $args );
echo "Thank you!";
if($referral_id2){
//Add the order note
$order = apply_filters( 'affwp_get_woocommerce_order', new WC_Order( $order_id ) );
$order->add_order_note( sprintf( __( 'Referral #%d for %s recorded for %s', 'affiliate-wp' ), $referral_id2, $parentamount, $parentamount ) );
}
}
add_action( 'woocommerce_thankyou', 'parent_referral_for_all', 10, 1 );
To avoid this repetition, you couldadd a custom post meta data to the current order, once your "another" referral has been added the first time.
So your code will be:
function parent_referral_for_all( $order_id ) {
## HERE goes the condition to avoid the repetition
$referral_done = get_post_meta( $order_id, '_referral_done', true );
if( empty($referral_done) ) {
//Direct referral
$existing = affiliate_wp()->referrals->get_by( 'reference', $order_id );
$affiliate_id = $existing->affiliate_id;
//Total amount
if( ! empty( $existing->products ) ) {
$productsarr = maybe_unserialize( maybe_unserialize( $existing->products ) );
foreach( $productsarr as $productarr ) {
$bigamount = $productarr['price'];
}
}
//Parent amount
$parentamount = $bigamount * .1;
$affiliate_id = $existing->affiliate_id;
$user_info = get_userdata( affwp_get_affiliate_user_id( $existing->affiliate_id ) );
$parentprovider = $user_info->referral;
//Affiliate id by username
$userparent = get_user_by('login',$parentprovider);
$thisid = affwp_get_affiliate_id($userparent->ID);
$args = array(
'amount' => $parentamount,
'reference' => $order_id,
'description' => $existing->description,
'campaign' => $existing->campaign,
'affiliate_id' => $thisid,
'visit_id' => $existing->visit_id,
'products' => $existing->products,
'status' => 'unpaid',
'context' => $existing->context
);
$referral_id2 = affiliate_wp()->referrals->add( $args );
echo "Thank you!";
if($referral_id2){
//Add the order note
$order = apply_filters( 'affwp_get_woocommerce_order', new WC_Order( $order_id ) );
$order->add_order_note( sprintf( __( 'Referral #%d for %s recorded for %s', 'affiliate-wp' ), $referral_id2, $parentamount, $parentamount ) );
## HERE you Create/update your custom post meta data to avoid repetition
update_post_meta( $order_id, '_referral_done', 'yes' )
}
}
}
add_action( 'woocommerce_thankyou', 'parent_referral_for_all', 10, 1 );
I hope this will help.
You can check for the existence of the _thankyou_action_done post_meta key like so:
<?php
/**
* Allow code execution only once when the hook is fired.
*
* #param int $order_id The Woocommerce order ID.
* #return void
*/
function so41284646_trigger_thankyou_once( $order_id ) {
if ( ! get_post_meta( $order_id, '_thankyou_action_done', true ) ) {
// Your code here.
}
}
add_action( 'woocommerce_thankyou', 'so41284646_trigger_thankyou_once', 10, 1 );

Categories