While declarative rules provide a lot of flexibility, occasionally, the configuration logic requires even more functionality. Coded rules allow the implementation of a wider variety of conditions and generate a large number of rule effects.
Coded rules use a simple business rules language for defining conditional logic and actions in a modular fashion. Rules help determine how certain components and tags should be allowed, blocked, or configured based on conditions such as tag presence, component placement, or attribute values. The language is readable, flexible, and intended to be easy for both technical and non-technical stakeholders to write, review, and maintain.
This rules language provides a straightforward way to define conditions and actions. By combining tags, placements, components, and attributes, you can tailor logic to enable or block features, require input, or set properties. The use of ANY, ALL, NOT, and the straightforward IF ... THEN ... END structure keeps rules readable and easy to maintain.
Tips
-
Use TAGGED to detect an active tag.
-
Use COMPONENT(component IN placement) to check if a component is in a specific placement.
-
Use HASVALUE(attribute OF placement) to check for attribute presence.
-
Use VALUE(attribute OF placement EQ value) to compare an attribute against an expected value.
-
Use actions like BLOCK, ALLOW, SELECT, or SET to enforce behavior once conditions are met.
-
Combine conditions with an explicit ANY OF or ALL OF block.
-
Negate any condition with NOT.
-
Use double-quotes to wrap values with spaces and special characters such as #
-
Use comma-separated lists in SELECT and SELECTBYTAG to declare a fallback order.
-
Use INITIAL to run a rule only once, when the configuration is first loaded.
-
Use # comments to explain intent to whoever maintains the rule next.
Rule syntax
A rule is typically structured as:
IF <condition(s)>
THEN
<action(s)>
END
Rules can be declared in sequence (one after another) or nested (an IF THEN block inside another). Each rule must end with the END keyword.
Conditions can be combined in several ways:
-
Single condition: IF TAGGED(spiked) THEN ...
-
Multiple conditions: combined with an explicit ANY OF or ALL OF operation. There is no implicit combination - listing several conditions directly after IF is a syntax error.
Rules can be combined using explicit ANY OF operation: the rule applies if at least one condition is true.
IF ANY OF
TAGGED(spiked)
COMPONENT(SoleRubber IN ShoeSole)
THEN
...
END
Similarly, rules can be combined using explicit ALL OF operation: the rule applies if all conditions are true.
IF ALL OF
TAGGED(spikeless)
HASVALUE(stamp-text OF ShoeToe)
THEN
...
END
ANY OF and ALL OF can only be used directly after IF (or after ELSEIF). Within such a block, each individual condition may still be negated with NOT.
Else actions
A rule may also have ELSE block which can contain actions to be performed if the rule condition fails. For example:
IF <condition(s)>
THEN
<action(s)>
ELSE
<alternate action(s)>
END
Additionally, ELSEIF can be used to perform a chain of checks, optionally ending at ELSE condition. Each ELSEIF requires its own THEN, and a single END closes the whole chain:
IF <condition(s)>
THEN
<action(s)>
ELSEIF <condition(s)>
THEN
<alternate action(s)>
ELSEIF <conditions>
THEN
<more actions(s)>
...
ELSE
<final actions(s)>
END
Negation
Any condition, single or combination operator, can be prefixed with NOT, for example:
-
NOT TAGGED(spiked) -
NOT COMPONENT(LacesWhite IN ShoeLaces) -
IF NOT ANY OF ...
Comments
Everything following a # character up to the end of the line is a comment and is ignored:
# Competition shoes never ship with the leisure sole.
IF TAGGED(spiked) THEN
BLOCK(leisure) # keep this in sync with the catalog tags
END
To use # as part of a value rather than as a comment, wrap the value in double-quotes, for example SET("#00FF00" TO trim-color OF ShoeToe).
Condition functions
-
TAGGED(tag): Checks whether a specified tag is active (e.g., TAGGED(spiked)). -
TAGGED(tag IN placement): Checks whether a component with the specified tag is active in the placement(e.g., TAGGED(spiked IN sole)). -
COMPONENT(component IN placement): Checks whether a specific component is placed in a given placement (e.g., COMPONENT(SoleVibram IN ShoeSole)). -
HASVALUE(attribute OF placement): Checks whether a particular attribute on a placement is present or set (e.g., HASVALUE(stamp-text OF ShoeToe)). -
VALUE(attribute OF placement EQ value): Checks whether the attribute of the component selected in the placement equals the given value (e.g., VALUE(stamp-text OF ShoeToe EQ "Team Issue")). -
VALUE(attribute OF placement NEQ value): The inverse comparison, true when the attribute differs from the given value. -
EMPTY(value): Checks whether a value or variable is empty or unset (e.g., EMPTY(VAR(chosenTag))). -
NOTEMPTY(value): Checks whether a value or variable holds a non-empty value. -
ISLOCALE(locale): Checks whether a specified locale is active (e.g., ISLOCALE(en-US)) -
ISSITE(site): Checks whether a specified site is active (e.g., ISSITE(Shopify)) -
ALWAYS: Always passes the condition check (e.g.,IF ALWAYS THEN BLOCK ...) -
INITIAL: Only runs the rule during the first evaluation, right after the configuration is loaded. Use it to establish defaults without re-applying them on every later change. -
CHANGED(placement): Only runs the rule when the specified placement has changed -
BEFORESAVE: Only runs the rule during the evaluation performed just before the configuration is saved. -
AFTERSAVE: Only runs the rule during the evaluation performed just after the configuration is saved.
HASVALUE and VALUE read the attribute from the component currently selected in the placement. If nothing is selected in the placement, HASVALUE is false, and VALUE compares against an empty value.
Keywords
The language uses several standard keywords when combining multiple statements:
-
IN: Indicates a location or container relationship, as in COMPONENT(LacesWhite IN ShoeLaces). -
OF: Indicates ownership or a property relationship, as in HASVALUE(stamp-text OF ShoeToe). -
TO: Used for assignment, as in SET("Approved" TO stamp-text OF ShoeSole). -
AS: Used for variable definition, as in LET(sole AS COMPONENT(ShoeSole)). -
EQ,NEQ: Equality and inequality comparison, as in VALUE(stamp-text OF ShoeToe EQ "Team Issue").
Variables
Variables can be referenced anywhere an identifier is allowed using VAR(name) syntax. This enables dynamic values in conditions and effects:
IF ALWAYS THEN
LET(myTag AS ATTRIBUTE(selectedTag OF options))
IF TAGGED(VAR(myTag)) THEN
DEBUG(VAR(myTag))
END
END
Like every other effect, LET has to live inside a rule - use IF ALWAYS THEN ... END when a variable is needed unconditionally. Variables assigned this way remain available to the rules that follow.
Define and assign a variable using a LET effect:
LET(variable-name AS variable-value)
Variable value can be calculated using a formula-like syntax, please see the Expression chapter. Once defined, variables can be reassigned new values if necessary.
Access a variable using VAR expression:
VAR(variable-name)
If a variable is not yet defined, an empty value will be returned.
Names and values
Names of tags, components, placements, and attributes are written directly, without quotes. Besides letters and digits, they may contain _, -, /, ., $, and , characters.
Any value that contains a space or another character - such as # or ( - must be wrapped in double-quotes:
SET("Limited Edition" TO stamp-text OF ShoeSole)
Within a quoted value, \\" inserts a double-quote, \\\\ a backslash, and \\n, \\r, and \\t the corresponding whitespace characters.
Because a comma is a regular name character, comma-separated lists must be written without spaces around the commas. SELECT(SoleVibram,SoleRubber IN ShoeSole) is valid, while SELECT(SoleVibram, SoleRubber IN ShoeSole) is a syntax error.
Case sensitivity
Language keywords, statements, and effects must be in uppercase.
Effects
Effects are applied when a rule is activated. Some effects result in the enablement or disablement of specific components, similar to declarative rules. Other rule effects allow to perform more explicit actions, such as selecting a component into a placement.
Availability effects
-
BLOCK(tag): Prevent or remove any component or functionality associated with the specified tag. -
BLOCK(tag IN placement): A variation of the BLOCK effect that applies only to components of a specific placement. -
BLOCKALL(placement): Blocks all components within the placement. This effect is typically followed by one or moreALLOWeffects to enable some of components in the placement. -
ALLOW(tag): Permit or enable components or functionality associated with the specified tag. -
ALLOW(tag IN placement): A variation of the ALLOW effect that applies only to components of a specific placement.
Selection effects
-
SELECT(component IN placement): Select or enable a particular component in the specified placement. -
SELECTBYTAG(tag IN placement): Select or enable a particular tagged component in the specified placement.
Both selection effects accept a comma-separated list instead of a single name, which declares a fallback order:
SELECT(SoleVibram,SoleRubber,SoleBasic IN ShoeSole)
SELECTBYTAG(premium,standard,basic IN ShoeSole)
The names are tried from left to right, and the first one that can actually be selected wins. A name is skipped when no matching component exists in the placement, or when the matching component is currently unavailable - because it is out of stock, or because another rule blocks it. If none of the listed names can be selected, the placement is left untouched.
SELECTBYTAG picks the first available component carrying the tag, in the order the components are defined in the placement.
Both effects are skipped when the requested component is already selected, so a rule can safely re-state the intended selection on every evaluation.
Update configuration
-
SET(value TO attribute OF placement): Assign a value to an attribute of the component selected in the specified placement. -
SETPLACEMENT(value TO attribute OF placement): Assign a value to an attribute of the placement itself, rather than of the component selected in it. -
SETQUANTITY(value OF placement): Assign a numeric quantity to the component selected in the specified placement. Non-numeric values are ignored. -
UPDATEBLUEPRINT(value OF path): Updates the blueprint configuration value, for example a view or a group property.
Requirement and validation effects
-
REQUIRESTRING(attribute OF placement): Enforce that the named attribute is set to a string value. -
REQUIRENUMBER(attribute OF placement): Enforce that the named attribute is set to a numeric value.
Variable assignment
-
LET(name AS expression): Assigns the result of an expression to a variable for use in subsequent rules.
Debugging
-
DEBUG(expression): Outputs the value of an expression for debugging purposes.
Other effects
-
ACTION(name arg0 arg1 ...): When an effect is triggered, a controller eventruleEventwill be triggered. An event will be triggered at most once per each state change.
Expressions
Expression functions can be used within LET and DEBUG effects.
|
Effect function |
Example |
Description |
|---|---|---|
|
VAR |
VAR(name) |
Returns the value of a variable |
|
COMPONENT |
COMPONENT(placement) |
Returns the component at the specified placement |
|
ATTRIBUTE |
ATTRIBUTE(name OF placement) |
Returns the attribute value |
|
TAGS |
TAGS(placement) |
Returns the tags at a placement, comma-separated |
|
FINDPLACEHOLDER |
FINDPLACEHOLDER(placement) |
Finds the first available placeholder component |
|
FINDACTUAL |
FINDACTUAL(placement) |
Finds the first available regular component |
|
TOUPPER |
TOUPPER(value) |
Converts value to uppercase |
|
TOLOWER |
TOLOWER(value) |
Converts value to lowercase |
|
CONCAT |
CONCAT(value value ...) |
Concatenates multiple values |
|
REPLACE |
REPLACE(value pattern replacement) |
Replaces pattern in value |
Any expression that cannot be resolved - a missing placement, an empty attribute, an undefined variable - returns an empty value rather than raising an error.
Examples
Below are some rule examples using the specific placements (ShoeSole, ShoeToe, ShoeLaces), components (LacesWhite, LacesBlack, SoleRubber, SoleVibram, ToeLeatherBlack, ToeLeatherWhite), attribute (stamp-text), and tags (spiked, spikeless).
Single condition: checking if a tag is active
IF TAGGED(spiked) THEN
BLOCK(spikeless)
END
Explanation: If spiked is active, then we block anything tagged with spikeless.
Multiple conditions and effects
IF ALL OF
TAGGED(spikeless)
COMPONENT(SoleRubber IN ShoeSole)
THEN
SELECT(SoleVibram IN ShoeSole)
SET("UltraActive" TO stamp-text OF ShoeSole)
END
Explanation : If spikeless is active AND SoleRubber is currently in ShoeSole,
-
we replace it with SoleVibram in ShoeSole,
-
and set the attribute stamp-text of ShoeSole to "UltraActive".
Using ANY OF (OR condition)
IF ANY OF
NOT TAGGED(spiked)
COMPONENT(LacesWhite IN ShoeLaces)
THEN
BLOCK(spiked)
END
Explanation : If either spiked is not active OR LacesWhite is in ShoeLaces, then we block spiked. In other words, as soon as one of the conditions is true, the actions (BLOCK(spiked)) are executed.
Using ALL OF (AND condition)
IF ALL OF
TAGGED(spiked)
HASVALUE(stamp-text OF ShoeToe)
THEN
SELECT(ToeLeatherBlack IN ShoeToe)
END
Explanation : If spiked is active AND there is a stamp-text attribute set on ShoeToe, we select ToeLeatherBlack in ShoeToe.
Negation
IF NOT COMPONENT(LacesBlack IN ShoeLaces) THEN
SELECT(LacesWhite IN ShoeLaces)
END
Explanation : If LacesBlack is not present in ShoeLaces, then select LacesWhite in ShoeLaces.
Selection with a fallback order
IF TAGGED(spiked) THEN
SELECT(SoleVibram,SoleRubber IN ShoeSole)
END
Explanation: If spiked is active, try to select SoleVibram in ShoeSole. If SoleVibram does not exist in that placement or is currently unavailable - out of stock, or blocked by another rule - fall back to SoleRubber. If neither can be selected, ShoeSole keeps whatever it had.
Fallback by tag
IF INITIAL THEN
SELECTBYTAG(premium,standard IN ShoeLaces)
END
Explanation: When the configuration is first loaded, select the first available component tagged premium in ShoeLaces. If no premium component is available, select the first available one tagged standard instead.
Establishing defaults on load
IF INITIAL THEN
SELECT(LacesWhite IN ShoeLaces)
SET("Standard Issue" TO stamp-text OF ShoeSole)
END
Explanation: These effects apply only during the first evaluation. Later on the shopper can freely change the laces and the stamp text without the rule resetting their choice.
Reacting to a specific placement change
IF ALL OF
CHANGED(ShoeSole)
TAGGED(spiked IN ShoeSole)
THEN
SELECTBYTAG(spiked IN ShoeToe)
END
Explanation: Only when ShoeSole is the placement that just changed, AND the component now selected there is tagged spiked, we pull a matching spiked component into ShoeToe. Using CHANGED keeps the rule from re-applying when an unrelated placement is edited.
Comparing an attribute value
IF VALUE(stamp-text OF ShoeSole EQ "Team Issue") THEN
BLOCK(leisure IN ShoeLaces)
ELSE
ALLOW(leisure IN ShoeLaces)
END
Explanation: When the stamp-text on ShoeSole reads exactly "Team Issue", leisure laces are blocked; otherwise they are explicitly allowed. Use NEQ for the inverse comparison.
Chaining checks with ELSEIF
IF COMPONENT(SoleVibram IN ShoeSole)
THEN
SET("Trail" TO stamp-text OF ShoeSole)
ELSEIF COMPONENT(SoleRubber IN ShoeSole)
THEN
SET("Street" TO stamp-text OF ShoeSole)
ELSE
SET("Custom" TO stamp-text OF ShoeSole)
END
Explanation: The first matching branch wins. Note that every ELSEIF carries its own THEN, and one END closes the entire chain.
Blocking everything, then allowing a subset
IF TAGGED(spiked) THEN
BLOCKALL(ShoeLaces)
ALLOW(competition IN ShoeLaces)
ALLOW(reinforced IN ShoeLaces)
END
Explanation: For spiked shoes, every component in ShoeLaces is blocked first, and then only those tagged competition or reinforced are allowed back. This is usually easier to maintain than blocking each unwanted tag individually.
Variables and expressions
IF ALWAYS THEN
LET(soleCode AS COMPONENT(ShoeSole))
LET(label AS TOUPPER(CONCAT(VAR(soleCode) "-" ATTRIBUTE(stamp-text OF ShoeToe))))
IF NOTEMPTY(VAR(label)) THEN
SET(VAR(label) TO stamp-text OF ShoeSole)
ELSE
DEBUG("No label could be built")
END
END
Explanation: The code of the component currently in ShoeSole is combined with the stamp-text of ShoeToe, upper-cased, and stored in the label variable. If anything was produced, it is written to stamp-text of ShoeSole; otherwise a trace message is logged for debugging.
Falling back to a placeholder
IF ALWAYS THEN
LET(toe AS COMPONENT(ShoeToe))
IF EMPTY(VAR(toe)) THEN
LET(placeholder AS FINDPLACEHOLDER(ShoeToe))
IF NOTEMPTY(VAR(placeholder)) THEN
SELECT(VAR(placeholder) IN ShoeToe)
END
END
END
Explanation: If nothing is selected in ShoeToe, look up the first available placeholder component for that placement and select it, so the shoe still renders. Note that EMPTY and NOTEMPTY take a name or a VAR(...) reference, so the expression result is stored in a variable first.
Placement attributes and quantity
IF TAGGED(spiked) THEN
SETPLACEMENT(compact TO display-mode OF ShoeLaces)
SETQUANTITY(2 OF ShoeLaces)
END
Explanation: SETPLACEMENT writes display-mode on the ShoeLaces placement itself, which is useful for driving presentation. SETQUANTITY changes the quantity of the component selected in ShoeLaces - here, ordering two sets of laces.
Site and locale targeting
IF ALL OF
ISSITE(Shopify)
NOT ISLOCALE(en-US)
THEN
BLOCK(domestic-only)
UPDATEBLUEPRINT(false OF views.0.visible)
END
Explanation: On the Shopify storefront, outside the en-US locale, components tagged domestic-only are blocked and the first view is hidden through a blueprint update.
Notifying the host application on save
IF ALL OF
BEFORESAVE
TAGGED(spiked)
THEN
ACTION(auditSelection ShoeSole "spiked configuration")
END
Explanation: Just before the configuration is saved, and only for spiked configurations, a ruleEvent named auditSelection is raised on the controller with the two arguments. The host application decides what to do with it.
Nested rules
IF COMPONENT(SoleVibram IN ShoeSole) THEN
IF TAGGED(spiked) THEN
SET("Spiked Vibram" TO stamp-text OF ShoeSole)
END
IF ANY OF
TAGGED(spikeless)
NOT HASVALUE(stamp-text OF ShoeSole)
THEN
SET("Default Sole" TO stamp-text OF ShoeSole)
END
END
Explanation:
-
The outer condition checks if SoleVibram is placed in ShoeSole.
-
Then inside:
-
If spiked is also active, set the stamp-text of ShoeSole to "Spiked Vibram".
-
If either spikeless is active or stamp-text is missing, set the stamp-text to "Default Sole".
-
-