Skip to content

Instantly share code, notes, and snippets.

@Preciousomonze
Last active May 2, 2019 21:08
Show Gist options
  • Save Preciousomonze/65fdfdc2bb5a5546db035130da1ab893 to your computer and use it in GitHub Desktop.
Save Preciousomonze/65fdfdc2bb5a5546db035130da1ab893 to your computer and use it in GitHub Desktop.
Pro Sites ThriveCart Gateway
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( ! class_exists( 'PK_Prosites_Thrivecart_Gateway' ) ) {
class PK_Prosites_Thrivecart_Gateway {
/**
* ID of the gateway.
*
* @var string
*
* @since Unknown
*/
private static $id = 'thrivecart';
private static $_instance = null;
/**
* separator for thrivecart fields
*
* @var string
*/
private static $field_sep = '||';
// 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://wgears.thrivecart.com/';
private static $thrive_account = 'wgears';
private static $thrive_secret_key = 'VJ7ZDVVQ49R9';
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 PK_Prosites_Thrivecart_Gateway();
}
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.'blog-plan/';
//annoyingly,thrivecart only allows 4 custom fields, so we have to join some data together
$url_params = array(
'blog_id_username'=>'',
'blog_name_title'=>'',
'blog_period_level'=>'',
'blog_activation_key'=>''
);
// 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.
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'];
}
$url_params['blog_id_username'] = $bid;
}
// 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['blog_activation_key'] = $activation_key;
}
//annoyingly,thrivecart only allows 4 custom fields, so we have to join some data together
$sep = self::$field_sep;
$url_params['blog_id_username'] .= $sep.$username;
$url_params['user_email'] = $user_email;//part of thrivecart required field
$url_params['blog_name_title'] = $blogname.$sep.$blog_title;
$url_params['blog_period_level'] = $period.$sep.$level;
//do some custom thrivecart url transform.
//Note: these custom fields should have been created in your thrivecart product
$thrive_params = self::get_thrive_url_param($url_params,true);
//$button_product_url .= '?'.str_replace('&amp;','&',urldecode(http_build_query( $thrive_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; ?>" method="get">
<?php echo $thrive_params; ?>
<input type="submit" value="<?php echo self::$thrivecart_buttontext; ?>" />
</form>
<?php
return ob_get_clean();
}
/**
* Converts the url params to fit thrivecarts url param
*
* @param array $url_params
* @param bool $html_input_display(optional) | if true, will return html input types
* @return mixed
*/
private static function get_thrive_url_param($url_params,$html_input_display = true){
$result = array();
$final_result = '';
foreach($url_params as $key => $value){
if(strpos($key,'email') !== false){
$result['passthrough[customer_email]'] = $value;
continue;
}
$filtered_key = str_replace('_','',$key);
$result['passthrough[custom_'.$filtered_key.']'] = !empty($value) ? $value : '.';//to prevent empty values
}
if($html_input_display){
foreach($result as $key=>$value){
$final_result .= '<input type="hidden" name="'.$key.'" value="'.$value.'">';
}
//set a jquery for period selector, noticed it doesnt update on its own
//first get the key value so we can split and join back properly
$sep = self::$field_sep;
$period_level_key ='passthrough[custom_blogperiodlevel]';
$period__level = explode($sep,$result[$period_level_key]);
$final_result .= '<script type="text/javascript">
var $=jQuery;
$(".period-selector select.chosen").change(function(){
let theVal = $(this).val().split("_")[1];
$("input[name=\''.$period_level_key.'\']").val(theVal+"'.$sep.$period__level[1].'");
});
</script>';
}
else{
$final_result = $result;
}
return $final_result;
}
/**
* 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;
if(!$this->is_auth_thrivecart_account($input))
return false;
if($input['event'] != 'order.success')//order wasnt successful
return false;
//convert the data to array
$input = $this->thrive_data_json_convert($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( $level, 'name' );
/*$url_params = array(
'blog_id_username'=>'',
'blog_name_title'=>'',
'blog_period_level'=>'',
'blog_activation_key'=>''
);*/
$sep = self::$field_sep;
$period__level = explode($sep,$this->get_thrivecart_custom_key_val('blog_period_level',$input) );
$period = $period__level[0];
$level = $period__level[1];
$period_timestamp = strtotime('+'.$period.' months');
$exp_timestamp = strtotime('+'.$period.' months');
$level_name = $psts->get_level_setting( $level, 'name' );
//default values, for now
$on_trial = true;
$recurring = false;
// 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 = false;
if($this->is_new_blog_sub($input)){//its a new blog subscription
$activation_key = $this->get_thrivecart_custom_key_val('blog_activation_key',$input);
$result = ProSites_Helper_Registration::activate_blog($activation_key,$on_trial,$period,$level,$exp_timestamp,$recurring);
//$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}
//);
}
else{
// 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()`:
$blog_id = explode($sep,$this->get_thrivecart_custom_key_val('blog_id_username',$input))[0];
$amount = $input['order']['total_str'];
var_dump($level_name);
$result = $psts->extend($blog_id,$period_timestamp,self::$id,$level,$amount,$exp_timestamp,$recurring,false,'',$on_trial);
// $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 );
//var_dump($result);
return $result;
}
/**
* Checks if it's a new blog or a recurring payment
*
* @param array $input | the json_decoded post data from thrivecart
* @return bool
*/
private function is_new_blog_sub($input){
var_dump($input);
$act_key = isset($input['customer']['custom_fields'][$this->filter_thrive_custom_key('blog_activation_key')]) ? trim($input['customer']['custom_fields'][$this->filter_thrive_custom_key('blog_activation_key')]) : '';
$blog_head = isset($input['customer']['custom_fields'][$this->filter_thrive_custom_key('blog_id_username')]) ? explode(self::$field_sep,$input['customer']['custom_fields'][$this->filter_thrive_custom_key('blogidusername')]) : '';
$id = trim($blog_head[0]);
if(empty($id) && (!empty($act_key) || $act_key == '.' ) )
return true;
return false;
}
/**
* Converts the json data to array
*
* @param array $input | the post data from thrivecart
* @param bool $to_array(optional) | if to convert the json to array or not
* @return array
*/
private function thrive_data_json_convert($input,$to_array = true){
$result = array();
foreach($input as $key => $value){
$val_a = json_decode($value, $to_array);
$val = is_array($val_a) && (json_last_error() == JSON_ERROR_NONE) ? $val_a : $value;
$result[$key] = $val;
}
return $result;
}
/**
* Gets value of custom fields from thrivecart
*
* @param string $key | a valid key from the webhook
* @param array $input | the json_decoded post data from thrivecart
* @return mixed|bool
*/
private function get_thrivecart_custom_key_val($key,$input){
$key = str_replace('_','',$key);
$val = isset($input['customer']['custom_fields'][$key]) ? $input['customer']['custom_fields'][$key] : false;
return $val;
}
/**
* Filters for thrive custom key
*
* @param $key
* @return string
*/
private function filter_thrive_custom_key($key){
return str_replace('_','',$key);
}
/**
* Check if its from authentic thrive account
*
* this should be run first before accepting any other data in the webhook
*
* @param array $input | the post data from thrivecart
* @return bool
*/
private function is_auth_thrivecart_account($input){
$account = isset($input['thrivecart_account']) ? $input['thrivecart_account'] : '';
$secret = isset($input['thrivecart_secret']) ? $input['thrivecart_secret'] : '';
if(self::$thrive_account == $account && self::$thrive_secret_key == $secret)
return true;
return false;
}
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( 'PK_Prosites_Thrivecart_Gateway' ) ) {
function pk_prosites_thrivecart_gateway(){
return PK_Prosites_Thrivecart_Gateway::get_instance();
}
add_action( 'plugins_loaded', 'pk_prosites_thrivecart_gateway', 10 );
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment