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/Hooks/actions.php +106 -12 1.302.1.0 View file →
@@ -18,11 +18,28 @@
18 18 */
19 19
20 20 (new \FluentBoards\App\Hooks\Handlers\AdminMenuHandler())->register();
21 21
22 +/*
23 + * Add custom CSS for fbs_notice.
24 + */
25 +add_action('admin_head', function () {
26 + echo '<style>
27 + .fbs_notice {
28 + background: var(--fbs-primary-bg, #ffffff);
29 + border: 1px solid var(--fbs-primary-border, #E1E4EA);
30 + border-left: 3px solid #FB3748;
31 + padding: 10px 12px !important;
32 + border-radius: 8px;
33 + margin-bottom: 5px;
34 + }
35 + </style>';
36 +});
37 +
22 38 //$app->addCustomAction('task_prop_changed', 'ActivityHandler@logActivity', 10, 3);
23 39 $app->addCustomAction('task_board_changed', 'ActivityHandler@logMoveTaskToAnotherBoardActivity', 10, 2); //will call from service after board change code merged
24 40 $app->addCustomAction('task_due_date_changed', 'ActivityHandler@logDueDateActivity', 10, 2);
41 +$app->addCustomAction('task_due_date_removed', 'ActivityHandler@logDueDateRemoveActivity', 10, 1);
25 42 $app->addCustomAction('task_start_date_changed', 'ActivityHandler@logStartDateActivity', 10, 2);
26 43
27 44 $app->addCustomAction('task_priority_changed', 'ActivityHandler@logPriorityChangeActivity', 10, 2);
28 45 $app->addCustomAction('comment_created', 'ActivityHandler@logCommentCreateActivity', 10, 1);
@@ -28,25 +45,33 @@
28 45 $app->addCustomAction('comment_created', 'ActivityHandler@logCommentCreateActivity', 10, 1);
29 46 $app->addCustomAction('comment_updated', 'ActivityHandler@logCommentUpdateActivity', 10, 2);
30 47 $app->addCustomAction('comment_deleted', 'ActivityHandler@logCommentDeleteActivity', 10, 1);
31 48 $app->addCustomAction('subtask_added', 'ActivityHandler@logSubtaskAddedActivity', 10, 2);
49 +$app->addCustomAction('subtask_cloned', 'ActivityHandler@logSubtaskCloneActivity', 10, 2);
50 +$app->addCustomAction('subtask_group_created', 'ActivityHandler@logSubtaskGroupAddedActivity', 10, 2);
32 51 $app->addCustomAction('subtask_deleted_activity', 'ActivityHandler@logSubtaskDeletedActivity', 10, 2);
52 +$app->addCustomAction('subtask_group_deleted_activity', 'ActivityHandler@logSubtaskGroupDeletedActivity', 10, 2);
53 +$app->addCustomAction('subtask_group_title_updated', 'ActivityHandler@logSubtaskGroupTitleUpdatedActivity', 10, 2);
33 54 $app->addCustomAction('task_completed_activity', 'ActivityHandler@logTaskCompletedOrReopenActivity', 10, 2);
34 -$app->addCustomAction('task_stage_updated', 'ActivityHandler@logTaskStageUpdatedActivity', 10, 2);
55 +$app->addCustomAction('task_stage_updated', 'ActivityHandler@logTaskStageUpdatedActivity', 10, 3);
35 56 $app->addCustomAction('task_assignee_added', 'ActivityHandler@logAssigneeAddedActivity', 10, 2);
36 57 $app->addCustomAction('task_assignee_removed', 'ActivityHandler@logAssigneeRemovedActivity', 10, 2);
37 58 $app->addCustomAction('task_added_from_fluent_form', 'ActivityHandler@taskAddedFromFluentForms', 10, 1);
59 +$app->addCustomAction('repeat_task_created', 'ActivityHandler@logRepeatTaskCreatedActivity', 10, 2);
60 +$app->addCustomAction('repeat_task_set', 'ActivityHandler@logRepeatTaskSet', 10, 1);
61 +$app->addCustomAction('repeat_task_updated', 'ActivityHandler@logRepeatTaskUpdated', 10, 1);
38 62 $app->addCustomAction('task_created', 'ActivityHandler@logTaskCreationActivity', 10, 1);
39 63 $app->addCustomAction('task_content_updated', 'ActivityHandler@logTaskContentUpdatedActivity', 10, 3);
40 64 $app->addCustomAction('task_deleted', 'TaskHandler@taskDeleted', 10, 1);
65 +$app->addCustomAction('task_archived', 'ActivityHandler@taskArchived', 10, 1);
66 +//$app->addCustomAction('task_custom_field_changed', 'ActivityHandler@logCustomFieldActivity', 10, 5); // commented for now, will implement later
41 67
42 68 $app->addCustomAction('board_created', 'BoardHandler@boardCreated', 10, 1);
69 +$app->addCustomAction('board_created_from_automation', 'BoardHandler@boardCreatedFromAutomation', 10, 1);
43 70 $app->addCustomAction('before_board_deleted', 'BoardHandler@beforeBoardDeleted', 10, 2);
44 -$app->addCustomAction('board_deleted', 'BoardHandler@boardDeleted', 10, 1);
45 71 $app->addCustomAction('board_updated', 'BoardHandler@boardUpdated', 10, 2);
46 72 $app->addCustomAction('stage_updated', 'BoardHandler@boardStageUpdated', 10, 3);
47 73 $app->addCustomAction('board_stage_moved', 'BoardHandler@boardStageMoved', 10, 2);
48 -$app->addCustomAction('board_stage_dragged', 'BoardHandler@boardStageDragged', 10, 1);
49 74 $app->addCustomAction('board_stage_added', 'BoardHandler@boardStageAdded', 10, 2);
50 75 $app->addCustomAction('stage_deleted', 'BoardHandler@boardStageDeleted', 10, 2);
51 76 $app->addCustomAction('stage_archived', 'BoardHandler@boardStageArchived', 10, 2);
52 77 $app->addCustomAction('board_stage_restored', 'BoardHandler@boardArchivedStageRestore', 10, 2);
@@ -53,10 +78,13 @@
53 78 $app->addCustomAction('task_created', 'BoardHandler@taskCreatedOnBoard', 10, 1);
54 79 $app->addCustomAction('before_task_deleted', 'BoardHandler@beforeTaskDeleted', 10, 2);
55 80 $app->addCustomAction('task_deleted', 'BoardHandler@taskdeleted', 10, 1);
56 81 $app->addCustomAction('task_moved_from_board', 'BoardHandler@taskMovedFromBoard', 10, 3);
57 -$app->addCustomAction('task_archived', 'BoardHandler@taskarchivedOnBoard', 10, 1);
82 +$app->addCustomAction('task_moved_from_board', 'ActivityHandler@taskMovedFromBoard', 10, 3);
83 +$app->addCustomAction('task_archived', 'BoardHandler@taskArchivedOnBoard', 10, 1);
84 +$app->addCustomAction('tasks_moved_between_stages', 'BoardHandler@tasksMovedBetweenStages', 10, 4);
58 85 $app->addCustomAction('board_member_added', 'BoardHandler@boardMemberAdded', 10, 2);
86 +$app->addCustomAction('board_viewer_added', 'BoardHandler@boardViewerAdded', 10, 2);
59 87 $app->addCustomAction('board_member_removed', 'BoardHandler@boardMemberRemoved', 10, 2);
60 88 $app->addCustomAction('board_admin_added', 'BoardHandler@boardAdminAdded', 10, 2);
61 89 $app->addCustomAction('board_admin_removed', 'BoardHandler@boardAdminRemoved', 10, 2);
62 90 $app->addCustomAction('associate_user_add_change_remove_activity', 'ActivityHandler@associateUserAddChangeRemoveActivity', 10, 3);
@@ -67,10 +95,10 @@
67 95 $app->addCustomAction('board_label_created', 'BoardHandler@boardLabelCreatedActivity', 10, 1);
68 96 $app->addCustomAction('board_label_updated', 'BoardHandler@boardLabelUpdatedActivity', 10, 1);
69 97 $app->addCustomAction('board_label_deleted', 'BoardHandler@boardLabelDeletedActivity', 10, 1);
70 98 $app->addCustomAction('board_stages_reordered', 'BoardHandler@boardStagesReOrdered', 10, 2);
99 +$app->addCustomAction('default_assignees_updated', 'BoardHandler@defaultAssigneesUpdated', 10, 2);
71 100
72 -
73 101 $app->addCustomAction('comment_created', 'NotificationHandler@addCommentNotification', 10, 1);
74 102 $app->addCustomAction('mention_comment_notification', 'NotificationHandler@mentionInCommentNotification', 10, 2);
75 103 $app->addCustomAction('subtask_added', 'NotificationHandler@addSubtaskNotification', 10, 2);
76 104 $app->addCustomAction('task_due_date_changed', 'NotificationHandler@changeDueDateNotification', 10, 2);
@@ -77,9 +105,9 @@
77 105 $app->addCustomAction('task_start_date_changed', 'NotificationHandler@changeStartDateNotification', 10, 2);
78 106 $app->addCustomAction('task_stage_updated', 'NotificationHandler@changeStageNotification', 10, 2);
79 107 $app->addCustomAction('task_priority_changed', 'NotificationHandler@changePriorityNotification', 10, 2);
80 108 $app->addCustomAction('task_archived', 'NotificationHandler@taskArchiveNotification', 10, 1);
81 -$app->addCustomAction('task_content_updated', 'NotificationHandler@changeTitleOrDescriptionNotification', 10, 3);
109 +$app->addCustomAction('task_content_updated', 'NotificationHandler@changeTitleNotification', 10, 3);
82 110 //$app->addCustomAction('description_changed_notification', 'NotificationHandler@changeDescriptionNotification', 10, 1);
83 111 $app->addCustomAction('board_changed_notification', 'NotificationHandler@changeBoardNotification', 10, 2);
84 112 $app->addCustomAction('task_assignee_added', 'NotificationHandler@assigneeAddedNotification', 10, 2);
85 113 $app->addCustomAction('task_assignee_removed', 'NotificationHandler@assigneeRemovedNotification', 10, 2);
@@ -96,18 +124,19 @@
96 124 $app->addCustomAction('one_time_schedule_send_email_for_removed_from_task', 'ScheduleHandler@sendEmailForChangeStage', 10, 3);
97 125
98 126 $app->addCustomAction('task_attachment_added', 'ActivityHandler@taskAttachmentAdded', 10, 1);
99 127 $app->addCustomAction('task_attachment_deleted', 'ActivityHandler@taskAttachmentDeleted', 10, 1);
100 -$app->addCustomAction('task_attachment_deleted', 'TaskHandler@taskAttachmentDeleted', 10, 1);
128 +$app->addCustomAction('task_attachment_deleted', 'TaskHandler@taskAttachmentDeleted', 10, 2);
129 +// Removed: direct call is made from Comment::deleting to TaskHandler@commentImageDeleted
101 130 $app->addAction('deleted_user', 'BoardHandler@deleteUserRelatedData', 10, 3);
102 -$app->addAction('delete_attachment', 'FileHandler@mediaFileDeleted', 10, 1);
103 131
104 -$app->addCustomAction('send_invitation', 'ScheduleHandler@sendInvitationViaEmail', 10, 3);
105 132 $app->addCustomAction('task_created', 'TaskHandler@onTaskCreated', 10, 1);
106 133 $app->addCustomAction('comment_created', 'TaskHandler@onCommentCreated', 10, 1);
107 134 $app->addCustomAction('assign_another_user', 'TaskHandler@onAssignAnotherUser', 10, 2);
135 +$app->addCustomAction('board_background_updated', 'BoardHandler@backgroundUpdated', 10, 2);
136 +$app->addCustomAction('task_cloned', 'TaskHandler@taskCloned', 10, 2);
137 +$app->addCustomAction('task_cloned_activity', 'ActivityHandler@taskCloned', 10, 2);
108 138
109 -
110 139 if (defined('WP_CLI') && WP_CLI) {
111 140 \WP_CLI::add_command('fluent_boards', '\FluentBoards\App\Hooks\Cli\Commands');
112 141 }
113 142
@@ -112,22 +141,24 @@
112 141 }
113 142
114 143
115 144 add_action('init', function () {
145 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public routing parameter check, no data modification
116 146 if (!isset($_REQUEST['fbs'])) {
117 147 return;
118 148 }
119 149 });
120 150
121 -
122 151 /*
123 152 * IMPORTANT
124 153 * External Pages Handler
125 154 * Each Request must have fbs=1 as a query parameter, then the plugin will handle the request.
126 155 */
156 +// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public routing logic, security validated in individual handlers
127 157 if(isset($_GET['fbs']) && $_GET['fbs'] == 1) {
128 158
129 159 // For viewing attachment
160 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public routing logic, security validated in handler
130 161 if(isset($_GET['route']) && ($_GET['route'] == 'task')) {
131 162 add_action('init', function() {
132 163 (new \FluentBoardsPro\App\Hooks\Handlers\ExternalPages())->handleTaskWebhook();
133 164 });
@@ -132,10 +163,12 @@
132 163 (new \FluentBoardsPro\App\Hooks\Handlers\ExternalPages())->handleTaskWebhook();
133 164 });
134 165 }
135 166
167 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public file serving endpoint, security validated by hash in handler
136 168 if(isset($_GET['fbs_comment_image'])) {
137 - if(isset($_GET['fbs_type']) == 'public_url') {
169 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public routing check, security validated in handler
170 + if(isset($_GET['fbs_type']) && $_GET['fbs_type'] == 'public_url') {
138 171 add_action('init', function() {
139 172 (new \FluentBoards\App\Hooks\Handlers\ExternalPages())->view_uploaded_comment_image();
140 173 });
141 174 } else {
@@ -145,5 +178,66 @@
145 178 }
146 179
147 180 }
148 181
182 +}
183 +
184 +// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public redirect endpoint, no sensitive operations
185 +if(isset($_GET['redirect']) && $_GET['redirect'] == 'to_task') {
186 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public redirect endpoint, validation performed in handler
187 + if (isset($_GET['taskId'])) {
188 + add_action('init', function() {
189 + (new \FluentBoards\App\Hooks\Handlers\ExternalPages())->redirectToPage();
190 + });
191 + }
192 +}
193 +// Stage Archive Handler - Archive tasks when stage is archived, restore when stage is restored
194 +$app->addAction('fluent_boards/stage_archived_with_tasks', 'StageArchiveHandler@onStageArchived', 10, 2);
195 +$app->addAction('fluent_boards/stage_restored_with_tasks', 'StageArchiveHandler@onStageRestored', 10, 2);
196 +
197 +/*
198 + * MCP - Register Fluent Boards abilities for the WordPress Abilities API.
199 + *
200 + * This mirrors FluentCRM's MCP architecture: on WordPress installs without the
201 + * Abilities API / WP MCP Adapter, `wp_register_ability` is undefined and the
202 + * integration skips silently. Admins can opt out with the `mcp_enabled` option.
203 + */
204 +add_filter('fluent_kit/mcp_products', [\FluentBoards\App\Modules\MCP\MCPInit::class, 'registerToolkitProduct'], 10, 2);
205 +add_filter('fluent_kit/mcp_toggle_handlers', function ($handlers) {
206 + $handlers['fluent-boards'] = [
207 + 'get_enabled' => function () {
208 + return fluent_boards_get_option('mcp_enabled', 'yes') === 'yes';
209 + },
210 + 'set_enabled' => function ($enabled) {
211 + fluent_boards_update_option('mcp_enabled', $enabled ? 'yes' : 'no');
212 + },
213 + ];
214 +
215 + return $handlers;
216 +});
217 +
218 +add_action('init', function () {
219 + if (!function_exists('wp_register_ability')) {
220 + return;
221 + }
222 +
223 + if (fluent_boards_get_option('mcp_enabled', 'yes') !== 'yes') {
224 + return;
225 + }
226 +
227 + (new \FluentBoards\App\Modules\MCP\MCPInit())->init();
228 +}, 5);
229 +
230 +$invalidateMcpContext = [\FluentBoards\App\Modules\MCP\Tools\ContextTools::class, 'invalidateCache'];
231 +foreach ([
232 + 'fluent_boards/board_created',
233 + 'fluent_boards/board_updated',
234 + 'fluent_boards/before_board_deleted',
235 + 'fluent_boards/board_stage_added',
236 + 'fluent_boards/stage_updated',
237 + 'fluent_boards/stage_deleted',
238 + 'fluent_boards/board_label_created',
239 + 'fluent_boards/board_label_updated',
240 + 'fluent_boards/board_label_deleted',
241 +] as $mcpContextHook) {
242 + add_action($mcpContextHook, $invalidateMcpContext);
149 243 }