Duplicate/Copy Order Woocommerce - wordpress

Anyone know how i could duplicate/copy an order from woocommmerce and create a new order from the old one?
I am working in a Payment gateway and after a payment has been made in a recurring subscription i will need to duplicate a new order and mark as paid!!!!
Is that possible?
Cheers.

When PayPal sends an IPN subscr_payment update to WooCommerce I'm using this code inside the valid_paypal_standard_ipn_request action to create new orders from existing orders. Once in a while the shipping info is empty on the new order. I'm not sure what's causing that, but this is new code so it might be buggy.
All the components of a WooCommerce order are here. I created this from the logic in class-cw-checkout.php create_order, but used an existing order to provide the values.
<?php
add_action( 'valid-paypal-standard-ipn-request', 'sapce_valid_paypal_standard_ipn_request', 10, 1 );
function sapce_valid_paypal_standard_ipn_request($formdata){
if (!empty($formdata['txn_type'])) {
if ($formdata['txn_type'] === "subscr_signup") {
$custom = unserialize(stripslashes($formdata['custom']));
$order_id = $custom[0];
$payment_profile_id = $formdata['subscr_id'];
addPayPalPaymentProfileIdToAutoShipOrder($order_id, $payment_profile_id);
}
if ($formdata['txn_type'] === "subscr_payment" && $formdata['payment_status'] === "Completed") {
$paypal_transaction_id = $formdata['txn_id'];
$custom = unserialize(stripslashes($formdata['custom']));
$original_order_id = $custom[0];
createNewOrderAndRecordPayment($formdata);
}
if ($formdata['txn_type'] === "subscr_cancel") {
customerCanceledAutoShipOrderFromPayPal($order_id, $payment_profile_id);
}
}
}
<?php
include_once ('../../../wp-load.php');
include_once ('../../../wp-blog-header.php');
function createNewOrderAndRecordPayment($formdata) {
global $wpdb;
global $woocommerce;
$paypal_transaction_id = $formdata['txn_id'];
$custom = unserialize(stripslashes($formdata['custom']));
$original_order_id = $custom[0];
$original_order = new WC_Order($original_order_id);
$currentUser = wp_get_current_user();
writeToLog("Attempting to copy original order: $original_order_id");
//1 Create Order
$order_data = array(
'post_type' => 'shop_order',
'post_title' => sprintf( __( 'Auto-Ship Order – %s', 'woocommerce' ), strftime( _x( '%b %d, %Y # %I:%M %p', 'Order date parsed by strftime', 'woocommerce' ) ) ),
'post_status' => 'publish',
'ping_status' => 'closed',
'post_excerpt' => 'Auto-Ship Order based on original order ' . $original_order_id,
'post_author' => $currentUser->ID,
'post_password' => uniqid( 'order_' ) // Protects the post just in case
);
$order_id = wp_insert_post( $order_data, true );
if ( is_wp_error( $order_id ) ){
$msg = "Unable to create order:" . $order_id->get_error_message();;
throw new Exception( $msg );
} else {
$order = new WC_Order($order_id);
//2 Update Order Header
update_post_meta( $order_id, '_order_shipping', get_post_meta($original_order_id, '_order_shipping', true) );
update_post_meta( $order_id, '_order_discount', get_post_meta($original_order_id, '_order_discount', true) );
update_post_meta( $order_id, '_cart_discount', get_post_meta($original_order_id, '_cart_discount', true) );
update_post_meta( $order_id, '_order_tax', get_post_meta($original_order_id, '_order_tax', true) );
update_post_meta( $order_id, '_order_shipping_tax', get_post_meta($original_order_id, '_order_shipping_tax', true) );
update_post_meta( $order_id, '_order_total', get_post_meta($original_order_id, '_order_total', true) );
update_post_meta( $order_id, '_order_key', 'wc_' . apply_filters('woocommerce_generate_order_key', uniqid('order_') ) );
update_post_meta( $order_id, '_customer_user', get_post_meta($original_order_id, '_customer_user', true) );
update_post_meta( $order_id, '_order_currency', get_post_meta($original_order_id, '_order_currency', true) );
update_post_meta( $order_id, '_prices_include_tax', get_post_meta($original_order_id, '_prices_include_tax', true) );
update_post_meta( $order_id, '_customer_ip_address', get_post_meta($original_order_id, '_customer_ip_address', true) );
update_post_meta( $order_id, '_customer_user_agent', get_post_meta($original_order_id, '_customer_user_agent', true) );
writeToLog("Updated order header");
//3 Add Billing Fields
update_post_meta( $order_id, '_billing_city', get_post_meta($original_order_id, '_billing_city', true));
update_post_meta( $order_id, '_billing_state', get_post_meta($original_order_id, '_billing_state', true));
update_post_meta( $order_id, '_billing_postcode', get_post_meta($original_order_id, '_billing_postcode', true));
update_post_meta( $order_id, '_billing_email', get_post_meta($original_order_id, '_billing_email', true));
update_post_meta( $order_id, '_billing_phone', get_post_meta($original_order_id, '_billing_phone', true));
update_post_meta( $order_id, '_billing_address_1', get_post_meta($original_order_id, '_billing_address_1', true));
update_post_meta( $order_id, '_billing_address_2', get_post_meta($original_order_id, '_billing_address_2', true));
update_post_meta( $order_id, '_billing_country', get_post_meta($original_order_id, '_billing_country', true));
update_post_meta( $order_id, '_billing_first_name', get_post_meta($original_order_id, '_billing_first_name', true));
update_post_meta( $order_id, '_billing_last_name', get_post_meta($original_order_id, '_billing_last_name', true));
update_post_meta( $order_id, '_billing_company', get_post_meta($original_order_id, '_billing_company', true));
writeToLog("Updated billing fields");
//4 Add Shipping Fields
update_post_meta( $order_id, '_shipping_country', get_post_meta($original_order_id, '_shipping_country', true));
update_post_meta( $order_id, '_shipping_first_name', get_post_meta($original_order_id, '_shipping_first_name', true));
update_post_meta( $order_id, '_shipping_last_name', get_post_meta($original_order_id, '_shipping_last_name', true));
update_post_meta( $order_id, '_shipping_company', get_post_meta($original_order_id, '_shipping_company', true));
update_post_meta( $order_id, '_shipping_address_1', get_post_meta($original_order_id, '_shipping_address_1', true));
update_post_meta( $order_id, '_shipping_address_2', get_post_meta($original_order_id, '_shipping_address_2', true));
update_post_meta( $order_id, '_shipping_city', get_post_meta($original_order_id, '_shipping_city', true));
update_post_meta( $order_id, '_shipping_state', get_post_meta($original_order_id, '_shipping_state', true));
update_post_meta( $order_id, '_shipping_postcode', get_post_meta($original_order_id, '_shipping_postcode', true));
writeToLog("Updated shipping fields");
//5 Add Line Items
writeToLog("Adding line items.");
foreach($original_order->get_items() as $originalOrderItem){
$itemName = $originalOrderItem['name'];
$qty = $originalOrderItem['qty'];
$lineTotal = $originalOrderItem['line_total'];
$lineTax = $originalOrderItem['line_tax'];
$productID = $originalOrderItem['product_id'];
$item_id = wc_add_order_item( $order_id, array(
'order_item_name' => $itemName,
'order_item_type' => 'line_item'
) );
wc_add_order_item_meta( $item_id, '_qty', $qty );
//wc_add_order_item_meta( $item_id, '_tax_class', $_product->get_tax_class() );
wc_add_order_item_meta( $item_id, '_product_id', $productID );
//wc_add_order_item_meta( $item_id, '_variation_id', $values['variation_id'] );
wc_add_order_item_meta( $item_id, '_line_subtotal', wc_format_decimal( $lineTotal ) );
wc_add_order_item_meta( $item_id, '_line_total', wc_format_decimal( $lineTotal ) );
wc_add_order_item_meta( $item_id, '_line_tax', wc_format_decimal( '0' ) );
wc_add_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( '0' ) );
}
writeToLog("Copying shipping items");
//6 Copy shipping items and shipping item meta from original order
$original_order_shipping_items = $original_order->get_items('shipping');
writeToLog(print_r($original_order_shipping_items));
foreach ( $original_order_shipping_items as $original_order_shipping_item ) {
$item_id = wc_add_order_item( $order_id, array(
'order_item_name' => $original_order_shipping_item['name'],
'order_item_type' => 'shipping'
) );
if ( $item_id ) {
wc_add_order_item_meta( $item_id, 'method_id', $original_order_shipping_item['method_id'] );
wc_add_order_item_meta( $item_id, 'cost', wc_format_decimal( $original_order_shipping_item['cost'] ) );
}
}
writeToLog("Copying store coupons");
// Store coupons
$original_order_coupons = $original_order->get_items('coupon');
foreach ( $original_order_coupons as $original_order_coupon ) {
$item_id = wc_add_order_item( $order_id, array(
'order_item_name' => $original_order_coupon['name'],
'order_item_type' => 'coupon'
) );
// Add line item meta
if ( $item_id ) {
wc_add_order_item_meta( $item_id, 'discount_amount', $original_order_coupon['discount_amount'] );
}
}
writeToLog("Setting payment info");
//Payment Info
update_post_meta( $order_id, '_payment_method', get_post_meta($original_order_id, '_payment_method', true) );
update_post_meta( $order_id, '_payment_method_title', get_post_meta($original_order_id, '_payment_method_title', true) );
update_post_meta( $order->id, 'Transaction ID', get_post_meta($original_order_id, 'Transaction ID', true) );
$order->payment_complete();
writeToLog("Setting order to processing");
//6 Set Order Status to processing to trigger initial emails to end user and vendor
$updateNote = "This Auto-Ship order was created by SAP Commerce Engine, per PayPal payment installment.";
$order->update_status('processing');
$order->add_order_note($updateNote);
writeToLog("Auto-Ship Order copy complete.");
}
}

You can copy all the order meta data first using wc_get_order_item_meta(), like this:
$main_order_metadata = get_metadata( 'post', $main_order_id );
And you can add the copied metadata using add_post_meta()
After that you can copy all item meta keys with wc_get_order_item_meta(), like this:
$order_item_metas = wc_get_order_item_meta( $order_item_id, '' );
And you can add the copied item metas using wc_add_order_item_meta()

Related

Creating coupons programmatically - WooCommerce [duplicate]

I add coupons at woocommerce with this code programmatically.
if(empty($coupon_post)){
$coupon = array(
'post_title' => $coupon_code,
'post_content' => '',
'post_status' => 'publish',
'post_author' => 1,
'post_type' => 'shop_coupon'
);
$new_coupon_id = wp_insert_post( $coupon );
// Add meta
update_post_meta( $new_coupon_id, 'discount_type', $discount_type );
update_post_meta( $new_coupon_id, 'coupon_amount', $amount );
update_post_meta( $new_coupon_id, 'individual_use', 'yes' );
update_post_meta( $new_coupon_id, 'product_ids', '' );
update_post_meta( $new_coupon_id, 'exclude_product_ids', '' );
update_post_meta( $new_coupon_id, 'usage_limit', '' );
update_post_meta( $new_coupon_id, 'expiry_date', '' );
update_post_meta( $new_coupon_id, 'apply_before_tax', 'yes' );
update_post_meta( $new_coupon_id, 'free_shipping', 'no' );
update_post_meta( $new_coupon_id, 'exclude_sale_items', 'no' );
update_post_meta( $new_coupon_id, 'free_shipping', 'no' );
update_post_meta( $new_coupon_id, 'product_categories', '' );
update_post_meta( $new_coupon_id, 'exclude_product_categories', '' );
update_post_meta( $new_coupon_id, 'minimum_amount', '' );
update_post_meta( $new_coupon_id, 'customer_email', '' );
}
But it says always the usage_limit = 1.
I add additional this code to update:
add_action( 'save_post_shop_coupon', 'my_child_after_coupon_save', 10, 3 );
function my_child_after_coupon_save( $post_id, $post, $update ) {
update_post_meta( $post_id, 'usage_limit', '');
}
But it doesn't work first.But if I open the coupon in the backend and update without any changes. The usage limit is set to unlimited.
How can trigger this, that I needn't to open all coupons.
Since WooCommerce 3, your code is a bit outdated as for example apply_before_tax is not used anymore. You should better use all available WC_Coupon setter methods, for coupon creation.
In the code below I just use the necessary setter methods (related to your code):
// Get an empty instance of the WC_Coupon Object
$coupon = new WC_Coupon();
// Set the necessary coupon data (since WC 3+)
$coupon->set_code( $coupon_code ); // (string)
// $coupon->set_description( $description ); // (string)
$coupon->set_discount_type( $discount_type ); // (string)
$coupon->set_amount( $coupon_amount ); // (float)
// $coupon->set_date_expires( $date_expires ); // (string|integer|null)
// $coupon->set_date_created( $date_created ); // (string|integer|null)
// $coupon->set_date_modified( $date_created ); // (string|integer|null)
// $coupon->set_usage_count( $usage_count ); // (integer)
$coupon->set_individual_use( true ); // (boolean)
// $coupon->set_product_ids( $product_ids ); // (array)
// $coupon->set_excluded_product_ids( $excl_product_ids ); // (array)
$coupon->set_usage_limit( 0 ); // (integer)
// $coupon->set_usage_limit_per_user( $usage_limit_per_user ); // (integer)
// $coupon->set_limit_usage_to_x_items( $limit_usage_to_x_items ); // (integer|null)
// $coupon->set_free_shipping( $free_shipping ); // (boolean) | default: false
// $coupon->set_product_categories( $product_categories ); // (array)
// $coupon->set_excluded_product_categories( $excl_product_categories ); // (array)
// $coupon->set_exclude_sale_items( $excl_sale_items ); // (boolean)
// $coupon->set_minimum_amount( $minimum_amount ); // (float)
// $coupon->set_maximum_amount( $maximum_amount ); // (float)
// $coupon->set_email_restrictions( $email_restrictions ); // (array)
// $coupon->set_used_by( $used_by ); // (array)
// $coupon->set_virtual( $is_virtual ); // (array)
// Create, publish and save coupon (data)
$coupon->save();
Now to update coupons you can use the following hooked function with any setter method like:
add_action( 'woocommerce_coupon_options_save', 'action_coupon_options_save', 10, 2 );
function action_coupon_options_save( $post_id, $coupon ) {
$coupon->set_usage_limit( 0 );
$coupon->save();
}
Code goes in functions.php file of the active child theme (or active theme).

woocommerce checkout custom fields update order meta

based on this https://stackoverflow.com/a/49163797/7783506 by #LoicTheAztec I was able to create the custom fields on flat rate shipping method, I could find the data on MySQL, but it was not showing on the order detail, email.
How do I add this to order details and email? here's the code that i use based on that post
// Add custom fields to a specific selected shipping method
add_action( 'woocommerce_after_shipping_rate', 'carrier_custom_fields', 20, 2 );
function carrier_custom_fields( $method, $index ) {
if( ! is_checkout()) return; // Only on checkout page
$customer_carrier_method = 'flat_rate:4';
if( $method->id != $customer_carrier_method ) return; // Only display for "local_pickup"
$chosen_method_id = WC()->session->chosen_shipping_methods[ $index ];
// If the chosen shipping method is 'legacy_local_pickup' we display
if($chosen_method_id == $customer_carrier_method ):
echo '<div class="custom-carrier">';
woocommerce_form_field( 'ds_name' , array(
'type' => 'text',
'class' => array('form-row-wide ds-name'),
'required' => true,
'placeholder' => 'Nama Toko',
), WC()->checkout->get_value( 'ds_name' ));
woocommerce_form_field( 'ds_number' , array(
'type' => 'text',
'class' => array('form-row-wide ds-number'),
'required' => true,
'placeholder' => 'Kode Booking',
), WC()->checkout->get_value( 'ds_number' ));
echo '</div>';
endif;
}
// Check custom fields validation
add_action('woocommerce_checkout_process', 'carrier_checkout_process');
function carrier_checkout_process() {
if( isset( $_POST['ds_name'] ) && empty( $_POST['ds_name'] ) )
wc_add_notice( ( "Anda belum memasukkan Nama Toko" ), "error" );
if( isset( $_POST['ds_number'] ) && empty( $_POST['ds_number'] ) )
wc_add_notice( ( "Anda belum memasukkan nomor kode booking" ), "error" );
}
// Save custom fields to order meta data
add_action( 'woocommerce_checkout_update_order_meta', 'carrier_update_order_meta', 30, 1 );
function carrier_update_order_meta( $order_id ) {
if( isset( $_POST['ds_name'] ))
update_post_meta( $order_id, '_ds_name', sanitize_text_field( $_POST['ds_name'] ) );
if( isset( $_POST['ds_number'] ))
update_post_meta( $order_id, '_ds_number', sanitize_text_field( $_POST['ds_number'] ) );
}
found the solution, removing _ (underscore) on update_post_meta then it show on order edit.
// Save custom fields to order meta data
add_action( 'woocommerce_checkout_update_order_meta', 'carrier_update_order_meta', 30, 1 );
function carrier_update_order_meta( $order_id ) {
if( isset( $_POST['ds_name'] ))
update_post_meta( $order_id, 'ds_name', sanitize_text_field( $_POST['ds_name'] ) );
if( isset( $_POST['ds_number'] ))
update_post_meta( $order_id, 'ds_number', sanitize_text_field( $_POST['ds_number'] ) );
}

Woocommerce set for all products SKU = Title + Variation?

How do I write Title + Variation in products _SKU (for a simple product only Title)? This is necessary to update existing products in the store (more than 8000) via WP All Import and add new ones. Now updates only simple products..
I'm trying this, but still not working...
function wpse_177056_init_shortcode() {
$args = array(
'post_type' => 'product'
);
$products = new WP_Query( $args );
if ( $products->have_posts() ):
while ( $products->have_posts() ):
$products->the_post();
update_post_meta( $post->ID, '_sku', 'test' );
endwhile;
endif;
}
add_action( 'init', 'wpse_177056_init_shortcode' );
Set more time limit if you have a lot of products...
add_filter( 'init', 'sku_from_title_and_variation', 10, 1);
function sku_from_title_and_variation(){
set_time_limit(300);
$query = array(
'numberposts' => -1,
'post_status' => 'published',
);
$products = wc_get_products( $query );
foreach ($products as $product) {
if( $product->is_type('variable') ){
$product_id = $product->get_id();
$product_title = $product->get_title();
update_post_meta( $product_id, '_sku', $product_title );
wc_delete_product_transients( $product_id );
foreach( $product->get_available_variations() as $variation_values ){
$variation_id = $variation_values['variation_id']; // variation id
$variation_attr = $variation_values['attributes'];
$variation_attr = $variation_attr['attribute_pa_variant'];
$variation_attr = get_term_by('slug', $variation_attr , 'pa_variant')->name;
update_post_meta( $variation_id, '_sku', $product_title.$variation_attr );
wc_delete_product_transients( $variation_id );
}
wc_delete_product_transients( $product->get_id() );
} else {
update_post_meta( $product->get_id(), '_sku', $product->get_title());
wc_delete_product_transients( $product->get_id() );
}
}
}
You can use set_sku function to update SKU's
foreach( $products as $product){
// Set Product name as SKU
$variable = esc_html( strtolower ( $product->name ) );
$product->set_sku( $variable );
}

Set Author of a saved post as its parent post author

I try to change author of saved harmonogram item with author of parent but those to functions seems not to work - empty i think. When i set the author id with constant value everything works.
$parent_post_id = wp_get_post_parent_id($post_id);
$post_author_id = get_post_field( 'post_author', $post_id );
Here is whole function
function func_auto_update_post_author( $post_id ) {
$post_type = get_post_type($post_id);
if ( "harmonogram" != $post_type ) return;
//$parent_post_id = get_queried_object_id();
$parent_post_id = wp_get_post_parent_id($post_id);
$post_author_id = get_post_field( 'post_author', $parent_post_id );
$my_post = array(
'ID' => $post_id,
'post_author' => $post_author_id,
);
remove_action('save_post', 'func_auto_update_post_author');
wp_update_post($my_post);
add_action( 'save_post', 'func_auto_update_post_author');
}
add_action( 'save_post', 'func_auto_update_post_author');
Try below Code :
function func_auto_update_post_author( $post_id )
{
$post_type = get_post_type($post_id);
if ( "harmonogram" != $post_type ) return;
$parent_post_id = wp_get_post_parent_id($post_id);
if($parent_post_id)
{
$post_author_id = get_post_field( 'post_author', $parent_post_id );
$my_post = array(
'ID' => $post_id,
'post_author' => $post_author_id
);
wp_update_post($my_post);
}
}
add_action( 'save_post', 'func_auto_update_post_author');
you can track if any error occurred during post update by putting below code in above action hook:
$post_id = wp_update_post( $my_post, true );
if (is_wp_error($post_id)) {
$errors = $post_id->get_error_messages();
foreach ($errors as $error) {
echo $error;
}
}
Hope this will help!

Add first link from post in custom field - Wordpress

I m trying to add the first link from the post content to a custom field. Something is wrong and I ve been trying to get it to work but no luck. What should I do to add the link to "link" custom field?
add_action( 'publish_post', 'check_post' );
function check_post( $post_id ) {
$user_info = get_userdata(1);
function get_first_link() {
global $post, $posts;
preg_match_all('/href\s*=\s*[\"\']([^\"\']+)/', $post->post_content, $links);
return $links[1][0];
}
$first_link = get_first_link();
add_post_meta($post_id, 'link', $first_link, true);
add_post_meta($post_id, 'users', $user_info->user_login, true);
}
EDIT
I got it working halfway. It saves the url, but it doesn't save it when the post is published. It saves it on update. What do I need to use? I tried using publish_post but that saved the url on update also.
add_action( 'save_post', 'my_save_post', 10, 2 );
function my_save_post( $post_id, $post ) {
if ( wp_is_post_revision( $post_id ) )
return;
$matches = array();
preg_match_all( '/href\s*=\s*[\"\']([^\"\']+)/', $post->post_content, $matches );
$first_link = false;
if ( ! empty( $matches[1][0] ) )
$first_link = $matches[1][0];
$user_info = get_userdata(1);
$meta_link = $_POST['link'];
$args = array(
'post__not_in'=> array($id),
'post_type' => 'post',
'post_status' => array('publish'),
'meta_query' => array(
array(
'key' => 'link',
'value' => $first_link,
'compare' => '='
)
)
);
$existingMeta = get_posts( $args );
if(empty($existingMeta)){
//Go ahead and save meta data
update_post_meta( $post_id, 'link', esc_url_raw( $first_link ) );
update_post_meta($post_id, 'users', $user_info->user_login);
}else{
//Revert post back to draft status
update_post_meta( $post_id, 'link', $existingMeta[0]->ID );
update_post_meta($existingMeta[0]->ID, 'users', $user_info->user_login);
//Now perform checks to validate your data.
//Note custom fields (different from data in custom metaboxes!)
//will already have been saved.
$prevent_publish= true;//Set to true if data was invalid.
if ($prevent_publish) {
// unhook this function to prevent indefinite loop
remove_action('save_post', 'my_save_post');
// update the post to change post status
wp_update_post(array('ID' => $post_id, 'post_status' => 'draft'));
}
}
}
Here you go:
add_action( 'save_post', 'my_save_post', 10, 2 );
function my_save_post( $post_id, $post ) {
if ( wp_is_post_revision( $post_id ) )
return;
$matches = array();
preg_match_all( '/href\s*=\s*[\"\']([^\"\']+)/', $post->post_content, $matches );
$first_link = false;
if ( ! empty( $matches[1][0] ) )
$first_link = $matches[1][0];
update_post_meta( $post_id, 'link', esc_url_raw( $first_link ) );
}

Resources