PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 2.2.0
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v2.2.0
2.2.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 All 43 releases
← All changes | app/Functions/helpers.php +170 -2 1.32 → 2.2.0 View file →
@@ -1,7 +1,8 @@
1 1 <?php
2 2
3 3 use FluentBoards\App\App;
4 +use FluentBoards\App\Services\Constant;
4 5
5 6 // $app is available
6 7
7 8 if (!function_exists('fluentBoards')) {
@@ -18,11 +19,65 @@
18 19 return is_null($key) ? $api : $api->{$key};
19 20 }
20 21 }
21 22
23 +if (!function_exists('fluent_boards_sanitize_description')) {
24 + function fluent_boards_sanitize_description($description): string
25 + {
26 + $description = preg_replace_callback('/<((?:https?:\/\/)[^<>\s]+)>/i', function ($matches) {
27 + $url = esc_url_raw(html_entity_decode($matches[1], ENT_QUOTES | ENT_HTML5, 'UTF-8'));
28 +
29 + return $url ? '[' . $url . '](' . str_replace(')', '%29', $url) . ')' : $matches[0];
30 + }, (string) $description);
31 +
32 + // Markdown email autolinks otherwise look like disallowed HTML to KSES.
33 + $description = preg_replace_callback('/<(?:mailto:)?([^<>\s]+@[^<>\s]+)>/i', function ($matches) {
34 + $email = html_entity_decode($matches[1], ENT_QUOTES | ENT_HTML5, 'UTF-8');
35 + if (!is_email($email)) {
36 + return $matches[0];
37 + }
38 +
39 + $label = str_replace(['*', '_', '`'], ['\\*', '\\_', '\\`'], $email);
40 + return '[' . $label . '](mailto:' . $email . ')';
41 + }, $description);
42 +
43 + // KSES encodes standalone > characters, which breaks Markdown quotes.
44 + // Protect only quote prefixes; all HTML still passes through KSES.
45 + $quotePrefix = 'fbs-quote-' . wp_generate_uuid4() . '-';
46 + $quotes = [];
47 + $description = preg_replace_callback('/^[ \t]*(?:>[ \t]*)+/m', function ($matches) use (&$quotes, $quotePrefix) {
48 + $key = $quotePrefix . count($quotes);
49 + $quotes[$key] = $matches[0];
50 + return $key;
51 + }, $description);
52 +
53 + return strtr(wp_kses_post($description), $quotes);
54 + }
55 +}
56 +
22 57 if (!function_exists('fluent_boards_user_avatar')) {
23 58 function fluent_boards_user_avatar($email, $name = '')
24 59 {
60 + $user = get_user_by('email', $email);
61 +
62 + if ($user) {
63 + $photo_url = get_user_meta($user->ID, Constant::PROFILE_PHOTO_META_KEY, true);
64 + if ($photo_url) {
65 + return apply_filters('fluent_boards/get_avatar', $photo_url, $email);
66 + }
67 +
68 + $has_custom_avatar = get_user_meta($user->ID, 'wp_user_avatar', true);
69 + if ($has_custom_avatar) {
70 + $custom_avatar_attachment = get_post($has_custom_avatar);
71 + if ($custom_avatar_attachment) {
72 + $avatar_url = wp_get_attachment_url($has_custom_avatar);
73 + return apply_filters('fluent_boards/get_avatar', $avatar_url, $email);
74 + }
75 + }
76 + $avatar_url = get_avatar_url($user->ID, array('size' => 128));
77 + return apply_filters('fluent_boards/get_avatar', $avatar_url, $email);
78 + }
79 +
25 80 $hash = md5(strtolower(trim($email)));
26 81 /**
27 82 * Gravatar URL by Email
28 83 *
@@ -62,8 +117,20 @@
62 117 return apply_filters('fluent_boards/app_url', admin_url('admin.php?page=fluent-boards#/'));
63 118 }
64 119 }
65 120
121 +if (!function_exists('fluent_boards_is_rtl')) {
122 + /**
123 + * Determine if Fluent Boards should render right-to-left UI.
124 + *
125 + * @return bool
126 + */
127 + function fluent_boards_is_rtl(): bool
128 + {
129 + return is_rtl();
130 + }
131 +}
132 +
66 133 function fluent_boards_get_pref_settings($cached = true)
67 134 {
68 135 static $pref = null;
69 136
@@ -157,10 +224,20 @@
157 224 {
158 225 return fluentBoards('db');
159 226 }
160 227
228 +/**
229 + * Retrieves features configuration.
230 + *
231 + * @deprecated 1.90 Use fluent_boards_get_features_config() instead.
232 + */
233 +function fbsGetFeaturesConfig()
234 +{
235 + _deprecated_function(__FUNCTION__, '1.90', 'fluent_boards_get_features_config');
236 + return fluent_boards_get_features_config();
237 +}
161 238
162 -function fbsGetFeaturesConfig()
239 +function fluent_boards_get_features_config()
163 240 {
164 241 $features = fluent_boards_get_option('_fbs_features', []);
165 242
166 243 $defaults = [
@@ -174,13 +251,104 @@
174 251
175 252 return wp_parse_args($features, $defaults);
176 253 }
177 254
255 +/**
256 + * Updates an option value.
257 + *
258 + * @deprecated 1.90 Use fluent_boards_get_option() instead.
259 + */
178 260 function fbsGetOption($key, $default = null)
179 261 {
262 + _deprecated_function(__FUNCTION__, '1.90', 'fluent_boards_get_option');
180 263 return fluent_boards_get_option($key, $default);
181 264 }
182 265
266 +/**
267 + * Updates an option value.
268 + *
269 + * @deprecated 1.90 Use fluent_boards_update_option() instead.
270 + */
183 271 function fbsUpdateOption($key, $value)
184 272 {
273 + _deprecated_function(__FUNCTION__, '1.90', 'fluent_boards_update_option');
185 274 return fluent_boards_update_option($key, $value);
186 -}
275 +}
276 +
277 +
278 +function fluentboardsCsvMimes()
279 +{
280 + /**
281 + * Board Import CSV Mimes
282 + *
283 + * @return array array of CSV mimes
284 + */
285 + return apply_filters('fluent_boards_csv_mimes', [
286 + 'text/csv',
287 + 'text/plain',
288 + 'application/csv',
289 + 'text/comma-separated-values',
290 + 'application/excel',
291 + 'application/vnd.ms-excel',
292 + 'application/vnd.msexcel',
293 + 'text/anytext',
294 + 'application/octet-stream',
295 + 'application/txt'
296 + ]);
297 +}
298 +
299 +function fluent_boards_string_to_bool($value)
300 +{
301 + // Normalize known string values to booleans
302 + $trueFalseMap = [
303 + 'yes' => true,
304 + 'no' => false,
305 + 'true' => true,
306 + 'false' => false,
307 + '1' => true,
308 + '0' => false,
309 + true => true,
310 + false => false,
311 + ];
312 +
313 + // Allow modification of the map
314 + $trueFalseMap = apply_filters('fluent_boards/true_false_convert', $trueFalseMap);
315 +
316 + // Handle array input recursively
317 + if (is_array($value)) {
318 + return array_map('fluent_boards_string_to_bool', $value);
319 + }
320 +
321 + // Normalize string input
322 + $key = is_string($value) ? strtolower(trim($value)) : $value;
323 +
324 + // Match normalized value against map
325 + if (array_key_exists($key, $trueFalseMap)) {
326 + return $trueFalseMap[$key];
327 + }
328 +
329 + // Fallback: return original value if not recognized
330 + return $value;
331 +}
332 +
333 +/**
334 + * Builds the canonical Fluent Boards Upgrade-to-Pro URL.
335 + *
336 + * @param string $utmContent Exact in-plugin CTA placement.
337 + * @return string
338 + */
339 +function fluent_boards_get_upgrade_url($utmContent = '')
340 +{
341 + $queryArgs = [
342 + 'utm_source' => 'fluent-boards',
343 + 'utm_medium' => 'free_plugin',
344 + 'utm_campaign' => 'upgrade_pro',
345 + 'utm_term' => FLUENT_BOARDS_PLUGIN_VERSION,
346 + ];
347 +
348 + $utmContent = sanitize_key($utmContent);
349 + if ($utmContent) {
350 + $queryArgs['utm_content'] = $utmContent;
351 + }
352 +
353 + return add_query_arg($queryArgs, 'https://fluentboards.com/pricing/');
354 +}