PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.3.27
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.3.27
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 / Services / Renderer / CheckoutFieldsSchema.php

CheckoutFieldsSchema.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.3.27, at app/Services/Renderer/CheckoutFieldsSchema.php

733 lines 26.8 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\Services\Renderer;
4
5 use FluentCart\Api\Resource\CustomerResource;
6 use FluentCart\Api\Resource\FrontendResource\CustomerAddressResource;
7 use FluentCart\App\App;
8 use FluentCart\App\Helpers\Helper;
9 use FluentCart\App\Services\Localization\LocalizationManager;
10 use FluentCart\Framework\Support\Arr;
11
12 class CheckoutFieldsSchema
13 {
14
15 public static function titleMap(): array
16 {
17 return [
18 'full_name' => __('Name', 'fluent-cart'),
19 'first_name' => __('First Name', 'fluent-cart'),
20 'last_name' => __('Last Name', 'fluent-cart'),
21 'email' => __('Email', 'fluent-cart'),
22 'company_name' => __('Company Name', 'fluent-cart'),
23 ];
24 }
25
26 public static function typeMap(): array
27 {
28 return [
29 'full_name' => 'text',
30 'first_name' => 'text',
31 'last_name' => 'text',
32 'email' => 'email',
33 'company_name' => 'text',
34 ];
35 }
36
37 public static function getNameEmailFieldsSchema($cart = null, $scope = 'render')
38 {
39
40 $fieldData = [];
41 if ($cart && $scope === 'render') {
42 $customerName = trim($cart->first_name . ' ' . $cart->last_name);
43 $customerEmail = $cart->email;
44 if (is_user_logged_in()) {
45 $user = wp_get_current_user();
46 $customerName = trim($user->first_name . ' ' . $user->last_name);
47 $fieldData['first_name'] = $user->first_name;
48 $fieldData['last_name'] = $user->last_name;
49 if (empty($customerName)) {
50 $customerName = $user->display_name;
51 }
52 $customerEmail = $user->user_email;
53 }
54
55 $fieldData['full_name'] = $customerName;
56 $fieldData['email'] = $customerEmail;
57
58 $fieldData['company_name'] = Arr::get($cart->checkout_data, 'form_data.billing_company_name', '');
59
60 }
61
62 $fieldsSchema = self::getFieldsSettings();
63
64 $titleMap = static::titleMap();
65 $nameFields = [];
66 foreach (Arr::get($fieldsSchema, 'basic_info') as $fieldKey => $basicField) {
67 if (Arr::get($basicField, 'enabled', 'no') !== 'yes') {
68 continue;
69 }
70 $key = 'billing_' . $fieldKey;
71 $isRequired = Arr::get($basicField, 'required', 'no') === 'yes' ? 'yes' : '';
72 $label = Arr::get($titleMap, $fieldKey);
73 $nameFields[$key] = [
74 'name' => $key,
75 'id' => $key,
76 'type' => 'text',
77 'data-type' => 'text',
78 'required' => $isRequired,
79 'label' => '',
80 'aria-label' => $label,
81 'placeholder' => $label . ($isRequired ? ' *' : ''),
82 'autocomplete' => 'organization',
83 'value' => Arr::get($fieldData, $fieldKey)
84 ];
85 }
86
87 $nameFields = apply_filters('fluent_cart/checkout_page_name_fields_schema', $nameFields, [
88 'cart' => $cart,
89 'scope' => $scope
90 ]);
91
92
93 return [
94 'type' => 'section',
95 'title' => '',
96 'id' => 'billing_personal_information_section',
97 'fields' => $nameFields,
98 ];
99 }
100
101 public static function getAddressBaseFields($config, $scope = 'render')
102 {
103
104 $configDefaults = [
105 'type' => 'billing', // billing or shipping
106 'product_type' => 'digital', // digital or physical
107 'with_shipping' => false, // only for billing type, if true and type is billing, then shipping fields will be returned without full_name field
108 'full_name' => '',
109 'country' => '',
110 'address_1' => '',
111 'address_2' => '',
112 'state' => '',
113 'city' => '',
114 'postcode' => '',
115 'company_name' => '',
116 'phone' => '',
117 ];
118
119 $config = wp_parse_args($config, $configDefaults);
120
121 $selectedCountry = Arr::get($config, 'country');
122 if (empty($selectedCountry)) {
123 $HTTP_CF_IP_COUNTRY = Arr::get(App::request()->server(), 'HTTP_CF_IPCOUNTRY');
124 $selectedCountry = $HTTP_CF_IP_COUNTRY ?? $selectedCountry;
125 }
126
127 $states = [];
128 if (empty($config['state']) || empty($selectedCountry)) {
129 $states = [
130 [
131 'name' => __('Select an option', 'fluent-cart'),
132 'value' => ''
133 ]
134 ];
135 }
136
137 $addressLocale = [];
138 if (!empty($selectedCountry)) {
139 $states = array_merge($states, LocalizationManager::getInstance()->statesOptions($selectedCountry));
140 $addressLocale = LocalizationManager::getInstance()->addressLocales($selectedCountry);
141 }
142
143 $stateLabel = Arr::get($addressLocale, 'state.label', __('State', 'fluent-cart'));
144 $countries = [
145 [
146 'name' => __('Select a Country', 'fluent-cart'),
147 'value' => ''
148 ]
149 ];
150
151 $countries = array_merge($countries, Helper::getCountryList());
152
153 $type = Arr::get($config, 'type', 'billing'); // billing or shipping
154
155 if (!in_array($type, ['billing', 'shipping'])) {
156 $type = 'billing';
157 }
158
159
160 if (empty($states) && !Arr::get($addressLocale, 'state.hidden')) {
161 $stateInput = [
162 'name' => $type . '_state',
163 'id' => $type . '_state',
164 'type' => 'text',
165 'data-type' => 'text',
166 'label' => '',
167 'required' => 'yes',
168 'autocomplete' => 'address-level2',
169 'placeholder' => $stateLabel,
170 'aria-label' => $stateLabel,
171 'value' => $config['state'],
172 'wrapper_atts' => [
173 'id' => $type . '_state_wrapper'
174 ]
175 ];
176 } else {
177 $stateInput = [
178 'name' => $type . '_state',
179 'id' => $type . '_state',
180 'type' => 'select',
181 'data-type' => 'select',
182 'label' => '',
183 'options' => $states,
184 'required' => 'yes',
185 'autocomplete' => 'address-level2',
186 'placeholder' => $stateLabel,
187 'aria-label' => $stateLabel,
188 'value' => $config['state'],
189 'wrapper_atts' => [
190 'id' => $type . '_state_wrapper'
191 ]
192 ];
193 }
194
195 $fields = [
196 'full_name' => [
197 'id' => $type . '_full_name',
198 'name' => $type . '_full_name',
199 'type' => 'text',
200 'data-type' => 'text',
201 'label' => '',
202 'is_core' => 'yes',
203 'required' => 'yes',
204 'autocomplete' => 'given-name',
205 'value' => $config['full_name'],
206 'placeholder' => esc_attr__('Full Name', 'fluent-cart'),
207 'aria-label' => esc_attr__('Your Full Name', 'fluent-cart'),
208 ],
209 'country' => [
210 'name' => $type . '_country',
211 'id' => $type . '_country',
212 'type' => 'select',
213 'options' => $countries,
214 'data-type' => 'text',
215 'label' => '',
216 'aria-label' => esc_attr__('Country / Region', 'fluent-cart'),
217 'required' => 'yes',
218 'autocomplete' => 'country',
219 'placeholder' => esc_attr__('Country / Region', 'fluent-cart'),
220 'value' => $selectedCountry,
221 ],
222 'address_1' => [
223 'name' => $type . '_address_1',
224 'id' => $type . '_address_1',
225 'type' => 'text',
226 'data-type' => 'text',
227 'label' => '',
228 'aria-label' => esc_attr__('Street Address', 'fluent-cart'),
229 /* translators: use local order of street name and house number. */
230 'placeholder' => esc_attr__('Street Address', 'fluent-cart'),
231 'required' => 'yes',
232 'autocomplete' => 'address-line1',
233 'value' => $config['address_1'],
234 ],
235 'address_2' => [
236 'name' => $type . '_address_2',
237 'id' => $type . '_address_2',
238 'type' => 'text',
239 'data-type' => 'text',
240 'label' => '',
241 'aria-label' => esc_attr__('Apt, suite, unit', 'fluent-cart'),
242 'label_class' => array(''),
243 'placeholder' => esc_attr__('Apt, suite, unit', 'fluent-cart'),
244 'autocomplete' => 'address-line2',
245 'value' => $config['address_2'],
246 ],
247 'state' => $stateInput,
248 'city' => [
249 'name' => $type . '_city',
250 'id' => $type . '_city',
251 'type' => 'text',
252 'data-type' => 'text',
253 'label' => '',
254 'aria-label' => esc_attr__('Town / City', 'fluent-cart'),
255 'required' => 'yes',
256 'autocomplete' => 'address-level2',
257 'placeholder' => esc_attr__('Town / City', 'fluent-cart'),
258 'value' => $config['city'],
259 ],
260 'postcode' => [
261 'name' => $type . '_postcode',
262 'id' => $type . '_postcode',
263 'type' => 'text',
264 'data-type' => 'text',
265 'label' => '',
266 'aria-label' => esc_attr__('Postal / ZIP Code', 'fluent-cart'),
267 'required' => 'yes',
268 'validate' => array('postcode'),
269 'autocomplete' => 'postal-code',
270 'placeholder' => esc_attr__('Postcode / ZIP', 'fluent-cart'),
271 'value' => $config['postcode'],
272 ],
273 'phone' => [
274 'name' => $type . '_phone',
275 'id' => $type . '_phone',
276 'type' => 'tel',
277 'data-type' => 'text',
278 'label' => '',
279 'aria-label' => esc_attr__('Phone number', 'fluent-cart'),
280 'placeholder' => esc_attr__('Phone number', 'fluent-cart'),
281 'autocomplete' => 'tel',
282 'value' => $config['phone'],
283 ],
284 'company_name' => [
285 'name' => $type . '_company_name',
286 'id' => $type . '_company_name',
287 'type' => 'text',
288 'data-type' => 'text',
289 'label' => '',
290 'aria-label' => esc_attr__('Company name', 'fluent-cart'),
291 'placeholder' => esc_attr__('Company name', 'fluent-cart'),
292 'autocomplete' => 'organization',
293 'value' => $config['company_name'],
294 ],
295 ];
296
297 if ($type === 'billing') {
298 unset($fields['full_name']);
299 }
300
301 $requirementsFields = [];
302 if ($scope === 'render') {
303 $requirementsFields = self::getCheckoutFieldsRequirements($type, $config['product_type'], $config['with_shipping']);
304
305 $formattedFields = [];
306 foreach ($fields as $key => $field) {
307 $requirement = Arr::get($requirementsFields, $key, '');
308 if (!$requirement) {
309 continue;
310 }
311 if ($requirement === 'required') {
312 $field['required'] = 'yes';
313 $field['placeholder'] = $field['placeholder'] . ' *';
314 } else {
315 unset($field['required']);
316 }
317 $formattedFields[$key] = $field;
318 }
319 $fields = $formattedFields;
320 }
321
322 return apply_filters('fluent_cart/fields/address_base_fields', $fields, [
323 'config' => $config,
324 'scope' => $scope,
325 'requirements' => $requirementsFields
326 ]);
327 }
328
329
330 private static function getRequirementType($config, $key)
331 {
332 $enabled = Arr::get($config, $key . '.enabled', 'no') === 'yes';
333 if (!$enabled) {
334 return '';
335 }
336
337 if (Arr::get($config, $key . '.required', 'no') === 'yes') {
338 return 'required';
339 }
340
341 return 'optional';
342 }
343
344 public static function getCheckoutFieldsRequirements($addressType = 'billing', $productType = 'digital', $withShipping = false) // digital or physical
345 {
346 $fieldsConfig = self::getFieldsSettings();
347
348
349 $shippingConfig = Arr::get($fieldsConfig, 'shipping_address', []);
350 $billingConfig = Arr::get($fieldsConfig, 'billing_address', []);
351 $basicConfig = Arr::get($fieldsConfig, 'basic_info', []);
352 $basicSchema = [];
353
354 if (static::isFullNameRequired()) {
355 $basicSchema = [
356 'full_name' => [
357 'billing' => '',
358 'shipping' => 'required'
359 ],
360 ];
361 } else {
362 $basicSchema = [
363 'first_name' => [
364 'billing' => 'required',
365 'shipping' => 'required'
366 ],
367 ];
368
369 if (static::isLastNameEnabled()) {
370 $basicSchema['last_name'] = [
371 'billing' => static::isLastNameRequired() ? 'required' : '',
372 'shipping' => static::isLastNameRequired() ? 'required' : ''
373 ];
374 }
375 }
376
377 $dataConfig = [
378 'country' => [
379 'billing' => self::getRequirementType($billingConfig, 'country'),
380 'shipping' => self::getRequirementType($shippingConfig, 'country')
381 ],
382 'address_1' => [
383 'billing' => self::getRequirementType($billingConfig, 'address_1'),
384 'shipping' => self::getRequirementType($shippingConfig, 'address_1')
385 ],
386 'address_2' => [
387 'billing' => self::getRequirementType($billingConfig, 'address_2'),
388 'shipping' => self::getRequirementType($shippingConfig, 'address_2')
389 ],
390 'state' => [
391 'billing' => self::getRequirementType($billingConfig, 'state'),
392 'shipping' => self::getRequirementType($shippingConfig, 'state')
393 ],
394 'city' => [
395 'billing' => self::getRequirementType($billingConfig, 'city'),
396 'shipping' => self::getRequirementType($shippingConfig, 'city')
397 ],
398 'postcode' => [
399 'billing' => self::getRequirementType($billingConfig, 'postcode'),
400 'shipping' => self::getRequirementType($shippingConfig, 'postcode')
401 ],
402 'company_name' => [
403 'billing' => self::getRequirementType($billingConfig, 'company_name'),
404 'shipping' => self::getRequirementType($shippingConfig, 'company_name')
405 ],
406 'phone' => [
407 'billing' => self::getRequirementType($billingConfig, 'phone'),
408 'shipping' => self::getRequirementType($shippingConfig, 'phone')
409 ]
410 ];
411 $dataConfig = array_merge(
412 $basicSchema,
413 $dataConfig
414 );
415
416
417 if ($withShipping && $addressType == 'billing') {
418 // now we have to merge the shipping fields requirements with billing fields requirements
419 foreach ($dataConfig as $key => $config) {
420 if ($config[$addressType] === 'required') {
421 $dataConfig[$key][$addressType] = 'required';
422 } elseif ($config[$addressType] === 'optional' && $dataConfig[$key][$addressType] !== 'required') {
423 $dataConfig[$key][$addressType] = 'optional';
424 } else {
425 $dataConfig[$key][$addressType] = '';
426 }
427 }
428 }
429
430 $formattedReturn = [];
431 foreach ($dataConfig as $key => $config) {
432 if (Arr::get($config, $addressType)) {
433 $formattedReturn[$key] = $config[$addressType];
434 }
435 }
436
437 return $formattedReturn;
438 }
439
440 public static function getFieldsSchemaConfig()
441 {
442 return [
443 'basic_info' => [
444 'full_name' => [
445 'label' => __('Full Name', 'fluent-cart'),
446 'help_text' => __('Enabling First/Last name will replace the default Full Name.', 'fluent-cart'),
447 'type' => 'text',
448 'can_alter' => 'no',
449 ],
450 'first_name' => [
451 'label' => __('First Name', 'fluent-cart'),
452 'type' => 'text',
453 'can_alter' => 'yes',
454 ],
455 'last_name' => [
456 'label' => __('Last Name', 'fluent-cart'),
457 'type' => 'text',
458 'can_alter' => 'yes',
459 ],
460 'email' => [
461 'label' => __('Email Address', 'fluent-cart'),
462 'type' => 'email',
463 'can_alter' => 'no',
464 ],
465 'company_name' => [
466 'label' => __('Company', 'fluent-cart'),
467 'type' => 'text',
468 'can_alter' => 'yes',
469 ]
470 ],
471 'billing_address' => [
472 'country' => [
473 'label' => __('Country', 'fluent-cart'),
474 'type' => 'text',
475 'can_alter' => 'yes',
476 ],
477 'state' => [
478 'label' => __('State', 'fluent-cart'),
479 'type' => 'text',
480 'can_alter' => 'yes',
481 ],
482 'address_1' => [
483 'label' => __('Street Address', 'fluent-cart'),
484 'type' => 'text',
485 'can_alter' => 'yes',
486 ],
487 'address_2' => [
488 'label' => __('Apt, suite, unit', 'fluent-cart'),
489 'type' => 'text',
490 'can_alter' => 'yes',
491 ],
492 'city' => [
493 'label' => __('City', 'fluent-cart'),
494 'type' => 'text',
495 'can_alter' => 'yes',
496 ],
497 'postcode' => [
498 'label' => __('Post Code', 'fluent-cart'),
499 'type' => 'text',
500 'can_alter' => 'yes',
501 ],
502 'phone' => [
503 'label' => __('Phone', 'fluent-cart'),
504 'type' => 'text',
505 'can_alter' => 'yes',
506 ]
507 ],
508 'shipping_address' => [
509 'full_name' => [
510 'label' => __('Full Name', 'fluent-cart'),
511 'type' => 'text',
512 'can_alter' => 'no',
513 ],
514 'country' => [
515 'label' => __('Country', 'fluent-cart'),
516 'type' => 'text',
517 'can_alter' => 'yes',
518 ],
519 'state' => [
520 'label' => __('State', 'fluent-cart'),
521 'type' => 'text',
522 'can_alter' => 'yes',
523 ],
524 'address_1' => [
525 'label' => __('Street Address', 'fluent-cart'),
526 'type' => 'text',
527 'can_alter' => 'yes',
528 ],
529 'address_2' => [
530 'label' => __('Apt, suite, unit', 'fluent-cart'),
531 'type' => 'text',
532 'can_alter' => 'yes',
533 ],
534 'city' => [
535 'label' => __('City', 'fluent-cart'),
536 'type' => 'text',
537 'can_alter' => 'yes',
538 ],
539 'postcode' => [
540 'label' => __('Post Code', 'fluent-cart'),
541 'type' => 'text',
542 'can_alter' => 'yes',
543 ],
544 'phone' => [
545 'label' => __('Phone', 'fluent-cart'),
546 'type' => 'text',
547 'can_alter' => 'yes',
548 ]
549 ],
550 'agree_terms' => [
551 'label' => __('Agree Terms and Conditions', 'fluent-cart'),
552 'type' => 'checkbox',
553 'can_alter' => 'yes',
554 ]
555 ];
556 }
557
558 public static function getFieldsSettings()
559 {
560 $defaults = [
561 'basic_info' => [
562 'full_name' => [
563 'required' => 'yes',
564 'enabled' => 'yes'
565 ],
566 'first_name' => [
567 'required' => 'no',
568 'enabled' => 'no'
569 ],
570 'last_name' => [
571 'required' => 'no',
572 'enabled' => 'no'
573 ],
574 'email' => [
575 'required' => 'yes',
576 'enabled' => 'yes'
577 ],
578 'company_name' => [
579 'required' => 'no',
580 'enabled' => 'no'
581 ]
582 ],
583 'billing_address' => [
584 'country' => [
585 'required' => 'yes',
586 'enabled' => 'yes'
587 ],
588 'state' => [
589 'required' => 'yes',
590 'enabled' => 'yes'
591 ],
592 'address_1' => [
593 'required' => 'yes',
594 'enabled' => 'yes'
595 ],
596 'address_2' => [
597 'required' => 'no',
598 'enabled' => 'yes'
599 ],
600 'city' => [
601 'required' => 'yes',
602 'enabled' => 'yes'
603 ],
604 'postcode' => [
605 'required' => 'yes',
606 'enabled' => 'yes'
607 ],
608 'phone' => [
609 'required' => 'no',
610 'enabled' => 'no'
611 ],
612 'company_name' => [
613 'required' => 'no',
614 'enabled' => 'no'
615 ]
616 ],
617 'shipping_address' => [
618 'full_name' => [
619 'required' => 'yes',
620 'enabled' => 'yes',
621 ],
622 'country' => [
623 'required' => 'yes',
624 'enabled' => 'yes'
625 ],
626 'state' => [
627 'required' => 'yes',
628 'enabled' => 'yes'
629 ],
630 'address_1' => [
631 'required' => 'yes',
632 'enabled' => 'yes'
633 ],
634 'address_2' => [
635 'required' => 'no',
636 'enabled' => 'yes'
637 ],
638 'city' => [
639 'required' => 'yes',
640 'enabled' => 'yes'
641 ],
642 'postcode' => [
643 'required' => 'yes',
644 'enabled' => 'yes'
645 ],
646 'phone' => [
647 'required' => 'no',
648 'enabled' => 'no'
649 ],
650 'company_name' => [
651 'required' => 'no',
652 'enabled' => 'no'
653 ]
654 ],
655 'agree_terms' => [
656 'required' => 'no',
657 'enabled' => 'no',
658 'text' => ''
659 ]
660 ];
661
662 $savedConfig = fluent_cart_get_option('_fc_checkout_fields', []);
663
664 if (!$savedConfig || !is_array($savedConfig)) {
665 return $defaults;
666 }
667
668 $groupFields = ['basic_info', 'billing_address', 'shipping_address'];
669
670 foreach ($defaults as $key => $default) {
671 $savedValues = Arr::get($savedConfig, $key, []);
672 if (in_array($key, $groupFields)) {
673 $savedValues = Arr::only($savedValues, array_keys($default));
674 }
675
676 $defaults[$key] = wp_parse_args($savedValues, $default);
677 }
678
679 return $defaults;
680 }
681
682 public static function isTermsRequired(): bool
683 {
684 $fieldSettings = self::getFieldsSettings();
685 return Arr::get($fieldSettings, 'agree_terms.enabled') === 'yes'
686 && Arr::get($fieldSettings, 'agree_terms.required') === 'yes';
687 }
688
689 public static function isTermsVisible(): bool
690 {
691 $fieldSettings = self::getFieldsSettings();
692 return Arr::get($fieldSettings, 'agree_terms.enabled') === 'yes';
693 }
694
695 public static function getTermsText()
696 {
697 $text = Arr::get(self::getFieldsSettings(), 'agree_terms.text', '');
698
699 if (!$text) {
700 $text = __('I agree to the terms and conditions.', 'fluent-cart');
701 }
702
703 return $text;
704 }
705
706 public static function isFirstNameEnabled(): bool
707 {
708 $fieldsSchema = self::getFieldsSettings();
709 return Arr::get($fieldsSchema, 'basic_info.first_name.enabled') === 'yes';
710
711 }
712
713 public static function isLastNameEnabled(): bool
714 {
715 $fieldsSchema = self::getFieldsSettings();
716 return Arr::get($fieldsSchema, 'basic_info.last_name.enabled') === 'yes';
717 }
718
719 public static function isLastNameRequired(): bool
720 {
721 $fieldsSchema = self::getFieldsSettings();
722 return Arr::get($fieldsSchema, 'basic_info.last_name.required') === 'yes';
723 }
724
725 public static function isFullNameRequired(): bool
726 {
727
728 $isFirstNameEnabled = static::isFirstNameEnabled();
729 $isLastNameEnabled = static::isLastNameEnabled();
730 return !($isFirstNameEnabled || $isLastNameEnabled);
731 }
732 }
733