PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.7.0
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.7.0
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.7.0, at app/Functions/Utility.php

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