--- name: perfex-hooks description: Perfex CRM hooks system. Actions, filters, add_action, add_filter, do_action, apply_filters. Complete hook list by category. Based on official documentation only. Use when user mentions "perfex hooks", "action hook", "filter perfex", "extend perfex". author: Descomplicar® Crescimento Digital version: 1.0.0 quality_score: 70 user_invocable: true desk_task: null --- # /perfex-hooks - Sistema de Hooks Perfex CRM Sistema de extensibilidade via actions e filters. **Zero assumptions, zero hallucinations** - apenas documentação oficial. --- ## Documentação Base - [Action Hooks](https://help.perfexcrm.com/action-hooks/) - [GitHub Hook List](https://gist.github.com/JamesSimpson/4eae4ba2d6d7072eca9f0fae58b8887c) --- ## Conceitos Fundamentais | Tipo | Função | Retorno | Uso | |------|--------|---------|-----| | **Action** | Executa lógica após eventos | void | Side effects (logs, emails, etc.) | | **Filter** | Modifica dados antes de processamento | Dados modificados | Alterar valores | --- ## Sintaxe (v2.3.0+) ### Registar Action ```php hooks()->add_action($tag, $callback, $priority = 10, $accepted_args = 1); ``` **Parâmetros:** - `$tag` (string): Nome do hook - `$callback` (callable): Função a executar - `$priority` (int): Ordem de execução (menor = primeiro). Default: 10 - `$accepted_args` (int): Número de argumentos. Default: 1 **Exemplo:** ```php // No init file do módulo hooks()->add_action('after_client_added', 'meu_modulo_after_client_added'); function meu_modulo_after_client_added($clientId) { // Lógica após cliente criado log_activity('Novo cliente criado: ' . $clientId); // Enviar notificação $CI = &get_instance(); $CI->load->model('clients_model'); $client = $CI->clients_model->get($clientId); // Integração externa, etc. } ``` ### Registar Filter ```php hooks()->add_filter($tag, $callback, $priority = 10, $accepted_args = 1); ``` **Exemplo:** ```php hooks()->add_filter('before_client_added', 'meu_modulo_before_client_added'); function meu_modulo_before_client_added($data) { // Modificar dados antes de guardar if (empty($data['country'])) { $data['country'] = 177; // Portugal } // OBRIGATÓRIO: retornar dados modificados return $data; } ``` ### Executar Action (criar hooks próprios) ```php hooks()->do_action($tag, $arg = ''); ``` **Exemplo:** ```php // No teu módulo, permitir que outros módulos executem código hooks()->do_action('meu_modulo_after_process', $resultId); ``` ### Aplicar Filter (criar filters próprios) ```php hooks()->apply_filters($tag, $value, $additionalParams = []); ``` **Exemplo:** ```php // Permitir que outros módulos modifiquem dados $data = hooks()->apply_filters('meu_modulo_data', $data); ``` --- ## Onde Colocar Hooks ### Opção 1: Init File do Módulo (Recomendado) ```php // modules/meu_modulo/meu_modulo.php hooks()->add_action('after_client_added', 'meu_modulo_client_handler'); ``` ### Opção 2: my_functions_helper.php (Customizações Simples) ```php // application/helpers/my_functions_helper.php hooks()->add_action('after_client_added', 'custom_client_handler'); ``` --- ## Lista Completa de Hooks por Categoria ### Autenticação | Hook | Trigger | Argumentos | |------|---------|------------| | `admin_auth_init` | Início auth admin | - | | `after_staff_login` | Após login staff | $staff_id | | `after_user_logout` | Após logout | - | | `after_contact_login` | Após login contacto | $contact_id | | `after_client_register` | Após registo cliente | $client_id | | `after_client_logout` | Após logout cliente | - | ### Clientes | Hook | Trigger | Argumentos | |------|---------|------------| | `before_client_added` | **FILTER** - Antes de criar | $data | | `after_client_added` | Após criar cliente | $client_id | | `before_client_updated` | **FILTER** - Antes de actualizar | $data, $client_id | | `after_client_updated` | Após actualizar | $client_id | | `before_client_deleted` | Antes de apagar | $client_id | | `after_client_deleted` | Após apagar | $client_id | | `contact_created` | Contacto criado | $contact_id | | `contact_updated` | Contacto actualizado | $contact_id | | `before_delete_contact` | Antes apagar contacto | $contact_id | | `contact_deleted` | Contacto apagado | $contact_id | ### Facturas | Hook | Trigger | Argumentos | |------|---------|------------| | `before_invoice_added` | **FILTER** - Antes de criar | $data | | `after_invoice_added` | Após criar | $invoice_id | | `before_invoice_updated` | **FILTER** - Antes de actualizar | $data, $invoice_id | | `after_invoice_updated` | Após actualizar | $invoice_id | | `invoice_sent` | Factura enviada | $invoice_id | | `invoice_status_changed` | Status alterado | $invoice_id, $status | | `before_invoice_deleted` | Antes de apagar | $invoice_id | | `invoice_marked_as_cancelled` | Factura cancelada | $invoice_id | ### Orçamentos (Estimates) | Hook | Trigger | Argumentos | |------|---------|------------| | `before_estimate_added` | **FILTER** - Antes de criar | $data | | `after_estimate_added` | Após criar | $estimate_id | | `after_estimate_updated` | Após actualizar | $estimate_id | | `estimate_sent` | Orçamento enviado | $estimate_id | | `estimate_accepted` | Aceite pelo cliente | $estimate_id | | `estimate_declined` | Rejeitado | $estimate_id | | `estimate_converted_to_invoice` | Convertido em factura | $estimate_id, $invoice_id | ### Propostas | Hook | Trigger | Argumentos | |------|---------|------------| | `proposal_created` | Proposta criada | $proposal_id | | `after_proposal_updated` | Após actualizar | $proposal_id | | `proposal_sent` | Proposta enviada | $proposal_id | | `proposal_accepted` | Aceite | $proposal_id | | `proposal_declined` | Rejeitada | $proposal_id | | `proposal_converted_to_invoice` | → Factura | $proposal_id | | `proposal_converted_to_estimate` | → Orçamento | $proposal_id | ### Leads | Hook | Trigger | Argumentos | |------|---------|------------| | `lead_created` | Lead criado | $lead_id | | `before_lead_deleted` | Antes de apagar | $lead_id | | `lead_marked_as_lost` | Marcado perdido | $lead_id | | `lead_marked_as_junk` | Marcado spam | $lead_id | | `lead_converted_to_customer` | Convertido | $lead_id, $customer_id | ### Tarefas | Hook | Trigger | Argumentos | |------|---------|------------| | `after_add_task` | Tarefa criada | $task_id | | `after_update_task` | Tarefa actualizada | $task_id | | `task_status_changed` | Status alterado | $task_id, $status | | `task_deleted` | Tarefa apagada | $task_id | | `task_timer_started` | Timer iniciado | $task_id, $staff_id | | `task_timer_deleted` | Timer apagado | $timer_id | | `task_comment_added` | Comentário adicionado | $comment_id, $task_id | | `task_checklist_item_created` | Checklist item criado | $item_id | | `task_checklist_item_finished` | Checklist item concluído | $item_id | ### Projectos | Hook | Trigger | Argumentos | |------|---------|------------| | `after_add_project` | Projecto criado | $project_id | | `after_update_project` | Projecto actualizado | $project_id | | `before_remove_project_file` | Antes remover ficheiro | $file_id | ### Staff | Hook | Trigger | Argumentos | |------|---------|------------| | `staff_member_created` | Staff criado | $staff_id | | `staff_member_updated` | Staff actualizado | $staff_id | | `staff_member_profile_updated` | Perfil actualizado | $staff_id | ### Pagamentos | Hook | Trigger | Argumentos | |------|---------|------------| | `after_payment_added` | Pagamento registado | $payment_id | | `customer_subscribed_to_subscription` | Subscrição activada | $subscription_id | | `credit_note_refund_created` | Reembolso criado | $refund_id | ### Contratos | Hook | Trigger | Argumentos | |------|---------|------------| | `after_contract_added` | Contrato criado | $contract_id | | `after_contract_updated` | Contrato actualizado | $contract_id | | `before_contract_deleted` | Antes de apagar | $contract_id | | `contract_html_viewed` | Contrato visualizado | $contract_id | ### Tickets | Hook | Trigger | Argumentos | |------|---------|------------| | `ticket_created` | Ticket criado | $ticket_id | | `before_ticket_deleted` | Antes de apagar | $ticket_id | | `before_delete_ticket_reply` | Antes apagar resposta | $reply_id | ### Módulos | Hook | Trigger | Argumentos | |------|---------|------------| | `modules_loaded` | Módulos carregados | - | | `pre_activate_module` | Antes de activar | $module_name | | `module_activated` | Módulo activado | $module_name | | `pre_deactivate_module` | Antes de desactivar | $module_name | | `module_deactivated` | Módulo desactivado | $module_name | | `module_installed` | Módulo instalado | $module_name | | `pre_uninstall_module` | Antes de desinstalar | $module_name | | `module_uninstalled` | Módulo desinstalado | $module_name | ### UI / Templates | Hook | Trigger | Argumentos | |------|---------|------------| | `app_admin_head` | Header admin | - | | `app_admin_footer` | Footer admin | - | | `before_start_render_dashboard_content` | Antes dashboard | - | | `after_dashboard` | Após dashboard | - | | `before_render_aside_menu` | Antes menu lateral | - | | `after_render_aside_menu` | Após menu lateral | - | --- ## Exemplos Práticos ### 1. Integração Externa Após Cliente Criado ```php hooks()->add_action('after_client_added', 'sync_to_external_crm'); function sync_to_external_crm($clientId) { $CI = &get_instance(); $CI->load->model('clients_model'); $client = $CI->clients_model->get($clientId); // Enviar para API externa $response = wp_remote_post('https://api.externa.com/customers', [ 'body' => json_encode([ 'name' => $client->company, 'email' => $client->email, 'vat' => $client->vat, ]) ]); log_activity('Cliente sincronizado: ' . $clientId); } ``` ### 2. Validar Dados Antes de Criar Factura ```php hooks()->add_filter('before_invoice_added', 'validate_invoice_data'); function validate_invoice_data($data) { // Forçar data de vencimento mínima 30 dias if (isset($data['duedate'])) { $due = strtotime($data['duedate']); $min = strtotime('+30 days'); if ($due < $min) { $data['duedate'] = date('Y-m-d', $min); } } return $data; // OBRIGATÓRIO retornar } ``` ### 3. Adicionar Conteúdo ao Dashboard ```php hooks()->add_action('before_start_render_dashboard_content', 'add_custom_widget'); function add_custom_widget() { $CI = &get_instance(); $CI->load->view('meu_modulo/dashboard_widget'); } ``` --- ## Anti-Patterns (NUNCA FAZER) | Anti-Pattern | Risco | Alternativa | |--------------|-------|-------------| | Não retornar valor em filter | Dados perdidos | SEMPRE retornar | | Modificar core em vez de hooks | Quebra em updates | Usar hooks | | Hooks sem prefixo único | Conflitos | Prefixar callbacks | | Ignorar prioridade | Ordem errada | Definir prioridade | | Exceptions não tratadas em hooks | Quebra sistema | Try/catch | --- ## Checklist Implementação de Hook ``` 1. [ ] Hook correcto identificado (action vs filter) 2. [ ] Callback com prefixo único 3. [ ] Número de argumentos correcto 4. [ ] Filter retorna dados (OBRIGATÓRIO) 5. [ ] Try/catch para operações externas 6. [ ] Testado em desenvolvimento 7. [ ] Log de actividade para debug ``` --- **Versão:** 1.0.0 | **Autor:** Descomplicar® **Fonte:** help.perfexcrm.com/action-hooks