Tuesday, September 21, 2010 - 04:33
Written by

As promised previously, here is the first recipe for creating your own CiviCRM extension. We'll start with the easy one - let's create an extension providing a custom search.


First, you obviously need to create your custom search, as described in documentation. Once you have the PHP class and the template, you can start packaging it. Let's say you will be doing an activity search. You need to prepare the info file as per description in previous blog post. Please note some details around info file has changed a bit since it was originally published - that's caused by integrating some of the feedback from blog comments. The info file structure shown that blog post has been updated and reflects the current structure.


Got the info file? Let's start putting the extension package together. Since we chose "org.civicrm.activity" to be the unique identifier of the extension, we need to call the directory that will contain our extension the same way. Once you created it, put info.xml file in it. Remember the "callback" section in info file? We've put "ActivitySearch" value in there. Now it's time to prepare our custom search PHP class to fit in the package. First of all, put it in the file named exactly after the callback value (minus file extension part). So we have second file in our extension directory: ActivitySearch.php. The name of the class that is inside this file should be constructed the following way: "Extension_<Type>_<key>_<callback>" - which means in our case it will be: Extension_Search_org_civicrm_activity_ActivitySearch. It's rather large, but we want to avoid any problems with class name duplication. Please also note, that the extension type is capitalised, but extension key is not.


Ok, we've got the info file, there is a custom search class ready, one last thing is a template. Just create a subdirectory of org.civicrm.activity named templates and put your template file there. It's recommended that you call the template using the name as for your PHP file - so it should be ActivitySearch.tpl.

You should end up with the following structure:


|-- ActivitySearch.php
|-- README.txt
|-- templates
|   `-- ActivitySearch.tpl
`-- info.xml


Let's come back to the PHP class for a minute. There are two small differences between what new extensions framework needs and what old way of doing custom searches require. First one is the name of the class, as described above. Second - when you define which template should be used, you don't have to define whole path - now it's enough to provide the path relative to the extension's templates directory. So the templateFile function, in our case, will look like this:


function templateFile( ) {
 return 'ActivitySearch.tpl';


How about that - you're practically done! Last thing to do is putting yor directory into the zip archive and calling it: Please note that for 3.3, we don't want to impose a hard requirement of having php_zip extension in your PHP installation, even though it seems like most installations have it - so it will be possible to basically put the extension directory on the server. However, handling extensions in archive form is recommended.


Last, but not least - if you would like to help us beta test our extension system and have a custom search that you would like to package, please let me know on Extensions forum board. Coming up next, payment processor packaging.

Filed under


I'm concerned about the proposed standard for no capitalization on the key, as that seems non-standard. I'd prefer more consistency one way or the other with caps or no caps.

Does the extension type need to already exist in core CiviCRM or is it possible to add one that does not exist in core? If so, how?

Why .zip rather than .tgz? Does drush support zip or tgz?

In some cases .tpl files invoke or refer to other tpl files, eg in reports this is quite common. Is there a standard for where to place or how to name other tpls? Is the order of search the extension's templates dir (but it doesn't have the right subdir structure for overriding), then custom_tpl dir, then core templates_c? What is an appropriate way for an extension to override a tpl, eg the statistics template for reports?