Table of Contents

  1. Introduction

  2. What Is a Dolibarr Module?

  3. The Core Architecture of Dolibarr

  4. How Modules Fit Into Dolibarr's Architecture

  5. Directory and File Structure of a Typical Module

  6. The Role of the Module Descriptor

  7. Hooks, Triggers, and Events: Extending Core Functionality

  8. Managing Database Tables in Modules

  9. Creating Interfaces: Pages, Forms, Templates

  10. Integration with Core Features (Menus, Permissions, PDFs)

  11. Best Practices for Customization Without Core Modification

  12. Common Mistakes and How to Avoid Them

  13. Advanced Customization Scenarios

  14. Maintaining Compatibility Across Dolibarr Versions

  15. Conclusion

  16. Developer Resources and References


1. Introduction

Dolibarr ERP & CRM has become a widely adopted open-source business management platform due to its flexibility, scalability, and ease of use. What makes Dolibarr particularly powerful is its modular architecture. This design allows developers and companies to customize and extend the software without altering the core files—ensuring a stable, upgrade-safe environment.

This article provides a deep dive into the architecture of Dolibarr modules, helping developers and IT professionals understand how modules work under the hood. Whether you’re planning to create a new module from scratch or customize existing ones, this guide will give you a detailed understanding of how to do it effectively, professionally, and in line with best practices.


2. What Is a Dolibarr Module?

A module in Dolibarr is a self-contained package that adds new functionality to the ERP system. This could range from:

  • Creating new business objects (e.g., contracts, tickets, certifications)

  • Adding new reports or dashboards

  • Integrating with third-party APIs

  • Modifying existing workflows or user interfaces

Modules allow for both front-end (UI) and back-end (logic, DB) changes while maintaining compatibility with Dolibarr’s upgrade cycle.

Modules can be:

  • Core modules: Shipped with Dolibarr by default

  • Third-party modules: Installed from the Dolistore or custom-developed

  • Custom/private modules: Built for internal use, residing in /htdocs/custom/


3. The Core Architecture of Dolibarr

Dolibarr is built primarily with PHP and runs on a LAMP or LEMP stack. Its architecture is based on:

  • Single-entry architecture: All requests go through main.inc.php

  • MVC-like structure: Loosely modeled with objects, controllers, templates

  • Modular layer: Modules are loaded dynamically and add functionality at runtime

  • Permission-based security model

  • Global configuration via $conf and $user objects

  • Database abstraction layer built on raw SQL with helper functions

Each component of Dolibarr—whether it's invoices, customers, or products—is built using a base object model that can be extended via modules.


4. How Modules Fit Into Dolibarr's Architecture

Modules sit on top of the core application and interact with it via:

  • Event listeners (triggers)

  • Hooks (interface-level plugins)

  • Custom pages and forms

  • Permissions and menu additions

  • Database table extensions

  • REST API endpoints (optional)

When a module is activated, Dolibarr dynamically loads:

  • Its menus

  • Permissions

  • Custom configurations

  • Triggers and hooks

  • Custom objects (classes, templates, forms)

This separation ensures clean modular development and upgrade-safe customization.


5. Directory and File Structure of a Typical Module

Understanding the structure of a module is essential for proper customization.

Here’s a breakdown of a standard module folder located in /htdocs/custom/mymodule/:

python

mymodule/ ├── admin/ # Backend config pages ├── class/ # PHP class files (business logic) ├── core/ │ └── triggers/ # System triggers │ └── modules/ # PDF, numbering modules ├── lang/ # Language translation files ├── page/ # Custom user-facing pages ├── sql/ # Install and upgrade SQL scripts ├── tpl/ # Template files for UI ├── modMyModule.class.php # Module descriptor

Each folder plays a distinct role in enabling functionality while keeping the module organized and maintainable.


6. The Role of the Module Descriptor

At the heart of every Dolibarr module is its descriptor class, typically named modMyModule.class.php.

This file contains:

  • Basic metadata (name, number, version, description)

  • Enable/disable logic

  • Menu definitions

  • Permission declarations

  • Configuration page URLs

  • Database schema definitions

  • Hooks, triggers, and cron jobs

Example snippet:

php

class modMyModule extends DolibarrModules { public function __construct($db) { $this->numero = 104100; // Unique ID $this->rights_class = 'mymodule'; $this->family = "projects"; $this->name = "MyModule"; $this->description = "A module to manage certifications."; $this->version = '1.0.0'; $this->const_name = 'MAIN_MODULE_MyModule'; $this->dirs = array("/mymodule/temp"); $this->config_page_url = array("admin_mymodule.php@mymodule"); $this->menu = array(); // Add menus $this->rights = array(); // Add permissions } }

This file is executed when the module is activated in the admin panel.


7. Hooks, Triggers, and Events: Extending Core Functionality

Dolibarr provides two key mechanisms to extend core functionality without modifying it:

7.1 Triggers

Triggers are event listeners executed during system actions such as:

  • Creating invoices

  • Deleting products

  • Validating orders

Trigger classes are placed in /core/triggers/ and named like interface_99_modMyModule_MyTriggers.class.php.

They implement the DolibarrTriggers interface and a runTrigger() method.

Example:

php

public function runTrigger($action, $object, $user, $langs, $conf) { if ($action == 'BILL_VALIDATE') { // Custom logic when invoice is validated } return 0; }

7.2 Hooks

Hooks inject logic or interface elements into existing Dolibarr pages.

  • UI hooks: Inject buttons, text, or HTML into templates

  • Logic hooks: Extend object creation, deletion, validation logic

Hook classes implement HookInterface and respond to areas like formObjectOptions, doActions, etc.

They are initialized via:

php

$hookmanager->initHooks(array('myarea')); $res = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action);

 

8. Managing Database Tables in Modules

Most modules require their own data structure. Dolibarr allows you to define and manage your own custom database tables in a clean, maintainable way.

8.1 SQL Install and Upgrade Scripts

You define your schema using SQL files placed in /sql/.

Example: /sql/mymodule.sql

sql

CREATE TABLE llx_mymodule_certification ( rowid INT AUTO_INCREMENT PRIMARY KEY, ref VARCHAR(50), label VARCHAR(255), status TINYINT DEFAULT 0, fk_user INT, date_creation DATETIME NOT NULL, tms TIMESTAMP ) ENGINE=InnoDB;

Dolibarr uses the module descriptor to run these scripts during installation.

8.2 Object-Oriented Table Mapping

Custom objects are defined as PHP classes in /class/, typically extending CommonObject.

Example: /class/certification.class.php

php

class Certification extends CommonObject { public $table_element = 'mymodule_certification'; public $element = 'certification'; public $fields = array( 'ref' => array('type' => 'string', 'required' => 1), 'label' => array('type' => 'string'), 'status' => array('type' => 'integer'), ); }

This structure allows Dolibarr to auto-generate forms, lists, and detail views with minimal coding.


9. Creating Interfaces: Pages, Forms, Templates

Modules often include custom pages—either admin pages or business interfaces.

9.1 Page Files

Custom pages are placed in /page/ and follow this structure:

php

require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; require_once '../class/certification.class.php'; llxHeader('', 'My Certifications'); print load_fiche_titre('Certifications Overview'); // Display UI print '<a class="butAction" href="create.php">New Certification</a>'; llxFooter();

9.2 Form Processing

Handle user input using GETPOST() and checkToken():

php

if ($_POST['action'] == 'add' && checkToken()) { $ref = GETPOST('ref', 'alphanohtml'); $label = GETPOST('label', 'alpha'); $cert = new Certification($db); $cert->ref = $ref; $cert->label = $label; $cert->create($user); }

9.3 Templates (TPL)

Templates are stored in /tpl/ and used with include DOL_DOCUMENT_ROOT.'/custom/mymodule/tpl/mypage.tpl.php';.

This separates logic from layout and supports Dolibarr’s HTML structure, classes, and translations.


10. Integration with Core Features (Menus, Permissions, PDFs)

Modules can deeply integrate into Dolibarr’s ecosystem.

10.1 Adding Menus

Defined in the module descriptor using $this->menu[] arrays. Each menu can be top-level, left menu, or submenu.

php

$this->menu[] = array( 'fk_menu'=>'', 'type'=>'top', 'titre'=>'My Module', 'mainmenu'=>'mymodule', 'leftmenu'=>'', 'url'=>'/mymodule/page/index.php', 'langs'=>'mymodule@mymodule', 'position'=>100, 'enabled'=>'1', 'perms'=>'1' );

10.2 Permissions

Define in the module descriptor:

php

$this->rights[] = array( 'id'=>104001, 'desc'=>'Read certifications', 'default'=>1, 'perm'=>'read' );

Access is then validated with:

php

if ($user->rights->mymodule->read) { ... }

10.3 PDF and Numbering Modules

PDF generators and numbering formats can be extended by placing custom classes in /core/modules/.

  • PDF documents: Extend ModelePDFXXX

  • Numbering modules: Extend ModelNumXXX

Declare them in the descriptor so they appear in the config panel.


11. Best Practices for Customization Without Core Modification

To keep Dolibarr maintainable:

  • ✅ Use hooks instead of modifying templates

  • ✅ Use triggers instead of editing object classes

  • ✅ Place your module in /custom/ to avoid overwriting in upgrades

  • ✅ Add version checking in your descriptor

  • ✅ Use language files for all interface strings

  • ✅ Validate all inputs and escape all outputs

  • ✅ Keep business logic in class/, not page/

These habits ensure upgrade compatibility and long-term stability.


12. Common Mistakes and How to Avoid Them

❌ Editing Core Files

Solution: Use overrides, hooks, and extensions.

❌ Using Direct SQL Instead of Object Classes

Solution: Use fetch(), create(), update() methods in your object classes.

❌ Not Managing Permissions

Solution: Always check $user->rights->mymodule->action.

❌ Skipping Input Validation

Solution: Always use GETPOST() and escape SQL inputs.

❌ Hardcoding Paths

Solution: Use DOL_URL_ROOT, dol_buildpath() and constants.


13. Advanced Customization Scenarios

13.1 Multicompany Support

If you're using the MultiCompany module, make sure your module:

  • Uses entity field in all custom tables

  • Respects $conf->entity when querying data

13.2 Scheduled Tasks with Cron Jobs

Add cron jobs to perform background tasks:

php

$this->cronjobs[] = array( 'label'=>'Sync Certifications', 'jobtype'=>'method', 'class'=>'CertificationSync', 'method'=>'run', 'parameters'=>'', 'comment'=>'Runs nightly' );

13.3 Custom REST Endpoints

Create custom APIs by placing scripts in /custom/mymodule/script/api_*.php and registering them in your module descriptor.


14. Maintaining Compatibility Across Dolibarr Versions

  • Test your module with each Dolibarr release

  • Use dol_version_compare() to handle version differences

  • Avoid using deprecated functions or global variables

  • Keep a changelog (changelog.txt) and maintain semantic versioning


15. Conclusion

Understanding the architecture of Dolibarr modules is essential for creating powerful, reliable, and upgrade-safe customizations. Whether you're building internal tools or commercial add-ons, mastering the following elements will help:

  • Module structure and descriptor files

  • Hooks, triggers, and permissions

  • Custom object classes and database schema

  • Admin panels and user interfaces

  • Integration with PDF generation, cron jobs, and APIs

Dolibarr was designed to be extended. The better you understand its architecture, the more value you can deliver with your custom modules—without ever touching the core codebase.


16. Developer Resources and References