Context: I'm creating a WordPress website where users can upload their own posts via frontend by paying a posting fee.
Here is how it works: the user uploads their post data inside a form created with the plugin WP User Frontend Pro; once they click on the "submit" button, they are redirected to the payment page and, once the payment is complete, the system handles the PayPal IPN confirmation and publishes the post.
I have this code snippet created by WP User Frontend Pro that handles the PayPal gateway:
<?php
public function prepare_to_send( $data ) {
$user_id = $data['user_info']['id'];
$listener_url = add_query_arg( 'action', 'wpuf_paypal_success', home_url( '' ) );
//$listener_url = 'http://a53d2f68b609.ngrok.io/?action=wpuf_paypal_success';
//$listener_url = 'https://wpuf.sharedwithexpose.com/?action=wpuf_paypal_success';
$redirect_page_id = wpuf_get_option( 'payment_success', 'wpuf_payment' );
if ( $redirect_page_id ) {
$return_url = add_query_arg( 'action', 'wpuf_paypal_success', untrailingslashit( get_permalink( $redirect_page_id ) ) );
} else {
$return_url = add_query_arg( 'action', 'wpuf_paypal_success', untrailingslashit( get_permalink( wpuf_get_option( 'subscription_page', 'wpuf_payment' ) ) ) );
}
$billing_amount = empty( $data['price'] ) ? 0 : $data['price'];
if ( isset( $_POST['coupon_id'] ) && ! empty( $_POST['coupon_id'] ) ) {
$billing_amount = WPUF_Coupons::init()->discount( $billing_amount, $_POST['coupon_id'], $data['item_number'] );
$coupon_id = $_POST['coupon_id'];
} else {
$coupon_id = '';
}
$data['subtotal'] = $billing_amount;
$billing_amount = apply_filters( 'wpuf_payment_amount', $data['subtotal'] );
$data['tax'] = $billing_amount - $data['subtotal'];
if ( $billing_amount == 0 ) {
wpuf_get_user( $user_id )->subscription()->add_pack( $data['item_number'], $profile_id = null, false, 'free' );
wp_redirect( $return_url );
exit();
}
if ( $data['type'] == 'pack' && $data['custom']['recurring_pay'] == 'yes' ) {
if ( $data['custom']['cycle_period'] == 'day' ) {
$period = 'D';
} elseif ( $data['custom']['cycle_period'] == 'week' ) {
$period = 'W';
} elseif ( $data['custom']['cycle_period'] == 'month' ) {
$period = 'M';
} elseif ( $data['custom']['cycle_period'] == 'year' ) {
$period = 'Y';
}
if ( $data['custom']['trial_duration_type'] == 'day' ) {
$trial_period = 'D';
} elseif ( $data['custom']['trial_duration_type'] == 'week' ) {
$trial_period = 'W';
} elseif ( $data['custom']['trial_duration_type'] == 'month' ) {
$trial_period = 'M';
} elseif ( $data['custom']['trial_duration_type'] == 'year' ) {
$trial_period = 'Y';
}
$paypal_args = [
'cmd' => '_xclick-subscriptions',
'business' => wpuf_get_option( 'paypal_email', 'wpuf_payment' ),
'a3' => $billing_amount,
'mc_amount3' => $billing_amount,
'p3' => ! empty( $data['custom']['billing_cycle_number'] ) ? $data['custom']['billing_cycle_number'] : '0',
't3' => $period,
'item_name' => $data['custom']['post_title'],
'custom' => json_encode(
[
'billing_amount' => $billing_amount,
'type' => $data['type'],
'user_id' => $user_id,
'coupon_id' => $coupon_id,
'subtotal' => $data['subtotal'],
'tax' => $data['tax'],
]
),
'shipping' => 0,
'no_note' => 1,
'currency_code' => $data['currency'],
'item_number' => $data['item_number'],
'rm' => 2,
'return' => $return_url,
'cancel_return' => $return_url,
'notify_url' => $listener_url,
'src' => 1,
'sra' => 1,
'srt' => intval( $data['custom']['billing_limit'] ),
'recurring' => 1,
];
if ( $data['custom']['trial_status'] == 'yes' ) {
$paypal_args['p1'] = $data['custom']['trial_duration'];
$paypal_args['t1'] = $trial_period;
$paypal_args['a1'] = 0;
}
} else {
$paypal_args = [
'cmd' => '_xclick',
'business' => wpuf_get_option( 'paypal_email', 'wpuf_payment' ),
'amount' => $billing_amount,
'item_name' => isset( $data['custom']['post_title'] ) ? $data['custom']['post_title'] : $data['item_name'],
'no_shipping' => '1',
'shipping' => '0',
'no_note' => '1',
'currency_code' => $data['currency'],
'item_number' => $data['item_number'],
'charset' => 'UTF-8',
'rm' => '2',
'custom' => json_encode(
[
'type' => $data['type'],
'user_id' => $user_id,
'coupon_id' => $coupon_id,
'subtotal' => $data['subtotal'],
'tax' => $data['tax'],
]
),
'return' => $return_url,
'notify_url' => $listener_url,
];
}
$this->set_mode();
?>
What I'm focusing on here is the $billing_amount var.
At the moment, this var value is declared via a setting inside the plugin and it is a fixed number value: what I can do is simply change the "posting fee" by changing the value inside the plugin's form settings.
I would like, if possible, to change the value based on some radio/checkbox input fields that the user selects inside the posting form that comes before the payment page (as described before). I already know how to change an input value via JS, but I have no idea on how I could pass this JS value to the $billing_amount var.
Related
I try to implement the Rawg.io API to my Wordpress Functions.php File but it doesn't work, i tried my code with another API and it is working fine, i think it has something to do with the API link Page='.$current_page.'
as you can see i created an custom post type to add the games to.
i also created custom fields with the right field keys.
My Report.txt file keeps returning current page = 1
function register_game_cpt() {
register_post_type( 'game', array(
'label' => 'Games',
'public' => true,
'capability_type' => 'post',
'supports' => array('title', 'editor', 'thumbnail'),
'taxonomies' => array('recordings', 'category', 'whatever', 'post_tag'),
));
}
add_action( 'init', 'register_game_cpt' );
// if ( ! wp_next_scheduled( 'update_game_list' ) ) {
// wp_schedule_event( time(), 'weekly', 'update_game_list' );
// }
add_action( 'update_game_list', 'get_games_from_api' );
add_action( 'wp_ajax_nopriv_get_games_from_api', 'get_games_from_api' );
add_action( 'wp_ajax_get_games_from_api', 'get_games_from_api' );
function get_games_from_api() {
$file = get_stylesheet_directory() . '/report.txt';
$current_page = ( ! empty( $_POST['current_page'] ) ) ? $_POST['current_page'] : 1;
$games = [];
// Should return an array of objects
$results = wp_remote_retrieve_body(wp_remote_get('https://api.rawg.io/api/games?key=/////////////////////&page='.$current_page.'&page_size=40'));
file_put_contents($file, "Current Page: " . $current_page. "\n\n", FILE_APPEND);
// turn it into a PHP array from JSON string
$results = json_decode( $results );
// Either the API is down or something else spooky happened. Just be done.
if( ! is_array( $results ) || empty( $results ) ){
return false;
}
$games[] = $results;
foreach( $games[0] as $game ){
$game_slug = sanitize_title( $game->name . '-' . $game->id );
$existing_game = get_page_by_path( $game_slug, 'OBJECT', 'game' );
if( $existing_game === null ){
$inserted_game = wp_insert_post( [
'post_name' => $game_slug,
'post_title' => $game_slug,
'post_type' => 'game',
'post_status' => 'publish'
] );
if( is_wp_error( $inserted_game ) || $inserted_game === 0 ) {
die('Could not insert game: ' . $game_slug);
error_log( 'Could not insert game: ' . $game_slug );
continue;
}
// add meta fields
$fillable = [
'field_62684fc72d524' => 'count',
'field_6266cb41982d3' => 'name',
'field_6266cb4c982d4' => 'publishers',
'field_6266cb54982d5' => 'genres',
'field_6266cb64012e9' => 'platforms',
'field_6266cb722ebe8' => 'dates',
'field_626850012d525' => 'results',
];
foreach( $fillable as $key => $name ) {
update_field( $key, $game->$name, $inserted_game );
}
} else {
$existing_game_id = $existing_game->ID;
$exisiting_game_timestamp = get_field('updated_at', $existing_game_id);
if( $game->updated_at >= $exisiting_game_timestamp ){
$fillable = [
'field_62684fc72d524' => 'count',
'field_6266cb41982d3' => 'name',
'field_6266cb4c982d4' => 'publishers',
'field_6266cb54982d5' => 'genres',
'field_6266cb64012e9' => 'platforms',
'field_6266cb722ebe8' => 'dates',
'field_626850012d525' => 'results',
];
foreach( $fillable as $key => $name ){
update_field( $name, $game->$name, $existing_game_id);
}
}
}
}
$current_page = $current_page + 1;
wp_remote_post( admin_url('admin-ajax.php?action=get_games_from_api'), [
'blocking' => false,
'sslverify' => false, // we are sending this to ourselves, so trust it.
'body' => [
'current_page' => $current_page
]
] );
}
I want to add an extra page to the breadcrumb trail of my site.
The problem is, that I'm using WooCommerce and on the breadcrumb doesn't work right on the my account dashboard. It always shows the following trail:
Home > My account
Even if I'm on a child page like "edit account".
These child pages aren't really pages. They are WooCommerce endpoints on the same page.
It should look like this:
Home > My account > Orders > Order ID
I tried to add a page but couldn't figure it out.
To remove a page from the breadcrumb trail, I'm using the following code:
/**
* Conditionally Override Yoast SEO Breadcrumb Trail
* http://plugins.svn.wordpress.org/wordpress-seo/trunk/frontend/class-breadcrumbs.php
* -----------------------------------------------------------------------------------
*/
add_filter( 'wpseo_breadcrumb_links', 'wpse_100012_override_yoast_breadcrumb_trail' );
function wpse_100012_override_yoast_breadcrumb_trail( $links ) {
global $post;
if ( is_home() || is_singular( 'post' ) || is_archive() ) {
$breadcrumb[] = array(
'url' => get_permalink( get_option( 'page_for_posts' ) ),
'text' => 'Blog',
);
array_splice( $links, 1, -2, $breadcrumb );
}
return $links;
}
Code is from here: https://wordpress.stackexchange.com/a/121618/96806
I've already changed it to check if I'm on a WooCommerce endpoint.
This code works fine.
But how can I change it to add a page instead of deleting it?
I guess it has something to do with the array_splice ;-)
OK, I have a solution.
Big thanks to the answer from #WebElaine: https://wordpress.stackexchange.com/a/332300/96806
Here's my full code to change the Yoast breadcrumb navigation in the WooCommerce My Account area:
add_filter('wpseo_breadcrumb_links', 'woocommerce_account_breadcrumb_trail');
function woocommerce_account_breadcrumb_trail($links) {
if ( is_wc_endpoint_url() or is_account_page() ) {
$endpoint = WC()->query->get_current_endpoint();
$endpoint_title = WC()->query->get_endpoint_title( $endpoint );
$endpoint_url = wc_get_endpoint_url($endpoint);
if ( is_account_page() && !is_wc_endpoint_url() ) :
//$links[2] = array('text' => $endpoint_title, 'url' => $endpoint_url, 'allow_html' => 1);
elseif ( is_wc_endpoint_url( 'edit-account' ) ) :
$links[2] = array('text' => $endpoint_title, 'url' => $endpoint_url, 'allow_html' => 1);
elseif ( is_wc_endpoint_url( 'orders' ) ) :
$links[2] = array('text' => $endpoint_title, 'url' => $endpoint_url, 'allow_html' => 1);
elseif ( is_wc_endpoint_url( 'view-order' ) ) :
$endpoint_orders = 'orders';
$endpoint_orders_title = WC()->query->get_endpoint_title( $endpoint_orders );
$endpoint_orders_url = wc_get_endpoint_url($endpoint_orders);
$links[2] = array('text' => $endpoint_orders_title, 'url' => $endpoint_orders_url, 'allow_html' => 1);
$links[3] = array('text' => $endpoint_title, 'url' => $endpoint_url, 'allow_html' => 1);
elseif ( is_wc_endpoint_url( 'edit-address' ) ) :
$links[2] = array('text' => $endpoint_title, 'url' => $endpoint_url, 'allow_html' => 1);
elseif ( is_wc_endpoint_url( 'payment-methods' ) ) :
$links[2] = array('text' => $endpoint_title, 'url' => $endpoint_url, 'allow_html' => 1);
elseif ( is_wc_endpoint_url( 'add-payment-method' ) ) :
$endpoint_payment_methods = 'payment-methods';
$endpoint_payment_methods_title = WC()->query->get_endpoint_title( $endpoint_payment_methods );
$endpoint_payment_methods_url = wc_get_endpoint_url($endpoint_payment_methods);
$links[2] = array('text' => $endpoint_payment_methods_title, 'url' => $endpoint_payment_methods_url, 'allow_html' => 1);
$links[3] = array('text' => $endpoint_title, 'url' => $endpoint_url, 'allow_html' => 1);
endif;
}
return $links;
}
I'm happy about every feedback.
I am using a wordpress/woocommerce theme named "invogue". This theme contain some ajax functions that are called using AJAX, but they are super slow >5 sec each.
Is there any way to edit this function to speed things up ?
the following gets the cart items
#GET CART NAV DATA
public function htheme_get_nav_cart_data(){
#GLOBALS
global $wpdb, $hmenu_helper, $woocommerce;
if ( class_exists( 'WooCommerce' ) ) {
#VARAIBLES
$cart_count = $woocommerce->cart->cart_contents_count;
$cart_link = esc_url(get_permalink(get_option('woocommerce_cart_page_id')));
$cart = $woocommerce->cart->get_cart();
$total_quantity = 0;
#ARRAY OF ITEMS
$cart_items = [];
$cart_count = 1;
#FOREACH CART ITEM
foreach($cart as $item){
$image = wp_get_attachment_image_src ( get_post_thumbnail_id ( $item['product_id'] ), 'full' );
$cart_items[] = array(
'id' => $item['product_id'],
'title' => esc_html($item['data']->post->post_title),
'quantity' => $item['quantity'],
'total' => $item['line_subtotal'],
'link' => get_permalink($item['product_id']),
'price' => wc_get_price_decimals(),
'image' => $image[0],
'price_html' => $this->htheme_return_price_html($item['product_id']),
'qty' => esc_html__('Qty', 'invogue'),
);
$total_quantity += $item['quantity'];
$cart_count++;
}
#ECHO JSON
echo json_encode(array(
'status' => 'active',
'count' => $total_quantity,
'url' => $cart_link,
'cart' => $cart_items,
'symbol' => get_woocommerce_currency_symbol(get_option('woocommerce_currency')),
'total' => $woocommerce->cart->get_cart_total(),
));
exit();
} else {
#NOT ACTIVE
echo json_encode(array(
'status' => 'not'
));
exit();
}
}
the following gets the wishlist items
public function htheme_get_nav_wishlist_data(){
#GLOBALS
global $wpdb, $hmenu_helper, $woocommerce;
if ( class_exists( 'WooCommerce' ) ) {
#GET USER ID
$user_ID = get_current_user_id();
#GET USER WISHLIST
$wishlist = esc_attr( get_the_author_meta( 'user_wishlist', $user_ID ) );
#ARGS
$args = array(
'post_type' => 'product',
'posts_per_page' => -1,
'offset' => 0,
'include' => explode(',', $wishlist)
);
#PRODUCTS
$products = get_posts($args);
#ECHO JSON
echo json_encode($products);
exit();
} else {
#NOT ACTIVE
echo json_encode(array(
'status' => 'not'
));
exit();
}
}
I've got this basic function as below:
function buy()
{
$item_id = ( int )$this->uri->segment( 3 );
if ( $item_id > '0' )
{
$item = $this->db->where( 'shop_id', $item_id )->get( 'shop' )->row();
if ( $item )
{
$player = $this->user->info( $this->user->id() );
if ( $player->users_money >= $item->shop_req_money && $player->users_credits >= $item->shop_req_credits)
{
$this->db->update( 'users_items', array( 'users_id' => $this->user->id(), 'users_motors_id' => '0' ), array( 'users_items_id' => $item->users_items_id ) );
$this->db->update( 'users', array( 'users_money' => $player->users_money - $item->shop_req_money, 'users_credits' => $player->users_credits - $item->shop_req_credits ), array( 'users_id' => $this->user->id() ) );
$this->db->query( 'UPDATE users SET users_money=users_money+' . $item->shop_req_money . ', users_credits=users_credits+' . $item->shop_req_credits . ' WHERE users_id=' . $this->db->escape( $item->shop_users_id ) );
$this->db->delete( 'shop', array( 'shop_id' => $item->shop_id ) );
$this->session->set_flashdata( 'success', true );
}
else
$this->session->set_flashdata( 'error', true );
}
}
header( 'Location: ' . $_SERVER['HTTP_REFERER'] );
}
and I edited it like that to add additional check if the reg ip isn't the same as the other one and if so to set an error message.
function buy()
{
$item_id = ( int )$this->uri->segment( 3 );
if ( $item_id > '0' )
{
$item = $this->db->where( 'shop_id', $item_id )->get( 'shop' )->row();
if ( $item )
{
$player = $this->user->info( $this->user->id() );
$players = $this->user->info( $item->shop_users_id );
if ( $players->users_reg_ip === $player->users_reg_ip )
{
$this->session->set_flashdata( 'errorip', true );
}
elseif ( $player->users_money >= $item->shop_req_money && $player->users_credits >= $item->shop_req_credits)
{
$this->db->update( 'users_items', array( 'users_id' => $this->user->id(), 'users_motors_id' => '0' ), array( 'users_items_id' => $item->users_items_id ) );
$this->db->update( 'users', array( 'users_money' => $player->users_money - $item->shop_req_money, 'users_credits' => $player->users_credits - $item->shop_req_credits ), array( 'users_id' => $this->user->id() ) );
$this->db->query( 'UPDATE users SET users_money=users_money+' . $item->shop_req_money . ', users_credits=users_credits+' . $item->shop_req_credits . ' WHERE users_id=' . $this->db->escape( $item->shop_users_id ) );
$this->db->delete( 'shop', array( 'shop_id' => $item->shop_id ) );
$this->session->set_flashdata( 'success', true );
}
else
$this->session->set_flashdata( 'error', true );
}
}
header( 'Location: ' . $_SERVER['HTTP_REFERER'] );
}
It works the way it is BUT basically I am asking if thats the correct way of doing that or there should be something else I can do similiar to that but better? Would be really appreciated if there any comments on my question. Thanks in advance!
Yes you can include that on the condition block. Like this:
if ( $players->users_reg_ip === $player->users_reg_ip) {
// trying to buy from the same IP
$this->session->set_flashdata( 'errorip', true );
}
elseif ( $player->users_money < $item->shop_req_money && $player->users_credits < $item->shop_req_credits) {
// if user has not enough money and user credits is less than shop requirement credits
// or maybe you mean OR ||
$this->session->set_flashdata( 'error', true );
}
else {
$this->db->update('users_items',
array( 'users_id' => $this->user->id(), 'users_motors_id' => '0' ),
array( 'users_items_id' => $item->users_items_id )
);
$this->db->update( 'users',
array( 'users_money' => $player->users_money - $item->shop_req_money,
'users_credits' => $player->users_credits - $item->shop_req_credits
),
array( 'users_id' => $this->user->id() )
);
$this->db->query( 'UPDATE users SET users_money=users_money+' . $item->shop_req_money . ', users_credits=users_credits+' . $item->shop_req_credits . ' WHERE users_id=' . $this->db-> escape( $item->shop_users_id ) );
$this->db->delete( 'shop', array( 'shop_id' => $item->shop_id ) );
$this->session->set_flashdata( 'success', true );
}
// instead of using referrer why not
// redirect('controller/method'); ?
I needed to create a Woocommerce order programatically, however using the 'old' Woocommerce made this a very dirty procedure.
I had to insert all kind of database records manually, using many update_post_meta calls.
Looking for a better solution.
With latest version of WooCommerce is possible try this as something like
$address = array(
'first_name' => 'Fresher',
'last_name' => 'StAcK OvErFloW',
'company' => 'stackoverflow',
'email' => 'test#test.com',
'phone' => '777-777-777-777',
'address_1' => '31 Main Street',
'address_2' => '',
'city' => 'Chennai',
'state' => 'TN',
'postcode' => '12345',
'country' => 'IN'
);
$order = wc_create_order();
$order->add_product( get_product( '12' ), 2 ); //(get_product with id and next is for quantity)
$order->set_address( $address, 'billing' );
$order->set_address( $address, 'shipping' );
$order->add_coupon('Fresher','10','2'); // accepted param $couponcode, $couponamount,$coupon_tax
$order->calculate_totals();
Call this above code with your function then it will work accordingly.
Note it not work with old version of WooCommerce like 2.1.12, It works only from 2.2 of WooCommerce.
Hope it helps
2017-2021 For WooCommerce 3 and Above
Woocommerce 3 has introduced CRUD objects and there is lot of changes on Order items… Also some WC_Order methods are now deprecated like add_coupon().
Here is a function that allow creating programmatically an order nicely with all required data in it, including the taxes:
function create_wc_order( $data ){
$gateways = WC()->payment_gateways->get_available_payment_gateways();
$order = new WC_Order();
// Set Billing and Shipping adresses
foreach( array('billing_', 'shipping_') as $type ) {
foreach ( $data['address'] as $key => $value ) {
if( $type === 'shipping_' && in_array( $key, array( 'email', 'phone' ) ) )
continue;
$type_key = $type.$key;
if ( is_callable( array( $order, "set_{$type_key}" ) ) ) {
$order->{"set_{$type_key}"}( $value );
}
}
}
// Set other details
$order->set_created_via( 'programatically' );
$order->set_customer_id( $data['user_id'] );
$order->set_currency( get_woocommerce_currency() );
$order->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) );
$order->set_customer_note( isset( $data['order_comments'] ) ? $data['order_comments'] : '' );
$order->set_payment_method( isset( $gateways[ $data['payment_method'] ] ) ? $gateways[ $data['payment_method'] ] : $data['payment_method'] );
$calculate_taxes_for = array(
'country' => $data['address']['country'],
'state' => $data['address']['state'],
'postcode' => $data['address']['postcode'],
'city' => $data['address']['city']
);
// Line items
foreach( $data['line_items'] as $line_item ) {
$args = $line_item['args'];
$product = wc_get_product( isset($args['variation_id']) && $args['variation_id'] > 0 ? $$args['variation_id'] : $args['product_id'] );
$item_id = $order->add_product( $product, $line_item['quantity'], $line_item['args'] );
$item = $order->get_item( $item_id, false );
$item->calculate_taxes($calculate_taxes_for);
$item->save();
}
// Coupon items
if( isset($data['coupon_items'])){
foreach( $data['coupon_items'] as $coupon_item ) {
$order->apply_coupon(sanitize_title($coupon_item['code']));
}
}
// Fee items
if( isset($data['fee_items'])){
foreach( $data['fee_items'] as $fee_item ) {
$item = new WC_Order_Item_Fee();
$item->set_name( $fee_item['name'] );
$item->set_total( $fee_item['total'] );
$tax_class = isset($fee_item['tax_class']) && $fee_item['tax_class'] != 0 ? $fee_item['tax_class'] : 0;
$item->set_tax_class( $tax_class ); // O if not taxable
$item->calculate_taxes($calculate_taxes_for);
$item->save();
$order->add_item( $item );
}
}
// Set calculated totals
$order->calculate_totals();
if( isset($data['order_status']) ) {
// Update order status from pending to your defined status and save data
$order->update_status($data['order_status']['status'], $data['order_status']['note']);
$order_id = $order->get_id();
} else {
// Save order to database (returns the order ID)
$order_id = $order->save();
}
// Returns the order ID
return $order_id;
}
Code goes in function.php file of your active child theme (or active theme) or in a plugin file.
USAGE EXAMPLE from a data array:
create_wc_order( array(
'address' => array(
'first_name' => 'Fresher',
'last_name' => 'StAcK OvErFloW',
'company' => 'stackoverflow',
'email' => 'test1#testoo.com',
'phone' => '777-777-777-777',
'address_1' => '31 Main Street',
'address_2' => '',
'city' => 'Chennai',
'state' => 'TN',
'postcode' => '12345',
'country' => 'IN',
),
'user_id' => '',
'order_comments' => '',
'payment_method' => 'bacs',
'order_status' => array(
'status' => 'on-hold',
'note' => '',
),
'line_items' => array(
array(
'quantity' => 1,
'args' => array(
'product_id' => 37,
'variation_id' => '',
'variation' => array(),
)
),
),
'coupon_items' => array(
array(
'code' => 'summer',
),
),
'fee_items' => array(
array(
'name' => 'Delivery',
'total' => 5,
'tax_class' => 0, // Not taxable
),
),
) );
With the new release of WC 2, it's much better.
However:
I do not want to use the REST API, cause I am doing a call from my own WP plugin directly. I see no use in doing a curl to my localhost
The 'WooCommerce REST API Client Library' is not useful for me cause it relay's on the REST API and it doesn't support a Create Order call
To be honest, WooCom's API Docs are limited, maybe they are still in the progress of updating it. They currently don't tell me how to create a new order, which params are required etc.
Any way, I figured out how to create an order with a line order (your product) using the classes and functions used by the REST API and I want to share it!
I created my own PHP class:
class WP_MyPlugin_woocommerce
{
public static function init()
{
// required classes to create an order
require_once WOOCOMMERCE_API_DIR . 'class-wc-api-exception.php';
require_once WOOCOMMERCE_API_DIR . 'class-wc-api-server.php';
require_once WOOCOMMERCE_API_DIR . 'class-wc-api-resource.php';
require_once WOOCOMMERCE_API_DIR . 'interface-wc-api-handler.php';
require_once WOOCOMMERCE_API_DIR . 'class-wc-api-json-handler.php';
require_once WOOCOMMERCE_API_DIR . 'class-wc-api-orders.php';
}
public static function create_order()
{
global $wp;
// create order
$server = new WC_API_Server( $wp->query_vars['wc-api-route'] );
$order = new WC_API_Orders( $server );
$order_id = $order->create_order( array
(
'order' => array
(
'status' => 'processing'
, 'customer_id' => get_current_user_id()
// , 'order_meta' => array
// (
// 'some order meta' => 'a value
// , some more order meta' => 1
// )
, 'shipping_address' => array
(
'first_name' => $firstname
, 'last_name' => $lastname
, 'address_1' => $address
, 'address_2' => $address2
, 'city' => $city
, 'postcode' => $postcode
, 'state' => $state
, 'country' => $country
)
, 'billing_address' => array(..can be same as shipping )
, 'line_items' => array
(
array
(
'product_id' => 258
, 'quantity' => 1
)
)
)
) );
var_dump($order_id);
die();
}
}
Important:
The 'WOOCOMMERCE_API_DIR' constant points to '/woocommerce/includes/api/' in your plugin dir.
The order is assigned to a customer, in my case the current logged in user. Make sure your user has a role that has the capability to read, edit, create and delete orders. My role looks like this:
$result = add_role(
'customer'
, __( 'Customer' )
, array
(
'read' => true
// , 'read_private_posts' => true
// , 'read_private_products' => true
, 'read_private_shop_orders' => true
, 'edit_private_shop_orders' => true
, 'delete_private_shop_orders' => true
, 'publish_shop_orders' => true
// , 'read_private_shop_coupons' => true
, 'edit_posts' => false
, 'delete_posts' => false
, 'show_admin_bar_front' => false
)
);
If you want to look at the shop manager's rights, check
var_dump(get_option( 'wp_user_roles'));
My create_order function nicely creates an order, with the lineitem in the order_items tables.
Hope I helped you out, it took me a while to get it right.
A lot of answers do you show the best filter(hook) to use. I searched for days because when I used the 'init' it kept making more orders. In 2 mins I had 30 orders. Anyway use this code and 1 order will be created. Also, change $product = wc_get_product( '1001' ) to your product id.Reference is here on line 144: https://github.com/dipolukarov/wordpress/blob/master/wp-content/plugins/woocommerce/classes/class-wc-checkout.php
function my_init2() {
$order = wc_create_order();
$order_id = $order->get_id();
$product = wc_get_product( '10001' );
$address = array(
'first_name' => 'John2',
'last_name' => 'Smith1',
'email' => 'johnsmith1#gmail.com',
);
//$order->date_created(2020-07-21 );
$order->add_product( $product, 1 );
$order->set_address( $address, 'billing' );
$order->set_created_via( 'programatically' );
$order->calculate_totals();
$order->set_total( $product->get_price() );
$order->update_status( 'wc-completed' );
error_log( '$order_id: ' . $order_id );
}
//add_action('admin_init','my_init2');
function my_run_only_once() {
if ( get_option( 'my_run_only_once_20' ) != 'completed' ) {
my_init2();
update_option( 'my_run_only_once_20', 'completed' );
}
}
add_action( 'admin_init', 'my_run_only_once' );