PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.6.01
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.6.01
2.10.0 2.10.01 2.9.1 2.9.0 2.8.1 2.8.0 2.7.7 2.7.5 2.7.0 2.6.01 2.6.0 2.5.0 2.4.01 trunk 1.0.90 1.0.91 1.0.92 1.0.93 1.0.94 1.0.95 1.0.96 1.0.97 1.0.98 1.0.99 1.1.0 All 77 releases
fluent-community / app / Functions / Utility.php

Utility.php in FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses 2.6.01, at app/Functions/Utility.php

1,237 lines 48.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCommunity\App\Functions;
4
5 use FluentCommunity\App\App;
6 use FluentCommunity\App\Models\Meta;
7 use FluentCommunity\App\Models\Space;
8 use FluentCommunity\App\Models\SpaceGroup;
9 use FluentCommunity\App\Models\Term;
10 use FluentCommunity\App\Services\FeedsHelper;
11 use FluentCommunity\App\Services\Helper;
12 use FluentCommunity\Framework\Support\Arr;
13 use FluentCommunity\Modules\Course\Model\Course;
14
15 class Utility
16 {
17 public static function isDev()
18 {
19 static $isDev = null;
20 if ($isDev !== null) {
21 return $isDev;
22 }
23
24 $config = App::getInstance()->config;
25 $isDev = $config->get('app.env') === 'dev';
26 return $isDev;
27 }
28
29 public static function getApp($instance = null)
30 {
31 return \FluentCommunity\App\App::getInstance($instance);
32 }
33
34 public static function extender()
35 {
36 return new FluentExtendApi();
37 }
38
39 /**
40 * Get Global Fluent Community Option
41 * @param string $key The option name
42 * @param mixed $default the default value of the option if option is not available
43 * @return mixed
44 */
45 public static function getOption($key, $default = null)
46 {
47 return self::getFromCache('option_' . $key, function () use ($key, $default) {
48 $exist = \FluentCommunity\App\Models\Meta::where('object_type', 'option')
49 ->where('meta_key', $key)
50 ->first();
51
52 if ($exist) {
53 return $exist->value;
54 }
55
56 return $default;
57 });
58 }
59
60 /**
61 * Update Global Fluent Community Option
62 * @param string $key The option name
63 * @param mixed $value the value of the option
64 * @return \FluentCommunity\App\Models\Meta
65 */
66 public static function updateOption($key, $value)
67 {
68 $exist = \FluentCommunity\App\Models\Meta::where('object_type', 'option')
69 ->where('meta_key', $key)
70 ->first();
71 if ($exist) {
72 $exist->value = $value;
73 $exist->save();
74
75 } else {
76 $exist = \FluentCommunity\App\Models\Meta::create([
77 'meta_key' => $key, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
78 'object_type' => 'option',
79 'value' => $value
80 ]);
81 }
82
83 self::setCache('option_' . $key, $value);
84
85 return $exist;
86 }
87
88 public static function deleteOption($key)
89 {
90 \FluentCommunity\App\Models\Meta::where('object_type', 'option')
91 ->where('meta_key', $key)
92 ->delete();
93
94 self::forgetCache('option_' . $key);
95 }
96
97 public static function getFeaturesConfig()
98 {
99 static $features = null;
100
101 if ($features) {
102 return $features;
103 }
104
105 $features = self::getOption('fluent_community_features', []);
106
107 $defaults = [
108 'leader_board_module' => 'yes',
109 'course_module' => 'yes',
110 'giphy_module' => 'no',
111 'giphy_api_key' => '',
112 'emoji_module' => 'yes',
113 'cloud_storage' => 'no',
114 'invitation' => 'yes',
115 'user_badge' => 'yes',
116 'has_crm_sync' => 'no',
117 'content_moderation' => 'no',
118 'followers_module' => 'no',
119 'custom_profile_fields' => 'no',
120 ];
121
122 if (defined('FLUENT_COMMUNITY_CLOUD_STORAGE') && FLUENT_COMMUNITY_CLOUD_STORAGE) {
123 $features['cloud_storage'] = 'yes';
124 }
125
126 $features = wp_parse_args($features, $defaults);
127
128 $hasPro = defined('FLUENT_COMMUNITY_PRO') && FLUENT_COMMUNITY_PRO;
129
130 if (!$hasPro) {
131 $features['leader_board_module'] = 'no';
132 $features['giphy_module'] = 'no';
133 $features['emoji_module'] = 'no';
134 $features['cloud_storage'] = 'no';
135 $features['user_badge'] = 'no';
136 $features['followers_module'] = 'no';
137 $features['custom_profile_fields'] = 'no';
138 }
139
140 return $features;
141 }
142
143 /**
144 * @param $key
145 * @param $callback
146 * @param $expire
147 * @return false|mixed
148 * @internal Internal Function
149 */
150 public static function getFromCache($key, $callback = false, $expire = 3600)
151 {
152 $key = 'focm_' . $key;
153
154 $value = wp_cache_get($key, 'fluent_community');
155
156 if ($value !== false) {
157 return $value;
158 }
159
160 if ($callback) {
161 $value = $callback();
162 if ($value) {
163 wp_cache_set($key, $value, 'fluent_community', $expire);
164 }
165 }
166
167 return $value;
168 }
169
170 /**
171 * @param $key
172 * @param $value
173 * @param $expire
174 * @return bool
175 * @internal Internal Function
176 */
177 public static function setCache($key, $value, $expire = 600)
178 {
179 $key = 'focm_' . $key;
180
181 return wp_cache_set($key, $value, 'fluent_community', $expire);
182 }
183
184 /**
185 * @param $key
186 * @return bool
187 * @internal Internal Function
188 */
189 public static function forgetCache($key)
190 {
191 $key = 'focm_' . $key;
192 return wp_cache_delete($key, 'fluent_community');
193 }
194
195 public static function getCustomizationSettings()
196 {
197 static $settings;
198
199 if ($settings) {
200 return $settings;
201 }
202
203 $defaults = [
204 'dark_mode' => 'yes',
205 'fixed_page_header' => 'yes',
206 'show_powered_by' => 'yes',
207 'feed_link_on_sidebar' => 'yes',
208 'show_post_modal' => 'yes',
209 'fixed_sidebar' => 'no',
210 'icon_on_header_menu' => 'no',
211 'affiliate_id' => '',
212 'rich_post_layout' => 'classic',
213 'member_list_layout' => 'classic', // grid, classic
214 'default_feed_layout' => 'timeline', // list, timeline
215 'disable_feed_layout' => 'no',
216 'post_title_pref' => 'optional',
217 'max_media_per_post' => 4,
218 'disable_feed_sort_by' => 'no',
219 'default_feed_sort_by' => '',
220 'collapse_sidebar_groups' => 'no',
221 'hide_header_on_scroll' => 'no'
222 ];
223 $settings = self::getOption('customization_settings', $defaults);
224
225 $settings = wp_parse_args($settings, $defaults);
226 $settings = apply_filters('fluent_community/customization_settings', $settings);
227 if (!defined('FLUENT_COMMUNITY_PRO')) {
228 $settings['show_powered_by'] = 'yes';
229 $settings['affiliate_id'] = '';
230 $settings['rich_post_layout'] = 'classic';
231 $settings['member_list_layout'] = 'classic';
232 }
233 return $settings;
234 }
235
236 public static function getCustomizationSetting($key)
237 {
238 $settings = self::getCustomizationSettings();
239 return Arr::get($settings, $key);
240 }
241
242 public static function updateCustomizationSettings($settings)
243 {
244 $preSettings = self::getCustomizationSettings();
245 $settings = Arr::only($settings, array_keys($preSettings));
246
247 self::updateOption('customization_settings', $settings);
248
249 return $settings;
250 }
251
252 public static function getPrivacySettings()
253 {
254 static $settings;
255
256 if ($settings) {
257 return $settings;
258 }
259
260 $defaults = [
261 'can_customize_username' => 'no',
262 'can_change_email' => 'no',
263 'show_last_activity' => 'yes',
264 'can_deactive_account' => 'no',
265 'email_auto_login' => 'yes',
266 'enable_gravatar' => 'yes',
267 'enable_user_sync' => 'yes',
268 'members_page_status' => 'everybody', // everybody, logged_in, admin_only
269 'profile_page_visibility' => 'everybody', // everybody, logged_in, admin_only
270 'user_space_visibility' => 'everybody', // everybody, logged_in, admin_only
271 'leaderboard_members_visibility' => 'everybody', // everybody, logged_in, admin_only
272 ];
273
274 $settings = self::getOption('privacy_settings', $defaults);
275
276 $settings = wp_parse_args($settings, $defaults);
277
278 if (!defined('FLUENT_COMMUNITY_PRO')) {
279 $settings['can_customize_username'] = 'no';
280 $settings['can_change_email'] = 'no';
281 $settings['email_auto_login'] = 'no';
282 }
283
284 return $settings;
285 }
286
287 public static function canViewMembersPage()
288 {
289 $pageStatus = self::getPrivacySetting('members_page_status');
290
291 if ($pageStatus == 'everybody') {
292 return apply_filters('fluent_community/can_view_members_page', true, $pageStatus);
293 }
294
295 if ($pageStatus == 'logged_in') {
296 return apply_filters('fluent_community/can_view_members_page', is_user_logged_in(), $pageStatus);
297 }
298
299 return apply_filters('fluent_community/can_view_members_page', Helper::isModerator(), $pageStatus);
300 }
301
302 public static function canViewLeaderboardMembers()
303 {
304 $pageStatus = self::getPrivacySetting('leaderboard_members_visibility');
305
306 if ($pageStatus == 'everybody') {
307 return apply_filters('fluent_community/can_view_leaderboard_members', true, $pageStatus);
308 }
309
310 if ($pageStatus == 'logged_in') {
311 return apply_filters('fluent_community/can_view_leaderboard_members', is_user_logged_in(), $pageStatus);
312 }
313
314 return apply_filters('fluent_community/can_view_leaderboard_members', Helper::isModerator(), $pageStatus);
315 }
316
317 public static function canViewUserProfile($targetUserId = null)
318 {
319 $pageStatus = self::getPrivacySetting('profile_page_visibility');
320
321 if ($pageStatus == 'everybody') {
322 return apply_filters('fluent_community/can_view_user_profile', true, $pageStatus, $targetUserId);
323 }
324
325 if ($pageStatus == 'logged_in') {
326 return apply_filters('fluent_community/can_view_user_profile', is_user_logged_in(), $pageStatus, $targetUserId);
327 }
328
329 $isOwn = $targetUserId && (get_current_user_id() === $targetUserId);
330
331 return apply_filters('fluent_community/can_view_user_profile', ($isOwn || Helper::isModerator()), $pageStatus, $targetUserId);
332 }
333
334 public static function getPrivacySetting($key)
335 {
336 $settings = self::getPrivacySettings();
337 return Arr::get($settings, $key);
338 }
339
340 public static function updatePrivacySettings($settings)
341 {
342 $preSettings = self::getPrivacySettings();
343 $settings = Arr::only($settings, array_keys($preSettings));
344
345 self::updateOption('privacy_settings', $settings);
346 self::forgetCache('privacy_settings');
347
348 return $settings;
349 }
350
351 public static function showLastActivity()
352 {
353 return self::getPrivacySetting('show_last_activity') === 'yes' || Helper::isModerator();
354 }
355
356 public static function isCustomizationEnabled($key, $matchingValue = 'yes')
357 {
358 $settings = self::getCustomizationSettings();
359 return isset($settings[$key]) && $settings[$key] === $matchingValue;
360 }
361
362 public static function getProductUrl($isPowered = false, $params = [])
363 {
364 $url = 'https://fluentcommunity.co/';
365 if ($isPowered) {
366 $defaultParams = [
367 'utm_source' => 'power_footer',
368 'utm_medium' => 'site',
369 'utm_campaign' => 'powered_by'
370 ];
371 $params = wp_parse_args($params, $defaultParams);
372
373 $settings = self::getCustomizationSettings();
374 $affId = Arr::get($settings, 'affiliate_id');
375 if ($affId) {
376 $params['ref'] = $affId;
377 }
378
379 return add_query_arg($params, $url);
380 }
381
382 return add_query_arg([
383 'utm_source' => 'plugin',
384 'utm_medium' => 'site',
385 'utm_campaign' => 'plugin_ui'
386 ], $url);
387 }
388
389 /**
390 * Get the email notification settings.
391 *
392 * @return array The email notification settings.
393 */
394 public static function getEmailNotificationSettings()
395 {
396 static $settings;
397 if ($settings) {
398 return $settings;
399 }
400
401 $default = [
402 'com_my_post_mail' => 'yes',
403 'reply_my_com_mail' => 'yes',
404 'mention_mail' => 'yes',
405 'digest_email_status' => 'no',
406 'digest_mail_day' => 'tue',
407 'daily_digest_time' => '09:00',
408 'send_from_email' => '',
409 'send_from_name' => '',
410 'reply_to_email' => '',
411 'reply_to_name' => '',
412 'email_footer' => 'You are getting this email because you are a member of {{site_name_with_url}}.' . PHP_EOL . PHP_EOL . '{{manage_email_notification_url|Manage Your Email Notifications Preference}}.',
413 'disable_powered_by' => 'no',
414 'logo' => ''
415 ];
416
417 $settings = array_filter(self::getOption('global_email_settings', $default));
418 $settings = wp_parse_args($settings, $default);
419
420 if (!defined('FLUENT_COMMUNITY_PRO')) {
421 $settings['disable_powered_by'] = 'no';
422 }
423
424 if (empty($settings['email_footer_rendered']) && !empty($settings['email_footer'])) {
425 $settings['email_footer_rendered'] = FeedsHelper::mdToHtml($settings['email_footer']);
426 }
427
428 return $settings;
429 }
430
431 public static function hasEmailAnnouncementEnabled()
432 {
433 $settings = self::getEmailNotificationSettings();
434 return Arr::get($settings, 'mention_mail', 'no') === 'yes';
435 }
436
437 public static function postTitlePref()
438 {
439 $pref = self::getCustomizationSetting('post_title_pref');
440
441 if ($pref == 'disabled') {
442 $pref = '';
443 }
444
445 return apply_filters('fluent_community/has_post_title', $pref);
446 }
447
448 public static function getSpaces($byGroups = false)
449 {
450 if ($byGroups) {
451 return SpaceGroup::orderBy('serial', 'ASC')->with('spaces', function ($q) {
452 $q->orderBy('serial', 'ASC')
453 ->where('type', 'community');
454 })->get();
455 }
456
457 return Space::where('type', 'community')->orderBy('serial', 'ASC')->get();
458 }
459
460 public static function getCourses($byGroups = false)
461 {
462 if ($byGroups) {
463 return SpaceGroup::orderBy('serial', 'ASC')->with('spaces', function ($q) {
464 $q->orderBy('serial', 'ASC')
465 ->where('type', 'course');
466 })->get();
467 }
468
469 return Course::orderBy('serial', 'ASC')->get();
470 }
471
472 public static function getTopics()
473 {
474 static $topics;
475 if ($topics) {
476 return $topics;
477 }
478
479 $key = 'fluent_community_post_topics';
480 $topics = self::getFromCache($key, function () {
481 $topics = Term::where('taxonomy_name', 'post_topic')->orderBy('title', 'ASC')->get();
482
483 /*
484 * object_id = term_id
485 * meta_key = space_id
486 */
487 $topicSpaceRelations = Meta::select(['id', 'object_id', 'meta_key'])->where('object_type', 'term_space_relation')
488 ->get();
489
490 $relations = [];
491 foreach ($topicSpaceRelations as $relation) {
492 if (!isset($relations[$relation->object_id])) {
493 $relations[$relation->object_id] = [];
494 }
495
496 $relations[$relation->object_id][] = $relation->meta_key;
497 }
498
499 $formattedTopics = [];
500 foreach ($topics as $topic) {
501 $formattedTopics[] = [
502 'id' => $topic->id,
503 'title' => $topic->title,
504 'description' => $topic->description,
505 'slug' => $topic->slug,
506 'admin_only' => Arr::get($topic->settings, 'admin_only', 'no'),
507 'space_ids' => isset($relations[$topic->id]) ? $relations[$topic->id] : []
508 ];
509 }
510
511 return $formattedTopics;
512 }, MONTH_IN_SECONDS);
513
514 return $topics;
515 }
516
517 public static function getTopicsBySpaceId($spaceId)
518 {
519 $topics = self::getTopics();
520 $topics = array_filter($topics, function ($topic) use ($spaceId) {
521 return in_array($spaceId, $topic['space_ids']);
522 });
523 return array_values($topics);
524 }
525
526 public static function getMaxRunTime()
527 {
528 if (function_exists('ini_get')) {
529 $maxRunTime = (int)ini_get('max_execution_time');
530 if ($maxRunTime === 0) {
531 $maxRunTime = 60;
532 }
533 // If set to 0 (unlimited) or a negative value, return a large number
534 if ($maxRunTime <= 0) {
535 return PHP_INT_MAX;
536 }
537
538 } else {
539 $maxRunTime = 30;
540 }
541
542 if ($maxRunTime > 58) {
543 $maxRunTime = 58;
544 }
545
546 $maxRunTime = $maxRunTime - 3;
547
548 return apply_filters('fluent_community/max_execution_time', $maxRunTime);
549 }
550
551 public static function getColorSchemas()
552 {
553 $defaultCustom = [
554 'title' => __('Custom', 'fluent-community'),
555 'selectors' => [
556 'body' => [],
557 'fcom_top_menu' => [],
558 'spaces' => []
559 ],
560 ];
561 $shemas = apply_filters('fluent-community/color_schemas', [
562 'lightSkins' => [
563 'default' => [
564 'title' => __('Default', 'fluent-community'),
565 'selectors' => [
566 'body' => [
567 'primary_bg' => '#ffffff',
568 'secondary_bg' => '#f0f2f5',
569 'secondary_content_bg' => '#f0f3f5',
570 'active_bg' => '#f0f3f5',
571 'light_bg' => '#E1E4EA',
572 'deep_bg' => '#222530',
573 'menu_text' => '#545861',
574 'primary_text' => '#19283a',
575 'secondary_text' => '#525866',
576 'text_off' => '#959595',
577 'primary_button' => '#2B2E33',
578 'primary_button_text' => '#ffffff',
579 'primary_border' => '#e3e8ee',
580 'secondary_border' => '#9CA3AF',
581 'highlight_bg' => '#fffce3',
582 'text_link' => '#2271b1',
583 ],
584 'fcom_top_menu' => [
585 'primary_bg' => '#ffffff',
586 'primary_border' => '#e3e8ee',
587 'menu_text' => '#545861',
588 'menu_text_active' => '#545861',
589 'active_bg' => '#f0f3f5',
590 'menu_text_hover' => '#545861',
591 'menu_bg_hover' => '#f0f3f5',
592 ],
593 'spaces' => [
594 'primary_bg' => '#ffffff',
595 'primary_border' => '#e3e8ee',
596 'menu_text' => '#545861',
597 'menu_text_active' => '#545861',
598 'menu_text_hover' => '#545861',
599 'menu_bg_hover' => '#f0f3f5',
600 'active_bg' => '#f0f3f5',
601 ]
602 ],
603 ],
604 'sunset_sands' => [
605 'title' => __('Sunset Sands', 'fluent-community'),
606 'selectors' => [
607 'body' => [
608 'primary_bg' => '#FFFFFF',
609 'secondary_bg' => '#FDF6F0',
610 'secondary_content_bg' => '#FDF6F0',
611 'active_bg' => '#FCF0E6',
612 'light_bg' => '#FAE5D3',
613 'deep_bg' => '#2D2D2D',
614 'menu_text' => '#5D5D5D',
615 'primary_text' => '#333333',
616 'secondary_text' => '#666666',
617 'text_off' => '#999999',
618 'text_link' => '#E67E22',
619 'primary_button' => '#E67E22',
620 'primary_button_text' => '#FFFFFF',
621 'primary_border' => '#EADDD3',
622 'secondary_border' => '#E0D0C3',
623 'highlight_bg' => '#FFF5EC',
624 ],
625 'fcom_top_menu' => [
626 'primary_bg' => '#FFFFFF',
627 'primary_border' => '#EADDD3',
628 'menu_text' => '#5D5D5D',
629 'menu_text_active' => '#E67E22',
630 'active_bg' => '#FFF5EC',
631 'menu_text_hover' => '#E67E22',
632 'menu_bg_hover' => '#FFF5EC',
633 ],
634 'spaces' => [
635 'primary_bg' => '#FFFFFF',
636 'primary_border' => '#EADDD3',
637 'menu_text' => '#5D5D5D',
638 'menu_text_hover' => '#E67E22',
639 'menu_bg_hover' => '#FFF5EC',
640 'menu_text_active' => '#FFFFFF',
641 'active_bg' => '#E67E22',
642 ]
643 ]
644 ],
645 'ocean_blue' => [
646 'title' => __('Ocean Blue', 'fluent-community'),
647 'selectors' => [
648 'body' => [
649 'primary_bg' => '#FFFFFF',
650 'secondary_bg' => '#F0F2F5',
651 'secondary_content_bg' => '#f0f3f5',
652 'active_bg' => '#E7F3FF',
653 'light_bg' => '#F6F9FA',
654 'deep_bg' => '#18191A',
655 'menu_text' => '#65676B',
656 'primary_text' => '#050505',
657 'secondary_text' => '#65676B',
658 'text_off' => '#8A8D91',
659 'text_link' => '#216FDB',
660 'primary_button' => '#1877F2',
661 'primary_button_text' => '#FFFFFF',
662 'primary_border' => '#DADDE1',
663 'secondary_border' => '#CED0D4',
664 'highlight_bg' => '#E7F3FF'
665 ],
666 'fcom_top_menu' => [
667 'primary_bg' => '#FFFFFF',
668 'primary_border' => '#DADDE1',
669 'menu_text' => '#65676B',
670 'menu_text_active' => '#1877F2',
671 'active_bg' => '#E7F3FF',
672 'menu_text_hover' => '#1877F2',
673 'menu_bg_hover' => '#E7F3FF',
674 ],
675 'spaces' => [
676 'primary_bg' => '#FFFFFF',
677 'primary_border' => '#DADDE1',
678 'menu_text' => '#65676B',
679 'menu_text_hover' => '#1877F2',
680 'menu_bg_hover' => '#E7F3FF',
681 'menu_text_active' => '#FFFFFF',
682 'active_bg' => '#1877F2'
683 ]
684 ]
685 ],
686 'sky_blue' => [
687 'title' => __('Sky Blue', 'fluent-community'),
688 'selectors' => [
689 'body' => [
690 'primary_bg' => '#FFFFFF',
691 'secondary_bg' => '#F7F9FA',
692 'secondary_content_bg' => '#f0f3f5',
693 'active_bg' => '#E8F5FD',
694 'light_bg' => '#F7F9FA',
695 'deep_bg' => '#15202B',
696 'menu_text' => '#536471',
697 'primary_text' => '#0F1419',
698 'secondary_text' => '#536471',
699 'text_off' => '#8899A6',
700 'text_link' => '#1D9BF0',
701 'primary_button' => '#1D9BF0',
702 'primary_button_text' => '#FFFFFF',
703 'primary_border' => '#EFF3F4',
704 'secondary_border' => '#CFD9DE',
705 'highlight_bg' => '#E8F5FD'
706 ],
707 'fcom_top_menu' => [
708 'primary_bg' => '#FFFFFF',
709 'primary_border' => '#EFF3F4',
710 'menu_text' => '#536471',
711 'menu_text_active' => '#1D9BF0',
712 'active_bg' => '#E8F5FD',
713 'menu_bg_hover' => '#E8F5FD',
714 'menu_text_hover' => '#536471',
715 ],
716 'spaces' => [
717 'primary_bg' => '#FFFFFF',
718 'primary_border' => '#EFF3F4',
719 'menu_text' => '#536471',
720 'menu_text_hover' => '#1D9BF0',
721 'menu_bg_hover' => '#E8F5FD',
722 'menu_text_active' => '#FFFFFF',
723 'active_bg' => '#1D9BF0'
724 ]
725 ]
726 ],
727 'emerald_essence' => [
728 'title' => __('Emerald Essence', 'fluent-community'),
729 'selectors' => [
730 'body' => [
731 'primary_bg' => '#FFFFFF',
732 'secondary_bg' => '#F0F7F4',
733 'secondary_content_bg' => '#f0f3f5',
734 'active_bg' => '#E3F2ED',
735 'light_bg' => '#F7FAFA',
736 'deep_bg' => '#1A2B32',
737 'menu_text' => '#4A5D5E',
738 'primary_text' => '#1F2937',
739 'secondary_text' => '#4B5563',
740 'text_off' => '#9CA3AF',
741 'text_link' => '#059669',
742 'primary_button' => '#10B981',
743 'primary_button_text' => '#FFFFFF',
744 'primary_border' => '#D1E7DD',
745 'secondary_border' => '#A7C4BC',
746 'highlight_bg' => '#ECFDF5'
747 ],
748 'fcom_top_menu' => [
749 'primary_bg' => '#FFFFFF',
750 'primary_border' => '#D1E7DD',
751 'menu_text' => '#4A5D5E',
752 'menu_text_active' => '#059669',
753 'active_bg' => '#ECFDF5',
754 'menu_bg_hover' => '#ECFDF5',
755 'menu_text_hover' => '#4A5D5E',
756 ],
757 'spaces' => [
758 'primary_bg' => '#FFFFFF',
759 'primary_border' => '#D1E7DD',
760 'menu_text' => '#4A5D5E',
761 'menu_text_hover' => '#059669',
762 'menu_bg_hover' => '#ECFDF5',
763 'menu_text_active' => '#FFFFFF',
764 'active_bg' => '#10B981'
765 ]
766 ]
767 ]
768 ],
769 'darkSkins' => [
770 'default' => [
771 'title' => __('Default (Dark)', 'fluent-community'),
772 'selectors' => [
773 'body' => [
774 'primary_bg' => '#2B2E33',
775 'secondary_bg' => '#191B1F',
776 'secondary_content_bg' => '#42464D',
777 'active_bg' => '#42464D',
778 'light_bg' => '#2B303B',
779 'deep_bg' => '#E1E4EA',
780 'menu_text' => '#E4E7EB',
781 'menu_text_active' => '#E4E7EB',
782 'primary_text' => '#F0F3F5',
783 'secondary_text' => '#99A0AE',
784 'menu_bg_hover' => '#E1E4EA',
785 'text_off' => '#A5A9AD',
786 'text_link' => '#60a5fa',
787 'primary_button' => '#FFFFFF',
788 'primary_button_text' => '#2B2E33',
789 'primary_border' => '#42464D',
790 'secondary_border' => '#A5A9AD',
791 'highlight_bg' => '#2c2c1a',
792 ],
793 'fcom_top_menu' => [
794 'primary_bg' => '#2B2E33',
795 'primary_border' => '#42464D',
796 'menu_text' => '#E4E7EB',
797 'menu_text_active' => '#E4E7EB',
798 'active_bg' => '#42464D',
799 'menu_bg_hover' => '#42464D',
800 'menu_text_hover' => '#E4E7EB',
801 ],
802 'spaces' => [
803 'primary_bg' => '#2B2E33',
804 'primary_border' => '#42464D',
805 'menu_text' => '#E4E7EB',
806 'menu_text_active' => '#E4E7EB',
807 'active_bg' => '#42464D',
808 'menu_bg_hover' => '#42464D',
809 'menu_text_hover' => '#fff',
810 ]
811 ],
812 ],
813 'sunset_sands' => [
814 'title' => __('Sunset Sands (Dark)', 'fluent-community'),
815 'selectors' => [
816 'body' => [
817 'primary_bg' => '#1A1A1A',
818 'secondary_bg' => '#222222',
819 'secondary_content_bg' => '#222222',
820 'active_bg' => '#2A2420',
821 'light_bg' => '#33302E',
822 'deep_bg' => '#111111',
823 'menu_text' => '#B0B0B0',
824 'primary_text' => '#E0E0E0',
825 'secondary_text' => '#A0A0A0',
826 'text_off' => '#707070',
827 'text_link' => '#F39C12',
828 'primary_button' => '#F39C12',
829 'primary_border' => '#3A3632',
830 'primary_button_text' => '#1A1A1A',
831 'secondary_border' => '#4C4D4F',
832 'highlight_bg' => '#2A2420',
833 ],
834 'fcom_top_menu' => [
835 'primary_bg' => '#1A1A1A',
836 'primary_border' => '#3A3632',
837 'menu_text' => '#B0B0B0',
838 'menu_text_active' => '#F39C12',
839 'active_bg' => '#2A2420',
840 'menu_text_hover' => '#F39C12',
841 'menu_bg_hover' => '#2A2420',
842 ],
843 'spaces' => [
844 'primary_bg' => '#1A1A1A',
845 'primary_border' => '#3A3632',
846 'menu_text' => '#B0B0B0',
847 'menu_text_hover' => '#F39C12',
848 'menu_bg_hover' => '#2A2420',
849 'menu_text_active' => '#1A1A1A',
850 'active_bg' => '#F39C12',
851 ]
852 ]
853 ],
854 'ocean_blue' => [
855 'title' => __('Ocean Blue (Dark)', 'fluent-community'),
856 'selectors' => [
857 'body' => [
858 'primary_border' => '#3E4042',
859 'menu_text' => '#B0B3B8',
860 'menu_text_active' => '#2D88FF',
861 'active_bg' => '#263951',
862 'menu_text_hover' => '#2D88FF',
863 'menu_bg_hover' => '#263951',
864 'primary_bg' => '#2B2E33',
865 'secondary_content_bg' => '#42464D',
866 'secondary_bg' => '#191B1F',
867 'light_bg' => '#2B303B',
868 'deep_bg' => '#E1E4EA',
869 'primary_text' => '#F0F3F5',
870 'secondary_text' => '#99A0AE',
871 'text_off' => '#A5A9AD',
872 'primary_button' => '#FFFFFF',
873 'primary_button_text' => '#191B1F',
874 'secondary_border' => '#A5A9AD',
875 'highlight_bg' => '#2c2c1a',
876 'text_link' => '#2d88ff',
877 ],
878 'fcom_top_menu' => [
879 'primary_bg' => '#242526',
880 'primary_border' => '#3E4042',
881 'menu_text' => '#B0B3B8',
882 'menu_text_active' => '#fff',
883 'active_bg' => '#263951',
884 'menu_text_hover' => '#fff',
885 'menu_bg_hover' => '#263951',
886 ],
887 'spaces' => [
888 'primary_bg' => '#242526',
889 'primary_border' => '#3E4042',
890 'menu_text' => '#B0B3B8',
891 'menu_text_hover' => '#2D88FF',
892 'menu_bg_hover' => '#263951',
893 'menu_text_active' => '#FFFFFF',
894 'active_bg' => '#2D88FF'
895 ]
896 ]
897 ],
898 'sky_blue' => [
899 'title' => __('Sky Blue (Dark)', 'fluent-community'),
900 'selectors' => [
901 'body' => [
902 'primary_bg' => '#15202B',
903 'secondary_bg' => '#1E2732',
904 'secondary_content_bg' => '#2C3640',
905 'active_bg' => '#1D2F41',
906 'light_bg' => '#22303C',
907 'deep_bg' => '#E7E9EA',
908 'menu_text' => '#8B98A5',
909 'primary_text' => '#E7E9EA',
910 'secondary_text' => '#8B98A5',
911 'text_off' => '#536471',
912 'text_link' => '#1D9BF0',
913 'primary_button' => '#1D9BF0',
914 'primary_button_text' => '#15202B',
915 'primary_border' => '#38444D',
916 'secondary_border' => '#536471',
917 'highlight_bg' => '#1D2F41'
918 ],
919 'fcom_top_menu' => [
920 'primary_bg' => '#15202B',
921 'primary_border' => '#38444D',
922 'menu_text' => '#8B98A5',
923 'menu_text_active' => '#1D9BF0',
924 'active_bg' => '#1D2F41',
925 'menu_bg_hover' => '#1D2F41',
926 'menu_text_hover' => '#E7E9EA',
927 ],
928 'spaces' => [
929 'primary_bg' => '#15202B',
930 'primary_border' => '#38444D',
931 'menu_text' => '#8B98A5',
932 'menu_text_hover' => '#1D9BF0',
933 'menu_bg_hover' => '#1D2F41',
934 'menu_text_active' => '#FFFFFF',
935 'active_bg' => '#1D9BF0'
936 ]
937 ]
938 ],
939 'emerald_essence' => [
940 'title' => __('Emerald Essence (Dark)', 'fluent-community'),
941 'selectors' => [
942 'body' => [
943 'primary_bg' => '#1A2B32',
944 'secondary_bg' => '#243B43',
945 'secondary_content_bg' => '#2C464F',
946 'active_bg' => '#1E3A31',
947 'light_bg' => '#2A3F48',
948 'deep_bg' => '#E2E8F0',
949 'menu_text' => '#A7BCBF',
950 'primary_text' => '#E2E8F0',
951 'secondary_text' => '#A7BCBF',
952 'text_off' => '#64748B',
953 'text_link' => '#34D399',
954 'primary_button' => '#10B981',
955 'primary_border' => '#2F4C41',
956 'primary_button_text' => '#1A2B32',
957 'secondary_border' => '#3D5C52',
958 'highlight_bg' => '#064E3B'
959 ],
960 'fcom_top_menu' => [
961 'primary_bg' => '#1A2B32',
962 'primary_border' => '#2F4C41',
963 'menu_text' => '#A7BCBF',
964 'menu_text_active' => '#34D399',
965 'active_bg' => '#064E3B',
966 'menu_bg_hover' => '#064E3B',
967 'menu_text_hover' => '#E2E8F0',
968 ],
969 'spaces' => [
970 'primary_bg' => '#1A2B32',
971 'primary_border' => '#2F4C41',
972 'menu_text' => '#A7BCBF',
973 'menu_text_hover' => '#34D399',
974 'menu_bg_hover' => '#064E3B',
975 'menu_text_active' => '#FFFFFF',
976 'active_bg' => '#10B981'
977 ]
978 ]
979 ]
980 ]
981 ]);
982
983 $customSchemaConfig = self::getColorConfig('edit');
984
985 $shemas['lightSkins']['custom'] = [
986 'title' => __('Custom', 'fluent-community'),
987 'selectors' => $customSchemaConfig['light_config'] ?? $defaultCustom
988 ];
989
990 $shemas['darkSkins']['custom'] = [
991 'title' => __('Custom', 'fluent-community'),
992 'selectors' => $customSchemaConfig['dark_config'] ?? $defaultCustom
993 ];
994
995 return $shemas;
996 }
997
998 public static function generateCss($sectors, $prefix = '')
999 {
1000 if (!$sectors) {
1001 return '';
1002 }
1003
1004 $bodyPrefix = 'body';
1005 if ($prefix) {
1006 $bodyPrefix = $prefix . ' body';
1007 }
1008
1009 $elementPlusMap = [
1010 'primary_text' => '--el-color-primary',
1011 'secondary_bg' => '--el-color-white'
1012 ];
1013
1014 $css = '';
1015 foreach ($sectors as $selector => $props) {
1016 $isBody = $selector === 'body';
1017 $prefix = $isBody ? $bodyPrefix : $bodyPrefix . ' .' . $selector;
1018 $prefix .= '{';
1019
1020 $css .= $prefix;
1021
1022 foreach ($props as $prop => $value) {
1023 $cssVar = '--fcom-' . str_replace('_', '-', $prop);
1024 $css .= $cssVar . ':' . $value . ';';
1025
1026 if ($isBody && isset($elementPlusMap[$prop])) {
1027 $css .= $elementPlusMap[$prop] . ':' . $value . ';';
1028 }
1029 }
1030 $css .= '} ';
1031 }
1032
1033 return $css;
1034 }
1035
1036 public static function getColorConfig($context = 'view')
1037 {
1038 return apply_filters('fluent_community/color_schmea_config', [
1039 'light_schema' => 'default',
1040 'dark_schema' => 'default',
1041 'light_config' => [
1042 'body' => [],
1043 'fcom_top_menu' => [],
1044 'spaces' => []
1045 ],
1046 'dark_config' => [
1047 'body' => [],
1048 'fcom_top_menu' => [],
1049 'spaces' => []
1050 ],
1051 'version' => FLUENT_COMMUNITY_PLUGIN_VERSION
1052 ], $context);
1053 }
1054
1055 public static function getColorCssVariables()
1056 {
1057 $customSchemaConfig = self::getColorConfig('view');
1058
1059 if (!empty($customSchemaConfig['cached_css'])) {
1060 if ($customSchemaConfig['version'] != FLUENT_COMMUNITY_PLUGIN_VERSION) {
1061 do_action('fluent_community/recache_color_schema');
1062 }
1063
1064 return (string)$customSchemaConfig['cached_css'];
1065 }
1066
1067 $schemas = self::getColorSchemas();
1068
1069 $lightName = Arr::get($customSchemaConfig, 'light_schema', 'default');
1070 $darkName = Arr::get($customSchemaConfig, 'dark_schema', 'default');
1071
1072 $lightCss = self::generateCss(Arr::get($schemas, "lightSkins.$lightName.selectors"));
1073 $darkCss = self::generateCss(Arr::get($schemas, "darkSkins.$darkName.selectors"), 'html.dark');
1074 return $lightCss . $darkCss;
1075 }
1076
1077 public static function getThemeColor($scope = 'theme')
1078 {
1079 static $cache = [];
1080 if (isset($cache[$scope])) {
1081 return $cache[$scope];
1082 }
1083
1084 $map = [
1085 'theme' => ['key' => 'primary_button', 'default' => '#2B2E33'],
1086 'theme_button_text' => ['key' => 'primary_button_text', 'default' => '#ffffff'],
1087 ];
1088 $entry = Arr::get($map, $scope, ['key' => $scope, 'default' => '']);
1089
1090 $schemas = self::getColorSchemas();
1091 $lightName = Arr::get(self::getColorConfig('view'), 'light_schema', 'default');
1092 $color = Arr::get($schemas, "lightSkins.$lightName.selectors.body.{$entry['key']}", $entry['default']);
1093
1094 $cache[$scope] = apply_filters('fluent_community/' . $scope . '_color', $color);
1095
1096 return $cache[$scope];
1097 }
1098
1099 public static function getColorSchemaConfig()
1100 {
1101 $customSchemaConfig = self::getColorConfig('view');
1102 $lightName = Arr::get($customSchemaConfig, 'light_schema', 'default');
1103 $darkName = Arr::get($customSchemaConfig, 'dark_schema', 'default');
1104 $schemas = self::getColorSchemas();
1105
1106 return [
1107 'dark' => Arr::get($schemas, "lightSkins.$darkName.selectors"),
1108 'light' => Arr::get($schemas, "darkSkins.$lightName.selectors"),
1109 ];
1110 }
1111
1112 public static function getSuggestedColors()
1113 {
1114 $pallets = current((array)get_theme_support('editor-color-palette'));
1115
1116 $colors = [];
1117
1118 if ($pallets && is_array($pallets)) {
1119 $colors = array_map(function ($color) {
1120 $colorString = Arr::get($color, 'color');
1121 // Trim any whitespace
1122 $colorString = trim($colorString);
1123 // Check if it's a CSS variable
1124 if (strpos($colorString, 'var(') === 0) {
1125 // Extract the fallback color if present
1126 preg_match('/var\(.*,\s*(#[A-Fa-f0-9]{6})\)/', $colorString, $matches);
1127 if (!empty($matches[1])) {
1128 return $matches[1];
1129 }
1130 // If no fallback color, return an empty string
1131 return '';
1132 }
1133
1134 if (preg_match('/#[A-Fa-f0-9]{6}/', $colorString, $matches)) {
1135 return $matches[0];
1136 }
1137
1138 return $colorString;
1139 }, $pallets);
1140
1141 $colors = array_filter($colors);
1142 }
1143
1144 if (!$colors) {
1145 $colors = ['#000000', '#abb8c3', '#ffffff', '#f78da7', '#ff6900', '#fcb900', '#7bdcb5', '#00d084', '#8ed1fc', '#0693e3', '#9b51e0'];
1146 }
1147
1148 return apply_filters('fluent_community/suggested_colors', $colors);
1149 }
1150
1151 public static function slugify($text, $fallback = '')
1152 {
1153 $title = preg_replace('/[\x{10000}-\x{10FFFF}]/u', '', $text);
1154
1155 $title = Helper::normalizeToAscii($title);
1156
1157 $title = remove_accents($title);
1158
1159 $title = strtolower($title);
1160 // only allow alphanumeric, dash, and underscore
1161 $title = trim(preg_replace('/[^a-z0-9-_]/', ' ', $title));
1162
1163 if (!$title) {
1164 $title = $fallback;
1165 }
1166
1167 if (!$title) {
1168 return $title;
1169 }
1170
1171 return sanitize_title($title, $fallback);
1172 }
1173
1174 public static function hasAnalyticsEnabled()
1175 {
1176 $defaultSettings = ['status' => 'no'];
1177
1178 $settings = apply_filters('fluent_community/features/analytics', $defaultSettings);
1179
1180 $status = Arr::get($settings, 'status');
1181
1182 return $status === 'yes';
1183 }
1184
1185 public static function getPortalSidebarData($scope = 'sidebar')
1186 {
1187 $userModel = Helper::getCurrentUser();
1188 $spaceGroups = Helper::getCommunityMenuGroups($userModel);
1189 $settingsMenu = apply_filters('fluent_community/settings_menu', [], $userModel);
1190 $menuGroups = Helper::getMenuItemsGroup('view');
1191 $topInlines = Arr::get($menuGroups, 'beforeCommunityMenuItems', []);
1192 $bottomLinkGroups = Arr::get($menuGroups, 'afterCommunityLinkGroups', []);
1193 $primaryMenuItems = Arr::get($menuGroups, 'mainMenuItems', []);
1194 $primaryMenuItems = apply_filters('fluent_community/main_menu_items', $primaryMenuItems, $scope);
1195
1196 return apply_filters('fluent_community/sidebar_menu_groups_config', [
1197 'primaryItems' => $primaryMenuItems,
1198 'spaceGroups' => $spaceGroups,
1199 'settingsItems' => $settingsMenu,
1200 'topInlineLinks' => $topInlines,
1201 'bottomLinkGroups' => $bottomLinkGroups,
1202 'is_admin' => Helper::isSiteAdmin(null, $userModel),
1203 'has_color_scheme' => Helper::hasColorScheme(),
1204 'context' => $scope,
1205 ], $userModel);
1206 }
1207
1208 public static function getVerifiedSenders()
1209 {
1210 $verifiedSenders = [];
1211
1212 if (defined('FLUENTMAIL')) {
1213 $smtpSettings = get_option('fluentmail-settings', []);
1214 if ($smtpSettings && count($smtpSettings['mappings'])) {
1215 $verifiedSenders = array_keys($smtpSettings['mappings']);
1216 }
1217 }
1218
1219 return apply_filters('fluent_community/verified_email_senders', $verifiedSenders);
1220 }
1221
1222 public static function safeUnserialize($data)
1223 {
1224 if (!$data) {
1225 return $data;
1226 }
1227
1228 if (is_serialized($data)) { // Don't attempt to unserialize data that wasn't serialized going in.
1229 return @unserialize(trim($data), [
1230 'allowed_classes' => false,
1231 ]);
1232 }
1233
1234 return $data;
1235 }
1236 }
1237