Table of Contents

  1. Introduction

  2. Understanding the Dolibarr Architecture

  3. Why Develop Custom Modules?

  4. Preparing Your Development Environment

  5. Anatomy of a Dolibarr Module

    • 5.1 The Module Descriptor (modMyModule.class.php)

    • 5.2 Directory Structure

    • 5.3 Hooks, Triggers, and Permissions

  6. Creating Your First Module Step-by-Step

    • 6.1 Naming and Initialization

    • 6.2 Adding Menus and Permissions

    • 6.3 Creating Database Tables

    • 6.4 Building Pages and Interfaces

    • 6.5 Handling Forms and Actions

  7. Understanding Dolibarr Hooks and Triggers

  8. Best Practices for Module Development

  9. Packaging and Distributing Your Module

  10. Using the Dolibarr API in Your Modules

  11. Debugging, Logging, and Maintenance

  12. Common Pitfalls to Avoid

  13. Advanced Use Cases and Ideas

  14. Conclusion

  15. Resources for Developers


1. Introduction

Dolibarr ERP & CRM has grown into a widely adopted open-source solution for managing business processes, thanks to its modular structure and developer-friendly ecosystem. One of its biggest advantages is that developers can extend its functionality through custom modules—without modifying the core.

Whether you're building features for internal use, client projects, or commercial distribution, understanding how to create your own Dolibarr module opens up endless possibilities. This guide is written specifically for developers, and it dives deep into the structure, best practices, and real-world implementation of custom modules for Dolibarr.

From creating a simple “Hello World” module to more advanced features like custom permissions, REST API endpoints, and dynamic menus—this guide will walk you through the entire process.


2. Understanding the Dolibarr Architecture

Before writing your first line of code, it’s important to understand how Dolibarr works under the hood. Dolibarr is written in PHP, and it follows a modular architecture where:

  • Each module is contained in its own directory inside /htdocs/custom/ or /htdocs/module_name/.

  • Modules are loaded at runtime, based on the activation status in the back office.

  • It uses a single-entry-point structure, where all URLs run through main.inc.php for initialization.

  • The database is managed using Dolibarr's built-in ORM functions like dol_sql_insert, dol_sql_update, etc.

  • User access is managed via a granular permission system using the user->rights object.

Modules can hook into existing core functionality, add their own menus, use templates, or create custom business logic.


3. Why Develop Custom Modules?

There are several reasons to create your own Dolibarr module:

  • Tailored Features: Implement specific features for unique workflows.

  • Improve Efficiency: Automate tasks and simplify interfaces for end-users.

  • Data Integrations: Build bridges with external APIs, accounting tools, or custom dashboards.

  • Resell or Distribute: Publish on Dolistore or GitHub for others to use.

  • Maintain Upgradeability: Avoid modifying the core, ensuring future Dolibarr upgrades are smooth.

Instead of hacking around the source code (which breaks compatibility and maintainability), modules let you extend Dolibarr the right way.


4. Preparing Your Development Environment

Before starting, make sure you have a working development setup.

4.1 Required Tools

  • PHP 7.4–8.x (depending on your Dolibarr version)

  • MySQL or MariaDB

  • Apache or NGINX

  • A local development environment (XAMPP, WAMP, MAMP, Docker, etc.)

  • Git (recommended for version control)

You’ll also want a good code editor or IDE such as VS Code, PhpStorm, or Sublime Text.

4.2 Recommended Setup

  • Clone the latest stable Dolibarr version from GitHub.

  • Create a virtual host pointing to /htdocs.

  • Store your module in the /htdocs/custom/ directory to separate it from core modules.

  • Enable error reporting in your php.ini or use dolibarr_dev constants for debugging.

4.3 Dolibarr Developer Tools

Install or enable:

  • Module Builder: A helper module that scaffolds the basic structure of a new module.

  • Developer Tools Module: Offers insights into variables, hooks, and page internals.

  • Web Profiler Module (optional): For performance benchmarking.


5. Anatomy of a Dolibarr Module

Understanding the structure of a module is critical. At a minimum, a Dolibarr module consists of:

  • A module descriptor file: Defines metadata and activation logic.

  • A directory with subfolders for pages, classes, templates, and SQL.

  • Optional hooks, triggers, and language files.


5.1 The Module Descriptor (modMyModule.class.php)

Every module starts with a descriptor class. Here's a minimal example:

php

class modMyModule extends DolibarrModules { function __construct($db) { $this->numero = 104000; // Must be unique $this->rights_class = 'mymodule'; $this->family = "crm"; $this->name = "MyModule"; $this->description = "A custom module for internal use"; $this->version = '1.0'; $this->const_name = 'MAIN_MODULE_MyModule'; $this->dirs = array("/mymodule/temp"); $this->config_page_url = array("admin_mymodule.php@mymodule"); $this->menu = array(); $this->rights = array(); } }

This file tells Dolibarr how to install, enable, and identify your module.


5.2 Directory Structure

Here’s a basic folder structure of a typical module:

bash

htdocs/custom/mymodule/ ├── class/ # PHP logic (objects, controllers) ├── core/modules/ # Custom PDF or numbering classes ├── lang/ # Language files ├── page/ # Custom pages and interfaces ├── sql/ # Install/upgrade SQL scripts ├── admin/ # Configuration pages ├── modMyModule.class.php # Main descriptor

You can add folders for js, css, tpl (template), and lib as needed.

 

6. Creating Your First Module Step-by-Step

This section walks you through creating a functional custom module from scratch. The goal is to give you a practical roadmap that you can adapt for your own needs.


6.1 Naming and Initialization

Every module must have a unique name and module number. Follow naming conventions to prevent conflicts:

  • Use CamelCase for class and module names (e.g., modMyCustomModule)

  • File structure must reflect naming (e.g., modMyCustomModule.class.php inside the root directory)

  • Choose a unique numero (e.g., 104001) not already used by other modules

Activate your module from Home > Setup > Modules/Applications after placing it in /htdocs/custom/.


6.2 Adding Menus and Permissions

Dolibarr menus are added in the descriptor using the $this->menu[] array. Here's an example of a top-level and sub-menu:

php

$this->menu[] = array( 'fk_menu'=>'', // No parent menu 'type'=>'top', 'titre'=>'MyModuleMenu', 'mainmenu'=>'mymodule', 'leftmenu'=>'', 'url'=>'/mymodule/page/dashboard.php', 'langs'=>'mymodule@mymodule', 'position'=>100, 'enabled'=>'1', 'perms'=>'1', 'target'=>'', 'user'=>2 ); $this->menu[] = array( 'fk_menu'=>'mymodule', 'type'=>'left', 'titre'=>'ListItems', 'mainmenu'=>'mymodule', 'leftmenu'=>'mymodule_left', 'url'=>'/mymodule/page/list.php', 'langs'=>'mymodule@mymodule', 'position'=>101, 'enabled'=>'1', 'perms'=>'$user->rights->mymodule->read', 'target'=>'', 'user'=>2 );

Define permissions in the same file under $this->rights[]:

php

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

6.3 Creating Database Tables

Database schema is initialized through SQL scripts placed in /sql/.

Install SQL file: mymodule.sql

sql

CREATE TABLE llx_mymodule_item ( rowid INT AUTO_INCREMENT PRIMARY KEY, ref VARCHAR(128), label VARCHAR(255), date_creation DATETIME, tms TIMESTAMP );

Reference it in your descriptor:

php

$this->module_parts = array('db'=>1); $this->sql = array('/mymodule/sql/mymodule.sql');

Dolibarr will auto-run this script when installing your module.

To update your schema in later versions, add upgrade SQL files:

sql

/sql/mymodule_1.1.sql /sql/mymodule_1.2.sql

6.4 Building Pages and Interfaces

Create a folder /page/ and add your first interface, e.g., dashboard.php.

php

require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; llxHeader('', 'My Module Dashboard'); print load_fiche_titre('Dashboard'); print '<div class="fichecenter">'; print '<p>This is your module landing page.</p>'; print '</div>'; llxFooter();

Use Dolibarr’s UI helpers like:

  • print load_fiche_titre()

  • dol_print_date()

  • dol_buildpath()

  • dol_escape_htmltag()

Dolibarr offers form helpers and object view rendering tools to maintain consistency with the UI.


6.5 Handling Forms and Actions

For pages that modify or save data, Dolibarr uses a common controller structure.

In your form-handling page:

php

if ($_POST['action'] == 'add') { $ref = GETPOST('ref', 'alpha'); $label = GETPOST('label', 'alpha'); $sql = "INSERT INTO llx_mymodule_item (ref, label, date_creation) VALUES ('".$db->escape($ref)."', '".$db->escape($label)."', NOW())"; $res = $db->query($sql); if ($res) { setEventMessages('Item created successfully', null, 'mesgs'); } else { setEventMessages($db->lasterror(), null, 'errors'); } }

Use Dolibarr's GETPOST() and $db->escape() to prevent injection vulnerabilities.


7. Understanding Dolibarr Hooks and Triggers

Dolibarr allows you to extend core actions using:

  • Triggers (triggerInterface)

  • Hooks (hookmanager)

7.1 Using Triggers

Triggers are fired on system events like:

  • BILL_CREATE

  • ORDER_VALIDATE

  • PRODUCT_DELETE

Create a file /core/triggers/interface_99_modMyModule_MyTriggers.class.php

Example:

php

public function runTrigger($action, $object, $user, $langs, $conf) { if ($action == 'BILL_VALIDATE') { dol_syslog("My trigger executed on invoice validation"); } return 0; }

7.2 Using Hooks

Hooks let you inject content into existing pages or interfaces.

Example usage in your page:

php

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

This allows your module to plug into events fired from Dolibarr core or other modules.

 

8. Best Practices for Module Development

Developing a Dolibarr module is not just about writing functional code—it’s about writing clean, maintainable, and secure code that follows Dolibarr’s conventions.

8.1 Follow Naming Conventions

  • Use lowercase for folders, uppercase for class files.

  • Prefix your tables with llx_ and a unique module identifier.

  • Avoid naming conflicts with existing modules or core features.

8.2 Keep Logic and Presentation Separate

Use:

  • .php files in /page/ for interfaces

  • Classes in /class/ for business logic

  • Templates in /tpl/ for layout

Following the MVC principle makes your module easier to debug and scale.

8.3 Use Permissions Carefully

Do not hardcode access logic. Always check:

php

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

Provide fine-grained permissions for:

  • Reading

  • Writing

  • Deleting

  • Validating

This ensures compatibility with Dolibarr’s user/role architecture.

8.4 Secure Your SQL and Input Handling

  • Use GETPOST() with appropriate type filters.

  • Sanitize all output using dol_escape_htmltag() or dol_htmlentities().

  • Use $db->escape() for SQL values.

  • Avoid using raw $_POST, $_GET, or unescaped values.

8.5 Document Your Code

  • Include PHPDoc headers in classes and functions.

  • Comment all SQL queries and business rules.

  • Include a README.md in your module folder.


9. Packaging and Distributing Your Module

Once your module is tested and ready, you can package and share it with others.

9.1 Required Files for Distribution

Include:

  • modMyModule.class.php

  • SQL scripts (install and upgrade)

  • A README.md file with instructions

  • Language files in /lang/

  • Optionally: logo, screenshots, license, and version changelog

9.2 Distributing on Dolistore

Dolistore is the official marketplace for Dolibarr modules.

To submit your module:

  1. Create a .zip file of your module folder

  2. Ensure it follows Dolibarr’s publishing standards

  3. Provide documentation, compatibility version, and contact information

  4. Choose a license (GNU GPL v3 preferred)

  5. Submit via the Dolistore vendor interface

Modules can be distributed for free or commercially with licensing control.


10. Using the Dolibarr API in Your Modules

Dolibarr includes a REST API that allows external tools and internal modules to interact programmatically.

10.1 Enable the API

Go to:
Home > Setup > Modules > Web Services (API) and activate the module.

10.2 Authentication Methods

  • API keys (defined per user)

  • OAuth 2.0 (advanced use)

  • Ensure all requests use https://yourdomain.com/api/index.php/

10.3 Example API Usage

Fetching all third parties:

bash

curl -X GET https://yourdomain.com/api/index.php/thirdparties \ -H "DOLAPIKEY: your_api_key"

10.4 Using the API in Your Module

You can also consume external APIs inside your module:

php

$client = curl_init('https://api.external.com/orders'); curl_setopt($client, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($client); curl_close($client); $data = json_decode($response, true);

Use APIs to sync data with:

  • E-commerce platforms (WooCommerce, PrestaShop)

  • Accounting tools (Xero, QuickBooks)

  • Email platforms (SendGrid, Mailchimp)


11. Debugging, Logging, and Maintenance

Effective debugging helps ensure your module is stable and production-ready.

11.1 Error Handling

Use Dolibarr's built-in error functions:

php

$this->errors[] = "Something went wrong"; setEventMessages($this->error, $this->errors, 'errors');

Log custom actions with:

php

dol_syslog("MyModule: Action X executed", LOG_DEBUG);

Enable logs in conf.php:

php

$conf->global->MAIN_LOGTOHTML = 1;

11.2 Development Constants

Use these to expose errors:

php

define('DOLIBARR_DEV', true); define('DOL_SHOW_GLOBALS', true); define('MAIN_DISABLE_ALL_CACHE', 1);

Always turn these off in production.


12. Common Pitfalls to Avoid

  • Modifying core files – Always use modules, hooks, and overrides.

  • Skipping permissions – This can expose sensitive data.

  • Ignoring version compatibility – Test your module across supported Dolibarr versions.

  • Hardcoding paths or URLs – Use DOL_URL_ROOT and dol_buildpath().

  • Poor SQL design – Use indexes, follow naming conventions, and avoid large JOINs without need.


13. Advanced Use Cases and Ideas

Once you're comfortable with basic modules, explore these advanced ideas:

13.1 Custom PDF Generators

Create custom documents (quotes, invoices, labels) by extending /core/modules/pdf/.

Define your own class like:

php

class pdf_mymodule extends ModelePDFXXX

13.2 Custom Numbering Models

Add personalized invoice or order numbering formats using the /core/modules/xxx/ folder.

13.3 Scheduled Tasks

Use cron module to automate processes (e.g., daily backups, email alerts, batch reports).

Register tasks via:

php

$this->cronjobs[] = array( 'label'=>'Daily Sync', 'jobtype'=>'method', 'class'=>'MyClass', 'method'=>'runDaily', 'parameters'=>'', 'comment'=>'Sync with external tool' );

14. Conclusion

Creating your own Dolibarr module opens the door to deep customization and powerful automation tailored to your business or your clients. The modular structure of Dolibarr ensures you can build:

  • Custom interfaces

  • Data entry tools

  • Workflow automation

  • REST-integrated solutions

  • Dynamic PDF generators

  • Full enterprise features—without touching core files

With best practices, security, and maintainability in mind, you’ll be able to design professional-grade modules that scale with Dolibarr and offer real-world value.


15. Resources for Developers