Create a WordPress Plugin

Share your feedback
Reach out to us with feedback and suggestions to improve the Wix Headless experience, and join the Headless channel of the Devs on Wix Discord community to discuss features and connect with our growing community of developers.

WordPress is a common web content management platform that allows users to build, maintain, and publish web pages. Wix Headless allows you to integrate many of Wix's business solutions into your WordPress site.

This tutorial shows you how to create a WordPress plugin that integrates your Wix Headless project with your WordPress site. It includes implementing a "Buy Now" flow that allows your visitor to purchase a product from a list.

You can find the full source code here.

In this tutorial, you will:

  1. Set up a Wix Headless project and a WordPress environment.
  2. Create a script to rebuild your plugin whenever you update it.
  3. Create a full authorization flow that allows your WordPress site to make requests to your Headless project and Wix APIs.
  4. Query and display a dynamic list of products on your WordPress site using the Wix Stores API.
  5. Implement a secured checkout functionality using the Wix eCommerce API.
  6. Implement the necessary routing functionality using the Wix Redirect Session API.

Step 1: Set up the Wix headless project

First, set the Wix Headless project to act as your site's dashboard. Here you can install apps to add Wix functionality to your WordPress site.

To set up the Wix Headless project, follow these steps:

  1. If you haven't already, create a Wix Headless project. When prompted to add functionalities to your new project, select eCommerce.

  2. Set up authorization by creating and configuring an OAuth app on your Headless project. Name the app wix_example_client_id. Note your client ID. You will need it later to integrate your WordPress site with the Wix Headless project.

  3. Finally, make sure that the Wix Stores app is installed: In your Headless project dashboard, click Apps. If the Wix Stores app is not installed, install it. This Wix Stores app allows your WordPress site to access the Wix Stores API.

Step 2: Set up a WordPress plugin

A WordPress plugin is a zip file that contains one or more PHP files. These files contain the functionality you want to add to your site with some metadata. This step describes how to write a script that automatically creates a zip file with your updated plugin files.

Create a script to automatically build your plugin file

This script builds your code as a zip file. The script is written in JavaScript in a node.js environment. However, you can use any build tool and runtime environment you prefer.

Create the plugin zip file:

  1. Create a new folder named headless-wordpress-tutorial. This folder will contain all the plugin files, including the build script and the finalized zip plugin file.

  2. In this folder, create a new file named wix-headless-example.php. In it, add the following code:

    Copy
    1
    <?php
    2
    namespace HeadlessExample;
    3
    4
    /**
    5
    * Plugin Name: Wix Headless Tutorial: Writing a WordPress Plugin
    6
    * Description: This tutorial describes how to write a WordPress plugin that integrates the WordPress site with Wix Headless.
    7
    * Version: 1.0.0
    8
    * Author: Wix Headless
    9
    * Author URI: https://www.wix.com/developers/headless
    10
    */
    11
    class WixHeadlessPlugin
    12
    {
    13
    public function __construct()
    14
    {
    15
    }
    16
    }
    17
    18
    $WixHeadlessPlugin = new WixHeadlessPlugin();

    This serves as the basis for the plugin's functionality.

  3. In the same headless-wordpress-tutorial folder, create two new folders:

    • A folder named build, to contain the automated build script.
    • A folder named plugin, to contain the plugin's functionality.
  4. In build, create a new file named zip-plugin.js, and write the following code:

    Copy
    1
    const fs = require('fs');
    2
    const { exec } = require('child_process');
    3
    4
    const folderToDelete = 'dist';
    5
    const folderToCreate = 'dist';
    6
    const folderToZip = 'plugin';
    7
    const zipFilePath = 'dist/wix-headless-example.zip';
    8
    9
    // Delete thw "dist" folder, if it already exists
    10
    if (fs.existsSync(folderToDelete)) {
    11
    fs.rmSync(folderToDelete, { recursive: true });
    12
    }
    13
    14
    // Create an empty folder "dist"
    15
    fs.mkdirSync(folderToCreate);
    16
    17
    // Zip the contents of the "plugin" folder into "dist/plugin.zip"
    18
    exec(`zip -r ${zipFilePath} ${folderToZip}/*`, (error, stdout, stderr) => {
    19
    if (error) {
    20
    console.error(`Error: ${error.message}`);
    21
    return;
    22
    }
    23
    if (stderr) {
    24
    console.error(`stderr: ${stderr}`);
    25
    return;
    26
    }
    27
    console.log(`Folder ${folderToZip} has been zipped successfully into ${zipFilePath}`);
    28
    });

    This code removes any existing zip files, and generates a Wordpress-ready plugin.zip file, with all your plugin's functionality, in the dist folder. Whenever you add functionality to your plugin, you need to run the build script again, and upload the updated plugin.zip file to your Wordpress site.

Optional: Test your plugin on your WordPress site

To test whether the plugin is recognized and rendered correctly on your WordPress site, include a test shortcode:

  1. Update wix-headless-example.php with the following code:

    Copy
    1
    class WixHeadlessPlugin
    2
    {
    3
    public function __construct() {
    4
    add_shortcode('initial_shortcode', array($this, 'initial_shortcode'));
    5
    }
    6
    7
    public function initial_shortcode() {
    8
    return "Hello, this is a minimal WordPress plugin";
    9
    }
    10
    }
  2. From the headless-wordpress-tutorial root directory, type node build/zip-plugin.js to run the build script.

  3. On your site's WP Admin panel, click Plugins -> Add New -> Upload Plugin, and upload dist/zip-plugin.js to the site.

  4. Activate the plugin.

  5. Launch one of your site's pages and add a shortcode block with the content [initial_shortcode].

  6. Save and view the page to see the result.

  7. Once you've confirmed the plugin is rendered on your site, remove the code you added in Step 1.

Create a plugin settings page on your WordPress site

Once you have installed the OAuth app on your Wix Headless project dashboard, your Headless project is configured to provide services only to clients that carry the correct client ID.

To enable communication between your WordPress site and your Headless project, configure your site with the correct client ID as provided by the OAuth app in Step 1. However, since the WP Admin panel does not have a built-in settings page to enable it to integrate with Wix Headless, you need to manually create a plugin settings page.

To create a plugin settings page and configure it with the client ID:

  1. In the plugin folder, create a new folder named templates.

  2. In plugin/templates, create a new file named settings.php with the following code:

    Copy
    1
    <?php
    2
    ?>
    3
    4
    <div class="wrap">
    5
    <h2 style="display: none"></h2>
    6
    <?php
    7
    8
    ?>
    9
    <div id="Connect-OAuth" class="tabcontent">
    10
    <h2>Wix Headless</h2>
    11
    <form method="post" action="options.php">
    12
    <?php settings_fields('wix_headless_example_settings_group'); ?>
    13
    <?php do_settings_sections('wix-headless-example-settings'); ?>
    14
    <table class="form-table">
    15
    <tr style="vertical-align:top">
    16
    <th scope="row">Wix Client ID</th>
    17
    <td>
    18
    <input required type="text" name="wix_example_client_id" value="<?php echo esc_attr(get_option('wix_example_client_id')); ?>" />
    19
    </td>
    20
    </tr>
    21
    <!-- Add more settings fields here -->
    22
    </table>
    23
    <?php submit_button(); ?>
    24
    </form>
    25
    </div>
    26
    </div>

    This file creates the structure of the plugin's settings page.

  3. Add the plugin's settings page to your site's Admin panel. In wix-headless-example.php, add the following code:

    Copy
    1
    <?php
    2
    namespace HeadlessExample;
    3
    4
    class WixHeadlessPlugin
    5
    {
    6
    public function __construct() {
    7
    // Register the plugin's settings
    8
    add_action('admin_init', array($this, 'register_settings'));
    9
    10
    // Add the plugin's settings page
    11
    add_action('admin_menu', array($this, 'create_settings_page'));
    12
    }
    13
    14
    public static function register_settings() {
    15
    add_option('wix_example_client_id', ''); // Add your settings here
    16
    17
    // Register the settings
    18
    register_setting('wix_headless_example_settings_group', 'wix_example_client_id');
    19
    }
    20
    21
    // Create the plugin's settings page
    22
    public static function create_settings_page() {
    23
    add_options_page(
    24
    'Wix Headless Example Settings', // Define the page title
    25
    'Wix Headless Example', // Define the menu title
    26
    'manage_options', // Add the capability required to access the page
    27
    'wix-headless-example-settings', // Define menu slug
    28
    array(__CLASS__, 'render_settings_page') // Define callback function to render the page
    29
    );
    30
    }
    31
    32
    // Render the plugin's settings page on the site's Admin panel
    33
    public static function render_settings_page() {
    34
    $template = plugin_dir_path(__FILE__) . 'templates/settings.php';
    35
    if (file_exists($template)) {
    36
    include $template;
    37
    } else {
    38
    error_log('Wix Headless Example: Could not find settings template');
    39
    }
    40
    }
    41
    }
    42
    43
    $WixHeadlessPlugin = new WixHeadlessPlugin();

    This code creates, registers, and renders your plugin's settings page on your WordPress site's Admin panel.

    Lastly, on your WordPress site's Admin panel, set the client ID as it appears on your Headless project's OAuth settings app:

  4. On your WordPress site's Admin panel, click Settings > Wix Headless Example.

  5. In the Wix Client ID input field, paste the client ID as it appears on your Headless project's Headless Settings page.

    Your WordPress site is now configured as the valid client of your Wix Headless project.

Step 3: Generate authorization tokens

To access Wix APIs, a client needs to carry valid access tokens. These include the client ID as defined in Step 2. Access tokens are only valid for several hours. When they expire, they must be refreshed. Without a valid authorization token, a client cannot make requests to a Headless project.

This step shows how to add a simple authorization service to your plugin. The service retrieves and checks for valid access tokens, refreshes them if necessary, and saves, or persists, them locally to your browser as cookies.

Note: For additional information about creating and using access tokens, see the Making API Calls with OAuth in the Wix REST API reference.

Important: To keep this tutorial simple and easy to understand, this authorization service applies to all devices. You might want to handle access tokens separately for each type of device.

To create the authorization service:

  1. In your plugin folder, create a new folder named services. In it, create a new file named wix-auth.php and add to it the following code:

    Copy
    1
    <?php
    2
    namespace HeadlessExample\Services;
    3
    4
    class Auth
    5
    {
    6
    private static $tokens = null;
    7
    8
    public static function getTokens() {
    9
    return Auth::$tokens;
    10
    }
    11
    }

    This creates the basic structural outline of the authorization service.

  2. Add the functionality to retrieve, or get, any tokens that might already be locally saved in the form of a browser cookie:

    Copy
    1
    <?php
    2
    namespace HeadlessExample\Services;
    3
    4
    class Auth
    5
    {
    6
    // ...
    7
    8
    private static string $COOKIE_NAME = 'wix-headless-example-tokens';
    9
    10
    public static function getPersistedTokens() {
    11
    if (isset($_COOKIE[Auth::$COOKIE_NAME])) {
    12
    // Retrieve existing JSON data from the cookie
    13
    $jsonData = urldecode($_COOKIE[Auth::$COOKIE_NAME]);
    14
    15
    // Decode the JSON data
    16
    $decodedData = json_decode($jsonData, true);
    17
    18
    if ($decodedData !== null) {
    19
    // Return the decoded JSON data
    20
    return $decodedData;
    21
    } else {
    22
    // Debug: Print the JSON decoding error
    23
    error_log('Failed to decode JSON from the cookie.');
    24
    return null;
    25
    }
    26
    } else {
    27
    // Cookie not set or has expired
    28
    return null;
    29
    }
    30
    }
    31
    }

    This function checks and decodes any tokens that already exist in a user's browser. If no cookies are found, the function returns null.

  3. Add the functionality to persist tokens in the user's browser as cookies:

    Copy
    1
    <?php
    2
    namespace HeadlessExample\Services;
    3
    4
    class Auth
    5
    {
    6
    // ...
    7
    8
    public static function persistTokens(): void {
    9
    $jsonData = json_encode(Auth::$tokens);
    10
    $expiry = time() + 60 * 60 * 24 * 30; // Set token validity for 30 days
    11
    $path = '/'; // Cookies are available in the entire domain
    12
    $domain = '';
    13
    setcookie(Auth::$COOKIE_NAME, urlencode($jsonData), $expiry, $path, $domain, false, false);
    14
    }
    15
    }

    This function saves a token to a user's browser in the form of a cookie. Each token is valid for 30 days, and can be used to access all parts of the site.

  4. Add the functionality to check whether an access token has expired:

    Copy
    1
    <?php
    2
    namespace HeadlessExample\Services;
    3
    4
    class Auth
    5
    {
    6
    // ...
    7
    public static function isAccessTokenValid(): bool {
    8
    $currentDate = time();
    9
    return !!(Auth::$tokens['accessToken']['value'] ?? false) && Auth::$tokens['accessToken']['expiresAt'] > $currentDate;
    10
    }
    11
    }
  5. Use the Wix API to get and refresh tokens:

    Copy
    1
    <?php
    2
    namespace HeadlessExample\Services;
    3
    4
    class TokenRole
    5
    {
    6
    const VISITOR = 'visitor';
    7
    const MEMBER = 'member';
    8
    }
    9
    10
    class Auth
    11
    {
    12
    // ...
    13
    14
    // Convert the raw tokens to access tokens and refresh them
    15
    private static function rawTokensToTokensResult(array $raw_tokens): array {
    16
    return array(
    17
    'accessToken' => Auth::createAccessToken($raw_tokens['access_token'], $raw_tokens['expires_in']),
    18
    'refreshToken' => array(
    19
    'value' => $raw_tokens['refresh_token'],
    20
    'role' => TokenRole::VISITOR,
    21
    ),
    22
    );
    23
    }
    24
    25
    // Create an access token with an expiration date
    26
    private static function createAccessToken(string $accessToken, int $expiresIn): array {
    27
    $now = time();
    28
    return array(
    29
    'value' => $accessToken,
    30
    'expiresAt' => $expiresIn + $now,
    31
    );
    32
    }
    33
    34
    // Generate a visitor token using the Wix Token endpoint
    35
    public static function generateVisitorTokens(): array {
    36
    $client_id = get_option('wix_example_client_id');
    37
    if (!empty($client_id)) {
    38
    $token_request = Auth::$tokens['refreshToken'] && Auth::$tokens['refreshToken']['role'] == TokenRole::VISITOR ? array(
    39
    'refresh_token' => Auth::$tokens['refreshToken']['value'], 'grantType' => 'refresh_token', 'scope' => 'offline_access',
    40
    ) : array(
    41
    'clientId' => $client_id, 'grantType' => 'anonymous', 'scope' => 'offline_access',
    42
    );
    43
    44
    $response = wp_remote_post('https://www.wixapis.com/oauth2/token', array(
    45
    'method' => 'POST',
    46
    'headers' => array('Content-Type' => 'application/json'),
    47
    'body' => wp_json_encode($token_request),
    48
    'data_format' => 'body',
    49
    ));
    50
    51
    if (!is_wp_error($response) && $response['response']['code'] === 200) {
    52
    $body = wp_remote_retrieve_body($response);
    53
    $raw_tokens = json_decode($body, true);
    54
    return Auth::rawTokensToTokensResult($raw_tokens);
    55
    } else {
    56
    error_log('Failed to get tokens : Wix request ID: '.get_wix_request_id($response).' full response '.json_encode($response));
    57
    throw new \RuntimeException('Failed to get tokens');
    58
    }
    59
    } else {
    60
    return [];
    61
    }
    62
    }
    63
    }

    This code defines two types of tokens, one for site visitors and one for logged-in site members. Then, the generateVisitorTokens() function creates and processes visitor tokens using the Wix REST Token endpoint.

    These tokens are required to make calls to Wix APIs on behalf of your visitor. Without them, your calls will be not be authorized. You can read more about visitor tokens in the Wix Headless REST API documentation.

  6. Finally, now that tokens have been set up, set the authorization service to initialize as soon as your WordPress site initializes the plugin.

  7. Still in services/wix-auth.php, add the service initialization function:

    Copy
    1
    <?php
    2
    namespace HeadlessExample\Services;
    3
    4
    class Auth
    5
    {
    6
    // ...
    7
    public static function init(): void {
    8
    Auth::$tokens = Auth::getPersistedTokens();
    9
    if (!Auth::isAccessTokenValid()) {
    10
    Auth::$tokens = Auth::generateVisitorTokens();
    11
    Auth::persistTokens();
    12
    }
    13
    }
    14
    }

    This function checks for existing visitor tokens, and if none are found, creates and persists new ones. It makes sure that your site has valid tokens when making calls to Wix APIs.

  8. Back in wix-headless-example.php, bring the authorization service into the scope of the file:

    Copy
    1
    <?php
    2
    namespace HeadlessExample;
    3
    4
    use HeadlessExample\Services\Auth;
    5
    require_once plugin_dir_path(__FILE__) . 'services/wix-auth.php';
    6
    7
    // ...

    These use and require_once statements allow the functions in this file to access the functions defined in the authorization service.

  9. Finally, register and call the authorization service's initialization method:

    Copy
    1
    <?php
    2
    namespace HeadlessExample;
    3
    4
    use HeadlessExample\Services\Auth;
    5
    6
    require_once plugin_dir_path(__FILE__) . 'services/wix-auth.php';
    7
    8
    class WixHeadlessPlugin
    9
    {
    10
    public function __construct() {
    11
    // ...
    12
    add_filter('init', array($this, 'init'));
    13
    }
    14
    15
    // ...
    16
    17
    public static function init() {
    18
    Auth::init();
    19
    }
    20
    }
    21
    22
    $WixHeadlessPlugin = new WixHeadlessPlugin();

    The add_filter() function registers the init() function for the init WordPress hook. This means that, whenever the init WordPress hook fires, the local init() function runs and initializes the authorization service.

Step 4: Get Wix Request ID Returned by Wix APIs

Whenever a Wix API responds to a client request, a unique request ID is included in the response. This can be helpful if you need to contact Wix support for help. In this step, you will add a service to retrieve the request ID as returned by the Wix API.

To get the Wix request ID:

  1. In the plugin folder, create a new folder named utils. This folder will contain various utility services.

  2. In plugin/utils, create a new file named wix-request-id.php and add to it the following code:

    Copy
    1
    <?php
    2
    3
    function get_wix_request_id($response) {
    4
    $headers = wp_remote_retrieve_headers( $response );
    5
    return $headers['x-wix-request-id'] ?? 'Header not found';
    6
    }

    When called, this function extracts the Wix request ID from the given response, and returns it to the caller.

  3. Back in services/wix-auth.php, call the get_wix_request_id() method whenever an error is logged by the generateVisitorTokens() function:

    Copy
    1
    <?php
    2
    namespace HeadlessExample\Services;
    3
    4
    class Auth
    5
    {
    6
    // ...
    7
    public static function generateVisitorTokens(): array {
    8
    9
    // ...
    10
    if (!empty($client_id)) {
    11
    // ...
    12
    if (!is_wp_error($response) && $response['response']['code'] === 200) {
    13
    // ...
    14
    } else {
    15
    error_log('Failed to get tokens : Wix request ID: '.get_wix_request_id($response).' full response '.json_encode($response));
    16
    throw new \RuntimeException('Failed to get tokens');
    17
    }
    18
    } else {
    19
    // ...
    20
    }
    21
    }
    22
    }

    Adding a call to get_wix_request_id() whenever tokens have failed to generate makes it easier to debug, resolve errors, and request additional help from Wix's support teams.

Step 5: Get products using the Wix Stores API

Now that you can make authorized calls to Wix APIs, you can integrate any of Wix Headless's business solutions into your site. In this tutorial, you will implement two eCommerce functionalities—a product list, and a checkout.

Important: A complete eCommerce user flow is usually comprised of a product list, a single-product page, a cart, and a checkout. However, this tutorial only covers creating a product list and a checkout. This is because this tutorial focuses on a pure server-side implementation, while implementing a product page and a cart requires client-side code using the Wix eCommerce SDK.

Query the existing products

The first Wix eCommerce functionality to implement is the product list. Use the Wix Stores API to create a service that queries and lists the products in your Wix Headless project's CMS.

First, create the service:

  1. In the plugin/services folder, create a new file named wix-products.php.

  2. In wix-products.php, add the following code:

    Copy
    1
    <?php
    2
    3
    namespace HeadlessExample\Services;
    4
    5
    class WixStoresProducts
    6
    {
    7
    public static function getProducts(string $slug = null): array {
    8
    $tokens = Auth::getTokens();
    9
    10
    if (! $tokens['accessToken']) {
    11
    throw new \RuntimeException('No access token');
    12
    }
    13
    14
    $response = wp_remote_post('https://www.wixapis.com/stores/v1/products/query', array(
    15
    'method' => 'POST',
    16
    'headers' => array('Content-Type' => 'application/json', 'Authorization' => $tokens['accessToken']['value']),
    17
    'body' => $slug ? '{"query": {"filter": "{\"slug\": \"'.$slug.'\"}"}}' : '',
    18
    'data_format' => 'body',
    19
    ));
    20
    21
    if (!is_wp_error($response) && $response['response']['code'] === 200) {
    22
    $body = wp_remote_retrieve_body($response);
    23
    return json_decode($body, true);
    24
    } else {
    25
    error_log('Failed to get products, request ID: '.get_wix_request_id($response).' full response: '.json_encode($response));
    26
    throw new \RuntimeException('Failed to get products');
    27
    }
    28
    }
    29
    }

    The getProducts() function makes an authorized call to the Wix Stores API. It queries all products that exist in your Headless project's CMS.

Create a template to display your products

Next, create a WordPress template file to display your product list:

  1. In plugin/templates, create a new file named product-list.php.

  2. In product-list.php, add the following code:

    Copy
    1
    <?php
    2
    3
    if (!defined('ABSPATH')) {
    4
    exit;
    5
    }
    6
    7
    /** @var array $products */
    8
    $buy_now_url = rest_url() . 'wix-headless-example/v1/buy-now?productSlug=';
    9
    ?>
    10
    <?php if (empty($products)) : ?>
    11
    <p>No products found.</p>
    12
    <?php else : ?>
    13
    <ul>
    14
    <?php foreach ($products as $product) : ?>
    15
    <li><?php echo esc_html($product['name']); ?></li>
    16
    <?php endforeach; ?>
    17
    </ul>
    18
    <?php endif; ?>

    This code creates the template for displaying a dynamic list of products.

Render the list of products on your WordPress site

Now that the products have been queried, and a template exists for displaying them, all that is left is to display them on your site.

  1. In plugin/wix-headless-example.php, add the following code:

    Copy
    1
    <?php
    2
    namespace HeadlessExample;
    3
    4
    class WixHeadlessPlugin
    5
    {
    6
    public function __construct() {
    7
    // ...
    8
    add_shortcode('wixwp_products', array($this, 'wix_headless_render_product_list'));
    9
    }
    10
    11
    // ...
    12
    13
    public static function wix_headless_render_product_list($attrs) {
    14
    $product_list = WixStoresProducts::getProducts();
    15
    $products = $product_list['products'];
    16
    $attrs = shortcode_atts(array(
    17
    'template' => '',
    18
    ), $attrs);
    19
    20
    $templates = array( $attrs['template'], 'templates/product-list.php');
    21
    22
    $template_file = locate_template( $templates, true, true );
    23
    24
    // If it isn't defined in the WordPress theme or attribute, use the plugin template
    25
    if (!file_exists($template_file)) {
    26
    $template_file = plugin_dir_path(__FILE__).'templates/product-list.php';
    27
    }
    28
    29
    extract($products);
    30
    ob_start();
    31
    32
    if (file_exists($template_file)) {
    33
    include $template_file;
    34
    } else {
    35
    echo 'Template file not found!';
    36
    }
    37
    38
    return ob_get_clean();
    39
    }
    40
    }
    41
    42
    $WixHeadlessPlugin = new WixHeadlessPlugin();

    This wix_headless_render_product_list() function queries the existing products and uses the product-list template file to render the products on the screen. It also registers this function for the wixwp_products shortcode.

    Note: The locate_template() function allows the theme to override the existing template.

  2. Finally, on your WordPress site, add a shortcode block with the [wixwp_products] shortcode. View your page to see the list of products.

Step 6: Add a secured checkout functionality

The second Wix eCommerce functionality you will implement is the Wix secured checkout. This involves implementing a dynamic "Buy Now" route for each product. When clicked, the route takes your visitor to a secured checkout page where they can complete their purchase.

Note: As its name suggests, the "Buy Now" functionality takes your visitor directly to a checkout page, without taking them through a product page and a shopping cart first. This means that product variants or options are not supported in this implementation. For a full eCommerce implementation, see the Wix Headless eCommerce tutorial.

Add URL slugs for the queried products

To create a dynamic checkout page for each product, queried each product must first be identified with a unique, dynamic URL. In plugin/services/wix-products.php, update the value of the request body to include a dynamic slug:

Copy
1
<?php
2
namespace HeadlessExample\Services;
3
4
class WixStoresProducts
5
{
6
public static function getProducts(string $slug = null): array {
7
// ...
8
$response = wp_remote_post('https://www.wixapis.com/stores/v1/products/query', array(
9
// ...
10
'body' => $slug ? '{"query": {"filter": "{\"slug\": \"'.$slug.'\"}"}}' : '',
11
// ...
12
));
13
// ...
14
}
15
}

Now, when making a call to the Wix Stores API, the request body includes a unique URL slug for each product.

Create the checkout service using Wix eCommerce API

Wix Headless offers a secured checkout service that can be dynamically populated with each product's details.

Use the Wix eCommerce API to create a secured checkout service:

  1. In plugin/services, create a new file named wix-checkout.php.

  2. Add to it the following code:

    Copy
    1
    <?php
    2
    namespace HeadlessExample\Services;
    3
    4
    class CheckoutServices {
    5
    public static function createCheckout($productId, $quantity) {
    6
    $tokens = Auth::getTokens();
    7
    8
    if (! $tokens['accessToken']) {
    9
    throw new \RuntimeException('No access token');
    10
    }
    11
    12
    $item = [
    13
    'quantity' => $quantity,
    14
    'catalogReference' => [
    15
    'catalogItemId' => $productId,
    16
    'appId' => '1380b703-ce81-ff05-f115-39571d94dfcd',
    17
    ],
    18
    ];
    19
    20
    $lineItems = [$item];
    21
    $channelType = "WEB";
    22
    23
    $data = [
    24
    "lineItems" => $lineItems,
    25
    "channelType" => $channelType
    26
    ];
    27
    28
    $response = wp_remote_post('https://www.wixapis.com/ecom/v1/checkouts', array(
    29
    'method' => 'POST',
    30
    'headers' => array('Content-Type' => 'application/json', 'Authorization' => $tokens['accessToken']['value']),
    31
    'body' => json_encode($data),
    32
    'data_format' => 'body',
    33
    ));
    34
    35
    if (!is_wp_error($response) && $response['response']['code'] === 200) {
    36
    $body = wp_remote_retrieve_body($response);
    37
    return json_decode($body, true);
    38
    } else {
    39
    error_log('Failed to create checkout, request ID: '.get_wix_request_id($response).' full response: '.json_encode($response));
    40
    throw new \RuntimeException('Failed to create checkout');
    41
    }
    42
    }
    43
    }

    The createCheckout() function makes a call to the Wix eCommerce API with the details of the product that was clicked. The function returns a new checkout object used to render the Wix Checkout page on your WordPress site.

Create the redirect session

Now, whenever a product is clicked, a checkout page dynamically loads with that product's details. However, the checkout page itself is a Wix page, which means it isn't hosted on your WordPress site, but rather on Wix's servers. Therefore, your visitor still needs to be redirected there to complete their purchase, and back to your WordPress site once they are done.

To redirect your visitor from your WordPress site to the Wix checkout page, and then return them to your site once they have completed their purchase, you need to use the Wix Redirect Session API.

Create a redirection service to handle redirecting your visitor to, and back from, the Wix checkout page:

  1. Still in plugin/services/wix-checkout.php, add the following code:

    Copy
    1
    <?php
    2
    namespace HeadlessExample\Services;
    3
    4
    class CheckoutServices {
    5
    // ...
    6
    7
    public static function createCallbackUrls(): array {
    8
    $baseUrl = get_site_url();
    9
    10
    return [
    11
    "baseUrl" => $baseUrl,
    12
    "postFlowUrl" => $baseUrl,
    13
    ];
    14
    }
    15
    16
    public static function createCheckoutRedirectSession($checkoutId) {
    17
    $tokens = Auth::getTokens();
    18
    19
    if (! $tokens['accessToken']) {
    20
    throw new \RuntimeException('No access token');
    21
    }
    22
    23
    $data = [
    24
    "ecomCheckout" => ["checkoutId" => $checkoutId],
    25
    "callbacks" => CheckoutServices::createCallbackUrls()
    26
    ];
    27
    28
    $response = wp_remote_post('https://www.wixapis.com/_api/redirects-api/v1/redirect-session', array(
    29
    'method' => 'POST',
    30
    'headers' => array('Content-Type' => 'application/json', 'Authorization' => $tokens['accessToken']['value']),
    31
    'body' => json_encode($data),
    32
    'data_format' => 'body',
    33
    ));
    34
    35
    if (!is_wp_error($response) && $response['response']['code'] === 200) {
    36
    $body = wp_remote_retrieve_body($response);
    37
    return json_decode($body, true);
    38
    } else {
    39
    error_log('Failed to create redirect session, request ID: '.get_wix_request_id($response).' full response: '.json_encode($response));
    40
    throw new \RuntimeException('Failed to create redirect session for checkout');
    41
    }
    42
    }
    43
    }

    The createCheckoutRedirectSession() function makes an authorized call to the Wix Redirect Sessions API. The postFlowUrl value included in the call specifies where your visitor returns upon completing their purchase. The function then returns the processed redirect session to the calling router.

Create a router to handle the "Buy Now" flow

The redirection functionality is now configured, but it is not integrated into your page. You now need to create a routing service that manages the entire "Buy Now" redirection and checkout flow.

Create the routing service:

  1. In plugin/utils, create a new file named routes.php.

  2. In routes.php, write the following code:

    Copy
    1
    <?php
    2
    use HeadlessExample\Services\CheckoutServices;
    3
    use HeadlessExample\Services\WixStoresProducts;
    4
    5
    function wix_headless_buy_now_endpoint(): void
    6
    {
    7
    register_rest_route('wix-headless-example/v1', '/buy-now', array(
    8
    'methods' => 'GET',
    9
    'callback' => 'wix_headless_buy_now_callback',
    10
    'permission_callback' => '__return_true',
    11
    'args' => array(
    12
    'productSlug' => array(
    13
    'required' => true,
    14
    ),
    15
    'quantity' => array(
    16
    'required' => false,
    17
    ),
    18
    ),
    19
    ));
    20
    }
    21
    22
    function wix_headless_buy_now_callback($request)
    23
    {
    24
    error_log('wix_headless_buy_now_callback');
    25
    $product_slug = $request->get_param('productSlug');
    26
    $quantity = intval($request->get_param('quantity') ?? '1', 10);
    27
    $products = WixStoresProducts::getProducts($product_slug);
    28
    $product = (object)($products['products'][0]);
    29
    30
    $checkout = CheckoutServices::createCheckout($product->id, $quantity);
    31
    32
    $redirect_session = CheckoutServices::createCheckoutRedirectSession($checkout['checkout']['id']);
    33
    34
    $response = rest_ensure_response(null);
    35
    $response->set_status(302); // Set the HTTP status code to 302 (Found/Temporary Redirect)
    36
    $response->header('Location', $redirect_session['redirectSession']['fullUrl']);
    37
    38
    return $response;
    39
    }

    The wix_headless_buy_now_endpoint() specifies which Wix REST endpoint must be called whenever a product is clicked. Its callback function, wix_headless_buy_now_callback(), creates both the dynamic checkout page with the clicked product's details, and the necessary redirection functionality.

Make the business services accessible to your plugin

The product list, checkout, and redirect services have been set up. You now need to let your main plugin logic know that they are available and where it can find them. Your WordPress site also needs to be aware of the Wix REST endpoints used by these services.

  1. Bring the router into the scope of your plugin. In plugin/wix-headless-example.php, add the following lines:

    Copy
    1
    <?php
    2
    namespace HeadlessExample;
    3
    4
    use HeadlessExample\Services\Auth;
    5
    use HeadlessExample\Services\WixStoresProducts;
    6
    defined( 'ABSPATH' ) || exit;
    7
    8
    require_once plugin_dir_path(__FILE__) . 'utils/wix-request-id.php';
    9
    require_once plugin_dir_path(__FILE__) . 'services/wix-auth.php';
    10
    require_once plugin_dir_path(__FILE__) . 'services/wix-products.php';
    11
    require_once plugin_dir_path(__FILE__) . 'services/wix-checkout.php';
    12
    require_once plugin_dir_path(__FILE__) . 'utils/routes.php';
    13
    14
    class WixHeadlessPlugin
    15
    {
    16
    // ...
    17
    }

    The use .../WixStoresProducts statement makes the product list, checkout, and redirection functionalities available to the functions in the current file. The various require_once statements act as safeguards to make sure that files already brought into scope won't be brought in again.

  2. Finally, register the "Buy Now" endpoint to your WordPress site. In plugin/wix-headless-example.php, add the following line:

    Copy
    1
    <?php
    2
    namespace HeadlessExample;
    3
    //...
    4
    require_once plugin_dir_path(__FILE__) . 'services/wix-checkout.php';
    5
    require_once plugin_dir_path(__FILE__) . 'utils/routes.php';
    6
    7
    class WixHeadlessPlugin
    8
    {
    9
    public function __construct() {
    10
    // ...
    11
    12
    add_action('rest_api_init', 'wix_headless_buy_now_endpoint');
    13
    }
    14
    15
    // ...
    16
    }
    17
    18
    $WixHeadlessPlugin = new WixHeadlessPlugin();

    The add_action() WordPress function registers wix_headless_buy_now_endpoint() as the callback function to be called whenever the rest_api_init hook fires. Whenever your WordPress site initializes its REST API functionality, the wix_headless_buy_now_endpoint() function runs and begins the "Buy Now" flow.

Add the "Buy Now" option to products

Finally, embed the "Buy Now" option in the list of products on your WordPress site. In templates/product-list.php, add the following line to your code:

Copy
1
<?php
2
3
// ...
4
5
<?php if (empty($products)) : ?>
6
// ...
7
<?php else : ?>
8
<ul>
9
<?php foreach ($products as $product) : ?>
10
<li>
11
<a href="<?php echo $buy_now_url.$product['slug'] ?>"><?php echo esc_html($product['name']); ?></a> // Add the "Buy Now" funcionality
12
</li>
13
<?php endforeach; ?>
14
</ul>
15
<?php endif; ?>

When a visitor clicks a product, they are redirected to the checkout page to complete their purchase, and redirected back to your site once they have completed their purchase.

Conclusion

Well done! In this tutorial you created from scratch a WordPress plugin that integrates a limited Wix Headless eCommerce user flow with your WordPress site. It was done using server-side code only.

You can find the full source code here.

However, You can expand the existing implementation to include other business services, such as product pages and a cart, by adding client-side code. For a sample implementation, see the Wix Headless eCommerce tutorial.

Was this helpful?
Yes
No