Payment Gateways in Tickera are class based and can be added as a WordPress plugins. This guide provides an intro to the payment gateway development for Tickera event ticketing system.
Form based gateways post data off-site (to the payment gateways websites) like Mijireh, PayPal Standard, 2Checkout.com, etc meaning that you don't have to worry about the security much. Direct gateways however, in most cases, require implementation of some extra security layers, SSL certificates, tokenization, etc. and may also require a level of PCI compliance.
As in any other plugin, you should define plugin headers first:
<?php
/* Plugin Name: My payment gateway for Tickera
Plugin URI: https://tickera.com/
Description: Description of the payment gateway plugin
Author: Tickera.com
Author URI: https://tickera.com/
Version: 1.0
TextDomain: tc-gateway-text-domain
Domain Path: /languages/ Copyright 2021 Tickera (https://tickera.com/)
*/
Payment gateways should be created as additional plugins that hook into Tickera. Within the plugin you should create your class after Tickera payment gateways are loaded. For example:
add_action( 'tc_load_gateway_plugins', 'register_my_payment_gateway' );
It is important that your gateway extends Tickera's base gateway class
function register_my_payment_gateway() {
class TC_My_Gateway extends TC_Gateway_API {
//Gateway variables and methods here
}
tc_register_gateway_plugin( 'TC_My_Gateway', 'my-gateway', __( 'My Gateway', 'tc-gateway-text-domain' ) ); //Call this function in order to register payment gateway, without this, payment gateway won't be created
}
Most methods are inherited from the TC_Gateway_API class, however, some are required in your custom gateway.
Within your init method (which is like constructor), you should define following variables:
$this->plugin_name = 'my-gateway'; //Unique payment gateway plugin name
$this->admin_name = 'My Gateway';//Title of the plugin shown within the admin area
$this->public_name = 'My Gateway';//Title of the gateway shown on the front-end part of the site
$this->method_img_url = plugin_dir_url( __FILE__ ) . 'assets/images/my-gateway-image-front-end.png';//URL of the image shown on the front-end
$this->admin_img_url = plugin_dir_url( __FILE__ ) . 'assets/images/my-gateway-image-admin.png';//URL of the image shown within the wp-admin
$this->skip_payment_screen = false; // whether to skip payment screen or not, you can set it to true if payment screen is not needed like for FREE Orders, forms with only hidden fields etc
You should also define here other variables needed by gateway like supported currencies, API access keys etc
$this->access_key = $this->get_option( 'access_key' );//access key set in the admin - check gateway_admin_settings method
$this->currencies = array(
'EUR' => __( 'EUR - Euro', 'tc-gateway-text-domain' ),
'AUD' => __( 'AUD - Australian Dollar', 'tc-gateway-text-domain' ),
'USD' => __( 'USD - U.S. Dollar', 'tc-gateway-text-domain' )
);
$this->currency = $this->get_option( 'currency', 'USD' ); //Get currency set in the admin - check gateway_admin_settings method
$this->mode = $this->get_option( 'mode', 'sandbox' );
You can add HTML form here for direct payment gateway types
function payment_form( $cart ) {
$buyer_full_name = $this->buyer_info( 'full_name' );
$content = '';
$content .= '<table class="cart_billing">
<thead><tr>
<th colspan="2">' . __( 'Enter Your Credit Card Information:', 'tc-gateway-text-domain' ) . '</th>
</tr></thead>
<tbody>
<tr>
<td align="right">' . __( 'Cardholder Name:', 'tc-gateway-text-domain' ) . '</td><td>
<input id="tcbs_cc_name" name="' . $this->plugin_name . '_cc_name" type="text" value="' . esc_attr( $buyer_full_name ) . '" /> </td>
</tr>';
$content .= '<tr>';
$content .= '<td align="right">';
$content .= __( 'Card Number', 'tc-gateway-text-domain' );
$content .= '</td>'; $content .= '<td>';
$content .= '<input type="text" autocomplete="off" name="' . $this->plugin_name . '_cc_number" id="' . $this->plugin_name . '_cc_number"/>';
$content .= '</td>';
$content .= '</tr>';
$content .= '<tr>';
$content .= '<td align="right">';
$content .= __( 'Expiration:', 'tc-gateway-text-domain' );
$content .= '</td>';
$content .= '<td>';
$content .= '<select id="' . $this->plugin_name . '_cc_month" name="' . $this->plugin_name . '_cc_month">';
$content .= tc_months_dropdown();//helper function to list months as a select box
$content .= '</select>';
$content .= '<span> / </span>';
$content .= '<select id="' . $this->plugin_name . '_cc_year" name="' . $this->plugin_name . '_cc_year">';
$content .= tc_years_dropdown( '', false );//helper function to list years as a select box
$content .= '</select>';
$content .= '</td>';
$content .= '</tr>';
$content .= '<tr>';
$content .= '<td align="right">';
$content .= __( 'CVC:', 'tc-gateway-text-domain' );
$content .= '</td>';
$content .= '<td>';
$content .= '<input id="' . $this->plugin_name . '_cc_cvc" name="' . $this->plugin_name . '_cc_cvc" type="text" maxlength="4" autocomplete="off" value=""/>';
$content .= '</td>';
$content .= '</tr>';
$content .= '</table>';
return $content;
}
or use it, for instance, to process canceled order messages, etc.
function payment_form( $cart ) {
global $tc;
if ( isset( $_GET[ 'cancel' ] ) ) {
$this->add_error( 'Your transaction has been cancelled' );//Set the error message
wp_redirect( $tc->get_payment_slug( true ) );//redirect to the payment page
exit;
}
}
In this method, you should process payment (for direct payment gateways)
function process_payment( $cart ) {
global $tc;
$this->maybe_start_session(); //required to start session if it's not already started
$this->save_cart_info(); //save cart information to the session
$order_id = $tc->generate_order_id(); //generate unique order number
$total = $this->total(); //get cart total
//submit data to the payment gateway and create an order
$payment_info = array(
'gateway_public_name' => $this->public_name,
'gateway_private_name' => $this->admin_name,
'total' => $total,
'currency' => $this->currency,
'method' => __( 'Credit Card', 'tc-gateway-text-domain' ),
);
$payment_info = $this->save_payment_info();//save payment info
$paid = true; //set whether the order is paid or not based on the response from a payment gateway server
$order = $tc->create_order( $order_id, $this->cart_contents(), $this->cart_info(), $payment_info, $paid );//create order and save all the data
wp_redirect( $tc->get_confirmation_slug( true, $order_id ) ); //redirect user to the payment confirmation page
exit;
}
or generate form fields and post it to payment gateway, example from 2checkout.com payment gateway:
function process_payment( $cart ) {
global $tc;
$this->maybe_start_session();
$this->save_cart_info();
$order_id = $tc->generate_order_id();
$params = array();
$params[ 'total' ] = $this->total();
$params[ 'sid' ] = $this->API_Username;
$params[ 'cart_order_id' ] = $order_id;
$params[ 'merchant_order_id' ] = $order_id; $params[ 'return_url' ] = $tc->get_confirmation_slug( true, $order_id );
$params[ 'x_receipt_link_url' ] = $this->ipn_url; //url where IPN messages will be sent after purchase, then validate in the ipn() method
$params[ 'skip_landing' ] = '1';
$params[ 'fixed' ] = 'Y';
$params[ 'currency_code' ] = $this->currency;
$params[ 'mode' ] = '2CO';
$params[ 'card_holder_name' ] = $this->buyer_info( 'full_name' );
$params[ 'email' ] = $this->buyer_info( 'email' );
if ( $this->mode == 'sandbox' ) {
$params[ 'demo' ] = 'Y';
}
$params[ "li_0_type" ] = "product";
$params[ "li_0_name" ] = apply_filters( 'tc_item_name_2checkout', __( 'Order: #', 'tc-gateway-text-domain' ) . $order_id );
$params[ "li_0_price" ] = $this->total();
$params[ "li_0_tangible" ] = 'N';
$param_list = array();
foreach ( $params as $k => $v ) {
$param_list[] = "{$k}=" . rawurlencode( $v );
}
$param_str = implode( '&', $param_list );
$paid = false; //make an pending order first then confirm it when server receives IPN message from 2checkout.com after payment completion
$payment_info = $this->save_payment_info(); //save payment info to the session
$tc->create_order( $order_id, $this->cart_contents(), $this->cart_info(), $payment_info, $paid ); //create order and save all the required info for the order
wp_redirect( "{$url}?{$param_str}" ); //redirect to the 2checkout.com page
exit;
}
This method executes after payment process ends. You can usually omit this method for the direct payment gateways since whole the logic, payment process and confirmation is already done in the process_payment method. You will use it most likely in all form based payment gateways to confirm whether the payment is completed or not. Bear in mind that you'll need to post to payment gateway website a return URL which should be $tc->get_confirmation_slug( true, $order_id ). You can see that parameter in the previous example for the 2checkout.com payment_process method.
function order_confirmation( $order, $payment_info = '', $cart_info = '' ) {
global $tc;
//Check here if order is paid, totals match, etc and change order status
$paid = true;
$order = tc_get_order_id_by_name( $order );
$tc->update_order_payment_status( $order->ID, true ); //change order status to paid
//OR
//Mark order as fraud if totals don't match
//$tc->update_order_status( $order->ID, 'order_fraud' ); }
This method triggers when a payment gateway server posts a message to Tickera store about payment statuses. You'll use it most likely only with form-based payment gateways if they have option for setting IPN / Webhook URL on the fly. If so, you should just pass $this->ipn_url, which is a URL automatically created by the base class internal method _generate_ipn_url(), then intercept the message and change the status of the order for instance. Example:
function ipn() {
global $tc;
$ipn_order_id = $_REQUEST[ 'order_id_received_from_payment_gateway_server' ]; //$_GET / $_POST variable received from payment gateway server
$order_id = tc_get_order_id_by_name( $ipn_order_id ); //get order id from order title / name received from server
$order = new TC_Order( $order_id ); $tc->update_order_payment_status( $order_id, true );
}
You can add admin fields required for a payment gateway with this method, example:
function gateway_admin_settings( $settings, $visible ) {
global $tc; ?>
<div id="<?php echo $this->plugin_name; ?>" class="postbox" <?php echo (!$visible ? 'style="display:none;"' : ''); ?>>
<h3 class='handle'><span><?php printf( __( '%s Settings', 'tc-gateway-text-domain' ), $this->admin_name ); ?></span></h3>
<div class="inside">
<span class="description">
<?php _e( 'Sell your tickets via' , 'tc-gateway-text-domain' ); ?>
</span>
<?php
$fields = array(
'mode' => array(
'title' => __( 'Mode', 'tc-gateway-text-domain' ),
'type' => 'select',
'options' => array(
'sandbox' => __( 'Sandbox / Test', 'tc-gateway-text-domain' ),
'live' => __( 'Live', 'tc-gateway-text-domain' )
),
'default' => 'sandbox',
),
'api_key' => array(
'title' => __( 'API Key', 'tc-gateway-text-domain' ),
'type' => 'text',
'description' => __('Description for this field', 'tc-gateway-text-domain'),
'default' => 'Some default value here'
),
'currency' => array(
'title' => __( 'Currency', 'tc-gateway-text-domain' ),
'type' => 'select',
'options' => $this->currencies,
'default' => 'USD',
),
);
$form = new TC_Form_Fields_API( $fields, 'tc-gateway-text-domain', 'gateways' );
?>
<table class="form-table">
<?php $form->admin_options(); ?>
</table>
</div>
</div>
<?php }
This method is used to retrieve all the currencies from Tickera system, for example:
echo $this->get_global_currencies();
This method adds an error message and redirects user to the payment page, example:
$this->add_error('Some gateway error message here');
Retrieves whether current page is payment page or not. It's useful when you want to enqueue_script on that particular page for instance. For example:
if($this->is_payment_page()){
//do something
}
This method determines if the current payment gateway is active or not. Example:
if($this->is_active()){
echo 'The gateway is active!';
}
This method returns cart total value
echo $this->total();
This method returns cart subtotal value
echo $this->subtotal();
This method returns cart total fees value
echo $this->total_fees();
This method returns cart total taxes value
echo $this->total_taxes();
This method returns part of the buyer info. Possible $part values: full_name, first_name, last_name, email. Example:
echo $this->buyer_info('full_name');
This method returns value of the payment gateway option. Example:
$currency_array = $this->get_option( 'currency', 'USD' );