Skip to content
Snippets Groups Projects
Commit 983ab5da authored by mickadoo's avatar mickadoo
Browse files

remove hookref-old.md and move all content into relevant files. Add wordpress...

remove hookref-old.md and move all content into relevant files. Add wordpress setup information for hooks.
parent 42413589
No related branches found
No related tags found
No related merge requests found
......@@ -323,10 +323,53 @@ then:
3. Added logic in the upgrader to create the relationship type
4. Added logic in the upgrader to evaluate the Smarty template
#### Accessing Custom Fields
For setting and getting custom field values in hooks, you need to know the field
ID of the custom field(s) you want to work with. You'll then access these
fields as "custom_<ID>". So if you have a field holding a custom value whose
ID in the civicrm_custom_field table is 34, you'll use "custom_34" to access it.
To get a custom field ID given the custom field name and custom group name,
you can use the following code:
```php
require_once 'CRM/Core/BAO/CustomField.php';
$customFieldID = CRM_Core_BAO_CustomField::getCustomFieldID($field, $group);
```
Once you have the ID(s), you'll want to use the setValues and getValues
functions in the CRM/Core/BAO/CustomValueTable.php file. Here are a couple
of examples of their use:
Setting values:
```php
require_once 'CRM/Core/BAO/CustomValueTable.php';
$params = array('entityID' => $contribution_id, 'custom_34' => 'new val');
CRM_Core_BAO_CustomValueTable::setValues($params);
```
Getting values:
```php
$params = array( 'entityID' => 1327, 'custom_13' => 1, 'custom_43' => 1);
require_once 'CRM/Core/BAO/CustomValueTable.php';
$values = CRM_Core_BAO_CustomValueTable::getValues($params);
```
!!! caution
Note that custom field values may not always be available when you
might expect.
For instance, you can't retrieve custom field values in the 'create'
operation in the _pre and _post hooks, because the custom field values
haven't been stored yet. However, you can retrieve values in the 'edit'
operation.
### Add a hook function
CiviCRM
[hook functions](http://wiki.civicrm.org/confluence/display/CRMDOC/Hook+Reference)
[hook functions](/hooks/)
allow extensions to run extra logic as
part of the normal CiviCRM processing. For example,
`hook_civicrm_buildForm()` allows a module to run logic whenever a
......
## Goals and background
- This documents how to extend CiviCRM to meet your needs. CiviCRM
uses hooks in a very similar manner to Drupal, primarily because
(based on our experience with Drupal's extension architecture) we
think it is clean and non-intrusive, yet incredibly powerful. For a
simple example module check [civitest
module](http://svn.civicrm.org/trunk/drupal/civitest.module.sample)
- See Drupal [hook documentation](http://drupal.org/node/292) for a
description of how hooks are implemented.
- See [CRM/Utils/Hook.php](http://svn.civicrm.org/civicrm/trunk/CRM/Utils/Hook.php)
in CiviCRM for the source code that invokes these hooks.
## Implementing hooks
- In Drupal or CiviCRM, hooks can be implemented within a module or
extension. In general, implement a hook by declaring a global
function that starts with the name of your module and ends with the
name of the hook.
In Drupal module or a CiviCRM extension for example: to implement hook\_civicrm\_buildForm from within the "my\_custom" module/extension you would add the following function to your main .php or .module file (or a file always included by that script):
````
function my_custom_civicrm_buildForm($formName, &$form) {
// since the $form object was passed by reference, modifying it here will change it permanently
$form->assign('intro_text', ts('hello world'));
}
````
As long as the module/extension is enabled, this function will be called every time CiviCRM builds a form.
In WordPress, hooks can be implemented in a variety of ways. You can write a plugin or include them in your theme's 'functions.php' file - where you place them depends largely on whether they are theme-dependent or theme-independent. The general rule for targeting the hook is to remove the 'hook\_' prefix when you create the filter or action, but see the "For a WordPress Plugin" section below for more details.
The following code block shows the simplest form of a hook implementation in WordPress. In this case, the code receives callbacks from 'hook\_civicrm\_pre':
```
// hook into civicrm_pre
add_filter( 'civicrm_pre', 'my_plugin_pre_callback', 10, 4 );
function my_plugin_pre_callback( $op, $objectName, $objectId, &$objectRef ) {
// your code here
}
```
As long as the plugin is active (or - if the code is in 'functions.php' - as long as your theme is active), this function will be called every time CiviCRM is about to save data to the database.
## For A CiviCRM (native) Extension
- See this page for [creating an extension and implementing hooks
within it](https://wiki.civicrm.org/confluence/display/CRMDOC/Create+a+Module+Extension).
## For A Drupal Module
- See this page for [creating a module in Drupal](http://drupal.org/node/1074360) esp. the section on implementing hooks.
- For a working example, see the hook\_civicrm\_postProcess documentation below.
- You can also find examples in your CiviCRM install in [drupal/civitest.module.sample](http://svn.civicrm.org/civicrm/trunk/drupal/civitest.module.sample)
## For a Joomla Plugin
- See this page for [creating a Joomla plugin](http://docs.joomla.org/Plugin). Joomla plugins implement the
observer design pattern.
- Hook plugins should be placed in the civicrm plugin group in a subfolder with the same name as the plugin.
- Once created plugins may be packaged and installed with the Joomla installer or the files can be placed in the appropriate folder and installed with the discover method.
- See this [sample Joomla plugin for CiviCRM hooks](https://wiki.civicrm.org/confluence/display/CRMDOC/Example+Joomla+Plugin+for+implementing+hooks)
## For a WordPress Plugin
- For a detailed overview of the updated relationship between WordPress and CiviCRM, see the blog post [Working with CiviCRM 4.6 in WordPress](https://civicrm.org/blogs/haystack/working-civicrm-46-wordpress) on the CiviCRM website.
- In summary, as of CiviCRM 4.6 there is (almost) full compatibility with the WordPress actions and filters system.
- Any PHP file that will be included by WordPress can be used to contain your hook implementations. Use an in-house plugin, your site's 'functions.php' file, or place a file named 'civicrmHooks.php' in your CiviCRM custom php path (as specified in
Administer -\> System Settings -\> Directories -\> Custom PHP Path Directory).
- Prior to CiviCRM 4.6, hooks had to use the prefix "wordpress\_" as
the replacement for the "hook\_" part of the hook name. So to implement 'hook\_civicrm\_pre' you had to write:
```
function wordpress_civicrm_pre($op, objectName, $objectId, &$objectRef)
```
This method still works, so if you have legacy modifications, they will not break.
- As of CiviCRM 4.6, the general rule for targeting the hook is to remove the 'hook\_' prefix when you create the filter or action. So, if your plugin or theme wants to receive callbacks from 'hook\_civicrm\_pre', the filter should be written as
```
add_filter('civicrm_pre', 'my_callback_function', 10, 4 )
```
or if your callback method is declared in a class, the filter should be written as
```
add_filter( 'civicrm_pre', array( $this, 'my_callback_method', 10, 4 )
```
For more details (as well as the exceptions to this rule) see the [blog post](https://civicrm.org/blogs/haystack/working-civicrm-46-wordpress) mentioned above.
## Inspecting hooks
The documentation about hooks can be somewhat abstract, and it sometimes
helps to see interactively how the hooks run.
- If you use Drupal, then you can inspect some hooks by installing
these two Drupal modules:
- [devel](http://drupal.org/project/devel)
- [civicrm\_developer](https://github.com/eileenmcnaughton/civicrm_developer)
- If you use WordPress, you can inspect hooks by installing the following plugin:
- [Query Monitor](https://wordpress.org/plugins/query-monitor/)
## Example Drupal module for implementing hooks
I found it useful, when implementing hooks, to write wrapper code for most of them. The [attached zip](http://wiki.civicrm.org/confluence/download/attachments/86213379/callhooks.zip?version=1&modificationDate=1372586243000&api=v2) file is an example Drupal module that illustrates this technique. From the README file:
This is just example code to implement custom hooks for CiviCRM.
Each custom hook defined by CiviCRM is implemented here.
To use:
1. Install this module or incorporate its code into your own custom module.
2. Uncomment some/all the watchdog lines.
3. Visit the page you need to modify via a CiviCRM custom hook.
4. Re-comment the watchdog lines.
5. Visit admin/reports/dblog and look at the comments there.
6. Write a function as described by one of the comments.
## Example Joomla Plugin for implementing hooks
This is a simple example of a plugin for Joomla that implements CiviCRM hooks. It consists of two file tabs.php and tabs.xml along with the blank index.html file which is considered good Joomla coding practice.
Note: Somewhere around Joomla 2.5.20 the JPlugin class was moved to cms.plugin.plugin from joomla.plugin.plugin (see the jimport call in Tab.php below). If you have not remained current with the latest Joomla revision, you may need to reference the correct location. If you find your plugins fail after updating to the latest release, be sure to check and fix that reference (it will often fail silently).
Tabs.php
```
<?php
/**
* @version
* @package Civicrm
* @subpackage Joomla Plugin
* @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
// No direct access
defined('_JEXEC') or die;
jimport('cms.plugin.plugin');
class plgCivicrmTabs extends JPlugin
{
/**
* Example Civicrm Plugin
*
* @package Civicrm
* @subpackage Joomla plugins
* @since 1.5
*/
public function civicrm_tabs(&$tabs, $contactID)
{
// unset the contribition tab, i.e. remove it from the page
unset( $tabs[1] );
// let's add a new "contribution" tab with a different name and put it last
// this is just a demo, in the real world, you would create a url which would
// return an html snippet etc.
$url = CRM_Utils_System::url( 'civicrm/contact/view/contribution',
"reset=1&snippet=1&force=1&cid=$contactID" );
$tabs[] = array( 'id' => 'mySupercoolTab',
'url' => $url,
'title' => 'Contribution Tab Renamed',
'weight' => 300 );
}
}
```
Tabs.xml
```
<?xml version="1.0" encoding="UTF-8"?>
<extension version="1.6" type="plugin" group="civicrm">
<name>plg_civcrm_tabs</name>
<author>Joomla! Project</author>
<creationDate>November 2005</creationDate>
<copyright>Copyright (C) 2005 - 2011 Open Source Matters. All rights reserved.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>1.6.0</version>
<description>PLG_CIVICRM_TABS_XML_DESCRIPTION</description>
<files>
<filename plugin="tabs">tabs.php</filename>
<filename>index.html</filename>
</files>
<config>
</config>
</extension>
```
You can make plugins that include multiple hooks or you can make separate plugins. What is appropriate will depend on the application.
## Setting and getting custom field values from within hooks
To get a custom field ID given the custom field name and custom group name, you can use the following code:
```
require_once 'CRM/Core/BAO/CustomField.php';
$customFieldID = CRM_Core_BAO_CustomField::getCustomFieldID( $fieldLabel, $groupTitle );
```
For setting and getting custom field values in hooks, you need to know the field ID of the custom field(s) you want to work with. The easiest place to find these IDs is in the civicrm_custom_field table in the database. You'll then access these fields as "custom_ID". So if you have a field holding a custom value whose ID in the civicrm_custom_field table is 34, you'll use "custom_34" to access it.
Once you have the ID(s), you'll want to use the setValues and getValues functions in the CRM/Core/BAO/CustomValueTable.php file. Here are a couple of examples of their use:
Setting values (on a Contribution object's custom fields):
```
$custom_fields = array('foo' => 'custom_1', 'bar' => 'custom_2');
function modulename_civicrm_pre ($op, objectName, $objectId, &$objectRef) {
if ($objectName != 'Contribution' || ($op != 'edit' && $op != 'create')) {
return;
}
$contribution_id = $objectId;
require_once 'CRM/Core/BAO/CustomValueTable.php';
$my_foo = 'blah';
$my_bar = 'baz';
$set_params = array('entityID' => $contribution_id,
$custom_fields['foo'] => $my_foo, $custom_fields['bar'] => $my_bar);
CRM_Core_BAO_CustomValueTable::setValues($set_params);
}
```
Getting values (from a Contribution's associated Contact object):
```
$custom_fields = array('contact_foo' => 'custom_3', 'contact_bar' => 'custom_4');
function modulename_civicrm_pre ($op, objectName, $objectId, &$objectRef) {
if ($objectName != 'Contribution' || ($op != 'edit' && $op != 'create')) {
return;
}
// set the field names to 1 that we want to get back
$get_params = array('entityID' => $objectRef['contact_id'],
$custom_fields['contact_foo'] => 1, $custom_fields['contact_bar'] => 1);
require_once 'CRM/Core/BAO/CustomValueTable.php';
$values = CRM_Core_BAO_CustomValueTable::getValues($get_params);
$my_cfoo = $values[$custom_fields['contact_foo']];
$my_cbar = $values[$custom_fields['contact_bar']];
}
```
Note that custom field values may not always be available when you might expect. For instance, you can't retrieve custom field values in the 'create' operation in the _pre and _post hooks, because the custom field values haven't been stored yet. However, you can retrieve values in the 'edit' operation.
\ No newline at end of file
......@@ -90,6 +90,22 @@ A good debugger is indispensable here. See the
certain hooks. Keep this in mind when upgrading, and make sure you
check the release notes before upgrading.
## Organizing Your Hooks
You may find that some of your hooks target a lot of different cases. Such
hooks can quickly get out of control, and maintaining them can be a nightmare.
You might find it helpful when implementing a hook to delegate certain
operations to different functions instead of lumping it all in together in
the main hook.
If you're using [Civix](/extensions/civix/) to create your extension it will
automatically generate wrapper code for your hook.
For more information you can checkout the README in this
[zip file][wrapper-zip] for setting up an example Drupal module that
illustrates this technique.
## Examples of using hooks
In all of these examples, you'll put the code we provide into your
......@@ -102,6 +118,24 @@ you're using Drupal for the rest of the example. But don't worry Joomla! users,
the concept is the same and just requires some tweaks to get it working. Have a
look at the [Joomla help][joomla] for more instructions.
### Setting Text on a Form
To implement `hook_civicrm_buildForm` from within the "myextension" extension
you would add the following function to your main .php or .module file (or a
file always included by that script):
```php
<?php
function myextension_civicrm_buildForm($formName, &$form) {
// note that form was passed by reference
$form->assign('intro_text', ts('hello world'));
}
```
As long as the extension is enabled, this function will be called every time
CiviCRM builds a form.
### Sending an Email Message When an Individuals Was Edited
In order to have CiviCRM tell you when an Individual was edited, define the
......@@ -220,4 +254,5 @@ function myextension_civicrm_tokenValues(&$details, $contactIDs, $jobID, $tokens
```
[drupal]: hooks/setup/drupal
[joomla]: hooks/setup/joomla
\ No newline at end of file
[joomla]: hooks/setup/joomla
[wrapper-zip]: http://wiki.civicrm.org/confluence/download/attachments/86213379/callhooks.zip?version=1&modificationDate=1372586243000&api=v2
\ No newline at end of file
## Using hooks with Drupal
The Drupal documentation has good information about
[hooks in general](https://www.drupal.org/docs/7/creating-custom-modules/understanding-the-hook-system-for-drupal-modules)
and [configuration to enable hooks for your module](https://www.drupal.org/docs/7/creating-custom-modules/telling-drupal-about-your-module)
The Drupal documentation has great information about
[hooks in general][drupal-hooks],
[configuration to enable hooks for your module][hooks-config],
and [this guide][hooks-intro] on starting out with hooks.
In order to start using hooks with a Drupal-based CiviCRM installation, you or
your administrator needs to do the following:
......@@ -32,23 +31,16 @@ Additionally, if you are using Drupal and add a new hook to an existing module,
you will need to clear the cache for the hook to start operating. One way of
doing this is by visiting the page Admin > Build > Modules.
Note that if you use certain Drupal functions from within CiviCRM, you could
break whatever form you're working with! To prevent very hard-to-troubleshoot
errors, do the following (at least for `user_save()` with Drupal 6, possibly
others):
```php
$config = CRM_Core_Config::singleton();
```
## Inspecting Hooks
```php
$config->inCiviCRM = TRUE;
```
The documentation about hooks can be somewhat abstract, and it sometimes
helps to see interactively how the hooks run.
```php
$user = user_save('',array(..));
```
- If you use Drupal, then you can inspect some hooks by installing
these two Drupal modules:
- [devel](http://drupal.org/project/devel)
- [civicrm\_developer](https://github.com/eileenmcnaughton/civicrm_developer)
```php
$config->inCiviCRM = FALSE;
```
\ No newline at end of file
[drupal-hooks]: https://www.drupal.org/docs/7/creating-custom-modules/understanding-the-hook-system-for-drupal-modules
[hooks-config]: https://www.drupal.org/docs/7/creating-custom-modules/telling-drupal-about-your-module
[hooks-intro]: https://www.drupal.org/docs/7/creating-custom-modules/writing-comments-and-implementing-your-first-hook
\ No newline at end of file
## Using hooks with Joomla!
If you're starting out with CiviCRM and Joomla! you might want to
check the [Joomla guide for creating a plugin](http://docs.joomla.org/Plugin).
Hooks may be implemented in Joomla in two ways, depending on the version of
CiviCRM and Joomla you are using. For sites running Joomla 1.5 with CiviCRM up
to and including version 3.4, you implement hooks with a single civicrmHooks.php
in your php override directory. Sites running Joomla 1.6+ and CiviCRM 4+ may
implement with either that single hooks file, or by creating a Joomla plugin.
In general, implementing through a plugin is preferred as you can benefit from
the native access control within the plugin structure, include code that
responds to other Joomla events, organize your hook implementations into
multiple plugins which may be enabled/disabled as desired, and roughly follow
the event-observer pattern intended by Joomla plugins.
Once created plugins may be packaged and installed with the Joomla installer
or the files can be placed in the appropriate folder and installed with the
discover method.
As you implement hooks in Joomla, be sure to check the CiviCRM wiki for the
most up-to-date information:
You can implement your hooks using a single hooks file, or by creating a Joomla
plugin. In general, implementing through a plugin is preferred as you can
benefit from the native access control within the plugin structure, include
code that responds to other Joomla events, organize your hook
implementations into multiple plugins which may be enabled/disabled as
desired, and roughly follow the event-observer pattern intended by Joomla
plugins.
- [http://tiny.booki.cc/?hooks-in-joomla](http://tiny.booki.cc/?hooks-in-joomla)
- [http://wiki.civicrm.org/confluence/display/CRMDOC/CiviCRM+hook+specification\#CiviCRMhookspecification-Proceduresforimplementinghooks%28forJoomla%29](http://wiki.civicrm.org/confluence/display/CRMDOC/CiviCRM+hook+specification#CiviCRMhookspecification-Proceduresforimplementinghooks%28forJoomla%29)
## Single File Implementation
To implement hooks with a single file, you will do the following:
......@@ -45,6 +43,8 @@ function joomla_civicrm_buildForm( $formName, &$form ) {
}
```
## Plugin Implementation
If you are implementing hooks with a Joomla plugin, you will create a standard,
installable plugin package. At a minimum, a plugin extension will consist of an
xml file (defining the plugin and its parameters), and a php file. Within the
......@@ -77,3 +77,88 @@ article](http://civicrm.org/blogs/mcsmom/hooks-and-joomla)
Note the reference in the comments to a sample plugin which you can download
and modify.
## Sample Joomla Plugin With Hooks
This is a simple example of a plugin for Joomla that implements CiviCRM
hooks. It consists of two file tabs.php and tabs.xml along with the blank
index.html file which is considered good Joomla coding practice.
Note: Somewhere around Joomla 2.5.20 the JPlugin class was moved to cms
.plugin.plugin from joomla.plugin.plugin (see the jimport call in Tab.php
below). If you have not remained current with the latest Joomla revision,
you may need to reference the correct location. If you find your plugins
fail after updating to the latest release, be sure to check and fix that
reference (it will often fail silently).
Tabs.php
```
<?php
/**
* @version
* @package Civicrm
* @subpackage Joomla Plugin
* @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
// No direct access
defined('_JEXEC') or die;
jimport('cms.plugin.plugin');
class plgCivicrmTabs extends JPlugin
{
/**
* Example Civicrm Plugin
*
* @package Civicrm
* @subpackage Joomla plugins
* @since 1.5
*/
public function civicrm_tabs(&$tabs, $contactID)
{
// unset the contribition tab, i.e. remove it from the page
unset( $tabs[1] );
// let's add a new "contribution" tab with a different name and put it last
// this is just a demo, in the real world, you would create a url which would
// return an html snippet etc.
$url = CRM_Utils_System::url( 'civicrm/contact/view/contribution',
"reset=1&snippet=1&force=1&cid=$contactID" );
$tabs[] = array( 'id' => 'mySupercoolTab',
'url' => $url,
'title' => 'Contribution Tab Renamed',
'weight' => 300 );
}
}
```
Tabs.xml
```
<?xml version="1.0" encoding="UTF-8"?>
<extension version="1.6" type="plugin" group="civicrm">
<name>plg_civcrm_tabs</name>
<author>Joomla! Project</author>
<creationDate>November 2005</creationDate>
<copyright>Copyright (C) 2005 - 2011 Open Source Matters. All rights reserved.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>1.6.0</version>
<description>PLG_CIVICRM_TABS_XML_DESCRIPTION</description>
<files>
<filename plugin="tabs">tabs.php</filename>
<filename>index.html</filename>
</files>
<config>
</config>
</extension>
```
You can make plugins that include multiple hooks or you can make separate
plugins. What is appropriate will depend on the application.
\ No newline at end of file
For a detailed overview of the updated relationship between WordPress and
CiviCRM, see the blog post [Working with CiviCRM 4.6 in WordPress][civi-wp-blog]
on the CiviCRM website.
In WordPress, hooks can be implemented in a variety of ways.
You can write a plugin or include them in your theme's 'functions.php'
file - where you place them depends largely on whether they are theme-dependent
or theme-independent. The general rule for targeting the hook is to
remove the 'hook_' prefix when you create the filter or action.
The following code block shows the simplest form of a hook implementation in
WordPress, in this case the 'hook_civicrm_pre' hook:
```
// Implements hook_civicrm_pre
add_filter( 'civicrm_pre', 'my_plugin_pre_callback', 10, 4 );
function my_plugin_pre_callback( $op, $objectName, $objectId, &$objectRef ) {
// your code here
}
```
As long as the plugin is active (or - if the code is in 'functions.php' - as
long as your theme is active), this function will be called every time CiviCRM
is about to save data to the database.
In summary, as of CiviCRM 4.6 there is (almost) full compatibility with the
WordPress actions and filters system.
## Including Your Hooks
Any PHP file that will be included by WordPress can be used to contain your
hook implementations. Use an in-house plugin, your site's 'functions.php'
file, or place a file named 'civicrmHooks.php' in your CiviCRM custom php
path as specified in
> Administer -> System Settings -> Directories -> Custom PHP Path Directory
## Targeting Hooks
As of CiviCRM 4.6, the general rule for targeting the hook is to remove the
'hook_' prefix when you create the filter or action. So, if your plugin or
theme wants to receive callbacks from 'hook_civicrm_pre', the filter
should be written as
```
add_filter('civicrm_pre', 'my_callback_function', 10, 4 )
```
or if your callback method is declared in a class, the filter should be written
as
```
add_filter( 'civicrm_pre', array( $this, 'my_callback_method', 10, 4 )
```
For more details (as well as the exceptions to this rule) see the
[blog post][civi-wp-blog] on CiviCRM in Wordpress.
## Legacy Hooks
Prior to CiviCRM 4.6, hooks had to use the prefix "wordpress_" as
the replacement for the "hook_" part of the hook name. So to implement
'hook_civicrm_pre' you had to write:
```
function wordpress_civicrm_pre($op, objectName, $objectId, &$objectRef)
```
This method still works, so if you have legacy modifications, they will not
break.
## Inspecting hooks
The documentation about hooks can be somewhat abstract, and it sometimes
helps to see interactively how the hooks run.
If you use WordPress, you can inspect hooks by installing the following plugin:
- [Query Monitor](https://wordpress.org/plugins/query-monitor/)
[civi-wp-blog]: https://civicrm.org/blog/haystack/working-with-civicrm-46-in-wordpress
\ No newline at end of file
......@@ -76,6 +76,7 @@ pages:
- Setup:
- Hooks with Joomla: hooks/setup/joomla.md
- Hooks with Drupal: hooks/setup/drupal.md
- Hooks with Wordpress: hooks/setup/wordpress.md
- Batch hooks:
- hook_civicrm_batchItems: hooks/hook_civicrm_batchItems.md
- hook_civicrm_batchQuery: hooks/hook_civicrm_batchQuery.md
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment