Skip to content

Commit

Permalink
idanl-wordpress-source-code-repo
Browse files Browse the repository at this point in the history
  • Loading branch information
idanlib-wix committed Dec 7, 2023
1 parent 5579ebb commit 777efa6
Show file tree
Hide file tree
Showing 9 changed files with 428 additions and 0 deletions.
28 changes: 28 additions & 0 deletions pages/wordpress/build/zip-plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const fs = require('fs');
const { exec } = require('child_process');

const folderToDelete = 'dist';
const folderToCreate = 'dist';
const folderToZip = 'plugin';
const zipFilePath = 'dist/wix-headless-example.zip';

// Delete the folder "dist" if it exists
if (fs.existsSync(folderToDelete)) {
fs.rmSync(folderToDelete, { recursive: true });
}

// Create an empty folder "dist"
fs.mkdirSync(folderToCreate);

// Zip all the content of the folder "plugin" into "dist/plugin.zip"
exec(`zip -r ${zipFilePath} ${folderToZip}/*`, (error, stdout, stderr) => {
if (error) {
console.error(`Error: ${error.message}`);
return;
}
if (stderr) {
console.error(`stderr: ${stderr}`);
return;
}
console.log(`Folder ${folderToZip} has been zipped successfully into ${zipFilePath}`);
});
109 changes: 109 additions & 0 deletions pages/wordpress/plugin/services/wix-auth.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php
namespace HeadlessExample\Services;

class Auth
{
private static string $COOKIE_NAME = 'wix-headless-example-tokens';
private static $tokens = null;

public static function getTokens() {
return Auth::$tokens;
}

public static function init(): void {
Auth::$tokens = Auth::getPersistedTokens();
if (!Auth::isAccessTokenValid()) {
Auth::$tokens = Auth::generateVisitorTokens();
Auth::persistTokens();
}
}

public static function getPersistedTokens() {
if (isset($_COOKIE[Auth::$COOKIE_NAME])) {
// Retrieve the JSON data from the cookie
$jsonData = urldecode($_COOKIE[Auth::$COOKIE_NAME]);

// Decode the JSON data
$decodedData = json_decode($jsonData, true);

if ($decodedData !== null) {
// Return the decoded JSON data
return $decodedData;
} else {
// Debug: Output the JSON decoding error
error_log('Failed to decode JSON from the cookie.');
return null;
}
} else {
// Cookie not set or expired, handle accordingly
return null;
}
}

public static function persistTokens(): void {
$jsonData = json_encode(Auth::$tokens);
$expiry = time() + 60 * 60 * 24 * 30; // 30 days
$path = '/'; // Cookie available across the entire domain
$domain = '';
setcookie(Auth::$COOKIE_NAME, urlencode($jsonData), $expiry, $path, $domain, false, false);
}

public static function isAccessTokenValid(): bool {
$currentDate = time(); // Get the current UNIX timestamp
return !!(Auth::$tokens['accessToken']['value'] ?? false) && Auth::$tokens['accessToken']['expiresAt'] > $currentDate;
}

public static function generateVisitorTokens(): array {
$client_id = get_option('wix_example_client_id');
if (!empty($client_id)) {
$token_request = Auth::$tokens['refreshToken'] && Auth::$tokens['refreshToken']['role'] == TokenRole::VISITOR ? array(
'refresh_token' => Auth::$tokens['refreshToken']['value'], 'grantType' => 'refresh_token', 'scope' => 'offline_access',
) : array(
'clientId' => $client_id, 'grantType' => 'anonymous', 'scope' => 'offline_access',
);
$response = wp_remote_post('https://www.wixapis.com/oauth2/token', array(
'method' => 'POST',
'headers' => array('Content-Type' => 'application/json'),
'body' => wp_json_encode($token_request),
'data_format' => 'body',
));

if (!is_wp_error($response) && $response['response']['code'] === 200) {
$body = wp_remote_retrieve_body($response);
$raw_tokens = json_decode($body, true);
return Auth::rawTokensToTokensResult($raw_tokens);
} else {
error_log('Failed to get tokens : Wix request ID: '.get_wix_request_id($response).' full response '.json_encode($response));
throw new \RuntimeException('Failed to get tokens');
}
} else {
return [];
}

}

private static function rawTokensToTokensResult(array $raw_tokens): array {
return array(
'accessToken' => Auth::createAccessToken($raw_tokens['access_token'], $raw_tokens['expires_in']),
'refreshToken' => array(
'value' => $raw_tokens['refresh_token'],
'role' => TokenRole::VISITOR,
),
);
}

private static function createAccessToken(string $accessToken, int $expiresIn): array {
$now = time(); // Get the current UNIX timestamp
return array(
'value' => $accessToken,
'expiresAt' => $expiresIn + $now,
);
}
}

class TokenRole {
const NONE = 'none';
const VISITOR = 'visitor';
// for future use
const MEMBER = 'member';
}
82 changes: 82 additions & 0 deletions pages/wordpress/plugin/services/wix-checkout.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php
namespace HeadlessExample\Services;

class CheckoutServices {
public static function createCheckout($productId, $quantity) {
$tokens = Auth::getTokens();

if (! $tokens['accessToken']) {
throw new \RuntimeException('No access token');
}

// this does not handle product options which requires client side logic
$item = [
'quantity' => $quantity,
'catalogReference' => [
'catalogItemId' => $productId,
'appId' => '1380b703-ce81-ff05-f115-39571d94dfcd',
],
];

$lineItems = [$item];
$channelType = "WEB";

$data = [
"lineItems" => $lineItems,
"channelType" => $channelType
];

$response = wp_remote_post('https://www.wixapis.com/ecom/v1/checkouts', array(
'method' => 'POST',
'headers' => array('Content-Type' => 'application/json', 'Authorization' => $tokens['accessToken']['value']),
'body' => json_encode($data),
'data_format' => 'body',
));

if (!is_wp_error($response) && $response['response']['code'] === 200) {
$body = wp_remote_retrieve_body($response);
return json_decode($body, true);
} else {
error_log('Failed to create checkout, request ID: '.get_wix_request_id($response).' full response: '.json_encode($response));
throw new \RuntimeException('Failed to create checkout');
}
}

public static function createCallbackUrls(): array {
$baseUrl = get_site_url();

return [
"baseUrl" => $baseUrl,
"postFlowUrl" => $baseUrl,
];
}

public static function createCheckoutRedirectSession($checkoutId) {
$tokens = Auth::getTokens();

if (! $tokens['accessToken']) {
throw new \RuntimeException('No access token');
}

$data = [
"ecomCheckout" => ["checkoutId" => $checkoutId],
"callbacks" => CheckoutServices::createCallbackUrls()
];


$response = wp_remote_post('https://www.wixapis.com/_api/redirects-api/v1/redirect-session', array(
'method' => 'POST',
'headers' => array('Content-Type' => 'application/json', 'Authorization' => $tokens['accessToken']['value']),
'body' => json_encode($data),
'data_format' => 'body',
));

if (!is_wp_error($response) && $response['response']['code'] === 200) {
$body = wp_remote_retrieve_body($response);
return json_decode($body, true);
} else {
error_log('Failed to create redirect session, request ID: '.get_wix_request_id($response).' full response: '.json_encode($response));
throw new \RuntimeException('Failed to create redirect session for checkout');
}
}
}
28 changes: 28 additions & 0 deletions pages/wordpress/plugin/services/wix-products.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php
namespace HeadlessExample\Services;

class WixStoresProducts
{
public static function getProducts(string $slug = null): array {
$tokens = Auth::getTokens();

if (! $tokens['accessToken']) {
throw new \RuntimeException('No access token');
}

$response = wp_remote_post('https://www.wixapis.com/stores/v1/products/query', array(
'method' => 'POST',
'headers' => array('Content-Type' => 'application/json', 'Authorization' => $tokens['accessToken']['value']),
'body' => $slug ? '{"query": {"filter": "{\"slug\": \"'.$slug.'\"}"}}' : '',
'data_format' => 'body',
));

if (!is_wp_error($response) && $response['response']['code'] === 200) {
$body = wp_remote_retrieve_body($response);
return json_decode($body, true);
} else {
error_log('Failed to get products, request ID: '.get_wix_request_id($response).' full response: '.json_encode($response));
throw new \RuntimeException('Failed to get products');
}
}
}
20 changes: 20 additions & 0 deletions pages/wordpress/plugin/templates/product-list.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

if (!defined('ABSPATH')) {
exit;
}

/** @var array $products */
$buy_now_url = rest_url() . 'wix-headless-example/v1/buy-now?productSlug=';
?>
<?php if (empty($products)) : ?>
<p>No products found.</p>
<?php else : ?>
<ul>
<?php foreach ($products as $product) : ?>
<li>
<a href="<?php echo $buy_now_url.$product['slug'] ?>"><?php echo esc_html($product['name']); ?></a>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
26 changes: 26 additions & 0 deletions pages/wordpress/plugin/templates/settings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php
?>

<div class="wrap">
<h2 style="display: none"></h2>
<?php

?>
<div id="Connect-OAuth" class="tabcontent">
<h2>Wix Headless</h2>
<form method="post" action="options.php">
<?php settings_fields('wix_headless_example_settings_group'); ?>
<?php do_settings_sections('wix-headless-example-settings'); ?>
<table class="form-table">
<tr style="vertical-align:top">
<th scope="row">Wix Client ID</th>
<td>
<input required type="text" name="wix_example_client_id" value="<?php echo esc_attr(get_option('wix_example_client_id')); ?>" />
</td>
</tr>
<!-- Add more settings fields here -->
</table>
<?php submit_button(); ?>
</form>
</div>
</div>
39 changes: 39 additions & 0 deletions pages/wordpress/plugin/utils/routes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php
use HeadlessExample\Services\CheckoutServices;
use HeadlessExample\Services\WixStoresProducts;

function wix_headless_buy_now_endpoint(): void
{
register_rest_route('wix-headless-example/v1', '/buy-now', array(
'methods' => 'GET',
'callback' => 'wix_headless_buy_now_callback',
'permission_callback' => '__return_true',
'args' => array(
'productSlug' => array(
'required' => true,
),
'quantity' => array(
'required' => false,
),
),
));
}

function wix_headless_buy_now_callback($request)
{
error_log('wix_headless_buy_now_callback');
$product_slug = $request->get_param('productSlug');
$quantity = intval($request->get_param('quantity') ?? '1', 10);
$products = WixStoresProducts::getProducts($product_slug);
$product = (object)($products['products'][0]);

$checkout = CheckoutServices::createCheckout($product->id, $quantity);

$redirect_session = CheckoutServices::createCheckoutRedirectSession($checkout['checkout']['id']);

$response = rest_ensure_response(null);
$response->set_status(302); // Set the HTTP status code to 302 (Found/Temporary Redirect)
$response->header('Location', $redirect_session['redirectSession']['fullUrl']);

return $response;
}
6 changes: 6 additions & 0 deletions pages/wordpress/plugin/utils/wix-request-id.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

function get_wix_request_id($response) {
$headers = wp_remote_retrieve_headers( $response );
return $headers['x-wix-request-id'] ?? 'Header not found';
}
Loading

0 comments on commit 777efa6

Please sign in to comment.