Part 1 - About the actual challenge
I'm assuming you're using a rule that looks similar (equal?) to the rule in the accepted answer in that related question, which looks like so:
{ "rules_improved_combination_of_taxonomy_terms" : {
"LABEL" : "Improved combination of taxonomy terms",
"PLUGIN" : "reaction rule",
"OWNER" : "rules",
"REQUIRES" : [ "rules" ],
"ON" : { "node_view--article" : { "bundle" : "article" } },
"DO" : [
{ "drupal_message" : { "message" : "[node:field-a][node:field-b]" } },
{ "variable_add" : {
"USING" : { "type" : "text", "value" : "[node:field-a][node:field-b]" },
"PROVIDE" : { "variable_added" : { "variable_added" : "Added variable" } }
}
},
{ "entity_create" : {
"USING" : {
"type" : "taxonomy_term",
"param_name" : "[variable-added:value]",
"param_vocabulary" : "tags"
},
"PROVIDE" : { "entity_created" : { "entity_created" : "Created entity" } }
}
},
{ "entity_save" : { "data" : [ "entity-created" ], "immediate" : "1" } },
{ "data_set" : { "data" : [ "node:field-c" ], "value" : [ "entity-created" ] } },
{ "entity_save" : { "data" : [ "node:field-c" ], "immediate" : "1" } }
]
}
}
The above rule does not perform any verification if the term [node:field-a][node:field-b]
(= the value that gets stored in "field C") already exists. Instead each time the Rules Actions are triggered (ie each time "an Article is viewed"), it unconditionally creates that term (which may already exist) another time. So that is why you get all those duplicate terms (like helloworld
in your example).
The solution (fix) for that is that you add some extra logic in your rule to only perform the 3rd (= entity_create
) and 4th (= entity_save
of the created term) Rules Action so that those 2 Rules Actions are only performed if the term does not exist yet.
There are basically 2 solutions/approaches to implement such exta logic:
- Use the the Conditional Rules module, which allows to include the equivalent of a Rules Condition within a Rules Action.
- Move those 2 Rules Actions to an appropriate (new) Rules Component, in which you can add the required Rules Conditions. And then in your rule you just call (perform) that Rules Component.
The advantage of the first solution is that the entire logic is contained in a single Rule, though (disadvantage) it requires yet another module.
With either of both solutions, you basically improve this rule with something like "If the term for field C does not exist yet, then let's quickly create it now, so that we can use that term as the value for field C".
Easy enough, no? ... All you need to know is how to actually perform a check in Rules to verify "If that term is already contained in the list of terms of your taxonomy".
Part 2 - Solution using Conditional Rules
Below is a possible solution using Conditional Rules. The improved rule looks like so:
{ "rules_combine_taxonomy_terms_without_creating_duplicates" : {
"LABEL" : "Combine taxonomy terms without creating duplicates",
"PLUGIN" : "reaction rule",
"OWNER" : "rules",
"REQUIRES" : [ "rules", "rules_conditional" ],
"ON" : { "node_view--article" : { "bundle" : "article" } },
"DO" : [
{ "drupal_message" : { "message" : "Value of term for field C will be set to: \u003Cstrong\u003E[node:field-a][node:field-b]\u003C\/strong\u003E." } },
{ "variable_add" : {
"USING" : { "type" : "text", "value" : "[node:field-a][node:field-b]" },
"PROVIDE" : { "variable_added" : { "combined_term" : "Combined Term" } }
}
},
{ "entity_query" : {
"USING" : {
"type" : "taxonomy_term",
"property" : "vocabulary",
"value" : [ "node:field-a:vocabulary" ]
},
"PROVIDE" : { "entity_fetched" : { "existing_terms" : "Existing Terms" } }
}
},
{ "variable_add" : {
"USING" : { "type" : "boolean", "value" : "0" },
"PROVIDE" : { "variable_added" : { "new_term_exist" : "New term exists" } }
}
},
{ "LOOP" : {
"USING" : { "list" : [ "existing-terms" ] },
"ITEM" : { "current_term" : "Current term" },
"DO" : [
{ "CONDITIONAL" : [
{
"IF" : { "text_matches" : { "text" : [ "current-term:name" ], "match" : "[combined-term:value]" } },
"DO" : [
{ "data_set" : { "data" : [ "new-term-exist" ], "value" : "1" } },
{ "data_set" : { "data" : [ "node:field-c" ], "value" : [ "current-term" ] } },
{ "drupal_message" : { "message" : "Term \u003Cstrong\u003E[node:field-a][node:field-b]\u003C\/strong\u003E already exists (no need to create it now)." } }
]
}
]
}
]
}
},
{ "CONDITIONAL" : [
{
"IF" : { "data_is" : { "data" : [ "new-term-exist" ], "value" : "0" } },
"DO" : [
{ "entity_create" : {
"USING" : {
"type" : "taxonomy_term",
"param_name" : "[combined-term:value]",
"param_vocabulary" : "tags"
},
"PROVIDE" : { "entity_created" : { "term_created" : "Created term" } }
}
},
{ "entity_save" : { "data" : [ "term-created" ], "immediate" : "1" } },
{ "data_set" : { "data" : [ "node:field-c" ], "value" : [ "term-created" ] } },
{ "drupal_message" : { "message" : "Term \u003Cstrong\u003E[node:field-a][node:field-b]\u003C\/strong\u003E did not yet exist and was created just now." } }
]
}
]
},
{ "entity_save" : { "data" : [ "node:field-c" ], "immediate" : "1" } },
{ "drupal_message" : { "message" : "\u003Cstrong\u003ENote\u003C\/strong\u003E: After updating field A or B, a page refresh is needed to actually SEE a value of field C = \u003Cstrong\u003E[node:field-a][node:field-b]\u003C\/strong\u003E." } }
]
}
}
Even though it's not an obvious rule to digest (I think), it mostly does these things:
- Perform an
entity_query
to create a list of existing terms (stored in existing_terms
), for the vocabulary used in Field A (as per the node:field-a:vocabulary
in that entity_query
). So the assumption is that Field A and Field C use the same vocabulary (there are no details about that in the question). If that's not the case, just replace that vocabulary with whatever fits, or maybe just hardcode it.
- Calculate a boolean variable with machine name
new_term_exist
, which verifies if the term to be saved in Field C already exists.
- Set the value for field C to an existing term (if it already exist).
- Create the term for field C on the fly (if it does not yet exist) and then use that to set the value for field C.
However, there is 1 minor detail to be aware of, as detailed in the message of the very last Rules Action ... For anybody interested in addressing that (to make that message obsolete), please post an extra answer and feel free to use this rule here to start from.
Note: even though, in theory, you should also be able to use Rules Components instead of Conditional Rules (refer to the answer to "What's the alternative to using the Conditional Rules module?" for more details on that), the key challenge with that is that you run in a tough-to-debug issue when passing values to such Rules Components, in the cases where the value of Field C is still blank (eg when creating a new node).
PS: Q: How do you eat an elephant? A: 1 bite at a time ... (though there is only 1 bite left of it now).