├── .github └── workflows │ └── stale.yml ├── .gitignore ├── LICENSE.txt ├── README.md ├── TODO.md ├── bin └── hook-summary.py ├── docs ├── api │ ├── index.md │ ├── interfaces.md │ ├── v3 │ │ ├── actions.md │ │ ├── chaining.md │ │ ├── changes.md │ │ ├── custom-data.md │ │ ├── examples.md │ │ ├── joins.md │ │ ├── options.md │ │ ├── usage.md │ │ └── wp-rest.md │ └── v4 │ │ ├── actions.md │ │ ├── architecture.md │ │ ├── chaining.md │ │ ├── changes.md │ │ ├── custom-data.md │ │ ├── differences-with-v3.md │ │ ├── joins.md │ │ └── usage.md ├── basics │ ├── community.md │ ├── planning.md │ ├── requirements.md │ └── skills.md ├── core │ ├── contributing.md │ ├── hacking.md │ ├── pr-review.md │ ├── release-process.md │ └── verify-fix.md ├── documentation │ ├── extensions.md │ ├── index.md │ ├── markdown.md │ └── style-guide.md ├── extensions │ ├── advanced.md │ ├── civix.md │ ├── cms-specific.md │ ├── index.md │ ├── info-xml.md │ ├── lifecycle.md │ ├── packaging.md │ ├── payment-processors │ │ ├── create.md │ │ ├── index.md │ │ └── types.md │ ├── publish.md │ ├── structure.md │ └── troubleshooting.md ├── financial │ ├── financialentities.md │ ├── orderAPI.md │ ├── overview.md │ └── paymentAPI.md ├── framework │ ├── ajax.md │ ├── angular │ │ ├── changeset.md │ │ ├── files.md │ │ ├── index.md │ │ ├── loader.md │ │ └── quickstart.md │ ├── asset-builder.md │ ├── backbone.md │ ├── bootstrap.md │ ├── cache.md │ ├── civimail.md │ ├── civireport.md │ ├── codebase.md │ ├── database │ │ ├── index.md │ │ ├── schema-definition.md │ │ ├── schema-design.md │ │ └── transactions.md │ ├── filesystem.md │ ├── pseudoconstant.md │ ├── queues │ │ └── index.md │ ├── quickform │ │ ├── entityref.md │ │ └── index.md │ ├── region.md │ ├── resources.md │ ├── routing.md │ ├── setting.md │ ├── setup │ │ ├── getting-started.md │ │ ├── index.md │ │ ├── new-installer.md │ │ ├── new-plugin.md │ │ └── plugins.md │ ├── templates │ │ ├── customizing.md │ │ ├── extending-smarty.md │ │ └── index.md │ ├── theme.md │ ├── token.md │ ├── ui.md │ └── upgrade.md ├── hooks │ ├── changes.md │ ├── hook_civicrm_aclGroup.md │ ├── hook_civicrm_aclWhereClause.md │ ├── hook_civicrm_activeTheme.md │ ├── hook_civicrm_alterAPIPermissions.md │ ├── hook_civicrm_alterAdminPanel.md │ ├── hook_civicrm_alterAngular.md │ ├── hook_civicrm_alterBadge.md │ ├── hook_civicrm_alterBarcode.md │ ├── hook_civicrm_alterCalculatedMembershipStatus.md │ ├── hook_civicrm_alterContent.md │ ├── hook_civicrm_alterCustomFieldDisplayValue.md │ ├── hook_civicrm_alterEntityRefParams.md │ ├── hook_civicrm_alterExternUrl.md │ ├── hook_civicrm_alterLocationMergeData.md │ ├── hook_civicrm_alterLogTables.md │ ├── hook_civicrm_alterMailContent.md │ ├── hook_civicrm_alterMailParams.md │ ├── hook_civicrm_alterMailer.md │ ├── hook_civicrm_alterMailingLabelParams.md │ ├── hook_civicrm_alterMailingRecipients.md │ ├── hook_civicrm_alterMenu.md │ ├── hook_civicrm_alterPaymentProcessorParams.md │ ├── hook_civicrm_alterReportVar.md │ ├── hook_civicrm_alterSettingsFolders.md │ ├── hook_civicrm_alterSettingsMetaData.md │ ├── hook_civicrm_alterTemplateFile.md │ ├── hook_civicrm_alterUFFields.md │ ├── hook_civicrm_angularModules.md │ ├── hook_civicrm_apiWrappers.md │ ├── hook_civicrm_batchItems.md │ ├── hook_civicrm_batchQuery.md │ ├── hook_civicrm_buildAmount.md │ ├── hook_civicrm_buildAsset.md │ ├── hook_civicrm_buildForm.md │ ├── hook_civicrm_buildProfile.md │ ├── hook_civicrm_buildStateProvinceForCountry.md │ ├── hook_civicrm_buildUFGroupsForModule.md │ ├── hook_civicrm_caseChange.md │ ├── hook_civicrm_caseSummary.md │ ├── hook_civicrm_caseTypes.md │ ├── hook_civicrm_check.md │ ├── hook_civicrm_config.md │ ├── hook_civicrm_contactListQuery.md │ ├── hook_civicrm_contact_get_displayname.md │ ├── hook_civicrm_container.md │ ├── hook_civicrm_copy.md │ ├── hook_civicrm_coreResourceList.md │ ├── hook_civicrm_cron.md │ ├── hook_civicrm_crudLink.md │ ├── hook_civicrm_custom.md │ ├── hook_civicrm_customFieldOptions.md │ ├── hook_civicrm_customPre.md │ ├── hook_civicrm_dashboard.md │ ├── hook_civicrm_dashboard_defaults.md │ ├── hook_civicrm_disable.md │ ├── hook_civicrm_dupeQuery.md │ ├── hook_civicrm_emailProcessor.md │ ├── hook_civicrm_emailProcessorContact.md │ ├── hook_civicrm_enable.md │ ├── hook_civicrm_entityRefFilters.md │ ├── hook_civicrm_entityTypes.md │ ├── hook_civicrm_eventDiscount.md │ ├── hook_civicrm_export.md │ ├── hook_civicrm_fieldOptions.md │ ├── hook_civicrm_fileSearches.md │ ├── hook_civicrm_findDuplicates.md │ ├── hook_civicrm_geocoderFormat.md │ ├── hook_civicrm_getAssetUrl.md │ ├── hook_civicrm_idsException.md │ ├── hook_civicrm_import.md │ ├── hook_civicrm_inboundSMS.md │ ├── hook_civicrm_install.md │ ├── hook_civicrm_links.md │ ├── hook_civicrm_mailingGroups.md │ ├── hook_civicrm_managed.md │ ├── hook_civicrm_membershipTypeValues.md │ ├── hook_civicrm_merge.md │ ├── hook_civicrm_navigationMenu.md │ ├── hook_civicrm_notePrivacy.md │ ├── hook_civicrm_optionValues.md │ ├── hook_civicrm_pageRun.md │ ├── hook_civicrm_permission.md │ ├── hook_civicrm_permission_check.md │ ├── hook_civicrm_post.md │ ├── hook_civicrm_postCommit.md │ ├── hook_civicrm_postEmailSend.md │ ├── hook_civicrm_postIPNProcess.md │ ├── hook_civicrm_postInstall.md │ ├── hook_civicrm_postJob.md │ ├── hook_civicrm_postMailing.md │ ├── hook_civicrm_postProcess.md │ ├── hook_civicrm_postSave_table_name.md │ ├── hook_civicrm_post_case_merge.md │ ├── hook_civicrm_pre.md │ ├── hook_civicrm_preJob.md │ ├── hook_civicrm_preProcess.md │ ├── hook_civicrm_pre_case_merge.md │ ├── hook_civicrm_processProfile.md │ ├── hook_civicrm_queryObjects.md │ ├── hook_civicrm_recent.md │ ├── hook_civicrm_referenceCounts.md │ ├── hook_civicrm_searchColumns.md │ ├── hook_civicrm_searchProfile.md │ ├── hook_civicrm_searchTasks.md │ ├── hook_civicrm_selectWhereClause.md │ ├── hook_civicrm_summary.md │ ├── hook_civicrm_summaryActions.md │ ├── hook_civicrm_tabs.md │ ├── hook_civicrm_tabset.md │ ├── hook_civicrm_themes.md │ ├── hook_civicrm_tokenValues.md │ ├── hook_civicrm_tokens.md │ ├── hook_civicrm_triggerInfo.md │ ├── hook_civicrm_unhandledException.md │ ├── hook_civicrm_uninstall.md │ ├── hook_civicrm_unsubscribeGroups.md │ ├── hook_civicrm_upgrade.md │ ├── hook_civicrm_validate.md │ ├── hook_civicrm_validateForm.md │ ├── hook_civicrm_validateProfile.md │ ├── hook_civicrm_viewProfile.md │ ├── hook_civicrm_xmlMenu.md │ ├── index.md │ ├── list.md │ └── usage │ │ ├── drupal.md │ │ ├── extension.md │ │ ├── joomla.md │ │ ├── symfony.md │ │ └── wordpress.md ├── img │ ├── APIv4-action-inheritance.svg │ ├── APIv4-entity-inheritance.svg │ ├── Api4-PHP-Styles.svg │ ├── CMS_URL.png │ ├── CiviCRM.png │ ├── Jenkis_Show_Results.png │ ├── api-or-example.png │ ├── financial │ │ └── FinancialAccount.png │ ├── gitlab-reference.png │ ├── index.md │ ├── inheritance-community-chest.jpg │ ├── mysql_workbench_civicrm_country_foreign_keys.png │ ├── mysql_workbench_civicrm_country_tables.png │ ├── quickform-lifecycle.png │ ├── repository-access.png │ └── security-inputs-and-outputs.svg ├── index.md ├── security │ ├── access.md │ ├── index.md │ ├── inputs.md │ ├── outputs.md │ ├── permissions.md │ └── reporting.md ├── standards │ ├── database.md │ ├── index.md │ ├── javascript.md │ ├── php.md │ ├── review.md │ └── review │ │ ├── template-del-1.0.md │ │ ├── template-mc-1.0.md │ │ └── template-word-1.0.md ├── testing │ ├── codeception.md │ ├── continuous-integration.md │ ├── index.md │ ├── karma.md │ ├── manual.md │ ├── phpunit.md │ ├── protractor.md │ ├── qunit.md │ ├── selenium.md │ └── upgrades.md ├── tools │ ├── buildkit.md │ ├── civi-test-run.md │ ├── civibuild.md │ ├── cividist.md │ ├── civilint.md │ ├── debugging.md │ ├── git.md │ ├── index.md │ ├── issue-tracking.md │ ├── jenkins.md │ ├── phpstorm.md │ └── universe.md └── translation │ ├── database.md │ ├── extensions.md │ └── index.md ├── mkdocs.yml └── redirects ├── internal.txt ├── wiki-crm.txt └── wiki-crmdoc.txt /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Mark stale issues and pull requests 2 | 3 | on: 4 | schedule: 5 | - cron: "0 * * * *" 6 | 7 | jobs: 8 | stale: 9 | 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/stale@v3 14 | with: 15 | repo-token: ${{ secrets.GITHUB_TOKEN }} 16 | stale-issue-message: 'This issue has had no activity in 60 days and has been marked as stale, it will not be closed.' 17 | stale-pr-message: 'This pull request has had no activity in 60 days and has been marked as stale, it will not be closed.' 18 | stale-issue-label: 'no-issue-activity' 19 | stale-pr-label: 'no-pr-activity' 20 | days-before-stale: 60 21 | days-before-close: -1 22 | exempt-issue-labels: 'awaiting-approval,work-in-progress' 23 | exempt-pr-labels: 'awaiting-approval,work-in-progress' 24 | remove-stale-when-updated: 'True' 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | site -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CiviCRM Developer Guide 2 | 3 | * **Issues have moved to https://lab.civicrm.org/documentation/docs/dev/-/issues** 4 | * **Submit new merge/pull requests at https://lab.civicrm.org/documentation/docs/dev** 5 | 6 | A documentation guide for people who develop with/for [CiviCRM](https://civicrm.org). 7 | 8 | - [Read published version](http://docs.civicrm.org/dev/en/master) 9 | - [Learn how to edit](https://docs.civicrm.org/dev/en/master/documentation/#how-to-edit) 10 | 11 | # Docs Infrastructure Links 12 | 13 | - [Docs Publisher system and issue queue](https://lab.civicrm.org/documentation/docs-publisher) 14 | - [Docs Book definitions for the Docs Publisher](https://lab.civicrm.org/documentation/docs-books) 15 | - [Docs Working Group meta issue queue](https://lab.civicrm.org/documentation/meta) 16 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # TODO 2 | 3 | ## Documentation structure 4 | 5 | * Where should we store deprecated documentation? Should we include it at all? 6 | * Should we rename `develop.md` (`core/develop.md` vs `extension/develop.md`?) 7 | 8 | ## Style Guide 9 | * Add guide for using footnotes 10 | 11 | ## Tasks 12 | 13 | * Finish importing [GitHub for CiviCRM](https://wiki.civicrm.org/confluence/display/CRMDOC43/GitHub+for+CiviCRM) to `develop.md` and `develop-deprecated.md`. 14 | 15 | ## Extension questions 16 | 17 | * How do I include Composer libraries in my CiviCRM extension? 18 | * Should I add the `vendor/` directory to Git? 19 | * How do I release my extension? 20 | * How do I provide downloadable .zip files from Github (which are working builds)? 21 | -------------------------------------------------------------------------------- /bin/hook-summary.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import yaml 4 | import re 5 | from os.path import dirname, abspath, join 6 | 7 | PROJECT_ROOT = dirname(dirname(abspath(__file__))) 8 | DOCS_ROOT = join(PROJECT_ROOT, 'docs/') 9 | MKDOCS_YAML_FILE = join(PROJECT_ROOT, 'mkdocs.yml') 10 | OUTPUT_FILE = join(DOCS_ROOT, 'hooks/', 'list.md') 11 | HEADER = """# All hooks 12 | 13 | 20 | 21 | 22 | This is an overview list of all available hooks, listed by category. 23 | """ 24 | 25 | def findBetween( s, first, last ): 26 | start = s.index( first ) + len( first ) 27 | end = s.index( last, start ) 28 | return s[start:end] 29 | 30 | def getSummary(hookFile): 31 | content = open(join(DOCS_ROOT + hookFile), 'r').read() 32 | summary = findBetween(content, '## Summary', '##') 33 | summary = re.sub('This hook (is)?(was)?', '', summary) 34 | summary = re.sub('\s+', ' ', summary).strip() 35 | if not (summary.endswith('.')): 36 | summary = summary + '.' 37 | return summary 38 | 39 | output = f = open(OUTPUT_FILE, 'w') 40 | with open(MKDOCS_YAML_FILE, 'r') as f: 41 | doc = yaml.load(f) 42 | pages = doc["nav"] 43 | for section in pages: 44 | if "Hooks" in section: 45 | hookSection = section.get("Hooks") 46 | 47 | output.write(HEADER) 48 | 49 | for section in hookSection: 50 | categoryHooks = list() 51 | category, hookList = section.popitem() 52 | if isinstance(hookList, list): 53 | for hookDetails in hookList: 54 | hookName = hookDetails.iterkeys().next() 55 | if re.match("^()?hook_civicrm_*", hookName): 56 | categoryHooks.append(hookDetails) 57 | 58 | if len(categoryHooks) > 0: 59 | output.write('\n## {}\n\n'.format(category)) 60 | for hookDetails in categoryHooks: 61 | hookName, hookFile = hookDetails.popitem() 62 | summary = getSummary(hookFile) 63 | hookNameForLink = hookFile.replace('hooks/', '') 64 | output.write('* **[{}]({})** - {}\n'.format(hookName, hookNameForLink, summary)) 65 | -------------------------------------------------------------------------------- /docs/api/v3/actions.md: -------------------------------------------------------------------------------- 1 | # APIv3 Actions 2 | 3 | Most entities support the following actions: 4 | 5 | ## create 6 | 7 | Insert or update one record. (Note: If an `id` is specified, then an 8 | existing record will be modified.) 9 | 10 | ## delete 11 | 12 | Delete one record. (Note: Requires an explicit `id`. Note: if you 13 | want to skip the 'recycle bin' for entities that support undelete (e.g. 14 | contacts) you should set `$param['skip_undelete'] => 1);` 15 | 16 | ## get 17 | 18 | Search for records 19 | 20 | ## getsingle 21 | 22 | Search for records and return the first or only match. (Note: This 23 | returns the record in a simplified format which is easy to use) 24 | 25 | ## getvalue 26 | Does a `getsingle` and returns a single value - you need to also set 27 | `$param['return'] => 'fieldname'`. 28 | 29 | ## getcount 30 | Search for records and return the quantity. (Note: In many cases in 31 | early versions queries are limited to 25 so this may not always be 32 | accurate) 33 | 34 | ## getrefcount 35 | 36 | Counts the number of references to a record 37 | 38 | ## getfields 39 | 40 | Fetch entity metadata, i.e. the list of fields supported by the entity 41 | 42 | ## getlist 43 | 44 | Used for autocomplete lookups by the 45 | [entityRef](./../../framework/quickform/entityref.md) widget 46 | 47 | ## getoptions 48 | 49 | Returns the options for a specified field e.g. 50 | ```php 51 | civicrm_api3( 52 | 'Contact', 53 | 'getoptions', 54 | array('field' => 'gender_id') 55 | ); 56 | ``` 57 | 58 | returns 59 | 60 | ```php 61 | array( 62 | 1 => 'Female', 63 | 2 => 'Male', 64 | 3 => 'Transgender' 65 | ) 66 | ``` 67 | 68 | ## replace 69 | 70 | Replace an old set of records with a new or modified set of records. 71 | (For example, replace the set of "Phone" numbers with a different set of 72 | "Phone" numbers.). 73 | 74 | Warning - REPLACE includes an implicit delete - use with care & test well 75 | before using in productions 76 | 77 | ## getunique 78 | 79 | Returns all unique fields (other than 'id' field) for a given entity. 80 | ```php 81 | civicrm_api3('Contribution', 'getunique'); 82 | ``` 83 | 84 | return 85 | 86 | ```php 87 | { 88 | "is_error": 0, 89 | "version": 3, 90 | "count": 2, 91 | "values": { 92 | "UI_contrib_trxn_id": [ 93 | "trxn_id" 94 | ], 95 | "UI_contrib_invoice_id": [ 96 | "invoice_id" 97 | ] 98 | } 99 | } 100 | ``` 101 | 102 | ## setvalue 103 | 104 | **Deprecated.** Use the create action with the param 'id' instead. 105 | 106 | ## update 107 | 108 | **Deprecated.** Use the create action with the param 'id' instead. 109 | -------------------------------------------------------------------------------- /docs/api/v3/chaining.md: -------------------------------------------------------------------------------- 1 | # APIv3 Chaining 2 | 3 | It is possible to do two API calls at once with the first call feeding into the second. E.g. to create a contact with a contribution you can nest the contribution create into the contact create. Once the contact has been created it will action the contribution create using the id from the contact create as `contact_id`. Likewise you can ask for all activities or all contributions to be returned when you do a `get`. 4 | 5 | See [api/v3/examples](https://github.com/civicrm/civicrm-core/tree/master/api/v3/examples) within the core source code for a plethora of examples (from unit tests) that use chaining. To start, look at these examples: 6 | 7 | - [APIChainedArray.php](https://github.com/civicrm/civicrm-core/blob/master/api/v3/examples/Contact/APIChainedArray.ex.php) 8 | - [APIChainedArrayFormats.php](https://github.com/civicrm/civicrm-core/blob/master/api/v3/examples/Contact/APIChainedArrayFormats.ex.php) 9 | - [APIChainedArrayValuesFromSiblingFunction.php](https://github.com/civicrm/civicrm-core/blob/master/api/v3/examples/Contact/APIChainedArrayValuesFromSiblingFunction.ex.php) 10 | 11 | Note that there are a few supported syntaxes: 12 | 13 | ```php 14 | civicrm_api('Contact', 'create', array( 15 | 'version' => 3, 16 | 'contact_type' => 'Individual', 17 | 'display_name' => 'BA Baracus', 18 | 'api.website.create' => array('url' => 'example.com'), 19 | )); 20 | ``` 21 | 22 | is the same as 23 | 24 | ```php 25 | civicrm_api('Contact', 'create', array( 26 | 'version' => 3, 27 | 'contact_type' => 'Individual', 28 | 'display_name' => 'BA Baracus', 29 | 'api.website' => array('url' => 'example.com'), 30 | )); 31 | ``` 32 | 33 | If you have 2 websites to create you can pass them as ids after the `.` 34 | or an array 35 | 36 | ```php 37 | civicrm_api('Contact', 'create', array( 38 | 'version' => 3, 39 | 'contact_type' => 'Individual', 40 | 'display_name' => 'BA Baracus', 41 | 'api.website.create' => array('url' => 'example.com'), 42 | 'api.website.create.2' => array('url' => 'example.org'), 43 | )); 44 | ``` 45 | 46 | or 47 | 48 | ```php 49 | civicrm_api('Contact', 'create', array( 50 | 'version' => 3, 51 | 'contact_type' => 'Individual', 52 | 'display_name' => 'BA Baracus', 53 | 'api.website.create' => array( 54 | array('url' => 'example.com'), 55 | array('url' => 'example.org'), 56 | ), 57 | )); 58 | ``` 59 | 60 | The format you use on the way in will dictate the format on the way out. 61 | 62 | Currently this supports any entity and it will convert to `entity_id` - i.e. a PledgePayment inside a contribution will receive the `contribution_id` from the outer call. 63 | -------------------------------------------------------------------------------- /docs/api/v3/custom-data.md: -------------------------------------------------------------------------------- 1 | # APIv3 and Custom Data 2 | 3 | Custom data attached to entities is referenced by `custom_N` where `N` is the unique numerical ID for the custom data field. 4 | 5 | To set a custom field, or find entities with custom fields of a particular value, you typically use a parameter like this: 6 | 7 | ```php 8 | $params['custom_N'] = 'value'; 9 | ``` 10 | 11 | To return custom data for an entity, especially when using the CustomValue API, you typically pass a param like the following: 12 | 13 | ```php 14 | $params['return.custom_N'] = 1; 15 | ``` 16 | 17 | *or (depending on which API entity you are querying)* 18 | 19 | ```php 20 | $params['return'] = 'custom_N'; 21 | ``` 22 | 23 | *or* 24 | 25 | ```php 26 | $params['return'] = 'custom_N,custom_O,custom_P'; 27 | ``` 28 | 29 | For setting custom date fields, (ie CustomValue create), date format is `YmdHis`, for example: `20050425000000`. 30 | 31 | This is just a brief introduction; each API may have different requirements and allow different formats for accessing the custom data. See the [API function documentation](../index.md) and also read the comments and documentation in each API php file (under civicrm/CRM/api/v3 in your CiviCRM installation) for exact details, 32 | which vary for each API entity and function. 33 | 34 | ## Custom Value get 35 | 36 | If developers want to get all custom data related to a particular entity. The best method is to do a `CustomValue.get` API Call. 37 | 38 | ```php 39 | $result = civicrm_api3('CustomValue', 'get', array('entity_id' => 1)); 40 | ``` 41 | 42 | A sample output would be like the following 43 | 44 | ```php 45 | { 46 | "is_error":0, 47 | "undefined_fields":["return_child:child_name"], 48 | "version":3, 49 | "count":1, 50 | "id":2, 51 | "values":[ 52 | { 53 | "entity_id":"1", 54 | "latest":"Bam Bam", 55 | "id":"2", 56 | "308":"Pebbles Flintstone", 57 | "309":"Bam Bam" 58 | } 59 | ] } 60 | ``` 61 | 62 | For entities other than the Contact Entity you can use an alternate notation to the `custom_n` to specify the custom fields you wish to return. You can use `custom_group_name:custom_field_name`. Read carefully the documentation and parameters in `CustomValue.php` for more alternatives and details. 63 | 64 | !!! note 65 | When retrieving custom data for contact entity, it will only return one value in the case of a multiple custom group set whereas for other entities (e.g. Address, or using the `CustomValue.get` API) you will get all custom data records that relate to the relevant entity 66 | 67 | The CustomValue Entity implicitly determines what the `entity_table` variable should be when it is not supplied. If you find that the implicitly is not working out exactly, then specify the `entity_table` key. 68 | 69 | When setting the value of custom data that is of type checkbox or multivalue it is important to note that the options need to be passed in as an array. For example, if you want to set options `a` and `c` of for custom value `2` on `contact` you should do the following 70 | 71 | ```php 72 | $result = civicrm_api3( 73 | 'Contact', 74 | 'create', 75 | array('id' = 2, 'custom_2' => array('a', 'c')) 76 | ); 77 | ``` 78 | -------------------------------------------------------------------------------- /docs/api/v3/examples.md: -------------------------------------------------------------------------------- 1 | # APIv3 Examples 2 | 3 | All the APIv3 Examples are generated through Tests in the CodeBase and are auto-generated from those tests so we can be certain of the code that is given. 4 | 5 | ## Location of Examples 6 | 7 | The most current examples can be found in CiviCRM's GitHub Repo on the [Master Branch](https://github.com/civicrm/civicrm-core/tree/master/api/v3/examples). When you install CiviCRM the Examples that come with the particular version of CiviCRM you have installed can be found in `/api/v3/examples`. You will also be able to view them through the [API Explorer](../index.md#api-explorer) by clicking on the **Examples** tab in the Explorer. 8 | 9 | ## Creating a New Example 10 | 11 | If you find that there is an API call or similar or perhaps a parameter for an API call that you feel is missing an example for that would be useful to the community, you can create a new example in the following way: 12 | 13 | 1. Find the relevant API test file e.g. `tests/phpunit/api/v3/MembershipTest.php` 14 | 2. Write your unit test with the API call that you want to create an Example of, however rather than using `$this->callAPISuccess` use `$this->callAPIAndDocument`. The Call API and Document function should be called similar to the following 15 | 16 | ```php 17 | $description = "This demonstrates setting a custom field through the API."; 18 | $result = $this->callAPIAndDocument($this->_entity, 'create', $params, __FUNCTION__, __FILE__, $description); 19 | ``` 20 | 21 | 3. Find in `tests/phpunit/CiviTest/CiviUnitTestCase.php` Find the function `documentMe` and comment out the if (defined) statement. 22 | 4. Run the test suite locally for that test e.g. `./tools/scripts/phpunit 'api_v3_MembershipTest'`. 23 | 5. Commit results including changes in the Examples dir and open a pull request. 24 | -------------------------------------------------------------------------------- /docs/api/v3/joins.md: -------------------------------------------------------------------------------- 1 | # API Joins 2 | 3 | An API "get" action will typically return only the values of the entity 4 | requested. However, there are times when it is advantageous to returned 5 | data from a related entity. For instance, when querying the API for email 6 | addresses, you may want to return the name of the associated contact from the 7 | Contact entity. 8 | 9 | The CiviCRM API supports two methods of returning data from associated entities; 10 | API Joins and [APIv3 Chaining](../v3/chaining.md). API joins provide higher 11 | performance by making a single SQL query with a 12 | [SQL join](https://dev.mysql.com/doc/refman/5.7/en/join.html), and are 13 | generally preferable to API chaining where available. 14 | 15 | ## Using an API Join 16 | 17 | To use a join in an API call, specify the name of the field on which the 18 | join happens, a period, and the name of the field to reference. 19 | 20 | For instance, to search for all primary emails, returning the email and joining 21 | to also return the contact's display name: 22 | ```php 23 | $result = civicrm_api3('Email', 'get', array( 24 | 'return' => array("email", "contact_id.display_name"), 25 | 'is_primary' => 1, 26 | )); 27 | ``` 28 | 29 | Alternatively, to return email addresses of everyone whose last name is Smith 30 | by joining to the Contact entity: 31 | ```php 32 | $result = civicrm_api3('Email', 'get', array( 33 | 'contact_id.last_name' => "Smith", 34 | )); 35 | ``` 36 | 37 | You can join multiple times in one query. For instance, to return a list of 38 | events, displaying their name, the name of the related campaign, and that 39 | campaign's type: 40 | ```php 41 | $result = civicrm_api3('Event', 'get', array( 42 | 'return' => array("title", "campaign_id.name", "campaign_id.campaign_type_id"), 43 | )); 44 | ``` 45 | !!! tip 46 | Joins are available only with the [get](../v3/actions.md#get), 47 | [getsingle](../v3/actions.md#getsingle), and [getcount](../v3/actions.md#getcount) 48 | actions. 49 | 50 | ## Identifying fields eligible for a join 51 | 52 | It is possible to join an entity to any other entity if the 53 | [xml schema](../../framework/database/schema-definition.md) 54 | identifies a [foreign key](../../framework/database/schema-definition.md#table-foreignKey) or 55 | a [pseudoconstant](../../framework/database/schema-definition.md#table-field-pseudoconstant). The [getfields](../v3/actions.md#getfields) action identifies 56 | fields that are eligible for an API join. 57 | 58 | !!! warning 59 | For historical reasons, some entities have a non-standard API in APIv3 60 | in order to handle more complicated operations. Those entities - 'Contact', 61 | 'Contribution', 'Pledge', and 'Participant' - can be joined to from another 62 | table, but you can not join to other tables from them. This limitation will 63 | be removed in APIv4. 64 | -------------------------------------------------------------------------------- /docs/api/v4/actions.md: -------------------------------------------------------------------------------- 1 | # APIv4 Actions 2 | 3 | *Most entities support the following actions:* 4 | 5 | ## Get 6 | 7 | Search for records based on query parameters. 8 | 9 | ## Create 10 | 11 | Insert new records into the database. 12 | 13 | ## Update 14 | 15 | Update one or more records in the database based on query parameters. 16 | 17 | ## Save 18 | 19 | Create or update one or more records. Passing an `id` determines that an existing record will be updated. 20 | 21 | ## Replace 22 | 23 | Replace an existing set of records with a new or modified set of records. For example, replace a group of "Phone" numbers for a given contact. 24 | 25 | !!! warning 26 | Replace includes an implicit delete action - use with care & test well before using in production. 27 | 28 | ## Delete 29 | 30 | Delete one or more records based on query parameters. 31 | 32 | ## GetFields 33 | 34 | Fetch entity metadata, i.e. the list of fields supported by the entity. Optionally include custom fields; optionally load the option-lists for fields. 35 | 36 | 37 | -------------------------------------------------------------------------------- /docs/api/v4/chaining.md: -------------------------------------------------------------------------------- 1 | # APIv4 Chaining 2 | 3 | Chaining lets you perform multiple API calls at once with the first call feeding into the second. E.g. to create a contact with a contribution you can nest the contribution create into the contact create. Likewise you can ask for all activities or all contributions to be returned when you do a `get`. 4 | 5 | ## Supported Syntaxes: 6 | 7 | Object Oriented way 8 | 9 | ```php 10 | $results = \Civi\Api4\Contact::create() 11 | ->addValue('contact_id', 'Individual') 12 | ->addValue('display_name', 'BA Baracus') 13 | ->addChain('create_website', \Civi\Api4\Website::create()->setValues(['contact_id' => '$id', 'url' => 'example.com'])) 14 | ->execute(); 15 | ``` 16 | 17 | Traditional: 18 | 19 | ```php 20 | civicrm_api('Contact', 'create', [ 21 | 'version' => 4, 22 | 'values' => [ 23 | 'contact_type' => 'Individual', 24 | 'display_name' => 'BA Baracus', 25 | ], 26 | 'chain' => [ 27 | 'create_website', ['Website', 'create', ['values' => ['url' => 'example.com', 'contact_id' => '$id']]], 28 | ], 29 | ]); 30 | ``` 31 | 32 | If you have 2 websites to create you can pass them as separate key => array pairs just specify a unique array key in the chain array. 33 | 34 | Object Oriented way 35 | 36 | ```php 37 | $results = \Civi\Api4\Contact::create() 38 | ->addValue('contact_id', 'Individual') 39 | ->addValue('display_name', 'BA Baracus') 40 | ->addChain('first_website', \Civi\Api4\Website::create()->setValues(['contact_id' => '$id', 'url' => 'example1.com'])) 41 | ->addChain('second_website', \Civi\Api4\Website::create()->setValues(['contact_id' => '$id', 'url' => 'example2.com'])) 42 | ->execute(); 43 | ``` 44 | 45 | Traditional: 46 | 47 | ```php 48 | civicrm_api('Contact', 'create', [ 49 | 'version' => 4, 50 | 'values' => [ 51 | 'contact_type' => 'Individual', 52 | 'display_name' => 'BA Baracus', 53 | ], 54 | 'chain' => [ 55 | 'first website', ['Website', 'create', ['values' => ['url' => 'example1.com', 'contact_id' => '$id']]], 56 | 'second_website', ['Website', 'create', ['values' => ['url' => 'example2.com', 'contact_id' => '$id']]], 57 | ], 58 | ]); 59 | ``` 60 | 61 | ## Back-references 62 | 63 | Note the use of '$id' in the examples above. Any field returned by the outer call can be passed down to a chained call by prefixing it with a dollar sign. Even the results of other chains can be accessed in this way. 64 | -------------------------------------------------------------------------------- /docs/api/v4/changes.md: -------------------------------------------------------------------------------- 1 | # APIv4 Changelog 2 | 3 | *This page lists additions to the APIv4 with each new release of CiviCRM Core.* 4 | 5 | Also see: [Differences Between Api v3 and v4](../v4/differences-with-v3.md) and [Hooks Changelog](../../hooks/changes.md). 6 | 7 | ## CiviCRM 5.29 8 | 9 | ### 5.29.0 10 | 11 | Added `target_contact_id` and `assignee_contact_id` to `Activity.create` in the API explorer. Each can take an array of contact IDs. This feature existed before version 5.29.0 but was previously not discoverable in the explorer. 12 | 13 | For more information see the [commit to CiviCRM Core](https://github.com/civicrm/civicrm-core/commit/8c6a5fd64b) 14 | 15 | ## CiviCRM 5.23 16 | 17 | ### 5.23 Added PaymentProcessor and PaymentProcessorType APIv4 Entities 18 | 19 | See [CiviCRM core pull request 15624](https://github.com/civicrm/civicrm-core/pull/15624) 20 | 21 | ### 5.23 `$index` param supports array input 22 | 23 | CiviCRM 5.23 supports two new modes for the `$index` param - associative and non-associative array. See [CiviCRM Core PR #16257](https://github.com/civicrm/civicrm-core/pull/16257) 24 | 25 | ### 5.23 Converts field values to correct data type 26 | 27 | The api historically returns everything as a raw string from the query instead of converting it to the correct variable type (bool, int, float). As of CiviCRM 5.23 this is fixed for all DAO-based entities. See [CiviCRM Core PR #16274](https://github.com/civicrm/civicrm-core/pull/16274) 28 | 29 | ### 5.23 Selects only relevant contact fields by default 30 | 31 | The Contact entity in CiviCRM is divided into 3 major types: Individuals, Households and Organizations. 32 | Not all contact fields apply to all contact types, e.g. the `sic_code` field is only used by Organizations, 33 | and the `first_name` and `last_name` fields are only used by Individuals. 34 | 35 | In CiviCRM 5.23 the schema has been augmented with metadata about which fields belong to which contact type, and Api4 now uses this 36 | metadata to select only relevant fields. E.g. fetching a household with the api will not return the `first_name` or `organization_name` fields 37 | as those will always be `null`. 38 | 39 | ### 5.23 Get actions support selecting fields by * wildcard 40 | 41 | The `select` param now supports the `*` wildcard character for matching field names. 42 | See [CiviCRM Core PR #16302](https://github.com/civicrm/civicrm-core/pull/16302). 43 | 44 | ### 5.23 Delete/Update do not throw error when 0 items found 45 | 46 | For consistency across all "batch-style" actions that update/delete records based on a query, 47 | the `Delete` and `Update` actions now simply return an empty result if no matches are found to act upon. 48 | Previously they would throw an exception, which was similar to APIv3 behavior but inconsistent with other 49 | APIv4 batch actions and SQL in general. See [CiviCRM Core PR #16374](https://github.com/civicrm/civicrm-core/pull/16374). 50 | -------------------------------------------------------------------------------- /docs/api/v4/custom-data.md: -------------------------------------------------------------------------------- 1 | # APIv4 and Custom Data 2 | 3 | CiviCRM has a flexible custom data system which allows nearly any entity to be extended. It comes in two distinct flavors: Single-record and Multi-record. 4 | For more background see the user guide chapter: [Creating Custom Fields](https://docs.civicrm.org/user/en/latest/organising-your-data/creating-custom-fields/). 5 | 6 | ## Single-Record Custom Data 7 | 8 | Because single-record fields extend an entity 1-to-1, the API treats the custom fields as an extension of the regular fields. 9 | For example, normally an Event has fields like `id`, `title`, `start_date`, `end_date`, etc. 10 | Adding a custom group named "Event_Extra" and a field named "Room_number" would be accessible from the API as "Event_Extra.Room_number". 11 | You would retrieve it and set it as if it were any other field. 12 | 13 | !!! tip 14 | The `name` of a field is not to be confused with the `label`. The API refers to custom groups/fields by name and not user-facing labels which are subject to translation and alteration. 15 | 16 | ## Multi-Record Custom Data 17 | 18 | Multiple record custom data sets are treated by the API as entities, which work similarly to other entities attached to contacts (Phone, Email, Address, etc.). For example, creating a multi-record set named "Work_History" could then be accessed via the API as an entity named "Custom_Work_History" (traditional style) or via the `CustomValue` php class (OO style). Creating a record would be done like so: 19 | 20 | **PHP (traditional):** 21 | ```php 22 | civicrm_api4('Custom_Work_History', 'create', [ 23 | 'values': ['entity_id': 202, 'Test_Field': 555] 24 | ]); 25 | ``` 26 | **Javascript:** 27 | ```javascript 28 | CRM.api4('Custom_Work_History', 'create', { 29 | values: {"entity_id":202, "Test_Field":555} 30 | }); 31 | ``` 32 | 33 | **PHP (OO):** Note that the object-oriented style uses the `CustomValue` class: 34 | 35 | ```php 36 | \Civi\Api4\CustomValue::create('Work_History') 37 | ->addValue('entity_id', 202) 38 | ->addValue('Test_Field', 555) 39 | ->execute(); 40 | ``` 41 | 42 | ## Field Types and I/O Formats 43 | 44 | New custom fields can be configured to store different types of data (Text, Date, Number, URL, etc.). In most cases the I/O format via the api will be a string, however there are a few exceptions: 45 | 46 | - **Date fields:** Input format is anything understood by `strtotime`, e.g. "now" or "-1 week" or "2020-12-25". Output format is the ISO string "YYYY-MM-DD HH:MM:SS". 47 | - **Checkbox/multi-select fields:** I/O format is an array of option values. 48 | 49 | ## Try It Out 50 | 51 | Once you have created some custom data in your system, look for it in the API Explorer. Single-record data will appear as fields on the entities they extend, and multi-record data will appear in the list of entities. 52 | 53 | !!! tip 54 | In the Api Explorer look for your multi-record custom entities under "C" alphabetically as they all start with the prefix "Custom_". 55 | -------------------------------------------------------------------------------- /docs/basics/requirements.md: -------------------------------------------------------------------------------- 1 | # Development requirements 2 | 3 | ## Languages and Services 4 | 5 | * Required 6 | - Unix-like environment (Linux, OS X, or a virtual machine) 7 | - [PHP v7.0+](http://php.net/) including the following extensions: `bcmath curl gd gettext imap intl imagick json mbstring openssl pdo_mysql phar posix soap zip` 8 | - [MySQL v5.7.5+](http://mysql.com/) or [MariaDB 10.0.2+](https://mariadb.org/), including both client and server 9 | - [NodeJS v8+](https://nodejs.org/) 10 | - [Git](https://git-scm.com/) 11 | * Recommended (for `civibuild` / `amp`): 12 | - Apache HTTPD v2.2 or v2.4 including the `mod_rewrite` module and, on SUSE, possibly `mod_access_compat` (This list may not be exhaustive.) 13 | 14 | ## Command Line 15 | 16 | There are many ways to install MySQL, PHP, and other dependencies -- for example, `apt-get` and `yum` can download packages automatically; `php.net` and `mysql.com` provide standalone installers; and MAMP/XAMPP provide bundled installers. 17 | 18 | Civi development should work with most packages -- with a priviso: ***the command-line must support standard command names*** (eg `git`, `php`, `node`, `mysql`, `mysqldump`, etc). 19 | 20 | Some environments (e.g. most Linux distributions) are configured properly out-of-the-box. Other environments (e.g. MAMP and XAMPP) may require configuring the `PATH`. 21 | 22 | 23 | 24 | ## Buildkit 25 | 26 | The developer docs reference a large number of developer tools, such as `drush` (the Drupal command line), `civix` (the CiviCRM code-generator), and `karma` (the Javascript tester). 27 | 28 | Many of these tools are commonly used by web developers, so you may have already installed a few. You could install all the tools individually -- but that takes a lot of work. 29 | 30 | [civicrm-buildkit](../tools/buildkit.md) provides a script which downloads the full collection. 31 | -------------------------------------------------------------------------------- /docs/core/hacking.md: -------------------------------------------------------------------------------- 1 | ## When should I edit core CiviCRM? 2 | 3 | !!! danger 4 | Most of the time, editing the core codebase directly is not the recommended way for developers to customise and extend CiviCRM. CiviCRM has multiple releases per year so direct edits to the core codebase will create upgrade issues for you. There are other recommended ways for the majority of scenarios: extensions, the APIs, and hooks. 5 | 6 | To help you decide, here are a couple of principles: 7 | 8 | - Bug fixes should always be applied to core. See [Contributing to Core](contributing.md) for details. 9 | - Some (but not all) enhancements to existing features may be best applied to core, especially if they would be useful to others. 10 | - New features should generally be packed as [Extensions](../extensions/index.md). 11 | - If you aren't familiar with CiviCRM, by far the best way to get a sense if you should be editing core is by [talking with the CiviCRM developer community](../basics/community.md#collaboration-tools). 12 | -------------------------------------------------------------------------------- /docs/extensions/cms-specific.md: -------------------------------------------------------------------------------- 1 | # CMS-specific extensions development 2 | 3 | When developing a native CiviCRM extension, sometimes you want to provide extra functionality for specific CMS platforms. This page provides instructions for doing so, where available. 4 | 5 | ## WordPress 6 | 7 | ### Shortcodes 8 | 9 | Here's an example of a WordPress shortcode: 10 | 11 | ```text 12 | [civicrm component="contribution" id="2" mode="live" discount="pkpwpabs7" hijack="0"] 13 | ``` 14 | 15 | Here's some code that an extension can use to receive data from the custom shortcode attribute and act on it: 16 | 17 | ```php 18 | if ( function_exists( 'add_filter' ) ) { 19 | add_filter( 'civicrm_shortcode_preprocess_atts', 'extensionprefix_amend_args', 10, 2 ); 20 | add_filter( 'civicrm_shortcode_get_data', 'extensionprefix_amend_data', 10, 3 ); 21 | } 22 | 23 | /** 24 | * Filter the CiviCRM shortcode arguments. 25 | * 26 | * Modify the attributes that the 'civicrm' shortcode allows. The attributes 27 | * that are injected (and their values) will become available in the $_REQUEST 28 | * and $_GET arrays. 29 | * 30 | * @param array $args Existing shortcode arguments 31 | * @param array $shortcode_atts Shortcode attributes 32 | * @return array $args Modified shortcode arguments 33 | */ 34 | function extensionprefix_amend_args( $args, $shortcode_atts ) { 35 | 36 | // our custom attribute name & default 37 | $name = 'discount'; 38 | $default = 'foo'; 39 | 40 | // add either passed value or default 41 | if ( array_key_exists($name, $shortcode_atts) ) { 42 | $args[$name] = $shortcode_atts[$name]; 43 | } else { 44 | $args[$name] = $default; 45 | } 46 | 47 | return $args; 48 | 49 | } 50 | 51 | /** 52 | * Filter the CiviCRM shortcode data array. 53 | * 54 | * Let's add some arbitrary text to the pre-rendered shortcode's description to 55 | * indicate that this extension has something to say. 56 | * 57 | * @param array $data Existing shortcode data 58 | * @param array $atts Shortcode attributes array 59 | * @param array $args Shortcode arguments array 60 | * @return array $data Modified shortcode data 61 | */ 62 | function extensionprefix_amend_data( $data, $atts, $args ) { 63 | 64 | // our custom attribute name 65 | $name = 'discount'; 66 | 67 | // add some arbitrary text to pre-rendered shortcode 68 | if ( array_key_exists($name, $atts) ) { 69 | $data['text'] .= ' ' . ts('Discount code: ') . $atts[$name]; 70 | } 71 | 72 | return $data; 73 | 74 | } 75 | ``` 76 | 77 | In addition, more sophisticated plugins and extensions can also filter the parameters passed the the CiviCRM API when there are multiple shortcodes present. This would allow them to retrieve additional (or alternative) data for display in the pre-rendered shortcode. 78 | -------------------------------------------------------------------------------- /docs/extensions/troubleshooting.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting 2 | 3 | If you are struggling, the best thing to do is reach out to the [CiviCRM community](../basics/community.md). 4 | 5 | If you cannot find the answer in this guide or by searching in the [CiviCRM StackExchange site](http://civicrm.stackexchange.com/) then please [ask](http://civicrm.stackexchange.com/questions/ask). Asking questions on StackExchange not only helps you but may well help others who follow you. 6 | 7 | That said, this is a small list of some of the commoner problems extension writers encounter. 8 | 9 | ## Extension not doing anything 10 | 11 | 12 | 13 | Q: I've created the files and edited them but I don't see the expected changes. 14 | 15 | A: Did you install and enable your extension? (/civicrm/admin/extensions?reset=1) 16 | 17 | ## Civix error messages 18 | 19 | Q: I get Error: "Cannot instantiate API client -- please set connection options in parameters.yml" 20 | 21 | A: You might have missed the step about setting 'civicrm\_api3\_conf\_path' ([https://github.com/totten/civix/](https://github.com/totten/civix/)), or it didn't get set properly for some reason. 22 | 23 | Q: I've tried to generate a page/report/search/upgrader/etc with civix but it's not working. 24 | 25 | A: For all of the various types, you must first run [generate:module](civix.md#generate-module), and then \`cd\` into the folder (e.g. com.example.myextension) before running one of the other \`generate:\` commands. 26 | 27 | ## Out-of-date templates 28 | 29 | Many of the generators in `civix` rely on helpers and stubs defined in `.php` or `.civix.php`. If you 30 | run `civix generate:*` on an older extension and have trouble with the generated code, then review [UPGRADE.md](https://github.com/totten/civix/blob/master/UPGRADE.md) 31 | for (a) general upgrade procedures and (b) a list of specific changes that could require manual attention. 32 | -------------------------------------------------------------------------------- /docs/financial/overview.md: -------------------------------------------------------------------------------- 1 | !!! abstract 2 | This area of CiviCRM code and documentation is a work-in-progress. Not all features 3 | will be documented and the core code underlying this area may change from version 4 | to version. 5 | 6 | The financial subsystem in civicrm encompasses: 7 | 8 | - contributions 9 | - recurring contributions 10 | - payments 11 | - refunds 12 | - prices 13 | - discounts 14 | - premiums (things given away to contacts who donate a lot) 15 | - accounting information 16 | - integrations with payment processors 17 | - integrations with accounting systems 18 | 19 | There are strong relationships between the financial area of CiviCRM and memberships, event registrations, and pledges. 20 | 21 | Due to the importance of data integrity, the tight coupling of related business operations, and large number of tables in the implementation, there is a strong focus on using higher level business APIs rather than lower level table oriented operations. 22 | 23 | Key concepts include: 24 | 25 | - order (sometimes called invoice) 26 | - line item 27 | - bookkeeping entries which encompass at a minimum a debit and credit financial account, an amount and a date 28 | - financial account, which corresponds to an account in a financial system's (like QuickBooks) chart of accounts 29 | - financial type, which organisations can use to categorise their contributions (like "Donation") for their own management purposes (e.g. "Donation for X"), accounting purposes (which financial accounts are used) and regulartory requirements (e.g. to identify taxable contributions) 30 | 31 | The main purpose of this documentation is to support 32 | 33 | - non-core systems for creating orders, eg a Drupal webform or WordPress Caldera Forms replacement of CiviCRM Contribution and Event Pages. 34 | - payment processor integrations in all of their variety. 35 | -------------------------------------------------------------------------------- /docs/financial/paymentAPI.md: -------------------------------------------------------------------------------- 1 | !!! abstract 2 | This area of CiviCRM code and documentation is a work-in-progress. Not all features 3 | will be documented and the core code underlying this area may change from version 4 | to version. 5 | 6 | ## Payment API 7 | 8 | Historically, one recorded a payment against a contribution by changing its payment status, for example from Pending to Completed. 9 | 10 | It is now best practice to use the Payment.create API call. 11 | 12 | Note that paymentprocessor.pay handles the communication with a payment processor to instigate a payment. Similarly, paymentprocessor.refund handles the communication with a payment processor to instigate a refund. 13 | 14 | After a contribution has been created, for example using the best practice Order.create API call, use the Payment.create API action to 15 | 16 | * record a payment against the contribution - either fully or partially paying the contribution amount 17 | * record a refund against the contribution 18 | 19 | Use the Payment.cancel api to reverse a refunded payment. 20 | 21 | -------------------------------------------------------------------------------- /docs/framework/angular/changeset.md: -------------------------------------------------------------------------------- 1 | # AngularJS: Changesets 2 | 3 | !!! caution "Work in progress" 4 | 5 | This documentation is still a work in progress. 6 | 7 | The [Quick Start](quickstart.md) and [Loader](loader.md) provide examples of 8 | creating *new* screens. But what if you need to alter an *existing* screen? 9 | CiviCRM allows third-parties to define *changesets* which programmatically 10 | manipulate Angular content before sending it to the client. 11 | 12 | ## Background 13 | 14 | Most AngularJS tutorials focus on idealized projects where a single 15 | developer or product-owner exercises full authority over their application. 16 | But CiviCRM is an _ecosystem_ with a range of stakeholders, including many 17 | developers (authoring indpendent extensions) and administrators (managing 18 | independent deployments with independent configurations). 19 | 20 | ... 21 | 22 | ## Hooks 23 | 24 | * **[hook_civicrm_alterAngular](../../hooks/hook_civicrm_alterAngular.md)** - Alter the definition of some Angular HTML partials. 25 | 26 | ## Example 27 | 28 | ```php 29 | function mailwords_civicrm_alterAngular(\Civi\Angular\Manager $angular) { 30 | $changeSet = \Civi\Angular\ChangeSet::create('inject_mailwords') 31 | // ->requires('crmMailing', 'mailwords') 32 | ->alterHtml('~/crmMailing/BlockSummary.html', 33 | function (phpQueryObject $doc) { 34 | $doc->find('.crm-group')->append(' 35 |
36 | 37 |
38 | '); 39 | }); 40 | $angular->add($changeSet); 41 | } 42 | ``` 43 | 44 | ``` 45 | cv ang:html:list 46 | cv ang:html:show 47 | cv ang:html:show --diff 48 | ``` 49 | -------------------------------------------------------------------------------- /docs/framework/setup/index.md: -------------------------------------------------------------------------------- 1 | !!! note "Status of `install` and `setup` subsystems" 2 | 3 | The CiviCRM `setup` subsystem is a refactored/rewritten version of the older `install` subsystem. 4 | There is a Gitlab issue for [tracking the migration from `install` to `setup`](https://lab.civicrm.org/dev/core/issues/1615). 5 | 6 | The CiviCRM `setup` subsystem facilitates installation and configuration. It aims to support multiple installers, such 7 | as a generic CLI (`cv core:install` and `cv core:uninstall`), a generic web-based installer, and specialized/scripted installers 8 | for different environments and use-cases. 9 | 10 | Key features: 11 | 12 | * The subsystem can be used by other projects -- such as `cv`, `civicrm-drupal`, `civicrm-wordpress` -- to provide an installation process. 13 | * It is a *leap*. It can coexist with the old installer. 14 | * _Example_: The `civicrm-wordpress` integration is phasing-in support for the new installer. By default, it uses the old installer. If you create a file `civicrm/.use-civicrm-setup`, then it will use the new installer. 15 | * It has minimal external dependencies. (The codebase for CiviCRM and its dependencies must be available -- but nothing else is needed.) 16 | 17 | General design: 18 | 19 | * Installers call a high-level API ([Civi\Setup](https://github.com/civicrm/civicrm-core/tree/master/setup/src/Setup.php)) which supports all major installation tasks/activities -- such as: 20 | * Check system requirements (`$setup->checkRequirements()`) 21 | * Check installation status (`$setup->checkInstalled()`) 22 | * Install data files (`$setup->installFiles()`) 23 | * Install database (`$setup->installDatabase()`) 24 | * A *data-model* ([Civi\Setup\Model](https://github.com/civicrm/civicrm-core/tree/master/setup/src/Setup/Model.php)) lists all the standard configuration parameters. This data-model is available when executing each task. For example, it includes: 25 | * The path to CiviCRM's code (`$model->srcPath`) 26 | * The system language (`$model->lang`) 27 | * The DB credentials (`$model->db`) 28 | * Each major task corresponds to an [*event*](https://github.com/civicrm/civicrm-core/tree/master/setup/src/Setup/Event) -- such as: 29 | * `civi.setup.checkRequirements` 30 | * `civi.setup.checkInstalled` 31 | * `civi.setup.installFiles` 32 | * `civi.setup.installDatabase` 33 | * *Plugins* (`plugins/*/*.civi-setup.php`) work with the model and the events. For example: 34 | * The plugin `init/WordPress.civi-setup.php` runs during initialization (`civi.setup.init`). It reads the WordPress config (e.g.`get_locale()` and `DB_HOST`) then updates the model (`$model->lang` and `$model->db`). 35 | * The plugin `installDatabase/SetLanguage.civi-setup.php` runs when installing the database (`civi.setup.installDatabase`). It reads the `$model->lang` and updates various Civi settings. 36 | 37 | -------------------------------------------------------------------------------- /docs/framework/setup/plugins.md: -------------------------------------------------------------------------------- 1 | Plugins in `civicrm/setup/plugins/*/*.civi-setup.php` are automatically 2 | detected and loaded. The simplest way to manage plugins is adding and 3 | removing files from this folder. 4 | 5 | However, you may find it useful to manage plugins programmatically. For 6 | example, the `civicrm-drupal` integration or the `civicrm-wordpress` 7 | integration might refine the installation process by: 8 | 9 | * Adding a new plugin 10 | * Removing a default plugin 11 | 12 | To programmatically manage plugins, take note of the 13 | `\Civi\Setup::init(...)` function. It accepts an argument, 14 | `$pluginCallback`, which can edit the plugin list. 15 | 16 | For example, this would add a custom plugin named `ExtraJoompralInstallPlugin`: 17 | 18 | ```php 19 | plugins_dir, __DIR__ . '/relative/path/to/custom/plugin/directory'); 19 | } 20 | ``` 21 | 22 | Then in that custom plugin directory, you can place whatever Smarty 23 | plugins you need. 24 | 25 | You can also use this trick to change other Smarty behavior, such as 26 | whether it can evaluate PHP placed directly in templates. For instance: 27 | 28 | ```php 29 | function yourmodule_civicrm_config(&$config) { 30 | $smarty = CRM_Core_Smarty::singleton(); 31 | 32 | // allow the explode() php function to be used as a "modifier" in Smarty templates 33 | array_push($smarty->security_settings['MODIFIER_FUNCS'], 'explode'); 34 | } 35 | ``` 36 | 37 | However, be very careful with these settings – if you don't know what 38 | you're doing, you can open security holes or create a mess of code 39 | that's difficult to maintain. 40 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_aclGroup.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_aclGroup 2 | 3 | ## Summary 4 | 5 | This hook is called when composing the ACL to restrict access to civicrm 6 | entities (civicrm groups, profiles and events). 7 | 8 | ## Notes 9 | 10 | In order to use this hook you must uncheck "View All Contacts" AND "Edit All Contacts" 11 | in Drupal Permissions for the user role you want to limit. You can then 12 | go into CiviCRM and grant permission to Edit or View "All Contacts" or 13 | "Certain Groups". See the Forum Topic at: 14 | [http://forum.civicrm.org/index.php/topic,14595.0.html](http://forum.civicrm.org/index.php/topic,14595.0.html) 15 | for more information. 16 | 17 | ## Definition 18 | 19 | hook_civicrm_aclGroup( $type, $contactID, $tableName, &$allGroups, &$currentGroups ) 20 | 21 | ## Parameters 22 | 23 | - $type the type of permission needed 24 | - $contactID the contactID for whom the check is made 25 | - $tableName the tableName which is being permissioned 26 | - $allGroups the set of all the objects for the above table 27 | - $currentGroups the set of objects that are currently permissioned 28 | for this contact . This array will be modified by the hook 29 | 30 | ## Returns 31 | 32 | - null - the return value is ignored 33 | 34 | ## Example 35 | 36 | Check [HRD Module](http://svn.civicrm.org/hrd/trunk/drupal/hrd.module) -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_activeTheme.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_activeTheme 2 | 3 | ## Summary 4 | 5 | The activeTheme hook determines which theme is active. 6 | 7 | ## Definition 8 | 9 | hook_civicrm_activeTheme( &$theme, $context) 10 | 11 | ## Parameters 12 | 13 | - parameter string $theme 14 | The identifier for the theme. Alterable. 15 | Ex: 'greenwich'. 16 | - parameter array $context 17 | Information about the current page-request. Includes some mix of: 18 | - page: the relative path of the current Civi page (Ex: 'civicrm/dashboard'). 19 | - themes: an instance of the Civi\Core\Themes service. 20 | 21 | ## Returns 22 | 23 | - null 24 | 25 | ## Availability 26 | 27 | - This hook was first available in CiviCRM 5.16 28 | 29 | ## Example 30 | 31 | ```php 32 | /* 33 | * Set which theme is active. 34 | */ 35 | 36 | function civitest_civicrm_activeTheme( &$theme, $context ) { 37 | $theme = 'civielection'; 38 | } 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterAPIPermissions.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterAPIPermissions 2 | 3 | ## Summary 4 | 5 | This hook is called when API 3 permissions are checked. 6 | 7 | ## Notes 8 | 9 | This hook can alter the `$permissions` structure from `CRM/Core/DAO/permissions.php` (as well as the API `$params` array) based on the `$entity` and `$action` (or unconditionally). 10 | 11 | !!! Note 12 | If a given entity/action permissions are unset, the default 13 | "administer CiviCRM" permission is enforced. 14 | 15 | 16 | ## Definition 17 | 18 | ```php 19 | hook_civicrm_alterAPIPermissions($entity, $action, &$params, &$permissions) 20 | ``` 21 | 22 | ## Parameters 23 | 24 | - string `$entity` - the API entity (like contact) 25 | - string `$action` - the API action (like get) 26 | - array `&$params` - the API parameters 27 | - array `&$permisisons` - the associative permissions array (probably to 28 | be altered by this hook) 29 | - Note: the entity in `$permissions` array use the camel case 30 | syntax (e.g. `$permissions['option_group']['get'] = ...` and not 31 | `$permissions['OptionGroup']['get'] = ...`) 32 | 33 | ## Returns 34 | 35 | - null 36 | 37 | ## Availability 38 | 39 | - This hook was first available in CiviCRM 3.4.1 40 | 41 | ## Example 42 | 43 | The `alterAPIPermissions` function is prefixed with the full extension name, all lowercase, 44 | followed by `_civicrm_alterAPIPermissions`. For an extension "CiviTest" the hook 45 | would be placed in the `civitest.php` file and might look like: 46 | 47 | ```php 48 | function civitest_civicrm_alterAPIPermissions($entity, $action, &$params, &$permissions) 49 | { 50 | // skip permission checks for contact/create calls 51 | // (but keep the ones for email, address, etc./create calls) 52 | // note: unsetting the below would require the default ‘access CiviCRM’ permission 53 | $permissions['contact']['create'] = array(); 54 | 55 | // enforce ‘view all contacts’ check for contact/get, but do not test ‘access CiviCRM’ 56 | $permissions['contact']['get'] = array('view all contacts'); 57 | 58 | // add a new permission requirement for your own custom API call 59 | // (if all you want to enforce is ‘access CiviCRM’ you can skip the below altogether) 60 | $permissions['foo']['get'] = array('access CiviCRM', 'get all foos'); 61 | 62 | // allow everyone to get info for a given event; also – another way to skip permissions 63 | if ($entity == 'event' and $action == 'get' and $params['title'] == 'CiviCon 2038') { 64 | $params['check_permissions'] = false; 65 | } 66 | } 67 | ``` 68 | 69 | The API function for the "get" action for the new custom API entity called "Foo" would be 70 | `function civicrm_api3_foo_get();`. 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterAdminPanel.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterAdminPanel 2 | 3 | ## Summary 4 | 5 | This hook is invoked after all the panels and items on Administer CiviCRM screen have been 6 | generated and allows for direct manipulation of these items and panels. 7 | 8 | ## Definition 9 | 10 | hook_civicrm_alterAdminPanel(&adminPanel) 11 | 12 | ## Parameters 13 | 14 | - array adminPanel - array of panels on Adminster CiviCRM screen 15 | 16 | ## Returns 17 | 18 | ## Example 19 | 20 | /** 21 | * Alter panels on administer CiviCRM screen 22 | */ 23 | function example_civicrm_alterAdminPanel(&$adminPanel) { 24 | // don't want to show Multi Site Settings to users as a configuration option 25 | unset($adminPanel['System_Settings']['fields']['weight}.Multi Site Settings']); 26 | } 27 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterAngular.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterAngular 2 | 3 | ## Summary 4 | 5 | This hook alters the definition of some AngularJS HTML partials and allows you to inject [AngularJS changesets](../framework/angular/changeset.md). 6 | 7 | ## Availability 8 | 9 | This hook is available in CiviCRM 4.7.21 and later. 10 | 11 | ## Definition 12 | 13 | hook_civicrm_alterAngular(&$angular) 14 | 15 | ## Parameters 16 | 17 | - array `$angular` - `\Civi\Angular\Manager` 18 | 19 | ## Example 20 | 21 | ```php 22 | function example_civicrm_alterAngular($angular) { 23 | $angular->add(\Civi\Angular\ChangeSet::create('mychanges') 24 | ->alterHtml('~/crmMailing/EditMailingCtrl/2step.html', function(phpQueryObject $doc) { 25 | $doc->find('[ng-form="crmMailingSubform"]')->attr('cat-stevens', 'ts(\'wild world\')'); 26 | }) 27 | ); 28 | } 29 | ``` 30 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterBadge.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterBadge 2 | 3 | ## Summary 4 | 5 | This hook allows you to modify the content and format of name badges. 6 | 7 | ## Availability 8 | 9 | Available in 4.5+. 10 | 11 | ## Definition 12 | 13 | hook_civicrm_alterBadge($labelName, &$label, &$format, &$participant); 14 | 15 | ## Parameters 16 | 17 | - $labelName - a string containing the name of the Badge format 18 | being used 19 | - $label - the CRM_Badge_BAO_Badge object, contains 20 | $label->pdf object 21 | - $format - the $formattedRow array used to create the 22 | badges--contains information like font and positioning 23 | - there is one entry for each element (6 in total, as you can see 24 | here /civicrm/admin/badgelayout?action=update&id=1&reset=1) with 25 | array of values for each element. Each array has the following 26 | keys: token, value, text_alignment, font_style (bold, italic, 27 | normal), font_size, font_name (the options for each key are 28 | the options that are available on this screen: 29 | civicrm/admin/badgelayout?action=update&id=1&reset=1), for 30 | example: 31 | 32 | \ 33 | token => {participant.participant_role} 34 | 35 | text_alignment => C 36 | 37 | font_style => bold 38 | 39 | font_size => 20 40 | 41 | font_name => courier 42 | 43 | value => Staff 44 | 45 | 46 | 47 | - $participant - array of token values for participant that will 48 | be displayed on badge, includes contact_id 49 | 50 | ## Returns 51 | 52 | ## Example 53 | 54 | 55 | 56 | function hook_civicrm_alterBadge($labelName, &$label, &$format, &$participant) { 57 | if ($labelName == 'My Custom Badge') { 58 | // change the font size for contact_id=12 59 | if ($participant['contact_id']==12){ 60 | foreach ($format['token'] as $valueFormat){ 61 | $valueFormat['font_size'] = 10; 62 | } 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterBarcode.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterBarcode 2 | 3 | ## Summary 4 | 5 | This hook allows you to modify the content that is encoded in barcode. 6 | 7 | ## Availability 8 | 9 | Available in 4.4+. 10 | 11 | ## Definition 12 | 13 | hook_civicrm_alterBarcode( &$data, $type='barcode', $context='name_badge' ); 14 | 15 | ## Parameters 16 | 17 | - $data - is an associated array with all token values and some 18 | additional info 19 | - $data['current_value'] - this will hold default value set by 20 | CiviCRM 21 | - $type - type of barcode ( barcode or qrcode ) 22 | - $context - currently this functionality is implemented only for 23 | name badges, hence context=name_badge 24 | 25 | ## Returns 26 | 27 | ## Example 28 | 29 | function hook_civicrm_alterBarcode(&$data, $type, $context ) { 30 | if ($type == 'barcode' && $context == 'name_badge') { 31 | // change the encoding of barcode 32 | $data['current_value'] = $data['event_id'] . '-' . $data['participant_id'] . '-' . $data['contact_id']; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterCalculatedMembershipStatus.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterCalculatedMembershipStatus 2 | 3 | ## Summary 4 | 5 | This hook is called when calculating the membership status. 6 | 7 | ## Notes 8 | 9 | Examples of when this hook is called include: 10 | 11 | * on a form 12 | * in the cron job that rolls over statuses 13 | 14 | ## Definition 15 | 16 | hook_civicrm_alterCalculatedMembershipStatus(&$membershipStatus, $arguments, $membership) 17 | 18 | ## Parameters 19 | 20 | * $membershipStatus the calculated membership status array 21 | * $arguments arguments used in the calculation 22 | * $membership the membership array from the calling function 23 | 24 | ## Added 25 | 26 | 4.5., 4.4.10 27 | 28 | ## Notes 29 | 30 | Although the membership array is passed through to the hooks no work has 31 | gone into ensuring the consistency of the data in the membership array 32 | so far - it was added to the parameters on the basis that it was easy to 33 | think of a use case (e.g requiring approval) but not tested against a 34 | current use case 35 | 36 | ## Examples 37 | 38 | Extend Grace period to one year for membership types 14, 15 & 16 39 | 40 | /** 41 | 42 | * Implementation of hook_civicrm_alterCalculatedMembershipStatus 43 | 44 | * Set membership status according to membership type 45 | 46 | * @param array $membershipStatus the calculated membership status array 47 | 48 | * @param array $arguments arguments used in the calculation 49 | 50 | * @param array $membership the membership array from the calling function 51 | 52 | */ 53 | 54 | function membershipstatus_civicrm_alterCalculatedMembershipStatus(&$membershipStatus, $arguments, $membership) { 55 | 56 | //currently we are hardcoding a rule for membership type ids 14, 15, & 16 57 | 58 | if(empty($arguments['membership_type_id']) || !in_array($arguments['membership_type_id'], array(14, 15, 16))) { 59 | 60 | return; 61 | 62 | } 63 | 64 | $statusDate = strtotime($arguments['status_date']); 65 | 66 | $endDate = strtotime($arguments['end_date']); 67 | 68 | $graceEndDate = strtotime('+ 12 months', $endDate); 69 | 70 | if($statusDate > $endDate && $statusDate <= $graceEndDate) { 71 | 72 | $membershipStatus['name'] = 'Grace'; 73 | 74 | $membershipStatus['id'] = 8; 75 | 76 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterContent.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterContent 2 | 3 | ## Summary 4 | 5 | This hook is invoked after all the content of a CiviCRM form or page is 6 | generated and allows for direct manipulation of the generated content. 7 | 8 | ## Definition 9 | 10 | hook_civicrm_alterContent( &$content, $context, $tplName, &$object ) 11 | 12 | ## Parameters 13 | 14 | - string $content - previously generated content 15 | - string $context - context of content - page or form 16 | - string $tplName - the file name of the tpl 17 | - object $object - a reference to the page or form object 18 | 19 | ## Returns 20 | 21 | ## Example 22 | 23 | /** 24 | * Alter fields for an event registration to make them into a demo form. 25 | */ 26 | function example_civicrm_alterContent( &$content, $context, $tplName, &$object ) { 27 | if($context == "form") { 28 | if($tplName == "CRM/Event/Form/Registration/Register.tpl") { 29 | if($object->_eventId == 1) { 30 | $content = "

Below is an example of an event registration.

".$content; 31 | $content = str_replace("Above is an example of an event registration

"; 34 | } 35 | } 36 | } 37 | } 38 | 39 | !!! tip 40 | While this hook is included in the Form related hooks section it can be used to alter almost all generated content. -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterCustomFieldDisplayValue.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterCustomFieldDisplayValue 2 | 3 | ## Summary 4 | 5 | This hook allows modification of custom field value for an entity eg Individual, Contribution etc before its displayed on screen. This might be useful if you want to alter the value of the custom field that's being displayed on the screen based on some condition. 6 | 7 | ## Definition 8 | 9 | hook_civicrm_alterCustomFieldDisplayValue(&$displayValue, $value, $entityId, $fieldInfo) { 10 | 11 | ## Parameters 12 | 13 | - $displayValue - String that will be displayed on screen. 14 | - $value - Value from the database for the entity id. 15 | - $entityId - Entity Id. 16 | - $fieldInfo - Array having details of custom field like name, label, custom_group_id etc. 17 | 18 | ## Returns 19 | 20 | - null 21 | 22 | ## Example 23 | 24 | ```php 25 | /** 26 | * Implementation of hook_civicrm_alterCustomFieldDisplayValue 27 | */ 28 | function extension_civicrm_alterCustomFieldDisplayValue(&$displayValue, $value, $entityId, $fieldInfo) { 29 | if ($fieldInfo['name'] == 'alter_cf_field') { 30 | $displayValue = 'New value'; 31 | } 32 | } 33 | ``` 34 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterEntityRefParams.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterEntityRefParams 2 | 3 | ## Summary 4 | 5 | This hook is called when an `entityRef` field is rendered in a form, which allows you to modify the parameters used to fetch options for this kind of field. 6 | 7 | ## Availability 8 | 9 | This hook is available in CiviCRM 4.7.28 and later. 10 | 11 | ## Definition 12 | 13 | hook_civicrm_alterEntityRefParams(&$params, $formName) 14 | 15 | ## Parameters 16 | 17 | - array `$params` - parameters of entityRef field 18 | - string `$formName` - form name 19 | 20 | ## Example 21 | 22 | ```php 23 | function myextension_civicrm_alterEntityRefParams(&$params, $formName) { 24 | // use your custom API to fetch tags of your choice on specific form say on 'New Individual' 25 | if ($formName == 'CRM_Contact_Form_Contact' && $params['entity'] == 'tag') { 26 | $params['entity'] = 'my_tags'; 27 | $params['api'] = array('params' => array('parent_id' => 292)); 28 | } 29 | // ... 30 | } 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterLocationMergeData.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterLocationMergeData 2 | 3 | ## Summary 4 | 5 | This hook allows you to alter the location information that will be moved from 6 | the duplicate contact to the master contact. 7 | 8 | ## Availability 9 | 10 | This hook was first available in CiviCRM 4.7.10. 11 | 12 | ## Definition 13 | 14 | ```php 15 | hook_civicrm_alterLocationMergeData(&$blocksDAO, $mainId, $otherId, $migrationInfo) 16 | ``` 17 | 18 | ## Parameters 19 | 20 | * array `$blocksDAO`: Array of location DAO objects. Formatted as follows: 21 | 22 | ```php 23 | [ 24 | 'email' => [ 25 | 'delete' => ['id' => object], 26 | 'update' => ['id' => object], 27 | ], 28 | 'address' => [ 29 | 'delete' => ['id' => object], 30 | 'update' => ['id' => object], 31 | ], 32 | ] 33 | ``` 34 | 35 | * int `$mainId`: Contact ID of the contact that survives the merge. 36 | * int `$otherId`: Contact ID of the contact that will be absorbed and deleted. 37 | * array `$migrationInfo`: Calculated migration info. 38 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterLogTables.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterLogTables 2 | 3 | ## Summary 4 | 5 | This hook allows you to amend the specification of the log tables to be 6 | created when logging is turned on. 7 | 8 | ## Notes 9 | 10 | You can adjust the specified tables and the engine and define indexes and exceptions. Note that CiviCRM creates log tables according to the specification at the point of creation. It does not update them if you change the specification, except with regards to adding additional tables. Tables are never automatically dropped. 11 | 12 | Turning logging on and off will cause any adjustments to the exceptions to be enacted as that information is in the triggers not the log tables, which are recreated. 13 | 14 | There is, however, a function that will convert log tables from Archive to INNODB (one way) if the hook is in play. This has to be done deliberately by calling the `system.updatelogtables` api and it can be a slow process. 15 | 16 | ## Availability 17 | 18 | This hook was first available in CiviCRM 4.7.7. 19 | 20 | ## Definition 21 | 22 | hook_civicrm_alterLogTables(&$logTableSpec) 23 | 24 | ## Parameters 25 | 26 | - @param array $logTableSpec 27 | 28 | ## Example 29 | 30 | This defines all tables as INNODB and adds indexes. 31 | 32 | https://github.com/eileenmcnaughton/nz.co.fuzion.innodbtriggers 33 | 34 | /** 35 | * Implements hook_alterLogTables(). 36 | * 37 | * @param array $logTableSpec 38 | */ 39 | function innodbtriggers_civicrm_alterLogTables(&$logTableSpec) { 40 | $contactReferences = CRM_Dedupe_Merger::cidRefs(); 41 | foreach (array_keys($logTableSpec) as $tableName) { 42 | $contactIndexes = array(); 43 | $logTableSpec[$tableName]['engine'] = 'INNODB'; 44 | $logTableSpec[$tableName]['engine_config'] = 'ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4'; 45 | $contactRefsForTable = CRM_Utils_Array::value($tableName, $contactReferences, array()); 46 | foreach ($contactRefsForTable as $fieldName) { 47 | $contactIndexes['index_' . $fieldName] = $fieldName; 48 | } 49 | $logTableSpec[$tableName]['indexes'] = array_merge(array( 50 | 'index_id' => 'id', 51 | 'index_log_conn_id' => 'log_conn_id', 52 | 'index_log_date' => 'log_date', 53 | ), $contactIndexes); 54 | } 55 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterMailContent.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterMailContent 2 | 3 | ## Summary 4 | 5 | This hook is called after getting the content of the mail and before 6 | tokenizing it. 7 | 8 | ## Definition 9 | 10 | hook_civicrm_alterMailContent(&$content) 11 | 12 | ## Parameters 13 | 14 | - $content - fields that include the content of the mail 15 | 16 | ## Details 17 | 18 | $content - fields include: html, text, subject, groupName, valueName, messageTemplateID, mailingID, campaign_id, template_type. 19 | Note that this hook is fired when: 20 | 21 | * creating mailings through the traditional BAO mailer (standard CiviMail) 22 | * creating mailings through FlexMailer (used by Mosaico) 23 | * sending emails using message templates, in CRM_Core_BAO_MessageTemplate 24 | 25 | In the latter case there is inherently no mailingID or template_type, so these will not be supplied. Similarly in the 2 former cases the messageTemplateID is not supplied. 26 | 27 | ## Example 28 | 29 | ```php 30 | /** 31 | * Implement hook_civicrm_alterMailContent 32 | * 33 | * Replace invoice template with custom content from file 34 | */ 35 | function mail_civicrm_alterMailContent(&$content) { 36 | if (CRM_Utils_Array::value('valueName', $content) == 'contribution_invoice_receipt') { 37 | $path = CRM_Core_Resources::singleton()->getPath('org.myorg.invoice'); 38 | $html = file_get_contents($path.'/msg/contribution_invoice_receipt.html.tpl'); 39 | $content['html'] = $html; 40 | } 41 | } 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterMailParams.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterMailParams 2 | 3 | ## Summary 4 | 5 | This hook is called when an email is being prepared for sending by CiviCRM. 6 | 7 | ## Definition 8 | 9 | hook_civicrm_alterMailParams(&$params, $context) 10 | 11 | ## Parameters 12 | 13 | - $params - the mailing params array 14 | - $context - the contexts of the hook call are: 15 | - "civimail" for when sending an email using CiviMail, 16 | - "flexmailer" for when sending an email using CiviMail and 17 | [FlexMailer](https://civicrm.org/extensions/flexmailer) 18 | (e.g. for Mosaico), 19 | - "singleEmail" for when sending a single email, 20 | - "messageTemplate" for when sending an email using a message 21 | template 22 | 23 | ## Details 24 | 25 | - $params array fields include: groupName, from, toName, toEmail, 26 | subject, cc, bcc, text, html, returnPath, replyTo, headers (array), 27 | attachments (array), and possibly others depending on context. 28 | - If you want to abort the mail from being sent, set the boolean 29 | abortMailSend to true in the params array 30 | - Note that this hook is called twice when sending a message template, once 31 | early in the message generation (before tokens are applied, with the context 32 | `messageTemplate`) and then later from `CRM_Utils_Mail::send()` with the 33 | context `singleEmail`. 34 | 35 | 36 | ## Adding custom headers to the email 37 | 38 | You can add custom headers by appending to `$params['headers']`. Example: 39 | 40 | ```php 41 | $params['headers']['X-My-Header'] = 'my header value'; 42 | ``` 43 | 44 | The `headers` key may not exist in the `$params` array when passed into the hook. 45 | 46 | For CiviMail based emails you can also add headers by simply adding a key 47 | directly to the `$params` array, however as CiviMail also supports the above, so 48 | it might be safer to use the `headers` key when adding headers as this is 49 | supported across all methods. 50 | 51 | Study the source before atttempting to set or unset non-custom headers this way! 52 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterMailer.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterMailer 2 | 3 | ## Summary 4 | 5 | This hook is called when CiviCRM prepares an email driver class to 6 | handle outbound message delivery. 7 | 8 | ## Availability 9 | 10 | Introduced in CiviCRM v4.4. 11 | 12 | ## Definition 13 | 14 | hook_civicrm_alterMailer(&$mailer, $driver, $params) 15 | 16 | ## Parameters 17 | 18 | - object**$mailer** -The default mailer produced by normal 19 | configuration; a PEAR "Mail" class (like those returned by 20 | Mail::factory) 21 | 22 | - string **$driver** - The type of the default $mailer (eg "smtp", 23 | "sendmail", "mock", "CRM_Mailing_BAO_Spool") 24 | 25 | - array **$params** - The default config options used to construct 26 | $mailer 27 | 28 | ## Example 29 | 30 | /** 31 | * Implementation of hook_civicrm_alterMailer 32 | * 33 | * Replace the normal mailer with our custom mailer 34 | */ 35 | function example_civicrm_alterMailer(&$mailer, $driver, $params) { 36 | $mailer = new ExampleMailDriver(); 37 | } 38 | 39 | /** 40 | * Outbound mailer which writes messages to a log file 41 | * 42 | * For better examples, see PEAR Mail. 43 | * 44 | * @see Mail_null 45 | * @see Mail_mock 46 | * @see Mail_sendmail 47 | * @see Mail_smtp 48 | */ 49 | class ExampleMailDriver { 50 | /** 51 | * Send an email 52 | */ 53 | function send($recipients, $headers, $body) { 54 | // Write mail out to a log file instead of delivering it 55 | $data = array( 56 | 'recipients' => $recipients, 57 | 'headers' => $headers, 58 | 'body' => $body, 59 | ); 60 | file_put_contents('/tmp/outbound-mail.log', json_encode($data), FILE_APPEND); 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterMailingLabelParams.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterMailingLabelParams 2 | 3 | ## Summary 4 | 5 | This hook is called to alter the parameters used to generate mailing 6 | labels. 7 | 8 | ## Availability 9 | 10 | CiviCRM 4.1 or later 11 | 12 | ## Definition 13 | 14 | function hook_civicrm_alterMailingLabelParams( &$args ) 15 | 16 | ## Parameters 17 | 18 | - $args: reference to the associative array of arguments that are 19 | about to be used to generate mailing labels 20 | - 21 | 22 | 23 | 24 | @param array $args an array of the args for the tcpdf MultiCell api call with the variable names below converted into string keys 25 | (ie $w become 'w' as the first key for $args). 26 | If ishtml is set true, then a subset of the args will be passed to the tcdpdf writeHTMLCell api call instead. 27 | 28 | float $w Width of cells. If 0, they extend up to the right margin of the page. 29 | float $h Cell minimum height. The cell extends automatically if needed. 30 | string $txt String to print 31 | mixed $border Indicates if borders must be drawn around the cell block. The value can 32 | be either 33 | a number: 34 | 0: no border (default) 35 | 1: frame or 36 | a string containing some or all of the following characters (in any order): 37 | L: left 38 | T: top 39 | R: right 40 | B: bottom 41 | string $align Allows to center or align the text. Possible values are: 42 | L or empty string: left align 43 | C: center 44 | R: right align 45 | J: justification (default value when $ishtml=false) 46 | int $fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0. 47 | int $ln Indicates where the current position should go after the call. Possible values are: 48 | 0: to the right 49 | 1: to the beginning of the next line DEFAULT 50 | 2: below 51 | float $x x position in user units 52 | float $y y position in user units 53 | boolean $reseth if true reset the last cell height (default true). 54 | int $stretch stretch carachter mode: 55 | 0 = disabled 56 | 1 = horizontal scaling only if necessary 57 | 2 = forced horizontal scaling 58 | 3 = character spacing only if necessary 59 | 4 = forced character spacing 60 | boolean $ishtml set to true if $txt is HTML content (default = false). 61 | boolean $autopadding if true, uses internal padding and automatically adjust it to account for line width. 62 | float $maxh maximum height. It should be >= $h and less then remaining space to the bottom of the page, 63 | or 0 for disable this feature. This feature works only when $ishtml=false. 64 | 65 | NB: not all html tags are supported, not all style parameters are 66 | supported, and improperly constructed html tends to lead to errors and 67 | crashes. 68 | 69 | ## Returns 70 | 71 | - null 72 | 73 | ## Example 74 | 75 | function mymodule_civicrm_alterMailingLabelParams( &$args ) { 76 | $args['ishtml'] = true; 77 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterMailingRecipients.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterMailingRecipients 2 | 3 | ## Summary 4 | 5 | This hook is called to allow the user to alter the mailing recipients after they have been constructed. 6 | 7 | ### Notes 8 | 9 | !!! Note 10 | This hook is called two times, once at the start and once at the end of mail recipients 11 | building, identified by $context as 'pre' or 'post' respectively 12 | 13 | ## Availability 14 | 15 | This hook was first available in CiviCRM 4.7.32 16 | 17 | ## Definition 18 | 19 | ```php 20 | function hook_civicrm_alterMailingRecipients(&$mailingObject, &$criteria, $context); 21 | ``` 22 | 23 | ## Parameters 24 | 25 | - object `$mailingObject` - reference to CRM_Mailing_DAO_Mailing object 26 | - array `$criteria` - the criteria in terms of SQL fragments Array(string $name => CRM_Utils_SQL_Select $criterion) to manipulate mailing recipients 27 | - string `$context` - contain 'pre' or 'post' value to indicate when the hook is fired 28 | 29 | ## Returns 30 | 31 | - null 32 | 33 | ## Example 34 | ```php 35 | function mymodule_civicrm_alterMailingRecipients(&$mailingObject, &$criteria, $context) { 36 | // fetch all emails marked is_bulkmail only AND consider only those contacts which are tagged with Volunteer 37 | if ($context == 'pre') { 38 | // criteria to choose email which are only used for mass mailing 39 | $criteria['location_filter'] = CRM_Utils_SQL_Select::fragment()->where("civicrm_email.is_bulkmail = 1"); 40 | // criteria to choose contacts which are tagged 'Volunteer' 41 | $criteria['tag_filter'] = CRM_Utils_SQL_Select::fragment() 42 | ->join('civicrm_entity_tag', "INNER JOIN civicrm_entity_tag et ON et.entity_id = civicrm_contact.id AND et.entity_table = 'civicrm_contact'") 43 | ->join('civicrm_tag', "INNER JOIN civicrm_tag t ON t.id = et.tag_id") 44 | ->where("t.name = 'Volunteer'"); 45 | // criteria to change order by to use is_bulkmail 46 | $criteria['order_by'] = CRM_Utils_SQL_Select::fragment()->orderBy('civicrm_email.is_bulkmail') 47 | } 48 | } 49 | ``` 50 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterMenu.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterMenu 2 | 3 | ## Summary 4 | 5 | This hook is called when building CiviCRM's list of HTTP routes and should be used when you want to register custom paths or URLS. 6 | 7 | ## Notes 8 | 9 | !!! note "Comparison of Related Hooks" 10 | This is one of three related hooks. The hooks: 11 | 12 | - [hook_civicrm_navigationMenu](hook_civicrm_navigationMenu.md) manipulates the navigation bar at the top of every screen 13 | - [hook_civicrm_alterMenu](hook_civicrm_alterMenu.md) manipulates the list of HTTP routes (using PHP arrays) 14 | - [hook_civicrm_xmlMenu](hook_civicrm_xmlMenu.md) manipulates the list of HTTP routes (using XML files) 15 | 16 | !!! tip "Applying changes" 17 | 18 | Menu data is cached. After making a change to the menu data, [clear the system cache](../tools/debugging.md#clearing-the-cache). 19 | 20 | ## Availability 21 | 22 | Added in CiviCRM 4.7.11. 23 | 24 | 25 | ## Definition 26 | 27 | hook_civicrm_alterMenu(&$items) 28 | 29 | ## Parameters 30 | 31 | - *"$items*" the array of HTTP routes, keyed by relative path. Each 32 | includes some combination of properties: 33 | - "*page_callback*": This should refer to a page/controller class 34 | ("*CRM_Example_Page_Example*") or a static function 35 | ("*CRM_Example_Page_AJAX::foobar*"). 36 | - "*access_callback*": (usually omitted) 37 | - "*access_arguments*": Description of required permissions. Ex: 38 | *array(array('access CiviCRM'), 'and')* 39 | - "*ids_arguments*": This array defines any [page-specific PHPIDS exceptions](hook_civicrm_xmlMenu.md#xml-ids). It includes any of these three child elements: 40 | - "*json*": Array of input fields which may contain JSON data. 41 | - "*html*": Array of input fields which may contain HTML data. 42 | - "*exceptions*": Array of input fields which are completely exempted from PHPIDS. 43 | 44 | ## Returns 45 | 46 | - null 47 | 48 | ## Example 49 | 50 | 51 | 52 | function EXAMPLE_civicrm_alterMenu(&$items) { 53 | $items['civicrm/my-page'] = array( 54 | 'page_callback' => 'CRM_Example_Page_AJAX::foobar', 55 | 'access_arguments' => array(array('access CiviCRM'), "and"), 56 | ); 57 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterPaymentProcessorParams.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterPaymentProcessorParams 2 | 3 | ## Summary 4 | 5 | This hook allows you to modify parameters passed to the payment processor. 6 | 7 | ## Notes 8 | 9 | This hook is called during the processing of a contribution after the 10 | payment processor has control, but before the CiviCRM processor-specific code starts a transaction with the back-end payment server (e.g. Authorize.net). 11 | 12 | With this hook, you can pass custom parameters, or use features of your back-end that CiviCRM does not "know" about. 13 | 14 | ## Definition 15 | 16 | hook_civicrm_alterPaymentProcessorParams($paymentObj,&$rawParams, &$cookedParams); 17 | 18 | ## Parameters 19 | 20 | - $paymentObj - instance of payment class of the payment processor 21 | invoked 22 | - $rawParams - the associative array passed by CiviCRM to the 23 | processor 24 | - $cookedParams - the associative array of parameters as translated 25 | into the processor's API. 26 | 27 | ## Returns 28 | 29 | ## Example 30 | 31 | function civitest_civicrm_alterPaymentProcessorParams($paymentObj, &$rawParams, &$cookedParams) { 32 | if ($paymentObj->class_name == Payment_Dummy ) { 33 | $employer = empty($rawParams['custom_1']) ? '' : $rawParams['custom_1']; 34 | $occupation = empty($rawParams['custom_2']) ? '' : $rawParams['custom_2']; 35 | $cookedParams['custom'] = "$employer|$occupation"; } 36 | else if ($paymentObj->class_name == Payment_AuthorizeNet) { 37 | //Actual translation for one application: 38 | //Employer > Ship to Country (x_ship_to_country) 39 | //Occupation > Company (x_company) 40 | //Solicitor > Ship-to First Name (x_ship_to_first_name) 41 | //Event > Ship-to Last Name (x_ship_to_last_name) 42 | //Other > Ship-to Company (x_ship_to_company) 43 | $cookedParams['x_ship_to_country'] = $rawParams['custom_1']; 44 | $cookedParams['x_company'] = $rawParams['custom_2']; 45 | $cookedParams['x_ship_to_last_name'] = $rawParams['accountingCode']; 46 | //for now 47 | $country_info = da_core_fetch_country_data_by_crm_id($rawParams['country-1']); 48 | $cookedParams['x_ship_to_company'] = $country_info['iso_code']; 49 | } 50 | elseif ($paymentObj->billing_mode == 2) { 51 | // Express Checkout 52 | $cookedParams['desc'] = $rawParams['eventName']; 53 | $cookedParams['custom'] = $rawParams['eventId']; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterSettingsFolders.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterSettingsFolders 2 | 3 | ## Summary 4 | 5 | This hook allows modules and extensions to scan for settings in 6 | additional folders. 7 | 8 | ## Notes 9 | 10 | The [Settings](../framework/setting.md) subsystem 11 | provides metadata about many of CiviCRM's internal settings by scanning 12 | for files matching "settings/*.setting.php" (e.g. 13 | [settings/Core.setting.php](https://github.com/civicrm/civicrm-core/blob/4.3/settings/Core.setting.php)). 14 | 15 | ## Availability 16 | 17 | This hook was introduced in CiviCRM v4.3.0 and v4.2.10. 18 | 19 | ## Definition 20 | 21 | hook_civicrm_alterSettingsFolders(&$metaDataFolders) 22 | 23 | ## Parameters 24 | 25 | - @param array $metaDataFolders list of directory paths 26 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterSettingsMetaData.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterSettingsMetaData 2 | 3 | ## Summary 4 | 5 | This hook is called when Settings have been loaded from the xml. 6 | It is an opportunity for hooks to alter the data. 7 | 8 | ## Definition 9 | 10 | alterSettingsMetaData(&$settingsMetaData, $domainID, $profile) 11 | 12 | ## Parameters 13 | 14 | - @param array $settingsMetaData Settings Metadata. 15 | - @param int $domainID 16 | - @param mixed $profile 17 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterTemplateFile.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterTemplateFile 2 | 3 | ## Summary 4 | 5 | This hook is invoked while selecting the tpl file to use to render the 6 | page. 7 | 8 | ## Definition 9 | 10 | hook_civicrm_alterTemplateFile($formName, &$form, $context, &$tplName) 11 | 12 | 13 | 14 | ## Parameters 15 | 16 | - string $formname -name of the form 17 | - object $form (reference) for object 18 | - string $context page or form 19 | - string $tplName - the file name of the tpl - alter this to alter 20 | the file in use 21 | 22 | ## Returns 23 | 24 | ## Example 25 | 26 | 27 | 28 | /** 29 | * Alter tpl file to include a different tpl file based on contribution/financial type 30 | * (if one exists). It will look for 31 | * templates/CRM/Contribute/Form/Contribution/Type2/Main.php 32 | * where the form has a contribution or financial type of 2 33 | * @param string $formName name of the form 34 | * @param object $form (reference) form object 35 | * @param string $context page or form 36 | * @param string $tplName (reference) change this if required to the altered tpl file 37 | */ 38 | function tplbytype_civicrm_alterTemplateFile($formName, &$form, $context, &$tplName) { 39 | $formsToTouch = array( 40 | 'CRM_Contribute_Form_Contribution_Main' => array('path' => 'CRM/Contribute/Form/Contribution/', 'file' => 'Main'), 41 | 42 | 'CRM_Contribute_Form_Contribution_Confirm' => array('path' => 43 | 'CRM/Contribute/Form/Contribution', 'file' => 'Confirm'), 44 | 45 | 'CRM_Contribute_Form_Contribution_ThankYou' => array('path' => 46 | 'CRM/Contribute/Form/Contribution', 'file' => 'ThankYou'), 47 | ); 48 | 49 | 50 | if(!array_key_exists($formName, $formsToTouch)) { 51 | return; 52 | } 53 | if(isset($form->_values['financial_type_id'])) { 54 | $type = 'Type' . $form->_values['financial_type_id']; 55 | } 56 | if(isset($form->_values['contribution_type_id'])) { 57 | $type = 'Type' . $form->_values['contribution_type_id']; 58 | } 59 | if(empty($type)) { 60 | return; 61 | } 62 | $possibleTpl = $formsToTouch[$formName]['path'] . $type . '/' . $formsToTouch[$formName]['file']. '.tpl'; 63 | $template = CRM_Core_Smarty::singleton(); 64 | if ($template->template_exists($possibleTpl)) { 65 | $tplName = $possibleTpl; 66 | } 67 | } 68 | 69 | !!! tip 70 | While this hook is included in the Form related hooks section it can be used to alter almost all generated content. -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_alterUFFields.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_alterUFFIelds 2 | 3 | ## Summary 4 | 5 | This hook allows for the modification of the available fields that are permissible for use within a profile. This might be useful for when you have an extension that has defined it's own entities or it is seeking to permit a core component that doesn't show up in profiles by default e.g. Grants 6 | 7 | ## Definition 8 | 9 | hook_civicrm_alterUFFields(&$fields) { 10 | 11 | ## Parameters 12 | 13 | - $fields - a multidimential array of Entities and their fields. 14 | For each field contained within the array there are at the following properties 15 | - name 16 | - title 17 | - export 18 | - import 19 | - hasLocationType 20 | - field_type - Entity of the field 21 | - other field keys as returned by entity.getfields 22 | 23 | ## Returns 24 | 25 | - null 26 | 27 | ## Example 28 | 29 | ```php 30 | /** 31 | * Implementation of hook_civicrm_alterUFFIelds 32 | */ 33 | function mte_civicrm_alterUFFields(&$fields) { 34 | // Include grant fields in the permissible array 35 | $fields['Grant'] = CRM_Grant_DAO_Grant::export(); 36 | } 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_angularModules.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_angularModules 2 | 3 | ## Summary 4 | 5 | This hook generates a list of AngularJS modules and allows you to register additional AngularJS modules. It is currently **experimental**. 6 | 7 | ## Availability 8 | 9 | This hook is available in CiviCRM 4.5+. It may use features only 10 | available in CiviCRM 4.6+. 11 | 12 | ## Definition 13 | 14 | ```php 15 | angularModules(&$angularModules) 16 | ``` 17 | 18 | ## Parameters 19 | 20 | * `&$angularModules` - an array containing a list of all Angular modules. The key for each item is the name of the module. The value for each item is an array with the following key/value pairs: 21 | 22 | * `'ext' =>`*`(string)`* - The name of the CiviCRM extension which has the source-code. 23 | * `'js' =>`*`(array)`* - List of Javascript files. May use the wildcard (`*`). Relative to the extension. 24 | * `'css' =>`*`(array)`* - List of CSS files. May use the wildcard (`*`). Relative to the extension. 25 | * `'partials' =>`*`(array)`* - List of HTML folders. Relative to the extension. 26 | * `'settings' =>`*`(array)`* - Runtime data to export from PHP to JS. 27 | * This is mapped to the JS global (Ex: `array("foo"=>"bar")`, which would be available as `CRM.myModule.foo`. 28 | * `'requires' =>`*`(array)`* - List of AngularJS modules required by this module. 29 | * Default: `array()`. 30 | * CiviCRM 4.7.21+ 31 | * `'basePages' =>`*`(array)`* - Unconditionally load this module onto the given Angular pages. 32 | * If omitted, the default is `array('civicrm/a')`. This provides backward compatibility with behavior since `v4.6+`. 33 | * For a utility that should only be loaded on-demand, use `array()`. 34 | * For a utility that should be loaded in all pages use, `array('*')`. 35 | * CiviCRM 4.7.21+ 36 | 37 | ## Returns 38 | 39 | * `null` 40 | 41 | ## Example 42 | 43 | ```php 44 | function mymod_civicrm_angularModules(&$angularModules) { 45 | $angularModules['myAngularModule'] = array( 46 | 'ext' => 'org.example.mymod', 47 | 'js' => array('js/myAngularModule.js'), 48 | ); 49 | $angularModules['myBigAngularModule'] = array( 50 | 'ext' => 'org.example.mymod', 51 | 'requires' => array('ngRoute', 'crmUi'), 52 | 'basePages' => array('civicrm/a'), 53 | 'js' => array('js/part1.js', 'js/part2.js'), 54 | 'css' => array('css/myAngularModule.css'), 55 | 'partials' => array('partials/myBigAngularModule'), 56 | 'settings' => array( 57 | 'foo' => 'bar', 58 | ), 59 | ); 60 | } 61 | ``` 62 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_batchItems.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_batchItems 2 | 3 | ## Summary 4 | 5 | This hook is called when a CSV batch export file is about to be 6 | generated. 7 | 8 | ## Notes 9 | 10 | Notice that this hook will be called in per batch bases, e.g. 11 | if 3 batches are going to be exported in the same CSV then this hook 12 | will be called three times regarding each batch. 13 | 14 | ## Definition 15 | 16 | ```php 17 | hook_civicrm_batchItems(&$results, &$items) 18 | ``` 19 | 20 | ## Parameters 21 | 22 | - `$results` - the query result for the current batch that is being processed 23 | - `$items` - the entries of financial items that will actually become the records on the CSV (still per batch based) 24 | 25 | ## Hints 26 | 27 | - This hook can be used together with `hook_civicrm_batchQuery` to add/modify the information in CSV batch exports 28 | - You can loop through the two parameters to modify per financial item. This can even be used to filter financial items. 29 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_batchQuery.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_batchQuery 2 | 3 | ## Summary 4 | 5 | This hook is called when the query of CSV batch export is generated 6 | 7 | ## Notes 8 | 9 | With this hook you can provide your own query objects which alter or extend the original query. 10 | 11 | ## Definition 12 | 13 | hook_civicrm_batchQuery( &$query ) 14 | 15 | ## Parameters 16 | 17 | - $query - A string of SQL Query 18 | 19 | ## Example 20 | 21 | 22 | function hook_civicrm_batchQuery(&$query) { 23 | $query = "SELECT * FROM civicrm_financial_item"; 24 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_buildAmount.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_buildAmount 2 | 3 | ## Summary 4 | 5 | This hook is called when building the amount structure for a 6 | Contribution or Event Page, allowing you to modify the set of radio 7 | buttons representing amounts for contribution levels and event 8 | registration fees. 9 | 10 | ## Definition 11 | 12 | hook_civicrm_buildAmount( $pageType, &$form, &$amount ) 13 | 14 | ## Parameters 15 | 16 | - $pageType - is this a 'contribution', 'event', or 'membership' 17 | - $form - reference to the form object 18 | - $amount - the amount structure to be displayed 19 | 20 | ## Returns 21 | 22 | - null 23 | 24 | ## Example 25 | For an extension that implements this hook see: https://github.com/mattwire/uk.org.som.proratamembership 26 | 27 | function proratamembership_civicrm_buildAmount($pageType, &$form, &$amount) { 28 | if (!empty($form->get('mid'))) { 29 | // Don't apply pro-rated fees to renewals 30 | return; 31 | } 32 | //sample to modify priceset fee 33 | $priceSetId = $form->get('priceSetId'); 34 | if (!empty($priceSetId)) { 35 | $feeBlock = &$amount; 36 | if (!is_array($feeBlock) || empty($feeBlock)) { 37 | return; 38 | } 39 | if ($pageType == 'membership') { 40 | // pro-rata membership per month 41 | // membership year is from 1st Jan->31st Dec 42 | // Subtract 1/12 per month so in Jan you pay full amount, 43 | // in Dec you pay 1/12 44 | // 12 months in year, min 1 month so subtract current numeric month from 13 (gives 12 in Jan, 1 in December) 45 | $monthNum = date('n'); 46 | $monthsToPay = 13-$monthNum; 47 | foreach ($feeBlock as &$fee) { 48 | if (!is_array($fee['options'])) { 49 | continue; 50 | } 51 | foreach ($fee['options'] as &$option) { 52 | // We only have one amount for each membership, so this code may be overkill, 53 | // as it checks every option displayed (and there is only one). 54 | if ($option['amount'] > 0) { 55 | // Only pro-rata paid memberships! 56 | $option['amount'] = $option['amount'] * ($monthsToPay / 12); 57 | if ($monthsToPay == 1) { 58 | $option['label'] .= ' - Pro-rata: Dec only'; 59 | } 60 | elseif ($monthsToPay < 12) { 61 | $dateObj = DateTime::createFromFormat('!m', $monthNum); 62 | $monthName = $dateObj->format('M'); 63 | $option['label'] .= ' - Pro-rata: ' . $monthName . ' to Dec'; 64 | } 65 | } 66 | } 67 | } 68 | // FIXME: Somewhere between 4.7.15 and 4.7.23 the above stopped working and we have to do the following to make the confirm page show the correct amount. 69 | $form->_priceSet['fields'] = $feeBlock; 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_buildAsset.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_buildAsset 2 | 3 | ## Summary 4 | 5 | This hook fires whenever the system builds a semi-dynamic asset. 6 | 7 | ## Notes 8 | 9 | For more discussion, see [AssetBuilder](../framework/asset-builder.md). 10 | 11 | ## Definition 12 | 13 | hook_civicrm_buildAsset($asset, $params, &$mimeType, &$content) 14 | 15 | ## Parameters 16 | 17 | * `$asset` (string): the logical file name of an asset (ex: `hello-world.json`) 18 | * `$params` (array): an optional set of parameters describing how to build the asset 19 | * `$mimeType` (string, output): the MIME type of the asset (ex: `application/json`) 20 | * `$content` (string, output): the full content of the asset 21 | 22 | ## Returns 23 | 24 | * null 25 | 26 | ## Example 27 | 28 | ```php 29 | function mymodule_civicrm_buildAsset($asset, $params, &$mimeType, &$content) { 30 | if ($asset === 'hello-world.json') { 31 | $mimeType = 'application/json'; 32 | $content = json_encode(array('hello', 'world')); 33 | } 34 | } 35 | ``` -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_buildProfile.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_buildProfile 2 | 3 | ## Summary 4 | 5 | This hook is called while preparing a profile form. This form allows for extension authors to add various scripts onto the profile pages. Note that `hook_civicrm_buildForm` is not fired for profile pages 6 | 7 | ## Definition 8 | 9 | buildProfile($profileName) 10 | 11 | ## Parameters 12 | 13 | - $profileName - the (machine readable) name of the profile. 14 | 15 | ## Returns 16 | 17 | - null 18 | 19 | ```php 20 | function myext_civicrm_buildProfile($profileName) { 21 | if ($profileName === 'MyTargetedProfile) { 22 | CRM_Core_Resources::singleton()->addScriptFile('org.example.myext', 'some/fancy.js', 100); 23 | } 24 | } 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_buildStateProvinceForCountry.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_buildStateProvinceForCountry 2 | 3 | ## Summary 4 | 5 | This hook is called during the ajax callback that is used to build the 6 | options that display in the State/Province select widget for a specific 7 | country, and can be used to alter the list of State/Province options for 8 | particular countries. 9 | 10 | ## Definition 11 | 12 | hook_civicrm_buildStateProvinceForCountry( $countryID, &$states ) 13 | 14 | ## Parameters 15 | 16 | - @param string $countryID Country ID for which State/Province data 17 | is being looked up 18 | - @param array $states array of State/Province data relating to 19 | country being looked up (keys = State/Province ID, values = 20 | State/Province name) 21 | 22 | ## Returns 23 | 24 | - null 25 | 26 | ## Availability 27 | 28 | - Available since 4.1 29 | 30 | ## Example 31 | 32 | The example below reorders the Irish State list so that Dublin is at the 33 | top of the list (by default, Dublin would be placed in the list in 34 | alphabetical order. 35 | 36 | /* 37 | * Implements hook_civicrm_buildStateProvinceForCountry(). 38 | * 39 | * Reorder the dublin states so that Dublin is at the top and dublin sub 40 | * states are ordered nicely. 41 | */ 42 | function ourclient_civicrm_buildStateProvinceForCountry( $countryID, &$states ) { 43 | // First separate out the Dublin options. 44 | $topStates = array(); 45 | foreach ($states as $key => $value) { 46 | if (preg_match('/Dublin/', $value)) { 47 | $topStates[$key] = $value; 48 | } 49 | else { 50 | $otherStates[$key] = $value; 51 | } 52 | } 53 | ksort($topStates); 54 | $states = $topStates + $otherStates; 55 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_buildUFGroupsForModule.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_buildUFGroupsForModule 2 | 3 | ## Summary 4 | 5 | This hook is called when ufgroups (profiles) are being built for a 6 | module. 7 | 8 | ## Notes 9 | 10 | The most common use case for this hook is to edit which profiles are 11 | visible on the Contact Dashboard or (Drupal) user registration page 12 | based on arbitrary criteria (e.g. whether the contact has a particular 13 | contact subtype). 14 | 15 | ## Availability 16 | 17 | This hook is available in CiviCRM 4.1+. 18 | 19 | ## Definition 20 | 21 | buildUFGroupsForModule($moduleName, &$ufGroups) 22 | 23 | ## Parameters 24 | 25 | - $moduleName - a string containing the module name (e.g. "User 26 | Registration", "User Account", "Profile", "CiviEvent"). 27 | - &$ufGroups - an array of ufgroups (profiles) available for the 28 | module. 29 | 30 | ## Returns 31 | 32 | - null -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_caseChange.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_caseChange 2 | 3 | ## Summary 4 | 5 | This hook fires whenever a record in a case changes. 6 | 7 | ## Notes 8 | 9 | See also the documentation for [CiviCase Util](https://wiki.civicrm.org/confluence/display/HR/CiviCase+Util). 10 | 11 | ## Availability 12 | 13 | This hook is available in CiviCRM 4.5+. 14 | 15 | ## Definition 16 | 17 | function caseChange(\Civi\CCase\Analyzer $analyzer) 18 | 19 | ## Parameters 20 | 21 | - $analyzer - A bundle of data about the case (such as the case and 22 | activity records). 23 | 24 | ## Returns 25 | 26 | - null -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_caseTypes.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_caseTypes 2 | 3 | ## Summary 4 | 5 | This hook defines available case types. 6 | 7 | ## Notes 8 | 9 | Note that this hook is actually an adapter 10 | for [hook_civicrm_managed](hook_civicrm_managed.md), so any case 11 | type defined inside this hook will be automatically 12 | inserted, updated, deactivated, and deleted in tandem with enabling, 13 | disabling, and uninstalling the module. For more background, see [API 14 | and the Art of 15 | Installation](http://civicrm.org/blogs/totten/api-and-art-installation). 16 | 17 | ## Definition 18 | 19 | hook_civicrm_caseTypes(&$caseTypes) 20 | 21 | ## Parameters 22 | 23 | - array **$caseTypes**list of case types; each item is an array with 24 | keys: 25 | - **'module'**: string; for module-extensions, this is the 26 | fully-qualifed name (e.g. "*com.example.mymodule*"); for Drupal 27 | modules, the name is prefixed by "drupal" (e.g. 28 | *"drupal.mymodule*") 29 | - **'name'**: string, a symbolic name which can be used to track 30 | this entity 31 | - **'file'**: string, the path to the XML file which defines the 32 | case-type 33 | 34 | ## Example 35 | 36 | function civitest_civicrm_caseTypes(&$caseTypes) { 37 | $caseTypes['MyCase'] = array( 38 | 'module' => 'org.example.mymodule', 39 | 'name' => 'MyCase', 40 | 'file' => __DIR__ . '/MyCase.xml', 41 | ); 42 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_check.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_check 2 | 3 | ## Summary 4 | 5 | This hook is called by the "System Check" api. 6 | 7 | ## Notes 8 | 9 | This runs on a regular basis (currently once a day, as well as whenever the status page is visited or `System.check` API is called). 10 | 11 | Typically your extension would add results by appending one or more 12 | `CRM_Utils_Check_Message` objects to the $messages array. Constructing 13 | a `CRM_Utils_Check_Message` requires the following parameters: 14 | 15 | - **Name:** A unique string for this type of message (no two messages in the array may have the same name). 16 | This will be the name given to a StatusPreference record if your message is hushed or disabled. 17 | - **Description:** Long description html string 18 | - **Title:** Short title plain text string 19 | - **Severity:** A [PSR-3 string](http://www.php-fig.org/psr/psr-3/). 20 | - **Icon:** A [font-awesome icon](https://fortawesome.github.io/Font-Awesome/icons/) string (optional). 21 | 22 | See `CRM_Utils_Check::checkAll` for more details about the system check api. 23 | 24 | ## Availability 25 | 26 | Introduced in CiviCRM v4.6.3. 27 | 28 | ## Definition 29 | 30 | hook_civicrm_check(&$messages) 31 | 32 | ## Parameters 33 | 34 | - **`&$messages`** `CRM_Utils_Check_Message[]`: Array of messages your hook can append to 35 | - **`$statusNames`** `array|null`: If only certain checks were requested, check this array and return early if your messages are not called for. 36 | - **`$includeDisabled`** `bool`: If your hook skips disabled checks (which it should!) this param tells you to bypass your skippage. 37 | 38 | ## Example 39 | 40 | /** 41 | * Implementation of hook_civicrm_check 42 | * 43 | * Add a check to the status page/System.check results if $snafu is TRUE. 44 | */ 45 | function mymodule_civicrm_check(&$messages, $statusNames, $includeDisabled) { 46 | 47 | // Early return if $statusNames doesn't call for our check 48 | if ($statusNames && !in_array('mymoduleSnafu', $statusNames)) { 49 | return; 50 | } 51 | 52 | // If performing your check is resource-intensive, consider bypassing if disabled 53 | if (!$includeDisabled) { 54 | $disabled = \Civi\Api4\StatusPreference::get() 55 | ->setCheckPermissions(FALSE) 56 | ->addWhere('is_active', '=', FALSE) 57 | ->addWhere('domain_id', '=', 'current_domain') 58 | ->addWhere('name', '=', 'mymoduleSnafu') 59 | ->execute()->count(); 60 | if ($disabled) { 61 | return; 62 | } 63 | } 64 | 65 | $snafu = (1 + 1 == 2); // Perform check here 66 | 67 | if ($snafu) { 68 | $messages[] = new CRM_Utils_Check_Message( 69 | 'mymoduleSnafu', 70 | ts('Situation normal, all funnied up'), 71 | ts('SNAFU Found'), 72 | \Psr\Log\LogLevel::WARNING, 73 | 'fa-flag' 74 | ) 75 | // Optionally add extended help 76 | ->addHelp(ts('This text will appear in a help bubble if the user clicks on the help icon.')); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_config.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_config 2 | 3 | ## Summary 4 | 5 | This hook is called soon after the `CRM_Core_Config` object has been 6 | initialized. 7 | 8 | ## Notes 9 | 10 | You can use this hook to modify the config object and hence 11 | behavior of CiviCRM dynamically. 12 | 13 | ## Definition 14 | 15 | hook_civicrm_config( &$config ) 16 | 17 | ## Parameters 18 | 19 | - $config the config object 20 | 21 | ## Example 22 | 23 | function civitest_civicrm_config( &$config ) { 24 | $civitestRoot = dirname( __FILE__ ) . DIRECTORY_SEPARATOR; 25 | 26 | // fix php include path 27 | $include_path = $civitestRoot . PATH_SEPARATOR . get_include_path( ); 28 | set_include_path( $include_path ); 29 | 30 | // fix template path 31 | $templateDir = $civitestRoot . 'templates' . DIRECTORY_SEPARATOR; 32 | $template =& CRM_Core_Smarty::singleton( ); 33 | array_unshift( $template->template_dir, $templateDir ); 34 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_contact_get_displayname.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_contact_get_displayname 2 | 3 | ## Summary 4 | 5 | This hook is called to retrieve the display name of a contact, allowing you to return a custom display name. 6 | 7 | ## Notes 8 | 9 | Probably you won't need this hook but in some case it might be useful. 10 | For example you want to show who is a manager of an organisation but you 11 | don't want to store this in the database. 12 | 13 | ## Definition 14 | 15 | civicrm_contact_get_displayname(&$display_name, $contactId, $objContact) 16 | 17 | ## Parameters 18 | 19 | - &$display_name - the current display name, you can change the 20 | display name by changing the contents of this parameter 21 | - $contactId - Contact ID 22 | - $objContact - The contact BAO 23 | 24 | ## Returns 25 | 26 | - null 27 | 28 | ## Example 29 | 30 | Below an example of showing the contact ID after the display name 31 | 32 | function myextension_civicrm_contact_get_displayname(&$display_name, $contactId, $objContact) { 33 | $display_name = $display_name . ' - '.$contactId; 34 | } 35 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_container.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_container 2 | 3 | ## Summary 4 | 5 | This hook modifies the CiviCRM container allowing you to add new services, parameters, 6 | extensions, etc. 7 | 8 | ## Notes 9 | 10 | !!! tip 11 | The container configuration will be compiled/cached. The default cache behavior is aggressive. When you first implement the hook, be sure to flush the cache. Additionally, you should relax caching during development. In `civicrm.settings.php`, set `define('CIVICRM_CONTAINER_CACHE', 'auto')`. 12 | 13 | !!! note 14 | As of CiviCRM version 5.27 CiviCRM now uses Symfony v3.4 or v4.4. There is an important change which is that in v3.3 Symfony services are now considered by default to be private. To ensure backwards compatibility you just need to add `->setPublic(TRUE)` after your definition in your code. This will make the service public as was the default originally in the Symfony 2.x series. If you don't need the service to be public, you can omit this. 15 | 16 | ## Availability 17 | 18 | This hook is available in CiviCRM 4.7+. 19 | 20 | ## Definition 21 | 22 | hook_civicrm_container(\Symfony\Component\DependencyInjection\ContainerBuilder $container) 23 | 24 | ## Parameters 25 | 26 | - $container - An object of type 27 | \Symfony\Component\DependencyInjection\ContainerBuilder. See 28 | [here](http://symfony.com/doc/current/components/dependency_injection/index.html). 29 | 30 | ## Returns 31 | 32 | - null 33 | 34 | ## Example 35 | 36 | ```php 37 | use Symfony\Component\Config\Resource\FileResource; 38 | use Symfony\Component\DependencyInjection\Definition; 39 | 40 | function mymodule_civicrm_container($container) { 41 | $container->addResource(new FileResource(__FILE__)); 42 | $container->setDefinition('mysvc', new Definition('My\Class', array()))->setPublic(TRUE); 43 | } 44 | ``` 45 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_copy.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_copy 2 | 3 | ## Summary 4 | 5 | This hook is called after a CiviCRM object (Event, ContributionPage, 6 | Profile) has been copied. 7 | 8 | ## Definition 9 | 10 | hook_civicrm_copy( $objectName, &$object ) 11 | 12 | ## Parameters 13 | 14 | - $objectName - the name of the object that is being copied (Event, 15 | ContributionPage, UFGroup) 16 | - $object - reference to the copied object 17 | 18 | ## Returns 19 | 20 | - null -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_coreResourceList.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_coreResourceList 2 | 3 | ## Summary 4 | 5 | This hook is called when the list of core js/css resources is about to 6 | be processed, giving you the opportunity to modify 7 | the list prior to the resources being added, or add your own. 8 | 9 | ## Notes 10 | 11 | Added in v4.6.6. 12 | 13 | See [Resource Reference](../framework/resources.md) 14 | for more information. 15 | 16 | ## Definition 17 | 18 | ```php 19 | hook_civicrm_coreResourceList(&$list, $region) 20 | ``` 21 | 22 | ## Parameters 23 | 24 | * `$list` - an array of items about to be added to the page. Items in the 25 | list may be: 26 | 27 | * A string ending in `.js` 28 | * A string ending in `.css` 29 | * An array of settings (will be added to the javascript CRM object). 30 | 31 | * `$region` - target region of the page - normally this is `"html-header"` 32 | 33 | ## Example 34 | 35 | 36 | ```php 37 | function myextension_civicrm_coreResourceList(&$list, $region) { 38 | // Prevent navigation.css from loading 39 | $cssWeDontWant = array_search('css/navigation.css', $list); 40 | unset($list[$cssWeDontWant]); 41 | 42 | // Add some css of our own to the page. 43 | // Note that if the file we want to add is outside civicrm directory 44 | // (e.g. in an extension) we can't just append it to the list. 45 | // But we can add it directly, which is what happens to items in this list anyway. 46 | Civi::resources()->addStyleFile('org.example.myextension', 'css/my_style.css', 0, $region); 47 | 48 | // Add a setting - in this example we override the CKEditor config file location 49 | $myCKEConfFile = Civi::resources()->getUrl('org.example.myextension', 'js/my-ckeditor-config.js'); 50 | $list[] = ['config' => ['CKEditorCustomConfig' => ['default' => $myCKEConfFile]]]; 51 | } 52 | ``` 53 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_cron.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_cron 2 | 3 | ## Summary 4 | 5 | This hook is called every time the CiviCRM scheduler is polled. 6 | 7 | ## Notes 8 | 9 | The timing and frequency with which this is called will vary depending on 10 | the system configuration. 11 | 12 | Introduced in CiviCRM v4.3. 13 | 14 | !!! note "This is a low-level approach" 15 | There are two ways to build on top of the CiviCRM scheduler. **hook_civicrm_cron** is a low-level approach which calls your code with an unpredictable schedule – in some systems, it could be once a day; in others, once every minute, every 5 minutes, every hour, every 2 hours, ad nauseum. You must ensure that your code will behave well in all these situations. Alternatively, the **Job API** is a higher-level approach by which you may register scheduled jobs ("Daily", "Hourly", etc), and the scheduler will make a best effort to match the declared scheduler. See, e.g., ["Create a Module Extension: How does one add a cron job"](../extensions/advanced.md##cron-jobs) 16 | 17 | 18 | ## Definition 19 | 20 | hook_civicrm_cron($jobManager) 21 | 22 | ## Parameters 23 | 24 | - CRM_Core_JobManager** $jobManager** 25 | 26 | ## Example 27 | 28 | /** 29 | * Implementation of hook_civicrm_cron 30 | * 31 | * Flag records in a custom table as dirty if they are over 2 days old. 32 | * Rerunning this logic at various times throughout the day should be safe 33 | * because there are no guarantees about when it will run. 34 | */ 35 | function example_civicrm_cron($jobManager) { 36 | CRM_Core_DAO::executeQuery('UPDATE my_table SET is_dirty = 1 WHERE last_modified < adddate(now(), "-2 day")'); 37 | } 38 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_crudLink.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_crudLink 2 | 3 | ## Summary 4 | 5 | Generate a default CRUD URL for an entity. 6 | 7 | ## Availability 8 | 9 | This hook is available in CiviCRM 4.5+. 10 | 11 | ## Definition 12 | 13 | crudLink($spec, $bao, &$link) 14 | 15 | ## Parameters 16 | 17 | - $spec - An array with keys: 18 | 19 | - action: int, eg CRM_Core_Action::VIEW or 20 | CRM_Core_Action::UPDATE 21 | - entity_table: string 22 | - entity_id: int 23 | - $bao CRM_Core_DAO 24 | 25 | - $link - An array. 26 | 27 | 28 | 29 | To define the link, add these keys to $link: 30 | 31 | - title: string 32 | 33 | - path: string 34 | 35 | - query: array 36 | 37 | - url: string (used in lieu of "path"/"query") 38 | 39 | Note: if making "url" CRM_Utils_System::url(), set $htmlize=false 40 | 41 | 42 | 43 | ## Returns 44 | 45 | - mixed -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_custom.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_custom 2 | 3 | ## Summary 4 | 5 | This hook is called *after* the database write on a custom table. 6 | 7 | ## Definition 8 | 9 | hook_civicrm_custom( $op, $groupID, $entityID, &$params ) 10 | 11 | ## Parameters 12 | 13 | - string $op - the type of operation being performed 14 | - string $groupID - the custom group ID 15 | - object $entityID - the entityID of the row in the custom table 16 | - array $params - the parameters that were sent into the calling 17 | function 18 | 19 | ## Returns 20 | 21 | - null - the return value is ignored 22 | 23 | ## Example 24 | 25 | /** 26 | * This example generates a custom contact ID (year + number, ex: 20080000001) 27 | */ 28 | 29 | function MODULENAME_civicrm_custom( $op, $groupID, $entityID, &$params ) { 30 | if ( $op != 'create' && $op != 'edit' ) { 31 | return; 32 | } 33 | 34 | if ($groupID == 1) { 35 | $needs_update = false; 36 | $tableName = CRM_Core_DAO::getFieldValue( 'CRM_Core_DAO_CustomGroup', 37 | $groupID, 38 | 'table_name' ); 39 | 40 | 41 | $sql = "SELECT member_id_4 FROM $tableName WHERE entity_id = $entityID"; 42 | $dao = CRM_Core_DAO::executeQuery( $sql, CRM_Core_DAO::$_nullArray ); 43 | 44 | if (! $dao->fetch()) { 45 | $needs_update = true; 46 | } 47 | 48 | // Value may also be empty. i.e. delete the value in the interface to reset the field. 49 | if (! $dao->member_id_4) { 50 | $needs_update = true; 51 | } 52 | 53 | if ($needs_update) { 54 | $member_id = date('Y') . sprintf('%07d', $entityID); 55 | 56 | $sql = "UPDATE $tableName SET member_id_4 = $member_id WHERE entity_id = $entityID"; 57 | CRM_Core_DAO::executeQuery( $sql, CRM_Core_DAO::$_nullArray ); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_customPre.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_customPre 2 | 3 | ## Summary 4 | 5 | This hook is called *before* the database write on a custom table. 6 | 7 | ## Definition 8 | 9 | hook_civicrm_customPre($op, $groupID, $entityID, &$params) 10 | 11 | ## Parameters 12 | 13 | - string $op - the type of operation being performed 14 | - string $groupID - the custom group ID 15 | - object $entityID - the entityID of the row in the custom table 16 | - array $params - the parameters that were sent into the calling function 17 | 18 | ## Returns 19 | 20 | - null - the return value is ignored 21 | 22 | ## Example 23 | 24 | /** 25 | * This example compares the submitted value of a field with its current value 26 | */ 27 | function MODULENAME_civicrm_customPre($op, $groupID, $entityID, &$params) { 28 | foreach ($params as $field) { 29 | if ($field['column_name'] == 'pipeline_stage') { 30 | //get existing value 31 | try { 32 | $existingValue = civicrm_api3('Contact', 'getvalue', [ 33 | 'id' => $field['entity_id'], 34 | 'return' => "custom_{$field['custom_field_id']}", 35 | ]); 36 | 37 | if ($existingValue != $field['value']) { 38 | //create Activity to record the change 39 | } 40 | } 41 | catch (CiviCRM_API3_Exception $e) {} 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_dashboard.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_dashboard 2 | 3 | ## Summary 4 | 5 | This hook is called when rendering the dashboard page and can be 6 | used to add content to the dashboard page. 7 | 8 | ## Definition 9 | 10 | hook_civicrm_dashboard( $contactID, &$contentPlacement = self::DASHBOARD_BELOW ) 11 | 12 | ## Parameters 13 | 14 | - $contactID the contactID for whom the dashboard is being generated 15 | - $contentPlacement (output parameter) where should the hook content 16 | be displayed relative to the activity list. One of 17 | CRM_Utils_Hook::DASHBOARD_BELOW, 18 | CRM_Utils_Hook::DASHBOARD_ABOVE, 19 | CRM_Utils_Hook::DASHBOARD_REPLACE. Default is to add content 20 | BELOW the standard dashboard Activities listing. DASHBOARD_REPLACE 21 | replaces the standard Activities listing with the provided content. 22 | 23 | ## Returns 24 | 25 | - the HTML to include in the dashboard 26 | 27 | ## Example 28 | ```php 29 | function civitest_civicrm_dashboard($contactID, &$contentPlacement) { 30 | // REPLACE Activity Listing with custom content 31 | $contentPlacement = 3; 32 | $content = array( 33 | 'Custom Content' => "Here is some custom content: $contactID", 34 | 'Custom Table' => " 35 | 36 | 37 | 38 | 39 |
Contact NameDate
FooBar
GooTar
", 40 | ); 41 | return $content; 42 | } 43 | ``` 44 | ### CiviTest example 45 | ```php 46 | function civitest_civicrm_dashboard_defaults($availableDashlets, &$defaultDashlets){ 47 | $contactID = CRM_Core_Session::singleton()->get('userID'); 48 | $defaultDashlets[] = array( 49 | 'dashboard_id' => 3, 50 | 'is_active' => 1, 51 | 'column_no' => 1, 52 | 'contact_id' => $contactID, 53 | ); 54 | } 55 | ``` 56 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_dashboard_defaults.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_dashboard_defaults 2 | 3 | ## Summary 4 | 5 | This hook is called while a contact views their dashboard for the first time and can be used to enable or disable the set of default dashlets. 6 | 7 | 8 | ## Definition 9 | 10 | hook_civicrm_dashboard_defaults($availableDashlets, &$defaultDashlets); 11 | 12 | ## Parameters 13 | 14 | - $availableDashlets - list of dashlets 15 | - $defaultDashlets - list of existing default dashlets 16 | 17 | ## Returns 18 | 19 | ## Example 20 | 21 | get('userID'); 24 | $defaultDashlets[] = array( 25 | 'dashboard_id' => 3, 26 | 'is_active' => 1, 27 | 'column_no' => 1, 28 | 'contact_id' => $contactID, 29 | ); 30 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_disable.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_disable 2 | 3 | ## Summary 4 | 5 | This hook is called when an extension is disabled. 6 | 7 | ## Notes 8 | 9 | To be specific, this hook is called when 10 | an extension's status changes from ***enabled*** to ***disabled**.* Each module 11 | will receive `hook_civicrm_disable` during its own disablement (but not 12 | during the disablement of unrelated modules). 13 | 14 | ## Parameters 15 | 16 | - None 17 | 18 | ## Returns 19 | 20 | - Void -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_emailProcessor.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_emailProcessor 2 | 3 | ## Summary 4 | 5 | This hook is called after *each* email has been processed by the script 6 | `bin/EmailProcessor.php`. 7 | 8 | ## Definition 9 | 10 | hook_civicrm_emailProcessor( $type, &$params, $mail, &$result, $action = null ) 11 | 12 | ## Parameters 13 | 14 | - @param string $type type of mail processed: 'activity' OR 'mailing' 15 | - @param array &$params the params that were sent to the CiviCRM API 16 | function 17 | - @param object $mail the mail object which is an ezcMail class 18 | - @param array &$result the result returned by the api call 19 | - @param string $action (optional ) the requested action to be 20 | performed if the types was 'mailing' 21 | 22 | ## Returns 23 | 24 | - null 25 | 26 | ## Availability 27 | 28 | This hook was first available in CiviCRM 3.4.0 -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_emailProcessorContact.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_emailProcessorContact 2 | 3 | ## Summary 4 | 5 | This hook is called by the Email Processor when deciding which 6 | contact to create an activitity for recording an inbound email. 7 | 8 | ## Notes 9 | 10 | You can use this hook to choose a different 11 | contact or decide whether it should create contacts. 12 | 13 | ## Definition 14 | 15 | hook_civicrm_emailProcessorContact($email, $contactID, &$result) 16 | 17 | ## Parameters 18 | 19 | - @param string $email - the email address 20 | - @param int $contactID - the contactID that matches this email address, IF it exists 21 | - @param array $result (reference) has two fields: 22 | - contactID - the new (or same) contactID 23 | - action - 3 possible values: 24 | - `CRM_Utils_Mail_Incoming::EMAILPROCESSOR_CREATE_INDIVIDUAL` - create a new contact record 25 | - `CRM_Utils_Mail_Incoming::EMAILPROCESSOR_OVERRIDE` - use the new contactID 26 | - `CRM_Utils_Mail_Incoming::EMAILPROCESSOR_IGNORE` - skip this email address 27 | 28 | ## Returns 29 | 30 | - null 31 | 32 | ## Availability 33 | 34 | This hook was first available in CiviCRM 4.1.0 35 | 36 | ## Example 37 | 38 | ```php 39 | function civitest_civicrm_emailProcessorContact($email, $contactID, &$result) { 40 | require_once 'CRM/Utils/Mail/Incoming.php'; 41 | 42 | // first split the email into name and domain 43 | // really simple, definitely wrong implementation 44 | list($mailName, $mailDomain) = CRM_Utils_System::explode('@', $email, 2); 45 | 46 | // we are doing all our checks based on mailDomain, so if empty 47 | // return and let EmailProcessor do its own thing 48 | if (empty($mailDomain)) { 49 | return; 50 | } 51 | 52 | define('FILE_TO_ORG_ALWAYS_TAG', 'MyTag1'); 53 | $orgID = _civitest_find_org_with_tag(FILE_TO_ORG_ALWAYS_TAG, $mailDomain); 54 | if ($orgID) { 55 | $result = array( 56 | 'contactID' => $orgID, 57 | 'action' => CRM_Utils_Mail_Incoming::EMAILPROCESSOR_OVERRIDE, 58 | ); 59 | return; 60 | } 61 | 62 | // if we already have a match, we will 63 | // return and let EmailProcessor do its own thing 64 | if ($contactID) { 65 | return; 66 | } 67 | 68 | // Orgs with this tag will have same-domain emails filed on them only if it 69 | // passes through the ALWAYS tag check without finding a match, AND it does 70 | // not match an individual. 71 | define('FILE_TO_ORG_INDIVIDUAL_UNMATCHED_TAG', 'MyTag2'); 72 | $orgID = _civitest_find_org_with_tag(FILE_TO_ORG_INDIVIDUAL_UNMATCHED_TAG, $mailDomain); 73 | if ($orgID) { 74 | $result = array( 75 | 'contactID' => $orgID, 76 | 'action' => CRM_Utils_Mail_Incoming::EMAILPROCESSOR_OVERRIDE); 77 | return; 78 | } 79 | 80 | $result = array('action' => CRM_Utils_Mail_Incoming::EMAILPROCESSOR_CREATE_INDIVIDUAL); 81 | } 82 | ``` 83 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_enable.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_enable 2 | 3 | ## Summary 4 | 5 | This hook is called when an extension is re-enabled. 6 | 7 | ## Notes 8 | 9 | To be specific, this hook is called when an extension's 10 | status changes from ***disabled*** to ***enabled.*** 11 | 12 | It is *NOT* called when the status changes from ***uninstalled*** to 13 | ***enabled***. Each module will receive `hook_civicrm_enable` during its 14 | own re-enablement (but not during the re-enablement of unrelated 15 | modules). 16 | 17 | For more background, see also [API and the Art of 18 | Installation](http://civicrm.org/blogs/totten/api-and-art-installation). 19 | 20 | ## Parameters 21 | 22 | - None 23 | 24 | ## Returns 25 | 26 | - Void -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_entityRefFilters.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_entityRefFilters 2 | 3 | ## Summary 4 | 5 | This hook is called when filters and create links for entityRef field is build. 6 | 7 | ## Definition 8 | 9 | hook_civicrm_entityRefFilters(&$filters, &$links) 10 | 11 | ## Parameters 12 | 13 | - array $filters - reference to list of filters 14 | - array $links - reference to list of create links 15 | 16 | ## Returns 17 | 18 | ## Example 19 | 20 | /** 21 | * Implements hook_civicrm_entityRefFilters(). 22 | * 23 | * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_entityRefFilters 24 | */ 25 | function modulename_civicrm_entityRefFilters(&$filters, &$links) { 26 | // Add New Staff link on entityRef field of contact 27 | $links['Contact'][] = [ 28 | 'label' => ts('New Staff'), 29 | 'url' => CRM_Utils_System::url('/civicrm/profile/create', 'reset=1&context=dialog&gid=5'), 30 | 'type' => 'Individual', 31 | 'icon' => 'fa-user', 32 | ]; 33 | 34 | // Add Do not email filter on contact entity ref field. 35 | $filters['Contact'][] = [ 36 | 'key' => 'do_not_email', 37 | 'value' => ts('Do Not Email'), 38 | ]; 39 | // Add Marital status filter on contact entity ref field. 40 | $filters['Contact'][] = [ 41 | 'key' => 'custom_2', 42 | 'value' => ts('Marital status'), 43 | ]; 44 | 45 | // Add custom field of address as filter on contact entity ref field. 46 | $filters['Contact'][] = [ 47 | 'key' => 'custom_34', 48 | 'value' => ts('Belongs to'), 49 | 'entity' => 'Address', 50 | ]; 51 | } 52 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_entityTypes.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_entityTypes 2 | 3 | ## Summary 4 | 5 | This hook is used to declare a new type of entity, for example a booking extension might want to declare a *Resource* entity. 6 | 7 | ## Notes 8 | 9 | [See this tutorial](../extensions/civix.md#generate-entity) for a more complete description of creating new types of entities. 10 | 11 | ## Definition 12 | 13 | ```php 14 | hook_civicrm_entityTypes(&$entityTypes) 15 | ``` 16 | 17 | ## Parameters 18 | 19 | * `$entityTypes` is a two-dimensional associative array. Each element in the array has: 20 | 21 | * A **key** which is the DAO name of the entity as a string (e.g. `'CRM_Report_DAO_Instance'`), although this has not always been enforced. 22 | 23 | * A **value** which is an associative with the following elements: 24 | 25 | * `'name'`: *string, required* - a unique short name (e.g. `"ReportInstance"`) 26 | 27 | * `'class'`: *string, required* - a PHP DAO class (e.g.`"CRM_Report_DAO_Instance"`) 28 | 29 | * `'table'`: *string, required* - a SQL table name (e.g. `"civicrm_report_instance"`) 30 | 31 | * `'fields_callback'`: *array, optional* - a list of callback functions which can modify the DAO field metadata. `function($class, &$fields)` Added circa 4.7.11+ 32 | 33 | * `'items_callback'`: *array, optional* - a list of callback functions which can modify the DAO foreign-key metadata. `function($class, &$links)` Added circa 4.7.11+ 34 | 35 | 36 | ## Returns 37 | 38 | * null 39 | 40 | ## Examples 41 | 42 | ### Add new entities 43 | 44 | This example is taken from CiviVolunteer [here](https://github.com/civicrm/org.civicrm.volunteer/blob/eafc2b0c3966a492a3080ac70abe06cbd960a00e/volunteer.php#L333). 45 | 46 | ```php 47 | /** 48 | * Implements hook_civicrm_apiWrappers(). 49 | */ 50 | function volunteer_civicrm_entityTypes(&$entityTypes) { 51 | $entityTypes[] = array( 52 | 'name' => 'VolunteerNeed', 53 | 'class' => 'CRM_Volunteer_DAO_Need', 54 | 'table' => 'civicrm_volunteer_need', 55 | ); 56 | $entityTypes[] = array( 57 | 'name' => 'VolunteerProject', 58 | 'class' => 'CRM_Volunteer_DAO_Project', 59 | 'table' => 'civicrm_volunteer_project', 60 | ); 61 | $entityTypes[] = array( 62 | 'name' => 'VolunteerProjectContact', 63 | 'class' => 'CRM_Volunteer_DAO_ProjectContact', 64 | 'table' => 'civicrm_volunteer_project_contact', 65 | ); 66 | } 67 | ``` 68 | 69 | ### Alter metadata for existing entities 70 | 71 | This functionality was added in (approximately) v4.7.11. 72 | 73 | ```php 74 | /** 75 | * Implements hook_civicrm_apiWrappers(). 76 | */ 77 | function apilogging_civicrm_entityTypes(&$entityTypes) { 78 | $entityTypes['CRM_Contact_DAO_Contact']['fields_callback'][] 79 | = function ($class, &$fields) { 80 | unset($fields['created_date']['export']); 81 | }; 82 | } 83 | ``` 84 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_eventDiscount.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_eventDiscount 2 | 3 | ## Summary 4 | 5 | This hook allows you to apply a customized discount to an event 6 | registration. 7 | 8 | ## Notes 9 | 10 | !!! caution 11 | This hook is outdated - notable, CiviDiscount does not make use of it. 12 | 13 | ## Definition 14 | 15 | eventDiscount(&$form, &$params) 16 | 17 | ## Parameters 18 | 19 | - &$form - An object of type CRM_Event_Form_Registration_Confirm. 20 | - &$params - An array containing $form->_params. 21 | 22 | ## Returns 23 | 24 | - mixed -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_fieldOptions.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_fieldOptions 2 | 3 | ## Summary 4 | 5 | This hook allows you to dynamically modify the option list for any field (including custom fields). 6 | 7 | ## Definition 8 | 9 | hook_civicrm_fieldOptions($entity, $field, &$options, $params) 10 | 11 | ## Parameters 12 | 13 | - **$entity** (string): API entity e.g. 'Contact', 'Email', 14 | 'Contribution' 15 | - **$field** (string): Name of field e.g. 'phone_type_id', 16 | 'custom_12' 17 | - **$options** (array): Array of key=>label options. Your hook may 18 | modify these at will. 19 | - **$params** (array): Parameters sent to the pseudoconstant lookup 20 | function. Especially noteworthy among them is *context*. 21 | 22 | ## See Also 23 | 24 | See [Pseudoconstant (option list) Reference](../framework/pseudoconstant.md) 25 | for more information about how option lists work and the *context* 26 | parameter. 27 | 28 | ## Example 29 | 30 | function example_civicrm_fieldOptions($entity, $field, &$options, $params) { 31 | if ($entity == 'Case' && $field == 'case_type_id') { 32 | if (!CRM_Core_Permission::check('access all cases and activities')) { 33 | // Remove access to certain case types for non-authorized users 34 | unset($options[3], $options[5]); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_fileSearches.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_fileSearches 2 | 3 | ## Summary 4 | 5 | This hook allows you to add a reference to a file search service (e.g. Solr). 6 | 7 | ## Availability 8 | 9 | This hook is available in CiviCRM 4.5+. 10 | 11 | ## Definition 12 | 13 | function fileSearches(&$fileSearches) 14 | 15 | ## Parameters 16 | 17 | - &$fileSearches - an array whose elements are all of type 18 | CRM_Core_FileSearchInterface. 19 | 20 | ## Returns 21 | 22 | - mixed 23 | 24 | ## Example 25 | 26 | function apachesolr_civiAttachments_civicrm_fileSearches(&$fileSearches) { 27 | require_once __DIR__ . '/DrupalSolrCiviAttachmentSearch.php'; 28 | $fileSearches[] = new DrupalSolrCiviAttachmentSearch(); 29 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_geocoderFormat.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_geocoderFormat 2 | 3 | ## Summary 4 | 5 | This hook allows you to manipulate the Address object during geocoding, 6 | for instance to extract additional fields from the geocoder's returned 7 | XML. 8 | 9 | ## Availability 10 | 11 | This hook was first available in CiviCRM 4.7.7. 12 | 13 | ## Definition 14 | 15 | hook_civicrm_geocoderFormat($geoProvider, &$values, $xml) 16 | 17 | ## Parameters 18 | 19 | - @param string $geoProvider - A short name for the geocoder. Core 20 | geocoders are 'Google' and 'Yahoo.' 21 | - @param array $values - The address that was passed to the geocoder. 22 | - @param SimpleXMLElement $xml - The response from the geocoder. 23 | 24 | 25 | 26 | 27 | 28 | ## Details 29 | 30 | ## Example 31 | 32 | **Populate the "county ID" field when using the Google geoprovider.** 33 | 34 | function countylookup_civicrm_geocoderFormat($geoProvider, &$values, $xml) { 35 | if($geoProvider !== 'Google') { 36 | exit; 37 | } 38 | foreach ($xml->result->address_component as $test) { 39 | $type = (string) $test->type[0]; 40 | if ($type == 'administrative_area_level_1') { 41 | $stateName = (string) $test->long_name; 42 | } 43 | if ($type == 'administrative_area_level_2') { 44 | $countyName = (string) $test->long_name; 45 | } 46 | } 47 | // Take off the word "County". 48 | $countyName = trim(str_replace('County', '', $countyName)); 49 | // For < 4.7 compatibility, do 2 API calls instead of a join 50 | $result = civicrm_api3('StateProvince', 'get', array( 51 | 'return' => array("id"), 52 | 'name' => $stateName, 53 | )); 54 | $state_province_id = $result['id']; 55 | $result = civicrm_api3('County', 'get', array( 56 | 'sequential' => 1, 57 | 'state_province_id' => $state_province_id, 58 | // 'state_province_id.name' => $stateName, 59 | 'name' => $countyName, 60 | )); 61 | $countyId = $result['id']; 62 | $values['county_id'] = $countyId; 63 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_getAssetUrl.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_getAssetUrl 2 | 3 | ## Summary 4 | 5 | This hook is called when building a link to a semi-static asset, allowing you to modify the params the asset will be built with. 6 | 7 | ## Notes 8 | 9 | For more discussion, see [AssetBuilder](../framework/asset-builder.md). 10 | 11 | ## Definition 12 | 13 | hook_civicrm_getAssetUrl(&$asset, &$params) 14 | 15 | ## Parameters 16 | 17 | * `$asset` (string): the logical file name of an asset (ex: `hello-world.json`) 18 | * `$params` (array): an optional set of parameters describing how to build the asset 19 | 20 | ## Returns 21 | 22 | * null 23 | 24 | ## Example 25 | 26 | ```php 27 | function mymodule_civicrm_getAssetUrl(&$asset, &$params) { 28 | if ($asset === 'hello-world.json') { 29 | $params['planet'] = 'Earth'; 30 | } 31 | } 32 | ``` 33 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_idsException.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_idsException 2 | 3 | ## Summary 4 | 5 | This hook allows you to modify the list of form or page paths where 6 | submitted data should not be sent through PHPIDS, the intrusion 7 | detection system (IDS). 8 | 9 | ## Notes 10 | 11 | This is one of two ways to bypass the IDS. The other is a CMS-level permission "skip IDS check". 12 | 13 | ## Definition 14 | 15 | hook_civicrm_idsException(&$skip) 16 | 17 | ## Parameters 18 | 19 | - $skip - an array of paths that should be skipped. 20 | 21 | The initial value of $skip is defined in CRM_Core_IDS::check(), which 22 | is where this hook is invoked. 23 | 24 | ## Returns 25 | 26 | - null 27 | 28 | ## Example 29 | 30 | /** 31 | * Implementation of hook_civicrm_idsException(). 32 | * 33 | * Prevent values on my form from being processed by the IDS 34 | */ 35 | function myextension_civicrm_idsException(&$skip) { 36 | $skip[] = 'civicrm/myform'; 37 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_inboundSMS.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_inboundSMS 2 | 3 | ## Summary 4 | 5 | This hook is called when an inbound SMS has been received, processed by the 6 | provider extension, but not matched or processed by CiviSMS. 7 | 8 | ## Availability 9 | 10 | 4.7.21+ 11 | 12 | ## Definition 13 | 14 | ```php 15 | hook_civicrm_inboundSMS(&$message) 16 | ``` 17 | 18 | ## Parameters 19 | 20 | * `CRM_SMS_Message` Object `$message` - The SMS Message 21 | 22 | 23 | ## Examples 24 | 25 | Alter the incoming SMS From number to match how phone numbers are stored in the database 26 | 27 | ```php 28 | function myextension_civicrm_inboundSMS(&$message) { 29 | // Alter the sender phone number to match the format used in database 30 | $message->from = str_replace('+614', '04', $message->from); 31 | } 32 | ``` 33 | 34 | Automatically add contacts to a group if the message contains 'SUBSCRIBE' 35 | 36 | ```php 37 | function myextension_civicrm_inboundSMS(&$message) { 38 | // Add contact to group if message contains keyword 39 | if (stripos($message->body, 'SUBSCRIBE') !== false) { 40 | $escapedFrom = CRM_Utils_Type::escape($message->from, 'String'); 41 | $message->fromContactID = CRM_Core_DAO::singleValueQuery('SELECT contact_id FROM civicrm_phone JOIN civicrm_contact ON civicrm_contact.id = civicrm_phone.contact_id WHERE !civicrm_contact.is_deleted AND phone LIKE "%' . $escapedFrom . '"'); 42 | if ($message->fromContactID) { 43 | CRM_Contact_BAO_GroupContact::AddContactsToGroup( 44 | array($message->fromContactID), 5, 'SMS', 'Added' 45 | ); 46 | } 47 | } 48 | } 49 | ``` 50 | 51 | Send an automatic response to incoming messages 52 | 53 | ```php 54 | function myextension_civicrm_inboundSMS(&$message) { 55 | // Send an automatic response 56 | $provider = CRM_SMS_Provider::singleton(array('provider_id' => 1)); 57 | $provider->send($message->from, array('To' => $message->from), 'Thank you for your message', NULL, NULL); 58 | } 59 | ``` 60 | 61 | Implement custom logic to match the message to the sender 62 | 63 | ```php 64 | function myextension_civicrm_inboundSMS(&$message) { 65 | // Implement custom matching logic 66 | // If there are multiple contacts with the phone number, preference the one that has been sent an SMS most recently 67 | $escapedFrom = CRM_Utils_Type::escape($message->from, 'String'); 68 | $message->fromContactID = CRM_Core_DAO::singleValueQuery(" 69 | SELECT civicrm_contact.id FROM civicrm_phone 70 | JOIN civicrm_contact ON civicrm_contact.id = civicrm_phone.contact_id 71 | LEFT JOIN civicrm_activity_contact ON civicrm_activity_contact.contact_id = civicrm_contact.id 72 | AND civicrm_activity_contact.record_type_id = 3 73 | LEFT JOIN civicrm_activity ON civicrm_activity.id = civicrm_activity_contact.activity_id 74 | AND civicrm_activity.activity_type_id = 4 75 | WHERE !civicrm_contact.is_deleted 76 | AND phone LIKE \"%" . $escapedFrom . "\" 77 | ORDER BY civicrm_activity.activity_date_time DESC" 78 | ); 79 | } 80 | ``` 81 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_install.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_install 2 | 3 | ## Summary 4 | 5 | This hook is called when an extension is installed. 6 | 7 | ## Notes 8 | 9 | To be specific, this hook is called when an extension's 10 | status changes from ***uninstalled*** to ***enabled*** 11 | 12 | It is *NOT* called when an extension moves from ***disabled*** to ***enabled*** 13 | (but `hook_civicrm_enable` is called at this event). Each module will 14 | receive `hook_civicrm_install` during its own installation (but not 15 | during the installation of unrelated modules). 16 | 17 | For more background, see [API and the Art of 18 | Installation](http://civicrm.org/blogs/totten/api-and-art-installation). 19 | 20 | ## Parameters 21 | 22 | - None 23 | 24 | ## Returns 25 | 26 | - Void -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_mailingGroups.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_mailingGroups 2 | 3 | ## Summary 4 | 5 | This hook is called when composing a mailing allowing you to include or exclude 6 | other groups as needed. 7 | 8 | ## Definition 9 | 10 | ```php 11 | hook_civicrm_mailingGroups(&$form, &$groups, &$mailings) 12 | ``` 13 | 14 | ## Parameters 15 | 16 | - object `$form` - the form object for which groups / mailings being displayed 17 | 18 | - array `$groups` - the list of groups being included / excluded 19 | 20 | - array `$mailings` - the list of mailings being included / excluded 21 | 22 | ## Returns 23 | 24 | - `NULL` - the return value is ignored 25 | 26 | ## Example 27 | 28 | ```php 29 | function civitest_civicrm_mailingGroups( &$form, &$groups, &$mailings ) { 30 | 31 | // unset group id 4 32 | unset( $groups[4] ); 33 | 34 | // add a fictitious mailing 35 | $mailings[1] = 'This mailing does not exist'; 36 | } 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_membershipTypeValues.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_membershipTypeValues 2 | 3 | ## Summary 4 | 5 | This hook is called when composing the array of membership types and 6 | their costs during a membership registration (new or renewal). 7 | 8 | ## Notes 9 | 10 | The hook is called on initial page load and also reloaded after submit ([PRG 11 | pattern](https://en.wikipedia.org/wiki/Post/Redirect/Get)). You can use it to alter the membership types when first 12 | loaded, or after submission (for example if you want to gather data in 13 | the form and use it to alter the fees). 14 | 15 | ## Definition 16 | 17 | ```php 18 | hook_civicrm_membershipTypeValues(&$form, &$membershipTypeValues) 19 | ``` 20 | 21 | ## Parameters 22 | 23 | - object `$form` - the form object that is presenting the page 24 | - array `$membershipTypeValues` - the membership types and their amounts 25 | 26 | ## Examples 27 | 28 | Give a 50% discount to some memberships in the sample data 29 | 30 | ```php 31 | function civitest_civicrm_membershipTypeValues(&$form, &$membershipTypeValues) { 32 | $membershipTypeValues[1]['name'] = 'General (50% discount)'; 33 | $membershipTypeValues[1]['minimum_fee'] = '50.00'; 34 | 35 | $membershipTypeValues[2]['name'] = 'Student (50% discount)'; 36 | $membershipTypeValues[2]['minimum_fee'] = '25.00'; 37 | } 38 | ``` 39 | 40 | Modify specific fee values 41 | 42 | ```php 43 | function mymodule_civicrm_membershipTypeValues(&$form, &$membershipTypeValues) { 44 | foreach ($membershipTypeValues as &$values) { 45 | if ($values['name'] == 'General') { 46 | $values['minimum_fee'] = "5.55"; 47 | } 48 | if ($values['name'] == 'Student') { 49 | $values['minimum_fee'] = "2.22"; 50 | } 51 | } 52 | } 53 | ``` 54 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_notePrivacy.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_notePrivacy 2 | 3 | ## Summary 4 | 5 | This hook provides a way to override the default privacy behavior for 6 | notes. 7 | 8 | ## Notes 9 | 10 | If a user has the "View All Notes" permission, this hook is bypassed. 11 | 12 | See also [this blog 13 | post](https://civicrm.org/blogs/allenshaw/adding-privacy-and-comments-civicrm-notes). 14 | 15 | ## Availability 16 | 17 | This hook is available in CiviCRM 3.3+. 18 | 19 | ## Definition 20 | 21 | ```php 22 | hook_civicrm_notePrivacy(&$noteValues) 23 | ``` 24 | 25 | ## Parameters 26 | 27 | - array `$noteValues` - The values from an object of type 28 | `CRM_Core_DAO_Note`, converted to an array. 29 | 30 | ## Returns 31 | 32 | - `NULL` 33 | 34 | ## Example 35 | 36 | ```php 37 | function civitest_civicrm_notePrivacy(&$noteValues) { 38 | /* CiviCRM will check for existence of $note['notePrivacy_hidden']. 39 | * If this value is not set, CiviCRM will show or display the note 40 | * based on the default, which is to display private notes only to 41 | * the note author. 42 | * If this value is set, CiviCRM will hide the note if the value is 43 | * TRUE, and display the note if the value is FALSE. 44 | */ 45 | if ($noteValues['is_private']) { 46 | if ($my_business_rules_say_so) { 47 | $noteValues['notePrivacy_hidden'] = TRUE; 48 | } 49 | else { 50 | $noteValues['notePrivacy_hidden'] = FALSE; 51 | } 52 | } 53 | } 54 | ``` 55 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_optionValues.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_optionValues 2 | 3 | ## Summary 4 | 5 | This hook was deprecated in 4.7 in favor of [hook_civicrm_fieldOptions](hook_civicrm_fieldOptions.md). 6 | 7 | ## Notes 8 | 9 | This hook is called after a option group is loaded. You can use this 10 | hook to add/remove options from the option group. 11 | 12 | Use [hook_civicrm_fieldOptions](hook_civicrm_fieldOptions.md) instead for modifying all option lists, not limited to items in the `civicrm_option_values` table. 13 | 14 | ## Definition 15 | 16 | ```php 17 | hook_civicrm_optionValues(&$options, $groupName) 18 | ``` 19 | 20 | ## Parameters 21 | 22 | - array `$options` - the current set of options 23 | - string `$groupName` - the name of the option group 24 | 25 | ## Returns 26 | 27 | - `NULL` 28 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_pageRun.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_pageRun 2 | 3 | ## Summary 4 | 5 | This hook is called before a CiviCRM page is rendered. 6 | 7 | 8 | ## Notes 9 | 10 | This does **not** execute on every CiviCRM *page* in the 11 | general sense. CiviCRM's pages are classified as either 'Forms' or 12 | 'Pages', and this only runs on pages classified as 'Pages'. If you are 13 | not sure if a particular page is a Page, test it by adding some 14 | temporary debug code to `/CRM/Utils/Hook.php` 15 | 16 | ## Definition 17 | 18 | hook_civicrm_pageRun( &$page ) 19 | 20 | ## Parameters 21 | 22 | - $page the page being rendered 23 | 24 | ## Returns 25 | 26 | - null 27 | 28 | ## Example 29 | 30 | The example below is for the enhanced tags extension. In this extension 31 | a coordinator can be assigned to a CiviCRM tag. In the pageRun hook 32 | below the coordinators are added to an array which is sent to the page 33 | template 34 | 35 | function enhancedtags_civicrm_pageRun(&$page) { 36 | $pageName = $page->getVar('_name'); 37 | if ($pageName == 'CRM_Admin_Page_Tag') { 38 | /* 39 | * retrieve all tag enhanced data and put in array with tag_id as index 40 | */ 41 | $enhancedTags = CRM_Enhancedtags_BAO_TagEnhanced::getValues(array()); 42 | $coordinators = array(); 43 | foreach ($enhancedTags as $enhancedTag) { 44 | $coordinators[$enhancedTag['tag_id']] = CRM_Enhancedtags_BAO_TagEnhanced::getCoordinatorName($enhancedTag['coordinator_id']); 45 | } 46 | $page->assign('coordinators', $coordinators); 47 | } 48 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_postEmailSend.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_postEmailSend 2 | 3 | ## Summary 4 | 5 | This hook is called when an email has been successfully sent by CiviCRM, 6 | but not on an error. 7 | 8 | 9 | ## Notes 10 | 11 | This is only triggered by activity emails, not bulk mailings. 12 | 13 | ## Definition 14 | 15 | hook_civicrm_postEmailSend( &$params ) 16 | 17 | ## Parameters 18 | 19 | - $params the mailing params 20 | 21 | ## Details 22 | 23 | - $params array fields include: groupName, from, toName, toEmail, 24 | subject, cc, bcc, text, html, returnPath, replyTo, headers, 25 | attachments (array) 26 | 27 | ## Example 28 | 29 | /** 30 | * Implementation of hook_civicrm_postEmailSend( ) 31 | * Update the status of activity created in hook_civicrm_alterMailParams, and add target_contact_id 32 | */ 33 | function mte_civicrm_postEmailSend(&$params) { 34 | // check if an activityId was added in hook_civicrm_alterMailParams 35 | // if so, update the activity's status and add a target_contact_id 36 | if(CRM_Utils_Array::value('activityId', $params)){ 37 | $activityParams = array( 38 | 'id' => $params['activityId'], 39 | 'status_id' => 2, 40 | 'version' => 3, 41 | 'target_contact_id' => CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Email', $params['toEmail'], 'contact_id', 'email'), 42 | ); 43 | $result = civicrm_api( 'activity','create',$activityParams ); 44 | } 45 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_postIPNProcess.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_postIPNProcess 2 | 3 | ## Summary 4 | 5 | This hook allows you to do custom processing of IPN Data following CiviCRM processing. 6 | 7 | ## Notes 8 | 9 | This hook as present only calls when CiviCRM has successfully processed the IPN. 10 | 11 | With this hook you can take any of the data including custom data stored via hook_civicrm_alterPaymentProcessorParms into the IPN. 12 | 13 | ## Definition 14 | 15 | hook_civicrm_postIPNProcess(&$IPNData); 16 | 17 | ## Parameters 18 | 19 | - $IPNData - Array of IPN data recieved from a payment processor. 20 | 21 | ## Returns 22 | 23 | ## Example 24 | 25 | ```php 26 | function civitest_civicrm_postIPNProcess(&$IPNData) { 27 | if (!empty($IPNData['custom'])) { 28 | $customParams = json_decode($IPNData['custom'], TRUE); 29 | if (!empty($customParams['gaid'])) { 30 | // trigger GA event id for e-commerce tracking. 31 | } 32 | } 33 | } 34 | ``` 35 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_postInstall.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_postInstall 2 | 3 | ## Summary 4 | 5 | This hook is called immediately after an extension is installed. 6 | 7 | ## Notes 8 | 9 | - Unlike most CiviCRM hooks, hook_civicrm_postInstall is defined not 10 | in CRM_Utils_Hook but in CRM_Extension_Manager_Module. 11 | - Each module will receive hook_civicrm_postInstall after its own 12 | installation (but not following the installation of unrelated 13 | modules). 14 | 15 | ## Definition 16 | 17 | hook_civicrm_postInstall() 18 | 19 | ## Parameters 20 | 21 | - None 22 | 23 | ## Returns 24 | 25 | - Void 26 | 27 | ## Example 28 | 29 | This hook may be useful as a final installation step. Use it to perform 30 | tasks which depend on something that is a product of the installation 31 | itself. 32 | 33 | For example, as of civix version 16.9.0, it is used to record the schema 34 | version number (i.e., which upgrade_N methods have run) in the 35 | civicrm_extension table. This step has to be performed in 36 | hook_civicrm_postInstall because the record doesn't yet exist to be 37 | updated in hook_civicrm_install. 38 | 39 | Another potential use is to act on settings or managed entities that are 40 | created during the installation (but not necessarily in order that you 41 | want them to be created): 42 | 43 | function hook_civicrm_postInstall() { 44 | $customFieldId = civicrm_api3('CustomField', 'getvalue', array( 45 | 'return' => array("id"), 46 | 'name' => "customFieldCreatedViaManagedHook", 47 | )); 48 | civicrm_api3('Setting', 'create', array( 49 | 'myWeirdFieldSetting' => array('id' => $customFieldId, 'weirdness' => 1), 50 | )); 51 | } 52 | 53 | 54 | 55 | 56 | 57 | 58 | \ -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_postJob.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_postJob 2 | 3 | ## Summary 4 | 5 | This hook is called after a scheduled job is executed or was interrupted by an exception. 6 | 7 | ## Notes 8 | 9 | We suspect this hook will be useful for developers who want to monitor the execution time of scheduled jobs or check whether a job is stuck (started but never ends). It can also be used to monitor the execution status of jobs. It is useful in combination with the hook `hook_civicrm_preJob`. 10 | 11 | ## Definition 12 | 13 | ```php 14 | hook_civicrm_postJob($job, $params, $result) 15 | ``` 16 | 17 | ## Parameters 18 | 19 | - $job - instance of CRM_Core_DAO_Job, the executed job 20 | - $params - array of arguments given to the job 21 | - $result - It can be: 22 | + the array returned by the API call of the job 23 | + the exception that interrupted the execution of the job 24 | 25 | ## Return 26 | None 27 | 28 | ## Example 29 | 30 | ```php 31 | function sencivity_civicrm_postJob($job, $params, $result) { 32 | if ($result['is_error']) { 33 | CRM_Core_Error::debug_log_message("Job $job->name failed!"); 34 | } 35 | } 36 | ``` 37 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_postMailing.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_postMailing 2 | 3 | ## Summary 4 | 5 | This hook is called at the successful completion of a bulk mailing done through CiviMail. 6 | 7 | ## Definition 8 | 9 | hook_civicrm_postMailing( $mailingId ) 10 | 11 | ## Parameters 12 | 13 | - $mailingId : the ID for the mailing 14 | 15 | ## Example 16 | 17 | /** 18 | * Implementation of hook_civicrm_postMailing() 19 | */ 20 | function myextension_civicrm_postMailing($mailingId) { 21 | $report = CRM_Mailing_BAO_Mailing::report($mailingId); 22 | if (!empty($report['created_id'])) { 23 | // Store activity in mailing creator's record 24 | $params = array( 25 | 'status_id' => 2, 26 | 'target_contact_id' => $report['created_id'], 27 | 'source_contact_id' => 1, 28 | 'activity_type_id' => 1, 29 | 'subject' => "Mailing $mailingId has completed.", 30 | 'activity_date_time' => 'now', 31 | ); 32 | civicrm_api3('Activity', 'create', $params); 33 | } 34 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_postSave_table_name.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_postSave_table_name 2 | 3 | ## Summary 4 | 5 | This hook is called after writing to a database table that has an 6 | associated DAO, including core tables but not custom tables or log 7 | tables. 8 | 9 | ## Parameters 10 | 11 | $dao: The object that has been saved 12 | 13 | ## Definition 14 | 15 | `hook_civicrm_postSave_[table_name]($dao)` 16 | 17 | ## Example 18 | 19 | hook_civicrm_postSave_civicrm_contact($dao) { 20 | $contact_id = $dao->id; 21 | // Do something with this contact, but be careful not to create an infinite loop if you update it via the api! This hook will get called again with every update. 22 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_post_case_merge.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_post_case_merge 2 | 3 | ## Summary 4 | 5 | This hook is called after a case merge happens. 6 | 7 | ## Notes 8 | 9 | A case merge is when two cases are merged or when a case is reassigned to another client. 10 | 11 | Added in CIviCRM 4.5 12 | 13 | ## Definition 14 | 15 | civicrm_post_case_merge($mainContactId, $mainCaseId, $otherContactId, $otherCaseId, $changeClient) 16 | 17 | ## Parameters 18 | 19 | - $mainContactId - Contact ID of the new case (if set already) 20 | - $mainCaseId - Case ID of the new case (if set already) 21 | - $otherContactId - Contact ID of the original case 22 | - $otherCaseId - Case ID of the original case 23 | - $changeClient - boolean if this function is called to change 24 | clients 25 | 26 | ## Return 27 | 28 | - Returns null 29 | 30 | ## Example 31 | 32 | In this example we want to move the linked documents of a case to the 33 | new case. 34 | 35 | function documents_civicrm_post_case_merge($mainContactId, $mainCaseId = NULL, $otherContactId = NULL, $otherCaseId = NULL, $changeClient = FALSE) { 36 | $repo = CRM_Documents_Entity_DocumentRepository::singleton(); 37 | if (!empty($mainCaseId) && !empty($otherCaseId)) { 38 | $docs = $repo->getDocumentsByCaseId($otherCaseId); 39 | $case = civicrm_api('Case', 'getsingle', array('id' => $otherCaseId, 'version' => 3)); 40 | foreach($docs as $doc) { 41 | $doc->addCaseId($mainCaseId); 42 | if ($changeClient) { 43 | $doc->removeCaseId($otherCaseId); //remove the old case 44 | } 45 | foreach($case['client_id'] as $cid) { 46 | $doc->addContactId($cid); 47 | } 48 | $repo->persist($doc); 49 | } 50 | } 51 | } 52 | 53 | 54 | 55 | ## See also 56 | 57 | [hook_civicrm_pre_case_merge](hook_civicrm_pre_case_merge.md) -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_preJob.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_preJob 2 | 3 | ## Summary 4 | 5 | This hook is called before a scheduled job is executed. 6 | 7 | ## Notes 8 | 9 | This hook does not allow aborting the job execution or modifying its parameters. 10 | 11 | We suspect this hook will be useful for developers who want to monitor the execution time of scheduled jobs or check whether a job is stuck (started but never ends). It is useful in combination with the hook `hook_civicrm_postJob`. 12 | 13 | ## Definition 14 | 15 | ```php 16 | hook_civicrm_preJob($job, $params) 17 | ``` 18 | 19 | ## Parameters 20 | 21 | - $job - instance of CRM_Core_DAO_Job, the job to be executed 22 | - $params - array of arguments to be given to the job 23 | 24 | ## Return 25 | None 26 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_preProcess.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_preProcess 2 | 3 | ## Summary 4 | 5 | This hook can be used to modify the behavior of a form before the 6 | `buildQuickForm` call. 7 | 8 | 9 | ## Notes 10 | 11 | There are some known issues with exception 12 | handling: [https://issues.civicrm.org/jira/browse/CRM-15683](https://issues.civicrm.org/jira/browse/CRM-15683). 13 | 14 | ## Definition 15 | 16 | hook_civicrm_preProcess($formName, &$form) 17 | 18 | 19 | ## Parameters 20 | 21 | - string $formName - the name of the form 22 | - object $form - reference to the form object 23 | 24 | ## Returns 25 | 26 | - null - the return value is ignored -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_pre_case_merge.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_pre_case_merge 2 | 3 | ## Summary 4 | 5 | This hook is called before a case merge happens. 6 | 7 | ## Notes 8 | 9 | A case merge is 10 | when two cases are merged or when a case is reassigned to another 11 | client. 12 | 13 | Added in CiviCRM 4.5 14 | 15 | ## Definition 16 | 17 | civicrm_pre_case_merge($mainContactId, $mainCaseId, $otherContactId, $otherCaseId, $changeClient) 18 | 19 | ## Parameters 20 | 21 | - $mainContactId - Contact ID of the new case (if set already) 22 | - $mainCaseId - Case ID of the new case (if set already) 23 | - $otherContactId - Contact ID of the original case 24 | - $otherCaseId - Case ID of the original case 25 | - $changeClient - boolean if this function is called to change 26 | clients 27 | 28 | ## Return 29 | 30 | - Returns null 31 | 32 | ## Example 33 | 34 | See for an example the documentation of the 35 | [hook_civicrm_post_case_merge](hook_civicrm_post_case_merge.md) 36 | 37 | ## See also 38 | 39 | [hook_civicrm_post_case_merge](hook_civicrm_post_case_merge.md) -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_processProfile.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_processProfile 2 | 3 | ## Summary 4 | 5 | This hook is called when processing a valid profile form submission (e.g. for "civicrm/profile/create" or "civicrm/profile/edit"). 6 | 7 | ## Definition 8 | 9 | processProfile($profileName) 10 | 11 | ## Parameters 12 | 13 | - $profileName - the (machine readable) name of the profile. 14 | 15 | !!! Tip 16 | In SQL, this corresponds to the "name" column of table "civicrm_uf_group" 17 | 18 | ## Returns 19 | 20 | - null -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_queryObjects.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_queryObjects 2 | 3 | ## Summary 4 | 5 | This hook is called while building the core search query, allowing you to provide your own query objects which alter or extend the core search. 6 | 7 | ## Definition 8 | 9 | hook_civicrm_queryObjects(&$queryObjects, $type = 'Contact') 10 | 11 | ## Parameters 12 | 13 | - $queryObjects - An array of Query Objects 14 | - $type - Search Context \ 15 | \ 16 | 17 | ## Example 18 | 19 | /** Taken from civiHR:/hrjob/hrjob.php **/ 20 | 21 | function hrjob_civicrm_queryObjects(&$queryObjects, $type) { 22 | if ($type == 'Contact') { 23 | $queryObjects[] = new CRM_HRJob_BAO_Query(); 24 | } 25 | elseif ($type == 'Report') { 26 | $queryObjects[] = new CRM_HRJob_BAO_ReportHook(); 27 | } 28 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_recent.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_recent 2 | 3 | ## Summary 4 | 5 | This hook is called before storing recently viewed items. 6 | 7 | ## Definition 8 | 9 | recent(&$recentArray) 10 | 11 | ## Parameters 12 | 13 | - $recentArray - An array of recently viewed or processed items, for 14 | in place modification. 15 | 16 | ## Returns 17 | 18 | - array -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_referenceCounts.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_referenceCounts 2 | 3 | ## Summary 4 | 5 | This hook is called to determine the reference-count for a record. 6 | 7 | ## Notes 8 | 9 | For example, when counting references to the activity type "Phone Call", one 10 | would want a tally that includes: 11 | 12 | - The number of activity records which use "Phone Call" 13 | - The number of surveys which store data in "Phone Call" records 14 | - The number of case-types which can embed "Phone Call" records 15 | 16 | The reference-counter will automatically identify references stored in 17 | the CiviCRM SQL schema, including: 18 | 19 | - Proper SQL foreign-keys (declared with an SQL constraint) 20 | - Soft SQL foreign-keys that use the "entity_table"+"entity_id" 21 | pattern 22 | - Soft SQL foreign-keys that involve an OptionValue 23 | 24 | However, if you have references to stored in an external system (such as 25 | XML files or Drupal database), then you may want write a custom 26 | reference-counters. 27 | 28 | ## Definition 29 | 30 | hook_civicrm_referenceCounts($dao, &$refCounts) 31 | 32 | ## Parameters 33 | 34 | - $dao: ***CRM_Core_DAO***, the item for which we want a reference 35 | count 36 | - $refCounts: ***array***, each item in the array is an array with 37 | keys: 38 | - name: ***string***, eg 39 | "sql:civicrm_email:contact_id" 40 | - type: ***string***, eg "sql" 41 | - count: ***int***, eg "5" if there are 5 email addresses that 42 | refer to $dao 43 | 44 | ## Returns 45 | 46 | - None 47 | 48 | ## Example 49 | 50 | Suppose we've written a module ("familytracker") which relies on the 51 | "Child Of" relationship-type. Now suppose an administrator considered 52 | deleting "Child Of" -- we might want to determine if anything depends on 53 | "Child Of" and display a warning about possible breakage. This code 54 | would allow the "familytracker" to increase the reference-count for 55 | "Child Of". 56 | 57 | name_a_b == 'Child Of') { 60 | $refCounts[] = array( 61 | 'name' => 'familytracker:childof', 62 | 'type' => 'familytracker', 63 | 'count' => 1, 64 | ); 65 | } 66 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_searchProfile.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_searchProfile 2 | 3 | ## Summary 4 | 5 | This hook is called while preparing a list of contacts (based on a 6 | profile). 7 | 8 | ## Definition 9 | 10 | searchProfile($profileName) 11 | 12 | ## Parameters 13 | 14 | - $profileName - the (machine readable) name of the profile. 15 | 16 | ## Returns 17 | 18 | - null -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_searchTasks.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_searchTasks 2 | 3 | ## Summary 4 | 5 | This hook is called to display the list of actions allowed after doing a 6 | search, allowing you to inject additional actions or to remove existing actions. 7 | 8 | ## Definition 9 | 10 | hook_civicrm_searchTasks( $objectType, &$tasks ) 11 | 12 | ## Parameters 13 | 14 | - $objectType - the object for this search - activity, campaign, 15 | case, contact, contribution, event, grant, membership, and pledge 16 | are supported. 17 | - $tasks - the current set of tasks for that custom field. You can 18 | add/remove existing tasks. Each task is an array with a title (eg 19 | 'title' => ts( 'Add Contacts to Group')) and a class (eg 'class' 20 | => 'CRM_Contact_Form_Task_AddToGroup'). Optional result 21 | (boolean) may also be provided. Class can be an array of classes 22 | (not sure what that does :( ). The key for new Task(s) should not 23 | conflict with the keys for core tasks of that $objectType, which 24 | can be found in CRM/$objectType/Task.php. 25 | 26 | ## Returns 27 | 28 | - null 29 | 30 | ## Example (Disable an existing task) 31 | 32 | function civitest_perm () { 33 | return array( 34 | 'access add contacts to group search action' 35 | ); 36 | } 37 | 38 | 39 | function civitest_civicrm_searchTasks($objectType, &$tasks ) { 40 | if ( $objectType == 'contact' ) { 41 | // remove the action from the contact search results if the user doesn't have the permission 42 | if (! user_access( 'access add contacts to group search action' )) { 43 | unset($tasks[CRM_Core_Task::GROUP_ADD]); 44 | } 45 | } 46 | } 47 | 48 | ## Example (Add a new task) 49 | 50 | function smsconversation_civicrm_searchTasks( $objectName, &$tasks ){ 51 | if($objectName == 'contact'){ 52 | $tasks[] = [ 53 | 'title' => 'SMS - schedule a conversation', 54 | 'class' => 'CRM_SmsConversation_Form_ScheduleMultiple' 55 | ]; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_selectWhereClause.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_selectWhereClause 2 | 3 | ## Summary 4 | 5 | This hook is called when executing a SELECT query. 6 | 7 | ## Notes 8 | 9 | The hook is called 10 | once for each entity in the query, allowing you to add (or remove) 11 | restrictions specific to that entity. Note that this hook will only be 12 | invoked for API calls if check_permissions is set to 1. It will be 13 | bypassed for API calls that do not set this parameter. 14 | 15 | This hook is new in 4.7 and coverage is limited. The Case entity is 16 | fully covered by this hook; selecting cases via api, ui, or searches 17 | will all invoke this hook. Most other entities are covered when being 18 | selected via api but not in the UI or searches. 19 | 20 | This hook is part of a general permissions refactoring which is not yet 21 | complete. 22 | 23 | The Contact entity is fully covered 24 | by [hook_civicrm_aclWhereClause](hook_civicrm_aclWhereClause.md) 25 | and that is the recommended hook for limiting access to contacts. For 26 | other entities, we need to increase coverage of this hook by using the 27 | api internally instead of directly executing sql, and by standardizing 28 | searches to use these permissions. 29 | 30 | ## Definition 31 | 32 | hook_civicrm_selectWhereClause($entity, &$clauses) 33 | 34 | ## Parameters 35 | 36 | - string $entity - name of entity being selected - follows api naming 37 | conventions (Contact, EntityTag, etc.) 38 | - array $clauses - (reference) array of clauses keyed by field\ 39 | Uses the format array('field_name' => array('operator 40 | condition')) 41 | 42 | ## Returns 43 | 44 | - void 45 | 46 | ## Example 47 | 48 | function example_civicrm_selectWhereClause($entity, &$clauses) { 49 | // Restrict access to cases by type 50 | if ($entity == 'Case') { 51 | $clauses['case_type_id'][] = 'IN (1,2,3)'; 52 | } 53 | } 54 | 55 | If your condition depends on joining onto another table, use a subquery, 56 | like so: 57 | 58 | function example_civicrm_selectWhereClause($entity, &$clauses) { 59 | // Restrict access to emails by contact type 60 | if ($entity == 'Email') { 61 | $clauses['contact_id'][] = "IN (SELECT id FROM civicrm_contact WHERE contact_type = 'Individual')"; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_summary.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_summary 2 | 3 | ## Summary 4 | 5 | This hook is called when the contact summary is rendered, allowing you to modify the summary with your own content. 6 | 7 | ## Definition 8 | 9 | hook_civicrm_summary( $contactID, &$content, &$contentPlacement = CRM_Utils_Hook::SUMMARY_BELOW ) 10 | 11 | ## Parameters 12 | 13 | - $contactID the contactID for whom the contact summary is being 14 | generated 15 | - $contentPlacement (output parameter) where should the hook content 16 | be displayed relative to the exiting content. One of 17 | CRM_Utils_Hook::SUMMARY_BELOW, CRM_Utils_Hook::SUMMARY_ABOVE, 18 | CRM_Utils_Hook::SUMMARY_REPLACE. Default is to add content BELOW 19 | default contact summary content. 20 | 21 | ## Example 22 | 23 | function civitest_civicrm_summary( $contactID, &$content, &$contentPlacement ) { 24 | // REPLACE default Contact Summary with your customized content 25 | $contentPlacement = CRM_Utils_Hook::SUMMARY_REPLACE; 26 | $content = " 27 | 28 | 29 | 30 | 31 |
Hook Data
Data 1
Data 2
32 | "; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_summaryActions.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_summaryActions 2 | 3 | ## Summary 4 | 5 | This hook allows you to customize the context menu actions on the Contact 6 | Summary Page. 7 | 8 | ## Definition 9 | 10 | hook_civicrm_summaryActions( &$actions, $contactID ) 11 | 12 | ## Parameters 13 | 14 | - `$actions` Array of all Actions in contextMenu. Each action item is 15 | itself an array that can contain the items below **(this is not the 16 | full list)**:\ 17 | \ 18 | - `title:` the text that appears in the action menu 19 | - `weight:` a number defining the "weight" - i.e where should the 20 | item sit in the action menu 21 | - `ref:` this is appended to the string "crm-action-record-" and 22 | becomes the list items CSS class (each action is a `li` element) 23 | - `key:` this is the array key that identifies the action 24 | - `href:` a URL that you want the link to navigate to 25 | - `permissions:` an array that contains permissions a user must 26 | have in order to use this action\ 27 | \ 28 | - `$contactID` contactID for the summary page. 29 | 30 | ## Example 31 | 32 | **Removing some action items** 33 | 34 | function civitest_civicrm_summaryActions( &$actions, $contactID ){ 35 | $customizeActions = array('contribution', 'note', 'rel'); 36 | foreach( $actions as $key => $value ) { 37 | if( in_array( $key, $customizeActions ) ) { 38 | unset( $actions[$key] ); 39 | } 40 | } 41 | } 42 | 43 | **Add an item to the action list** 44 | 45 | function mymodulename_civicrm_summaryActions(&$actions, $contactID) 46 | { 47 | $actions['casework'] = array( 48 | 'title' => 'Record casework', 49 | 'weight' => 999, 50 | 'ref' => 'record-casework', 51 | 'key' => 'casework', 52 | 'href' => '/casework/recording_form 53 | ); 54 | } 55 | 56 | **Add an item to the third column of action list** 57 | 58 | function mymodulename_civicrm_summaryActions(&$actions, $contactID) 59 | { 60 | $actions['otherActions']['casework'] = array( 61 | 'title' => 'Record casework', 62 | 'weight' => 999, 63 | 'ref' => 'record-casework', 64 | 'key' => 'casework', 65 | 'href' => '/casework/recording_form 66 | ); 67 | } 68 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_tabs.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_tabs 2 | 3 | ## Summary 4 | 5 | This hook was deprecated in 4.7 in favor of [hook_civicrm_tabset](hook_civicrm_tabset.md). 6 | 7 | ## Notes 8 | 9 | This hook is called when composing the tabs to display when viewing a 10 | contact 11 | 12 | ## Definition 13 | 14 | hook_civicrm_tabs( &$tabs, $contactID ) 15 | 16 | ## Parameters 17 | 18 | - $tabs - the array of tabs that will be displayed 19 | - $contactID - the contactID for whom the view is being rendered 20 | 21 | ## Returns 22 | 23 | - null - the return value is ignored 24 | 25 | ## Example 26 | 27 | function civitest_civicrm_tabs( &$tabs, $contactID ) { 28 | 29 | // unset the contribition tab, i.e. remove it from the page 30 | unset( $tabs[1] ); 31 | 32 | // let's add a new "contribution" tab with a different name and put it last 33 | // this is just a demo, in the real world, you would create a url which would 34 | // return an html snippet etc. 35 | $url = CRM_Utils_System::url( 'civicrm/contact/view/contribution', 36 | "reset=1&snippet=1&force=1&cid=$contactID" ); 37 | // $url should return in 4.4 and prior an HTML snippet e.g. '

....'; 38 | // in 4.5 and higher this needs to be encoded in json. E.g. json_encode(array('content' => )); 39 | // or CRM_Core_Page_AJAX::returnJsonResponse($content) where $content is the html code 40 | // in the first cases you need to echo the return and then exit, if you use CRM_Core_Page method you do not need to worry about this. 41 | $tabs[] = array( 'id' => 'mySupercoolTab', 42 | 'url' => $url, 43 | 'title' => 'Contribution Tab Renamed', 44 | 'weight' => 300 ); 45 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_themes.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_themes 2 | 3 | ## Summary 4 | 5 | This hook is called when building a list of available themes for use within CiviCRM. 6 | 7 | ## Definition 8 | 9 | hook_civicrm_themes( &$themes ) 10 | 11 | ## Parameters 12 | 13 | - array $themes - array of theme information 14 | - ext: string (required) 15 | The full name of the extension which defines the theme. 16 | Ex: "org.civicrm.themes.greenwich". 17 | - title: string (required) 18 | Visible title. 19 | - help: string (optional) 20 | Description of the theme's appearance. 21 | - url_callback: mixed (optional) 22 | A function ($themes, $themeKey, $cssExt, $cssFile) which returns the URL(s) for a CSS resource. 23 | Returns either an array of URLs or PASSTHRU. 24 | Ex: \Civi\Core\Themes\Resolvers::simple (default) 25 | Ex: \Civi\Core\Themes\Resolvers::none 26 | - prefix: string (optional) 27 | A prefix within the extension folder to prepend to the file name. 28 | - search_order: array (optional) 29 | A list of themes to search. 30 | Generally, the last theme should be "*fallback*" (Civi\Core\Themes::FALLBACK). 31 | - excludes: array (optional) 32 | A list of files (eg "civicrm:css/bootstrap.css" or "$ext:$file") which should never 33 | be returned (they are excluded from display). - object being imported (for now Contact 34 | 35 | ## Returns 36 | 37 | - null 38 | 39 | ## Availability 40 | 41 | - This hook was first available in CiviCRM 5.16 42 | 43 | ## Example 44 | 45 | A minimal example: 46 | 47 | ```php 48 | /* 49 | * A theme is a set of CSS files which are loaded on CiviCRM pages. 50 | */ 51 | function civitest_civicrm_themes( &$themes ) { 52 | $themes['civielection'] = [ 53 | 'title' => 'civielection theme', 54 | 'ext' => 'au.org.greens.civielection', 55 | ]; 56 | } 57 | ``` 58 | 59 | A more detailed example 60 | 61 | ```php 62 | /* 63 | * A theme is a set of CSS files which are loaded on CiviCRM pages. 64 | */ 65 | function civitest_civicrm_themes( &$themes ) { 66 | $themes['civielection'] = [ 67 | 'title' => 'civielection theme', 68 | 'ext' => 'au.org.greens.civielection', 69 | 'name' => 'civielection', 70 | 'url_callback' => '\\Civi\\Core\\Themes\\Resolvers::simple', 71 | 'search_order' => [ 72 | 0 => 'civielection', 73 | 1 => Civi\Core\Themes::FALLBACK, 74 | ], 75 | 'prefix' => 'election', 76 | 'excludes' => ['bootstrap.css'], 77 | ]; 78 | } 79 | ``` 80 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_tokenValues.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_tokenValues 2 | 3 | ## Summary 4 | 5 | This hook is called to get all the values for the tokens registered. 6 | 7 | ## Notes 8 | 9 | Use it to overwrite or reformat existing token values, or supply the values 10 | for custom tokens you have defined in 11 | [hook_civicrm_tokens](hook_civicrm_tokens.md). See [this 12 | article](https://civicrm.org/blog/colemanw/create-your-own-tokens-for-fun-and-profit) for 13 | usage examples. 14 | 15 | ## Definition 16 | 17 | ```php 18 | hook_civicrm_tokenValues(&$values, $cids, $job = null, $tokens = [], $context = null) 19 | ``` 20 | 21 | ## Parameters 22 | 23 | - $values - array of values, keyed by contact id 24 | - $cids - array of contactIDs that the system needs values for. 25 | - $job - the job_id 26 | - $tokens - tokens used in the mailing - use this to check whether a 27 | token is being used and avoid fetching data for unneeded tokens 28 | - $context - the class name 29 | 30 | ## Returns 31 | 32 | - null 33 | 34 | ## Example 35 | 36 | ```php 37 | function customtokens_civicrm_tokenValues(&$values, $cids, $job = null, $tokens = [], $context = null) { 38 | $group = 'team'; 39 | if(isset($tokens[$group])) { 40 | $token = 'team_number'; 41 | if (!customtokens_isTokenRequested($tokens, $group, $token)) { 42 | return; 43 | } 44 | 45 | foreach ($cids as $cid) { 46 | // get team (employer) id 47 | $individualResult = civicrm_api3('Contact', 'getsingle', [ 48 | 'return' => ["current_employer_id"], 49 | 'contact_id' => $cid, 50 | ]); 51 | 52 | // if there is a team (employer) id, get team number for the team (employer) 53 | if(!$individualResult['is_error'] && isset($individualResult['current_employer_id']) && strlen($individualResult['current_employer_id'])){ 54 | 55 | $teamResult = civicrm_api3('Contact', 'getsingle', [ 56 | 'return' => ["custom_70"], 57 | 'id' => $individualResult['current_employer_id'], 58 | ]); 59 | 60 | // if there is a team number, display it as the token 61 | if(!$teamResult['is_error'] && isset($teamResult['custom_70'])) { 62 | $values[$cid]['team.team_number'] = $teamResult['custom_70']; 63 | } 64 | } 65 | } 66 | } 67 | } 68 | 69 | /** 70 | * "Send an Email" and "CiviMail" send different parameters to the tokenValues hook (in CiviCRM 5.x). 71 | * This works around that. 72 | * 73 | * @param array $tokens 74 | * @param string $group 75 | * @param string $token 76 | * 77 | * @return bool 78 | */ 79 | function customtokens_isTokenRequested($tokens, $group, $token) { 80 | // CiviMail sets $tokens to the format: 81 | // [ 'group' => [ 'token_name' => 1 ] ] 82 | // "Send an email" sets $tokens to the format: 83 | // [ 'group' => [ 0 => 'token_name' ] ] 84 | if (array_key_exists($token, $tokens[$group]) || in_array($token, $tokens[$group])) { 85 | return TRUE; 86 | } 87 | return FALSE; 88 | } 89 | ``` 90 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_tokens.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_tokens 2 | 3 | ## Summary 4 | 5 | This hook is called to allow custom tokens to be defined. 6 | 7 | ## Notes 8 | 9 | The token values 10 | will need to be supplied by 11 | [hook_civicrm_tokenValues](hook_civicrm_tokenValues.md). 12 | 13 | See [this article](https://civicrm.org/blog/colemanw/create-your-own-tokens-for-fun-and-profit) 14 | for usage examples. 15 | 16 | ## Definition 17 | 18 | ```php 19 | hook_civicrm_tokens(&$tokens) 20 | ``` 21 | 22 | ## Parameters 23 | 24 | - $tokens: reference to the associative array of custom tokens that 25 | are available to be used in mailings and other contexts. This will 26 | be an empty array unless an implementation of hook_civicrm_tokens 27 | adds items to it. Items should be added in this format: 28 | 29 | ```php 30 | $tokens['date'] = [ 31 | 'date.date_short' => ts("Today's Date: short format"), 32 | 'date.date_med' => ts("Today's Date: med format"), 33 | 'date.date_long' => ts("Today's Date: long format"), 34 | ]; 35 | $tokens['party'] = [ 36 | 'party.balloons' => ts("Number of balloons"), 37 | ]; 38 | ``` 39 | 40 | ## Returns 41 | 42 | - null 43 | 44 | ## Example 45 | 46 | ```php 47 | function customtokens_civicrm_tokens(&$tokens) { 48 | $tokens['team'] = [ 49 | 'team.team_number' => 'Team number', 50 | ]; 51 | } 52 | ``` 53 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_triggerInfo.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_triggerInfo 2 | 3 | ## Summary 4 | 5 | This hook allows you to define MySQL triggers. 6 | 7 | ## Notes 8 | 9 | Using the hooks causes them not to clash with 10 | core or other extension triggers. They are compiled into one trigger 11 | with core triggers. 12 | 13 | !!! note 14 | Once the function is created, visit the following URL to rebuild triggers 15 | and create to create the new trigger: 16 | 17 | `http://example.com/civicrm/menu/rebuild?reset=1&triggerRebuild=1` 18 | 19 | 20 | ## Definition 21 | 22 | ```php 23 | hook_civicrm_triggerInfo(&$info, $tableName) 24 | ``` 25 | 26 | ## Parameters 27 | 28 | * array `$info` - array of triggers to be created 29 | * string `$tableName` - not sure how this bit works 30 | 31 | 32 | 33 | ## Returns 34 | 35 | - ?? 36 | 37 | 38 | ## Example 39 | 40 | Add trigger to update custom region field based on postcode (using a lookup 41 | table) 42 | 43 | Note that this example uses hard-coded a prioritisation of location types 44 | (since it was customer specific code and unlikely to change). 45 | 46 | ```php 47 | function regionfields_civicrm_triggerInfo(&$info, $tableName) { 48 | $table_name = 'civicrm_value_region_13'; 49 | $customFieldID = 45; 50 | $columnName = 'region_45'; 51 | $sourceTable = 'civicrm_address'; 52 | $locationPriorityOrder = '1, 3, 5, 2, 4, 6'; // hard coded prioritisation of addresses 53 | $zipTable = 'CANYRegion'; 54 | if(civicrm_api3('custom_field', 'getcount', array('id' => $customFieldID, 'column_name' => 'region_45', 'is_active' => 1)) == 0) { 55 | return; 56 | } 57 | 58 | $sql = " 59 | REPLACE INTO `$table_name` (entity_id, $columnName) 60 | SELECT * FROM ( 61 | SELECT contact_id, b.region 62 | FROM 63 | civicrm_address a INNER JOIN $zipTable b ON a.postal_code = b.zip 64 | WHERE a.contact_id = NEW.contact_id 65 | ORDER BY FIELD(location_type_id, $locationPriorityOrder ) 66 | ) as regionlist 67 | GROUP BY contact_id; 68 | "; 69 | $sql_field_parts = array(); 70 | 71 | $info[] = array( 72 | 'table' => $sourceTable, 73 | 'when' => 'AFTER', 74 | 'event' => 'INSERT', 75 | 'sql' => $sql, 76 | ); 77 | $info[] = array( 78 | 'table' => $sourceTable, 79 | 'when' => 'AFTER', 80 | 'event' => 'UPDATE', 81 | 'sql' => $sql, 82 | ); 83 | // For delete, we reference OLD.contact_id instead of NEW.contact_id 84 | $sql = str_replace('NEW.contact_id', 'OLD.contact_id', $sql); 85 | $info[] = array( 86 | 'table' => $sourceTable, 87 | 'when' => 'AFTER', 88 | 'event' => 'DELETE', 89 | 'sql' => $sql, 90 | ); 91 | } 92 | ``` 93 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_unhandledException.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_unhandledException 2 | 3 | ## Summary 4 | 5 | This hook fires when an unhandled exception (fatal error) occurs. 6 | 7 | ## Notes 8 | 9 | A use case is to show an alternative page to donors rather than a fatal 10 | error screen if a fatal error occurs during a donation. 11 | 12 | ## Availability 13 | 14 | This hook is available in CiviCRM 4.6+. 15 | 16 | ## Definition 17 | 18 | unhandledException($exception, $request = NULL) 19 | 20 | ## Parameters 21 | 22 | - $exception - An object of type CRM_Core_Exception Exception. 23 | - $request - Reserved for future use. 24 | 25 | ## Returns 26 | 27 | - null -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_uninstall.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_uninstall 2 | 3 | ## Summary 4 | 5 | This hook is called when an extension is uninstalled. 6 | 7 | ## Notes 8 | 9 | To be specific, when its status changes from ***disabled*** to ***uninstalled***. 10 | 11 | Each module will receive `hook_civicrm_uninstall` during its own 12 | uninstallation (but not during the uninstallation of unrelated modules). 13 | 14 | ## Parameters 15 | 16 | - None 17 | 18 | ## Returns 19 | 20 | - Void -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_unsubscribeGroups.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_unsubscribeGroups 2 | 3 | ## Summary 4 | 5 | This hook is called when CiviCRM receives a request to unsubscribe a 6 | user from a mailing. 7 | 8 | ## Availability 9 | 10 | Introduced in CiviCRM v4.2 11 | 12 | ## Definition 13 | 14 | hook_civicrm_unsubscribeGroups($op, $mailingId, $contactId, &$groups, &$baseGroups) 15 | 16 | ## Parameters 17 | 18 | - - string $op - hard coded to be unsubscribe 19 | 20 | - int $mailingId - the id of the mailing sent that originated 21 | this unsubscribe request 22 | - int $contactId - the id of the contact that wishes to be 23 | unsubscribed 24 | - array $groups - the list of groups that the contact will be 25 | removed from 26 | - array $baseGroups - the list of base groups (for smart 27 | mailings) that the contact will be removed from 28 | 29 | ## Example 30 | 31 | function civitest_civicrm_unsubscribeGroups( $op, $mailingId, $contactId, &$groups, &$baseGroups ) { 32 | // do the below for even mailing ids only 33 | // in a real implementation, you will have some logic to restrict what mailings 34 | // you want to handle the unsub via a different patch 35 | // this hook basically redirects you to a custom unsubscribe page 36 | // thanx to parvez @ veda consulting for this example 37 | if ($op == 'unsubscribe' && $mailingId % 2 == 0) { 38 | $oConfig = CRM_Core_Config::singleton(); 39 | $sUnsubscribeRedirectUrl = $oConfig->unsubscribe_redirect_url; 40 | if ( !empty( $sUnsubscribeRedirectUrl ) ) { 41 | CRM_Utils_System::redirect( $sUnsubscribeRedirectUrl ); 42 | } else { 43 | CRM_Core_Error::statusBounce( 'Unsubscribe URL has not been set.' ); 44 | } 45 | CRM_Utils_System::civiExit(); 46 | } 47 | } -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_upgrade.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_upgrade 2 | 3 | ## Summary 4 | 5 | This hook is called when an administrator visits the "Manage Extensions" 6 | screen to determine if there are any pending upgrades. 7 | 8 | ## Notes 9 | 10 | As of version 4.7, it is also called periodically by [CiviCRM's system status 11 | utility](https://docs.civicrm.org/user/en/stable/initial-set-up/civicrm-system-status/). 12 | 13 | If there are upgrades, and if the administrator chooses to execute them, 14 | the hook is called a second time to construct a list of upgrade tasks. 15 | 16 | ## Definition 17 | 18 | hook_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) 19 | 20 | ## Parameters 21 | 22 | - $op - the type of operation being performed; 'check' or 'enqueue' 23 | - $queue - (for 'enqueue') the modifiable list of pending up upgrade 24 | tasks 25 | 26 | ## Returns 27 | 28 | - For 'check' operations, return array(bool) (TRUE if an upgrade is 29 | required) 30 | - For 'enqueue' operations, return void -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_validate.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_validate 2 | 3 | ## Summary 4 | 5 | **(Removed)** This hook is invoked during all CiviCRM form validation. An array of errors 6 | detected is returned. Else we assume validation succeeded. 7 | 8 | ## Availability 9 | 10 | This hook was **removed in v4.7**. 11 | 12 | ## Definition 13 | 14 | ```php 15 | hook_civicrm_validate($formName, &$fields, &$files, &$form) 16 | ``` 17 | ## Parameters 18 | 19 | * string `$formName` - The name of the form. 20 | * array `&$fields` - the POST parameters as filtered by QF 21 | * array `&$files` - the FILES parameters as sent in by POST 22 | * array `&$form` - the form object 23 | 24 | ## Returns 25 | 26 | * mixed - formRule hooks return a boolean or an array of error messages which display a QF Error 27 | -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_validateProfile.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_validateProfile 2 | 3 | ## Summary 4 | 5 | This hook is called while validating a profile form submission. 6 | 7 | ## Definition 8 | 9 | validateProfile($profileName) 10 | 11 | ## Parameters 12 | 13 | - $profileName - the (machine readable) name of the profile. 14 | 15 | ## Returns 16 | 17 | - null -------------------------------------------------------------------------------- /docs/hooks/hook_civicrm_viewProfile.md: -------------------------------------------------------------------------------- 1 | # hook_civicrm_viewProfile 2 | 3 | ## Summary 4 | 5 | This hook is called while preparing a read-only profile screen. 6 | 7 | ## Definition 8 | 9 | viewProfile($profileName) 10 | 11 | ## Parameters 12 | 13 | - $profileName - the (machine readable) name of the profile. 14 | 15 | ## Returns 16 | 17 | - null -------------------------------------------------------------------------------- /docs/hooks/usage/drupal.md: -------------------------------------------------------------------------------- 1 | The Drupal documentation has great information about 2 | [hooks in general][drupal-hooks], 3 | [configuration to enable hooks for your module][hooks-config], 4 | and [this guide][hooks-intro] on starting out with hooks. 5 | 6 | In order to start using hooks with a Drupal-based CiviCRM installation, you or 7 | your administrator needs to do the following: 8 | 9 | 1. Create a file with the extension .info (for instance, myhooks.info) 10 | containing the following lines. Replace the example text in the first 2 11 | lines with something appropriate for your organization, and assign 7.x 12 | to core if you use Drupal 7. 13 | 14 | name = My Organization's Hooks 15 | description = Module containing the CiviCRM hooks for my organization 16 | dependencies[] = civicrm 17 | package = CiviCRM 18 | core = 7.x 19 | version = 7.x-1.0 20 | 21 | 2. Create a new file with the extension *.module* (for instance, 22 | *myhooks.module*) to hold your PHP functions. 23 | 3. Upload both the *.info* and *.module* files to the server running CiviCRM, 24 | creating a new directory for them under */sites/all/modules* (for 25 | instance, */sites/all/modules/myhooks/*) inside your Drupal installation. 26 | The directory name you create should be short and contain only lowercase 27 | letters, digits, and underlines without spaces. 28 | 4. Enable your new hooks module through the Drupal administration page. 29 | 30 | Additionally, if you are using Drupal and add a new hook to an existing module, 31 | you will need to clear the cache for the hook to start operating. One way of 32 | doing this is by visiting the page Admin > Build > Modules. 33 | 34 | ## Inspecting Hooks 35 | 36 | The documentation about hooks can be somewhat abstract, and it sometimes 37 | helps to see interactively how the hooks run. 38 | 39 | - If you use Drupal, then you can inspect some hooks by installing 40 | these two Drupal modules: 41 | - [devel](http://drupal.org/project/devel) 42 | - [civicrm\_developer](https://github.com/eileenmcnaughton/civicrm_developer) 43 | 44 | [drupal-hooks]: https://www.drupal.org/docs/7/creating-custom-modules/understanding-the-hook-system-for-drupal-modules 45 | [hooks-config]: https://www.drupal.org/docs/7/creating-custom-modules/telling-drupal-about-your-module 46 | [hooks-intro]: https://www.drupal.org/docs/7/creating-custom-modules/writing-comments-and-implementing-your-first-hook -------------------------------------------------------------------------------- /docs/img/CMS_URL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/civicrm/civicrm-dev-docs/4693cbeec0027b6203eceb5f8603f2f48e4490db/docs/img/CMS_URL.png -------------------------------------------------------------------------------- /docs/img/CiviCRM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/civicrm/civicrm-dev-docs/4693cbeec0027b6203eceb5f8603f2f48e4490db/docs/img/CiviCRM.png -------------------------------------------------------------------------------- /docs/img/Jenkis_Show_Results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/civicrm/civicrm-dev-docs/4693cbeec0027b6203eceb5f8603f2f48e4490db/docs/img/Jenkis_Show_Results.png -------------------------------------------------------------------------------- /docs/img/api-or-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/civicrm/civicrm-dev-docs/4693cbeec0027b6203eceb5f8603f2f48e4490db/docs/img/api-or-example.png -------------------------------------------------------------------------------- /docs/img/financial/FinancialAccount.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/civicrm/civicrm-dev-docs/4693cbeec0027b6203eceb5f8603f2f48e4490db/docs/img/financial/FinancialAccount.png -------------------------------------------------------------------------------- /docs/img/gitlab-reference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/civicrm/civicrm-dev-docs/4693cbeec0027b6203eceb5f8603f2f48e4490db/docs/img/gitlab-reference.png -------------------------------------------------------------------------------- /docs/img/index.md: -------------------------------------------------------------------------------- 1 | This folder contains images for the CiviCRM demo documentation. 2 | -------------------------------------------------------------------------------- /docs/img/inheritance-community-chest.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/civicrm/civicrm-dev-docs/4693cbeec0027b6203eceb5f8603f2f48e4490db/docs/img/inheritance-community-chest.jpg -------------------------------------------------------------------------------- /docs/img/mysql_workbench_civicrm_country_foreign_keys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/civicrm/civicrm-dev-docs/4693cbeec0027b6203eceb5f8603f2f48e4490db/docs/img/mysql_workbench_civicrm_country_foreign_keys.png -------------------------------------------------------------------------------- /docs/img/mysql_workbench_civicrm_country_tables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/civicrm/civicrm-dev-docs/4693cbeec0027b6203eceb5f8603f2f48e4490db/docs/img/mysql_workbench_civicrm_country_tables.png -------------------------------------------------------------------------------- /docs/img/quickform-lifecycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/civicrm/civicrm-dev-docs/4693cbeec0027b6203eceb5f8603f2f48e4490db/docs/img/quickform-lifecycle.png -------------------------------------------------------------------------------- /docs/img/repository-access.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/civicrm/civicrm-dev-docs/4693cbeec0027b6203eceb5f8603f2f48e4490db/docs/img/repository-access.png -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # CiviCRM Developer Guide 2 | 3 | [CiviCRM](https://civicrm.org) is an open-source application. The code can be poked, prodded, twisted, and hacked. It can be customized, extended, and collaboratively developed. This documentation tells you how to do that. 4 | 5 | It starts with a high level introduction to get you familiar with CiviCRM development. It covers setting up your development environment, checking whether or not you actually need to implement your own custom code (i.e. you can't achieve what you want through configuration or installing an already existing extension), best practice ways to extend CiviCRM (a.k.a. how to write an extension), things you should know before you start hacking on core, and best practice for testing. 6 | 7 | The guide also includes detailed references for tools and subsystems of CiviCRM. These cover topics like the API and hook system and are intended for use by people that are familiar with CiviCRM development. 8 | 9 | ## Editing this guide 10 | 11 | * This guide is made with MkDocs and stored in a [GitHub repository](https://github.com/civicrm/civicrm-dev-docs). 12 | * See the "[Writing Documentation](documentation/index.md)" section in this guide for specific details on editing this guide. 13 | 14 | ## Credits 15 | 16 | This guide is collaboratively written by the CiviCRM community, with facilitation from the [Documentation Working Group](https://civicrm.org/working-groups/documentation). 17 | -------------------------------------------------------------------------------- /docs/security/access.md: -------------------------------------------------------------------------------- 1 | # Access Control in CiviCRM 2 | 3 | ## Introduction 4 | 5 | CiviCRM has a system of Access Control Lists (ACLs) which allow administrators to customise what information groups of their users are able to see. ACLs work alongside the system of permissions set out by CiviCRM which is integrated in the Content Management System's Permissions structure. 6 | 7 | ## Context 8 | 9 | Access Control is used to control access to CiviCRM data and functionality. This is done through Access Control Lists (ACL's). An ACL consists of: 10 | 11 | 1. A Role that has permission to do this operation ('Administrator', 'Team Leader'), 12 | 2. An Operation (e.g. 'View' or 'Edit'), and 13 | 3. A set of Data that the operation can be performed on (e.g. a group of contacts) 14 | 15 | Example: there may be a role called "Team Leaders" that can "Edit" all the contacts within the "Active Volunteers Group" 16 | 17 | ## Within Code 18 | 19 | Much of the ACL control process happens within the `CRM/ACL/Api.php` file and `CRM/ACL/BAO/Acl.php` file. These files demonstrate how the ACL is used to add clauses to the WHERE statement of queries that are generated within CiviCRM. Many of these functions will be called from within the relevant CMS system files in `CRM/Utils/System/xxx.php` where xxx is the UF name of your CMS. e.g. Drupal 7 is Drupal, Drupal 8 is Drupal8 etc. These functions are usually checked at run time and are very low level. 20 | 21 | ## Extending ACLs 22 | 23 | There are a few ACL hooks that allow developers in their extension to extend the implementation of various ACLs for their own purposes. 24 | 25 | - [`hook_civicrm_aclGroup`](../hooks/hook_civicrm_aclGroup.md) This hook alters what entities (e.g. CiviCRM Groups, CiviCRM Events) an end user is able to see. 26 | 27 | - [`hook_civicrm_aclWhereClause`](../hooks/hook_civicrm_aclWhereClause.md) This hook adds extra SQL statements when the ACL contact cache table is to be filled up. Depending on how frequently your ACL cache is cleared this may become taxing on your database. 28 | 29 | - [`hook_civicrm_selectWhereClause`](../hooks/hook_civicrm_selectWhereClause.md) This hook was introduced in 4.7 and allows you to add specific restrictions or remove restrictions when querying specific entities. This is different to `hook_civicrm_aclWhereClause` because that only deals with contacts and limiting of contacts and also `hook_civicrm_selectWhereClause` is run every time a select query for that entity is run. 30 | 31 | It should be noted that especially with `hook_civicrm_selectWhereClause` there is little CiviCRM Core test coverage on these items so it is always very important that administrators test their own ACLs when testing any upgrade to CiviCRM. 32 | -------------------------------------------------------------------------------- /docs/security/reporting.md: -------------------------------------------------------------------------------- 1 | # Reporting a Security Vulnerability 2 | 3 | ## Introduction 4 | 5 | CiviCRM Core Team and Security Team are responsible for fixing reported security issues within [supported CiviCRM versions](https://civicrm.org/download). Security releases will only be made for those versions with active CiviCRM support, at which point [Security Advisories](https://civicrm.org/advisory) will be issued. 6 | 7 | ## Release Timing. 8 | 9 | CiviCRM maintains two security release windows, they are the first and third Wednesday of every month US/PDT Timezone. Having a release window doesn't mean that a release will occur, but it does allow for site administrators to be conscious of when there may be a security update. 10 | 11 | ## Reporting a Security bug 12 | 13 | CiviCRM maintains an email address [security@civicrm.org](mailto:security@civicrm.org) as the primary mechanism for reporting security issues. When you report an issue, please include all possible information that would help the Security Team replicate and help solve the issue. Unless you request anonymity, you will be credited for your role in reporting the issue as well as any other roles you take in resolving it. 14 | 15 | ## Security Policy 16 | 17 | CiviCRM has a publicly available [Security Policy](https://civicrm.org/security) which details these points and goes into some further detail around our security practices. 18 | -------------------------------------------------------------------------------- /docs/standards/database.md: -------------------------------------------------------------------------------- 1 | # Database standards 2 | 3 | The following standards apply to the database layer in CiviCRM: 4 | 5 | 1. Every BAO will have a create function. This will be called by the API & form layer. 6 | 1. The create function will take a single params array. 7 | 1. Depending on the parameters passed in, the create function will perform any additional actions like creating activities. 8 | 1. The create function will call hooks. 9 | 1. We are moving away from the `$ids` array being included. 10 | 1. The add function (if it exists) will be internal to the BAO layer. 11 | 1. If any additional actions are to be done when deleting the BAO there should be a function `del` which takes the entity id as the only required parameter. 12 | 1. The delete action will take any additional tasks like deleting additional objects (generally done by code). 13 | 1. The delete action will take an array including `['id']`. 14 | 1. The api will call the `del` action & fall back onto delete. It is recommended that the form layer call the API. 15 | -------------------------------------------------------------------------------- /docs/standards/review/template-word-1.0.md: -------------------------------------------------------------------------------- 1 | (*CiviCRM Review Template WORD-1.2*) 2 | 3 | 4 | 5 | * General standards 6 | * ([`r-explain`](https://docs.civicrm.org/dev/en/latest/standards/review/#r-explain)) __Undecided__ 7 | * ([`r-user`](https://docs.civicrm.org/dev/en/latest/standards/review/#r-user)) __Undecided__: 8 | * ([`r-doc`](https://docs.civicrm.org/dev/en/latest/standards/review/#r-doc)) __Undecided__ 9 | * ([`r-run`](https://docs.civicrm.org/dev/en/latest/standards/review/#r-run)) __Undecided__: 10 | * Developer standards 11 | * ([`r-tech`](https://docs.civicrm.org/dev/en/latest/standards/review/#r-tech)) __Undecided__: 12 | * ([`r-code`](https://docs.civicrm.org/dev/en/latest/standards/review/#r-code)) __Undecided__ 13 | * ([`r-maint`](https://docs.civicrm.org/dev/en/latest/standards/review/#r-maint)) __Undecided__ 14 | * ([`r-test`](https://docs.civicrm.org/dev/en/latest/standards/review/#r-test)) __Undecided__ 15 | -------------------------------------------------------------------------------- /docs/testing/codeception.md: -------------------------------------------------------------------------------- 1 | !!! tip "Setup" 2 | 3 | The test suites require a small amount of [setup](../testing/index.md#setup). If your system was created via [buildkit](../tools/buildkit.md) and 4 | [civibuild](../tools/civibuild.md), then it was handled automatically. 5 | 6 | TODO -------------------------------------------------------------------------------- /docs/testing/karma.md: -------------------------------------------------------------------------------- 1 | !!! tip "Setup" 2 | 3 | The test suites require a small amount of [setup](index.md#setup). If your system was created via [buildkit](../tools/buildkit.md) and 4 | [civibuild](../tools/civibuild.md), then it was handled automatically. 5 | 6 | [Karma] is a Javascript testing tool which executes [Jasmine] tests on the command-line. 7 | It was introduced in Civi v4.6 in tandem with several AngularJS-based UIs. 8 | 9 | [Buildkit](../tools/buildkit.md) includes a copy of `karma`. Alternatively, 10 | you can download it by running `npm install` in the `civicrm` directory. 11 | 12 | ## Running Karma 13 | 14 | If you're actively working on Javascript files or Karma tests, then you can 15 | start `karma` in a *watch* mode. Any time you save a change to disk, it 16 | will automatically re-execute the tests. 17 | 18 | ```bash 19 | $ cd /path/to/civicrm 20 | $ karma start 21 | ``` 22 | 23 | ## Running Karma (Other ways) 24 | 25 | You can also run the karma tests as they would be run by [Jenkins](continuous-integration.md) using [civi-test-run](../tools/civi-test-run.md). 26 | 27 | [Karma]: https://karma-runner.github.io/1.0/index.html 28 | [Jasmine]: https://jasmine.github.io/2.1/introduction.html 29 | -------------------------------------------------------------------------------- /docs/testing/protractor.md: -------------------------------------------------------------------------------- 1 | !!! tip "Setup" 2 | 3 | The test suites require a small amount of [setup](index.md#setup). If your system was created via [buildkit](../tools/buildkit.md) and 4 | [civibuild](../tools/civibuild.md), then it was handled automatically. 5 | 6 | TODO -------------------------------------------------------------------------------- /docs/testing/selenium.md: -------------------------------------------------------------------------------- 1 | !!! tip "Setup" 2 | 3 | The test suites require a small amount of [setup](index.md#setup). If your system was created via [buildkit](../tools/buildkit.md) and 4 | [civibuild](../tools/civibuild.md), then it was handled automatically. 5 | 6 | Web tests ensure the overall system is working as expected – that is, ensuring 7 | that the right things happen when you click on the right buttons. 8 | 9 | Examples of web tests include that the event confirmation screen is displayed 10 | when I hit the register for an event button, or that all 23 contacts are 11 | displayed when I search for contacts that live in France. 12 | 13 | You can record tests using the Selenium IDE which you can download from the 14 | [Selenium website](http://seleniumhq.org/). Web tests should be recorded using an 15 | instance of CiviCRM that has standard sample data. 16 | 17 | To ensure consistency, all tests should be carried out using the standard 18 | CiviCRM sample data. 19 | 20 | ## Setup 21 | 22 | [buildkit](../tools/buildkit.md) should be installed. You will also need Java and Firefox. 23 | 24 | ## Running the Web Tests 25 | 26 | 1. Open two terminals 27 | 28 | 2. From Terminal 1: Launch the Selenium service 29 | ```bash 30 | $ cd /path/to/civicrm 31 | $ cd packages/SeleniumRC/ 32 | $ bash selenium.sh 33 | Runnning selenium-server-2.35.0 34 | Mar 06, 2015 8:58:22 PM org.openqa.grid.selenium.GridLauncher main 35 | INFO: Launching a standalone server 36 | ``` 37 | 38 | 3. From Terminal 2: Run the tests 39 | ```bash 40 | $ cd /path/to/civicrm 41 | $ cd tools 42 | $ ./scripts/phpunit WebTest_AllTests 43 | ``` 44 | 45 | ## See Also 46 | 47 | - [Selenium documentation](http://seleniumhq.org/docs/) 48 | - [Selenium reference](http://release.seleniumhq.org/selenium-core/1.0.1/reference.html) 49 | -------------------------------------------------------------------------------- /docs/testing/upgrades.md: -------------------------------------------------------------------------------- 1 | Upgrade tests provide a basic sanity check on the DB upgrade logic – 2 | they ensure that the upgrade process does not cause a crash when upgrading 3 | from an older version. 4 | 5 | They are suitable for checking issues in the DB upgrade logic – 6 | but do not check for issues in the administrative experience or in the 7 | CMS-integration. 8 | 9 | Upgrade tests are run daily on the Jenkins [continuous integration](continuous-integration.md) server. 10 | 11 | Locally you can use [civi-test-run](../tools/civi-test-run.md) to run the same upgrade tests as Jenkins would. 12 | -------------------------------------------------------------------------------- /docs/tools/civi-test-run.md: -------------------------------------------------------------------------------- 1 | # civi-test-run 2 | 3 | `civi-test-run` is a script which runs one or more test suites locally. It is compatible with `civibuild`-based deployments. 4 | 5 | ## Installation 6 | 7 | `civi-test-run` is included within [buildkit](buildkit.md). 8 | 9 | ## Usage 10 | 11 | Run without arguments to see the exact usage: 12 | 13 | ```bash 14 | $ civi-test-run 15 | ``` 16 | 17 | ## Test types 18 | 19 | The test type is one of: 20 | 21 | - `all` - Run all standard CiviCRM test suites 22 | - `karma` - Run the KarmaJS test suite 23 | - `phpunit-api` - Run the `api_v3` test suite 24 | - `phpunit-civi` - Run the `Civi/` test suite 25 | - `phpunit-crm` - Run the `CRM` test suite 26 | - `phpunit-e2e` - Run the `E2E` test suite 27 | - `upgrade` - Run the upgrade test suite 28 | -------------------------------------------------------------------------------- /docs/tools/cividist.md: -------------------------------------------------------------------------------- 1 | ## CiviDist 2 | 3 | `cividist` generates a website with tarballs built from the official git repos ([civicrm-core.git](https://github.com/civicrm/civicrm-core.git), [civicrm-packages.git](https://github.com/civicrm/civicrm-packages.git), etc). It manages the CiviCRM [nightly builds](http://dist.civicrm.org). 4 | 5 | If you wish to run `cividist` with your own repos, you will need to do the some initial setup and then periodically build new tarballs. 6 | 7 | `cividist` expects that branch names match across all repos (e.g. the `4.6` branch in `civicrm-core.git` must match the `4.6` branch in `civicrm-packages.git`). If you use a non-standard branch name, it must exist in all repos. 8 | 9 | ## Setup: Make the web root 10 | 11 | ``` 12 | civibuild create dist --url http://dist.localhost 13 | ``` 14 | 15 | ## Setup: Register your forks 16 | 17 | !!! note 18 | If you use forks, you should do so consistently across all repos (even if you don't have any customizations on one repo or another). The goal is to consistently name the `remote`s and `branch`es across all repos. 19 | 20 | ``` 21 | cd build/dist/src 22 | git remote add myfork https://github.com/myfork/civicrm-core.git 23 | 24 | cd build/dist/src/drupal 25 | git remote add myfork https://github.com/myfork/civicrm-drupal.git 26 | 27 | cd build/dist/src/packages 28 | git remote add myfork https://github.com/myfork/civicrm-packages.git 29 | 30 | cd build/dist/src/joomla 31 | git remote add myfork https://github.com/myfork/civicrm-joomla.git 32 | 33 | cd build/dist/src/WordPress 34 | git remote add myfork https://github.com/myfork/civicrm-wordpress.git 35 | ``` 36 | 37 | ## Setup: Permissions 38 | 39 | If your system has specific permission requirements, then apply the permissions as you normally would. For example, if you use chgrp and and set all files as group-writable: 40 | 41 | ``` 42 | sudo git config --system core.filemode false 43 | sudo chgrp -R mygroup build/dist 44 | sudo chmod -R g+w build/dist 45 | ``` 46 | 47 | ## Periodic: Update tarballs 48 | 49 | This will retrieve the latest code from the remote alias (eg `myfork`) and build new build tarballs: 50 | 51 | ``` 52 | cd build/dist 53 | env GIT_REMOTE=myfork cividist update 54 | cividist build myfork/4.6 55 | ``` 56 | 57 | By default the tarballs will have the date in the name. If you don't want this you can add a FILE_SUFFIX e.g., to this command as used by Fuzion to a) use a remote called 'fuzion', b) use the branch 4.6.4rc1 from those repos & c) output using filenames like civicrm-4.6.5-drupal-nightly.tar.gz 58 | 59 | ``` 60 | env FILE_SUFFIX=nightly cividist build fuzion/4.6.4rc1 61 | ``` 62 | 63 | You can also build multiple tarballs with one command, e.g. 64 | 65 | ``` 66 | cividist build myfork/4.5 myfork/4.6 myfork/master 67 | ``` 68 | 69 | ## Periodic: Cleanup old/orphaned tarballs 70 | 71 | ``` 72 | cd build/dist 73 | cividist prune 74 | ``` 75 | -------------------------------------------------------------------------------- /docs/tools/civilint.md: -------------------------------------------------------------------------------- 1 | Civilint is a thin wrapper which calls jshint and PHP_CodeSniffer (with the coder ruleset). 2 | 3 | Code-style tests ensure a consistent layout across all of the codebase, and they also identify some unsafe or confusing coding patterns. While working on a patch, you should run civilint to determine if the pending changes comply with style guides. 4 | 5 | Note that civilint may be invoked a few different ways: 6 | 7 | ```bash 8 | # (no arguments) – Check style of any uncommitted changes. 9 | civilint 10 | 11 | # Check style of a specific file (or list of files). 12 | civilint some/file.php 13 | 14 | # Check your last commit 15 | git diff --name-only HEAD~1 | civilint - 16 | 17 | # Check for changes in your branch (compared to master) 18 | git diff --name-only master | civilint - 19 | ``` 20 | 21 | See also: 22 | 23 | - [CiviCRM Coding Standards](../standards/php.md) 24 | - [CiviCRM Javascript Standards](../standards/javascript.md) 25 | - [Drupal Coding Standards](https://www.drupal.org/docs/develop/standards/coding-standards) 26 | - [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) 27 | - [coder](https://github.com/civicrm/coder) 28 | - [jshint](http://jshint.com/) 29 | -------------------------------------------------------------------------------- /docs/tools/jenkins.md: -------------------------------------------------------------------------------- 1 | # Jenkins continuous integration 2 | 3 | Pull-requests are tested automatically with build-bot software called [Jenkins](https://jenkins.io/) which runs on [test.civicrm.org](http://test.civicrm.org/). Key things to know: 4 | 5 | * If you are a new contributor, the tests may be placed on hold pending a cursory review. One of the administrators will post a comment like `jenkins, ok to test` or `jenkins, add to whitelist`. 6 | * The pull-request will have a colored dot indicating its status: 7 | * **Yellow**: The automated tests are running. 8 | * **Red**: The automated tests have failed. 9 | * **Green**: The automated tests have passed. 10 | * If the automated test fails, click on the red dot to investigate details. Check for information in: 11 | * The initial summary. Ordinarily, this will list test failures and error messages. 12 | * The console output. If the test-suite encountered a significant error (such as a PHP crash), the key details will only appear in the console. 13 | * __Tip__: Sometimes, the console output is pretty long (several hundred KB). This usually means that a majority of tests ran, but there's a failure mixed in somewhere. View the full log and search for the word `EXITCODE`; this should normally appear as blank or 0. The first non-empty `EXITCODE` should be close to the problem. 14 | * __Tip__: Sometimes, the console output is relatively short (a page or two). You might look for evidence of one of these typical problems: 15 | * A network service (such as `github.com` or `packagist.org`) was unavailable. These are usually corrected quickly without any action. Try running the test again. 16 | * The pull-request is based on an old version of the codebase, and it cannot be applied cleanly with `git apply` or `git scan am`. Rebasing the PR branch should resolve this. 17 | * On the test node, a local resource (such as disk-space, RAM, or inode count) was exhausted. If the failure was recent (past few hours), seek help on [the infrastructure channel](https://chat.civicrm.org/civicrm/channels/infrastructure). If the failure occurred a few hours or days ago, try running the test again. 18 | * Some part of the build/test toolchain needs attention. For example, a test script may have been changed without supporting an edge-case; or a tool like `bower` or `npm` may need to be upgraded. Seek help on `infrastructure`. 19 | * Code-style tests are executed first. If the code-style in this patch is inconsistent, the remaining tests will be skipped. 20 | * The primary tests may take 20-120 min to execute. This includes the following suites: `api_v3_AllTests`, `CRM_AllTests`, `Civi\AllTests`, `civicrm-upgrade-test`, and `karma` 21 | * There are a handful of unit tests which are time-sensitive and which fail sporadically. See: https://forum.civicrm.org/index.php?topic=36964.0 22 | * The web test suite (`WebTest_AllTests`) takes several hours to execute. [It runs separately -- after the PR has been merged.](https://test.civicrm.org/job/CiviCRM-WebTest-Matrix/) 23 | 24 | For detailed discussion about automated tests, see [Testing](../testing/index.md) 25 | -------------------------------------------------------------------------------- /docs/translation/extensions.md: -------------------------------------------------------------------------------- 1 | # Extensions Translation 2 | 3 | For developing a CiviCRM extension in a way that can be translated, all the best practices described in the [Internationalisation for Developers](index.md) page apply. This page describes special considerations that need to be taken into account for extensions. 4 | 5 | See also: ["Extension translation" wiki in the Translation project](https://lab.civicrm.org/dev/translation/wikis/extension-translation). 6 | 7 | ## For translators: Translating strings on Transifex 8 | 9 | There is a separate project on Transifex to translate extensions. Each extension has its own "resource". Therefore, when a translator joins a translation team, they can translate all extensions. We didn't see a need to separate each extension in a separate project, because each extension should have only one translation (`.po`) file. 10 | 11 | See: 12 | 13 | Translation strings are sent to Transifex when the extension is "ready for automatic distribution". See: [Publishing Extensions](../extensions/publish.md). 14 | 15 | ## For administrators: Download translation files for extensions 16 | 17 | The easiest way to download translations for extensions is to use the [l10nupdate](https://github.com/cividesk/com.cividesk.l10n.update/) extension. 18 | 19 | ## For developers: Correct usage of the `E::ts()` function 20 | 21 | In PHP, Smarty, and JS code, the convention is to perform translations using the `E::ts()` helper function. This is the same as in core code — with the additional requirement that one must specify the "domain" so that the translation engine can use the correct dictionary (`.mo` file) at run-time. 22 | 23 | !!! note "New in civix 17.08" 24 | `E::ts()` was added to civix 17.08. The civix file may need to be regenerated. You can read more about it in the [civix upgrade notes](https://github.com/totten/civix/blob/master/UPGRADE.md#upgrade-to-v17081-the-big-e). Extensions may still use the old syntax using `ts()` with the `domain` argument. 25 | 26 | !!! note "`E::ts()` and `ts()`" 27 | `E::ts()` is recommended, but it won't fallback to core. (it might in JS, but not in PHP because we don't have a way to detect if gettext translated or not) 28 | 29 | PHP: 30 | 31 | ```php 32 | use CRM_Myextension_ExtensionUtil as E; 33 | 34 | class CRM_Myextension_Form_Example { 35 | function example() { 36 | $string = E::ts('Hello, %1', array( 37 | 1 => $display_name, 38 | )); 39 | } 40 | } 41 | ``` 42 | 43 | Smarty templates: 44 | 45 | ```smarty 46 | {crmScope extensionKey='org.example.myextension'} 47 |

{ts 1=$display_name}Hello, %1{/ts}

48 | {/crmScope} 49 | ``` 50 | 51 | Javascript: 52 | 53 | ```js 54 | (function ($, ts){ 55 | $('.foo').click(function greet(display_name) { 56 | window.alert(ts('Hello, %1', {1: display_name})); 57 | }); 58 | }(CRM.$, CRM.ts('org.example.myextension'))); 59 | ``` 60 | 61 | Angular: 62 | 63 | ```js 64 | $scope.ts = CRM.ts('org.example.myextension'); 65 | ``` 66 | 67 | Angular HTML templates: 68 | 69 | ```html 70 |

{{ts('Hello, %1', {1: display_name})}}

71 | ``` 72 | -------------------------------------------------------------------------------- /redirects/internal.txt: -------------------------------------------------------------------------------- 1 | dev-tools/debugging tools/debugging 2 | extend-stages extensions/lifecycle 3 | markdownrules documentation/markdown 4 | best-practices/documentation-style-guide documentation/style-guide 5 | extensions/basics extensions 6 | api/general api 7 | hooks/hook_civicrm_trigger_info hooks/hook_civicrm_triggerInfo 8 | testing/setup testing 9 | testing/javascript testing/karma 10 | framework/schema-definition framework/database/schema-definition 11 | api/params api/v3/options 12 | api/usage api/v3/usage 13 | api/actions api/v3/actions 14 | api/options api/v3/options 15 | api/joins api/v3/joins 16 | api/chaining api/v3/chaining 17 | api/custom-data api/v3/custom-data 18 | api/examples api/v3/examples 19 | api/changes api/v3/changes 20 | testing/selinium testing/selenium 21 | core/develop tools/git 22 | basics/filesystem framework/filesystem 23 | core/architecture framework/codebase 24 | framework/civimail/tokens https://docs.civicrm.org/user/en/latest/common-workflows/tokens-and-mail-merge/ 25 | framework/api-architecture api/v4/architecture 26 | -------------------------------------------------------------------------------- /redirects/wiki-crm.txt: -------------------------------------------------------------------------------- 1 | Documentation+Infrastructure+Canary develop 2 | Book+style+guide best-practices/documentation-style-guide 3 | CiviCRM+Unit+Testing+basic+information testing 4 | Setting+up+your+personal+testing+sandbox+HOWTO testing 5 | Writing+a+PHPUnit+testcase+HOWTO testing 6 | Pull-Request+Process tools/git/#pr 7 | --------------------------------------------------------------------------------