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 +158 -2 1.312.1.0 View file →
@@ -18,11 +18,54 @@
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 {
48 + $user = get_user_by('email', $email);
49 +
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 +
56 + $has_custom_avatar = get_user_meta($user->ID, 'wp_user_avatar', true);
57 + if ($has_custom_avatar) {
58 + $custom_avatar_attachment = get_post($has_custom_avatar);
59 + if ($custom_avatar_attachment) {
60 + $avatar_url = wp_get_attachment_url($has_custom_avatar);
61 + return apply_filters('fluent_boards/get_avatar', $avatar_url, $email);
62 + }
63 + }
64 + $avatar_url = get_avatar_url($user->ID, array('size' => 128));
65 + return apply_filters('fluent_boards/get_avatar', $avatar_url, $email);
66 + }
67 +
25 68 $hash = md5(strtolower(trim($email)));
26 69 /**
27 70 * Gravatar URL by Email
28 71 *
@@ -62,8 +105,20 @@
62 105 return apply_filters('fluent_boards/app_url', admin_url('admin.php?page=fluent-boards#/'));
63 106 }
64 107 }
65 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 +
66 121 function fluent_boards_get_pref_settings($cached = true)
67 122 {
68 123 static $pref = null;
69 124
@@ -157,10 +212,20 @@
157 212 {
158 213 return fluentBoards('db');
159 214 }
160 215
216 +/**
217 + * Retrieves features configuration.
218 + *
219 + * @deprecated 1.90 Use fluent_boards_get_features_config() instead.
220 + */
221 +function fbsGetFeaturesConfig()
222 +{
223 + _deprecated_function(__FUNCTION__, '1.90', 'fluent_boards_get_features_config');
224 + return fluent_boards_get_features_config();
225 +}
161 226
162 -function fbsGetFeaturesConfig()
227 +function fluent_boards_get_features_config()
163 228 {
164 229 $features = fluent_boards_get_option('_fbs_features', []);
165 230
166 231 $defaults = [
@@ -174,13 +239,104 @@
174 239
175 240 return wp_parse_args($features, $defaults);
176 241 }
177 242
243 +/**
244 + * Updates an option value.
245 + *
246 + * @deprecated 1.90 Use fluent_boards_get_option() instead.
247 + */
178 248 function fbsGetOption($key, $default = null)
179 249 {
250 + _deprecated_function(__FUNCTION__, '1.90', 'fluent_boards_get_option');
180 251 return fluent_boards_get_option($key, $default);
181 252 }
182 253
254 +/**
255 + * Updates an option value.
256 + *
257 + * @deprecated 1.90 Use fluent_boards_update_option() instead.
258 + */
183 259 function fbsUpdateOption($key, $value)
184 260 {
261 + _deprecated_function(__FUNCTION__, '1.90', 'fluent_boards_update_option');
185 262 return fluent_boards_update_option($key, $value);
186 -}
263 +}
264 +
265 +
266 +function fluentboardsCsvMimes()
267 +{
268 + /**
269 + * Board Import CSV Mimes
270 + *
271 + * @return array array of CSV mimes
272 + */
273 + return apply_filters('fluent_boards_csv_mimes', [
274 + 'text/csv',
275 + 'text/plain',
276 + 'application/csv',
277 + 'text/comma-separated-values',
278 + 'application/excel',
279 + 'application/vnd.ms-excel',
280 + 'application/vnd.msexcel',
281 + 'text/anytext',
282 + 'application/octet-stream',
283 + 'application/txt'
284 + ]);
285 +}
286 +
287 +function fluent_boards_string_to_bool($value)
288 +{
289 + // Normalize known string values to booleans
290 + $trueFalseMap = [
291 + 'yes' => true,
292 + 'no' => false,
293 + 'true' => true,
294 + 'false' => false,
295 + '1' => true,
296 + '0' => false,
297 + true => true,
298 + false => false,
299 + ];
300 +
301 + // Allow modification of the map
302 + $trueFalseMap = apply_filters('fluent_boards/true_false_convert', $trueFalseMap);
303 +
304 + // Handle array input recursively
305 + if (is_array($value)) {
306 + return array_map('fluent_boards_string_to_bool', $value);
307 + }
308 +
309 + // Normalize string input
310 + $key = is_string($value) ? strtolower(trim($value)) : $value;
311 +
312 + // Match normalized value against map
313 + if (array_key_exists($key, $trueFalseMap)) {
314 + return $trueFalseMap[$key];
315 + }
316 +
317 + // Fallback: return original value if not recognized
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/');
342 +}