Skip to content

Instantly share code, notes, and snippets.

@igorbenic
Last active February 21, 2024 21:32
Show Gist options
  • Save igorbenic/9d555cd278c128deee0f43a56eba14da to your computer and use it in GitHub Desktop.
Save igorbenic/9d555cd278c128deee0f43a56eba14da to your computer and use it in GitHub Desktop.
How to create a custom WooCommerce Payment Gateway
<?php
// ...
function woo_payment_gateway() {
class Woo_PayPal_Gateway extends WC_Payment_Gateway {
}
}
/**
* Add Gateway class to all payment gateway methods
*/
function woo_add_gateway_class( $methods ) {
$methods[] = 'Woo_PayPal_Gateway';
return $methods;
}
add_filter( 'woocommerce_payment_gateways', 'woo_add_gateway_class' );
<?php
// ...
function woo_payment_gateway() {
class Woo_PayPal_Gateway extends WC_Payment_Gateway {
/**
* API Context used for PayPal Authorization
* @var null
*/
public $apiContext = null;
/**
* Constructor for your shipping class
*
* @access public
* @return void
*/
public function __construct() {
$this->id = 'woo_paypal';
$this->method_title = __( 'Woo PayPal', 'woodev_payment' );
$this->method_description = __( 'WooCommerce Payment Gateway for ibenic.com tutorial', 'woo_paypal' );
$this->title = __( 'Woo PayPal', 'woo_paypal' );
$this->has_fields = false;
$this->supports = array(
'products'
);
$this->get_paypal_sdk();
// Load the settings.
$this->init_form_fields();
$this->init_settings();
$this->enabled = $this->get_option('enabled');
add_action( 'check_woopaypal', array( $this, 'check_response') );
// Save settings
if ( is_admin() ) {
// Versions over 2.0
// Save our administration options. Since we are not going to be doing anything special
// we have not defined 'process_admin_options' in this class so the method in the parent
// class will be used instead
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
}
}
}
}
// ...
<?php
// ...
private function get_paypal_sdk() {
require_once WOO_PAYMENT_DIR . 'includes/paypal-sdk/autoload.php';
}
<?php
// ...
public function init_form_fields() {
$this->form_fields = array(
'enabled' => array(
'title' => __( 'Enable', 'woo_paypal' ),
'type' => 'checkbox',
'label' => __( 'Enable WooPayPal', 'woo_paypal' ),
'default' => 'yes'
),
'client_id' => array(
'title' => __( 'Client ID', 'woo_paypal' ),
'type' => 'text',
'default' => ''
),
'client_secret' => array(
'title' => __( 'Client Secret', 'woo_paypal' ),
'type' => 'password',
'default' => ''
),
);
}
<?php
// ...
private function get_api_context(){
$client_id = $this->get_option('client_id');
$client_secret = $this->get_option('client_secret');
$this->apiContext = new ApiContext(new OAuthTokenCredential(
$client_id,
$client_secret
));
}
<?php
// ...
public function process_payment( $order_id ) {
global $woocommerce;
$order = new WC_Order( $order_id );
$this->get_api_context();
$payer = new Payer();
$payer->setPaymentMethod("paypal");
$all_items = array();
$subtotal = 0;
// Products
foreach ( $order->get_items( array( 'line_item', 'fee' ) ) as $item ) {
$itemObject = new Item();
$itemObject->setCurrency( get_woocommerce_currency() );
if ( 'fee' === $item['type'] ) {
$itemObject->setName( __( 'Fee', 'woo_paypal' ) );
$itemObject->setQuantity(1);
$itemObject->setPrice( $item['line_total'] );
$subtotal += $item['line_total'];
} else {
$product = $order->get_product_from_item( $item );
$sku = $product ? $product->get_sku() : '';
$itemObject->setName( $item['name'] );
$itemObject->setQuantity( $item['qty'] );
$itemObject->setPrice( $order->get_item_subtotal( $item, false ) );
$subtotal += $order->get_item_subtotal( $item, false ) * $item['qty'];
if( $sku ) {
$itemObject->setSku( $sku );
}
}
$all_items[] = $itemObject;
}
$itemList = new ItemList();
$itemList->setItems( $all_items );
// ### Additional payment details
// Use this optional field to set additional
// payment information such as tax, shipping
// charges etc.
$details = new Details();
$details->setShipping( $order->get_total_shipping() )
->setTax( $order->get_total_tax() )
->setSubtotal( $subtotal );
$amount = new Amount();
$amount->setCurrency( get_woocommerce_currency() )
->setTotal( $order->get_total() )
->setDetails($details);
$transaction = new Transaction();
$transaction->setAmount($amount)
->setItemList($itemList)
->setInvoiceNumber(uniqid());
$baseUrl = $this->get_return_url( $order );
if( strpos( $baseUrl, '?') !== false ) {
$baseUrl .= '&';
} else {
$baseUrl .= '?';
}
$redirectUrls = new RedirectUrls();
$redirectUrls->setReturnUrl( $baseUrl . 'woopaypal=true&order_id=' . $order_id )
->setCancelUrl( $baseUrl . 'woopaypal=cancel&order_id=' . $order_id );
$payment = new Payment();
$payment->setIntent("sale")
->setPayer($payer)
->setRedirectUrls($redirectUrls)
->setTransactions(array($transaction));
try {
$payment->create($this->apiContext);
$approvalUrl = $payment->getApprovalLink();
return array(
'result' => 'success',
'redirect' => $approvalUrl
);
} catch (Exception $ex) {
wc_add_notice( $ex->getMessage(), 'error' );
}
return array(
'result' => 'failure',
'redirect' => ''
);
}
<?php
// ...
use PayPal\Rest\ApiContext;
use PayPal\Auth\OAuthTokenCredential;
use PayPal\Api\Amount;
use PayPal\Api\Details;
use PayPal\Api\ExecutePayment;
use PayPal\Api\Item;
use PayPal\Api\ItemList;
use PayPal\Api\Payer;
use PayPal\Api\Payment;
use PayPal\Api\PaymentExecution;
use PayPal\Api\RedirectUrls;
use PayPal\Api\Transaction;
<?php
/**
* Plugin Name: Custom WooCommerce PayPal Gateway
*/
<?php
// ...
define( 'WOO_PAYMENT_DIR', plugin_dir_path( __FILE__ ));
add_action( 'plugins_loaded', 'woo_payment_gateway' );
<?php
// ...
add_action( 'init', 'check_for_woopaypal' );
function check_for_woopaypal() {
if( isset($_GET['woopaypal'])) {
// Start the gateways
WC()->payment_gateways();
do_action( 'check_woopaypal' );
}
}
<?php
// ...
public function check_response() {
global $woocommerce;
if( isset( $_GET['woopaypal'] ) ) {
$woopaypal = $_GET['woopaypal'];
$order_id = $_GET['order_id'];
if( $order_id == 0 || $order_id == '' ) {
return;
}
$order = new WC_Order( $order_id );
if( $order->has_status('completed') || $order->has_status('processing')) {
return;
}
if( $woopaypal == 'true' ) {
$this->get_api_context();
$paymentId = $_GET['paymentId'];
$payment = Payment::get($paymentId, $this->apiContext);
$execution = new PaymentExecution();
$execution->setPayerId($_GET['PayerID']);
$transaction = new Transaction();
$amount = new Amount();
$details = new Details();
$subtotal = 0;
// Products
foreach ( $order->get_items( array( 'line_item', 'fee' ) ) as $item ) {
if ( 'fee' === $item['type'] ) {
$subtotal += $item['line_total'];
} else {
$subtotal += $order->get_item_subtotal( $item, false ) * $item['qty'];
}
}
$details->setShipping( $order->get_total_shipping() )
->setTax( $order->get_total_tax() )
->setSubtotal( $subtotal );
$amount = new Amount();
$amount->setCurrency( get_woocommerce_currency() )
->setTotal( $order->get_total() )
->setDetails($details);
$transaction->setAmount($amount);
$execution->addTransaction($transaction);
try {
$result = $payment->execute($execution, $this->apiContext);
} catch (Exception $ex) {
$data = json_decode( $ex->getData());
wc_add_notice( $ex->getMessage(), 'error' );
$order->update_status('failed', sprintf( __( '%s payment failed! Transaction ID: %d', 'woocommerce' ), $this->title, $paymentId ) . ' ' . $ex->getMessage() );
return;
}
// Payment complete
$order->payment_complete( $paymentId );
// Add order note
$order->add_order_note( sprintf( __( '%s payment approved! Trnsaction ID: %s', 'woocommerce' ), $this->title, $paymentId ) );
// Remove cart
$woocommerce->cart->empty_cart();
}
if( $woopaypal == 'cancel' ) {
$order = new WC_Order( $order_id );
$order->update_status('cancelled', sprintf( __( '%s payment cancelled! Transaction ID: %d', 'woocommerce' ), $this->title, $paymentId ) );
}
}
return;
}
@Amberkamran
Copy link

Can i creat my own custom payment gateway like paypal

@Amberkamran
Copy link

Will you plz help me

@mtvbrianking
Copy link

mtvbrianking commented Mar 12, 2023

@igorbenic do you happen to know why the gateway class is nested in a function?

function woo_payment_gateway() {
    class Woo_PayPal_Gateway extends WC_Payment_Gateway {}
}

@TheFedGuy
Copy link

@igorbenic do you happen to know why the gateway class is nested in a function?

function woo_payment_gateway() {
    class Woo_PayPal_Gateway extends WC_Payment_Gateway {}
}

because of this
add_action( 'plugins_loaded', 'woo_payment_gateway' );

@mtvbrianking
Copy link

Thanks @TheFedGuy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment