Last active
February 21, 2024 21:32
-
-
Save igorbenic/9d555cd278c128deee0f43a56eba14da to your computer and use it in GitHub Desktop.
How to create a custom WooCommerce Payment Gateway
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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' ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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' ) ); | |
} | |
} | |
} | |
} | |
// ... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// ... | |
private function get_paypal_sdk() { | |
require_once WOO_PAYMENT_DIR . 'includes/paypal-sdk/autoload.php'; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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' => '' | |
), | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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 | |
)); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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' => '' | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Plugin Name: Custom WooCommerce PayPal Gateway | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// ... | |
define( 'WOO_PAYMENT_DIR', plugin_dir_path( __FILE__ )); | |
add_action( 'plugins_loaded', 'woo_payment_gateway' ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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' ); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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; | |
} |
@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' );
Thanks @TheFedGuy
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@igorbenic do you happen to know why the gateway class is nested in a function?