Skip to content

Instantly share code, notes, and snippets.

@wpmudev-sls
Last active April 23, 2019 09:57
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save wpmudev-sls/0bb76413634ebb25f8e76e10dff51e56 to your computer and use it in GitHub Desktop.
[Pro Sites] - Custom Gateway Skeleton. Basic Parts to set up a custom gateway for Pro Sites plugin.
<?php
/**
* Plugin Name: [Pro Sites] - Custom Gateway Skeleton
* Plugin URI: https://premium.wpmudev.org/
* Description: Basic Parts to set up a custom gateway for Pro Sites plugin
* Author: Panos Lyrakis @ WPMUDEV
* Author URI: https://premium.wpmudev.org/
* License: GPLv2 or later
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( ! class_exists( 'WPMUDEV_MS_Custom_Gateway_Skeleton' ) ) {
class WPMUDEV_MS_Custom_Gateway_Skeleton {
/**
* ID of the gateway.
*
* @var string
*
* @since Unknown
*/
private static $id = 'thrivecart';
private static $_instance = null;
// Some custom parameters specific to gateway
// These paramaters are for custom webhook
private static $webhook = 'ps-thrivecart-getway';
private static $webhook_tag = 'thrive-cart-webhook';
// This param is for linking to gateway
private static $gateway_url = 'https://thrivecart.com/';
private static $thrivecart_action = 'wpmudev_ps_thrivecart';
// This parameters are the ones set in settings() method.
// We use the same names as we used in the settings fields. No restriction though
private static $thrivecart_buttontext = null;
private static $thrivecart_thankyou = null;
public static function get_instance() {
if( is_null( self::$_instance ) ){
self::$_instance = new WPMUDEV_MS_Custom_Gateway_Skeleton();
}
return self::$_instance;
}
private function __construct() {
add_action( 'init', array( $this, 'setup' ) );
add_action( 'parse_request', array( $this, 'parse_request' ) );
add_action( self::$thrivecart_action, array( $this, 'webhook_handler' ) );
}
public function setup() {
global $psts;
self::$thrivecart_buttontext = $psts->get_setting( 'thrivecart_buttontext' );
self::$thrivecart_thankyou = $psts->get_setting( 'thrivecart_thankyou' );
if ( empty( self::$thrivecart_buttontext ) ) {
self::$thrivecart_buttontext = 'Checkout';
}
$this->add_rewrite_rules_tags();
$this->add_rewrite_rules();
$this->prepare_gateway_setting();
}
/**
* Get gateway's title name. Required in order to show up in active gateways dropdown in admin
*
* @since Unknown
*
* @return array
*/
public static function get_name() {
return array(
self::$id => __( 'Thrivecart', 'psts' ),
);
}
/**
* Render the gateway form in front end. Required by Pro Sites in order to display the gateway's checkout form in checkout page
*
* @param array $render_data Data for render.
* @param array $args Arguments for the form.
* @param int $blog_id Blog ID.
* @param string $domain Site domain.
*
* @since Unknown
*
* @return string
*/
public static function render_gateway( $render_data = array(), $args, $blog_id, $domain ) {
global $psts, $current_user;
// Set the default values.
$activation_key = $user_name = $new_blog = $customer = false;
$button_product_url = self::$gateway_url . 'product_url_here/';
$url_params = array();
// First we need to clear caches.
ProSites_Helper_Cache::refresh_cache();
// Set new/upgrading blog data to render data array.
foreach ( array( 'new_blog_details', 'upgraded_blog_details', 'activation_key' ) as $key ) {
$render_data[ $key ] = isset( $render_data[ $key ] ) ? $render_data[ $key ] : ProSites_Helper_Session::session( $key );
}
// New blog data.
$blog_data = empty( $render_data['new_blog_details'] ) ? array() : $render_data['new_blog_details'];
// Set period and levels.
$period = empty( $blog_data['period'] ) ? ProSites_Helper_ProSite::default_period() : (int) $blog_data['period'];
$level = empty( $blog_data['level'] ) ? 0 : (int) $blog_data['level'];
$level = empty( $render_data['upgraded_blog_details']['level'] ) ? $level : (int) $render_data['upgraded_blog_details']['level'];
// We need to get the email.
$email = self::get_email( $render_data );
// Current action.
$action = self::from_request( 'action', false, 'get' );
// Set a flag that it is new blog.
if ( ProSites_Helper_ProSite::allow_new_blog() && ( self::from_request( 'new_blog' ) || 'new_blog' === $action ) ) {
$new_blog = true;
}
// If blog id is found in url.
$bid = self::from_request( 'bid', $blog_id, 'get' );
// If blog id is found in url.
$bid = self::from_request( 'bid', $blog_id, 'get' );
// If blog id is found in url.
if ( ! empty( $bid ) ) {
// Blog exists so probably might need to get info from Gateway's API, eg for use info instead of :
if ( ! empty( $blog_data ) ) {
// Get the data.
$username = empty( $blog_data['username'] ) ? '' : $blog_data['username'];
$user_email = empty( $blog_data['email'] ) ? '' : $blog_data['email'];
$blogname = empty( $blog_data['blogname'] ) ? '' : $blog_data['blogname'];
$blog_title = empty( $blog_data['title'] ) ? '' : $blog_data['title'];
}
}
// This is a new blog.
if ( isset( $render_data['activation_key'] ) ) {
// Get the activation key.
$activation_key = $render_data['activation_key'];
// If new blog details is found.
if ( ! empty( $blog_data ) ) {
// Get the data.
$username = empty( $blog_data['username'] ) ? '' : $blog_data['username'];
$user_email = empty( $blog_data['email'] ) ? '' : $blog_data['email'];
$blogname = empty( $blog_data['blogname'] ) ? '' : $blog_data['blogname'];
$blog_title = empty( $blog_data['title'] ) ? '' : $blog_data['title'];
}
// Since this is a new blog, there is no blog_id as it is still in signups table. We need to use the activation key in button params.
$url_params['activation_key'] = $activation_key;
}
$url_params['username'] = $username;
$url_params['user_email'] = $user_email;
$url_params['blogname'] = $blogname;
$url_params['blog_title'] = $blog_title;
$button_product_url .= http_build_query( $url_params );
ob_start();
?>
<h3><?php esc_html_e( 'Checkout Using Thrivecard Checkout Expirience', 'psts' ); ?></h3>
<p><?php esc_attr_e( 'The world\'s easiest and most powerful cart platform', 'psts' ); ?></p>
<form action="<?php echo $button_product_url; ?>">
<input type="submit" value="<?php echo self::$thrivecart_buttontext; ?>" />
</form>
<?php
return ob_get_clean();
}
/**
* Handles the HTTP Request sent from Thrivecart to site's webhook
*
*
* @since Unknown
*
* @return bool
*/
public function webhook_handler() {
global $psts;
/*
* If we are here it means that we have some HTTP Request to the Webhook we have set in this site.
*
* Depending on the Request we can retrieve the input with $_POST or file_get_contents
*/
$input = $_POST;
// OR
// $input = @file_get_contents( 'php://input' );
// You might need to decode json:
// $json = json_decode( $input );
// The request from the getway should include information about site/blog, payment and user
// For site it should include the activation key, especially for first payment.
// If it is a subscription and this is a recurring payment it can contain the blog_id too
// For the site it should also contain the level id. From the level id we can get the level name with:
// $level_name = $psts->get_level_setting( {RETRIEVED ID}, 'name' );
// For payment it should contain :
// A transaction code. This can be stored in a custom table
// A transaction/event type. For insance it can be a notification for a subscription creation or update. Or it could be for a successfull or failed payment. Lets not forget about cancellations too.
// If the transaction type is a successfull payment for a new site ( new site could be when there is no blog_id in HTTP Request. It depends ),
// we need to activate that signup:
//$result = ProSites_Helper_Registration::activate_blog(
// {ACTIVATION KEY FROM HTTP REQUEST},
// {CHECK IF IS ON TRIAL},
// {PERIOD FROM REQUEST},
// {LEVEL FROM REQUEST},
// {EXPIRE TIMESTAMP - CALCULATE OR FROM REQUEST},
// {IF IT IS RECURRING : true OR false}
//);
// In case of a new or recurring payment, you will need to extend the Pro Site level for the blog. You can use the Pro Sites method `$psts->extend()`:
// $psts->extend(
//{BLOG ID},
//{PERIOD TIMESTAMP},
//{GATEWAY ID : self::$id},
//{LEVEL},
//{AMOUNT PAID},
//{EXPIRATION TIMESTAMP},
//{IS RECURRING _ true or false},
//{SEND A MANUAL NOTIFIACTION - set it to false},
//{TYPE OF EXTENSION, - manual or trial. You can leave it blank},
//{ON TRIAL - true or false}
//);
// Upon a Cancellation event we will need to cancel site's Pro Site level:
//$psts->withdraw( {BLOG ID} );
// You might need some custom option for that blog
//update_blog_option( {BLOG ID}, 'psts_thrivecart_canceled', 1 );
}
private function prepare_gateway_setting() {
//add_action( 'psts_gateway_settings', array( $this, 'settings' ) );
// For Gateway settings
// 1. Add gateway admin tab
add_filter( 'prosites_gateways_tabs', array( $this, 'settings_tab' ) );
// 2. Load the content for the Gateway Settings
add_action( 'psts_settings_page', array( $this, 'settings' ) );
// 2. Add the tab callback function. That callbck is the one that will fetch the settings content
//add_filter( 'prosites_settings_tabs_render_callback', array( $this, 'settings_tab_callback' ), 20, 2 );
}
public function settings_tab( $tabs ) {
$tabs[ self::$id ] = array(
'header_save_button' => true,
'button_name' => 'button_name',
'title' => 'Thrivecart',
'desc' => array( 'Use the Thrivecart checkout!' ),
'url' => "admin.php?page=psts-gateways&tab=" . self::$id
);
return $tabs;
}
public function settings_tab_callback( $render_callback, $active_tab ) {
if ( $active_tab == self::$id ) {
$render_callback = array( get_class(), 'settings' );
}
return $render_callback;
}
public function settings() {
global $psts;
ProSites_Helper_Settings::settings_header( ProSites_Helper_Tabs_Gateways::get_active_tab() );
$class_name = get_class();
$active_gateways = (array) $psts->get_setting('gateways_enabled');
$checked = in_array( $class_name, $active_gateways ) ? 'on' : 'off';
/**
* IMPORTANT !!
* You need at least one form element with name `psts[]`. Else settings won't be saved. Elemnts without `psts[]` name won't be set to PS settings
*/
?>
<div class="inside">
<p class="description">
Learn more about <a href="https://thrivecart.com/" target="_blank"><?php _e( 'Thrivecart here &raquo;', 'psts' ); ?></a>
</p>
<p>
<?php
printf(
__( 'To use Thrivecart you must enter this webook url <strong>%1$s</strong> in your Thrivecart account under <strong>Settings > API & Webhooks > Webhooks & notifications</strong>.', 'psts' ),
network_site_url( self::$webhook . DIRECTORY_SEPARATOR . self::$webhook_tag )
);
?>
</p>
<table class="form-table">
<tr>
<th scope="row"><?php _e( 'Enable Gateway', 'psts' ) ?></th>
<td>
<input type="hidden" name="gateway" value="<?php echo esc_attr( $class_name ); ?>" />
<input type="checkbox" name="gateway_active" value="1" <?php checked( $checked, 'on' ); ?> />
<input type="hidden" name="submit_gateways" />
</td>
</tr>
<tr valign="top">
<th scope="row" class="psts-help-div psts-thrivecart-thankyou"><?php echo esc_html__( 'Thank You Message', 'psts' ) . $psts->help_text( esc_html__( 'Displayed on successful checkout. HTML allowed', 'psts' ) ); ?></th>
<td>
<textarea name="psts[thrivecart_thankyou]" type="text" rows="4" wrap="soft" id="thrivecart_thankyou" style="width: 100%"><?php echo esc_textarea( stripslashes( $psts->get_setting( 'thrivecart_thankyou' ) ) ); ?></textarea>
</td>
</tr>
<tr valign="top">
<th scope="row" class="psts-help-div psts-thrivecart-buttontext"><?php echo esc_html__( 'Button text', 'psts' ) . $psts->help_text( esc_html__( 'The text on the buttons that will re-direct to Thrivecart checkout page', 'psts' ) ); ?></th>
<td>
<input type="text" name="psts[thrivecart_buttontext]" id="thrivecart_buttontext" value="<?php echo esc_textarea( stripslashes( $psts->get_setting( 'thrivecart_thankyou' ) ) ); ?>" />
</td>
</tr>
</table>
</div>
<?php
}
public function parse_request( &$wp ) {
if( array_key_exists( self::$webhook_tag, $wp->query_vars ) ) {
do_action( self::$thrivecart_action );
die(0);
}
}
protected function add_rewrite_rules_tags() {
add_rewrite_tag( '%' . self::$webhook_tag . '%', '([^&]+)' );
}
protected function add_rewrite_rules() {
//To use like http://site.com/ps-thrivecart-getway/payment-notification/
add_rewrite_rule( '^' . self::$webhook . '/([^/]*)/?', 'index.php?' . self::$webhook_tag . '=$matches[1]', 'top' );
}
// Helper functions taken from Stripe Gateway that ws created by Joel James ♥
/**
* Get a value from $_POST global.
*
* @param string $string String name.
* @param mixed $default Default value.
* @param string $type Type of request.
*
* @since Unknown
*
* @return mixed
*/
public static function from_request( $string, $default = false, $type = 'post' ) {
switch ( $type ) {
case 'post':
// Get data from post.
$value = isset( $_POST[ $string ] ) ? $_POST[ $string ] : false; // input var okay.
break;
case 'get':
$value = isset( $_GET[ $string ] ) ? $_GET[ $string ] : false; // input var okay.
break;
default:
$value = isset( $_REQUEST[ $string ] ) ? $_REQUEST[ $string ] : false; // input var okay.
}
// If empty return default value.
if ( ! empty( $value ) ) {
return $value;
}
return $default;
}
/**
* Get email for the current registration.
*
*
* @param array $process_data Process data.
*
* @since Unknown
*
* @return string|false
*/
private static function get_email( $process_data = array() ) {
global $current_user;
// First try to get the email.
$email = empty( $current_user->user_email ) ? false : $current_user->user_email;
// Email is empty so try to get user email.
if ( empty( $email ) ) {
// Let's try to get signup email.
$email = self::from_request( 'user_email' );
}
// Email is empty.
if ( empty( $email ) ) {
// Let's try to get signup email.
$email = self::from_request( 'signup_email' );
}
// Again email is empty.
if ( empty( $email ) ) {
// Let's try to get from blog email.
$email = self::from_request( 'blog_email' );
}
// In case if email is not set, try to get from process data.
if ( empty( $email ) && isset( $process_data['new_blog_details']['user_email'] ) ) {
$email = $process_data['new_blog_details']['user_email'];
}
return $email;
}
}
if ( ! function_exists( 'wpmudev_ms_custom_gateway_skeleton' ) ) {
function wpmudev_ms_custom_gateway_skeleton(){
return WPMUDEV_MS_Custom_Gateway_Skeleton::get_instance();
};
add_action( 'plugins_loaded', 'wpmudev_ms_custom_gateway_skeleton', 10 );
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment