Статьи

Создайте собственный API для соединения WordPress с Ruby on Rails

Конечный продукт
Что вы будете создавать

Когда-то веб-приложения были монолитами, которые все делали сами. В наши дни не так уж и много. С веб-сервисами, открывающими свои API, разработчики переходят на использование сторонних приложений для обработки части функциональных возможностей, таких как аутентификация или отправка электронных писем пользователям.

Хотя наиболее распространенным случаем является случай, когда вы используете API для подключения к одной из популярных онлайн-служб (Google, Twitter и т. Д.), Бывают случаи, когда оба приложения, которые вы хотите подключить, являются вашими собственными.

Это случилось со мной некоторое время назад: я создал собственную корзину для покупок в качестве приложения Ruby on Rails и какое-то время был рад использовать ее вместе с простой HTML-страницей. Однако через некоторое время я обнаружил, что для того, чтобы сделать целевую страницу более привлекательной, мне нужно было обновить ее до более часто обновляемого. Я хотел блог, и поэтому WordPress был естественным выбором.

С созданным сайтом WordPress все было хорошо, за исключением одной мелочи: когда посетители добавляли товары в корзину, а затем возвращались за покупками, они забывали, что добавили товары в корзину! Корзина и веб-сайт должны работать вместе. Мне нужно было отобразить содержимое корзины на главном веб-сайте.

Это было место для разработки API.

Познакомившись с API-интерфейсом корзины для покупок, а затем вызвав его из моей темы WordPress, я смогу элегантно передать данные, не взломав ни одну из систем.

В этом руководстве, основываясь на уроках, извлеченных из этого проекта, я рассмотрю оба конца взаимодействия API: во-первых, с помощью гема Grape мы создадим API для предоставления части Ruby on Rails корзина для внешних приложений. Затем мы будем использовать API для получения содержимого корзины покупок и отображения его на сайте WordPress. В зависимости от ваших потребностей, вы можете обнаружить, что создание API — это то, что вас интересует или что вы на самом деле просто заинтересованы в части о вызове внешнего API из WordPress. В любом случае, я надеюсь, вы найдете этот урок полезным и интересным.

Для запуска кода в этом руководстве вам понадобится следующая настройка:

  • Ruby on Rails версия 3.2
  • PHP 5.3
  • cURL и его библиотеки PHP / Apache

Хотя в этом уроке нет ничего сложного, требуется базовое понимание Ruby и Ruby on Rails, а также PHP и WordPress.

Поскольку вы планируете подключить приложение Ruby on Rails к веб-сайту на платформе WordPress, вероятно, можно с уверенностью предположить, что у вас уже есть приложение Rails — и, возможно, даже сайт WordPress — и оно работает. Итак, для нужд учебника я создал упрощенную, но функциональную версию корзины покупок с методами для основных действий, необходимых на месте.

Вы можете скачать пример кода или просто прочитать учебник и применить его к собственному проекту Rails.

В качестве примера проекта Ruby on Rails можно использовать только модель ( ShoppingCart ) и контроллер ( ShoppingCartController ). В модели ShoppingCart вы найдете следующие методы:

  • find_or_create_with (token): этот статический метод ищет и возвращает объект корзины покупок с указанным идентифицирующим токеном. Если он не найден (или токен не указан), новая корзина покупок создается и возвращается.
  • токен: этот метод возвращает токен, идентифицирующий текущий объект корзины покупок.
  • as_json: этот метод возвращает содержимое корзины покупок в виде строки в формате JSON.

Контроллер ShoppingCartController содержит действие для добавления товаров в корзину. Действие add принимает два параметра: token и id (продукта):

http://<SERVER_PATH>/shopping_cart/add/<id>?token=<token>

Мы вернемся ко всем этим позже, но теперь давайте приступим к работе и создадим API для корзины покупок.

Теперь, когда проект Rails уже готов, пришло время приступить к созданию API.

Для создания нашего API мы будем использовать инструмент под названием Grape . Grape — это микро-фреймворк, предназначенный для реализации простых API-интерфейсов, подобных REST, в ситуациях, когда, как говорят разработчики, «вам не нужны тяжелые возможности больших фреймворков, таких как Rails».

Платформа Grape может использоваться сама по себе, но она также отлично подходит для Rails, предоставляя простой способ создания API для доступа к подмножеству (или почему не ко всем) функциональных возможностей вашего приложения Rails. Именно это мы и собираемся делать в этом уроке.

Чтобы добавить гем в ваш проект Rails, добавьте следующую строку в ваш Gemfile :

1
gem ‘grape’

Затем обновите ваши драгоценные камни, позвонив (в командной строке):

1
bundle install

Вот и все. Драгоценный камень был установлен, и мы можем начать использовать его.

Чтобы начать писать API, сначала нужно создать исходный файл ruby, который будет содержать функциональность API. Это облегченный фреймворк, и поэтому мы можем написать весь API в одном файле. Поместите этот файл в приложение Rails, в каталог с именем api прямо в главном каталоге app .

В примере проекта вы найдете код API в app/api/cart_external.rb .

Добавьте следующие строки в файл конфигурации application.rb чтобы убедиться, что файлы в app/api включены:

1
2
config.paths.add «app/api», glob: «**/*.rb»
config.autoload_paths += Dir[«#{Rails.root}/app/api/*»]

Внутри исходного файла API мы теперь определим модуль, который будет содержать наш класс API:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
module CartExternal
 
  class API < Grape::API
    version ‘v1’, :using => :path
    format :json
 
    helpers do
    end
 
    resource :cart do
    end
  end
 
end

Это самая голая версия содержимого простого Grape API. На данный момент он еще ничего не делает, но давайте посмотрим на элементы конфигурации в начале кода внутри класса.

  • Во-первых, строка version 'v1', :using => :path указывает, что это версия API v1 и что версия, к которой хочет обратиться пользователь API, должна быть определена в URL-адресе, например http: // localhost: 3000 / v1 / . Другие опции для этого поля конфигурации :header :accept_version_header и :param , каждый из которых определяет свой метод передачи информации о версии. См. Документацию Grape для получения дополнительной информации об использовании каждого из них.
  • format :json указывает Grape кодировать исходящие ответы в виде строк в формате JSON (также можно использовать :txt и :xml ).

Прежде чем мы начнем добавлять функциональность к API, в качестве заключительного шага настройки объявите класс API в вашем приложении Rails, чтобы он знал, как обслуживать его людям и службам, запрашивающим его.

Для этого добавьте следующую строку в config/routes.rb :

1
mount CartExternal::API => ‘/’

Теперь вернемся к CartExternal::API мы определили выше.

Внутри класса API вы найдете два элемента, которые я еще не упомянул: helpers и resource .

  • helpers — это макрос, который можно использовать вместе с блоком (или модулем) для представления вспомогательных методов, которые затем можно использовать в действиях API. Эти методы могут быть, например, помощниками, необходимыми для проверки параметров API или методов для связи с родительским приложением Rails.
  • resource определяет логическую коллекцию методов API. Вы можете добавить столько, сколько захотите, но в нашем случае мы справимся только с одним, который мы назовем :cart . Этот ресурс будет содержать все методы API, связанные с корзиной покупок. С этими определениями любые вызовы, сделанные к http://<APPLICATION_PATH>/v1/cart будут перенаправлены на наш ресурс и действия, определенные внутри него.

Чтобы увидеть, как это работает, давайте начнем с создания вызова API для извлечения товаров из корзины покупок, идентифицируемых маркером параметра.

Внутри блока resources добавьте следующий код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
desc ‘Return items in cart.’
params do
  optional :token, type: String, default: nil
end
get ‘/items’ do
  token = params[:token]
   
  cart = ShoppingCart.find_or_create_with token
 
  response = {
    status: 200,
    token: cart.token,
    cart: cart.as_json
  }
 
  response.as_json
end

Теперь мы создали действие, которое отвечает на запросы GET, отправленные на путь /items .

Действие принимает один необязательный строковый параметр token , объявленный в блоке params . Хотя объявление параметров не является обязательным, это хорошая практика, поскольку это делает ваш код более читабельным, а также экономит ваше время, поскольку Grape выполнит большую часть проверки параметров за вас. Для обязательных параметров вы можете использовать аналогичную конструкцию, заменив необязательную на require. Обязательные параметры не могут иметь значения по умолчанию.

Наше действие ищет корзину покупок, которая соответствует токену или создает новую, если токен не передан. Затем он возвращает закодированный в JSON ответ, который состоит из статуса, фактического токена корзины покупок и содержимого корзины покупок.

Если вы запускаете приложение Rails локально, теперь вы можете запустить свой сервер и указать браузеру на http: // localhost: 3000 / v1 / cart / items, чтобы увидеть ответ, который должен выглядеть примерно так:

1
{«status»:200,»token»:»XBrf2nCkTYfQJoU8d4A1nw»,»cart»:{«item_count»:0,»items»:[]}}

Поскольку мы не передавали токен в нашем звонке, была создана новая корзина покупок, которой было присвоено случайно сгенерированное уникальное значение токена. Вот почему корзина еще пуста.

Если вы хотите, для тестирования вы можете использовать действие add в ShoppingCartController чтобы добавить товар в корзину:

HTTP: // локальный: 3000 / shopping_cart / добавить / 1 маркер = TOKEN_FROM_PREVIOUS_CALL

После добавления продукта при повторном вызове API вы заметите, что теперь в корзине есть товар:

{"status":200,"token":"XBrf2nCkTYfQJoU8d4A1nw","cart":{"item_count":1,"items":[{"cart_id":2,"created_at":"2014-05-20T16:44:24Z","id":4,"product_id":1,"product_name":"Test Product","product_price":"10.0","updated_at":"2014-05-20T16:44:24Z"}]}}

Добавьте столько элементов, сколько захотите, а затем, прежде чем добавлять какие-либо дополнительные функции, давайте завершим настройку и поговорим с API WordPress.

Теперь мы проверили API, вызвав его из веб-браузера, и затем пришло время заставить WordPress общаться с ним.

Следующий код WordPress может быть включен либо в плагин WordPress, либо в файл functions.php темы WordPress, в зависимости от вашего проекта и контекста, где необходима связь API. В своей интеграции с корзиной для покупок я решил добавить код в дочернюю тему для простоты.

Какой бы путь вы ни выбрали, код будет одинаковым.

Откройте файл functions.php (или подходящий PHP-файл плагина) и вставьте следующую функцию PHP. Это вспомогательная функция, которая инкапсулирует связь API, так что в будущем, если вам потребуется изменить сигнатуру API или другие общие элементы в вызовах, вы можете сделать это в одном месте.

Вот голые кости того, что должно быть в этой функции:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function api_get_as_json( $action, $params ) {
 
    $api_endpoint = «http://localhost:3000/v1/cart»;
 
    if ( null == $params ) {
        $params = array();
    }
 
    // Create URL with params
    $url = $api_endpoint .
 
    // Use curl to make the query
    $ch = curl_init();
 
    curl_setopt_array(
        $ch, array(
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true
        )
    );
 
    $output = curl_exec($ch);
 
    // Decode output into an array
    $json_data = json_decode( $output, true );
 
    curl_close( $ch );
 
    return $json_data;
}

Функция принимает путь к действию API и необходимые параметры, объединяет их в URL и затем использует cURL для запроса к API.

После получения ответа функция анализирует его в массив, используя json_decode , которая является частью стандартных библиотек PHP.

Теперь, когда мы создали функциональность для вызова API, давайте использовать его для запроса содержимого корзины покупок через наш метод API /cart/items а затем распечатаем ответ:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function show_shopping_cart() {
    $cart_data = api_get_as_json(‘/items’, null);
?>
    <div class=»shopping-cart»>
        <h3>Shopping Cart</h3>
        <ul>
        <?php if (isset($cart_data[«cart»][«items»])
                    && $cart_data[«cart»][«items»].length > 0) : ?>
 
            <?php foreach ($cart_data[«cart»][«items»] as $item) : ?>
                <li>
                    <?php echo $item[«product_name»];
                    $<?php echo $item[«product_price»];
                </li>
            <?php endforeach;
 
        <?php else : ?>
 
            Your shopping cart is empty.
 
        <?php endif;
        </ul>
    </div>
     
    <div style=»margin-top: 20px;»>
        <pre style=»font-size: 8pt;»><?php print_r($cart_data);
    </div>
<?php
}

Функция выполняет вызов API для /items и выводит ответ с некоторым базовым форматированием HTML. В конце функции я включил простой блок print_r для визуализации содержимого ответа JSON для целей отладки.

Это полезно, особенно в начале, когда корзина еще пуста, и мы хотим убедиться, что нет ошибок связи, мешающих коду показать его содержимое.

Теперь, когда у нас есть функции для выполнения вызова и распечатки ответа, остается только заставить WordPress вызывать их.

Самый простой способ сделать это — перейти прямо к файлам шаблонов темы и просто вызвать show_shopping_cart прямо там, где вы хотите показать корзину. Если тема ваша и вы уверены, что это все, что вам нужно, это может быть приемлемым вариантом.

На другом конце спектра находится наиболее гибкий и удобный для пользователя способ встраивания вызова в виджет WordPress. Таким образом, вы можете перемещать корзину покупок и размещать ее в любой области боковой панели на своем сайте WordPress. Это не так сложно, так что давайте продолжим и сделаем это.

Все, что нам нужно, это WP_Widget с конструктором и некоторым кодом для отображения содержимого корзины в widget функции. Две другие функции, form и options можно пока оставить пустыми (если вы хотите добавить настройку в виджет, это то, куда он пойдет).

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class ShoppingCartWidget extends WP_Widget {
 
    public function __construct() {
        parent::__construct(
            ‘shopping_cart_widget’,
            __( ‘Shopping Cart Widget’, ‘shopping_cart’ ),
            array( ‘description’ => __( ‘A widget for displaying a shopping cart.’, ‘shopping_cart’ ) )
        );
    }
 
    /**
     * Outputs the content of the widget
     */
    public function widget( $args, $instance ) {
        echo $args[‘before_widget’];
 
        show_shopping_cart();
 
        echo $args[‘after_widget’];
    }
 
    /**
     * Outputs the options form.
     */
    public function form( $instance ) {
        // The widget takes no options
    }
 
    /**
     * Processing widget options on save
     */
    public function update( $new_instance, $old_instance ) {
        // The widget takes no options
    }
     
}
 
function register_shopping_cart_widget() {
    register_widget( ‘ShoppingCartWidget’ );
}
add_action(‘widgets_init’, ‘register_shopping_cart_widget’);

Теперь перейдите к администратору WordPress и перетащите виджет Корзина покупок на одну из боковых панелей:

Теперь посетите сайт WordPress, чтобы увидеть код в действии. Вы должны увидеть что-то вроде этого:

Ваша корзина покупок все еще пуста, но, как вы можете видеть из вывода print_r под print_r покупок, связь работает, и блог WordPress получает данные из нашего приложения Rails.

Теперь, с основами, рассмотрим, как сделать общение более безопасным.

Теперь мы создали API для приложения Ruby on Rails и вызвали его с сайта WordPress; Тем не менее, по-прежнему не хватает чего-то важного: обеспечения безопасности API, чтобы в Интернете не все могли звонить так, как им нравится. Я уверен, что вы можете вспомнить все виды плохих вещей, которые могут случиться, если вы оставите дверь полностью открытой для всех, верно?

Простой способ защитить API — это сгенерировать секретный ключ для каждого приложения, которое вы можете вызывать для своего API. Таким образом, всякий раз, когда приложение выполняет запрос к API, оно должно отправить свой ключ API для проверки сервером. Абоненты без действительного ключа API не смогут отправлять запросы. Для дополнительной безопасности большинство служб также включают в себя API-ключ в дополнение к API-ключу.

Итак, давайте вернемся к работе и добавим ключ API, сначала в наш код Ruby, а затем на стороне WordPress.

Сначала добавьте метод проверки ключа API. Этот идет в блоке helpers вашего класса API:

1
2
3
def is_valid_api_key?(key)
  key == ‘API_KEY’
end

Это простая версия с одним ключом API, поэтому в зависимости от вашего приложения вам может потребоваться его расширение. Например, если у вас есть несколько приложений, вызывающих API, вам необходимо определить уникальный ключ API для каждого из них и сохранить их в базе данных. Вы также можете создать страницу администратора для создания новых ключей API.

По крайней мере, вам нужно заменить API_KEY реальным сгенерированным ключом, который не так просто угадать. Однако для этого примера все, что имеет значение, это то, что у вас есть ключ API и метод для проверки того, что переданный ключ совпадает с ключом, хранящимся в системе.

Имея вспомогательный метод, мы можем добавить проверку к нашему единственному вызову API, окружив код в нем следующей конструкцией if...else :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
if is_valid_api_key?
  token = params[:token]
 
  cart = ShoppingCart.find_or_create_with token
 
  response = {
    status: 200,
    token: cart.token,
    cart: cart.as_json
  }
 
  response.as_json
else
  error!(‘401 Unauthorized’, 401)
end

Обратите внимание на блок else где мы вызываем ошибку, используя метод Grape error! ,

Теперь перезапустите сервер Rails и перезагрузите домашнюю страницу WordPress, и вы увидите что-то вроде этого:

Это потому, что мы еще не добавили ключ API в наш код WordPress, и поэтому Rails API больше не принимает запросы, которые он делает. Если вам нравится, на данный момент вы можете добавить некоторую правильную обработку ошибок и отобразить хорошее сообщение об ошибке.

Затем давайте продолжим и сделаем вызов API снова.

Сейчас вы можете просто api_get_as_json код API в функции api_get_as_json , но добавление новых параметров на страницу общих настроек WordPress очень просто, давайте сделаем это через поле настроек.

И, добавляя его, мы также можем добавить опцию для определения URL для API.

Таким образом, позже, когда вы развернете код WordPress на реальном сервере, вы сможете настроить его, не касаясь кода — что всегда хорошо.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
$cart_api_settings_field = new CartApiSetting();
 
class CartApiSetting {
    function CartApiSetting() {
        add_filter( ‘admin_init’, array( $this , ‘register_fields’ ) );
    }
 
    function register_fields() {
        register_setting( ‘general’, ‘cart_api_key’, ‘esc_attr’ );
 
        add_settings_field( ‘cart_api_key’,
             ‘<label for=»cart_api_key»>’ .
              array( $this, ‘fields_html’ ) , ‘general’ );
    }
 
    function fields_html() {
        $value = get_option( ‘cart_api_key’, » );
        echo ‘<input type=»text» id=»cart_api_key» name=»cart_api_key» value=»‘ . $value . ‘» />’;
    }
}

Вот определение поля настроек для URL-адреса конечной точки API с использованием той же конструкции:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
$cart_api_endpoint_settings_field = new CartApiEndpointSetting();
 
class CartApiEndpointSetting {
    function CartApiEndpointSetting() {
        add_filter( ‘admin_init’, array( $this, ‘register_fields’ ) );
    }
 
    function register_fields() {
        register_setting( ‘general’, ‘cart_api_endpoint’, ‘esc_attr’ );
 
        add_settings_field( ‘cart_api_endpoint’,
             ‘<label for=»cart_api_endpoint»>’ .
              array( $this, ‘fields_html’ ) , ‘general’ );
    }
 
    function fields_html() {
        $value = get_option( ‘cart_api_endpoint’, » );
        echo ‘<input type=»text» id=»cart_api_endpoint» name=»cart_api_endpoint» value=»‘ . $value . ‘» />’;
    }
}

Зайдите в меню общих настроек WordPress, чтобы установить правильные значения этих настроек, убедившись, что ключ API совпадает с тем, что вы установили в своем сервисе Rails.

Теперь, когда ключ API и URL-адрес хранятся в настройках WordPress, давайте обновим функцию, которая выполняет вызов API.

Изменения идут в начале функции, например так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
function api_get_as_json($action, $params) {
 
    if ( null == $params ) {
        $params = array();
    }
 
    $api_key = get_option( «cart_api_key» );
    $api_endpoint = get_option( «cart_api_endpoint» );
 
    if ( ! isset( $api_key ) || ! isset( $api_endpoint ) ) {
        return false;
    }
 
    $params[«key»] = $api_key;
     
}

Глядя на новый код выше, вы заметите, что $api_key и $api_endpoint читаются из опций WordPress. $api_endpoint уже использовался для создания URL-адреса для вызова, но для $api_key нам нужно добавить строку (14), чтобы включить значение в параметры, отправляемые в API.

Обновите домашнюю страницу WordPress, и содержимое корзины покупок снова появится, на этот раз с помощью ключа API. Все выглядит хорошо — на самом деле, так же, как и раньше, требуя ключ API — и вы подключили приложение Rails к своему сайту WordPress.

Код WordPress, который мы написали до сих пор, выполняет вызовы API и защищает их с помощью ключа API, но делает это полностью без сохранения состояния. Для простых действий без сохранения состояния, таких как публикация обновлений на доске объявлений или в вашем собственном Твиттере, таких как платформа микроблогов, вам достаточно однократных звонков. Однако для нашего примера корзины покупок этого недостаточно.

Как вы заметили при тестировании кода, в то время как наш сервер Rails идентифицирует корзину покупок с помощью токена, мы нигде не использовали этот токен, поэтому каждый раз, когда осуществляется вызов cart/list , сервер создает новую пустую корзину покупок. ,

Не очень хорошо. Чтобы подключение к корзине покупок имело какой-либо смысл, вам нужно иметь возможность добавлять элементы в корзину и сохранять их там некоторое время, даже если вы переходите с одной страницы на другую.

Одним словом, вам нужен сеанс.

Существует несколько способов создать сеанс, но давайте перейдем к самому простому: использовать токен, переданный нам приложением Rails, и сохранить его в файле cookie клиента. Поскольку ваш сайт WordPress является интерфейсом, который пользователь (и его веб-браузер) видит и общается с ним, нам также необходимо установить cookie.

Файлы cookie могут быть установлены только в заголовке до того, как какой-либо контент будет отображен, поэтому нам нужно сделать некоторую перестановку в коде, перемещая вызов /cart/items в потоке выполнения. Чтобы сделать это, давайте создадим новую функцию PHP, get_shopping_cart , и вызовем ее прямо в начале выполнения сайта WordPress.

Это можно сделать с помощью хуков действий WordPress. Полный список хуков вы можете найти в Кодексе WordPress . В этом случае действие init делает то, что нам нужно, поэтому давайте подключим наш запрос к этому.

add_action( "init", "get_shopping_cart" );

Сама функция get_shopping_cart выглядит так:

01
02
03
04
05
06
07
08
09
10
function get_shopping_cart() {
 
    $cart_data = api_get_as_json( ‘/items’, null );
    $token = $cart_data[‘token’];
 
    // Expire cookie in 30 minutes
    setcookie( ‘bread_cart’, $token, time() + 60 * 30 );
    set_saved_cart_data( $cart_data );
     
}

Во-первых, функция делает уже знакомый вызов нашему действию API /items . Затем у нас появляется что-то новое: в строке 3 мы извлекаем токен корзины покупок, возвращенный API, а затем, несколькими строками позже, сохраняем его в файле cookie. Срок действия файла cookie истекает через 30 минут, так как я предполагаю, что кто-то, делающий покупки в интернет-магазине, к тому времени забудет о магазине …

В строке 7 вы можете заметить еще один новый вызов функции: set_saved_cart_data . Мы вернемся к этому через минуту. Но сначала давайте сделаем так, чтобы вызовы API тоже использовали токен.

Сначала давайте создадим вспомогательную функцию для извлечения токена из cookie:

01
02
03
04
05
06
07
08
09
10
function api_shopping_cart_token() {
 
    $token = null;
 
    if ( isset( $_COOKIE[‘shopping_cart_token’] ) ) {
        $token = $_COOKIE[‘shopping_cart_token’];
    }
 
    return $token;
}

А затем, используя эту функцию, добавьте следующую строку в api_get_as_json , сразу после строки, где мы устанавливаем параметр ключа API:

1
$params[‘token’] = api_shopping_cart_token();

Благодаря этому добавлению каждый раз, когда выполняется вызов API, метод api_get_as_json ищет токен корзины покупок в api_get_as_json cookie и добавляет его в параметры запроса. Если файл cookie не найден, API получит пустой токен и будет рассматривать вызов как нового посетителя, создавая новую пустую корзину.

А теперь вернемся к set_saved_cart_data .

Как мы заметили в приведенном выше коде, get_shopping_cart получает все содержимое корзины покупок — те самые данные, которые мы запрашиваем в show_shopping_cart . Это означает, что мы вызываем API дважды на одной странице рендеринга WordPress, когда достаточно одного вызова. Сохранение ответа для продолжительности HTTP-запроса — это простая оптимизация, которую мы можем использовать, чтобы сократить количество вызовов API до половины.

В PHP глобальные переменные относятся только к одному HTTP-запросу и проходят через него, поэтому мы можем безопасно использовать один для хранения данных из get_shopping_cart до точки, где они используются для фактического отображения содержимого корзины покупок.

Для этого я создал простую пару функций set_saved_cart_data и get_saved_cart_data , которые обертывают глобальную переменную $g_shopping_cart_data чтобы сделать код читабельным и простым в обслуживании:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
global $g_shopping_cart_data;
 
function set_saved_cart_data( $cart_data ) {
 
    global $g_shopping_cart_data;
    $g_shopping_cart_data = $cart_data;
     
}
 
function get_saved_cart_data() {
 
    global $g_shopping_cart_data;
    return $g_shopping_cart_data;
     
}

Когда данные корзины покупок хранятся в глобальной переменной, все, что вам нужно сделать, это изменить первую строку в show_shopping_cart на:

1
$cart_data = get_saved_cart_data();

После внесения этого изменения в корзине покупок теперь есть сеанс, и пользователь может добавлять товары в корзину и перемещаться между страницами, все еще видя ту же корзину.

Чтобы проверить функциональность, давайте создадим ссылку на действие контроллера shopping_cart/add и распечатаем ее в конце show_shopping_cart . Обратите внимание, что для того, чтобы контроллер разделил наш сеанс, ему также нужен токен корзины покупок в качестве параметра:

1
2
3
4
5
6
$product_id = 1;
 
$token_params = http_build_query(array(‘token’ => api_shopping_cart_token()));
$url = «http://localhost:3000/shopping_cart/add/» .
 
echo ‘<p><a href=»‘ . $url . ‘»>Add test item to cart</a></p>’;

Нажмите на ссылку, Добавить тестовый товар в корзину , чтобы добавить товар. Затем вернитесь на свой сайт WordPress, и теперь вы можете увидеть товар из корзины покупок в блоге WordPress!

Вот и все: вы успешно подключили корзину покупок на основе Ruby on Rails к своему блогу WordPress или веб-сайту.

Удалите отладку print_r , print_r вывод с помощью некоторого CSS и создайте несколько реальных ссылок «Добавить в корзину» (а также кнопку «Оформить заказ», которая возвращает пользователя к реальному приложению корзины покупок), и вы получаете полностью функциональные покупки интеграция корзины.

Что еще более важно, однако, вы можете использовать метод создания и возврата к API, чтобы связать два ваших собственных приложения. Они могут быть чем угодно, так что теперь, давайте создавать API-интерфейсы!