1

I posted this code before it has been passed on to me, but this time I have a different question. We are using an integration with a company called GiveX who has given me very little documentation. The company that hired me had to sign a nda, so I don't think I can reveal much of the documentation they have revealed to us. I will try and make it as clear as possible what I am trying to achieve. I will place all my code below my questions with titles of the file naming in Wordpress.

  1. How do I console log for example the $result of the gi_check_balance() function in the integrate.php file? what I want to know is what giveX is sending back to us. Now this is even if this function is sending a post request to giveX I can't even tell. And where am I supposed to be to see this consoled? on the order complete page? or in some logs somewhere?
  2. What does add_action( 'wp_ajax_gi_check_balance', 'gi_check_balance' ); this line do? I see that in the Wordpress docs add_action is a hook that fires at a certain point and the first value should be a string and the second a function, I see that to be true however what is the point of creating this hook, I don't see the first value the string referenced anywhere else, so how is it triggered? or when is that function run or does just giving it a string name and a function allow that function to run?
  3. Again there are two functions gi_check_balance() and gi_secure_register() how do I know when these are fired? how do these functions connect to the check-balance.js file and the secure-register.jsfile (now my understanding of the gi_secure_register() function is that it is only for testing purposes, the only difference I know is the code that is sent in the post request labeled as the method one is 904 and one is 994 and they are supposed to do different things but reading through giveX documentation I can't really tell the difference.
  4. Now I am aware that there is a webhook as well, and it seems to run based on a custom topic in woocommerce that is defined inside the integrate.php file. This web hook also seems to make a post request to giveX url, now I can't for the life of me understand why would we be firing a post request 3 times, one in the integrate.php plugin file itself, one in the webhook.php file and another in either one of the js files. I know it will be hard for someone to determine this for me, but if I could know what scenarios in a woocommerce completed order these post requests will be fired? it will help me understand why there are three different ones.
  5. This section of the email that is being sent by the webhook <b>Card Number:</b> ' . $response->result[3] . '<br /> <b>PIN:</b> ' . $response_reference[1] . '<br /> <b>Card Amount:</b> ' . $response->result[4] . '<br /> <b>Reference Number:</b> ' . $response_reference[0] . '</p>' currently returns empty variables in the email. I want to figure out why giveX is not sending back data? I'd like to be able to console log this result somewhere I can see any errors coming back from giveX.
  6. So Basically, I would like some help breaking down when certain functions are being fired based off of events in woocommerce/wordpress. Also I want to know which post requests are actually being fired, because I would think we only have to send one request to giveX to order these gift card purchase.

Ok Here is the code (thanks so much ahead of time :)

plugins/givex/integrate.php

 // Get grouped product ID from child product ID
 function get_parent_grouped_id( $children_id ){
     global $wpdb;
     $results = $wpdb->get_col("SELECT post_id FROM {$wpdb->prefix}postmeta
         WHERE meta_key = '_children' AND meta_value LIKE '%$children_id%'");
     // Will only return one product Id or false if there is zero or many
     return sizeof($results) == 1 ? reset($results) : false;
 }
 /**
  * add_new_topic_hooks will add a new webhook topic hook. 
  * @param array $topic_hooks Esxisting topic hooks.
  */
 function add_new_topic_hooks( $topic_hooks ) {
    // Array that has the topic as resource.event with arrays of actions that call that topic.
    $new_hooks = array(
        'order.gift_card' => array(
            'order_gift_card_filter',
            ),
        );
    return array_merge( $topic_hooks, $new_hooks );
 }
 add_filter( 'woocommerce_webhook_topic_hooks', 'add_new_topic_hooks' );
 /**
  * add_new_topic_events will add new events for topic resources.
  * @param array $topic_events Existing valid events for resources.
  */
 function add_new_topic_events( $topic_events ) {
    // New events to be used for resources.
    $new_events = array(
        'gift_card',
        );
    return array_merge( $topic_events, $new_events );
 }
 add_filter( 'woocommerce_valid_webhook_events', 'add_new_topic_events' );
 /**
  * add_new_webhook_topics adds the new webhook to the dropdown list on the Webhook page.
  * @param array $topics Array of topics with the i18n proper name.
  */
 function add_new_webhook_topics( $topics ) {
    // New topic array to add to the list, must match hooks being created.
    $new_topics = array( 
        'order.gift_card' => __( 'Order Gift Card', 'woocommerce' ),
        );
    return array_merge( $topics, $new_topics );
 }
 add_filter( 'woocommerce_webhook_topics', 'add_new_webhook_topics' );
 /**
  * my_order_item_check will check an order when it is created through the checkout form,
  * if it has product ID 1030 as one of the items, it will fire off the action `order_gift_card_filter`
  * 
  * @param  int    $order_id    The ID of the order that was just created.
  * @param  array  $posted_data Array of all of the data that was posted through checkout form.
  * @param  object $order       The order object.
  * @return null
  */
  function my_order_item_check( $order_id, $posted_data, $order ) {
    $order = wc_get_order( $order_id );
    $order_status = $order->status;
    $items = $order->get_items();
    foreach ( $items as $item ) {

        if ( is_a( $item, 'WC_Order_Item_Product' ) ) {

            if ( 1457 === $item->get_product_id() ) {

          $item_data = $item->get_data();
          $item_meta_data_group = $item_data['meta_data'];
          $gift_card_data = array();
          foreach ( $item_meta_data_group as $item_meta_data ) {
            $gift_card_data[$item_meta_data->key] = $item_meta_data->value;
          }

          do_action( 'order_gift_card_filter', $order_id, $posted_data, $order );

            }
        }
    }
  }

//The two below actions are what the order.created webhook is tied into, it is up to you to use these if you wish. 

//add_action( 'woocommerce_payment_complete', 'my_order_item_check', 10, 4 );
add_action( 'woocommerce_checkout_order_processed', 'my_order_item_check', 10, 3 );
//add_action( 'woocommerce_process_shop_order_meta', 'my_order_item_check', 10, 2 );

add_action( 'wp_enqueue_scripts', 'add_ajax_script' );
function add_ajax_script() {
  wp_enqueue_script( 'check-balance', plugins_url( '/check-balance.js', __FILE__ ), array('jquery'), '1.0', true );
  wp_enqueue_script( 'secure-register', plugins_url( '/secure-register.js', __FILE__ ), array('jquery'), '1.0', true );
  wp_localize_script( 'check-balance', 'gi_check_balance', array( 'ajax_url' => admin_url('admin-ajax.php') ) );
  wp_localize_script( 'secure-register', 'gi_secure_register', array( 'ajax_url' => admin_url('admin-ajax.php') ) );
}

add_action( 'wp_ajax_nopriv_gi_check_balance', 'gi_check_balance' );
add_action( 'wp_ajax_gi_check_balance', 'gi_check_balance' );
function gi_check_balance() {
  $gx_url_1 = 'https://givexurl-1.com';
  $gx_url_2 = 'https://givexurl-2.com';
  $gx_port_1 = port;
  $gx_port_2 = port;
  $gx_post_url_1 = $gx_url_1 . ':' . $gx_port_1;
  $gx_post_url_2 = $gx_url_2 . ':' . $gx_port_2;
  $gx_user = 'user';
  $gx_password = 'pass';

  $gx_card_number = $_POST['gx_card_number'];

  $data = array(
    'method' => '994',
    'params' => [
      'en',
      'rc1',
      //null,
      $gx_user,
      $gx_password,
      $gx_card_number,
      $gx_card_pin,
      null
    ],
    'id' => 'test'
  );

  $options = array(
    'http' => array(
      'method' => 'POST',
      'header' => 'Content-Type: application/json',
      'content' => json_encode( $data )
    )
  );

  $context  = stream_context_create( $options );
  $result = file_get_contents( $gx_post_url_1, false, $context );
  if ( $result == false ) {
    $result = file_get_contents( $gx_post_url_2, false, $context );
  }
  $response = json_decode( $result );

  echo $result;
  //echo json_encode($result) ;
  //var_dump( $response );
  //echo $response;

  die();
}

// function only for dev testing purposes
//add_action( 'wp_ajax_gi_secure_register', 'gi_secure_register' );
function gi_secure_register() {
  $gx_url_1 = 'https://givexurl-1.com';
  $gx_url_2 = 'https://givexurl-2.com';
  $gx_port_1 = port;
  $gx_port_2 = port;
  $gx_post_url_1 = $gx_url_1 . ':' . $gx_port_1;
  $gx_post_url_2 = $gx_url_2 . ':' . $gx_port_2;
  $gx_user = 'user';
  $gx_password = 'pass';

  $gx_register_amount = $_POST['gx_register_amount'];

  $data = array(
    'method' => '904',
    'params' => [
      'en',
      'rc2',
      //null,
      $gx_user,
      $gx_password,
      $gx_register_amount,
      null,
      null,
      null
    ],
    'id' => 'test'
  );

  $options = array(
    'http' => array(
      'method' => 'POST',
      'header' => 'Content-Type: application/json',
      'content' => json_encode( $data )
    )
  );

  $context  = stream_context_create( $options );
  $result = file_get_contents( $gx_post_url_1, false, $context );
  if ( $result == false ) {
    $result = file_get_contents( $gx_post_url_2, false, $context );
  }
  $response = json_decode( $result );

  echo json_encode($result);

  die();
}

plugins/givex/webhook.php

<?php 
// required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");

$passed = false;
$request_body = file_get_contents('php://input');
$secret = 'P&_(e>P _I?%/aOW?wv0H.U149+Eyv8bh~qXd<6XrIY8+K0oo]';
$sig = base64_encode(hash_hmac('sha256', $request_body, $secret, true));

if( !function_exists('apache_request_headers') ) {
  function apache_request_headers() {
    $headers = array();
    foreach($_SERVER as $key => $value) {
        if (substr($key, 0, 5) <> 'HTTP_') {
            continue;
        }
        $header = str_replace(' ', '-', ucwords(str_replace('_', ' ', strtolower(substr($key, 5)))));
        $headers[$header] = $value;
    }
    return $headers;
  }
}
$header = apache_request_headers(); 
foreach ( $header as $headers => $value ) {
  if( $headers == 'X-Wc-Webhook-Signature' ) {
    if ( $value == $sig ) {
      $passed = true;
    }
  }
}

if( $passed !== true ) {
  header("Location: https://our-url.com");
} else {

$gx_url_1 = 'https://givexurl-1.com';
$gx_url_2 = 'https://givexurl-2.com';
$gx_port_1 = port;
$gx_port_2 = port;
$gx_post_url_1 = $gx_url_1 . ':' . $gx_port_1;
$gx_post_url_2 = $gx_url_2 . ':' . $gx_port_2;
$gx_user = 'user';
$gx_password = 'pass';

$data = json_decode(file_get_contents('php://input'), true);

foreach( $data['line_items'] as $item ) {
  if( $item['product_id'] == 1457 ) {
    $item_meta_data_group = $item['meta_data'];
    $gift_card_data = array();
    foreach( $item_meta_data_group as $item_meta_data ) {
      $gift_card_data[$item_meta_data['key']] = $item_meta_data['value'];
    }

    $data_modified = array(
      'method' => '904',
      'params' => [
        'en',
        null,
        $gx_user,
        $gx_password,
        str_replace(array(',', '$', ' '), '', $gift_card_data['gift-card-amount']),
        null,
        null,
        null
      ],
      'id' => 'test'
    );

    $options = array(
      'http' => array(
        'method' => 'POST',
        'header' => 'Content-Type: application/json',
        'content' => json_encode( $data_modified )
      )
    );

    $context  = stream_context_create( $options );
    //$result = file_get_contents( $gx_post_url, false, $context );
    $result = file_get_contents( $gx_post_url_1, false, $context );
    if ( $result == false ) {
      $result = file_get_contents( $gx_post_url_2, false, $context );
    }
    $response = json_decode( $result );
    $response_reference = explode(':', $response->result[2]);
    echo $result;

    $to = $gift_card_data['recipient_email'];
    $subject_decoded = 'You received a gift card ';
    $subject = '=?UTF-8?B?' . base64_encode( $subject_decoded ) . '?=';
    $subject1 = 'test';
    $message = '<table border="0" cellspacing="0" cellpadding="0" width="100%" style="width: 100%; border-collapse: collapse;"><tbody><tr><td style="padding: 40px 40px 20px; background-color: #f9f9f9;" align="center"><table border="0" cellspacing="0" cellpadding="0" width="600" style="border-collapse: collapse;"><tbody>';
    $message .= '<tr><td align="center" valign="bottom" style="padding: 0 0 20px;">';
    $message .= '</td></tr>';
    $message .= '<tr><td align="center" style="padding: 10px 40px 20px; background-color: #ffffff; color: #676767; font-family: Helvetica, Arial, sans-serif;">';
    $message .= '<h2 style="font-family: Garamond, serif; font-size: 28px; font-weight: 600; color: #444444;">' . (!empty($gift_card_data['recipient_name']) ? $gift_card_data['recipient_name'] : 'Whoa') . ', you&rsquo;ve got ' . $gift_card_data['gift-card-amount'] . ' to spend at!</h2>';
    $message .= '<p style="color: #676767;">' . (!empty($gift_card_data['sender']) ? $gift_card_data['sender'] : 'Someone') . ' sent you a gift card' . (!empty($gift_card_data['message']) ? ' with the following message:' : '.') . '</p>';
    if( !empty($gift_card_data['message']) ) {
      $message .= '<p style="color: #676767;"><i><br />' . nl2br($gift_card_data['message']) . '<br /><br /></i></p>';
    }
    //$message .= '<img src="https://www.barcodesinc.com/generator/image.php?code=' . $response->result[3] . '&style=68&type=C39&width=300&height=50&xres=1&font=4" alt="" />';
    // barcode generator website: https://www.barcodesinc.com/generator/index.php
    $message .= '<p style="color: 676767; font-size: 1.25em;"><b>Card Number:</b> ' . $response->result[3] . '<br /> <b>PIN:</b> ' . $response_reference[1] . '<br /> <b>Card Amount:</b> ' . $response->result[4] . '<br /> <b>Reference Number:</b> ' . $response_reference[0] . '</p>';
    $message .= '</td></tr>';
    $message .= '<tr><td align="center" style="padding: 20px 0 0;">';
    $message .= '<p style="color: #676767;"><b>We look forward to you dining with us!</b></p>';  
    $message .= '</td></tr>';
    $message .= '</tbody></table></td></tr></tbody></table>';
    $headers = "From: Gift Cards <test.com>\r\n";
    $headers .= "Reply-To: noreply@test.com\r\n";
    $headers .= "MIME-Version: 1.0\r\n";
    $headers .= "Content-Type: text/html; charset=ISO-8859-1\r\n";
    mail($to, $subject, $message, $headers);
  }
} // end foreach

} // end if else '$passed !== true'

plugins/givex/check-balance.js

   jQuery(document).ready(function($) {

      // checks card balance
      $('.gi-check-balance').submit(function() {

        var gx_card_number = $(this).find('[name=card-number]').val()
        var gx_card_pin = $(this).find('[name=card-pin]').val()

        $.ajax({
          url: gi_check_balance.ajax_url,
          type: 'post',
          data: {
            action: 'gi_check_balance',
            gx_card_number: gx_card_number,
            gx_card_pin: gx_card_pin
          },
          dataType: 'json',
          success: function(response) {
            console.log(response)
            $('.gi-check-balance-result').text(response['result'][2])
            //$('.gi-check-balance-result').text(JSON.stringify(response))
            $('.gi-check-balance-result').show()
          }
        })

        return false

      })

    })

plugins/givex/secure-register.js

jQuery(document).ready(function($) {

  // registers gift card
  $('.gi-secure-register').submit(function() {

    var gx_register_amount = $(this).find('[name=register-amount]').val()

    $.ajax({
      url: gi_secure_register.ajax_url,
      type: 'post',
      data: {
        action: 'gi_secure_register',
        gx_register_amount: gx_register_amount
      },
      dataType: 'json',
      success: function(response) {
        //$('.gi-secure-register-result').html('Reference Number: ' + response['result'][2] + '<br>' + 'Card Number: ' + response['result'][3] + '<br>' + 'Card Amount: ' + response['result'][4])
        $('.gi-secure-register-result').text(response)
        $('.gi-secure-register-result').show();
        console.log(response);
      }
    })

    return false

  })

})

UPDATE

First Noticed error. It looks like since I am on localhost I am getting rejected from the https connection? Now I know very little about ssl, how would I get that working locally. Do I need something further from the url I am sending the request too?

[22-Nov-2019 02:59:00 UTC] PHP Warning:  file_get_contents(): SSL operation failed with code 1. OpenSSL Error messages:
error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed in /Users/anderskitson/Local Sites/river-cafe/app/public/wp-content/plugins/givex-integrate/webhook.dev.php on line 94

The error above is solved here https://stackoverflow.com/a/58924492/2949184 and solves the main issues I have been having.

Anders Kitson
  • 1,413
  • 6
  • 38
  • 98
  • 1
    there is too much questions for my little comment, I just answer one : the hooks starting by `wp_ajax_nopriv_` and `wp_ajax_` are fired by `admin-ajax.php` : https://codex.wordpress.org/AJAX_in_Plugins – Kaperto Nov 21 '19 at 23:57
  • ok, is there a way to know what even on the user side would be causing admin-ajax.php to run? – Anders Kitson Nov 21 '19 at 23:58
  • search for `gi_secure_register` in JavaScript file to find ajax calls. – Kaperto Nov 21 '19 at 23:59
  • Sometimes its a good idea to just add some error_log statements to what is being fired and then do a bunch of user cases (click around in woocommerce) to see when they fire. – Snuwerd Nov 22 '19 at 00:05

1 Answers1

3
  1. When it comes to console logging, I use error_log(); and then look in the PHP error log file. See https://www.loggly.com/ultimate-guide/php-logging-basics/

  2. When I want to know where a hook is used, i take the first string, 'wp_ajax_gi_check_balance' and search the entire website (or less if I know where to look) in *.php files and look for a line that says do_action('wp_ajax_gi_check_balance'....

I'll post more later.

Update

I realize I'm not much more savvy on the rest of your questions than you are. I think at least the error logging can get you much further in uncovering of how it works. And I'm off to bed, but I may check again tomorrow in case you have any updates.

Update 2

About your SSL error: file_get_contents(): SSL operation failed with code 1, Failed to enable crypto

Did you try googling the error yourself?

Snuwerd
  • 459
  • 3
  • 6
  • 1
    your error_log(); solution already helped me a bunch, and don't want to bog anyone down with all the questions for now. Thanks – Anders Kitson Nov 22 '19 at 20:22