Logic Hooks are the backbone of advanced SuiteCRM development. While workflows handle most automation through the admin interface, Logic Hooks give developers programmatic control over CRM events — from validating data before a record saves to triggering external API calls when deals close.
If workflows are the no-code automation layer, Logic Hooks are the code-level automation layer. Together, they make SuiteCRM one of the most extensible CRM platforms available. This guide covers every hook type, the correct file structure, practical examples, and upgrade-safe development practices.
What Are Logic Hooks?
Logic Hooks are PHP functions that execute automatically at specific trigger points in SuiteCRM’s application lifecycle. When a record is saved, deleted, retrieved, or when a relationship changes, SuiteCRM checks for registered Logic Hooks and fires them in the specified order.
Think of them as event listeners: you define which event to listen for (e.g., “before a Lead is saved”) and what action to take (e.g., “validate the phone number format” or “call an external API to enrich the lead data”).
Logic Hooks can do anything PHP can do — query the database, call external APIs, modify record data, create related records, send notifications, write to log files, or trigger third-party services.
The Three Hook Contexts
SuiteCRM Logic Hooks operate in three contexts:
1. Module Hooks
Module Hooks fire on record-level actions for a specific module. These are the most commonly used hooks.
before_save — Fires before a record is saved to the database. Use this to validate data, modify field values, enforce business rules, or cancel the save by throwing an exception. The $bean object contains the record data that’s about to be saved — any changes you make to $bean here will be persisted.
after_save — Fires after a record is successfully saved. Use this to trigger follow-up actions like creating related records, sending notifications, updating external systems, or logging events. Note that some related modules (like email addresses on Company modules) may not be fully persisted when this hook fires.
before_delete — Fires before a record is deleted. Use this to perform cleanup actions, archive data, or prevent deletion by throwing an exception.
after_delete — Fires after a record is deleted. Use this for post-deletion cleanup like notifying external systems or updating related records.
after_retrieve — Fires after a record is loaded from the database (on EditView and DetailView). Use this to modify display data, add computed values, or load additional information from external sources.
process_record — Fires during ListView, SubPanel, Popup, and Dashlet rendering. Use this to modify how records appear in list contexts — adding badges, formatting values, or injecting custom display logic.
before_relationship_add / after_relationship_add — Fire when a relationship between two records is created. Note these may fire twice (once for each side of the relationship). Use for enforcing relationship rules or synchronizing data.
before_relationship_delete / after_relationship_delete — Fire when a relationship is removed. Same dual-firing behavior applies.
before_restore / after_restore — Fire when a deleted record is undeleted (restored from trash).
2. Application Hooks
Application Hooks fire at the global application level, not tied to any specific module.
after_ui_frame — Fires after the UI frame is rendered. after_ui_footer — Fires after the UI footer is rendered. server_round_trip — Fires during a server request-response cycle. after_entry_point — Fires after an entry point is accessed. after_session_start — Fires after a session starts.
Application Hooks are defined in the top-level logic hook file and receive only $event and $arguments parameters — the $bean parameter is not available since these aren’t module-specific.
3. User Hooks
User Hooks fire on authentication events.
after_login — Fires after a successful login. before_logout — Fires before logout. after_logout — Fires after logout. login_failed — Fires on a failed login attempt.
These are useful for custom authentication logging, session management, or security monitoring. User Hooks are also defined in the top-level logic hook file.
File Structure: Where to Put Your Hooks
This is where many developers make mistakes. SuiteCRM has two approaches — the legacy method and the Extension method. Always use the Extension method for upgrade-safe development.
Extension Method (Recommended)
For module hooks, create your hook definition file at:
custom/Extension/modules/{ModuleName}/Ext/LogicHooks/my_hook_name.php
For application and user hooks, create the file at:
_hook_name.php
The file name (e.g., my_hook_name.php) can be anything — it’s part of the Extension framework and gets compiled automatically. This is the upgrade-safe approach because files in custom/Extension/ are never overwritten during SuiteCRM upgrades.
Hook Definition File Structure
The hook definition file registers which event to listen for and which PHP class/method to execute. It follows this format:
The file must contain a $hook_array variable. Each entry in the array specifies: a sort order number (lower numbers execute first), a descriptive label, the path to the PHP file containing your logic, the class name, and the method name to call.
For example, a before_save hook on the Opportunities module would have the hook definition file pointing to a custom PHP class file that contains your business logic.
Logic Class File
The actual PHP class that contains your hook logic lives in:
custom/modules/{ModuleName}/YourClassName.php
The class receives three parameters: $bean (the record being acted on), $event (the hook event name like “before_save”), and $arguments (additional context data depending on the hook type).
Practical Examples
Example 1: Auto-Set Opportunity Stage Based on Amount
A common scenario: automatically change an Opportunity’s sales stage to “Closed Won” when the amount exceeds a threshold.
Create the hook definition at _win_opp.php. This registers a before_save hook that points to your logic class.
Create the logic class at .php. In the method, check if $bean->amount is greater than your threshold (e.g., 50000), and if so, set $bean->sales_stage to “Closed Won”. Because this is a before_save hook, your changes to $bean persist when the record saves.
After creating both files, run Admin → Repair → Quick Repair and Rebuild for SuiteCRM to pick up the new hook.
Example 2: Validate Email Format Before Saving a Lead
Use a before_save hook on the Leads module to validate the email address format before allowing the save. In your logic class, check if the email field matches a valid format using PHP’s filter_var function. If invalid, you can log a warning, correct the data, or throw a SugarApiException to block the save entirely.
Example 3: Create Follow-Up Task After Saving a New Contact
Use an after_save hook on the Contacts module. Check if this is a new record (the $arguments array contains ‘isUpdate’ — if false, it’s a new record). When a new Contact is created, instantiate a Tasks bean, set the subject to “Follow up with {contact name}”, assign it to the record’s assigned user, set a due date 3 days in the future, relate it to the Contact, and save the Task.
Example 4: Notify External API When a Deal Closes
Use an after_save hook on Opportunities to detect when sales_stage changes to “Closed Won”. Check if the stage field actually changed (compare $bean->sales_stage with $bean->fetched_row[‘sales_stage’]). If it changed to “Closed Won”, make an HTTP POST request to your external system (ERP, Slack, billing platform) with the deal details.
This pattern is essential for SuiteCRM integration with external tools — it enables real-time data flow without relying on scheduled batch syncs. See our REST API guide for more on API-based integrations.
Example 5: Prevent Deletion of Accounts with Open Cases
Use a before_delete hook on Accounts. Query the Cases module to check if the Account has any open Cases. If open Cases exist, throw an exception that prevents the deletion and displays a message to the user explaining why the Account can’t be deleted.
Example 6: Log User Login Activity
Use an after_login User Hook to record every successful login — capturing the user ID, timestamp, IP address, and browser information. Write this to a custom audit log table or SuiteCRM’s built-in notes system. This is valuable for security monitoring and compliance in regulated industries like healthcare.
Hook Execution Order
When multiple hooks are registered for the same event, the sort order number (the first element in each hook array entry) determines execution sequence. Lower numbers run first. If two hooks have the same sort order, execution order is unpredictable.
Best practice: use sort order numbers with gaps (10, 20, 30 rather than 1, 2, 3) so you can insert new hooks between existing ones without renumbering.
Common Pitfalls and How to Avoid Them
Infinite loops. An after_save hook that modifies and re-saves the same record will trigger itself again, creating an infinite loop. Always add a check to prevent recursion — use a static flag variable that you set before saving and check at the start of your hook method.
Performance impact. Hooks that make external API calls or heavy database queries slow down the save process for every user. For time-consuming operations, consider using SuiteCRM’s Scheduler (Job Queue) instead — have the hook create a scheduled job that executes asynchronously.
Modifying core files. Never edit files in the modules/ or include/ directories. These are overwritten during upgrades. All custom code belongs in the custom/ directory tree. This is the single most important rule for upgrade-safe development.
Not running Quick Repair. After adding or modifying Logic Hook files, always run Admin → Repair → Quick Repair and Rebuild. SuiteCRM caches hook registrations, and new hooks won’t execute until the cache is rebuilt.
Email addresses in before_save. Email addresses on Company modules (Accounts, Contacts, Leads) are saved after the main bean save completes. If you need to access email addresses in a Logic Hook, use after_save instead of before_save.
Relationship hooks firing twice. The before_relationship_add and after_relationship_add hooks fire once for each side of the relationship. If your logic should only execute once, add a check for the specific module/relationship side you care about.
Logic Hooks vs Workflows: When to Use Which
| Criteria | Workflows (AOW) | Logic Hooks |
| Configuration | Admin UI, no code | PHP code |
| Best for | Standard automation (email, field updates, record creation) | Complex logic, API calls, data validation |
| Trigger timing | On save or scheduled | Any event (save, delete, retrieve, relationship, login) |
| External API calls | Not supported | Fully supported |
| Data validation | Limited | Full control (can block saves) |
| Performance control | Limited | Fine-grained (async via Scheduler) |
| Maintenance | Non-technical admins can modify | Requires developer |
Use workflows for straightforward automation that admins should be able to modify. Use Logic Hooks for complex business logic, external integrations, data validation, and anything that requires programmatic control.
In practice, the most powerful SuiteCRM customizations combine both — workflows handle the standard automation while Logic Hooks manage the edge cases and integrations.
Logic Hooks in SuiteCRM 8
SuiteCRM 8 introduced a modern Angular-based frontend with a Symfony backend, but it still supports legacy Logic Hooks. If you’re developing for SuiteCRM 8, legacy hooks placed in the custom/ directory continue to work. However, SuiteCRM 8 is moving toward a more modern event-driven architecture — check the SuiteCRM documentation for the latest guidance on version 8 development patterns.
For production deployments, TechEsperto recommends using the legacy hook approach until SuiteCRM 8’s new event system is fully stabilized, as community examples and documentation are still limited.
When to Get Professional Help
Logic Hooks are powerful but require PHP expertise and a deep understanding of SuiteCRM’s internal architecture. Common scenarios where professional SuiteCRM development services save time and prevent issues include complex multi-module business logic with conditional branching, real-time integrations with external APIs (ERP, telephony, marketing platforms), data validation rules that span multiple modules and relationships, performance optimization for hooks that execute on high-traffic modules, and migration of custom hooks during SuiteCRM upgrades.
As the Official SuiteCRM Professional Partner, TechEsperto’s developers have built hundreds of Logic Hook implementations across industries.Contact usfor custom development support.
