Skip to content

Extension Structure

Extension Files

The civix command line tool will generate the following structure for you:

  • info.xml is a manifest that describes your extension – the name, license, version number, etc. You should edit most information in this file. The information contained in this file will also be used if published on civicrm.org.
  • myextension.php stores source code for all your hooks. It includes a few default hook implementations which will make development easier. You can add and remove hooks as you wish. (Note: This file name is different in each module – it is based the module's short-name.)
  • myextension.civix.php contains auto-generated helper functions. These deal with common problems like registering your module in the template include-path. civix may automatically overwrite this file, so generally do not edit it.

Extension Directory Structure

Each extension has the one or or more of the following directories. Those are not necessarily needed and most of them are generated when using civix generate:module. These directories are similar to the directory structure of CiviCRM core.

  • Civi// Contains the PSR4 autoloaded classes for the namespace "Civi".
  • CRM/Myextension/ stores PHP class files. Classes in this folder should be prefixed with "CRM_Myextension_".
  • templates/ stores Smarty templates.
  • xml/ stores XML configuration files (such as URL routes and schema xml).
  • build/ stores exportable .zip files.
  • api/ when the extension provides custom api v3 those are stored in this folder.
  • mixin/ contains mixin files generated by Civix.
  • managed/ contains the saved searches from Search Kit.
  • sql/ when your extension provides custom entities or custom database tables this directory contains the SQL file to install and uninstall the extension.
  • ang/ when your extension provides functionality developed in angular this is the place where your angular code is stored
  • form-processors/ when your extension provides form processors this is the directory containing the form processors
  • data-processors/ when your extension provides data processors this is the directory containing the data processors
  • searchactions/ when your extension provides search actions from the search action designer this is the directory containing the search actions.
  • tests/ when your extension provides units tests those are stored in this directory.

When adding files into these directories it is advisable to follow similar patterns to that in CiviCRM Core e.g. BAO files should go in "CRM\Myextension\BAO\", likewise with Form and Page. This ensures that for developers that seek to modify or improve the extension files can be found in standard locations.

Also, if you want the classes in CRM/Myextension/ folder to be autoloaded, make sure to follow PSR0 conventions: i.e. CRM_Myextension_Myfolder_MyClass corresponds to file CRM/Myextension/Myfolder/MyClass.php. If you don't you'll have to manually include/require your class files.

The Big E

There are many times when you need to reference something from the extension -- e.g. its name, its file-path, or its translated messages.

For example, this code displays a translated message (using the translation data for this extension):

if ($welcoming) {
  CRM_Core_Session::setStatus(ts('Hello world!', array(
    'domain' => 'org.civicrm.myextension',
  )));
} else {
  CRM_Core_Session::setStatus(ts('Goodbye cruel world!', array(
    'domain' => 'org.civicrm.myextension',
  )));
}

Repeatedly entering the name of the extension is a bit tiresome.

For code generated by civix v17.08.0+ (or suitably upgraded), civix includes the E helper which provides easier access:

use CRM_Mymodule_ExtensionUtil as E;

if ($welcoming) {
  CRM_Core_Session::setStatus(E::ts('Hello world!'));
} else {
  CRM_Core_Session::setStatus(E::ts('Goodbye cruel world!'));
}

Note that E is an alias. It stands for "extension" -- as in "the current extension that I'm writing". It's a very thin class that provides small helpers for looking up your extension's resources, e.g.

  • E::ts($text) -- Translate a string (using the extensions' translation file)
  • E::path($file) -- Get the path to a resource file (within this extension)
  • E::url($file) -- Get the URL to a resource file (within this extension)
  • E::findClass($suffix) -- Get the full name of a class (within this extension)
  • E::LONG_NAME -- The full length key for this extension (eg org.example.myextension)
  • E::SHORT_NAME -- The abbreviated key for this extension (eg myextension)