I created a custom payment gateway plugin that caters payment for WooCommerce site orders via a third party payment gateway. Once the third party received the payment of the customer it then sends post data into your designated URL so you can process/update your database. Updating order status on WooCommerce callback via Get method works but not with Post.
This what i am working with
add_action( 'woocommerce_api_callback', array( $this, 'thirdparty_response' ));
function thirdparty_response()
{
global $woocommerce;
if(isset($_POST['order_id']) && isset($_POST['order_status'])) //Parameters sent by third party gateway
{
$order_status = $_POST['order_status'];
$order_id = $_POST['order_id'];
$order = new WC_Order( $order_id );
if ($order_status == "success")
{
$order->update_status('processing', __('Payment Received', 'woothemes'));
}
else
{
$order->update_status('failed', __('Payment Failed', 'woothemes'));
}
}
}
Thank you and I hope you can help me.
Have you created your Gateway class? This is a snippet from WC Paypal Gateway, and to activate the check_response you have to configure your 3rd party Payment Gateway service to callback your URL formed like this (you need to replace the name of your class in both callback URL and in the hook name):
$your_callback = str_replace( 'https:', 'http:', add_query_arg( 'wc-api', 'WC_Gateway_Paypal', home_url( '/' ) ) );
public function __construct( $sandbox = false, $receiver_email = '' ) {
add_action( 'woocommerce_api_wc_gateway_paypal', array( $this, 'check_response' ) );
add_action( 'valid-paypal-standard-ipn-request', array( $this, 'valid_response' ) );
$this->receiver_email = $receiver_email;
$this->sandbox = $sandbox;
}
Related
I'm trying to learn WooCommerce and WordPress plugins so I'm tweaking around. I'm trying to create a plugin that redirects customer to a custom page after checkout. The custom page/url can be defined when I create the product. Here is my code:
<?php
/*
Plugin Name: Custom Redirect After Sale
Description: Redirects customers to a custom page after a successful sale.
*/
// Register a new meta field for products
add_action( 'add_meta_boxes', 'custom_redirect_meta_box' );
function custom_redirect_meta_box() {
add_meta_box( 'custom_redirect_meta_box', 'Custom Redirect URL', 'custom_redirect_meta_box_callback', 'product', 'side' );
}
function custom_redirect_meta_box_callback( $post ) {
$value = get_post_meta( $post->ID, '_custom_redirect_url', true );
echo '<label for="custom_redirect_url">Custom Redirect URL:</label>';
echo '<input type="text" id="custom_redirect_url" name="custom_redirect_url" value="' . esc_attr( $value ) . '" style="width:100%">';
}
// Save the meta field value when the product is saved
add_action( 'save_post_product', 'save_custom_redirect_meta_box_data' );
function save_custom_redirect_meta_box_data( $post_id ) {
if ( isset( $_POST['custom_redirect_url'] ) ) {
update_post_meta( $post_id, '_custom_redirect_url', sanitize_text_field( $_POST['custom_redirect_url'] ) );
}
}
// Redirect to the custom page after a successful sale
add_action( 'woocommerce_payment_complete', 'custom_redirect_after_sale' );
function custom_redirect_after_sale( $order_id ) {
$order = wc_get_order( $order_id );
//$order->update_status( 'completed' );
$items = $order->get_items();
// Get the first product in the order
$product = reset($items);
// Get the custom redirect URL for the product
//$redirect_url = get_post_meta( $product->get_product_id(), '_custom_redirect_url', true );
$redirect_url = get_post_meta( $product->get_id(), '_custom_redirect_url', true );
//echo "Meta retrieved: " . $redirect_url;
//error_log("callback fired");
//echo "Payment complete ho ho ho";
if( $redirect_url ) {
wp_redirect( $redirect_url );
exit;
}
}
It seems the woocommerce_payment_complete hook is not firing. I tried to echo out the redirect url and text but it doesn't seem to work.
I'm on localhost and I'm using the cash on delivery payment method.
Basing this answer on the great https://rudrastyh.com/ - specifically this tutorial https://rudrastyh.com/woocommerce/thank-you-page.html#redirects this is the code that should work for what you are trying to do.
First, you hook into the template_redirect action to determine the URL where the customer needs to go
Getting the Order ID, you can get the products purchased for that order
Once you have the purchased products, you can get their ID and meta data, the redirect URL you saved for each. Note that while you use WP functions for handling meta, when working with WooCommerce it is best practice to use its CRUD methods. In case in the future they port products to custom tables, your code will continue working.
Implement the redirect with the WP function wp_safe_redirect
Note that what you are trying to achieve will have problems if customers purchase orders with more than 1 product, and you have more than 1 redirect URL. In this implementation, the first product in the order that has a saved redirect URL will override all others
add_action( 'template_redirect', 'purchased_product_redirect');
function purchased_product_redirect(){
if( !function_exists( 'is_wc_endpoint_url' )){
return;
}
// do nothing if we are not on the order received page
if( ! is_wc_endpoint_url( 'order-received' ) || empty( $_GET[ 'key' ] ) ) {
return;
}
// Get the order ID
$order_id = wc_get_order_id_by_order_key( $_GET[ 'key' ] );
// Get an instance of the WC_Order object
$order = wc_get_order( $order_id );
// Get and Loop Over Order Items
foreach ( $order->get_items() as $item_id => $item ) {
$product_id = $item->get_product_id();
$product = wc_get_product($product_id);
if(!$product){
continue;
}
//Get the first product's redirect URL
$product_redirect_url = $product->get_meta('_custom_redirect_url');
if(!$product_redirect_url){
continue;
}
wp_safe_redirect( $product_redirect_url );
exit; // always exit after using wp_safe_redirect
}
}
Our scenario is:
The guest user enters the site and places one or more orders without the need to register. And after a while, he decides to register on the site.
Now how to link guest orders to customer account after registeration?
I use the following code, but this code only works for users who have already registered but did not log in at the time of purchase. Any advice?
//assign user in guest order
add_action( 'woocommerce_new_order', 'action_woocommerce_new_order', 10, 1 );
function action_woocommerce_new_order( $order_id ) {
$order = new WC_Order($order_id);
$user = $order->get_user();
if( !$user ){
//guest order
$userdata = get_user_by( 'email', $order->get_billing_email() );
if(isset( $userdata->ID )){
//registered
update_post_meta($order_id, '_customer_user', $userdata->ID );
}else{
//Guest
}
}
}
You can use the woocommerce_created_customer action hook and the wc_update_new_customer_past_orders() function
So you get:
function action_woocommerce_created_customer( $customer_id, $new_customer_data, $password_generated ) {
// Link past orders to this newly created customer
wc_update_new_customer_past_orders( $customer_id );
}
add_action( 'woocommerce_created_customer', 'action_woocommerce_created_customer', 10, 3 );
I was develop a custom payment gateway for woocommerce, everything is good but after payment success the order still "pending payment"
In the __construct() function I check for payment provider respond
<?php
//when payment done and redirected with payment reference code
if(isset($_REQUEST['transaction_id'])){
paytabs_set_cookie('transaction_id', $_REQUEST['transaction_id']);
$order = new WC_Order($order_id);
$this->order = $order;
$this->complete_transaction($order->get_id(), $_REQUEST['transaction_id']);
}
and here is the complete_transaction() function
<?php
/*
When transaction completed it is check the status
is transaction completed or rejected
*/
function complete_transaction($order_id, $transaction_id) {
global $woocommerce;
$order = new WC_Order( $order_id );
$request_string=array(
'secret_key' => $_COOKIE['secret_key'],
'merchant_email' => $_COOKIE['merchant_email'],
'transaction_id' => $transaction_id,
'order_id' => $order_id
);
$gateway_url=$this->liveurl.'apiv2/verify_payment_transaction';
$getdataresponse=$this->sendRequest($gateway_url, $request_string);
$object=json_decode($getdataresponse, true);
if (isset($object->response_code)) {
//if get response successfull
if($object->response_code == '100'){
// thankyou and set error message
$this->msg['class'] = 'woocommerce_message';
$check=$order->payment_complete();
// Reduce stock levels
$order->reduce_order_stock();
// Remove cart
$woocommerce->cart->empty_cart();
wc_add_notice( '' . __( 'Thank you for shopping with us. Your account has been charged and your transaction is successful.
We will be shipping your order to you soon.', 'woocommerce' ), 'success' );
wp_redirect( $this->get_checkout_order_received_url( $order ) );
exit;
}else{
// Change the status to pending / unpaid
$order->update_status('failed', __('Payment Cancelled', 'error'));
// Add error for the customer when we return back to the cart
$message=$object->result;
wc_add_notice( '<strong></strong> ' . __($message, 'error' ), 'error' );
// Redirect back to the last step in the checkout process
wp_redirect( $this->get_cancel_order_url( $order ) );
exit;
}
}
}
But the order status still "pending payment".
now I need to change the order status to "Completed" after check the payment provider respond.
Fixed
The problem because of this line
wp_redirect( $this->get_checkout_order_received_url( $order ) );
it must be $order instead of $this so the line is like this
wp_redirect( $order->get_checkout_order_received_url( $order ) );
I am trying to attach the billing company to the admin email. I am using this script
add_action( 'user_register', array( $this, 'user_register' ) );
function user_register( $user_id ) {
// using this function to send the email
$this->send_notification( 'admin-user', $user_id );
}
public function send_notification( $setting, $id ) {
$user_company = get_user_meta($id, 'billing_company');
wp_mail( $email, $subj, $msg.$user_company[0], $headers );
}
the issue is that get_user_meta returns empty because according to wordpress doc when you use 'user_register' action Not all user meta data has been stored. So basically when user register the usermeta table is still empty because I tried to put an existing user id and it worked fine.
https://codex.wordpress.org/Plugin_API/Action_Reference/user_register.
can anyone suggest a way to send the company name in the admin notification email?
If you are using custom registration form, you can send the email before updating the database.
add_action( 'user_register', array( $this, 'user_register' ) );
function user_register( $user_id ) {
$billing_company = $_POST['billing_company'];
wp_mail( $email, $subj, $billing_company, $headers );
}
Alternatively, you can delay the execution of the function with sleep:
add_action( 'user_register', array( $this, 'user_register' ) );
function user_register( $user_id ) {
sleep(5);
$this->send_notification( 'admin-user', $user_id );
}
I have a site running an old version of Woo v2.5.5 using legacy v3 for the API. I was able to use the action woocommerce_api_order_response to add data to the orders.
Something like:
add_action( 'woocommerce_api_order_response', 'add_testing_api_function', 10, 1 );
function add_testing_api_function( $order_data ) {
$order_data['foo'] = "testing";
return $order_data;
}
This works fine over the older API link:
https://example.com/wc-api/v3/orders?consumer_key=KEY&consumer_secret=SECRET
However, I need to update to Woo v3.3+ and the REST API is server up as:
https://example.com/wp-json/wc/v2/orders?consumer_key=KEY&consumer_secret=SECRET
My custom data no longer appears, and the hook does not appear to work. Is there another I can use?
WC API is indeed a great tool. Adding your own custom data to WC API shop order's response in WooCommerce 3.x can still be achieved as easily as it used to be with the legacy version of the API.
WooCommerce has these prepare filters for most of their API responses (see). Note that the format of them is woocommerce_rest_prepare_{$post_type}, where $post_type is a post type or taxonomy name like shop_orders or product_cat. In WooCommerce 2.7+ some of these filters also have a _object suffix.
As long as our intent is to add custom data to orders, the right filter to use will be woocommerce_rest_prepare_shop_order_object, where shop_order is our {$post_type} followed the _object suffix (as described above).
The following function conditionally gets user meta and returns the user's social profile's avatar url if available.
/**
* Add custom data to WC API shop order response
* Overriding "$object" here with $order so it's easier to access its properties
*/
function my_wc_rest_prepare_order( $response, $order, $request ) {
if( empty( $response->data ) )
return $response;
$order_id = $order->get_id();
// Get an instance of the WC_Order object
$order = wc_get_order($order_id);
// Get the user ID from WC_Order methods
$user_id = $order->get_customer_id(); // $order->get_user_id(); // or $order->get_customer_id();
// check for WooCommerce Social Login User Avatar
if( class_exists( 'WC_Social_Login' ) ) {
$fb_avatar = get_user_meta( $user_id, '_wc_social_login_facebook_profile_image', true );
$gplus_avatar = get_user_meta( $user_id, '_wc_social_login_google_profile_image', true );
}
$social_data = array();
$avatar_url = array();
$customer_picture = array(
'default' => get_avatar_url( $user_id ),
'facebook' => ( $fb_avatar ) ? esc_url( $fb_avatar ) : '',
'google' => ( $gplus_avatar ) ? esc_url( $gplus_avatar ) : ''
);
$response->data['social_data']['avatar_url'] = $customer_picture;
return $response;
}
add_filter( 'woocommerce_rest_prepare_shop_order_object', 'my_wc_rest_prepare_order', 10, 3 );
Result:
[{
"social_data": {
"avatar_url": {
"default": "https://secure.gravatar.com/avatar/6e27402273b47316097247a2057492f8?s=96&d=mm&r=g",
"facebook": "https://graph.facebook.com/2028542057604385/picture?width=150&height=150",
"google": ""
}
},
}]