Part 1: Processing field collections in a rule
Consider a configuration with a field collection like so:
- The machine name of the field collection is
field_treatment_details
, and the number of values for it is unlimited.
This field collection has 2 fields:
- a text field labeled "Doelpubliek" (Dutch for "Target audience") with machine name
field_doelpubliek
.
- a boolean field labeled "Betalend" (Dutch for "Payable") with machine name
field_betalend
.
Assume a node with "some number of" field collection items, with values that look like so (with some number = 2 in this case, but that could be any number as per the "unlimited" above):
- Doelpubliek=Baby with Betalend=Nee
- Doelpubliek=Moeder with Betalend=Ja
Let's assume you want to display these data via a Rule, using Rules Action "Set message", and using Rules Event "Content is viewed", so that such message looks like so:
This is a demo of a node containing a field collection ...
About this demo:
The machine name of the field collection is field_treatment_details, and the number of values for it is unlimited.
This field collection has 2 fields:
- a text field labeled Doelpubliek with machine name field_doelpubliek.
- a boolean field labeled Betalend with machine name field_betalend.
Part 1: The field collection with machine name 'field_treatment_details' looks like so:
Doelpubliek: Baby
Betalend: Nee
Doelpubliek: Moeder
Betalend: Ja
Part 2: The result of a Rules loop that iterates for each of the field collection items (using its unique ID) ...
The unique ID of the field collection item: 2
The host entity of this field collection item: 43
Field "field_doelpubliek": Baby
Field "field_betalend": Nee
The unique ID of the field collection item: 3
The host entity of this field collection item: 43
Field "field_doelpubliek": Moeder
Field "field_betalend": Ja
Here is the Rule (in Rules export format) that produced the above "message":
{ "rules_field_collection_demo" : {
"LABEL" : "Field Collection Demo",
"PLUGIN" : "reaction rule",
"ACTIVE" : false,
"OWNER" : "rules",
"REQUIRES" : [ "rules" ],
"ON" : { "node_view" : [] },
"IF" : [
{ "entity_has_field" : { "entity" : [ "node" ], "field" : "field_treatment_details" } }
],
"DO" : [
{ "drupal_message" : { "message" : "\u003Ch2\u003EThis is a demo of a node containing a field collection ... \u003C\/h2\u003E\r\n\u003Chr \/\u003E\r\n\u003Cstrong\u003EAbout this demo\u003C\/strong\u003E:\u003Cbr \/\u003E\r\n\u003Cbr \/\u003E\r\nThe machine name of the field collection is \u003Cstrong\u003Efield_treatment_details\u003C\/strong\u003E, and the number of values for it is unlimited.\u003Cbr \/\u003E\r\nThis field collection has 2 fields:\u003Cbr \/\u003E\u003Cbr \/\u003E\r\n- a text field labeled \u003Cstrong\u003EDoelpubliek\u003C\/strong\u003E with machine name \u003Cstrong\u003Efield_doelpubliek\u003C\/strong\u003E.\u003Cbr \/\u003E\r\n- a boolean field labeled \u003Cstrong\u003EBetalend\u003C\/strong\u003E with machine name \u003Cstrong\u003Efield_betalend\u003C\/strong\u003E.\u003Cbr \/\u003E\u003Cbr \/\u003E\r\n\u003Chr \/\u003E\r\n\u003Cstrong\u003EPart 1\u003C\/strong\u003E: The field collection with machine name \u003Cstrong\u003E\u0027field_treatment_details\u0027\u003C\/strong\u003E looks like so:\r\n\u003Chr \/\u003E\r\n[node:field_treatment_details]\r\n \u003Chr \/\u003E\r\n\u003Cstrong\u003EPart 2\u003C\/strong\u003E: The result of a \u003Cstrong\u003ERules loop\u003C\/strong\u003E that iterates for each of the field collection items (using its unique ID) ...\r\n\u003Chr \/\u003E" } },
{ "LOOP" : {
"USING" : { "list" : [ "node:field-treatment-details" ] },
"ITEM" : { "treatment_details_item" : "Treatment details item" },
"DO" : [
{ "drupal_message" : { "message" : "The unique ID of the field collection item: [treatment-details-item:item-id]\u003Cbr \/\u003E\r\nThe host entity of this field collection item: [treatment-details-item:host]\u003Cbr \/\u003E\r\nField \u0022field_doelpubliek\u0022: [treatment-details-item:field-doelpubliek]\u003Cbr \/\u003E\r\nField \u0022field_betalend\u0022: [treatment-details-item:field-betalend]\u003Cbr \/\u003E\r\n\u003Chr \/\u003E" } }
]
}
}
]
}
}
Admitted, this is a slightly simplified field collection configuration (no "nesting" involved). But apart from that it is similar to what you will need to specify in your Rules logic. Here are some more details to explain the above rule:
- You need (repeat: need) a Rules Condition "Entity has field" (prior to being able to use it anywhere later on in your rule), which refers to your field collection field.
- The 1st Rules Action (which produces the data below "Part 1" in the message) just displays the entire field collection, simply by referring to token
[node:field_treatment_details]
.
The 2nd Rules Action (which produces the data below "Part 2" in the message) is simply a Rules "loop", which iterates over each of the field collection items (it uses a variable that I named treatment_details_item
to actually display a message for each item). You will then be able to use any of the typical tokens (in the replacement patterns) related to that variable, such as how I used them to create my message I wanted to display, i.e.:
The unique ID of the field collection item: [treatment-details-item:item-id]<br />
The host entity of this field collection item: [treatment-details-item:host]<br />
Field "field_doelpubliek": [treatment-details-item:field-doelpubliek]<br />
Field "field_betalend": [treatment-details-item:field-betalend]<br />
Notice how, in the message I wanted my rule to display, I was able to refer to my "Doelpubliek" and "Betalend" fields (part of my field collection).
Part 2: Performing a loop within
After posting Part 1 of my answer, this "Update" got added to the end of the question (after it was first posted as a comment below this answer):
While I understand the example shown in the existing answer, I can't seem to conceptualize how I would be able to write a Rules "loop" to display the field collections in an email. The email body of the rules module does not seem to have the ability to "loop" over content.
I think you're right about 'The email body of the rules module does not seem to have the ability to "loop" over content
', or at least I've never discovered anything to do so. However, if what you're looking for is not available, then just make it available ... The trick to do so is similar to what is shown in the Rules example included in my answer to "How to concatenate all token values of a list in a single field within a Rules loop?". In your case, you could make it work like so:
- Populate some new Rules variable before the Rules Action to send an eMail, say you name the variable
field_collection_var_for_email_body
. And the value of this variable should consist of a concatenation of the appropriate values of your nested field collection.
- Within the Rules Action to send an eMail, you'll be able to select the token for
field_collection_var_for_email_body
to include anywhere in your eMail body.
Attention: even though it should technically possible to do all this in a single rule, such rule would possibly get pretty complicated to understand/maintain. That's why if it was up to me, I'd probably implement the Rules logic (as explained in this Part 2) in a separated Rules Component, which provides ... (cfr Rules Component terminology) field_collection_var_for_email_body
!!!
Voilà ...
Happying Rules-ing! ... Also with (unlimitted) field collections ... even inside the body of an eMail created with a Rules action to Send an eMail.
PS: No need to write some PHP code to make this happen ...
PPS: For the newbies out there, it should look something like this:

Note that the fields are different here, and not the same as the example/scenario provided above.
Important: Make sure you select True for the uniqueness option in Add an item to a list, other wise this will trigger a bug that causes your fields to become empty or get readed multiple times. Once you get this bug, the only fix is to restore to a DB backup as you are not able to remove these fields even after turning off the Rule. Some more details about the bug (to avoid):