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
fluent-boards / app / Functions / helpers.php

helpers.php in FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration 2.1.0, at app/Functions/helpers.php

343 lines 9.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 use FluentBoards\App\App;
4
5 // $app is available
6
7 if (!function_exists('fluentBoards')) {
8 function fluentBoards($module = null)
9 {
10 return App::getInstance($module);
11 }
12 }
13
14 if (!function_exists('FluentBoardsApi')) {
15 function FluentBoardsApi($key = null)
16 {
17 $api = fluentBoards('api');
18 return is_null($key) ? $api : $api->{$key};
19 }
20 }
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
45 if (!function_exists('fluent_boards_user_avatar')) {
46 function fluent_boards_user_avatar($email, $name = '')
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
68 $hash = md5(strtolower(trim($email)));
69 /**
70 * Gravatar URL by Email
71 *
72 * @return string $gravatar url of the gravatar image
73 */
74 $fallback = '';
75 if ($name) {
76 $fallback = '&d=https%3A%2F%2Fui-avatars.com%2Fapi%2F' . urlencode($name) . '/128';
77 }
78
79 return apply_filters('fluent_boards/get_avatar',
80 "https://www.gravatar.com/avatar/{$hash}?s=128" . $fallback,
81 $email
82 );
83 }
84 }
85
86 if (!function_exists('fluent_boards_mix')) {
87 function fluent_boards_mix($path, $manifestDirectory = '')
88 {
89 return fluentBoards('url.assets') . ltrim($path, '/');
90 }
91 }
92
93 if (!function_exists('FluentBoardsAssetUrl')) {
94 function FluentBoardsAssetUrl($path = null)
95 {
96 $assetUrl = fluentBoards('url.assets');
97
98 return $path ? ($assetUrl . $path) : $assetUrl;
99 }
100 }
101
102 if (!function_exists('fluent_boards_page_url')) {
103 function fluent_boards_page_url(): ?string
104 {
105 return apply_filters('fluent_boards/app_url', admin_url('admin.php?page=fluent-boards#/'));
106 }
107 }
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
121 function fluent_boards_get_pref_settings($cached = true)
122 {
123 static $pref = null;
124
125 if ($cached && $pref) {
126 return $pref;
127 }
128
129 $settings = [
130 'timeTracking' => [
131 'enabled' => 'no',
132 'all_boards' => 'yes',
133 'selected_boards' => []
134 ],
135 'frontend' => [
136 'enabled' => 'no',
137 'slug' => 'projects',
138 'render_type' => 'standalone',
139 'page_id' => ''
140 ],
141 'menu_settings' => [
142 'in_fluent_crm' => 'no',
143 'menu_position' => 3
144 ],
145 'recurring_task' => [
146 'enabled' => 'no',
147 'all_boards' => 'yes',
148 'selected_boards' => []
149 ],
150 ];
151
152 $storedSettings = get_option('fluent_boards_modules', []);
153 if ($storedSettings && is_array($storedSettings)) {
154 $settings = wp_parse_args($storedSettings, $settings);
155 }
156
157 $pref = $settings;
158
159 return $settings;
160 }
161
162 if (!function_exists('fluent_boards_site_logo')) {
163 function fluent_boards_site_logo()
164 {
165 $logo_url = '';
166 if (function_exists('get_custom_logo') && has_custom_logo()) {
167 $custom_logo_id = get_theme_mod('custom_logo');
168 $logo = wp_get_attachment_image_src($custom_logo_id, 'full');
169 if ($logo) {
170 $logo_url = $logo[0];
171 }
172 }
173 return apply_filters('fluent_boards/site_logo', $logo_url);
174 }
175 }
176
177 function fluent_boards_get_option($key, $default = null)
178 {
179 $exit = \FluentBoards\App\Models\Meta::where('object_type', 'option')
180 ->where('key', $key)
181 ->first();
182
183 if ($exit) {
184 return $exit->value;
185 }
186
187 return $default;
188 }
189
190 function fluent_boards_update_option($key, $value)
191 {
192 $exit = \FluentBoards\App\Models\Meta::where('object_type', 'option')
193 ->where('key', $key)
194 ->first();
195
196 if ($exit) {
197 $exit->value = $value;
198 $exit->save();
199 } else {
200 $exit = \FluentBoards\App\Models\Meta::create([
201 'object_type' => 'option',
202 'key' => $key,
203 'value' => $value
204 ]);
205 }
206
207 return $exit;
208 }
209
210
211 function fluentBoardsDb()
212 {
213 return fluentBoards('db');
214 }
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 }
226
227 function fluent_boards_get_features_config()
228 {
229 $features = fluent_boards_get_option('_fbs_features', []);
230
231 $defaults = [
232 'cloud_storage' => 'no',
233 // more advanced features/config can be added here
234 ];
235
236 if (defined('FLUENT_BOARDS_CLOUD_STORAGE') && FLUENT_BOARDS_CLOUD_STORAGE) {
237 $features['cloud_storage'] = 'yes';
238 }
239
240 return wp_parse_args($features, $defaults);
241 }
242
243 /**
244 * Updates an option value.
245 *
246 * @deprecated 1.90 Use fluent_boards_get_option() instead.
247 */
248 function fbsGetOption($key, $default = null)
249 {
250 _deprecated_function(__FUNCTION__, '1.90', 'fluent_boards_get_option');
251 return fluent_boards_get_option($key, $default);
252 }
253
254 /**
255 * Updates an option value.
256 *
257 * @deprecated 1.90 Use fluent_boards_update_option() instead.
258 */
259 function fbsUpdateOption($key, $value)
260 {
261 _deprecated_function(__FUNCTION__, '1.90', 'fluent_boards_update_option');
262 return fluent_boards_update_option($key, $value);
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 }
343