PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 2.1.0
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v2.1.0
2.1.0 2.0.15 2.0.12 2.0.10 2.0.4 2.0.1 2.0.0 1.95.3 1.95.2 1.95 1.91.6 trunk 1.11 1.12 1.13 1.20 1.21 1.22 1.23 1.30 1.31 1.32 1.35 1.40 1.41 All 42 releases
← All changes | app/Functions/helpers.php +64 -1 1.91.62.1.0 View file →
@@ -18,14 +18,42 @@
18 18 return is_null($key) ? $api : $api->{$key};
19 19 }
20 20 }
21 21
22 +if (!function_exists('fluent_boards_sanitize_description')) {
23 + function fluent_boards_sanitize_description($description): string
24 + {
25 + $description = preg_replace_callback('/<((?:https?:\/\/)[^<>\s]+)>/i', function ($matches) {
26 + $url = esc_url_raw(html_entity_decode($matches[1], ENT_QUOTES | ENT_HTML5, 'UTF-8'));
27 +
28 + return $url ? '[' . $url . '](' . str_replace(')', '%29', $url) . ')' : $matches[0];
29 + }, (string) $description);
30 +
31 + // KSES encodes standalone > characters, which breaks Markdown quotes.
32 + // Protect only quote prefixes; all HTML still passes through KSES.
33 + $quotePrefix = 'fbs-quote-' . wp_generate_uuid4() . '-';
34 + $quotes = [];
35 + $description = preg_replace_callback('/^[ \t]*(?:>[ \t]*)+/m', function ($matches) use (&$quotes, $quotePrefix) {
36 + $key = $quotePrefix . count($quotes);
37 + $quotes[$key] = $matches[0];
38 + return $key;
39 + }, $description);
40 +
41 + return strtr(wp_kses_post($description), $quotes);
42 + }
43 +}
44 +
22 45 if (!function_exists('fluent_boards_user_avatar')) {
23 46 function fluent_boards_user_avatar($email, $name = '')
24 47 {
25 48 $user = get_user_by('email', $email);
26 49
27 - if($user) {
50 + if ($user) {
51 + $photo_url = get_user_meta($user->ID, 'fbs_profile_photo', true);
52 + if ($photo_url) {
53 + return apply_filters('fluent_boards/get_avatar', $photo_url, $email);
54 + }
55 +
28 56 $has_custom_avatar = get_user_meta($user->ID, 'wp_user_avatar', true);
29 57 if ($has_custom_avatar) {
30 58 $custom_avatar_attachment = get_post($has_custom_avatar);
31 59 if ($custom_avatar_attachment) {
@@ -77,8 +105,20 @@
77 105 return apply_filters('fluent_boards/app_url', admin_url('admin.php?page=fluent-boards#/'));
78 106 }
79 107 }
80 108
109 +if (!function_exists('fluent_boards_is_rtl')) {
110 + /**
111 + * Determine if Fluent Boards should render right-to-left UI.
112 + *
113 + * @return bool
114 + */
115 + function fluent_boards_is_rtl(): bool
116 + {
117 + return is_rtl();
118 + }
119 +}
120 +
81 121 function fluent_boards_get_pref_settings($cached = true)
82 122 {
83 123 static $pref = null;
84 124
@@ -275,5 +315,28 @@
275 315 }
276 316
277 317 // Fallback: return original value if not recognized
278 318 return $value;
319 +}
320 +
321 +/**
322 + * Builds the canonical Fluent Boards Upgrade-to-Pro URL.
323 + *
324 + * @param string $utmContent Exact in-plugin CTA placement.
325 + * @return string
326 + */
327 +function fluent_boards_get_upgrade_url($utmContent = '')
328 +{
329 + $queryArgs = [
330 + 'utm_source' => 'fluent-boards',
331 + 'utm_medium' => 'free_plugin',
332 + 'utm_campaign' => 'upgrade_pro',
333 + 'utm_term' => FLUENT_BOARDS_PLUGIN_VERSION,
334 + ];
335 +
336 + $utmContent = sanitize_key($utmContent);
337 + if ($utmContent) {
338 + $queryArgs['utm_content'] = $utmContent;
339 + }
340 +
341 + return add_query_arg($queryArgs, 'https://fluentboards.com/pricing/');
279 342 }