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.1 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 All 44 releases
← All changes | app/Hooks/Handlers/AdminMenuHandler.php +55 -73 1.95 → 2.2.0 View file →
@@ -126,12 +126,21 @@
126 126 );
127 127
128 128 add_submenu_page(
129 129 'fluent-boards',
130 + __('Addons', 'fluent-boards'),
131 + __('Addons', 'fluent-boards'),
132 + 'manage_options',
133 + 'fluent-boards#/add-ons',
134 + [$this, 'render']
135 + );
136 +
137 + add_submenu_page(
138 + 'fluent-boards',
130 139 __('Settings', 'fluent-boards'),
131 140 __('Settings', 'fluent-boards'),
132 141 'manage_options',
133 - 'fluent-boards#/settings/members-role',
142 + 'fluent-boards#/settings/general-settings',
134 143 [$this, 'render']
135 144 );
136 145 }
137 146
@@ -148,11 +157,8 @@
148 157 $baseUrl = fluent_boards_page_url();
149 158
150 159 do_action('fluent_boards/rendering_app');
151 160
152 - // For subtask sync
153 - UpdateHandler::maybeSubtaskGroupSync();
154 -
155 161 App::make('view')->render('admin.menu', [
156 162 'name' => $name,
157 163 'slug' => $slug,
158 164 'menuItems' => $this->getMenuItems($app),
@@ -205,25 +211,8 @@
205 211
206 212 $isAdmin = PermissionManager::isAdmin();
207 213
208 214 if ($isAdmin) {
209 - $menuItems['settings'] = [
210 - 'key' => 'settings',
211 - 'label' => __('Settings', 'fluent-boards'),
212 - 'permalink' => $baseUrl . 'settings/members-role'
213 - ];
214 - }
215 -
216 - if (!defined('FLUENT_BOARDS_PRO')) {
217 - $menuItems['get_pro'] = [
218 - 'key' => 'get_pro',
219 - 'label' => __('Get Pro', 'fluent-boards'),
220 - 'permalink' => 'https://fluentboards.com?utm_source=plugin&utm_medium=menu&utm_campaign=pro&utm_id=wp',
221 - 'class' => 'pro_link'
222 - ];
223 - }
224 -
225 - if ($isAdmin) {
226 215 $menuItems['help'] = [
227 216 'key' => 'help',
228 217 'label' => __('Community', 'fluent-boards'),
229 218 'target' => '_blank',
@@ -233,9 +222,9 @@
233 222
234 223 if ($isDiffUrl) {
235 224 $menuItems['front'] = [
236 225 'key' => 'front',
237 - 'label' => __('Frontend Portal', 'fluent-boards'),
226 + 'label' => __('Front Portal', 'fluent-boards'),
238 227 'target' => '_blank',
239 228 'permalink' => fluent_boards_page_url()
240 229 ];
241 230 }
@@ -312,23 +301,11 @@
312 301
313 302 // Inject Vite HMR client in dev mode
314 303 Vite::injectViteClient();
315 304
316 - $isRtl = is_rtl();
317 - $adminAppCss = $isRtl ? 'scss/admin.scss' : 'scss/admin.scss';
318 - Vite::enqueueStyle($slug . '_admin_app', $adminAppCss);
305 + $isRtl = fluent_boards_is_rtl();
306 + Vite::enqueueStyle($slug . '_admin_app', 'scss/admin.scss');
319 307
320 - // In production, load the RTL version if needed
321 - if ($isRtl && !Vite::underDevelopment()) {
322 - $assets = $app['url.assets'];
323 - wp_enqueue_style(
324 - $slug . '_admin_app_rtl',
325 - $assets . 'admin/admin-rtl.css',
326 - [$slug . '_admin_app'],
327 - FLUENT_BOARDS_PLUGIN_VERSION
328 - );
329 - }
330 -
331 308 // Enqueue merged chunk CSS (Vue SFC styles) in production
332 309 if (!Vite::underDevelopment()) {
333 310 $assets = $app['url.assets'];
334 311 $styleCssPath = FLUENT_BOARDS_PLUGIN_PATH . 'assets/admin/style.css';
@@ -341,8 +318,23 @@
341 318 );
342 319 }
343 320 }
344 321
322 + // RTL overrides must load after style.css so rules appended to the
323 + // element-plus layer win by source order, not only by specificity.
324 + if ($isRtl) {
325 + $rtlDeps = [$slug . '_admin_app'];
326 + if (wp_style_is($slug . '_vite_style', 'enqueued')) {
327 + $rtlDeps[] = $slug . '_vite_style';
328 + }
329 + Vite::enqueueStyle(
330 + $slug . '_admin_app_rtl',
331 + 'scss/admin_rtl.scss',
332 + $rtlDeps,
333 + FLUENT_BOARDS_PLUGIN_VERSION
334 + );
335 + }
336 +
345 337 do_action('fluent-boards_loading_app');
346 338
347 339 Vite::enqueueScript(
348 340 $slug . '_admin_app',
@@ -375,8 +367,9 @@
375 367 $currentUser = get_user_by('ID', get_current_user_id());
376 368 $assets = $app['url.assets'];
377 369 $roleAndPermissions = $this->getRoleAndPermissions($currentUser->ID);
378 370 $onboardingValue = $this->getOnboardingValue();
371 + $generalSettings = fluent_boards_get_option('general_settings', []);
379 372
380 373 return apply_filters('fluent_boards/app_vars', [
381 374 'slug' => $slug = $app->config->get('app.slug'),
382 375 'nonce' => wp_create_nonce($slug),
@@ -384,13 +377,23 @@
384 377 'fluent_boards_file_upload_nonce' => wp_create_nonce('fluent_boards_file_upload_nonce'),
385 378 'ajaxurl' => admin_url('admin-ajax.php'),
386 379 'file_upload_limit' => $this->fileUploadLimit(),
387 380 'brand_logo' => $this->getMenuIcon(),
381 + 'business_name' => sanitize_text_field(Arr::get($generalSettings, 'business_name', '')),
388 382 'asset_url' => $assets,
389 383 'admin_url' => admin_url('admin.php'),
390 384 'fluent_crm_exists' => !defined('FLUENTCRM') ? false : true,
385 + 'fluent_support_exists' => !!defined('FLUENT_SUPPORT_VERSION'),
386 + 'can_manage_crm_contacts' => $this->canManageCrmContacts(),
391 387 'fluent_roadmap_exists' => !defined('FLUENT_ROADMAP') ? false : true,
392 388 'has_pro' => !!defined('FLUENT_BOARDS_PRO_VERSION'),
389 + 'upgrade_url' => fluent_boards_get_upgrade_url(),
390 + 'board_solid_colors' => Constant::BOARD_BACKGROUND_DEFAULT_SOLID_COLORS,
391 + 'board_gradient_colors' => Constant::BOARD_BACKGROUND_DEFAULT_GRADIENT_COLORS,
392 + 'label_color_presets' => Constant::LABEL_COLOR_PRESETS,
393 + 'ai_features' => [
394 + 'enabled' => (new \FluentBoards\App\Services\AiService())->isReady(),
395 + ],
393 396 'me' => [
394 397 'id' => $currentUser->ID,
395 398 'full_name' => trim($currentUser->first_name . ' ' . $currentUser->last_name),
396 399 'display_name' => $currentUser->display_name,
@@ -395,8 +398,9 @@
395 398 'full_name' => trim($currentUser->first_name . ' ' . $currentUser->last_name),
396 399 'display_name' => $currentUser->display_name,
397 400 'email' => $currentUser->user_email,
398 401 'photo' => fluent_boards_user_avatar($currentUser->user_email, $currentUser->display_name),
402 + 'logout_url' => wp_logout_url(),
399 403 'fluent_boards_role' => $roleAndPermissions['role'],
400 404 'fluent_boards_capabilities' => $roleAndPermissions['permissions'],
401 405 'is_wp_admin' => user_can($currentUser->ID, 'manage_options') ? 'yes' : 'no',
402 406 'can_create_board' => PermissionManager::userHasBoardCreationPermission($currentUser->ID)
@@ -410,8 +414,10 @@
410 414 'trans' => TransStrings::getStrings(),
411 415 'is_new' => Board::count() == 0 ? 'yes' : 'no',
412 416 'is_onboarded' => $onboardingValue,
413 417 'render_in' => is_admin() ? 'admin' : 'front',
418 + // Gates wp-admin links (WP profile, CRM, application passwords) so the frontend portal shows no admin traces.
419 + 'can_access_wp_admin' => (bool) apply_filters('fluent_boards/can_access_wp_admin', is_admin() || current_user_can('manage_options'), $currentUser),
414 420 'dashboard_notices' => apply_filters('fluent_boards/dashboard_notices', []),
415 421 'is_beta' => defined('FLUENT_BOARDS_PRO_VERSION') && !defined('FLUENT_BOARDS_PRO_LIVE'),
416 422 'advanced_modules' => fluent_boards_get_pref_settings(),
417 423 'crm_base_url' => defined('FLUENTCRM') ? fluentcrm_menu_url_base() : '',
@@ -425,15 +431,19 @@
425 431 'dashiconsCss' => add_query_arg(
426 432 'ver', get_bloginfo('version'),
427 433 site_url('/wp-includes/css/dashicons.css')
428 434 ),
429 - 'is_rtl' => is_rtl(),
430 - 'task_tabs' => apply_filters('fluent_boards/task_tabs', $this->getDefaultTaskTabs()),
435 + 'is_rtl' => fluent_boards_is_rtl(),
431 436 'board_menu_items' => BoardMenuHandler::getMenuItems(),
432 437 'reminder_types' => defined('FLUENT_BOARDS_PRO') ? Helper::taskReminderTypes() : [],
433 438 ]);
434 439 }
435 440
441 + protected function canManageCrmContacts()
442 + {
443 + return defined('FLUENTCRM') && \FluentCrm\App\Services\PermissionManager::currentUserCan('fcrm_manage_contacts');
444 + }
445 +
436 446 private function getOnboardingValue()
437 447 {
438 448 $onboarding = Meta::where('key', Constant::FBS_ONBOARDING)->first();
439 449 if ($onboarding) {
@@ -445,34 +455,16 @@
445 455 //
446 456 // return 'no';
447 457 }
448 458
449 - private function getDefaultTaskTabs()
450 - {
451 - return [
452 - 'all' => [
453 - 'key' => 'all',
454 - 'label' => __('All', 'fluent-boards'),
455 - 'component' => 'task-all-comments-and-activities'
456 - ],
457 - 'comment' => [
458 - 'key' => 'comment',
459 - 'label' => __('Comments', 'fluent-boards'),
460 - 'component' => 'task-comments'
461 - ],
462 - 'activity' => [
463 - 'key' => 'activity',
464 - 'label' => __('Activities', 'fluent-boards'),
465 - 'component' => 'task-activities'
466 - ]
467 - ];
468 - }
469 459 public function getDefaultPriorities()
470 460 {
471 461 return [
472 - 'low' => __('Low', 'fluent-boards'),
462 + '' => __('No priority', 'fluent-boards'),
463 + 'urgent' => __('Urgent', 'fluent-boards'),
464 + 'high' => __('High', 'fluent-boards'),
473 465 'medium' => __('Medium', 'fluent-boards'),
474 - 'high' => __('High', 'fluent-boards')
466 + 'low' => __('Low', 'fluent-boards')
475 467 ];
476 468 }
477 469
478 470 /*
@@ -552,25 +544,15 @@
552 544 });
553 545 }
554 546
555 547 /**
556 - * Retrieves the maximum upload limit based on PHP and WordPress configurations.
548 + * Retrieves the Fluent Boards upload limit exposed to the admin app.
557 549 *
558 - * This method calculates and returns the minimum value among the following:
559 - * 1. The PHP 'upload_max_filesize' configuration.
560 - * 2. The PHP 'post_max_size' configuration.
561 - * 3. The WordPress maximum upload size limit using the 'wp_max_upload_size' function.
562 - *
563 - * @return int The minimum of the mentioned upload size limits in bytes.
550 + * @return int Upload limit in bytes.
564 551 */
565 552 public function fileUploadLimit()
566 553 {
567 - // Calculate the minimum of 'upload_max_filesize', 'post_max_size', and WordPress maximum upload size.
568 - return min(
569 - wp_convert_hr_to_bytes(ini_get('upload_max_filesize')),
570 - wp_convert_hr_to_bytes(ini_get('post_max_size')),
571 - wp_max_upload_size()
572 - );
554 + return (new \FluentBoards\App\Services\UploadService())->getFileUploadLimit();
573 555 }
574 556
575 557 public function getInlineScript()
576 558 {