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 +58 -0 1.95.22.1.0 View file →
@@ -18,8 +18,31 @@
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);
@@ -82,8 +105,20 @@
82 105 return apply_filters('fluent_boards/app_url', admin_url('admin.php?page=fluent-boards#/'));
83 106 }
84 107 }
85 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 +
86 121 function fluent_boards_get_pref_settings($cached = true)
87 122 {
88 123 static $pref = null;
89 124
@@ -280,5 +315,28 @@
280 315 }
281 316
282 317 // Fallback: return original value if not recognized
283 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/');
284 342 }