---
title: "Conditional Logic"
description: "Show or hide a control in the block editor based on another control's value, the block's CSS class, or the block style variation, using Lazy Blocks Pro."
url: "https://www.lazyblocks.com/docs/blocks-controls/conditional-logic/"
lastUpdated: 2026-09-09
source: "blocks-controls/conditional-logic.mdx"
---
# Conditional Logic [Pro]

Conditional Logic hides a control in the block editor until its rules pass. A block with a Layout select and eight layout-specific options shows two controls instead of nine, and the seven that do not apply are out of the way rather than greyed out.

Rules are set per control. Open the control in the block builder, find **Conditional Logic** in its settings, and add a rule.

## What a rule can test

A rule has three parts: what to look at, an operator, and a value to compare against.

The first dropdown lists every control on the block under a **Controls** heading, and two more sources under **Other**:

| Source | What it reads |
| ------ | ------------- |
| any control | that control's stored value |
| `CSS Class Name` | the block's `className` attribute, which holds whatever a user typed in the Advanced panel |
| `Block Styles` | the applied style variation, matched through `className` |

**Block Styles** is greyed out until the block has at least one style variation.

A control inside a Repeater appears in the list under its parent, and stores its target as `parent-name.child-name`.

## Operators

Nine operators exist. Which ones the second dropdown offers depends on the control type, because most of them only make sense for some kinds of value.

| Label | Stored value | Offered for |
| ----- | ------------ | ----------- |
| `Has any value` | `!=empty` | every control except Checkbox, Toggle, Inner Blocks and Message, plus both `Other` sources |
| `Has no value` | `==empty` | the same list |
| `Is equal to` | `==` | Text, Textarea, Number, Range, URL, Email, Password, Rich Text, Classic Editor, Code Editor, Select, Radio, Color Picker, Date Time Picker, Units, Checkbox, Toggle |
| `Is not equal to` | `!=` | the same list |
| `Contains` | `==contains` | the `Is equal to` list minus Checkbox and Toggle, plus `CSS Class Name` |
| `Is greater than` | `>` | Number, Range, Gallery, Posts, Taxonomy, Users, Repeater |
| `Is less than` | `<` | the same list |
| `Has class` | `==class` | `CSS Class Name` |
| `Has no class` | `!=class` | `CSS Class Name` |

On **Block Styles** the last two are labelled `Has style` and `Has no style`.

Two control types behave differently from the rest. Checkbox and Toggle are not offered the empty operators at all, and their value field is locked to a single option, `Checked`. **Inner Blocks** has a name so it appears in the list, but no operator applies to it, so its operator dropdown comes up empty.

The value field changes with the source. Select and Radio give you a dropdown of their own choices, Block Styles gives you a dropdown of the block's style variations, and everything else is a text field.

### A count, not a value

For Gallery, Repeater, Posts, Taxonomy and Users, `Is greater than` and `Is less than` compare the **number of items**, not the value. "Is greater than 2" on a Gallery control means the block has three images or more. On a Repeater it means three rows or more.

The same conversion makes the empty operators work on these controls: an empty gallery counts as no value, so `Has no value` passes.

Posts, Taxonomy and Users only hold a list when their **Multiple** setting is on. With Multiple off they hold a single value, and the range operators compare that value as a number instead of counting it.

## Rules, and groups of rules

Inside a group, **and** joins the rules. Every rule in the group has to pass.

Between groups, **or** joins them. The control is shown when any one group passes in full.

So this pair of groups:

```
Group 1   layout        Is equal to        grid
          images        Is greater than    2

or

Group 2   Block Styles  Has style          outline
```

shows the control on a grid layout with more than two images, or on any block using the `outline` style.

Add a rule to the current group with the **and** button. Add a whole new group with **Add Rule Group**.

## Matching a style or a class

`Has class` matches a whole class name, not a fragment. A rule of `Has class` and `card` passes for `card wide` and fails for `card-wide`. Use `Contains` when you want a fragment.

**Block Styles** stores the style's name and matches the class Gutenberg generates from it. A variation named `outline` is stored as `outline` and matched against `is-style-outline`, so you pick the name from the dropdown and never type the class yourself.

A block that has never had a class or a style applied has no `className` attribute at all, and a rule against it is skipped rather than passed or failed.

## What it does not do

Conditional Logic is an editor feature and nothing more. It decides whether a control is drawn in the inspector or in the block body. It does not touch the stored value and it does not touch the rendered block.

Three consequences follow, and all three surprise people:

- **A hidden control keeps its value.** Hide a control after someone filled it in and the value is still on the block, still passed to your block code, and still printed on the front end.
- **Your template has to repeat the condition.** If the output should disappear along with the control, guard it in Handlebars with `{{#if}}` or in PHP with an `if` of your own.
- **A required control that is hidden still blocks saving.** The save lock checks every control on the block without consulting its rules, so a required control hidden by conditional logic locks the post with no visible field to fix. Do not mark a conditional control as required.

## Where the rules are stored

The rules live on the control itself, under `conditional_logic`, as an array of groups where each group is an array of rules. Exporting a block carries them along.

```json title="Block JSON"
"control_a1b2c3": {
  "type": "number",
  "name": "columns",
  "label": "Columns",
  "placement": "inspector",
  "conditional_logic": [
    [
      { "control": "layout", "operator": "==", "value": "grid" },
      { "control": "images", "operator": ">", "value": "2" }
    ],
    [
      { "control": "__BLOCK_STYLE__", "operator": "==class", "value": "outline" }
    ]
  ]
}
```

`value` is always a string, even for the numeric comparisons, and it is absent on a rule using one of the empty operators. `__BLOCK_STYLE__` is how Block Styles is stored; `CSS Class Name` is stored as `className`.

A rule that targets a Repeater child from outside the Repeater reads the first row only. Rules on controls inside the Repeater are evaluated per row, so each row shows and hides its own controls independently.

## Documentation Index
> Fetch the complete documentation index at: https://www.lazyblocks.com/llms.txt
> Fetch every page in a single file at: https://www.lazyblocks.com/llms-full.txt
