diff --git a/pages/wordpress/build/zip-plugin.js b/pages/wordpress/build/zip-plugin.js new file mode 100644 index 0000000..43dee82 --- /dev/null +++ b/pages/wordpress/build/zip-plugin.js @@ -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}`); +}); diff --git a/pages/wordpress/plugin/services/wix-auth.php b/pages/wordpress/plugin/services/wix-auth.php new file mode 100644 index 0000000..66484cb --- /dev/null +++ b/pages/wordpress/plugin/services/wix-auth.php @@ -0,0 +1,109 @@ + $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'; +} diff --git a/pages/wordpress/plugin/services/wix-checkout.php b/pages/wordpress/plugin/services/wix-checkout.php new file mode 100644 index 0000000..f8045e0 --- /dev/null +++ b/pages/wordpress/plugin/services/wix-checkout.php @@ -0,0 +1,82 @@ + $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'); + } + } +} diff --git a/pages/wordpress/plugin/services/wix-products.php b/pages/wordpress/plugin/services/wix-products.php new file mode 100644 index 0000000..5eb15ce --- /dev/null +++ b/pages/wordpress/plugin/services/wix-products.php @@ -0,0 +1,28 @@ + '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'); + } + } +} diff --git a/pages/wordpress/plugin/templates/product-list.php b/pages/wordpress/plugin/templates/product-list.php new file mode 100644 index 0000000..d97d0c3 --- /dev/null +++ b/pages/wordpress/plugin/templates/product-list.php @@ -0,0 +1,20 @@ + + +

No products found.

+ + + diff --git a/pages/wordpress/plugin/templates/settings.php b/pages/wordpress/plugin/templates/settings.php new file mode 100644 index 0000000..14e4926 --- /dev/null +++ b/pages/wordpress/plugin/templates/settings.php @@ -0,0 +1,26 @@ + + +
+

+ +
+

Wix Headless

+
+ + + + + + + + +
Wix Client ID + +
+ +
+
+
diff --git a/pages/wordpress/plugin/utils/routes.php b/pages/wordpress/plugin/utils/routes.php new file mode 100644 index 0000000..a3f54b3 --- /dev/null +++ b/pages/wordpress/plugin/utils/routes.php @@ -0,0 +1,39 @@ + '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; +} diff --git a/pages/wordpress/plugin/utils/wix-request-id.php b/pages/wordpress/plugin/utils/wix-request-id.php new file mode 100644 index 0000000..5ea7fe7 --- /dev/null +++ b/pages/wordpress/plugin/utils/wix-request-id.php @@ -0,0 +1,6 @@ + '', + ), $attrs); + + $templates = array( $attrs['template'], 'templates/product-list.php'); + + $template_file = locate_template( $templates, true, true ); + if (!file_exists($template_file)) { + // use plugin template if not defined in theme/ attribute + $template_file = plugin_dir_path(__FILE__).'templates/product-list.php'; + } + extract($products); + ob_start(); + if (file_exists($template_file)) { + include $template_file; + } else { + echo 'Template file not found!!'; + } + + return ob_get_clean(); + } +} + +$WixHeadlessPlugin = new WixHeadlessPlugin();