PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.5.4
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.5.4
1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 trunk All 48 releases
fluent-cart / app / Http / Routes / WebRoutes.php

WebRoutes.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.5.4, at app/Http/Routes/WebRoutes.php

375 lines 12.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\App\Http\Routes;
4
5 use FluentCart\Api\Resource\FrontendResource\CartResource;
6 use FluentCart\Api\StoreSettings;
7 use FluentCart\App\App;
8
9 use FluentCart\App\Helpers\CartHelper;
10 use FluentCart\App\Helpers\Helper;
11 use FluentCart\App\Hooks\Handlers\ShortCodes\Checkout\CheckoutPageHandler;
12 use FluentCart\App\Hooks\Handlers\ShortCodes\ReceiptHandler;
13 use FluentCart\App\Http\Controllers\WebController\FileDownloader;
14 use FluentCart\App\Models\Cart;
15 use FluentCart\App\Models\ProductVariation;
16 use FluentCart\App\Modules\PaymentMethods\PayPalGateway\API\PayPalPartnerRenderer;
17 use FluentCart\App\Modules\Templating\AssetLoader;
18 use FluentCart\App\Services\FrontendView;
19 use FluentCart\App\Services\PrintService;
20 use FluentCart\App\Services\Renderer\CartRenderer;
21 use FluentCart\App\Services\TemplateService;
22 use FluentCart\App\Services\URL;
23 use FluentCart\App\Vite;
24 use FluentCart\Framework\Support\Arr;
25 use FluentCart\App\Services\Renderer\CheckoutRenderer;
26 use FluentCart\App\Services\Renderer\ModalCheckoutRenderer;
27
28 class WebRoutes
29 {
30 public static function register()
31 {
32
33 add_action('init', function () {
34 self::registerRoutes();
35 });
36 }
37
38 public static function renderModalCheckout() {
39 add_action('wp_footer', function () {
40 if (!AssetLoader::isFrontendAssetsMarked() && !AssetLoader::isFluentCartContext()) {
41 return;
42 }
43
44 AssetLoader::loadModalCheckoutAssets();
45
46 if (
47 isset($_SERVER['HTTP_SEC_FETCH_DEST']) &&
48 $_SERVER['HTTP_SEC_FETCH_DEST'] === 'iframe'
49 ) {
50 return;
51 }
52
53 $cart = CartHelper::getCart();
54
55 if (!$cart) {
56 $cart = new Cart();
57 }
58
59 (new ModalCheckoutRenderer($cart))->render();
60 });
61 }
62
63 public static function registerRoutes()
64 {
65 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
66 $page = sanitize_text_field(wp_unslash($_REQUEST['fluent-cart'] ?? ''));
67
68 if (empty($page)) {
69 return;
70 }
71
72 $page = sanitize_text_field($page);
73
74 if (!$page) {
75 return;
76 }
77
78 if ($page === 'instant_checkout') {
79 $requestData = App::request()->all();
80 $variationId = sanitize_text_field(App::request()->get('item_id'));
81 $quantity = App::request()->get('quantity', 1);
82 // Raw request flag; actual validation and normalization
83 // happens in CartResource.
84 $isCustom = (bool)Arr::get($requestData, 'is_custom', false);
85
86 if(!$isCustom) {
87 if (!is_numeric($variationId)) {
88 return;
89 }
90 }
91
92 if (is_numeric($quantity)) {
93 $quantity = intval($quantity);
94 $quantity = max($quantity, 1);
95 } else {
96 $quantity = 1;
97 }
98
99 if($isCustom) {
100 $variation = apply_filters('fluent_cart/cart/validate_custom_item', null, [
101 'item_id' => $variationId,
102 'quantity' => $quantity,
103 'is_custom' => $isCustom,
104 'action' => 'instant_checkout',
105 ]);
106
107 if (!is_object($variation)) {
108 $variation = (object) $variation;
109 }
110
111 } else {
112 $variation = ProductVariation::query()->find($variationId);
113 }
114
115 if (empty($variation)) {
116 return;
117 }
118
119 $soldIndividually = $isCustom
120 ? !empty($variation->sold_individually)
121 : (bool) $variation->soldIndividually();
122
123 if ($soldIndividually) {
124 $quantity = 1;
125 }
126
127 $cart = CartResource::generateCartForInstantCheckout($variationId, $quantity, [
128 'is_custom' => $isCustom,
129 'variation' => $variation
130 ]);
131
132 if (is_wp_error($cart)) {
133 (new CheckoutPageHandler())->enqueueStyles();
134 ob_start();
135 (new CartRenderer([]))->renderEmpty(
136 $cart->get_error_message()
137 );
138 $view = ob_get_clean();
139 FrontendView::make(__('Product Not Found', 'fluent-cart'), $view);
140 die();
141 }
142
143 $coupons = App::request()->get('coupons', '');
144 if ($coupons) {
145 $coupons = explode(',', $coupons);
146 $coupons = array_map('sanitize_text_field', $coupons);
147 $couponResult = $cart->applyCoupon($coupons);
148
149
150 $couponErrors = [];
151 if (is_wp_error($couponResult)) {
152 $couponErrors[] = esc_html($couponResult->get_error_message());
153 } elseif (is_array($couponResult)) {
154 $perCouponResults = Arr::get($couponResult, 'coupon_results', []);
155 foreach ($coupons as $code) {
156 foreach ($perCouponResults as $resultCode => $result) {
157 if (strcasecmp((string) $resultCode, (string) $code) === 0) {
158 $errorMessage = Arr::get($result, 'error', '');
159 if ($errorMessage !== '') {
160 $couponErrors[] = esc_html($errorMessage);
161 }
162 break;
163 }
164 }
165 }
166 }
167
168 if ($couponErrors) {
169 $checkoutData = is_array($cart->checkout_data) ? $cart->checkout_data : [];
170 $checkoutData['__checkout_error_notices'] = $couponErrors;
171 $cart->checkout_data = $checkoutData;
172 $cart->save();
173 }
174 }
175
176 $target_path = (new StoreSettings())->getCheckoutPage();
177
178 $redirectTo = App::request()->get('redirect_to');
179 if (!empty($redirectTo)) {
180 $url = sanitize_url(wp_unslash($redirectTo));
181 $allowedHosts = [parse_url(home_url(), PHP_URL_HOST)];
182 $allowedHosts = apply_filters('fluent_cart/instant_checkout/allowed_redirect_hosts', $allowedHosts, [
183 'allowed_hosts' => $allowedHosts
184 ]);
185 if (!empty($url) && filter_var($url, FILTER_VALIDATE_URL) && in_array(parse_url($url, PHP_URL_HOST), $allowedHosts, true)) {
186 $target_path = $url;
187 }
188 }
189
190
191 // Step 1: Get current query string and parse to array
192
193 $queryArray = [];
194 $queryString = Arr::get( App::request()->server(), 'QUERY_STRING');
195 if ( isset($queryString) ) {
196 parse_str($queryString, $queryArray);
197 }
198
199 unset($queryArray['fluent-cart']);
200 unset($queryArray['item_id']);
201 unset($queryArray['quantity']);
202 unset($queryArray['coupons']);
203 unset($queryArray['redirect_to']);
204
205 if (isset($queryArray['is_custom'])) {
206 unset($queryArray['is_custom']);
207 }
208
209 $queryArray['fct_cart_hash'] = $cart->cart_hash;
210
211 $redirect_url = URL::appendQueryParams($target_path, $queryArray);
212
213 wp_redirect($redirect_url);
214 exit;
215 }
216
217 $served = self::handleMainRoutes($page);
218
219 // Handle faker routes if enabled and not already served
220 if (!$served && App::config()->get('using_faker') === true) {
221 $served = FakerRoutes::handle($page);
222 }
223
224 if (has_action('fluent_cart_action_' . $page)) {
225 $requestData = App::request()->all();
226 do_action('fluent_cart_action_' . $page, $requestData);
227 die();
228 }
229
230 if ($served) {
231 die();
232 }
233
234 return '';
235 }
236
237 private static function handleMainRoutes($page): bool
238 {
239 $request = App::request();
240 switch ($page) {
241 case 'fluent_cart_payment_authenticate':
242 (new PayPalPartnerRenderer($request->mode))->render(
243 $request->all()
244 );
245 return true;
246 case 'download-by-id':
247 case 'download-file':
248 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaped in view template
249 echo (new FileDownloader())->index(App::request());
250 return true;
251
252 case 'receipt':
253 $receiptHandler = new ReceiptHandler();
254
255 $view = $receiptHandler->renderRedirectPage([
256 'type' => 'receipt'
257 ]);
258
259 FrontendView::make(
260 __('Order Receipt', 'fluent-cart'),
261 $view,
262 [
263 'styles' => [
264 'public/checkout/style/confirmation.scss'
265 ],
266 'scripts' => [
267 [
268 'source' => 'public/lib/printThis-2.0.0.min.js',
269 'isStatic' => true
270 ],
271 'public/print/Print.js'
272 ],
273 'enqueue_prefix' => 'fluent-cart-checkout-order-receipt',
274 'wp_head' => false,
275 'wp_footer' => false,
276 ]);
277 return true;
278
279
280 case 'print-invoice':
281 return self::handlePrintRoute('invoice');
282
283 case 'print-packing-slip':
284 return self::handlePrintRoute('packingSlip');
285
286 case 'print-delivery-slip':
287 return self::handlePrintRoute('deliverySlip');
288
289 case 'print-shipping-slip':
290 return self::handlePrintRoute('shippingSlip');
291
292 case 'print-dispatch-slip':
293 return self::handlePrintRoute('dispatchSlip');
294
295 case 'modal_checkout':
296 return self::handleModalCheckout();
297
298 default:
299 return false;
300 }
301 }
302
303 private static function handleModalCheckout(): bool
304 {
305 $variationId = App::request()->get('item_id');
306 $quantity = App::request()->get('quantity', 1);
307
308 if (!is_numeric($variationId)) {
309 return false;
310 }
311
312 if (is_numeric($quantity)) {
313 $quantity = intval($quantity);
314 $quantity = max($quantity, 1);
315 } else {
316 $quantity = 1;
317 }
318
319 $variation = ProductVariation::query()->find($variationId);
320
321 if (empty($variation)) {
322 return false;
323 }
324
325 $soldIndividually = $variation->soldIndividually();
326
327 if ($soldIndividually) {
328 $quantity = 1;
329 }
330
331 $cart = CartResource::generateCartForInstantCheckout($variationId, $quantity);
332
333 if ($cart) {
334 $modalCheckoutRenderer = new ModalCheckoutRenderer($cart);
335 ob_start();
336 $modalCheckoutRenderer->renderForm();
337 $checkoutContent = ob_get_clean();
338
339 AssetLoader::loadCheckoutAssets($cart);
340
341 Vite::enqueueStyle(
342 'fluentcart-modal-checkout-iframe-css',
343 'public/checkout/style/checkout-iframe.scss'
344 );
345
346 // Vite::enqueueScript(
347 // 'fluentcart-modal-checkout-form-js',
348 // 'public/checkout/ModalCheckoutForm.js',
349 // []
350 // );
351
352 FrontendView::make(__('Checkout', 'fluent-cart'), $checkoutContent);
353 die();
354 }
355
356 return false;
357
358
359 }
360
361 private static function handlePrintRoute($method): bool
362 {
363 if (!is_user_logged_in() || !current_user_can('manage_options')) {
364 return false;
365 }
366
367 $order = App::request()->get('order');
368 if (!empty($order)) {
369 PrintService::$method($order);
370 return true;
371 }
372 return false;
373 }
374 }
375