$features, 'addOns' => $this->getAddons() ]; return apply_filters('fluent_community/features_api_response', $data, $this->request->all()); } public function setFeatures(Request $request) { $request->validate([ 'features.giphy_api_key' => 'required_if:features.giphy_module,yes|string', ]); $data = $request->get('features', []); $data = Sanitizer::sanitize($data, [ 'leader_board_module' => 'sanitize_text_field', 'course_module' => 'sanitize_text_field', 'giphy_module' => 'sanitize_text_field', 'giphy_api_key' => 'sanitize_text_field', 'cloud_storage' => 'sanitize_text_field', 'emoji_module' => 'sanitize_text_field', 'user_badge' => 'sanitize_text_field', 'has_crm_sync' => 'sanitize_text_field', 'followers_module' => 'sanitize_text_field', 'custom_profile_fields' => 'sanitize_text_field', 'pwa_module' => 'sanitize_text_field', ]); $prevConfig = Utility::getFeaturesConfig(); if (Arr::get($data, 'giphy_api_key') === 'FCOM_ENCRYPTED_DATA_KEY') { $data['giphy_api_key'] = Arr::get($prevConfig, 'giphy_api_key', ''); } $data = wp_parse_args($data, $prevConfig); Utility::updateOption('fluent_community_features', $data); return [ 'message' => __('Features saved successfully.', 'fluent-community') ]; } public function getMenuSettings(Request $request) { $menuGroups = Helper::getMenuItemsGroup('edit'); $formattedGroups = []; foreach ($menuGroups as $indexName => $menuGroup) { if (is_array($menuGroup)) { $formattedGroups[$indexName] = array_values($menuGroup); } else { $formattedGroups[$indexName] = []; } } $afterCommunityLinkGroups = Arr::get($formattedGroups, 'afterCommunityLinkGroups', []); $formattedAfterCommunityGroups = []; if (is_array($afterCommunityLinkGroups)) { foreach ($afterCommunityLinkGroups as $group) { if (!is_array($group)) continue; $title = Arr::get($group, 'title', ''); if (empty($title)) continue; $items = Arr::get($group, 'items', []); $items = is_array($items) ? array_values($items) : []; $formattedAfterCommunityGroups[] = [ 'title' => $title, 'slug' => Arr::get($group, 'slug', ''), 'items' => $items, ]; } } $formattedGroups['afterCommunityLinkGroups'] = $formattedAfterCommunityGroups; $data = [ 'menuSettings' => $formattedGroups ]; return apply_filters('fluent_community/menu_settings_api_response', $data, $request->all()); } public function saveMenuSettings(Request $request) { $menuSettings = $request->get('menuSettings', []); $mainMenuItems = $menuSettings['mainMenuItems'] ?? []; $profileDropdownItems = $menuSettings['profileDropdownItems'] ?? []; $beforeCommunityMenuItems = $menuSettings['beforeCommunityMenuItems'] ?? []; $afterCommunityLinkGroups = $menuSettings['afterCommunityLinkGroups'] ?? []; $previousSettings = Helper::getMenuItemsGroup('edit'); $menuSettings['mainMenuItems'] = $this->formatMenuGroup($mainMenuItems, $previousSettings['mainMenuItems']); $menuSettings['profileDropdownItems'] = $this->formatMenuGroup($profileDropdownItems, $previousSettings['profileDropdownItems']); $menuSettings['beforeCommunityMenuItems'] = $this->formatMenuGroup($beforeCommunityMenuItems, $previousSettings['beforeCommunityMenuItems']); $formattedAfterCommunityGroups = []; foreach ($afterCommunityLinkGroups as $afterCommunityLinkGroup) { if (empty($afterCommunityLinkGroup['title'])) continue; $formattedAfterCommunityGroups[] = [ 'title' => sanitize_text_field($afterCommunityLinkGroup['title']), 'slug' => !empty($afterCommunityLinkGroup['slug']) ? $afterCommunityLinkGroup['slug'] : 'custom_footer_group_' . time(), 'items' => $this->formatMenuGroup($afterCommunityLinkGroup['items'], []) ]; } $menuSettings['afterCommunityLinkGroups'] = $formattedAfterCommunityGroups; $menuSettings = Arr::only($menuSettings, ['mainMenuItems', 'profileDropdownItems', 'beforeCommunityMenuItems', 'afterCommunityLinkGroups']); Utility::updateOption('fluent_community_menu_groups', $menuSettings); return [ 'message' => __('Menu settings saved successfully.', 'fluent-community') ]; } private function formatMenuGroup($mainMenuItems, $savedMenuItems) { $formattedMainMenuItems = []; foreach ($mainMenuItems as $item) { $slug = (string)Arr::get($item, 'slug'); if (!Arr::get($item, 'title') || !Arr::get($item, 'permalink')) { continue; } if (!$slug) { $slug = 'custom_' . sanitize_title(Arr::get($item, 'title')) . time(); $item['slug'] = $slug; $item['is_custom'] = 'yes'; } $defaultItem = Arr::get($savedMenuItems, $slug, []); if ($defaultItem) { $preservedKeys = ['is_system', 'is_locked', 'is_unavailable', 'slug']; foreach ($preservedKeys as $key) { if (isset($defaultItem[$key])) { $item[$key] = Arr::get($defaultItem, $key); } } } $item = \FluentCommunity\App\Services\CustomSanitizer::sanitizeMenuLink($item); $formattedMainMenuItems[$slug] = $item; } return $formattedMainMenuItems; } public function getAddons() { $addons = [ 'fluent-messaging' => [ 'is_repo' => false, 'title' => __('FluentCommunity Chat', 'fluent-community'), 'logo' => Helper::assetUrl('images/brands/fluent-messages.svg'), 'is_installed' => defined('FLUENT_MESSAGING_CHAT_VERSION'), 'learn_more_url' => 'https://fluentcommunity.co', 'settings_url' => Helper::baseUrl('chat'), 'action_text' => $this->isPluginInstalled('fluent-messaging/fluent-messaging.php') ? __('Active FluentCommunity Chat', 'fluent-community') : __('Install FluentCommunity Chat', 'fluent-community'), 'description' => __('FluentCommunity Chat is a real-time chat plugin for WordPress. It allows you to create a chat room for your community members.', 'fluent-community') ], 'fluent-notify' => [ 'is_repo' => false, 'title' => __('FluentNotify', 'fluent-community'), 'logo' => Helper::assetUrl('images/brands/fluent-notify.svg'), 'is_installed' => defined('FLUENT_NOTIFY_PLUGIN_VERSION'), 'learn_more_url' => 'https://fluentnotify.com', 'action_text' => $this->isPluginInstalled('fluent-notify/fluent-notify.php') ? __('Active FluentNotify', 'fluent-community') : __('Install FluentNotify', 'fluent-community'), 'description' => __('Send browser push notifications to your community members for comments, replies and mentions.', 'fluent-community') ], 'fluent-player' => [ 'is_repo' => false, 'title' => __('FluentPlayer', 'fluent-community'), 'logo' => Helper::assetUrl('images/brands/fluent-player.svg'), 'is_installed' => defined('FLUENT_PLAYER_VERSION'), 'learn_more_url' => 'https://wordpress.org/plugins/fluent-player/', 'action_text' => $this->isPluginInstalled('fluent-player/fluent-player.php') ? __('Active FluentPlayer', 'fluent-community') : __('Install FluentPlayer', 'fluent-community'), 'description' => __('Advanced video player with support for YouTube, Vimeo, HLS and more.', 'fluent-community') ], 'fluent-cart' => [ 'is_repo' => true, 'title' => __('FluentCart', 'fluent-community'), 'logo' => Helper::assetUrl('images/brands/fluent-cart.svg'), 'is_installed' => defined('FLUENTCART_VERSION'), 'learn_more_url' => 'https://wordpress.org/plugins/fluent-cart/', 'settings_url' => defined('FLUENTCART_VERSION') ? admin_url('admin.php?page=fluent-cart#/') : '', 'action_text' => $this->isPluginInstalled('fluent-cart/fluent-cart.php') ? __('Active FluentCart', 'fluent-community') : __('Install Fluent Cart', 'fluent-community'), 'description' => __('The easiest way to sell digital and physical products in WordPress. Create, manage, and sell products with ease.', 'fluent-community') ], 'fluent-crm' => [ 'is_repo' => true, 'title' => __('FluentCRM', 'fluent-community'), 'logo' => Helper::assetUrl('images/brands/fluentcrm.svg'), 'is_installed' => defined('FLUENTCRM'), 'learn_more_url' => 'https://fluentcrm.com', 'settings_url' => defined('FLUENTCRM') ? admin_url('admin.php?page=fluentcrm-admin#/') : '', 'action_text' => $this->isPluginInstalled('fluent-crm/fluent-crm.php') ? __('Active FluentCRM', 'fluent-community') : __('Install FluentCRM', 'fluent-community'), 'description' => __('The Best Email Marketing Automation Plugin for WordPress. Capture, Segment and Automate your Marketing.', 'fluent-community') ], 'fluentform' => [ 'is_repo' => true, 'title' => __('Fluent Forms', 'fluent-community'), 'logo' => Helper::assetUrl('images/brands/fluentform.png'), 'is_installed' => defined('FLUENTFORM'), 'learn_more_url' => 'https://wordpress.org/plugins/fluentform/', 'settings_url' => defined('FLUENTFORM') ? admin_url('admin.php?page=fluent_forms') : '', 'action_text' => $this->isPluginInstalled('fluentform/fluentform.php') ? __('Active Fluent Forms', 'fluent-community') : __('Install Fluent Forms', 'fluent-community'), 'description' => __('Collect leads and build any type of forms, accept payments, connect with your CRM with the Fastest Contact Form Builder Plugin for WordPress', 'fluent-community') ], 'fluent-smtp' => [ 'is_repo' => true, 'title' => __('Fluent SMTP', 'fluent-community'), 'logo' => Helper::assetUrl('images/brands/fluent-smtp.svg'), 'is_installed' => defined('FLUENTMAIL'), 'learn_more_url' => 'https://wordpress.org/plugins/fluent-smtp/', 'settings_url' => defined('FLUENTMAIL') ? admin_url('options-general.php?page=fluent-mail#/') : '', 'action_text' => $this->isPluginInstalled('fluent-smtp/fluent-smtp.php') ? __('Active Fluent SMTP', 'fluent-community') : __('Install Fluent SMTP', 'fluent-community'), 'description' => __('Fluent SMTP is the ultimate SMTP and SES plugin for WordPress. Connect with any SMTP service, including SendGrid, Mailgun, SES, Sendinblue, PepiPost, Google, Microsoft, and more.', 'fluent-community') ], 'fluent-support' => [ 'is_repo' => true, 'title' => __('Fluent Support', 'fluent-community'), 'logo' => Helper::assetUrl('images/brands/fluent-support.svg'), 'is_installed' => defined('FLUENT_SUPPORT_VERSION'), 'learn_more_url' => 'https://wordpress.org/plugins/fluent-support/', 'settings_url' => defined('FLUENT_SUPPORT_VERSION') ? admin_url('admin.php?page=fluent-support#/') : '', 'action_text' => $this->isPluginInstalled('fluent-support/fluent-support.php') ? __('Active Fluent Support', 'fluent-community') : __('Install Fluent Support', 'fluent-community'), 'description' => __('WordPress Helpdesk and Customer Support Ticket Plugin. Provide awesome support and manage customer queries right from your WordPress dashboard.', 'fluent-community') ] ]; if (defined('FLUENT_COMMUNITY_PRO')) { $addons['wp-payment-form'] = [ 'is_repo' => true, 'title' => __('Paymattic', 'fluent-community'), 'logo' => Helper::assetUrl('images/brands/paymattic.png'), 'is_installed' => defined('WPPAYFORM_VERSION'), 'learn_more_url' => 'https://wordpress.org/plugins/wp-payment-form/', 'settings_url' => defined('WPPAYFORM_VERSION') ? admin_url('admin.php?page=wppayform.php#/integrations/fluent_community') : '', 'action_text' => $this->isPluginInstalled('wp-payment-form/wp-payment-form.php') ? __('Active Paymattic', 'fluent-community') : __('Install Paymattic', 'fluent-community'), 'description' => __('Paymattic – Secure, Simple Payment & Donation with Subscription Payments, Recurring Donations, Customer Management', 'fluent-community') ]; } return $addons; } private function isPluginInstalled($plugin) { return file_exists(WP_PLUGIN_DIR . '/' . $plugin); } public function installPlugin(Request $request) { $pluginSlug = $request->get('plugin'); $addons = $this->getAddons(); if (!isset($addons[$pluginSlug])) { return $this->sendError(['message' => __('Invalid Plugin', 'fluent-community')]); } $details = $addons[$pluginSlug]; $pluginFile = $pluginSlug . '/' . $pluginSlug . '.php'; // Already on disk but deactivated: that is an activation, so it answers to // activate_plugins and needs no download. if (!$details['is_repo'] && $this->isPluginInstalled($pluginFile)) { if (!current_user_can('activate_plugins')) { return $this->sendError(['message' => __('You do not have permission to activate plugins', 'fluent-community')]); } require_once ABSPATH . 'wp-admin/includes/plugin.php'; if (!is_plugin_active($pluginFile)) { $activated = activate_plugin($pluginFile); if (is_wp_error($activated)) { return $this->sendError(['message' => wp_kses_post($activated->get_error_message())]); } } return [ 'message' => __('Plugin has been activated Successfully', 'fluent-community'), 'is_installed' => true ]; } if (!current_user_can('install_plugins')) { return $this->sendError([ 'message' => __('You do not have permission to install plugins', 'fluent-community') ]); } if ($details['is_repo']) { $plugin = [ 'name' => $details['title'], 'repo-slug' => $pluginSlug, 'file' => $pluginSlug . '.php', ]; try { OnboardingService::backgroundInstaller($plugin); } catch (\Exception $e) { return $this->sendError(['message' => $e->getMessage()]); } } else { $installHook = ''; if ($pluginSlug == 'fluent-messaging') { if (!defined('FLUENT_COMMUNITY_PRO')) { return $this->sendError(['message' => __('FluentMessaging is a Pro Plugin. Please install FluentCommunity Pro first.', 'fluent-community')]); } $installHook = 'fluent_community/install_messaging_plugin'; } else if ($pluginSlug == 'fluent-player') { if (!defined('FLUENT_COMMUNITY_PRO')) { return $this->sendError(['message' => __('FluentPlayer requires the pro version of FluentCommunity. Please install FluentCommunity Pro first.', 'fluent-community')]); } $installHook = 'fluent_community/install_fluent_player_plugin'; } else if ($pluginSlug == 'fluent-notify') { $installHook = 'fluent_community/install_fluent_notify_plugin'; } if (!$installHook || !has_action($installHook)) { return $this->sendError(['message' => __('This plugin can not be installed from here. Please install it manually.', 'fluent-community')]); } try { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- every assigned value is a literal fluent_community/ prefixed hook, guarded above do_action($installHook); } catch (\Exception $e) { return $this->sendError(['message' => $e->getMessage()]); } } return [ 'message' => __('Plugin has been installed Successfully', 'fluent-community'), 'is_installed' => true ]; } public function getCustomizationSettings(Request $request) { $data = [ 'settings' => Utility::getCustomizationSettings() ]; return apply_filters('fluent_community/customization_settings_api_response', $data, $request->all()); } public function updateCustomizationSettings(Request $request) { $settings = $request->get('settings', []); $yesNoFields = [ 'dark_mode', 'fixed_page_header', 'show_powered_by', 'show_post_modal', 'feed_link_on_sidebar', 'fixed_sidebar', 'icon_on_header_menu', 'disable_feed_layout', 'collapse_sidebar_groups', 'hide_header_on_scroll', 'enable_sidebar_toggle' ]; foreach ($settings as $key => $value) { if (in_array($key, $yesNoFields)) { $settings[$key] = $value == 'yes' ? 'yes' : 'no'; } else if ($key == 'default_theme_mode') { $settings[$key] = in_array($value, ['light', 'dark', 'system'], true) ? $value : 'light'; } else if ($key == 'affiliate_id') { $settings[$key] = (int)$value; if (!$settings[$key]) { $settings[$key] = ''; } } else { $settings[$key] = sanitize_text_field($value); } } if (isset($settings['dark_mode']) && $settings['dark_mode'] !== 'yes') { $settings['default_theme_mode'] = 'light'; } Utility::updateCustomizationSettings($settings); return [ 'message' => __('Customization settings have been saved successfully.', 'fluent-community') ]; } public function getFluentPlayerSettings(Request $request) { return [ 'settings' => \FluentCommunity\Modules\Integrations\FluentPlayer\Bootstrap::getSettings() ]; } public function updateFluentPlayerSettings(Request $request) { $settings = $request->get('settings', []); $updatedSettings = \FluentCommunity\Modules\Integrations\FluentPlayer\Bootstrap::updateSettings($settings); return [ 'message' => __('FluentPlayer settings have been saved successfully.', 'fluent-community'), 'settings' => $updatedSettings ]; } public function getPrivacySettings(Request $request) { $data = [ 'settings' => Utility::getPrivacySettings() ]; return apply_filters('fluent_community/privacy_settings_api_response', $data, $request->all()); } public function updatePrivacySettings(Request $request) { $settings = $request->get('settings', []); Utility::updatePrivacySettings($settings); return [ 'message' => __('Privacy settings have been saved successfully.', 'fluent-community') ]; } public function getColorConfig(Request $request) { $config = Utility::getColorConfig('edit'); $schemas = Utility::getColorSchemas(); $data = [ 'config' => $config, 'schemas' => $schemas ]; return apply_filters('fluent_community/color_config_api_response', $data, $request->all()); } public function getCrmTaggingConfig(Request $request) { $defaults = [ 'is_enabled' => 'no', 'tagging_maps' => [], 'linked_maps' => [], 'create_crm_contact' => 'yes', 'create_user' => 'no', 'send_welcome_email' => 'yes', 'has_space_tagging' => 'no', 'has_space_sync' => 'no', 'has_course_tagging' => 'no', 'has_course_sync' => 'no', ]; $settings = get_option('_fcom_crm_tagging', []); $settings = wp_parse_args($settings, $defaults); $spaceGroups = SpaceGroup::with(['spaces' => function ($query) { $query->where('type', 'community'); }]) ->orderBy('serial', 'ASC') ->get(); $formattedSpaceGroups = []; foreach ($spaceGroups as $spaceGroup) { if ($spaceGroup->spaces->isEmpty()) { continue; } $spaces = $spaceGroup->spaces->map(function ($space) { return [ 'id' => $space->id, 'title' => $space->title, 'privacy' => $space->privacy, 'slug' => $space->slug, 'icon' => $space->getIconMark(), 'type' => $space->type, ]; }); $formattedSpaceGroups[] = [ 'id' => $spaceGroup->id, 'title' => $spaceGroup->title, 'spaces' => $spaces ]; } $otherSpaces = Space::whereNull('parent_id') ->orderBy('title', 'ASC') ->get(); if (!$otherSpaces->isEmpty()) { $formattedSpaceGroups[] = [ 'id' => 'other', 'title' => __('Other Spaces', 'fluent-community'), 'spaces' => $otherSpaces->map(function ($space) { return [ 'id' => $space->id, 'type' => $space->type, 'title' => $space->title, 'privacy' => $space->privacy, 'slug' => $space->slug, 'icon' => $space->getIconMark(), ]; }) ]; } $courses = Course::orderBy('title', 'ASC')->get(); if (!$courses->isEmpty()) { $formattedSpaceGroups[] = [ 'id' => 'courses', 'title' => __('All Courses', 'fluent-community'), 'spaces' => $courses->map(function ($course) { return [ 'id' => $course->id, 'title' => $course->title, 'privacy' => $course->privacy, 'slug' => $course->slug, 'icon' => $course->getIconMark(), 'type' => $course->type, ]; }) ]; } if (empty($settings['tagging_maps'])) { $settings['tagging_maps'] = (object)[]; } if (empty($settings['linked_maps'])) { $settings['linked_maps'] = (object)[]; } if (defined('FLUENTCRM')) { $fluentCrmTags = \FluentCrm\App\Models\Tag::select(['id', 'title'])->orderBy('title', 'ASC')->get(); } else { $fluentCrmTags = []; } $data = [ 'settings' => $settings, 'spaceGroups' => $formattedSpaceGroups, 'crm_tags' => $fluentCrmTags, 'has_fluentcrm' => defined('FLUENTCRM') ]; return apply_filters('fluent_community/crm_tagging_config_api_response', $data, $request->all()); } }