| @@ -10,8 +10,9 @@ | ||
| 10 | 10 | use FluentCommunity\App\Services\FeedsHelper; |
| 11 | 11 | use FluentCommunity\App\Services\Helper; |
| 12 | 12 | use FluentCommunity\Framework\Support\Arr; |
| 13 | 13 | use FluentCommunity\Modules\Course\Model\Course; |
| 14 | +use FluentCommunity\Modules\PushNotification\PushNotificationModule; | |
| 14 | 15 | |
| 15 | 16 | class Utility |
| 16 | 17 | { |
| 17 | 18 | public static function isDev() |
| @@ -116,8 +117,9 @@ | ||
| 116 | 117 | 'has_crm_sync' => 'no', |
| 117 | 118 | 'content_moderation' => 'no', |
| 118 | 119 | 'followers_module' => 'no', |
| 119 | 120 | 'custom_profile_fields' => 'no', |
| 121 | + 'pwa_module' => 'no', | |
| 120 | 122 | ]; |
| 121 | 123 | |
| 122 | 124 | if (defined('FLUENT_COMMUNITY_CLOUD_STORAGE') && FLUENT_COMMUNITY_CLOUD_STORAGE) { |
| 123 | 125 | $features['cloud_storage'] = 'yes'; |
| @@ -134,8 +136,9 @@ | ||
| 134 | 136 | $features['cloud_storage'] = 'no'; |
| 135 | 137 | $features['user_badge'] = 'no'; |
| 136 | 138 | $features['followers_module'] = 'no'; |
| 137 | 139 | $features['custom_profile_fields'] = 'no'; |
| 140 | + $features['pwa_module'] = 'no'; | |
| 138 | 141 | } |
| 139 | 142 | |
| 140 | 143 | return $features; |
| 141 | 144 | } |
| @@ -201,8 +204,9 @@ | ||
| 201 | 204 | } |
| 202 | 205 | |
| 203 | 206 | $defaults = [ |
| 204 | 207 | 'dark_mode' => 'yes', |
| 208 | + 'default_theme_mode' => 'light', | |
| 205 | 209 | 'fixed_page_header' => 'yes', |
| 206 | 210 | 'show_powered_by' => 'yes', |
| 207 | 211 | 'feed_link_on_sidebar' => 'yes', |
| 208 | 212 | 'show_post_modal' => 'yes', |
| @@ -261,13 +265,15 @@ | ||
| 261 | 265 | |
| 262 | 266 | $defaults = [ |
| 263 | 267 | 'can_customize_username' => 'no', |
| 264 | 268 | 'can_change_email' => 'no', |
| 269 | + 'can_change_password' => 'yes', | |
| 265 | 270 | 'show_last_activity' => 'yes', |
| 266 | 271 | 'can_deactive_account' => 'no', |
| 267 | 272 | 'email_auto_login' => 'yes', |
| 268 | 273 | 'enable_gravatar' => 'yes', |
| 269 | 274 | 'enable_user_sync' => 'yes', |
| 275 | + 'skip_crm_undeliverable_emails' => 'yes', | |
| 270 | 276 | 'members_page_status' => 'everybody', // everybody, logged_in, admin_only |
| 271 | 277 | 'profile_page_visibility' => 'everybody', // everybody, logged_in, admin_only |
| 272 | 278 | 'user_space_visibility' => 'everybody', // everybody, logged_in, admin_only |
| 273 | 279 | 'leaderboard_members_visibility' => 'everybody', // everybody, logged_in, admin_only |
| @@ -343,8 +349,12 @@ | ||
| 343 | 349 | { |
| 344 | 350 | $preSettings = self::getPrivacySettings(); |
| 345 | 351 | $settings = Arr::only($settings, array_keys($preSettings)); |
| 346 | 352 | |
| 353 | + $settings = array_map(function ($value) { | |
| 354 | + return is_scalar($value) ? sanitize_text_field($value) : ''; | |
| 355 | + }, $settings); | |
| 356 | + | |
| 347 | 357 | self::updateOption('privacy_settings', $settings); |
| 348 | 358 | self::forgetCache('privacy_settings'); |
| 349 | 359 | |
| 350 | 360 | return $settings; |
| @@ -388,8 +398,46 @@ | ||
| 388 | 398 | ], $url); |
| 389 | 399 | } |
| 390 | 400 | |
| 391 | 401 | /** |
| 402 | + * Build a spec-compliant "Upgrade to Pro" URL. | |
| 403 | + * | |
| 404 | + * Follows the shared Fluent* UTM spec: | |
| 405 | + * utm_source = fluent-community (fixed vocabulary, never the wp.org slug) | |
| 406 | + * utm_medium = free_plugin | pro_plugin (acquisition vs cross-sell) | |
| 407 | + * utm_campaign= upgrade_pro (override for xsell_<target> / license_* ) | |
| 408 | + * utm_content = the exact placement, e.g. feature_lock_moderation, upgrade_page | |
| 409 | + * utm_term = plugin version that generated the link | |
| 410 | + * utm_id = promo id, blank normally (omit unless passed) | |
| 411 | + * | |
| 412 | + * @param string $content The utm_content placement. | |
| 413 | + * @param array $overrides Override any utm_* param (e.g. utm_campaign for cross-sell). | |
| 414 | + * @return string | |
| 415 | + */ | |
| 416 | + public static function getProUpgradeUrl($content = 'upgrade_page', $overrides = []) | |
| 417 | + { | |
| 418 | + $baseUrl = apply_filters( | |
| 419 | + 'fluent_community/pro_upgrade_base_url', | |
| 420 | + 'https://fluentcommunity.co/pricing/' | |
| 421 | + ); | |
| 422 | + | |
| 423 | + $params = wp_parse_args($overrides, [ | |
| 424 | + 'utm_source' => 'fluent-community', | |
| 425 | + 'utm_medium' => defined('FLUENT_COMMUNITY_PRO_VERSION') ? 'pro_plugin' : 'free_plugin', | |
| 426 | + 'utm_campaign' => 'upgrade_pro', | |
| 427 | + 'utm_content' => $content, | |
| 428 | + 'utm_term' => FLUENT_COMMUNITY_PLUGIN_VERSION, | |
| 429 | + ]); | |
| 430 | + | |
| 431 | + // Drop any blank params (e.g. an unset utm_id) so they never hit the URL. | |
| 432 | + $params = array_filter($params, function ($value) { | |
| 433 | + return $value !== '' && $value !== null; | |
| 434 | + }); | |
| 435 | + | |
| 436 | + return add_query_arg($params, $baseUrl); | |
| 437 | + } | |
| 438 | + | |
| 439 | + /** | |
| 392 | 440 | * Get the email notification settings. |
| 393 | 441 | * |
| 394 | 442 | * @return array The email notification settings. |
| 395 | 443 | */ |
| @@ -429,8 +477,29 @@ | ||
| 429 | 477 | |
| 430 | 478 | return $settings; |
| 431 | 479 | } |
| 432 | 480 | |
| 481 | + public static function getPushNotificationSettings() | |
| 482 | + { | |
| 483 | + static $settings; | |
| 484 | + if ($settings) return $settings; | |
| 485 | + | |
| 486 | + $default = [ | |
| 487 | + 'push_enabled' => 'yes', | |
| 488 | + 'com_my_post_push' => 'yes', | |
| 489 | + 'reply_my_com_push' => 'yes', | |
| 490 | + 'mention_push' => 'yes', | |
| 491 | + 'co_com_push' => 'yes', | |
| 492 | + 'prompt_placements' => PushNotificationModule::PROMPT_PLACEMENTS | |
| 493 | + ]; | |
| 494 | + | |
| 495 | + $settings = self::getOption('global_push_settings', $default); | |
| 496 | + | |
| 497 | + $settings = wp_parse_args($settings, $default); | |
| 498 | + | |
| 499 | + return $settings; | |
| 500 | + } | |
| 501 | + | |
| 433 | 502 | public static function hasEmailAnnouncementEnabled() |
| 434 | 503 | { |
| 435 | 504 | $settings = self::getEmailNotificationSettings(); |
| 436 | 505 | return Arr::get($settings, 'mention_mail', 'no') === 'yes'; |
| @@ -481,8 +550,25 @@ | ||
| 481 | 550 | $key = 'fluent_community_post_topics'; |
| 482 | 551 | $topics = self::getFromCache($key, function () { |
| 483 | 552 | $topics = Term::where('taxonomy_name', 'post_topic')->orderBy('title', 'ASC')->get(); |
| 484 | 553 | |
| 554 | + // Respect the admin-defined order (settings.serial) when present; | |
| 555 | + // topics without a serial fall back to the alphabetical order above. | |
| 556 | + $topics = $topics->sort(function ($a, $b) { | |
| 557 | + $serialA = Arr::get($a->settings, 'serial'); | |
| 558 | + $serialB = Arr::get($b->settings, 'serial'); | |
| 559 | + if ($serialA === null && $serialB === null) { | |
| 560 | + return 0; | |
| 561 | + } | |
| 562 | + if ($serialA === null) { | |
| 563 | + return 1; | |
| 564 | + } | |
| 565 | + if ($serialB === null) { | |
| 566 | + return -1; | |
| 567 | + } | |
| 568 | + return (int) $serialA <=> (int) $serialB; | |
| 569 | + })->values(); | |
| 570 | + | |
| 485 | 571 | /* |
| 486 | 572 | * object_id = term_id |
| 487 | 573 | * meta_key = space_id |
| 488 | 574 | */ |
| @@ -505,8 +591,9 @@ | ||
| 505 | 591 | 'title' => $topic->title, |
| 506 | 592 | 'description' => $topic->description, |
| 507 | 593 | 'slug' => $topic->slug, |
| 508 | 594 | 'admin_only' => Arr::get($topic->settings, 'admin_only', 'no'), |
| 595 | + 'serial' => Arr::get($topic->settings, 'serial'), | |
| 509 | 596 | 'space_ids' => isset($relations[$topic->id]) ? $relations[$topic->id] : [] |
| 510 | 597 | ]; |
| 511 | 598 | } |
| 512 | 599 | |