Come utilizzare wc_create_order con prodotti in abbonamento
Voglio creare un nuovo ordine programmaticamente.
Questo codice funziona bene con prodotti semplici,
$product = get_product($product_id);
$order = wc_create_order();
$order->add_product( $product , 1 );
$order->calculate_totals();
// assegna l'ordine all'utente corrente
update_post_meta($order->id, '_customer_user', get_current_user_id() );
// completa il pagamento
$order->payment_complete();
ma quando lo uso per un prodotto in abbonamento non aggiunge l'abbonamento, aggiunge solo l'ordine.

Ecco il mio codice per creare un abbonamento - ci sono voluti molti tentativi ed errori per capire tutto. Buona fortuna!
function create_test_sub() {
$email = 'test@test.com';
$start_date = '2015-01-01 00:00:00';
$address = array(
'first_name' => 'Jeremy',
'last_name' => 'Test',
'company' => '',
'email' => $email,
'phone' => '777-777-777-777',
'address_1' => '31 Main Street',
'address_2' => '',
'city' => 'Auckland',
'state' => 'AKL',
'postcode' => '12345',
'country' => 'AU'
);
$default_password = wp_generate_password();
if (!$user = get_user_by('login', $email)) $user = wp_create_user( $email, $default_password, $email );
// Ho usato un prodotto con più varianti
$parent_product = wc_get_product(22998);
$args = array(
'attribute_billing-period' => 'Yearly',
'attribute_subscription-type' => 'Both'
);
$product_variation = $parent_product->get_matching_variation($args);
$product = wc_get_product($product_variation);
// Ogni variante ha anche la sua classe di spedizione
$shipping_class = get_term_by('slug', $product->get_shipping_class(), 'product_shipping_class');
WC()->shipping->load_shipping_methods();
$shipping_methods = WC()->shipping->get_shipping_methods();
// Ho una logica per selezionare quale metodo di spedizione usare; il tuo caso d'uso sarà probabilmente diverso, quindi individua il metodo che ti serve e memorizzalo in $selected_shipping_method
$selected_shipping_method = $shipping_methods['free_shipping'];
$class_cost = $selected_shipping_method->get_option('class_cost_' . $shipping_class->term_id);
$quantity = 1;
// Per quanto ne so, devi prima creare l'ordine, poi l'abbonamento
$order = wc_create_order(array('customer_id' => $user->id));
$order->add_product( $product, $quantity, $args);
$order->set_address( $address, 'billing' );
$order->set_address( $address, 'shipping' );
$order->add_shipping((object)array (
'id' => $selected_shipping_method->id,
'label' => $selected_shipping_method->title,
'cost' => (float)$class_cost,
'taxes' => array(),
'calc_tax' => 'per_order'
));
$order->calculate_totals();
$order->update_status("completed", 'Ordine importato', TRUE);
// Ordine creato, ora crea l'abbonamento collegato - opzionale se non stai creando un abbonamento
// Ogni variante ha un periodo di abbonamento diverso
$period = WC_Subscriptions_Product::get_period( $product );
$interval = WC_Subscriptions_Product::get_interval( $product );
$sub = wcs_create_subscription(array('order_id' => $order->id, 'billing_period' => $period, 'billing_interval' => $interval, 'start_date' => $start_date));
$sub->add_product( $product, $quantity, $args);
$sub->set_address( $address, 'billing' );
$sub->set_address( $address, 'shipping' );
$sub->add_shipping((object)array (
'id' => $selected_shipping_method->id,
'label' => $selected_shipping_method->title,
'cost' => (float)$class_cost,
'taxes' => array(),
'calc_tax' => 'per_order'
));
$sub->calculate_totals();
WC_Subscriptions_Manager::activate_subscriptions_for_order($order);
print "<a href='/wp-admin/post.php?post=" . $sub->id . "&action=edit'>Abbonamento creato! Clicca qui per modificare</a>";
}

Grazie per questo, ma non riesco a farlo funzionare. Qual è la funzione wcs_create_subscription()
? Non è definita, e nemmeno wc_create_subscription()
se è un errore di battitura.

Avrai bisogno dell'estensione Subscriptions per far funzionare quella parte! (Non dimenticare che puoi cercare i nomi delle funzioni su Google, di solito sono molto facili da trovare perché sono molto specifici.)

Sì, avevo il plugin Subscriptions, ma sembra che avessi una versione più vecchia (1.5.). L'ho aggiornata alla 2.0. ora e il codice sembra funzionare. Grazie mille!

Ottimo caso d'uso ed esempio di wc_create_order + wcs_create_subscription!

Continuo a ricevere Call to undefined method WP_Error::add_product()
qualche idea?

Sfortunatamente devi gestire manualmente la creazione dell'abbonamento tramite codice, poiché semplicemente aggiungendo un ordine non viene gestito automaticamente.
Ecco la mia funzione personalizzata che ho creato basandomi su tutte le risposte trovate su Stack Overflow e scavando nel codice base di Subscriptions.
Testato con:
- WordPress 5.2.5
- WooCommerce 3.8.0
- WooCommerce Subscriptions 2.6.1
https://gist.github.com/tripflex/a3123052f36daf18f7cb05391d752223
function give_user_subscription( $product, $user_id, $note = '' ){
// Prima verifica che tutte le funzioni e classi richieste esistano
if( ! function_exists( 'wc_create_order' ) || ! function_exists( 'wcs_create_subscription' ) || ! class_exists( 'WC_Subscriptions_Product' ) ){
return false;
}
$order = wc_create_order( array( 'customer_id' => $user_id ) );
if( is_wp_error( $order ) ){
return false;
}
$user = get_user_by( 'ID', $user_id );
$fname = $user->first_name;
$lname = $user->last_name;
$email = $user->user_email;
$address_1 = get_user_meta( $user_id, 'billing_address_1', true );
$address_2 = get_user_meta( $user_id, 'billing_address_2', true );
$city = get_user_meta( $user_id, 'billing_city', true );
$postcode = get_user_meta( $user_id, 'billing_postcode', true );
$country = get_user_meta( $user_id, 'billing_country', true );
$state = get_user_meta( $user_id, 'billing_state', true );
$address = array(
'first_name' => $fname,
'last_name' => $lname,
'email' => $email,
'address_1' => $address_1,
'address_2' => $address_2,
'city' => $city,
'state' => $state,
'postcode' => $postcode,
'country' => $country,
);
$order->set_address( $address, 'billing' );
$order->set_address( $address, 'shipping' );
$order->add_product( $product, 1 );
$sub = wcs_create_subscription(array(
'order_id' => $order->get_id(),
'status' => 'pending', // Lo stato dovrebbe essere inizialmente impostato su pending per corrispondere al normale processo di checkout
'billing_period' => WC_Subscriptions_Product::get_period( $product ),
'billing_interval' => WC_Subscriptions_Product::get_interval( $product )
));
if( is_wp_error( $sub ) ){
return false;
}
// Modellato su WC_Subscriptions_Cart::calculate_subscription_totals()
$start_date = gmdate( 'Y-m-d H:i:s' );
// Aggiungi prodotto all'abbonamento
$sub->add_product( $product, 1 );
$dates = array(
'trial_end' => WC_Subscriptions_Product::get_trial_expiration_date( $product, $start_date ),
'next_payment' => WC_Subscriptions_Product::get_first_renewal_payment_date( $product, $start_date ),
'end' => WC_Subscriptions_Product::get_expiration_date( $product, $start_date ),
);
$sub->update_dates( $dates );
$sub->calculate_totals();
// Aggiorna lo stato dell'ordine con una nota personalizzata
$note = ! empty( $note ) ? $note : __( 'Ordine e abbonamento aggiunti programmaticamente.' );
$order->update_status( 'completed', $note, true );
// Aggiorna anche lo stato dell'abbonamento da pending ad active (e aggiungi nota)
$sub->update_status( 'active', $note, true );
return $sub;
}
