PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.0
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.0
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 / Modules / StorageDrivers / S3 / S3.php

S3.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.6.0, at app/Modules/StorageDrivers/S3/S3.php

757 lines 25.2 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\Modules\StorageDrivers\S3;
4
5 use FluentCart\App\Helpers\Helper;
6 use FluentCart\App\Services\FileSystem\Drivers\S3\S3ConnectionVerify;
7 use FluentCart\App\Services\FileSystem\Drivers\S3\S3Driver;
8 use FluentCart\App\Services\FileSystem\Drivers\S3\S3InputValidator;
9 use FluentCart\App\Vite;
10 use FluentCart\App\Modules\StorageDrivers\BaseStorageDriver;
11 use FluentCart\Framework\Support\Arr;
12
13 class S3 extends BaseStorageDriver
14 {
15 /**
16 * title, slug, brandColor
17 */
18 public function __construct()
19 {
20 parent::__construct(
21 __('S3', 'fluent-cart'),
22 's3',
23 '#4f94d4'
24 );
25 }
26
27 public function registerHooks()
28 {
29 add_filter('fluent_cart/verify_driver_connect_info_' . $this->slug, [$this, 'verifyConnectInfo'], 10, 2);
30 add_filter('fluent_cart/get_dynamic_search_s3_bucket_list', [$this, 'getBucketList'], 10, 2);
31 }
32
33 public function getBucketList($buckets = [], $args = []): array
34 {
35 $driverSettings = Arr::get($args, 'driver_settings', []);
36 $query = strtolower(trim((string) Arr::get($args, 'query', '')));
37 $resolvedCredentials = $this->resolveCredentials($driverSettings);
38
39 if (empty($resolvedCredentials['access_key']) || empty($resolvedCredentials['secret_key'])) {
40 return [];
41 }
42
43 $bucketList = \FluentCart\App\Services\FileSystem\Drivers\S3\S3BucketList::get(
44 $resolvedCredentials['secret_key'],
45 $resolvedCredentials['access_key'],
46 'us-east-1',
47 $resolvedCredentials['session_token']
48 );
49
50 if (is_wp_error($bucketList)) {
51 return [];
52 }
53
54 if ($query !== '') {
55 $bucketList = array_values(array_filter($bucketList, function ($bucket) use ($query) {
56 return strpos(strtolower((string) $bucket), $query) !== false;
57 }));
58 }
59
60 $bucketList = array_slice($bucketList, 0, 50);
61
62 $buckets = [];
63 foreach ($bucketList as $bucket) {
64 $buckets[] = array(
65 "label" => $bucket,
66 "value" => $bucket,
67 );
68 }
69 return $buckets;
70 }
71
72 public function getLogo(): string
73 {
74 return Vite::getAssetUrl("images/storage-drivers/s3.svg");
75 }
76
77 public function getDarkLogo()
78 {
79 return Vite::getAssetUrl("images/storage-drivers/s3-dark.svg");
80 }
81
82 public function hasBucket(): bool
83 {
84 return true;
85 }
86
87 public function needsReconfigure(): bool
88 {
89 return S3Settings::resolveConfiguredBucket($this->getSettings()) === '';
90 }
91
92
93 public function getDescription()
94 {
95 return esc_html__('S3 bucket allows to configure storage options and others for efficient and secure cloud-based file storage', 'fluent-cart');
96 }
97
98 public function isEnabled(): bool
99 {
100 $settings = $this->getSettings();
101 $isActive = Arr::get($settings, 'is_active') === 'yes';
102 $hasSelectedBucket = S3Settings::resolveEffectiveBucket($settings) !== '';
103 return $isActive && $hasSelectedBucket;
104 }
105
106 public function getSettings()
107 {
108 return (new S3Settings())->get();
109 }
110
111 public function getSettingsTemplate(): ?string
112 {
113 $templatePath = dirname(__DIR__, 4) . '/app/Modules/StorageDrivers/S3/VueTemplates/SettingsPage.vue';
114
115 if (!file_exists($templatePath)) {
116 return null;
117 }
118
119 $template = file_get_contents($templatePath);
120
121 return $template ?: null;
122 }
123
124 public function getSettingsTemplatePayload(array $response = []): array
125 {
126 return array_merge(parent::getSettingsTemplatePayload($response), [
127 'connection_verify_endpoint' => 'settings/storage-drivers/verify-info',
128 'create_bucket_endpoint' => 'settings/storage-drivers/create-bucket',
129 'bucket_list_endpoint' => 'settings/storage-drivers/bucket-list',
130 'save_endpoint' => 'settings/storage-drivers',
131 'reset_endpoint' => 'settings/storage-drivers/reset',
132 'supports_template_mode' => true,
133 ]);
134 }
135
136 public function listBuckets(array $data, array $args = [])
137 {
138 $credentialError = $this->requireCredentials($data);
139 if ($credentialError) {
140 return $credentialError;
141 }
142
143 return $this->getBucketList([], [
144 'driver_settings' => $data,
145 'query' => Arr::get($args, 'query')
146 ]);
147 }
148
149 public function createBucket(array $data)
150 {
151 $credentialError = $this->requireCredentials($data);
152 if ($credentialError) {
153 return $credentialError;
154 }
155
156 $resolvedCredentials = $this->resolveCredentials($data);
157
158 if (empty($resolvedCredentials['access_key']) || empty($resolvedCredentials['secret_key'])) {
159 return new \WP_Error('invalid_credentials', __('Invalid credentials for bucket creation', 'fluent-cart'));
160 }
161
162 $newBucket = sanitize_text_field(Arr::get($data, 'new_bucket_name'));
163 $newBucket = strtolower($newBucket);
164 $newBucket = preg_replace('/[^a-z0-9\.-]/', '-', $newBucket);
165 $newBucket = preg_replace('/-+/', '-', $newBucket);
166 $newBucket = trim($newBucket, '-.');
167
168 $newRegion = sanitize_text_field(Arr::get($data, 'new_bucket_region', 'us-east-1')) ?: 'us-east-1';
169
170 if (!$newBucket) {
171 return new \WP_Error('invalid_bucket', __('Bucket name is required', 'fluent-cart'));
172 }
173
174 $validation = S3InputValidator::validateBucketAndRegion($newBucket, $newRegion);
175 if (is_wp_error($validation)) {
176 return $validation;
177 }
178
179 $creation = \FluentCart\App\Services\FileSystem\Drivers\S3\S3BucketCreator::create(
180 $resolvedCredentials['secret_key'],
181 $resolvedCredentials['access_key'],
182 $newBucket,
183 $newRegion,
184 $resolvedCredentials['session_token']
185 );
186
187 if (is_wp_error($creation)) {
188 return $creation;
189 }
190
191 $bucketCheck = S3ConnectionVerify::checkBucketExistence(
192 $resolvedCredentials['secret_key'],
193 $resolvedCredentials['access_key'],
194 $resolvedCredentials['session_token'],
195 $newBucket,
196 $newRegion
197 );
198
199 if (is_wp_error($bucketCheck)) {
200 return $bucketCheck;
201 }
202
203 $region = Arr::get($bucketCheck, 'region', $newRegion);
204
205 $securitySettings = S3ConnectionVerify::checkSecuritySettings(
206 $resolvedCredentials['secret_key'],
207 $resolvedCredentials['access_key'],
208 $resolvedCredentials['session_token'],
209 $newBucket,
210 $region
211 );
212
213 return [
214 'message' => __('Bucket created successfully', 'fluent-cart'),
215 'bucket' => $newBucket,
216 'region' => $region,
217 'connection_error' => '',
218 'block_public_access' => !empty($securitySettings['block_public_access']) ? 'yes' : 'no',
219 'object_ownership' => !empty($securitySettings['object_ownership']) ? 'yes' : 'no'
220 ];
221 }
222
223 public function updateSettings($data)
224 {
225 $settings = $this->getSettings();
226
227 if (!array_key_exists('auth_method', $data) && isset($settings['auth_method'])) {
228 $data['auth_method'] = $settings['auth_method'];
229 }
230
231 if (!array_key_exists('buckets', $data) && isset($settings['buckets'])) {
232 $data['buckets'] = $settings['buckets'];
233 }
234
235 $mergeKeys = array_diff($this->hiddenSettingKeys(), ['create_new_bucket', 'new_bucket_name', 'new_bucket_region']);
236 foreach ($mergeKeys as $key) {
237 if (!array_key_exists($key, $data) && isset($settings[$key])) {
238 $data[$key] = $settings[$key];
239 }
240 }
241
242 if (
243 Arr::get($data, 'is_active') === 'no' &&
244 !Arr::get($data, 'verify_only_credentials') &&
245 !Arr::get($data, 'check_bucket_exists')
246 ) {
247 $data['is_active'] = 'no';
248
249 if (!Arr::get($data, 'preserve_settings')) {
250 $resetSettings = $this->resetSettings();
251
252 return [
253 'data' => Arr::except($resetSettings, $this->hiddenSettingKeys()),
254 'message' => __('S3 settings have been reset successfully', 'fluent-cart'),
255 'shouldReload' => false
256 ];
257 }
258
259 if (!empty($data['bucket'])) {
260 $data['show_buckets'] = 'yes';
261 }
262
263 parent::updateSettings($this->prepareSettingsForStorage($data));
264
265 return [
266 'data' => Arr::except($data, $this->hiddenSettingKeys()),
267 'message' => __('S3 is deactivated successfully', 'fluent-cart'),
268 'shouldReload' => false
269 ];
270 }
271
272 $credentialError = $this->requireCredentials($data);
273 if ($credentialError) {
274 return $credentialError;
275 }
276
277 $resolvedCredentials = $this->resolveCredentials($data);
278 $userBlockPublicAccess = Arr::get($data, 'block_public_access');
279 $userObjectOwnership = Arr::get($data, 'object_ownership');
280 $verificationResult = true;
281
282 if (Arr::get($data, 'verify_only_credentials')) {
283 $verificationResult = $this->verifyConnectInfo($data);
284 if (is_wp_error($verificationResult)) {
285 return $verificationResult;
286 }
287 }
288
289 if (!empty($data['bucket'])) {
290 $bucketValidation = S3InputValidator::validateBucket($data['bucket']);
291 if (is_wp_error($bucketValidation)) {
292 return $bucketValidation;
293 }
294
295 if (!empty($data['region'])) {
296 $regionValidation = S3InputValidator::validateRegion($data['region']);
297 if (is_wp_error($regionValidation)) {
298 return $regionValidation;
299 }
300 }
301
302 $region = Arr::get($data, 'region') ?: self::getBucketRegion($data['bucket']) ?: 'us-east-1';
303
304 $bucketCheck = S3ConnectionVerify::checkBucketExistence(
305 $resolvedCredentials['secret_key'],
306 $resolvedCredentials['access_key'],
307 $resolvedCredentials['session_token'],
308 $data['bucket'],
309 $region
310 );
311
312 if (is_wp_error($bucketCheck)) {
313 $errorSettings = $settings;
314 $errorSettings['connection_error'] = $bucketCheck->get_error_message();
315
316 parent::updateSettings($this->prepareSettingsForStorage($errorSettings));
317
318 return $bucketCheck;
319 }
320
321 $data['connection_error'] = '';
322
323 if (isset($bucketCheck['region']) && $bucketCheck['region'] !== Arr::get($data, 'region')) {
324 $data['region'] = $bucketCheck['region'];
325 }
326
327 $securitySettings = S3ConnectionVerify::checkSecuritySettings(
328 $resolvedCredentials['secret_key'],
329 $resolvedCredentials['access_key'],
330 $resolvedCredentials['session_token'],
331 $data['bucket'],
332 Arr::get($data, 'region') ?: $region
333 );
334
335 $bucketCheck['block_public_access'] = Arr::get($securitySettings, 'block_public_access');
336 $bucketCheck['object_ownership'] = Arr::get($securitySettings, 'object_ownership');
337 $verificationResult = $bucketCheck;
338 }
339
340 if (is_array($verificationResult) && array_key_exists('block_public_access', $verificationResult) && $userBlockPublicAccess === null) {
341 $data['block_public_access'] = $verificationResult['block_public_access'] ? 'yes' : 'no';
342 }
343
344 if (is_array($verificationResult) && array_key_exists('object_ownership', $verificationResult) && $userObjectOwnership === null) {
345 $data['object_ownership'] = $verificationResult['object_ownership'] ? 'yes' : 'no';
346 }
347
348 if (
349 !empty($data['bucket']) &&
350 Arr::get($data, 'is_active') === 'yes' &&
351 !Arr::get($data, 'verify_only_credentials') &&
352 !is_wp_error($verificationResult)
353 ) {
354 $bucketRegion = Arr::get($data, 'region') ?: self::getBucketRegion($data['bucket']) ?: 'us-east-1';
355
356 if ($userBlockPublicAccess !== null) {
357 $enableBlock = $this->isTrue($userBlockPublicAccess);
358 $syncResult = S3ConnectionVerify::updatePublicAccessBlock(
359 $resolvedCredentials['secret_key'],
360 $resolvedCredentials['access_key'],
361 $resolvedCredentials['session_token'],
362 $data['bucket'],
363 $enableBlock,
364 $bucketRegion
365 );
366
367 if (is_wp_error($syncResult)) {
368 return $syncResult;
369 }
370
371 $data['block_public_access'] = $enableBlock ? 'yes' : 'no';
372 }
373
374 if ($userObjectOwnership !== null) {
375 $enableOwnership = $this->isTrue($userObjectOwnership);
376 $syncResult = S3ConnectionVerify::updateObjectOwnership(
377 $resolvedCredentials['secret_key'],
378 $resolvedCredentials['access_key'],
379 $resolvedCredentials['session_token'],
380 $data['bucket'],
381 $enableOwnership,
382 $bucketRegion
383 );
384
385 if (is_wp_error($syncResult)) {
386 return $syncResult;
387 }
388
389 $data['object_ownership'] = $enableOwnership ? 'yes' : 'no';
390 }
391 }
392
393 if (Arr::get($data, 'verify_only_credentials') || !empty($data['bucket']) || Arr::get($data, 'is_active') === 'yes') {
394 $data['show_buckets'] = 'yes';
395 }
396
397 if (Arr::get($data, 'is_active') === 'yes') {
398 $data['is_active'] = 'yes';
399 $data['connection_error'] = '';
400 }
401
402 parent::updateSettings($this->prepareSettingsForStorage($data));
403
404 $shouldReload = Arr::get($data, 'is_active') === 'yes';
405
406 if (empty($message)) {
407 if (Arr::get($data, 'is_active') === 'yes') {
408 $message = __('Your s3 storage is activated successfully', 'fluent-cart');
409 } else {
410 $message = __('Settings saved successfully.', 'fluent-cart');
411 }
412 }
413
414
415 return [
416 'data' => Arr::except($data, $this->hiddenSettingKeys()),
417 'message' => $message,
418 'shouldReload' => $shouldReload
419 ];
420 }
421
422 private function requireCredentials(array $data)
423 {
424 $settings = $this->getSettings();
425 $authMethod = Arr::get($data, 'auth_method', Arr::get($settings, 'auth_method', 'db'));
426
427 if ($authMethod === 'define' && !S3Settings::hasDefinedCredentials()) {
428 return new \WP_Error(
429 'missing_credentials',
430 __('S3 credentials are not defined in wp-config.php. Please add them and try again.', 'fluent-cart')
431 );
432 }
433
434 return null;
435 }
436
437 private function resolveCredentials(array $data): array
438 {
439 $settings = $this->getSettings();
440 $authMethod = Arr::get($data, 'auth_method', Arr::get($settings, 'auth_method', 'db'));
441
442 if ($authMethod === 'define') {
443 $definedCredentials = S3Settings::getDefinedCredentials();
444
445 if (!empty($definedCredentials)) {
446 return [
447 'access_key' => Arr::get($definedCredentials, 'access_key', ''),
448 'secret_key' => Arr::get($definedCredentials, 'secret_key', ''),
449 'session_token' => null
450 ];
451 }
452 }
453
454 $accessKey = Arr::get($data, 'access_key');
455 if (empty($accessKey)) {
456 $accessKey = Arr::get($settings, 'access_key');
457 }
458
459 $secretKey = Arr::get($data, 'secret_key');
460 if (empty($secretKey)) {
461 $secretKey = Arr::get($settings, 'secret_key');
462 }
463
464 return [
465 'access_key' => $accessKey,
466 'secret_key' => $secretKey,
467 'session_token' => null
468 ];
469 }
470
471 public function resetSettings()
472 {
473 fluent_cart_update_option($this->driverHandler, []);
474 S3Settings::$cachedSettings = null;
475
476 return $this->getSettings();
477 }
478
479 private function prepareSettingsForStorage(array $settings): array
480 {
481 if (Arr::get($settings, 'auth_method') === 'define') {
482 unset($settings['access_key'], $settings['secret_key'], $settings['session_token']);
483 } else {
484 if (!empty($settings['access_key'])) {
485 $settings['access_key'] = Helper::encryptKey($settings['access_key']);
486 }
487
488 if (!empty($settings['secret_key'])) {
489 $settings['secret_key'] = Helper::encryptKey($settings['secret_key']);
490 }
491 }
492
493 unset($settings['create_new_bucket'], $settings['new_bucket_name'], $settings['new_bucket_region']);
494 unset($settings['verify_credentials'], $settings['verify_only_credentials'], $settings['preserve_settings'], $settings['check_bucket_exists']);
495
496 return $settings;
497 }
498
499 /**
500 * Verify Connect configuration
501 */
502 public function verifyConnectInfo(array $data, $args = [])
503 {
504 $credentialError = $this->requireCredentials($data);
505 if ($credentialError) {
506 return $credentialError;
507 }
508
509 $resolvedCredentials = $this->resolveCredentials($data);
510 $accessKey = Arr::get($resolvedCredentials, 'access_key');
511 $secretKey = Arr::get($resolvedCredentials, 'secret_key');
512 $sessionToken = Arr::get($resolvedCredentials, 'session_token');
513
514 if (empty($secretKey) || empty($accessKey)) {
515 return new \WP_Error('invalid_credentials', __('Invalid credentials', 'fluent-cart'));
516 }
517
518 $verifyOnlyCredentials = (bool) Arr::get($data, 'verify_only_credentials');
519 $bucket = '';
520 $region = 'us-east-1';
521
522 if (!$verifyOnlyCredentials) {
523 $bucket = Arr::get($data, 'bucket');
524
525 if ($bucket) {
526 $bucketValidation = S3InputValidator::validateBucket($bucket);
527 if (is_wp_error($bucketValidation)) {
528 return $bucketValidation;
529 }
530
531 $region = Arr::get($data, 'region');
532
533 if ($region) {
534 $regionValidation = S3InputValidator::validateRegion($region);
535 if (is_wp_error($regionValidation)) {
536 return $regionValidation;
537 }
538 }
539
540 if (!$region) {
541 $region = self::getBucketRegion($bucket);
542 }
543 }
544 }
545
546 if (!$region && $bucket) {
547 return new \WP_Error('missing_region', __('Region information is missing for the selected bucket.', 'fluent-cart'));
548 }
549
550 $result = S3ConnectionVerify::verify(
551 $secretKey,
552 $accessKey,
553 $sessionToken,
554 $bucket,
555 $region ?: 'us-east-1'
556 );
557
558 if (!is_wp_error($result)) {
559 $result['is_active'] = 'yes';
560 }
561
562 return $result;
563 }
564
565 public function fields(): array
566 {
567 $settings = $this->getSettings();
568 $showBucket = Arr::get($settings, 'show_buckets') === 'yes';
569 $usingDefineMode = Arr::get($settings, 'auth_method') === 'define';
570
571 $schema = [
572 'is_active' => [
573 'value' => '',
574 'label' => __('Enable s3 driver', 'fluent-cart'),
575 'type' => 'checkbox',
576 'attributes' => [
577 'disabled' => !$showBucket
578 ],
579 ],
580 'access_key' => [
581 'conditions' => [
582 [
583 'key' => 'is_active',
584 'operator' => '==',
585 'value' => 'yes'
586 ],
587 ],
588 'value' => '',
589 'label' => __('Access Key', 'fluent-cart'),
590 'type' => 'text',
591 'placeholder' => __('Enter access key', 'fluent-cart')
592 ],
593 'secret_key' => [
594 'conditions' => [
595 [
596 'key' => 'is_active',
597 'operator' => '==',
598 'value' => 'yes'
599 ],
600 ],
601 'value' => '',
602 'label' => __('Secret Key', 'fluent-cart'),
603 'type' => 'text',
604 'attributes' => [
605 'type' => 'password'
606 ],
607 'placeholder' => __('Enter secret key', 'fluent-cart')
608 ],
609 ];
610
611
612 if ($showBucket) {
613 $bucketList = Arr::get($settings, 'buckets', []);
614 $buckets = [];
615
616 foreach ($bucketList as $bucket) {
617 $buckets[] = array(
618 "label" => $bucket,
619 "value" => $bucket,
620 );
621 }
622
623 $schema['buckets'] = [
624 'conditions' => [
625 [
626 'key' => 'is_active',
627 'operator' => '==',
628 'value' => 'yes'
629 ],
630 ],
631 'value' => '',
632 'label' => __('Buckets', 'fluent-cart'),
633 'type' => 'remote_select',
634 'remote_key' => 's3_bucket_list',
635 'multiple' => true,
636 'options' => [],
637 'placeholder' => __('Select bucket', 'fluent-cart'),
638 'search_only_on_type' => false,
639 ];
640 }
641
642 if ($usingDefineMode) {
643 unset($schema['access_key'], $schema['secret_key']);
644 $schema['is_using_define_mode'] = [
645 'value' => Arr::get($settings, 'define_credentials_missing')
646 ? Arr::get($settings, 'define_credentials_missing_message')
647 : __('Using Define Mode', 'fluent-cart'),
648 'type' => 'html'
649 ];
650 }
651
652 return [
653 'view' => [
654 'title' => __('S3 Settings', 'fluent-cart'),
655 'type' => 'section',
656 'disable_nesting' => true,
657 'columns' => [
658 'default' => 1,
659 'md' => 1
660 ],
661 'schema' => $schema
662 ]
663 ];
664 }
665
666 public function getDriverClass(): string
667 {
668 return S3Driver::class;
669 }
670
671 public function hiddenSettingKeys(): array
672 {
673 return [
674 'show_buckets',
675 'access_key',
676 'secret_key',
677 'session_token',
678 'create_new_bucket',
679 'new_bucket_name',
680 'new_bucket_region',
681 'verify_credentials',
682 'verify_only_credentials',
683 'preserve_settings',
684 'check_bucket_exists',
685 ];
686 }
687
688 public static function getBucketRegion($bucket)
689 {
690 if (!S3InputValidator::isValidBucket($bucket)) {
691 return null;
692 }
693
694 $cacheKey = 'fct_s3_region';
695 $existingMeta = \FluentCart\App\Models\Meta::query()->where('meta_key', $cacheKey)->first();
696
697
698 if ($existingMeta) {
699 $region = Arr::get($existingMeta->meta_value, $bucket);
700 if ($region) {
701 return $region;
702 }
703 }
704
705 //$url = "https://{$bucket}.s3.amazonaws.com"; // The global endpoint
706 if (strpos($bucket, '.') !== false) {
707 // If bucket contains dot, use path-style (required for SSL)
708 $url = "https://s3.amazonaws.com/{$bucket}";
709 } else {
710 // Normal bucket: use virtual-hosted style
711 $url = "https://{$bucket}.s3.amazonaws.com";
712 }
713
714
715 $response = wp_remote_head($url);
716
717 if (is_wp_error($response)) {
718 return null;
719 }
720
721 $headers = wp_remote_retrieve_headers($response);
722
723 $region = Arr::get($headers, 'x-amz-bucket-region') ?? 'us-east-1';
724 if (!S3InputValidator::isValidRegion($region)) {
725 $region = 'us-east-1';
726 }
727
728 // 5. Save or update the Meta record
729 if ($existingMeta) {
730 $values = $existingMeta->meta_value;
731 $values[$bucket] = $region;
732 $existingMeta->meta_value = $values;
733 $existingMeta->save();
734 } else {
735 \FluentCart\App\Models\Meta::query()->create([
736 'meta_key' => $cacheKey,
737 'meta_value' => [
738 $bucket => $region
739 ],
740 ]);
741 }
742
743 return $region;
744 }
745
746 private function isTrue($value)
747 {
748 if (is_string($value)) {
749 $value = strtolower($value);
750
751 return in_array($value, ['yes', 'true', '1', 'on'], true);
752 }
753
754 return (bool) $value;
755 }
756 }
757