Perfex CRM Module Development Guide 2026: Save Time & Build Better CRM Modules

This guide shows exactly how to build and integrate Perfex CRM modules with CodeIgniter, covering directory structure, hooks, security best practices, controllers, models, views, and deployment, without guesswork.

Perfex CRM, built on the CodeIgniter PHP framework, supports a modular architecture that allows developers to build custom modules to extend its core functionality. As the official Perfex CRM documentation notes, modules can include controllers, models, views, language files, libraries, hooks, and more.

In this guide, we’ll walk through how to structure, build, and deploy a custom module in Perfex CRM, covering all the major parts: initialization, controllers, models, views, hooks, language files, options, security, and even payment gateway integration.

Kickstart Your Perfex CRM Development Today!

Get your Free Perfex CRM Module Starter Pack — pre-built templates and a checklist to speed up your project.

➤ Get Free Perfex CRM Module Starter Pack

perfex crm module prerequisites & setup

1. Perfex CRM Module Prerequisites & Setup

Before you start:

     

      1. Perfex CRM Version: Make sure you’re using a version that supports modules (module documentation is valid from v2.3.2+).

      1. Enable Development Mode: To catch errors or warnings, turn on development mode in your Perfex CRM instance.

      1. Familiarity with CodeIgniter: Since Perfex is based on CodeIgniter, knowing its MVC structure, how controllers and models work, and how to access the $CI instance is very important.

    2. Module Directory Structure

    Every module lives under the modules/ directory in your Perfex CRM installation. Perfex CRM+1 Here is a typical structure:

    modules/
      my_module/
        my_module.php           // init file
        controllers/
          Admin_my_module.php   // admin controller
          Clients_my_module.php // client area controller (optional)
        models/
          My_module_model.php
        views/
          admin/
            index.php
          public/
            index.php
        libraries/
          My_module_lib.php
        language/
          english/
            my_module_lang.php
        assets/
          css/
          js/
    

       

        • The init file (my_module.php) is mandatory. Its name must match the module folder name.

        • Controllers: separate admin (AdminController) and client (ClientsController) controllers.

        • Models: for database interaction.

        • Views: separate views for admin and client.

        • Libraries: for shared logic or helper classes.

        • Language files: store translatable text.

        • Assets: CSS / JS if your module needs UI.

      3. Perfex CRM Module Init File (Metadata + Hooks)

      The init file is the starting point. It provides the module’s metadata, and where you register activation, deactivation, and uninstall hooks.

      Example modules/my_module/my_module.php :

      <?php
      defined('BASEPATH') or exit('No direct script access allowed');
      
      /*
      Module Name: My Module
      Description: This is a sample custom module for Perfex CRM.
      Version: 1.0.0
      Requires at least: 2.3.*
      Author: Your Name
      */
      
      register_activation_hook('my_module', 'my_module_activate');
      register_deactivation_hook('my_module', 'my_module_deactivate');
      register_uninstall_hook('my_module', 'my_module_uninstall');
      
      function my_module_activate() {
          // Code to run when module is activated
          // e.g., create database tables
      }
      
      function my_module_deactivate() {
          // Code to run when module is deactivated
      }
      
      function my_module_uninstall() {
          // Code to run when module is uninstalled (cleanup)
      }
      
      // Hooks / filters example
      hooks()->add_action('admin_init', 'my_module_admin_init');
      
      function my_module_admin_init() {
          // add menu items or other admin logic
      }
      

      Key points:

         

          • Use unique function prefixes (e.g., my_module_) to avoid collisions.

          • You can register Cron tasks, payment gateways, or language files using helper functions provided by Perfex.

        4. Controllers

        Controllers handle HTTP logic. For modules, you typically create controllers under controllers/.

           

            • AdminController: for staff / admin side.

            • ClientsController: for client portal side.

          Example modules/my_module/controllers/Admin_my_module.php:

          <?php
          defined('BASEPATH') or exit('No direct script access allowed');
          
          class Admin_my_module extends AdminController
          {
              public function __construct()
              {
                  parent::__construct();
              }
          
              public function index()
              {
                  $data['title'] = 'My Module Admin Page';
                  $this->load->view('my_module/admin/index', $data);
              }
          
              public function save_settings()
              {
                  $CI = &get_instance();
                  // Use models or libraries to save module-specific data
                  $this->load->model('my_module/my_module_model');
                  $this->my_module_model->save_settings($CI->input->post());
                  set_alert('success', 'Settings saved.');
                  redirect(admin_url('my_module'));
              }
          }
          

          f you want a client-side controller, you might do:

          <?php
          defined('BASEPATH') or exit('No direct script access allowed');
          
          use app\services\ValidatesContact;
          
          class Clients_my_module extends ClientsController
          {
              use ValidatesContact;
          
              public function dashboard()
              {
                  $data['my_info'] = 'Hello, client!';
                  $this->load->view('my_module/public/index', $data);
              }
          }
          

          Note: If you extend ClientsController, you can use the ValidatesContact trait to ensure only logged-in contacts access controller methods.

          5. Models

          Models live in modules/my_module/models/, and you use them to interact with the database.

          Example My_module_model.php:

          <?php
          defined('BASEPATH') or exit('No direct script access allowed');
          
          class My_module_model extends CI_Model
          {
              public function __construct()
              {
                  parent::__construct();
              }
          
              public function save_settings($data)
              {
                  // For example, store settings in perfex options table
                  foreach ($data as $key => $value) {
                      add_option('my_module_' . $key, $value);
                  }
              }
          
              public function get_settings()
              {
                  $settings = [];
                  $settings['foo'] = get_option('my_module_foo');
                  $settings['bar'] = get_option('my_module_bar');
                  return $settings;
              }
          }
          

          Use Perfex helper functions like add_option(), get_option(), update_option() for storing module settings.

          Prefix your option names (e.g., my_module_foo) to avoid conflicting with Perfex core or other modules.

          Need Help with Perfex CRM Development?

          We offer tailored Perfex CRM module services that cut development time and boost reliability. Let our experts guide your project from start to finish.

          ➤ Book a Free Consultation

           

          6. Views

          Your views folder should contain separate subfolders for admin and public (client side).

          For example:

          modules/my_module/views/
            admin/
              index.php
            public/
              index.php
          

          Admin view (index): modules/my_module/views/admin/index.php:

          <?php defined('BASEPATH') or exit('No direct script access allowed'); ?>
          <div class="panel_s">
            <div class="panel-body">
              <h4><?php echo $title; ?></h4>
              <form action="<?php echo admin_url('my_module/save_settings'); ?>" method="post">
                <div class="form-group">
                  <label for="foo">Foo</label>
                  <input type="text" name="foo" id="foo" value="<?php echo isset($settings['foo']) ? $settings['foo'] : ''; ?>" class="form-control">
                </div>
                <button type="submit" class="btn btn-primary">Save</button>
              </form>
            </div>
          </div>
          

          Public/Client view: modules/my_module/views/public/index.php:

          <?php defined('BASEPATH') or exit('No direct script access allowed'); ?>
          <div class="my-module-client-dashboard">
            <h3>Welcome to My Module</h3>
            <p><?php echo $my_info; ?></p>
          </div>
          

          7. Language Files

          To support translations, create language files under modules/my_module/language/[language]/.

          For example: modules/my_module/language/english/my_module_lang.php

          <?php
          
          # English
          $lang['my_module_title'] = 'My Module';
          $lang['my_module_settings_saved'] = 'Settings have been saved successfully.';
          

          Use your language variables in views and controllers to support internationalization.

          Working With Hooks (Actions & Filters)

          Perfex CRM provides hooks (similar to WordPress-style) that you can use to execute code at various points.

          Some common hook functions:

          hooks()->add_action('hook_name', 'my_function', $priority = 10);
          hooks()->add_filter('filter_name', 'my_filter_function', $priority = 10, $accepted_args = 1);
          hooks()->do_action('hook_name', $params = '');
          hooks()->apply_filters('filter_name', $value, $params = []);
          

          For example, to add a menu item when the admin panel loads:

          hooks()->add_action('admin_init', function() {
              $CI = &get_instance();
              $CI->app_menu->add_sidebar_menu_item('my_module', [
                  'name'     => 'My Module',
                  'collapse' => false,
                  'position' => 20,
                  'href'     => admin_url('my_module'),
                  'icon'     => 'fa fa-puzzle-piece',
              ]);
          });
          

          9. Module Options / Settings

          As mentioned, use add_option(), get_option(), and update_option() to manage settings in the module. These store values in tbloptions table in Perfex database.

             

              • add_option($name, $value, $autoload) — add a new option.

              • get_option($name, $default = null) — retrieve an option.

              • update_option($name, $value) — update or create option if it doesn’t exist (from v2.3.3+).

            10. Security Best Practices

            When developing modules, you must ensure security:

               

                • Validate and sanitize all input data (e.g., from forms).

                • Use CodeIgniter’s built-in CSRF protection. Note: Perfex enables CSRF by default; ensure your forms work with it. Perfex CRM

                • Use defined('BASEPATH') or exit('No direct script access allowed'); at the top of your PHP files to prevent direct access.

                • Use parameterized queries when accessing the database (via CI’s Query Builder) to avoid SQL Injection.

              11. Module Upgrading

              When you release a new version of your module, you can handle upgrades via the init file version header. Perfex CRM compares the version in the init file with what’s already installed.

              In the register_activation_hook, you can include logic to run database migrations or other setup for the new version.

              Example:

              function my_module_activate() {
                  $CI = &get_instance();
                  $CI->db->query("ALTER TABLE `" . db_prefix() . "my_module_table` ADD COLUMN `new_field` VARCHAR(255) NULL;");
              }
              

              12. Payment Gateway Module (Optional)

              If you want to build a custom payment gateway module, Perfex provides support for this.

              Steps:

                 

                  1. Create a folder /modules/my_gateway/libraries/ and a class named e.g. My_gateway_gateway.php. The filename must end with _gateway.php.

                  1. In your init file, register the payment gateway:

                register_payment_gateway('my_gateway', 'my_gateway');

                   

                    • In your gateway library class, define methods like process_payment($data) to handle the payment logic.

                    • Optionally, create a controller under controllers/ for handling redirects or webhook callbacks.

                    • If your gateway needs a webhook callback endpoint, you may need to exclude that URL from CSRF protection (since webhooks might POST data).

                  Example: Full “Simple Module” Walk‑Through

                  Putting it all together, here is a short walkthrough to build a very simple “Hello World” module.

                     

                      1. Create directory: modules/hello_world/

                      1. Init File: hello_world.php:

                    <?php
                    defined('BASEPATH') or exit('No direct script access allowed');
                    
                    /*
                    Module Name: Hello World
                    Description: A simple demo module for Perfex CRM.
                    Version: 1.0.0
                    Requires at least: 2.3.*
                    Author: Your Name
                    */
                    
                    register_activation_hook('hello_world', 'hello_world_activate');
                    register_deactivation_hook('hello_world', 'hello_world_deactivate');
                    
                    function hello_world_activate() {
                      // Module installed / activated
                    }
                    
                    function hello_world_deactivate() {
                      // Module deactivated
                    }
                    
                    hooks()->add_action('admin_init', 'hello_world_add_menu');
                    function hello_world_add_menu() {
                      $CI = &get_instance();
                      $CI->app_menu->add_sidebar_menu_item('hello_world', [
                        'name' => 'Hello World',
                        'href' => admin_url('hello_world'),
                        'position' => 50,
                        'icon' => 'fa fa-smile'
                      ]);
                    }
                    

                    Controller: modules/hello_world/controllers/Admin_hello_world.php:

                    <?php
                    defined('BASEPATH') or exit('No direct script access allowed');
                    
                    class Admin_hello_world extends AdminController
                    {
                      public function index()
                      {
                        $data['title'] = _l('hello_world_title'); // use language
                        $this->load->view('hello_world/admin/index', $data);
                      }
                    }
                    

                    Model: optional, but you could create Hello_world_model if needed.

                    View: modules/hello_world/views/admin/index.php:

                    <?php defined('BASEPATH') or exit('No direct script access allowed'); ?>
                    <div class="panel_s">
                      <div class="panel-body">
                        <h4><?php echo $title; ?></h4>
                        <p>Hello, this is my custom module!</p>
                      </div>
                    </div>
                    

                    Language: modules/hello_world/language/english/hello_world_lang.php:

                    <?php
                    $lang['hello_world_title'] = 'Hello World Module';
                    

                    After you upload this module (zipped) into Setup → Modules in your Perfex admin UI, install and activate it, you should see a new “Hello World” menu item in the sidebar, and clicking it will display the simple page.

                    14. Testing & Debugging

                    Use development mode (enabled earlier) to catch PHP errors & deprecated function warnings.

                    Log via CodeIgniter’s logging (e.g., log_message('debug', 'my_module debug info');) for debugging.

                    Use browser dev tools to debug JS or view assets if your module includes CSS/JS.

                    Check database after activation if you’re creating tables or options, to ensure they exist.

                    15. Best Practices for Module Development

                    Best Practice Description
                    Prefix functions and classes Prevent naming collisions with core or other modules.
                    Security Use CSRF protection, sanitize inputs, prevent direct access.
                    Use hooks Leverage hooks()->add_action and hooks()->add_filter for clean integration.
                    Versioning Use module version in the init file and handle upgrades.
                    Separation of concerns Keep controllers, models, views, and libraries well organized.
                    Internationalization Use language files for UI strings.
                    Maintain compatibility Test module against new versions of Perfex, because major updates may break modules.

                    16. Advanced Use Cases

                    Payment Gateway Module: As covered, create a custom gateway by providing a library and controller.

                    Cron / Scheduled Tasks: You can register cron tasks in the init file to run background jobs.

                    Custom Libraries: Add PHP classes in libraries/ for business logic.

                    Language Packs: Add support for multiple languages by creating additional language subfolders.

                    Module Dependencies: If your module depends on other modules or libraries, check for their existence in activation hook.

                    17. Packaging & Distribution

                    Once your module is ready, zip the module folder.

                    The zip should preserve the structure under modules/my_module/....

                    Install via Perfex CRM Admin → Setup → Modules → Upload Module.

                    After uploading, click Install and then Activate. support.corbitaltech.dev

                    If you’re distributing (e.g., via CodeCanyon), clearly document version, requirements, and update process.

                    18. Troubleshooting Common Issues

                    Problem Possible Cause Solution
                    Module not showing in list Init file name mismatch or header missing Ensure modules/<name>/<name>.php exists, headers are correct.
                    CSRF token errors on form CSRF protection is enabled Use CI form helper, include CSRF token, or adjust CSRF settings.
                    Controller 404 Wrong class name or path Check controller file name, class extends correct base (AdminController or ClientsController).
                    Settings not saving Option keys wrong Use add_option / update_option with correctly prefixed names.
                    Security vulnerability Unsanitized input Validate, sanitize, and escape inputs before database usage.

                    Want to Speed Up Your Perfex CRM Development?

                    Get our Free Perfex CRM Module Template + Checklist — ready to plug into your next project and start building faster, smarter, and error-free.

                    ➤ Download Now

                    Conclusion

                    Developing a custom module in Perfex CRM gives you the flexibility to extend the CRM exactly as your business needs, whether you’re adding a simple admin page, integrating a payment gateway, or building a full client-facing feature. By following the modular structure, using CodeIgniter conventions, and leveraging Perfex’s hooks and helper functions, you can build robust, maintainable, and upgrade-friendly modules.

                    Here’s a quick recap:

                    1. Set up your module directory under modules/.
                    2. Create an init file with metadata and hooks.
                    3. Build controllers, models, views, and optionally libraries & language files.
                    4. Use add_option / get_option for settings.
                    5. Secure your module, handle CSRF, and version your module.
                    6. Package your module as a zip for installation.
                    7. Test thoroughly, especially after Perfex updates.

                    FAQ’s About Perfex CRM Module Development:

                    1. What is a Perfex CRM module?

                    A module is an add-on that extends Perfex CRM with custom features.

                    Yes, Perfex allows full custom module development.

                    It is built with PHP (CodeIgniter framework).

                    Upload the module into the /modules/ directory.

                    Yes, you can create and extend API endpoints.

                    Yes, basic PHP, MVC, and CodeIgniter knowledge is required.

                    Use the main module init file e.g., mymodule.php.

                    Yes, using hooks like admin_init and admin_head.

                    Yes, each module includes activation and deactivation functions.

                    Yes, via the views/admin/ and views/public/ folders.

                    Yes, using migration files or manual schema creation.

                    Use $this->load->model('module_name/module_model');.

                    Yes, through assets and view loading functions.

                    Yes, via language/english/module_lang.php.

                    Enable CodeIgniter debugging or use log_message().

                    Yes, through custom libraries and controllers.

                    Yes, modules can include versioning and update scripts.

                    At the official docs: help.perfexcrm.com.

                    Yes, poorly written code can slow the CRM down.

                    Yes, many developers sell modules on marketplaces like CodeCanyon.

                    Perfex CRM documentation is available on its official website and support portal, covering setup, configuration, and module usage.

                    Perfex CRM module development involves creating custom modules that extend Perfex’s core functionality using its modular architecture, which is built on the CodeIgniter PHP framework. Developers define a module structure (controllers, models, views, language files, and an init file with hooks) to add new features or integrations while staying compatible with Perfex updates.

                    Perfex CRM hooks documentation is available in the official Perfex Help Center under the “Action Hooks” section, which explains how to register and use hooks in custom modules.

                    Hooks in Perfex CRM are extension points that let you run custom code before or after specific system events, so you can change behaviour without modifying core files.

                    You typically use functions like hooks()->add_action() or hooks()->add_filter() inside your module’s init file to attach your callback to a named hook.

                    Yes, developers maintain updated hook lists on GitHub that catalogue most available hooks, which you can use alongside the official documentation to find the right hook name.

                    Using hooks keeps your customisations upgrade-safe, because your logic lives in modules rather than modified core code, reducing breakage when Perfex CRM is updated.

                    Scroll to Top