This CiviCRM extension adds support for dynamic in-page behaviors based on changes to form fields in CiviCRM forms, including showing/hiding form elements and setting field values.
Current support includes the following forms:
- event registration (/civicrm/event/register), including "additional participant" form
- contribution page (/civicrm/contribute/transact)
Patch welcome for other forms.
git clone https://github.com/twomice/com.joineryhq.profcond in your local extension repository and it should work.
This extension has no browser-based configuration form within CiviCRM. Configuration is by PHP arrays in code within the civicrm.settings.php file.
You need to add in your civicrm.settings.php a new config variable
global $civicrm_setting;
$civicrm_setting['com.joineryhq.profcond']['com.joineryhq.profcond'] = array(
'event' => array(
81 => array (
'onload' => array(
'selectors' => array(
'#priceset' => array(
'display' => 'hide',
),
),
'profiles' => array (
'1' => array(
'display' => 'hide',
),
),
),
'1_swim' => array(
'conditions' => array(
'all_of' => array(
array(
'id' => 'custom_261',
'op' => 'value_is',
'value' => '1', //"swim"
),
)
),
'states' => array(
'pass' => array (
'profiles' => array (
'108' => array(
'display' => 'show',
),
),
'selectors' => array(
'#priceset' => array(
'display' => 'show',
),
'div.price-set-row.ticket_selection-row1' => array(
'display' => 'show',
),
'div.price-set-row.ticket_selection-row1 input[type="radio"]' => array(
'is_price_change' => TRUE,
'properties' => array(
'checked' => TRUE,
),
),
'div.price-set-row.ticket_selection-row2' => array(
'display' => 'hide',
),
),
),
'fail' => array(
'profiles' => array (
'1' => array(
'display' => 'hide',
),
'108' => array(
'display' => 'hide',
),
),
'selectors' => array(
'div.price-set-row.ticket_selection-row1 input[type="radio"]' => array(
'is_price_change' => TRUE,
'properties' => array(
'checked' => FALSE,
),
),
),
),
),
),
),
),
'contribution' => array(
),
);
This nested array format is fragile but explicit, expressing any number of rules, and for each rule, any number of conditions (either AND or OR), and any number of field states to manifest when the condition test as either true or false.
$civicrm_setting['com.joineryhq.profcond']['com.joineryhq.profcond'] = array(
'[page-type]' => array(
[page-id] => array (
'[rule-name]' => array(
'limit' => array(
'formId' => array(
'pattern' => [limit-regex-pattern],
'flags' => [limit-regex-flags],
),
'conditions' => array(
'[condition-type]' => array(
array(
'[subject-identifier-type]' => '[subject-identifier]',
'op' => '[operator]',
'value' => '[test-value]',
),
)
),
'states' => array(
'[condition-success]' => array (
'[state-type]' => array (
'[state-selector]' => array(
'[state-property]' => '[state-property-value]',
),
),
),
),
),
),
),
);
Must be 'event' or 'contribution' to indicate that this section applies to event registration pages or contribution pages. In future, other values may be supported.
Must be one these:
- An event ID or contribution page ID. Rules in this section will only be applied to this page-type and ID.
- The string
all
, to apply the rule to all events (or contribution pages). If you specify bothall
and a page ID, the page ID settings will override theall
settings.
- Must be a unique string within this page-type/page-id section.
- Must also be suitable for use as a CSS class.
- The special name 'onload' defines a rule which fires upon page load;
its key is 'onload' and its value is an array in the form of [condition-success];
upon page load, the state described in this rule is applied unconditionally.
Optional array defining a regular expression that will limit the forms on which this rule is applied. Because [page-type] and [page-id] already facilitate limiting rules to specific events and contribution pages, this "limit" array is only expected to be useful in the case of multi-participant event registrations, in which the primary participant form has the formId "Register", and additional participant forms have the formId "Participant_1", "Participant_2", etc. The "limit" definition provides a way to specify that certain rules should only apply on the "Register" formId, or one or more of the additional participant forms.
String. A pattern to be used in `new RegExp('[limit-regex-pattern]', '[limit-regex-flags]'). If the regular expression does not matche the formId value (see "limit"), this rule will not be used at all on the page.
String. A pattern to be used in `new RegExp('[limit-regex-pattern]', '[limit-regex-flags]'). Optional, and probably not needed in any case; but see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Advanced_searching_with_flags for more on regular expression flags.
A string indicating how the conditions should be joined. One of:
- any_of: If any condition is met, the conditions are considered passing.
- all_of: If all conditions are met, the conditions are considered passing.
Combining any_of
with all_of
has not been tested and may produce unpredictable results.
It's recommended to use one or the other. Nesting of conditions is not supported.
Thus, under 'conditions', you should have one array element, keyed to either any_of
or all_of
, containing any number of conditions.
One of:
- id: if the item being evaluated is a DOM element on the page.
- selector: if the item being evaluated is a DOM element on the page.
- variable: if the item being evaluated is a JavaScript variable. (See "Variables" for more information about the JavaScript variables defined by Profile Conditionals.)
One of these, depending on the value of [subject-identifier-type]:
- If [subject-identifier-type] is 'id': The HTML "id" attribute of the field to be tested in this condition.
- If [subject-identifier-type] is 'selector': A jQuery selector describing the field to be tested in this condition.
- If [subject-identifier-type] is 'variable': One of these:
- String: name of a global variable (property of the window object)
- Array: ordered array of nested variable names within a global object variable (property of the window object)
Example:['CRM','vars','myextension','foobar',0]
to test the value of window.CRM.vars.myextension.foobar[0]
The type of comparison to be performed for this field. One of:
- value_is: The subject of [subject-identifier] must have the given [test-value] value for the condition to pass.
- value_is_one_of: The subject of [subject-identifier] must have any of the given [test-value] values for the condition to pass.
- is_set: The subject of [subject-identifier] must have a value for the condition to pass.
- is_checked: The subject of [subject-identifier] must be checked to pass (appropriate for checkbox and radio elements);
only appropriate where [subject-identifier-type] is 'id' or 'selector'.
The value to be compared in this condition.
One of:
- 'pass': If the conditions are considered passing, these states will be applied.
- 'fail': If the conditions are considered failing, these states will be applied.
One of:
- 'profile': This state will be applied to a CiviCRM profile on the page.
- 'selector': This state will be applied to an element on the page described by a jQuery selector.
Depending on the value of [state-type], one of the following:
- If [state-type] is 'profile', the CiviCRM system ID of the profile.
- If [state-type] is 'selector', a jQuery selector describing one or more elements on the page.
The attribute of the given element to be changed. One of:
- 'display'
- 'properties'
- 'css'
- 'html'
- 'attributes'
- 'value'
- 'before'
- 'after'
- 'is_price_change'
See [state-property-value] for more information.
Depending on the value of [state-property], the appropriate value for that property. For these values of [state-property], the possible [state-property] values are:
- 'display': One of:
- 'hide': The element will be hidden with jQuery().hide().
- 'show': The element will be shown with jQuery().show().
- 'properties': An associative array of properties, to be applied to the element with jQuery().prop().
- 'css': An associative array of properties, to be applied to the element with jQuery().css().
- 'html': An associative array of properties, to be applied to the element with jQuery().html().
- 'attributes': An associative array of attributes, to be applied to the element with jQuery().attr().
- 'value': The value to which the element (which should be a form field) will be set, using jQuery().val().
- 'before': The element will be relocated before the element indicated by this jQuery selector, with jQuery().insertBefore().
- 'after': The element will be relocated after the element indicated by this jQuery selector, with jQuery().insertAfter().
- 'is_price_change': TRUE if this field is a price field and changing it should update the total amount. Defaults to FALSE.
ProfileConditionals defines these JavaScript variables in CRM.vars.profcond:
- pageConfig: the full array of rules as configured for the current [page-type] and [page-id].
- formId: the
id
attribute of the CiviCRM form being displayed. - submittedParticipantValues: defined on "additional participantn" forms in a multi-participant event registration;
an array of the values submitted values (omitting credit card details) from the
participants submitted on earlier forms.
submittedParticipantValues[0]
contains values submitted for the primary participant,submittedParticipantValues[1]
for the first additional participant, etc. This variable, when referenced by a condition in which [subject-identifier] = 'variable', optionally in conjunction with a rule "limit", allows definition of rules which affect behavior on an additional participant form based on selections in earlier participant forms.
A more involved example is contained in CONFIG_EXAMPLE.md.
This extension provides hook_civicrm_profcond_alterConfig()
, which can be implemented like so:
/**
* Implements hook_civicrm_profcond_alterConfig().
* @link https://twomice.github.io/com.joineryhq.profcond/#developer-hooks
*/
function myextension_civicrm_profcond_alterConfig(&$config, $pageType, $entityId) {
// $config contains the full value of $civicrm_setting['com.joineryhq.profcond']['com.joineryhq.profcond'];
// change as needed.
// $pageType will be either 'contribution' or 'event'.
// $entityId will be the current event ID or contribution page ID.
// If we're on an event registration page, and my custom decider says to do so,
// create a rule for showing/hiding profile id=1.
if ($pageType == 'event') {
if (_myextensionWantsToAlterProfCondForEvent($entityId)) {
$config['event'][$entityId]['myextension_1'] = [
'conditions' => [
'all_of' => [
[
'id' => 'myExtensionCustomField',
'op' => 'value_is_one_of',
'value' => [1, 2, 3, 4],
],
],
],
'states' => [
'pass' => [
'profiles' => [
1 => [
'display' => 'show',
],
],
],
'fail' => [
'profiles' => [
1 => [
'display' => 'hide',
],
],
],
],
];
}
}
}
-
What about wildcards? I want to apply the same rules to several different events.
Use the stringall
as the event ID or contribution page ID; see notes on[page-id]
, above.Alternately, you could do something like this for a more specific set of events (or the equivalent, for contribution pages):
$eventsConfig = array( // whatever ); $civicrm_setting['com.joineryhq.profcond']['com.joineryhq.profcond'] = array( 'event' => array( '81' => $eventsConfig, '82' => $eventsConfig, '83' => $eventsConfig, ), );
-
I want to conditionally display and require a field. How can I do that?
Configure the two fields as required within the profile. Use this extension to show/hide them according to your own rules. If this extension hides a required field, it will also ensure that the field is not required when hidden.
Joinery provides services for CiviCRM including custom extension development, training, data migrations, and more. We aim to keep this extension in good working order, and will do our best to respond appropriately to issues reported on its github issue queue. In addition, if you require urgent or highly customized improvements to this extension, we may suggest conducting a fee-based project under our standard commercial terms. In any case, the place to start is the github issue queue -- let us hear what you need and we'll be glad to help however we can.
And, if you need help with any other aspect of CiviCRM -- from hosting to custom development to strategic consultation and more -- please contact us directly via https://joineryhq.com