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