-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5579ebb
commit 777efa6
Showing
9 changed files
with
428 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}`); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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'; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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'); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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'); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; ?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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'; | ||
} |
Oops, something went wrong.