Introduction

In Part 1 of this series, you created a simple WordPress plugin, added an admin page for users to set the credentials to connect to Amadeus Self-Service APIs, and gave the plugin the ability to communicate with the Flight Offers Search API. In Part 2, you’ll equip your plugin with a web form for users to enter and submit their travel details via AJAX requests. Then, you’ll finish by giving it the ability to extract flight deals and display them in a table.

You can find the source code used in the article on our GitHub repository.

Receiving user input

Your plugin will provide a web form for users to submit their origin and destination, departure date, return date (if round-trip) and number of travelling adults, via AJAX requests. You’ll reuse the get_flight_offers function to receive the AJAX requests. Let’s get started!

Create the following function called flight_offers_form, which outputs a web form when called and saves it in a new PHP file called flight-offers-form.php:

<?php
function flight_offers_form() {
  echo '<form id="flight_offers_request_form">';
  echo '<input type="hidden" name="action" value="get_flight_offers_action">';
  echo '<p>';
  echo 'Origin Location Code (required): ';
  echo '<input type="text" id="originLocationCode" name="originLocationCode" pattern="[A-Z]{3}" required>';
  echo '</p>';
  echo '<p>';
  echo 'Destination Location Code (required): ';
  echo '<input type="text" id="destinationLocationCode" name="destinationLocationCode" pattern="[A-Z]{3}" required>';
  echo '</p>';
  echo '<p>';    
  echo 'Departure Date (required): ';
  echo '<input type="text" id="departureDate" name="departureDate" id="departureDate" required>';
  echo '</p>';
  echo '<p>';    
  echo 'Return Date: ';
  echo '<input type="text" id="returnDate" name="returnDate" id="returnDate">';
  echo '</p>';    
  echo '<p>';
  echo 'No of Travelling Adults (required): ';
  echo '<input type="text" id="adults" name="adults" pattern="[0-9]+" required>';
  echo '</p>';
  echo '<p><input type="submit" value="Search"></p>';
  echo '</form>';
  echo '<div id="response"></div>';

This web form will consist of five input text boxes and a submission button. Later, you’ll convert the two text boxes for date entry into datepickers.

The form also contains a hidden field called action with a value of get_flight_offers_action, which will be used to identify the PHP script that handles the AJAX request (more on this later).

Apart from the form, you’ll include <div id=”response”></div>, a placeholder reserved for appending the response received from the Flight Offers Search API.

Now include the code from the flight-offers-form.php file in the main PHP file, amadeus-flight-offers-search.php, like so:

require_once( 'flight-offers-form.php' );

In the amadeus_flight_offers_search_shortcode function inside the amadeus-flight-offers-search.php file, remove the following statement to call the get_flight_offers function:

get_flight_offers();

Then add the statement to call the flight_offers_form function. Here’s the code:

function amadeus_flight_offers_search_shortcode() {  
  flight_offers_form();
}

Launch the WordPress post or page that contains the [amadeus-flight-offers-search] tag and you’ll see that it displays a web form similar to this:

The next step is to add the jQuery code that converts the two date-entry text boxes into datepickers and submits the form data to the get_flight_offers function via an AJAX request.

In amadeus-flight-offers-search.php, add a function called enqueue_amadeus_script that contains two WordPress functions: wp_enqueue_script and wp_localize_script:

function enqueue_amadeus_script() {
    wp_enqueue_script( 'ajax-request-amadeus-flight-offers', plugins_url( 'js/amadeus-flight-offers-search.js', __FILE__ ), array( 'jquery', 'jquery-ui-datepicker' ), True );
wp_enqueue_style( 'jquery-ui', 'https://code.jquery.com/ui/1.12.0/themes/smoothness/jquery-ui.css'  );
wp_localize_script( 'ajax-request-amadeus-flight-offers', 'ajax_object', array( 'ajax_url' => admin_url( 'admin-ajax.php' ), ) );
}

The wp_enqueue_script function will include a script on any WordPress post or page with the [amadeus-flight-offers-search] tag added. The script’s name is ajax-request-amadeus-flight-offers and it’s source is a JavaScript file called amadeus-flight-offers-search.js (to be created in the next step) and the dependency scripts required by the amadeus-flight-offers-search.js: jquery and jquery-ui-datepicker.

The wp_localize_script function creates an object called ajax_object that’s made accessible to amadeus-flight-offers-search.js by attaching it to the enqueued ajax-request-amadeus-flight-offers script. The ajax_object receives a property called ajax_url that stores the URL of the WordPress admin-ajax.php file. This is returned by admin_url( ‘admin-ajax.php’) to which the AJAX request will be routed (more on this later).

Next, in amadeus-flight-offers-search.php, attach the enqueue_amadeus_script function to the wp_enqueue_scripts action hook, which is triggered when scripts and styles are enqueued, like so:

add_action( 'wp_enqueue_scripts', 'enqueue_amadeus_script' );

In the plugin’s directory, create a new directory called js and add to it a new file called amadeus-flight-offers-search.js. This file will contain jQuery code that converts the two date entry text boxes into datepickers and submits the user input to the get_flight_offers function via an AJAX request, as follows:

jQuery(function($){
  $( "#departureDate" ).datepicker( { dateFormat: "yy-mm-dd" } );
  $( "#returnDate" ).datepicker( { dateFormat: "yy-mm-dd" } );
  $( "#flight_offers_request_form" ).submit( function( event ) {
    event.preventDefault();
    $( "#response" ).html( '' );
    $.ajax({
        url: ajax_object.ajax_url,
        type: "post",
        dataType: 'JSON',
        data: $( this ).serialize(),
    })
    .done ( function( response ) {
// code to handle response from successful AJAX request
    })
    .fail(function( jqXHR, textStatus ) {
// code to handle response from failed AJAX request
    })
  })
});

All AJAX requests in WordPress are routed to admin-ajax.php, which is part of the WordPress AJAX API. In amadeus-flight-offers-search.js, the URL of this admin-ajax.php is passed to the url parameter of the $.ajax method via an object property called ajax_object.ajax_url. This ajax_object.ajax_url was created and made accessible by the wp_localize_script function after amadeus-flight-offers-search.js was enqueued by the wp_enqueue_script function earlier.

Since all AJAX requests in WordPress are routed to the admin-ajax.php, how can WordPress know the actual PHP script to process an AJAX request? The answer is the hidden field called action in our web form, created at the beginning of this section:

<input type="hidden" name="action" value="get_flight_offers_action">

You’ll append the value of this action field (get_flight_offers_action) to the WordPress wp_ajax_ or wp_ajax_nopriv_ hook to create a new action hook called either wp_ajax_get_flight_offers_action or wp_ajax_nopriv_get_flight_offers_action. You’ll then use it to hook up the plugin’s AJAX request to the get_flight_offers function in the amadeus-flight-offers-search.php, as shown here:

add_action( 'wp_ajax_get_flight_offers_action', 'get_flight_offers' );
add_action( 'wp_ajax_nopriv_get_flight_offers_action', 'get_flight_offers' );

The wp_ajax_(action) hook executes for users who are logged in, while wp_ajax_nopriv_(action) executes for users who are not. For your plugin, you’ll allow both so you register both hooks.

At this point, the amadeus-flight-offers-search.php file should contain the following code:

<?php
/**
 * Plugin Name:     Amadeus Flight Offers Search
 * Plugin URI:      https://developers.amadeus.com/
 * Description:     Connecting to Flight Offers Search API.
 * Version:         1.0.0
 * Requires PHP:    5.2
 * Author:          Amadeus for Developers
 * Author URI:      https://developers.amadeus.com/
 * License:         GPL v2 or later
 * License URI:     https://www.gnu.org/licenses/gpl-2.0.html
 */
require_once( 'amadeus-api-settings.php' );
require_once( 'flight-offers-form.php' );
require_once( 'get-flight-offers.php' );
function enqueue_amadeus_script() {
    wp_enqueue_script( 'ajax-request-amadeus-flight-offers', plugins_url( 'js/amadeus-flight-offers-search.js', __FILE__ ), array( 'jquery', 'jquery-ui-datepicker' ), True );
wp_enqueue_style( 'jquery-ui', 'https://code.jquery.com/ui/1.12.0/themes/smoothness/jquery-ui.css'  );
    wp_localize_script( 'ajax-request-amadeus-flight-offers', 'ajax_object', array( 'ajax_url' => admin_url( 'admin-ajax.php' ), ) );
}
add_action( 'wp_enqueue_scripts', 'enqueue_amadeus_script' );
add_action( 'wp_ajax_get_flight_offers_action', 'get_flight_offers' );
add_action( 'wp_ajax_nopriv_get_flight_offers_action', 'get_flight_offers' );
function amadeus_flight_offers_search_shortcode() {
    flight_offers_form();
}
add_shortcode( 'amadeus-flight-offers-search', 'amadeus_flight_offers_search_shortcode' );

You’ll reuse the get_flight_offers function to receive and process the AJAX request. We’ll discuss this in detail in the next section.

Calling the API

For the get_flight_offers function to receive and process the AJAX request, you must changes its code to allow it to:

Receive user input submitted via an AJAX request.
Query the Flight Offers Search API using the user input as the parameters.
Return the API’s response to the front end in a JSON string.

Let’s get started. Instead of hardcoding the travel data in the get_flight_offers function, obtain it dynamically from the user input submitted via an AJAX request, with this code:

/*
$travel_data = array(
  'originLocationCode' 	  => 'SIN',
  'destinationLocationCode' => 'BKK',
  'departureDate' 	      => '2020-08-14',
  'returnDate' 	          => '2020-08-17',
  'adults'                  => 2
);
*/
$travel_data = array(
  'originLocationCode' 	  => sanitize_text_field( $_POST["originLocationCode"] ),
  'destinationLocationCode' => sanitize_text_field( $_POST["destinationLocationCode"] ),
  'departureDate' 	      => sanitize_text_field( $_POST["departureDate"] ),
  'adults'                  => sanitize_text_field( $_POST["adults"] ),
);
if ( $_POST["returnDate"] !== '' ) {
  $travel_data['returnDate'] = sanitize_text_field( $_POST["returnDate"]
}

Next, remove these two blocks of redundant output statements from the get_flight_offers function:

echo 'Response from the authorization server:';
echo '<pre>', json_encode($response_body, JSON_PRETTY_PRINT), '</pre>';

echo 'Response from the Flight Offers Search API:';

Then rewrite these three respective code blocks in the get_flight_offers function:

// if(property_exists( $response_body, 'error' ) ) die; 
if ( property_exists($response_body, 'error') ) {
  die( '<p>' . ( $response_body -> error_description ) . '.</p>' );
}

// print_r( $e->getMessage() );
die( '<p>' . ( $e -> getMessage() ) . '.</p>' );

// echo '<pre>', substr( json_encode($response_body, JSON_PRETTY_PRINT), 0, 5000 ), '</pre>';
echo json_encode($requests_response->body);

Finally, add the following statement to the end of the get_flight_offers function to terminate immediately and return a response:

wp_die();

At this point, the get_flight_offers function in the get_flight_offers.php file should contain the following code:

function get_flight_offers() {
  Requests::register_autoloader();
  $url = 'https://test.api.amadeus.com/v1/security/oauth2/token';
  $options = get_option( 'amadeus_api_options' ); 
  $auth_data = array();
  $auth_data[ 'client_id' ] = $options[ 'api_key_text_field_0' ];
  $auth_data[ 'client_secret' ] = $options[ 'api_secret_text_field_1' ];
  $auth_data[ 'grant_type' ] = 'client_credentials';
  $headers = array( 'Content-Type' => 'application/x-www-form-urlencoded' );
try {
  $requests_response = Requests::post( $url, $headers, $auth_data );
  $response_body = json_decode( $requests_response->body );
  if ( property_exists($response_body, 'error') ) {
    die( '<p>' . ( $response_body -> error_description ) . '.</p>' );
  }
  $access_token = $response_body->access_token;
} catch (Exception $e) {
   die( '<p>' . ( $e -> getMessage() ) . '.</p>' );
}
if ( isset( $access_token ) ) {
  $endpoint = 'https://test.api.amadeus.com/v2/shopping/flight-offers';
  $travel_data = array(
	'originLocationCode' => sanitize_text_field( $_POST["originLocationCode"] ),
	'destinationLocationCode' => sanitize_text_field( $_POST["destinationLocationCode"] ),
	'departureDate' => sanitize_text_field( $_POST["departureDate"] ),
	'adults' => sanitize_text_field( $_POST["adults"] ),
  );
  if ( $_POST["returnDate"] !== '' ) {
	$travel_data['returnDate'] = sanitize_text_field( $_POST["returnDate"] );
  }
  $params = http_build_query( $travel_data );
  $url = $endpoint.'?'.$params;
  $headers = array( 'Authorization' => 'Bearer '.$access_token );
  $options = array(
	  'timeout' => 10,
  );
  try {
	$requests_response = Requests::get( $url, $headers, $options );
	$response_body = json_decode( $requests_response->body );
	if ( property_exists($response_body, 'error') ) {
		die( '<p>' . ( $response_body -> error_description ) . '.</p>' );
	}
	echo json_encode($requests_response->body);
	} catch ( Exception $e ) {
		die( '<p>' . ( $e -> getMessage() ) . '.</p>' );
	}
  }
  wp_die();
}

All that’s left to do is to get your plugin to extract useful information from the data returned by the get_flight_offers function and display it in a table. Ready?

Showing the data

When a user submits a form, the $.ajax method in the amadeus-flight-offers-search.js file makes the AJAX request and returns a jQuery XMLHttpRequest (jqXHR) object. The jqXHR object’s done method captures and handles the data returned from a successful AJAX request, while the object’s fail method handles the data from a failed AJAX request.

Let’s start with the easiest one. Add this code to the fail method to format and display the text response from a failed AJAX request:

.fail(function( jqXHR, textStatus ) {
    $( "#response" ).html( '<p>' + jqXHR.responseText + '</p>' );
})

Then add the following code to the done method to extract, format, and display useful information from data returned from a successful AJAX request in a table:

.done ( function( response ){
  var responseObj = $.parseJSON( response );
  var content = '';
  content += '<p>Flight offers from ' +
        $( '#originLocationCode' ).val() +
        ' to ' + $( '#destinationLocationCode' ).val() +
        ' departing on ' + $( '#departureDate' ).val() +
        ( ( $( '#returnDate' ).val() !== '' ) ? ( ' and returning on ' + $( '#returnDate' ).val() ) : '') +
        ' for ' + $( '#adults' ).val() +
        ' adult' + ( $( '#adults' ).val() > 1 ? 's.' : '.' ) +
        '</p>';
  content += '<table>';
  content += '<tr><th>ID</th><th>Departure Place</th><th>Departure Time</th><th>Arrival Place</th><th>Arrival Time</th><th>Flight No</th><th>Duration</th><th>Total Price</th></tr>';
  $.each( responseObj.data, function( idx, data ) {
    var id = data.id;
    var currency = data.price.currency;
    var total = data.price.total;
    var segment_count = 0;
    $.each( data.itineraries, function( idx, itinerary ) {
      $.each( itinerary.segments, function( idx, segment ) {
        var departure_from = segment.departure.iataCode;
        var departure_time = segment.departure.at;
        var arrival_at = segment.arrival.iataCode;
        var arrival_time = segment.arrival.at;
        var carrierCode = segment.carrierCode;
        var number = segment.number;
        var duration = segment.duration;
        content += '<tr>';
        content += '<td>' + ( ( segment_count === 0 ) ? id : '' ) + '</td><td>';
        content += departure_from + '</td><td>' +
                    departure_time + '</td><td>' +
                    arrival_at + '</td><td>' +
                    arrival_time + '</td><td>' +
                    carrierCode + ' ' + number +
                    '</td><td>' +
                    duration + '</td>';
        content += '<td>' + ( ( segment_count === 0 ) ? currency + ' ' + total : '' ) + '</td><td>';       
        content += '</tr>';	
        segment_count++;
      })
    })
  })
  content += '</table>';
  $( '#response' ).html( content );
})

Once it’s complete, the amadeus-flight-offers-search.js file should contain the following code:

jQuery(function($){
  $( "#departureDate" ).datepicker( { dateFormat: "yy-mm-dd" } );
  $( "#returnDate" ).datepicker( { dateFormat: "yy-mm-dd" } );
  $( "#flight_offers_request_form" ).submit( function( event ) {
    event.preventDefault();
    $( "#response" ).html( '' );
    $.ajax({
        url: ajax_object.ajax_url,
        type: "post",
        dataType: 'JSON',
        data: $( this ).serialize(),
    })
    .done ( function( response ){
      var responseObj = $.parseJSON( response );
      var content = '';
      content += '<p>Flight offers from ' +
            $( '#originLocationCode' ).val() +
            ' to ' + $( '#destinationLocationCode' ).val() +
            ' departing on ' + $( '#departureDate' ).val() +
            ( ( $( '#returnDate' ).val() !== '' ) ? ( ' and returning on ' + $( '#returnDate' ).val() ) : '') +
            ' for ' + $( '#adults' ).val() +
            ' adult' + ( $( '#adults' ).val() > 1 ? 's.' : '.' ) +
            '</p>';
      content += '<table>';
      content += '<tr><th>ID</th><th>Departure Place</th><th>Departure Time</th><th>Arrival Place</th><th>Arrival Time</th><th>Flight No</th><th>Duration</th><th>Total Price</th></tr>';
      $.each( responseObj.data, function( idx, data ) {
        var id = data.id;
        var currency = data.price.currency;
        var total = data.price.total;
        var segment_count = 0;
        $.each( data.itineraries, function( idx, itinerary ) {
          $.each( itinerary.segments, function( idx, segment ) {
            var departure_from = segment.departure.iataCode;
            var departure_time = segment.departure.at;
            var arrival_at = segment.arrival.iataCode;
            var arrival_time = segment.arrival.at;
            var carrierCode = segment.carrierCode;
            var number = segment.number;
            var duration = segment.duration;
            content += '<tr>';
            content += '<td>' + ( ( segment_count === 0 ) ? id : '' ) + '</td><td>';
            content += departure_from + '</td><td>' +
                        departure_time + '</td><td>' +
                        arrival_at + '</td><td>' +
                        arrival_time + '</td><td>' +
                        carrierCode + ' ' + number +
                        '</td><td>' +
                        duration + '</td>';
            content += '<td>' + ( ( segment_count === 0 ) ? currency + ' ' + total : '' ) + '</td><td>';       
            content += '</tr>';	
            segment_count++;
          })
        })
      })
      content += '</table>';
      $( '#response' ).html( content );
    })
    .fail(function( jqXHR, textStatus ) {
        $( "#response" ).html( '<p>' + jqXHR.responseText + '</p>' );
    })
  })
});

Finally, launch the WordPress post or page containing the added [amadeus-flight-offers-search] tag, enter the trip details into the web form and click the search button. In this example, the trip is for two adults from SIN (Singapore) to BKK (Bangkok), departing on 2020-08-14 and returning on 2020-08-17. You will then see a list of flight offers found for the trip displayed in a table, like so:

Conclusion

In this two-part series, you built and tested a WordPress plugin using the Amadeus Flight Offers Search API and with a small amount of code, were able to add basic flight search data to WordPress. This is just the start of what’s possible. All of the lessons learned in this series can easily be used to integrate other Amadeus Self-Service APIs with WordPress.

This article was originally published on Amadeus’s blog.

How to work with us

  • Contact us to set up a call.
  • We will analyze your needs and recommend a content contract solution.
  • Sign on with ContentLab.
  • We deliver topic-curated, deeply technical content to you.

To get started, complete the form to the right to schedule a call with us.

Send this to a friend