GFPaystationPlugin

The Gravity Forms Paystation (3 party hosted) GFPaystationPlugin class.

Defined (1)

The class is defined in the following location(s).

/class.GFPaystationPlugin.php  
  1. class GFPaystationPlugin { 
  2.  
  3. public $urlBase; // String: base URL path to files in plugin 
  4. public $options; // Array of plugin options 
  5.  
  6. private $validationMessage = ''; // The validation message. 
  7. private $feed = null; // Current feed mapping form fields to payment fields. 
  8. private $formData = null; // Current form data collected from form. 
  9.  
  10. // ==================================================================================================================================== 
  11. /** 
  12. * Static method for getting the instance of this singleton object 
  13. * @return GFPaystationPlugin 
  14. */ 
  15. // ==================================================================================================================================== 
  16. public static function getInstance() { 
  17. static $instance = null; 
  18.  
  19. if (is_null($instance)) { 
  20. $instance = new self(); 
  21.  
  22. return $instance; 
  23.  
  24. // ==================================================================================================================================== 
  25. /** 
  26. * Constructor 
  27. */ 
  28. // ==================================================================================================================================== 
  29. private function __construct() { 
  30.  
  31. // Grab options, setting new defaults for any that are missing 
  32. $this->initOptions(); 
  33.  
  34. // Record plugin URL base 
  35. $this->urlBase = plugin_dir_url(__FILE__); 
  36.  
  37. add_action('init', array($this, 'init')); 
  38. add_action('parse_request', array($this, 'processPaystationReturn')); // Process paystation return 
  39. add_action('wp', array($this, 'processFormConfirmation'), 5); // Process redirect to GF confirmation 
  40.  
  41. // ==================================================================================================================================== 
  42. /** 
  43. * initialise plug-in options, handling undefined options by setting defaults 
  44. */ 
  45. // ==================================================================================================================================== 
  46. private function initOptions() { 
  47.  
  48. static $defaults = array ( 
  49. 'paystationId' => '',  
  50. 'gatewayId' => '',  
  51. 'testMode' => 'Y', // Set test mode to Yes by default. It will be set to No when a payment is made if test mode if off in the settings. 
  52. 'securityHash' => '',  
  53. 'sslVerifyPeer' => true,  
  54. ); 
  55.  
  56. $this->options = (array) get_option(GFPAYSTATION_PLUGIN_OPTIONS); 
  57.  
  58. if (count(array_diff_assoc($defaults, $this->options)) > 0) { 
  59. $this->options = array_merge($defaults, $this->options); 
  60. update_option(GFPAYSTATION_PLUGIN_OPTIONS, $this->options); 
  61.  
  62. // ==================================================================================================================================== 
  63. /** 
  64. * handle the plugin's init action 
  65. */ 
  66. // ==================================================================================================================================== 
  67. public function init() { 
  68. // Hook into Gravity Forms and specify the functions which are to be called when these hooks are triggered. 
  69. add_filter('gform_validation', array($this, "gformValidation")); 
  70. add_filter('gform_validation_message', array($this, "gformValidationMessage"), 10, 2); 
  71. add_filter('gform_confirmation', array($this, "gformConfirmation"), 1000, 4); 
  72. add_filter('gform_disable_post_creation', array($this, 'gformDelayPost'), 10, 3); 
  73.  
  74. // The first two will not work from version 1.7, the third will work for all versions as has code in there to check the version number. 
  75. add_filter('gform_disable_user_notification', array($this, 'gformDelayUserNotification'), 10, 3); 
  76. add_filter('gform_disable_admin_notification', array($this, 'gformDelayAdminNotification'), 10, 3); 
  77. add_filter('gform_disable_notification', array($this, 'gformDelayNotification'), 10, 4); 
  78.  
  79. add_filter('gform_custom_merge_tags', array($this, 'gformCustomMergeTags'), 10, 4); 
  80. add_filter('gform_replace_merge_tags', array($this, 'gformReplaceMergeTags'), 10, 7); 
  81.  
  82. // Register custom post types. 
  83. $this->registerTypeFeed(); 
  84.  
  85. if (is_admin()) { 
  86. // kick off the admin handling 
  87. new GFPaystationAdmin($this); 
  88.  
  89. // ==================================================================================================================================== 
  90. /** 
  91. * register custom post type for Paystation form field mappings 
  92. */ 
  93. // ==================================================================================================================================== 
  94. protected function registerTypeFeed() { 
  95. // register the post type 
  96. register_post_type(GFPAYSTATION_TYPE_FEED, array( 
  97. 'labels' => array ( 
  98. 'name' => __( 'Gravity Forms Paystation (3 party hosted) Feeds' ),  
  99. 'singular_name' => __( 'Gravity Forms Paystation (3 party hosted) Feed' ),  
  100. 'add_new_item' => __( 'Add New Gravity Forms Paystation (3 party hosted) Feed' ),  
  101. 'edit_item' => __( 'Edit Gravity Forms Paystation (3 party hosted) Feed' ),  
  102. 'new_item' => __( 'New Gravity Forms Paystation (3 party hosted) Feed' ),  
  103. 'view_item' => __( 'View Gravity Forms Paystation (3 party hosted) Feed' ),  
  104. 'search_items' => __( 'Search Gravity Forms Paystation (3 party hosted) Feeds' ),  
  105. 'not_found' => __( 'No Gravity Forms Paystation (3 party hosted) feeds found' ),  
  106. 'not_found_in_trash' => __( 'No Gravity Forms Paystation (3 party hosted) feeds found in Trash' ),  
  107. 'parent_item_colon' => __( 'Parent Gravity Forms Paystation (3 party hosted) feed' ),  
  108. ),  
  109. 'description' => 'Paystation Feeds, as a custom post type',  
  110. 'public' => false,  
  111. 'show_ui' => true,  
  112. 'show_in_menu' => false,  
  113. 'hierarchical' => false,  
  114. 'has_archive' => false,  
  115. 'supports' => array('null'),  
  116. 'rewrite' => false,  
  117. )); 
  118.  
  119. // ==================================================================================================================================== 
  120. /** 
  121. * filter whether post creation from form is enabled (yet) 
  122. * @param bool $is_disabled 
  123. * @param array $form 
  124. * @param array $lead 
  125. * @return bool 
  126. */ 
  127. // ==================================================================================================================================== 
  128. public function gformDelayPost($is_disabled, $form, $lead) { 
  129.  
  130. $feed = $this->getFeed($form['id']); 
  131.  
  132. if ($feed && $feed->DelayPost) { 
  133. $is_disabled = true; 
  134.  
  135. return $is_disabled; 
  136.  
  137. // ====================================================================================================================================  
  138. /** 
  139. * Filter whether form triggers autoresponder (yet) 
  140. * @param bool $is_disabled 
  141. * @param array $form 
  142. * @param array $lead 
  143. * @return bool 
  144. */ 
  145. // ====================================================================================================================================  
  146. public function gformDelayUserNotification($is_disabled, $form, $lead) { 
  147.  
  148. $feed = $this->getFeed($form['id']); 
  149.  
  150. if ($feed && $feed->DelayAutorespond) { 
  151. $is_disabled = true; 
  152.  
  153. return $is_disabled; 
  154.  
  155. // ====================================================================================================================================  
  156. /** 
  157. * Filter whether form triggers admin notification (yet) 
  158. * @param bool $is_disabled 
  159. * @param array $form 
  160. * @param array $lead 
  161. * @return bool 
  162. */ 
  163. // ====================================================================================================================================  
  164. public function gformDelayAdminNotification($is_disabled, $form, $lead) { 
  165.  
  166. $feed = $this->getFeed($form['id']); 
  167.  
  168. if ($feed && $feed->DelayNotify) { 
  169. $is_disabled = true; 
  170.  
  171. return $is_disabled; 
  172.  
  173. // ====================================================================================================================================  
  174. /** 
  175. * filter whether form triggers admin notification (yet) 
  176. * @param bool $is_disabled 
  177. * @param array $notification 
  178. * @param array $form 
  179. * @param array $lead 
  180. * @return bool 
  181. */ 
  182. // ====================================================================================================================================  
  183. public function gformDelayNotification($is_disabled, $notification, $form, $lead) { 
  184.  
  185. $feed = $this->getFeed($form['id']); 
  186.  
  187. if ($feed) { 
  188. switch (rgar($notification, 'type')) { 
  189. // old "user" notification 
  190. case 'user': 
  191. if ($feed->DelayAutorespond) { 
  192. $is_disabled = true; 
  193. break; 
  194.  
  195. // old "admin" notification 
  196. case 'admin': 
  197. if ($feed->DelayNotify) { 
  198. $is_disabled = true; 
  199. break; 
  200.  
  201. // new since 1.7, add any notification you like 
  202. default: 
  203. if (trim($notification['to']) == '{admin_email}') { 
  204. if ($feed->DelayNotify) { 
  205. $is_disabled = true; 
  206. else { 
  207. if ($feed->DelayAutorespond) { 
  208. $is_disabled = true; 
  209. break; 
  210.  
  211. return $is_disabled; 
  212.  
  213.  
  214. // ==================================================================================================================================== 
  215. /** 
  216. * process a form validation filter hook; if can find a total, attempt to bill it 
  217. * @param array $data an array with elements is_valid (boolean) and form (array of form elements) 
  218. * @return array 
  219. */ 
  220. // ==================================================================================================================================== 
  221. public function gformValidation($data) { 
  222.  
  223. // Make sure all other validations passed. 
  224. if ($data['is_valid']) { 
  225.  
  226. $feed = $this->getFeed($data['form']['id']); 
  227.  
  228. if ($feed) { 
  229. $formData = $this->getFormData($data['form']); 
  230.  
  231. // Make sure form hasn't already been submitted / processed. 
  232. if ($this->hasFormBeenProcessed($data['form'])) { 
  233. $data['is_valid'] = false; 
  234. $this->validationMessage .= "Payment already submitted and processed - please close your browser window.\n"; 
  235.  
  236. // Make sure that we have something to bill. 
  237. if (!$formData->hasPurchaseFields()) { 
  238. $data['is_valid'] = false; 
  239. $this->validationMessage .= "This form has no products or totals; unable to process transaction.\n"; 
  240.  
  241. return $data; 
  242.  
  243. // ==================================================================================================================================== 
  244. /** 
  245. * Alter the validation message to one that we want, wrap it in a div with a validation error message. 
  246. * @param string $msg 
  247. * @param array $form 
  248. * @return string 
  249. */ 
  250. // ==================================================================================================================================== 
  251. public function gformValidationMessage($msg, $form) { 
  252.  
  253. if ($this->validationMessage) { 
  254. $msg = "<div class='validation_error'>" . nl2br($this->validationMessage) . "</div>"; 
  255.  
  256. return $msg; 
  257.  
  258. // ==================================================================================================================================== 
  259. /** 
  260. * This function handles the form confirmation by first trying to make the payment using paystation, then either returning the url 
  261. * to redirect the user's browser to so they see the payment screen, or the error message is returned. 
  262. * @param mixed $confirmation text or redirect for form submission 
  263. * @param array $form the form submission data 
  264. * @param array $entry the form entry 
  265. * @param bool $ajax form submission via AJAX 
  266. * @return mixed 
  267. */ 
  268. // ==================================================================================================================================== 
  269. public function gformConfirmation($confirmation, $form, $entry, $ajax) { 
  270.  
  271. // Return if not the current form. 
  272. if (RGForms::post('gform_submit') != $form['id']) { 
  273. return $confirmation; 
  274.  
  275. // Get feed mapping form fields to payment request, return if not set as need the feed to actually do anything. 
  276. $feed = $this->getFeed($form['id']); 
  277. if (!$feed) { 
  278. return $confirmation; 
  279.  
  280. // -------------------------------------- 
  281. // Record payment gateway. 
  282. gform_update_meta($entry['id'], 'payment_gateway', 'gfpaystation'); 
  283.  
  284. // -------------------------------------- 
  285. // Get the data posted from the form and build the payment request by creating a Paystation payment request object,  
  286. // setting it's properties, then calling the processPayment() method. 
  287. $formData = $this->getFormData($form); 
  288. $paymentReq = null; 
  289.  
  290. // If a paystation override id has been specified on the form from dropdown to override etc then create new payment object with that Paystation id 
  291. // Otherwise default to the normal paystation_id in the main settings. This feature allows money to be paid in to different paystation accounts 
  292. // based on user selection of something on the form such as branch, region, country etc. 
  293. if ((isset($formData->PaystationOverrideId)) && ($formData->PaystationOverrideId)) 
  294. $paymentReq = new GFPaystationPayment($formData->PaystationOverrideId, $this->options['gatewayId'], $this->options['testMode'], $this->securityHash); 
  295. else 
  296. $paymentReq = new GFPaystationPayment($this->options['paystationId'], $this->options['gatewayId'], $this->options['testMode'], $this->securityHash); 
  297.  
  298. $paymentReq->amount = (int) ($formData->total * 100); // We multiply by 100 because the amount sent to the gateawy must be an int, so cents not a float. 
  299. $paymentReq->currency = GFCommon::get_currency(); // Get the currency from gravity forms. 
  300. $paymentReq->merchantSession = $this->buildSessionId($entry['id']); // Call function in this class to create the merchantSession id. 
  301. $paymentReq->merchantReference = $formData->MerchantReference; // Set other things. 
  302. $paymentReq->customerDetails = $formData->CustomerDetails; 
  303. $paymentReq->orderDetails = $formData->OrderDetails; 
  304.  
  305. // -------------------------------------- 
  306. // Try making the payment, if successful the redirect the user to the payment URL, if not then catch error. 
  307. try { 
  308. $response = $paymentReq->processPayment(); // Call processPayment function in PaystationPayment class, it will do the POST to the paystation gateway. 
  309.  
  310. // If digitalOrder is populated then there were no issues with the transaction request, so update the status of the 
  311. // the lead record and then set the confirmation to the url of the payment screen. 
  312. if ($response->digitalOrder) {  
  313. GFFormsModel::update_lead_property($entry['id'], 'payment_status', 'Processing'); 
  314. GFFormsModel::update_lead_property($entry['id'], 'transaction_id', $response->transactionId); 
  315.  
  316. // NB: GF handles redirect via JavaScript if headers already sent, or AJAX. 
  317. $confirmation = array('redirect' => $response->digitalOrder); 
  318. else { 
  319. // There was an error with the payment initiation, an error message will be set so 
  320. // throw it so that the exception code below will update the status to failed 
  321. // and cause the user to see the error emssage. 
  322. throw new GFPaystationException($response->errorMessage); 
  323.  
  324. catch (GFPaystationException $e) { 
  325. // Update the status to failed. 
  326. GFFormsModel::update_lead_property($entry['id'], 'payment_status', 'Failed'); 
  327.  
  328. // If the there is a failure url set the confirmation to the failure message so it is displayed to the user. 
  329. // When there is an error like this the form is not displayed, so we need to wrap the error div in the gform  
  330. // wrapper div in order for the validation error style to actually be applied. 
  331. $confirmation = "<div class='gform_wrapper'><div class='validation_error'>" . nl2br($e->getMessage()) . "</div></div>"; 
  332.  
  333. return $confirmation; 
  334.  
  335. // ==================================================================================================================================== 
  336. /** 
  337. * This function takes the entryId and prepends a dash and then the time in seconds since Jan 1 1970 
  338. * to make a unique value which is required for the merchant session. It will shoudl ensure that any 
  339. * tests done from a test environment will not prevent live transactions because the merchant session has already been used. 
  340. * @param int $entryId The lead entryId. 
  341. * @return string The merchantSession for use in the payment is returned. 
  342. */ 
  343. // ==================================================================================================================================== 
  344. protected function buildSessionId($entryId) { 
  345.  
  346. $merchantSession = $entryId . "-" . time(); 
  347.  
  348. return $merchantSession; 
  349.  
  350. // ==================================================================================================================================== 
  351. /** 
  352. * This function takes the merchant session like above and splits it, and returns the 
  353. * the lead "entry id" so that it can be used to load the record from the database. 
  354. * @param string $merchantSession The merchant session returned from the paystation gateway. 
  355. * @return int $leadId The id of the lead record is returned. 
  356. */ 
  357. // ==================================================================================================================================== 
  358. protected function getLeadIdFromMerchantSession($merchantSession) { 
  359.  
  360. $sessionParts = explode('-', $merchantSession); 
  361. $leadId = $sessionParts[0]; 
  362.  
  363. return $leadId; 
  364.  
  365. // ==================================================================================================================================== 
  366. /** 
  367. * Return from Paystation 3 party hosted screens, retreive and process payment result and redirect to form 
  368. * This code also deals with the postback from the paystation system (which happens in the background). 
  369. */ 
  370. // ==================================================================================================================================== 
  371. public function processPaystationReturn() { 
  372.  
  373. // Pull out the query part of the url as we need this to see if a paystation return. 
  374. $parts = parse_url($_SERVER['REQUEST_URI']); 
  375. $query = isset($parts['query']) ? $parts['query'] : ''; 
  376.  
  377. // If have query parts. 
  378. if ($query) {  
  379.  
  380. // If the query part contains the paystation return string, then we are probably getting 
  381. // the redirect back from paystation after the payment has been done. 
  382. if (strpos($query, GFPAYSTATION_RETURN) !== false) { 
  383.  
  384. try { 
  385. // Create object to deal with the return result passing the query string in to it for parsing. 
  386. $resultReq = new GFPaystationReturnResult(stripslashes($query)); 
  387.  
  388. // If received valid paystation response (must contain paystation response GET variables). 
  389. if ($resultReq->isValid) { 
  390.  
  391. // Load the lead and the form as we need some of the details of these. 
  392. $leadId = $this->getLeadIdFromMerchantSession($resultReq->merchantSession); 
  393. $lead = GFFormsModel::get_lead($leadId); 
  394. $form = GFFormsModel::get_form_meta($lead['form_id']); 
  395.  
  396. // Check to see if the payment was successful. 
  397. // The redirect back is not the final say on the matter, the postback is so we don't  
  398. // update anything in the database until the postback has been recieved. 
  399.  
  400. // If failed then redirect the user to the failure URL, otherwise let the gravity form normal submit happen  
  401. // and take the user to wherever the gravity form is supposed to go on success. 
  402. if ($resultReq->errorCode != 0) { 
  403.  
  404. $feed = $this->getFeed($form['id']); 
  405.  
  406. // Redirect to the fail url for the form if there is one then exit so the code below does not 
  407. // execute which is the redirect when successful or no fail url specified. 
  408. if ($feed->UrlFail) { 
  409. wp_redirect($feed->UrlFail); 
  410. exit; 
  411.  
  412. // Redirect to Gravity Forms page, passing form and lead IDs. 
  413. // Whatever the developer specified to happen after the form was submitted will happen. 
  414. $query = "form_id={$lead['form_id']}&lead_id={$lead['id']}"; 
  415. $query .= "&hash=" . wp_hash($query); 
  416.  
  417. wp_redirect(add_query_arg(array(GFPAYSTATION_RETURN => base64_encode($query)), $lead['source_url'])); 
  418. exit; 
  419.  
  420. // If there is an exception with this then there is not much more we can do than echo it out. 
  421. // We may not have the id of the form so cannot update its status to failed, nor do I know a way 
  422. // for us to set something in the url to get wordpress to display the exception to the user in a nice way. 
  423. catch (GFPaystationException $e) { 
  424. echo nl2br(htmlspecialchars($e->getMessage())); 
  425. exit; 
  426. else if (strpos($query, GFPAYSTATION_POSTBACK) !== false) { 
  427.  
  428. // In order to help ensure that the postback XML came from Paystation, ensure that the value of the GFPAYSTATION_POSTBACK 
  429. // in the querystring is equal to that of the security hash saved in the plugin options. 
  430. $pluginOptions = (array) get_option(GFPAYSTATION_PLUGIN_OPTIONS); 
  431. parse_str($query, $params); 
  432.  
  433. if ((isset($params[GFPAYSTATION_POSTBACK])) && ($params[GFPAYSTATION_POSTBACK] == $pluginOptions['securityHash'])) 
  434. try { 
  435.  
  436. // Get the contents of the XML packet that has been POSTed back from Paystation. 
  437. $postback = file_get_contents("php://input"); 
  438.  
  439. // Create object to deal with the postback passing the postback as it will parse and put xml in to properties of the class. 
  440. $resultReq = new GFPaystationPostbackResult($postback); 
  441.  
  442. // If got valid paystation postback response. 
  443. if ($resultReq->isValid) { 
  444.  
  445. // Load the lead and the form as we need some of the details of these. 
  446. $leadId = $this->getLeadIdFromMerchantSession($resultReq->merchantSession); 
  447. $lead = GFFormsModel::get_lead($leadId); 
  448. $form = GFFormsModel::get_form_meta($lead['form_id']); 
  449. $feed = $this->getFeed($form['id']); 
  450.  
  451. // Check to see if the payment was successful 
  452. // Because this time it is from the postback we know 100% for sure that the payment was successul or not 
  453. // so we must update the status of the lead to sucess or failure and also send any responses. 
  454. if ($resultReq->errorCode === 0) { 
  455.  
  456. // Success (i.e. error code is 0). Update some details on the lead. 
  457. $lead['payment_status'] = 'Approved'; 
  458.  
  459. // NOTE: the date returned is New Zealand date and time, so in order for payment date to match the date_created of the lead 
  460. // and also display correct in the admin part of the site, we need to convert the date to a timestamp then back out to UTC datetime. 
  461. $nz_timezone = new DateTimeZone('Pacific/Auckland'); 
  462. $nz_datetime = new DateTime($resultReq->transactionTime, $nz_timezone); 
  463. $utc_datetime = gmdate('Y-m-d H:i:s', strtotime($nz_datetime->format('r'))); 
  464.  
  465. $lead['payment_date'] = $utc_datetime; 
  466.  
  467. // Set remaining details. 
  468. $lead['payment_amount'] = $resultReq->purchaseAmount ? ($resultReq->purchaseAmount / 100) : 0; // Need to convert back to float for saving in record. 
  469. $lead['transaction_id'] = $resultReq->transactionId; 
  470. $lead['transaction_type'] = 1; 
  471. GFFormsModel::update_lead($lead); 
  472.  
  473. // Trigger hook if one is present. 
  474. do_action('gfpaystation_post_payment', $lead, $form);  
  475.  
  476. // Record entry's unique ID in database. 
  477. gform_update_meta($lead['id'], 'gfpaystation_unique_id', GFFormsModel::get_form_unique_id($form['id']));  
  478.  
  479. // Now we need to send the email notifications etc since it is all confirmed. 
  480. if (!$lead['is_fulfilled']) { 
  481.  
  482. if ($feed->DelayPost) { 
  483. GFFormsModel::create_post($form, $lead); 
  484.  
  485. if ($feed->DelayNotify || $feed->DelayAutorespond) { 
  486. $this->sendDeferredNotifications($feed, $form, $lead); 
  487.  
  488. GFFormsModel::update_lead_property($lead['id'], 'is_fulfilled', true); 
  489. else { 
  490.  
  491. // Failure, error code is not 0 so update the status of the lead to Failed. 
  492. $lead['payment_status'] = 'Failed'; 
  493. GFFormsModel::update_lead($lead); 
  494.  
  495. // Also set the error message for the lead so that this can be included with an error message 
  496. // to the user if the developer has not specified a failure URL (which means the form will re-load). 
  497. gform_update_meta($lead['id'], 'gfpaystation_error', $resultReq->errorMessage); 
  498.  
  499. // Trigger hook if there is one. 
  500. do_action('gfpaystation_post_payment_fail', $lead, $form); 
  501.  
  502. // No redirects are done as the result of this is not seen by the user. 
  503. // The home page of the site is displayed so that will satisfy the paystation system that the response was received. 
  504.  
  505. // Because the output from this code is only ever seen by the paystation system, echoing the error message etc 
  506. // will be of not use; because a page will be rendered the paystation system will think that the resaponse was 
  507. // successfully received, so in this case if there is an error we case an error 500 which means the paystation 
  508. // system will try again a few times until successful and if not then paystation will know there was an issue. 
  509. catch (GFPaystationException $e) { 
  510.  
  511. header('HTTP/1.1 500 Internal Server Error', true, 500); 
  512. exit; 
  513. else { 
  514.  
  515. // Not valid from paystation so also error 500 (just in case was sent from paystation but security hash no longer matches 
  516. // it will be recorded in the paystation system that there was an error). 
  517. header('HTTP/1.1 500 Internal Server Error', true, 500); 
  518. exit; 
  519.  
  520. // ==================================================================================================================================== 
  521. /** 
  522. * send deferred notifications, handling pre- and post-1.7.0 worlds 
  523. * @param array $feed 
  524. * @param array $form the form submission data 
  525. * @param array $lead the form entry 
  526. */ 
  527. // ==================================================================================================================================== 
  528. protected function sendDeferredNotifications($feed, $form, $lead) { 
  529.  
  530. // Get the version of gravity forms. 
  531. // NOTE: if there is not a valid license key entered for gravity forms the version information will be empty. 
  532. $gfversion = GFCommon::get_version_info(); 
  533.  
  534. if (version_compare($gfversion['version'], '1.7.0', '<')) { 
  535.  
  536. // pre-1.7.0 notifications 
  537. //+ the code will also come in to this block if Gravity Forms is not proppery licenced 
  538. //+ which might be an issue during development and testing if a licence has not been purchased. 
  539.  
  540. if ($feed->DelayNotify) { 
  541. GFCommon::send_admin_notification($form, $lead); 
  542. if ($feed->DelayAutorespond) { 
  543. GFCommon::send_user_notification($form, $lead); 
  544. else { 
  545.  
  546. $notifications = GFCommon::get_notifications_to_send("form_submission", $form, $lead); 
  547.  
  548. foreach ($notifications as $notification) { 
  549.  
  550. switch (rgar($notification, 'type')) { 
  551. // old "user" notification 
  552. case 'user': 
  553. if ($feed->DelayAutorespond) { 
  554. GFCommon::send_notification($notification, $form, $lead); 
  555. break; 
  556.  
  557. // old "admin" notification 
  558. case 'admin': 
  559. if ($feed->DelayNotify) { 
  560. GFCommon::send_notification($notification, $form, $lead); 
  561. break; 
  562.  
  563. // new since 1.7, add any notification you like 
  564. default: 
  565. if (trim($notification['to']) == '{admin_email}') { 
  566.  
  567. if ($feed->DelayNotify) { 
  568. GFCommon::send_notification($notification, $form, $lead); 
  569. else { 
  570. if ($feed->DelayAutorespond) { 
  571. GFCommon::send_notification($notification, $form, $lead); 
  572. break; 
  573.  
  574. // ==================================================================================================================================== 
  575. /** 
  576. * This simply checks if the confirmation page needs to be displayed and if so then does. 
  577. */ 
  578. // ==================================================================================================================================== 
  579. public function processFormConfirmation() { 
  580.  
  581. // check for redirect to Gravity Forms page with our encoded parameters. 
  582. if (isset($_GET[GFPAYSTATION_RETURN])) { 
  583.  
  584. // Decode the encoded form and lead parameters. 
  585. parse_str(base64_decode($_GET[GFPAYSTATION_RETURN]), $query); 
  586.  
  587. // Make sure we have a match. 
  588. if (wp_hash("form_id={$query['form_id']}&lead_id={$query['lead_id']}") == $query['hash']) { 
  589.  
  590. // stop WordPress SEO from stripping off our query parameters and redirecting the page 
  591. global $wpseo_front; 
  592.  
  593. if (isset($wpseo_front)) { 
  594. remove_action('template_redirect', array($wpseo_front, 'clean_permalink'), 1); 
  595.  
  596. // Load form and lead data. 
  597. $form = GFFormsModel::get_form_meta($query['form_id']); 
  598. $lead = GFFormsModel::get_lead($query['lead_id']); 
  599.  
  600. // Get confirmation page. 
  601. if (!class_exists('GFFormDisplay')) 
  602. require_once(GFCommon::get_base_path() . '/form_display.php'); 
  603.  
  604. $confirmation = GFFormDisplay::handle_confirmation($form, $lead, false); 
  605.  
  606. // ------------------------------ 
  607. // If the confirmation is not an array (which means its just a message), then check to see if the status 
  608. // of the payment is failed. If so then change the confirmnation message to an error div with a message that 
  609. // the playment failed along with the error message from Paystation which is stored in the meta table for the lead. 
  610.  
  611. // In order for this to work the postback needs to have happened before this code has loaded, which should nornally be the case 
  612. // given that paystation waits 10 seconds before redirecting back to this site. 
  613. if ((!is_array($confirmation)) && ($lead['payment_status'] == 'Failed')) { 
  614. $confirmation = "<div class='gform_wrapper'><div class='validation_error'>Sorry the payment failed : " . gform_get_meta($lead['id'], 'gfpaystation_error') . "</div></div>"; 
  615.  
  616. // ------------------------------ 
  617. // Preload the GF submission, ready for processing the confirmation message. 
  618. GFFormDisplay::$submission[$form['id']] = array( 
  619. 'is_confirmation' => true,  
  620. 'confirmation_message' => $confirmation,  
  621. 'form' => $form,  
  622. 'lead' => $lead,  
  623. ); 
  624.  
  625. // ------------------------------ 
  626. // If it's a redirection (page or other URL) then do the redirect now. 
  627. if (is_array($confirmation) && isset($confirmation['redirect'])) { 
  628. header('Location: ' . $confirmation['redirect']); 
  629. exit; 
  630.  
  631. // ==================================================================================================================================== 
  632. /** 
  633. * add custom merge tags 
  634. * @param array $merge_tags 
  635. * @param int $form_id 
  636. * @param array $fields 
  637. * @param int $element_id 
  638. * @return array 
  639. */ 
  640. // ==================================================================================================================================== 
  641. public function gformCustomMergeTags($merge_tags, $form_id, $fields, $element_id) { 
  642.  
  643. if ($form_id && $this->getFeed($form_id)) { 
  644. $merge_tags[] = array('label' => 'Transaction ID', 'tag' => '{transaction_id}'); 
  645. $merge_tags[] = array('label' => 'Payment Amount', 'tag' => '{payment_amount}'); 
  646.  
  647. return $merge_tags; 
  648.  
  649. // ==================================================================================================================================== 
  650. /** 
  651. * replace custom merge tags 
  652. * @param string $text 
  653. * @param array $form 
  654. * @param array $lead 
  655. * @param bool $url_encode 
  656. * @param bool $esc_html 
  657. * @param bool $nl2br 
  658. * @param string $format 
  659. * @return string 
  660. */ 
  661. // ==================================================================================================================================== 
  662. public function gformReplaceMergeTags($text, $form, $lead, $url_encode, $esc_html, $nl2br, $format) { 
  663.  
  664. $tags = array ( 
  665. '{transaction_id}',  
  666. '{payment_amount}' 
  667. ); 
  668.  
  669. $values = array ( 
  670. isset($lead['transaction_id']) ? $lead['transaction_id'] : '',  
  671. isset($lead['payment_amount']) ? $lead['payment_amount'] : '' 
  672. ); 
  673.  
  674. return str_replace($tags, $values, $text); 
  675.  
  676. // ==================================================================================================================================== 
  677. /** 
  678. * Check whether this form entry's unique ID has already been used; if so, we've already done a payment attempt. 
  679. * @param array $form 
  680. * @return boolean 
  681. */ 
  682. // ==================================================================================================================================== 
  683. protected function hasFormBeenProcessed($form) { 
  684. global $wpdb; 
  685.  
  686. $unique_id = GFFormsModel::get_form_unique_id($form['id']); 
  687.  
  688. $sql = "select lead_id from {$wpdb->prefix}rg_lead_meta where meta_key='gfpaystation_unique_id' and meta_value = %s"; 
  689. $lead_id = $wpdb->get_var($wpdb->prepare($sql, $unique_id)); 
  690.  
  691. return !empty($lead_id); 
  692.  
  693. // ==================================================================================================================================== 
  694. /** 
  695. * Get feed for form using the paystationFeed object. 
  696. * @param int $form_id the submitted form's ID 
  697. * @return GFPaystationFeed 
  698. */ 
  699. // ==================================================================================================================================== 
  700. protected function getFeed($form_id) { 
  701.  
  702. if ($this->feed !== false && (empty($this->feed) || $this->feed->FormID != $form_id)) { 
  703. $this->feed = GFPaystationFeed::getFormFeed($form_id); 
  704.  
  705. return $this->feed; 
  706.  
  707. // ==================================================================================================================================== 
  708. /** 
  709. * Get form data for form 
  710. * @param array $form the form submission data 
  711. * @return GFPaystationFormData 
  712. */ 
  713. // ==================================================================================================================================== 
  714. protected function getFormData($form) { 
  715.  
  716. if (empty($this->formData) || $this->formData->formID != $form['id']) { 
  717. $feed = $this->getFeed($form['id']); 
  718. $this->formData = new GFPaystationFormData($form, $feed); 
  719.  
  720. return $this->formData; 
  721.  
  722. // ==================================================================================================================================== 
  723. /** 
  724. * Display a message (already HTML-conformant) 
  725. * @param string $msg HTML-encoded message to display inside a paragraph 
  726. */ 
  727. // ==================================================================================================================================== 
  728. public static function showMessage($msg) { 
  729. echo "<div class='updated fade'><p><strong>$msg</strong></p></div>\n"; 
  730.  
  731. // ==================================================================================================================================== 
  732. /** 
  733. * Display an error message (already HTML-conformant) 
  734. * I beleive this only works for errors to be output in the admin part of the site. 
  735. * @param string $msg HTML-encoded message to display inside a paragraph 
  736. */ 
  737. // ==================================================================================================================================== 
  738. public static function showError($msg) { 
  739. echo "<div class='error'><p><strong>$msg</strong></p></div>\n";