---
title: Shortcodes for Content Generation
audience: content
source: us-core 8.46
generated: 2026-05-27 by scripts/llms/build.php (hybrid: skeleton auto, per-shortcode body from manual overlays)
---

<!--
  GENERATED FILE — do not edit directly.
  Per-shortcode bodies come from scripts/llms/manual/shortcodes/<config-id>.md
  Intro comes from              scripts/llms/manual/shortcodes/_intro.md
  Order & categories from       scripts/llms/manifest.php
  Rebuild:  php scripts/llms/build.php --wp-load=… --only=content-shortcodes
  Direct edits here will be lost on the next regeneration.
-->

# Shortcodes for Content Generation

> Compact guide for AI agents that compose page content (`post_content`) using UpSolution shortcodes. Each entry tells you **when to use** the shortcode, **when to avoid** it, lists the most useful parameters, and shows minimal copy-paste examples plus a couple of common combinations.
>
> Cross-cutting rules (root structure, nesting graph, attribute encoding, palette tokens, anti-patterns) are in [`composition-rules.md`](composition-rules.md) — read that first when assembling new blocks.
>
> Three parameter packs are shared across most shortcodes and documented once: [Effects](element-effects.md), [Display Logic](element-display-logic.md), [Design](element-design.md). The per-shortcode **Key parameters** tables below list only element-specific params; consult the shared files when a shortcode needs scroll motion, conditional rendering, or custom CSS / classes / visibility breakpoints.
>
> One more cross-cutting reference: many text / link / image params accept **dynamic values** — `{{the_title}}`, `{{site_title}}`, `{{tax|category}}`, `{{<custom-field>}}` for text params; per-param enum keys like `"type":"post"` / `"type":"author_page"` / `"type":"popup_image"` for `link` params. The complete reference (every token, every link enum, plus an auto-generated per-(shortcode, parameter) matrix) is at [Dynamic Values](element-dynamic-values.md). When a parameter row below says _supports dynamic values_ or you see `{{…}}` in an example, that's the place to look up valid substitutions.
>
> Conventions:
>
> - Shortcode tags are shown with their `us_*` / `vc_*` prefix exactly as they must appear in `post_content`.
> - Examples use `text` fenced blocks so agents do not treat them as PHP or HTML.
> - Containers (`vc_row`, `vc_column`, `hwrapper`, `vc_tta_*`) are listed first — every shortcode block must live inside `vc_row` → `vc_column` at the top level.

## Containers

### `vc_row` — Row / Section

**When to use**: the top-level container of any page block. Every shortcode in `post_content` must be wrapped in `vc_row → vc_column` at the root; nothing else can sit directly under `post_content`. This is also the only place that can carry a section-level background (image, video, image slider), a sticky behaviour, shape dividers between sections, and full-viewport height.

**Avoid when**:
- you only need to group a couple of inline elements with a gap — use `[us_hwrapper]` or `[us_vwrapper]` inside a column instead;
- you need a nested grid inside a column — use `vc_row_inner` + `vc_column_inner` (it has only column-layout params, no section-level features);
- you want a horizontally scrollable list — use `[us_content_carousel]` (out of scope of this iteration).

**Key parameters**

**Width & vertical size**

| Param | What it does |
|-------|--------------|
| `width` | **Content** width — `default` (theme default ~1240px), `full` (content bleeds edge-to-edge), `full_with_indents` (full content + side gutters), `custom`. Controls the inner content container only. **The row's background** (color set via `css="…"`, `us_bg_*` image / video / slider, overlay, shape dividers) **is always full-viewport-width regardless of this param** — at render time `<section class="l-section">` is the full-width host of all background layers, and `width_*` modifies only the child `.l-section-h` content wrapper. So a hero with a coloured / imaged background does **not** need `width="full"` to get an edge-to-edge background; set `full` only when the **content itself** should reach the screen edges (full-width images, edge-to-edge banner copy, wide carousels). |
| `width_custom` | Custom width when `width="custom"`. Default `1240px`. Slider in `px`. |
| `height` | Vertical padding preset — `default` (theme default ~4vh), `auto` (no padding), `small`, `medium`, `large`, `huge`. |
| `full_height` | `1` makes the row fill the viewport height (typical for hero sections). Default `0`. |
| `v_align` | Vertical alignment of content when `full_height="1"` — `top`, `center` (default), `bottom`. |
| `color_scheme` | Color palette — empty (content colors), `alternate`, `primary` (primary bg + white text), `secondary` (secondary bg + white text), `footer-top`, `footer-bottom`. |
| `row_title` | Optional editor-only label for this row (shown in the builder UI, not on the front-end). |

**Background — image**

| Param | What it does |
|-------|--------------|
| `us_bg_image_source` | `none` (default), `media` (custom upload), `featured` (post's featured image). |
| `us_bg_image` | Media library ID when `us_bg_image_source="media"`. |
| `us_bg_size` | `cover` (default — fill, may crop), `contain` (fit, may letterbox), `initial`. |
| `us_bg_pos` | One of 9 positions: `top left`, `top center`, `top right`, `center left`, `center center` (default), `center right`, `bottom left`, `bottom center`, `bottom right`. |
| `us_bg_repeat` | `repeat` (default), `repeat-x`, `repeat-y`, `no-repeat`. |
| `us_bg_parallax` | Parallax effect — empty (none, default), `vertical`, `horizontal`, `still` (fixed). |
| `us_bg_parallax_width` | Background width for `horizontal` parallax. Default `130%`. |
| `us_bg_parallax_reverse` | `1` reverses `vertical` parallax direction. |
| `us_bg_overlay_color` | Overlay tint on top of the background (HEX/RGBA or palette var, e.g. `rgba(0,0,0,0.5)`). |

**Background — video or image slider**

| Param | What it does |
|-------|--------------|
| `us_bg_show` | Foreground background-media — empty (none), `video`, `img_slider`. Combines with the image background above. |
| `us_bg_video` | Video URL (YouTube/Vimeo/mp4/webm/ogg). Supports dynamic values. Visible when `us_bg_show="video"`. |
| `us_bg_video_disable_width` | Below this screen width, hide the video and fall back to the static image. Default `600px`. |
| `us_bg_slider_ids` | Comma-separated media IDs for the slider when `us_bg_show="img_slider"`. |
| `us_bg_slider_include_post_thumbnail` | `1` prepends the post's featured image. |
| `us_bg_slider_orderby` | `1` randomises slide order. |
| `us_bg_slider_transition` | `slide` (default) or `crossfade`. |
| `us_bg_slider_speed` | Transition duration. Default `1000ms`. |
| `us_bg_slider_interval` | Auto-rotation interval. Default `3.0s`. |

**Sticky behaviour**

| Param | What it does |
|-------|--------------|
| `sticky` | `1` pins the row to the top of the viewport during scroll. Useful for context bars, ToC headers. |
| `sticky_shadow` | Shadow when stuck — `none` (default), `thin`, `wide`. |

**Columns layout**

The **desktop column layout is determined by the `width` attribute on each child `vc_column`**, not by an attribute on `vc_row` itself. The `columns` attribute below is auto-computed from those widths at render time and cannot be set manually — passing `columns="3"` on the row alone does nothing if the columns do not carry `width="1/3"`. See `vc_column` for the full list of allowed `width` fractions and the layouts they produce. The responsive overrides below (`laptops_columns`, `tablets_columns`, `mobiles_columns`) **do** work as attributes on the row, because there are no narrower-viewport equivalents on child columns.

| Param | What it does |
|-------|--------------|
| `columns` | _Computed automatically from child `vc_column` widths._ Do not set on the row — it is overwritten at render time. Documented here only because it shows up in the live builder's UI. |
| `columns_layout` | CSS `grid-template-columns` value when the child widths reduce to `custom`. Also auto-computed from children — do not set manually. |
| `laptops_columns` | Override columns layout on laptops (≤1380px). Accepts the same enum as the computed `columns` (`1`, `2`, `3`, `4`, `5`, `6`, `1-2`, `2-1`, `1-3`, `3-1`, `1-4`, `4-1`, `1-5`, `5-1`, `2-3`, `3-2`, `1-2-1`, `1-3-1`, `1-4-1`, `custom`). `inherit` (default) reuses desktop. |
| `tablets_columns` | Override on tablets (≤1024px). `inherit` reuses laptop. |
| `mobiles_columns` | Override on mobile (≤600px). Defaults to `1`. |
| `columns_gap` | Spacing between columns. Default `3rem`. Two shapes (no separate `tablets_columns_gap` / `mobiles_columns_gap` attribute exists): **scalar** — `columns_gap="2rem"`, applied to every breakpoint, becomes the vertical gap when columns stack on mobile; **per-breakpoint JSON** — `columns_gap='{"default":"6rem","mobiles":"1rem"}'` (single quotes around the attribute, raw JSON inside). Keys: `default`, `laptops`, `tablets`, `mobiles` — all optional, missing keys fall back to CSS default. See composition-rules §3.4 for the full pattern. |
| `equal_columns_height` | `1` forces all columns to the same height (useful for cards). |
| `content_placement` | Vertical position of column content when `equal_columns_height="0"` — `top` (default), `middle`, `bottom`. |
| `gap` | Additional gap on top of `columns_gap` (free-form CSS units). |
| `columns_type` | `1` adds extra padding around each column's content — improves cards with backgrounds. |
| `columns_reverse` | `1` reverses column stacking on mobile (last column becomes first when stacked). |
| `ignore_columns_stacking` | `1` opts the row out of the global "Columns Stacking Width" theme option (useful for icon-grids that should stay multi-column on narrow screens). |

**Shape dividers** (decorative wave / triangle / curve between sections)

Top and bottom each have their own independent set with the same shape:

| Param | What it does |
|-------|--------------|
| `us_shape_show_top` / `us_shape_show_bottom` | `1` enables the divider at the top / bottom edge of the row. |
| `us_shape_top` / `us_shape_bottom` | Shape style — `tilt`, `curve`, `curve-inv`, `triangle`, `triangle-inv`, `triangle-2`, `triangle-2-inv`, `wave`, `zigzag`, `custom`. Default `tilt`. |
| `us_shape_custom_top` / `us_shape_custom_bottom` | Media ID of a custom SVG when `us_shape_*="custom"`. |
| `us_shape_height_top` / `us_shape_height_bottom` | Divider height (CSS units). Default `15vmin`. |
| `us_shape_color_top` / `us_shape_color_bottom` | Divider color (HEX/RGBA/palette var, e.g. `_content_bg` to match the next section). |
| `us_shape_overlap_top` / `us_shape_overlap_bottom` | `1` lets the row's content peek over the divider. |
| `us_shape_flip_top` / `us_shape_flip_bottom` | `1` flips the shape horizontally. |

**Minimal example**

```text
[vc_row][vc_column][us_text text="Hello"][/vc_column][/vc_row]
```

**Common combinations**

Hero section — background image, dark overlay, centered content, viewport height. The background image and overlay span the full viewport regardless of `width`, so leave `width` at its default and let the content stay within the theme's content column:

```text
[vc_row full_height="1" v_align="center" us_bg_image_source="media" us_bg_image="123" us_bg_overlay_color="rgba(0,0,0,0.5)" color_scheme="primary"]
  [vc_column]
    [us_text text="Headline" tag="h1"]
    [us_btn label="Get started" link="url:%23signup" align="center"]
  [/vc_column]
[/vc_row]
```

Two equal-width columns of features, with a wave divider into the next section:

```text
[vc_row us_shape_show_bottom="1" us_shape_bottom="wave" us_shape_color_bottom="_content_bg_alt"]
  [vc_column width="1/2"][us_iconbox icon="fas|bolt" title="Fast"]Cold-start under 50ms.[/us_iconbox][/vc_column]
  [vc_column width="1/2"][us_iconbox icon="fas|lock" title="Secure"]End-to-end encryption.[/us_iconbox][/vc_column]
[/vc_row]
```

Image slider as the row background (auto-rotating, fades between slides):

```text
[vc_row full_height="1" v_align="center" us_bg_show="img_slider" us_bg_slider_ids="11,12,13" us_bg_slider_transition="crossfade" us_bg_slider_interval="5.0s" us_bg_overlay_color="rgba(0,0,0,0.3)" color_scheme="primary"]
  [vc_column]
    [us_text text="Built for builders" tag="h1"]
  [/vc_column]
[/vc_row]
```

Three equal columns that become 2 on tablet, 1 on mobile:

```text
[vc_row tablets_columns="2" mobiles_columns="1" columns_gap="2rem" equal_columns_height="1"]
  [vc_column width="1/3"][us_iconbox icon="fas|bolt"  title="Fast"]…[/us_iconbox][/vc_column]
  [vc_column width="1/3"][us_iconbox icon="fas|lock"  title="Secure"]…[/us_iconbox][/vc_column]
  [vc_column width="1/3"][us_iconbox icon="fas|heart" title="Friendly"]…[/us_iconbox][/vc_column]
[/vc_row]
```

Sticky context bar at the top of a long page:

```text
[vc_row sticky="1" sticky_shadow="thin" height="auto" color_scheme="alternate"]
  [vc_column][us_text text="📍 You are reading: Section title"][/vc_column]
[/vc_row]
```

**Anti-patterns**

- Putting elements directly inside `vc_row` without a `vc_column` — they will not render correctly.
- Stacking `vc_row` inside `vc_column` to add a nested grid — use `vc_row_inner` + `vc_column_inner` for nested grids instead.
- Setting `full_height="1"` on every row — reserve it for hero sections, otherwise the page feels endless.
- **Setting `columns="N"` on the row and omitting `width="…"` on the child columns.** The attribute is recomputed from the children at render time and silently collapses to `cols_1`. Always put `width="<num>/<den>"` on each `vc_column`. See the **Columns layout** section above.
- Setting `us_bg_show="video"` with autoplay on a long page without `us_bg_video_disable_width` — mobile devices struggle to render a background video and battery drains. The disable-width fallback (default `600px`) is your friend.
- Loading background images for rows below the fold without considering page weight — combine with theme-level image optimization or set `us_bg_image_source="featured"` so WP serves the correct size.

### `vc_row_inner` — Inner Row

**When to use**: a nested grid inside a `vc_column`. Use when one column of the outer row needs its own multi-column layout (e.g. a sidebar block with two stacked cards, or a feature row inside a tab section).

**Avoid when**:
- you only need a horizontal arrangement of two-three elements with a gap — `[us_hwrapper]` is lighter;
- you are at the top level — that's `vc_row`'s job, not `vc_row_inner`.

**Key parameters**

`vc_row_inner` only has **column-layout** parameters — none of the section-level row settings (no background image, no color scheme, no full-height, no sticky). Its children must be `vc_column_inner`.

The desktop column layout follows the same rule as `vc_row`: it is **derived from the `width` attribute on each child `vc_column_inner`**, not from any attribute on the inner row itself. See `vc_column` for the full list of allowed `width` fractions and their layouts. The responsive overrides below work as attributes on the inner row.

| Param | What it does |
|-------|--------------|
| `columns` | _Computed automatically from child `vc_column_inner` widths._ Do not set — overwritten at render time. |
| `columns_layout` | Auto-computed CSS `grid-template-columns` value when children reduce to `custom`. Do not set. |
| `columns_gap` | Gap between columns. Same shape as `vc_row.columns_gap` — either scalar (`"2rem"`) or per-breakpoint JSON in single quotes (`'{"default":"4rem","mobiles":"1rem"}'`). No separate `tablets_columns_gap` / `mobiles_columns_gap` attribute. See composition-rules §3.4. |
| `columns_reverse` | `1` reverses column stacking on mobile (last column goes on top). |
| `equal_columns_height` | `1` makes columns the same height. |
| `content_placement` | Vertical alignment of column content — `top` / `middle` / `bottom`. |
| `columns_type` | `1` adds extra padding around the column content (useful when columns have a background). |
| `gap` | Additional gap (CSS units). |
| `laptops_columns` / `tablets_columns` / `mobiles_columns` | Responsive column overrides on the inner row. Same enum as the computed `columns` on `vc_row`. |
| `ignore_columns_stacking` | `1` ignores the global "Columns Stacking Width" theme option. |

**Minimal example**

```text
[vc_row][vc_column]
  [vc_row_inner]
    [vc_column_inner width="1/2"][us_text]Left[/us_text][/vc_column_inner]
    [vc_column_inner width="1/2"][us_text]Right[/us_text][/vc_column_inner]
  [/vc_row_inner]
[/vc_column][/vc_row]
```

**Anti-patterns**

- Wrapping `vc_row_inner` directly under `post_content` — it must live inside `vc_row → vc_column`.
- Mixing `vc_column` (instead of `vc_column_inner`) inside `vc_row_inner` — wrong tag, layout breaks.
- Trying to set a background image / `color_scheme` / `full_height` on `vc_row_inner` — those are section-level and only exist on `vc_row`. Wrap the inner row in an outer row if you need a section background.
- **Omitting `width="…"` on `vc_column_inner` children.** Same trap as on `vc_row`: bare inner columns default to `width="1/1"` and the row collapses to one column.

### `vc_column` — Column

**When to use**: the only allowed direct child of `vc_row`. Every content element lives inside a column.

**Avoid when**:
- you want columns inside columns — use `vc_row_inner` + `vc_column_inner` for nested grids;
- you need a horizontal/vertical wrapper with gap controls — use `[us_hwrapper]` / `[us_vwrapper]` inside the column.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `width` | **The column's fractional width — sets the row layout.** Format `<num>/<den>`. Default `1/1` (single full-width column). See the table below for the full enum. |
| `sticky` | `1` pins the column at the top during scroll (typical for sidebars). |
| `sticky_pos_top` | When `sticky=1`, distance from the top of the viewport at which the column sticks (CSS units, e.g. `80px`, `6rem`). |
| `stretch` | `1` stretches the column to the browser-window edge, ignoring the row's content width. |
| `us_bg_overlay_color` | A color/gradient drawn as an overlay above the column background — useful when an image is set on the parent row. |
| `link` | Wraps the whole column in a clickable link. **Note**: all inner clickable elements become non-clickable in this mode. JSON shape: `{"url":"...","target":"_blank","rel":"nofollow"}`. |

### How column layout works

The row's overall layout is **derived from the `width` attributes of its child columns**, not from any attribute on the row itself. At render time, us-core scans the row's children, collects their `width` values, and reduces them to a layout descriptor. A row with no widths (or `width="1/1"` on each child) is always a single-column row, no matter what other attributes you set.

Allowed `width` values and the layouts they produce:

| Children `width` (in order) | Resulting layout |
|-----------------------------|------------------|
| `1/1` | 1 column, full width |
| `1/2`, `1/2` | 2 equal columns |
| `1/3`, `1/3`, `1/3` | 3 equal columns |
| `1/4` × 4 | 4 equal columns |
| `1/5` × 5 | 5 equal columns |
| `1/6` × 6 | 6 equal columns |
| `1/3`, `2/3` | 2 columns, 1/3 + 2/3 |
| `2/3`, `1/3` | 2 columns, 2/3 + 1/3 |
| `1/4`, `3/4` | 2 columns, 1/4 + 3/4 |
| `3/4`, `1/4` | 2 columns, 3/4 + 1/4 |
| `1/5`, `4/5` | 2 columns, 1/5 + 4/5 |
| `4/5`, `1/5` | 2 columns, 4/5 + 1/5 |
| `1/6`, `5/6` | 2 columns, 1/6 + 5/6 |
| `5/6`, `1/6` | 2 columns, 5/6 + 1/6 |
| `2/5`, `3/5` | 2 columns, 2/5 + 3/5 |
| `3/5`, `2/5` | 2 columns, 3/5 + 2/5 |
| `1/4`, `1/2`, `1/4` | 3 columns, 1/4 + 1/2 + 1/4 |
| `1/5`, `3/5`, `1/5` | 3 columns, 1/5 + 3/5 + 1/5 |
| `1/6`, `2/3`, `1/6` | 3 columns, 1/6 + 2/3 + 1/6 |
| any other combination | falls back to a custom CSS-grid layout (each `width` becomes a `1fr`-scaled track) |

Responsive overrides for narrower viewports are controlled by `laptops_columns` / `tablets_columns` / `mobiles_columns` on the parent **`vc_row`** (not the columns) — see `vc_row` for details.

**Minimal example**

Single full-width column:

```text
[vc_row][vc_column][us_text text="Body"][/vc_column][/vc_row]
```

Three equal columns:

```text
[vc_row]
  [vc_column width="1/3"][us_text text="A"][/vc_column]
  [vc_column width="1/3"][us_text text="B"][/vc_column]
  [vc_column width="1/3"][us_text text="C"][/vc_column]
[/vc_row]
```

**Common combinations**

Sticky sidebar column (1/4) next to a wider content column (3/4):

```text
[vc_row]
  [vc_column width="1/4" sticky="1" sticky_pos_top="80px"]
    [us_additional_menu source="docs-nav" layout="ver"]
  [/vc_column]
  [vc_column width="3/4"]
    [us_text text="Doc title" tag="h1"]
    [vc_column_text]Body text with multiple paragraphs and rich HTML.[/vc_column_text]
  [/vc_column]
[/vc_row]
```

Three columns on desktop, two on tablet, one on mobile — desktop comes from the column widths, the others from the row attributes:

```text
[vc_row tablets_columns="2" mobiles_columns="1"]
  [vc_column width="1/3"]…[/vc_column]
  [vc_column width="1/3"]…[/vc_column]
  [vc_column width="1/3"]…[/vc_column]
[/vc_row]
```

**Anti-patterns**

- **Omitting `width` on multi-column rows.** Bare `[vc_column]` defaults to `width="1/1"`, so three bare `[vc_column]` siblings still render as a single full-width column (the layout is computed from widths, not from how many columns you wrote).
- **Setting `columns="3"` on the `vc_row` and expecting it to split the row.** That attribute is overwritten at render time from the child `width` values; without `width` on each column it has no effect.
- **Mixing fractions with different denominators in a three-or-more-column row** unless the combination is one of the special triples (`1/4+1/2+1/4`, `1/5+3/5+1/5`, `1/6+2/3+1/6`). Other mixes fall through to a custom CSS-grid layout and may not look as you expect.
- **Setting `link` on a column that contains buttons or other links** — those become non-clickable.
- **Using `stretch="1"` on every column** — the row stops feeling like a row.

### `vc_column_inner` — Inner Column

**When to use**: the only allowed direct child of `vc_row_inner` (mirror of `vc_column` ↔ `vc_row` at the inner level).

**Key parameters**

Same shape as `vc_column`. The most important is `width="<num>/<den>"` — it determines the inner row's layout, exactly as on `vc_column`. See the `vc_column` entry for the full width-to-layout mapping.

| Param | What it does |
|-------|--------------|
| `width` | Fractional width of this inner column. Required when the inner row has more than one column. See `vc_column` for the full enum. |

**Minimal example**

See `vc_row_inner` above.

**Anti-patterns**

- Using `vc_column_inner` inside `vc_row` (instead of `vc_column`) — wrong tag at the wrong level.
- **Omitting `width="…"`** when the inner row has multiple columns — defaults to `1/1` and the row collapses to a single column.

### `us_hwrapper` — Horizontal Wrapper

**When to use**: place a small group of inline elements side-by-side with a gap — two buttons, an icon next to text, a price with a "from" label. Lives inside a `vc_column`.

**Avoid when**:
- you need a full grid (multiple rows of side-by-side blocks) — use `vc_row_inner` + `vc_column_inner`;
- you have a single element — wrappers are pointless.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `alignment` | Horizontal alignment of items inside the wrapper — `none` (default), `left`, `center`, `right`, `justify`. Responsive (can differ per breakpoint via the builder UI). |
| `valign` | Vertical alignment of items when their heights differ — `top` (default), `middle`, `bottom`, `baseline`, `stretch`. |
| `inner_items_gap` | Spacing between items. Default `1.2rem`. Accepts `px`, `rem`, `em`. |
| `wrap` | `1` allows children to wrap to the next line on narrow screens; default `0` keeps them in one row. |
| `stack_on_mobiles` | `1` stacks the items into a single column on mobile breakpoints (useful for two CTA buttons that should be stacked on small screens). |
| `link` | Wraps the whole row in a clickable link. JSON shape: `{"url":"...","target":"_blank","rel":"nofollow"}`. **Important**: all inner clickable elements (buttons, links) become non-clickable when this is set. |

**Minimal example**

```text
[us_hwrapper inner_items_gap="1rem" valign="middle"]
  [us_btn label="Primary"   link="url:%23a" style="1"]
  [us_btn label="Secondary" link="url:%23b" style="2"]
[/us_hwrapper]
```

**Common combinations**

Two CTAs that stack on mobile:

```text
[us_hwrapper inner_items_gap="1rem" valign="middle" stack_on_mobiles="1"]
  [us_btn label="Get started" link="url:%23signup"   style="1"]
  [us_btn label="Learn more"  link="url:%23features" style="2"]
[/us_hwrapper]
```

Icon next to a heading, vertically aligned to the baseline:

```text
[us_hwrapper inner_items_gap="0.5rem" valign="baseline"]
  [us_text text="Why us" tag="h2"]
  [us_text text="(updated)" tag="span"]
[/us_hwrapper]
```

**Anti-patterns**

- Using the old/invalid `gap` parameter — the correct name is `inner_items_gap`.
- Stuffing 5+ elements into one wrapper without `wrap="1"` or `stack_on_mobiles="1"` — they overflow on narrow screens.
- Setting `link` on a wrapper that contains its own buttons — the buttons become non-clickable.

### `us_vwrapper` — Vertical Wrapper

**When to use**: stack a small group of elements vertically with a controlled gap — heading + sub-heading + button, three icon-boxes inside a card, a small product card. Lives inside a `vc_column`.

**Avoid when**:
- the default vertical flow inside a column already gives the right spacing — adding a wrapper just for one gap is overkill;
- you need horizontal arrangement — use `[us_hwrapper]`;
- you need a multi-row grid — use `vc_row_inner` + `vc_column_inner`.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `alignment` | Horizontal alignment of children — `none` (default), `left`, `center`, `right`. |
| `valign` | Vertical distribution of children inside the wrapper — `top` (default), `middle`, `bottom`, `justify`. |
| `inner_items_gap` | Vertical spacing between children. Default `0.7rem`. Accepts `px`, `rem`, `em`. |
| `link` | Wraps the whole stack in a clickable link. JSON shape: `{"url":"...","target":"_blank","rel":"nofollow"}`. Note: any clickable elements inside (buttons, links) become non-clickable when this is set. |

**Minimal example**

```text
[us_vwrapper alignment="center" inner_items_gap="1rem"]
  [us_text]<h2>Plan name</h2>[/us_text]
  [us_text]$19/mo[/us_text]
  [us_btn label="Choose" link="url:%23signup"]
[/us_vwrapper]
```

**Anti-patterns**

- Using `us_vwrapper` to recreate a `vc_column` layout — columns already stack vertically.
- Setting `link` on a wrapper that contains its own buttons or links — those become non-clickable.
- Mixing `gap` (the old/invalid param name) — the correct name is `inner_items_gap`.

### `vc_tta_accordion` — Accordion

**When to use**: FAQ sections, long support docs, "click to reveal" content — a stacked list of titles where each opens to show its body. Each row is a `vc_tta_section` inside.

**Avoid when**:
- you have only 2 short panels — use tabs or two columns;
- the content must always be visible (don't hide it behind a click for SEO-critical text);
- you need horizontal tab switching — that's `vc_tta_tabs`.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `toggle` | `1` allows several sections to be opened at the same time; default `0` (only one open). |
| `scrolling` | When `toggle="0"`, `1` (default) scrolls the page to the opened section. Set `0` to disable. |
| `remove_indents` | `1` strips the left/right indents inside section panels. |
| `faq_markup` | `1` outputs FAQ structured-data markup for SEO. Available when the schema-markup theme option is on. |
| `c_align` | Title alignment — `none` (default, left) or `center`. |
| `c_icon` | Control indicator icon — `''` (none) / `chevron` / `plus` / `triangle`. Default `chevron`. |
| `c_position` | Position of the control icon — `left` (before title) or `right` (after title, default). |
| `title_tag` | HTML tag for section titles — `div` (default), `h2`–`h6`. Use `h3`/`h4` on FAQ pages for SEO. |
| `title_size` | Custom title font-size (CSS units). |

**Minimal example**

```text
[vc_tta_accordion]
  [vc_tta_section title="How do I sign up?"][us_text]Click "Sign up" above.[/us_text][/vc_tta_section]
  [vc_tta_section title="Do you offer refunds?"][us_text]Yes, within 30 days.[/us_text][/vc_tta_section]
[/vc_tta_accordion]
```

**Common combinations**

FAQ accordion with schema markup, H3 titles, plus icon on the left:

```text
[vc_tta_accordion faq_markup="1" title_tag="h3" c_icon="plus" c_position="left"]
  [vc_tta_section title="Question 1"][us_text]Answer 1[/us_text][/vc_tta_section]
  [vc_tta_section title="Question 2"][us_text]Answer 2[/us_text][/vc_tta_section]
[/vc_tta_accordion]
```

**Anti-patterns**

- Hiding the primary value proposition inside the first collapsed accordion item — users may not click.
- Setting `toggle="1"` for an FAQ — defeats the "one focused question" UX.
- Using `c_icon=""` (no indicator) — users don't realise the rows are expandable.

### `vc_tta_tabs` — Tabs

**When to use**: switching between a small number of grouped content panels with horizontal tab triggers — feature comparisons, plan tiers, FAQ topics. Each tab is a `vc_tta_section` inside.

**Avoid when**:
- you have only 2 short blocks and they fit side-by-side — use `vc_row.columns="2"`;
- you have many sequential expandable rows — use `vc_tta_accordion` instead;
- you need a vertical tab strip — use `vc_tta_tour`.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `layout` | Visual style of the tab strip — `default`, `simple`, `simple2`, `simple3`, `radio`, `radio2`, `radio3`, `modern`, `trendy`, `timeline`, `timeline2`. |
| `tabs_alignment` | Tab-strip alignment — `none` (default), `center`, `justify`. |
| `switch_sections` | What triggers a tab switch — `click` (default) or `hover`. |
| `accordion_at_width` | CSS width below which the tabs collapse into an accordion (e.g. `768px`). Leave empty for automatic. |
| `title_tag` | HTML tag for tab labels — `div` (default), `h2`–`h6`. |
| `title_size` | Custom font-size of the tab labels. |
| `title_font` | Tab-label font family (Theme Options fonts). |

**Minimal example**

```text
[vc_tta_tabs]
  [vc_tta_section title="Starter"][us_text]Starter content[/us_text][/vc_tta_section]
  [vc_tta_section title="Pro"][us_text]Pro content[/us_text][/vc_tta_section]
[/vc_tta_tabs]
```

**Common combinations**

Centered tab strip that becomes an accordion under 768px:

```text
[vc_tta_tabs layout="modern" tabs_alignment="center" accordion_at_width="768px"]
  [vc_tta_section title="Overview"][us_text]…[/us_text][/vc_tta_section]
  [vc_tta_section title="Features"][us_text]…[/us_text][/vc_tta_section]
  [vc_tta_section title="Pricing"][us_text]…[/us_text][/vc_tta_section]
[/vc_tta_tabs]
```

**Anti-patterns**

- Putting more than ~5 tabs on a single strip — labels overflow or wrap on narrow viewports. Use `accordion_at_width` to mitigate.
- Using `vc_tta_tabs` for very long content per tab — accordions paginate that better on mobile.
- Using `switch_sections="hover"` on touch devices — hover doesn't exist there, users get stuck on the first tab.

### `vc_tta_tour` — Vertical Tabs (Tour)

**When to use**: tabs whose triggers sit in a vertical column (typical for "step-by-step" walkthroughs or feature-on-the-left, content-on-the-right layouts). Each step is a `vc_tta_section`.

**Avoid when**:
- you have few short panels and a wide viewport — horizontal `vc_tta_tabs` reads better;
- you need each step always visible — render them as consecutive rows instead.

**Key parameters**

Most parameters mirror `vc_tta_tabs` (`layout`, `switch_sections`, `c_align`, `accordion_at_width`, `title_font`/`title_weight`/`title_transform`/`title_size`/`title_lineheight`, `title_tag`, `c_icon`, `c_position`). See `vc_tta_tabs.md` for those.

**Tour-specific** (no equivalents in `vc_tta_tabs`):

| Param | What it does |
|-------|--------------|
| `tab_position` | Which side the vertical strip sits on — `left` (default) or `right`. |
| `controls_size` | Width of the strip relative to the section — `auto` (default, content-based), `10`, `20`, `30`, `40`, `50` (percent of the wrapper). Use a fixed % when you want a stable trigger column even if labels change length. |

**Layout differences from tabs**: `vc_tta_tour.layout` accepts the same set as tabs **except** `timeline`/`timeline2` — those are horizontal-only and not available here. Available values: `default`, `simple`, `simple2`, `simple3`, `radio`, `radio2`, `radio3`, `modern`, `trendy`.

**Minimal example**

```text
[vc_tta_tour]
  [vc_tta_section title="1. Install"][us_text text="Download…"][/vc_tta_section]
  [vc_tta_section title="2. Configure"][us_text text="Open settings…"][/vc_tta_section]
  [vc_tta_section title="3. Launch"][us_text text="Run the app…"][/vc_tta_section]
[/vc_tta_tour]
```

**Common combinations**

Right-anchored tour strip of fixed width (30%), good for a feature-list with screenshot on the left:

```text
[vc_tta_tour tab_position="right" controls_size="30"]
  [vc_tta_section title="Dashboards"][us_image image="11" size="large"][/vc_tta_section]
  [vc_tta_section title="Reports"][us_image image="12" size="large"][/vc_tta_section]
  [vc_tta_section title="Exports"][us_image image="13" size="large"][/vc_tta_section]
[/vc_tta_tour]
```

**Anti-patterns**

- Putting more than ~6 steps on a single tour — the vertical strip becomes hard to scan on mobile (it collapses to a horizontal scroller or stack on narrow screens). Pair with `accordion_at_width` to mitigate.
- Setting `layout="timeline"` or `"timeline2"` — those styles are horizontal-only and not available on tour; the value will be ignored or fall back to `default`.

### `vc_tta_section` — Tab / Accordion / Tour Item

**When to use**: a single panel inside `vc_tta_tabs`, `vc_tta_accordion`, or `vc_tta_tour`. The tag is the same in all three contexts; the wrapper decides how it renders.

**Avoid when**:
- you use it outside any of the three parent containers — it has no rendering context;
- you want a generic info card — use `[us_iconbox]` or a styled `[us_text]`.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `title` | Label shown on the trigger (tab name / accordion summary). Required. Default `Tab 1`. Supports dynamic values. |
| `tab_link` | Optional link — when set, **clicking the trigger navigates to this URL** instead of switching the panel. Use this to turn a tab into a navigation item that opens an external page or anchor. JSON shape: `{"url":"...","target":"_blank","rel":"nofollow"}`. Supports dynamic values. |
| `active` | `1` makes this section open by default when the page loads. Default `0`. Only one section should typically have `active="1"` per container (in accordion with `toggle="1"`, more than one is allowed). |
| `indents` | `1` stretches the section content to the **full available width**, removing the default left/right indents. Useful for full-width media inside a tab. Default `0`. |
| `icon` | Icon shown next to the trigger title (`set\|name`, e.g. `fas\|info-circle`). |
| `i_position` | Icon position — `left` (default, before title) or `right` (after title). |
| `bg_color` | Per-section background color (HEX/RGBA/palette var). Overrides the parent container's background for this section only. |
| `text_color` | Per-section text color. Use together with `bg_color` for sections that need a distinct theme. |

There is **no** `tab_id` parameter for anchor / deep-linking — for that purpose use the common `el_id` parameter from the Design group instead, and link to `#yourid` from elsewhere on the page.

**Minimal example**

```text
[vc_tta_section title="Starter"]
  [us_text text="Starter content"]
[/vc_tta_section]
```

**Common combinations**

A section that opens by default, with an icon prefix:

```text
[vc_tta_section title="Overview" active="1" icon="fas|home" i_position="left"]
  [us_text text="Welcome…"]
[/vc_tta_section]
```

A tab that navigates to an external page instead of switching panels:

```text
[vc_tta_section title="Docs" tab_link="url:https%3A%2F%2Fexample.com%2Fdocs|target:_blank"]
[/vc_tta_section]
```

A featured/highlighted section with custom colors and stretched content:

```text
[vc_tta_section title="Pro" bg_color="#1a73e8" text_color="#fff" indents="1"]
  [us_image image="123" size="full"]
[/vc_tta_section]
```

**Anti-patterns**

- Using `tab_id` for deep-linking — that parameter does not exist on `vc_tta_section`. Set `el_id` (from the Design group) and link to `#<id>` from outside.
- Setting `active="1"` on multiple sections inside a tabs/tour container — only one panel can be active at a time; the last wins.
- Empty `title` — the trigger becomes unclickable on touch and unreadable to screen readers.
- Using `tab_link` thinking it's a deep-link — it converts the tab into a navigation link that **leaves** the panel-switching behaviour entirely.

### `us_content_carousel` — Content Carousel

**When to use**: a horizontally-rotating slider of arbitrary children (icon boxes, person cards, CTA blocks, testimonial cards…). Anything you can put inside a `vc_column` you can put inside one slide here.

**Avoid when**:
- the children are all images — `[us_image_slider]` is purpose-built for that (smaller markup, fullscreen view, thumb nav);
- the children are post entries — `[us_post_list]` / `[us_post_carousel]` know how to query them;
- you only need a static row — `[us_hwrapper]` or two `vc_column`s avoid the JS init cost.

**Children**: any leaf element. **Not allowed as children** (the container blocks them): `vc_column`, other carousels (`us_carousel`, `us_content_carousel`, `us_post_carousel`…), `vc_tta_*` tabs/accordions, `us_gmaps`, `us_cform`, `us_dropdown`, `us_search`, `us_login`, `us_page_block`, `us_separator`, `us_gallery`, `us_image_slider`. Each direct child becomes one slide.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `items_gap` | Gap between slides, **px only** (default `30px`). Unlike other carousels this one has no rem/em option. |
| `items_quantity` | Slides visible at once. Responsive JSON: `'{"default":"4","tablets":"2","mobiles":"1"}'`. Default `4`. |
| `arrows` | `1` shows prev/next arrows. |
| `arrows_style` | Arrow style preset — `circle`, `square`, `none`. |
| `arrows_pos` | Arrow position relative to the carousel — `inside`, `outside`. |
| `arrows_offset` | Pixel offset of arrows from the carousel edge. |
| `dots` | `1` shows pagination dots under the slides. |
| `auto_play` | `1` enables auto-rotation. |
| `timeout` | Auto-rotation period in ms (e.g. `5000`). Only applies when `auto_play="1"`. |
| `transition_speed` | Slide transition duration in ms. |
| `loop` | `1` (default) wraps around at the ends; `0` stops at first/last. |
| `mouse_drag` | `1` lets visitors drag-swipe with the mouse. |
| `touch_swipe` | `1` (default) enables touch swipe on mobile. |

**Minimal example**

```text
[us_content_carousel arrows="1" dots="1" items_quantity='{"default":"3","tablets":"2","mobiles":"1"}']
  [us_iconbox icon="fas|star" title="Fast" text="Loads in under 1s."]
  [us_iconbox icon="fas|shield" title="Secure" text="End-to-end encryption."]
  [us_iconbox icon="fas|bolt" title="Scalable" text="From 1 to 1M users."]
[/us_content_carousel]
```

**Common combinations**

Testimonials rotation, one card at a time, auto-advance every 6s:

```text
[us_content_carousel items_quantity="1" auto_play="1" timeout="6000" arrows="1" dots="1"]
  [us_person name="Anna Lee" role="CTO, Acme" text="..." image="123"]
  [us_person name="Mark Yu"  role="Lead, Beta" text="..." image="124"]
[/us_content_carousel]
```

**Anti-patterns**

- Wrapping a single child — there's nothing to carousel; use the child directly.
- Putting `vc_column` inside (the container's `except` list blocks it — the markup will render but the column won't behave as a slide).
- `items_gap` written as `1rem` — only `px` is accepted here. Use a number with `px` or none.
- `items_quantity` set to `4` on mobile — slides become unreadable. Always set a per-breakpoint JSON.

## Basic

### `vc_column_text` — Rich Text (WPBakery)

**When to use**: a block of body copy edited via the WordPress classic editor — supports lists, headings, links, inline images via standard HTML. The natural pick for long-form prose, blog-style intros, terms-of-service text. Also exposes a "Show More" reveal for long content and a `background_inside_text` flag for gradient-text effects.

**Avoid when**:
- you only need a single styled paragraph or a heading — `[us_text]` is leaner and supports UpSolution's dynamic-values popup;
- you need HTML pasted verbatim without WP filtering — use `[us_html]`.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `content` | The body of the block. Type `editor` (rich HTML) — pass it as the shortcode's **inner content** between the opening and closing tags, **not** as a quoted attribute. |
| `background_inside_text` | `1` clips the parent row/column background image (or gradient) **inside** the text glyphs — produces the "gradient text" effect. Default `0`. |

**"Show More" reveal** (optional)

| Param | What it does |
|-------|--------------|
| `show_more_toggle` | `1` collapses the content to a fixed height and adds a "Show More" link. Useful for long Terms / FAQ answers / changelogs that should not dominate the page on first view. Default `0`. |
| `show_more_toggle_height` | Visible height before the reveal. Default `200px`. |
| `show_more_toggle_text_more` | Link label while collapsed. Default `Show More`. |
| `show_more_toggle_text_less` | Link label while expanded. Default `Show Less`. |
| `show_more_toggle_alignment` | Position of the reveal link — `none` (default — left), `left`, `center`, `right`. |

**Minimal example**

```text
[vc_column_text]
<h2>About</h2>
<p>We make software for designers.</p>
<ul><li>Fast</li><li>Reliable</li></ul>
[/vc_column_text]
```

(The body is the `content` — passed as inner content.)

**Common combinations**

Collapsible terms-of-service block with centred "Show More" link:

```text
[vc_column_text show_more_toggle="1" show_more_toggle_height="180px" show_more_toggle_alignment="center"]
<h3>Terms of service</h3>
<p>By using this site you agree to…</p>
<p>Section 2. Liability…</p>
<p>Section 3. Refunds…</p>
[/vc_column_text]
```

Gradient-text effect — the row's background image is clipped inside the headline glyphs (combine with a row that has `us_bg_image_source="media"`):

```text
[vc_column_text background_inside_text="1"]
<h1 style="font-weight:800;">GRADIENT HEADLINE</h1>
[/vc_column_text]
```

**Anti-patterns**

- Using a non-existent `text` parameter — the correct name is `content`, and it works only as the shortcode's inner content (between `[vc_column_text]…[/vc_column_text]`).
- Using `vc_column_text` for a single label or one-line heading — `[us_text]` is lighter and avoids WP's `wpautop` filtering quirks.
- Setting `show_more_toggle_height` so short that the "Show More" link is more prominent than the visible content — defeats the purpose.
- Combining `background_inside_text="1"` without an actual background on the parent — the text becomes invisible (it's clipped to nothing).
- Pasting unsanitised HTML with inline `<script>` tags — use `[us_html]` if you really need raw output.

### `us_text` — Text Block

**When to use**: a **single line / short string** wrapped in an HTML tag of your choice (`div`, `p`, `h1`–`h6`, `span`). Pick this for headings, sub-headings, taglines, small labels, button-adjacent text — anything that is one piece of text under one wrapping tag. The text supports dynamic tokens (post title, ACF fields, etc.) via the builder's dynamic-values popup.

**Avoid when**:
- you need long-form prose with multiple paragraphs, lists, embedded images or other rich HTML — use `[vc_column_text]`;
- you need to paste a third-party HTML snippet — use `[us_html]`;
- you need a clickable CTA — use `[us_btn]`.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `text` | The text string — **passed as a parameter value**, not as inner content of the shortcode. Supports the dynamic-values popup (e.g. `{{post.title}}`-style tokens picked from the builder UI). |
| `tag` | HTML wrapper tag — `div` (default), `p`, `h1`/`h2`/`h3`/`h4`/`h5`/`h6`, `span`, and other tags from the theme's allow-list. Use `h1`–`h6` to make the text a real heading for SEO/accessibility. |
| `link` | Wrap the text in a link. JSON shape: `{"url":"...","target":"_blank","rel":"nofollow"}`. |
| `hide_with_empty_link` | `1` hides the element entirely when `link.url` is empty — useful when the text is driven by dynamic values that may be absent. |
| `icon` | Optional icon (`set\|name`, e.g. `fas\|chevron-right`). Available when `fit_to_width="0"`. |
| `iconpos` | Icon position — `left` (default, before text) or `right`. |
| `fit_to_width` | `1` auto-sizes the font so the text spans the full container width. Hides `icon`/`iconpos` when on. Default `0`. |
| `background_inside_text` | `1` clips a parent's background image/gradient inside the text glyphs (for the "gradient text" look). Default `0`. |

**Minimal example**

```text
[us_text text="Welcome" tag="h1"]
```

**Common combinations**

Hero stack — H1 + sub-line + CTA, vertically centered:

```text
[us_vwrapper alignment="center" inner_items_gap="1rem"]
  [us_text text="Build better, faster" tag="h1"]
  [us_text text="A workflow your team will actually use." tag="p"]
  [us_btn label="Try it" link="url:%23signup" align="center"]
[/us_vwrapper]
```

Heading with a leading icon:

```text
[us_text text="Why us" tag="h2" icon="fas|star" iconpos="left"]
```

**Anti-patterns**

- Wrapping a paragraph of HTML between `[us_text]...[/us_text]` tags — `us_text` ignores inner content, only the `text` attribute is rendered. Use `[vc_column_text]` for prose with multiple tags or paragraphs.
- Multiple `tag="h1"` on the same page — keep one `<h1>` per page for SEO. Use `h2`/`h3` for subsequent headings.
- Stuffing many sentences into one `text=` string just to avoid `vc_column_text` — long values become unwieldy to edit and you lose paragraph semantics.

### `us_btn` — Button

**When to use**: a stand-alone call-to-action link (Sign up, Learn more, Download). Pairs naturally with a `text` block above it inside the same column.

**Avoid when**:
- you need a button inside a form submit — use the submit control of `[us_cform]` instead;
- you want a clickable icon without text — use `[us_iconbox]` with a link param.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `label` | Visible button text. Required for any CTA — never leave default `"Click Me"`. |
| `link` | Destination. JSON shape: `{"url":"...","target":"_blank","rel":"nofollow"}`. |
| `style` | Visual style id from Theme Options → Buttons (per-site). Common values: `1` primary, `2` outline, `3` ghost — but the actual set depends on the install. |
| `align` | `left`, `center`, `right`, `justify`, or `none` (= default). Responsive. |
| `icon` | Optional icon, format `set\|name` (e.g. `fas\|arrow-right`). |
| `iconpos` | `left` (before text) or `right` (after text). |

**Minimal example**

```text
[us_btn label="Get started" link="url:%23pricing"]
```

**Common combinations**

Centered CTA with icon-after-text:

```text
[us_btn label="Sign up" link="url:https%3A%2F%2Fexample.com%2Fsignup" align="center" icon="fas|arrow-right" iconpos="right"]
```

Secondary button next to a primary one (wrap both in `hwrapper` so they sit side-by-side):

```text
[us_hwrapper valign="middle" inner_items_gap="1rem"]
  [us_btn label="Get started" link="url:%23pricing" style="1"]
  [us_btn label="Learn more"   link="url:%23features" style="2"]
[/us_hwrapper]
```

**Anti-patterns**

- Setting `link="url:#"` and leaving it like that — produces a button that does nothing. If the destination isn't known yet, use a placeholder anchor on the same page.
- Mixing more than two styles in one row — pick one primary CTA and at most one secondary; reserve the third style for a follow-up section.

### `us_iconbox` — Icon Box

**When to use**: a feature / benefit / service card with an icon (or small image), a title, and an optional rich-text description. Typical content for "Features" or "How it works" sections.

**Avoid when**:
- the feature is just text without a visual — use `[us_text]`;
- you need an interactive flip card — use `[us_flipbox]`;
- the icon is the whole CTA — use `[us_btn]` with `icon=...`;
- you need a full pricing/comparison card — `[us_pricing]`.

**Key parameters**

**Content**

| Param | What it does |
|-------|--------------|
| `icon` | Required when there's no `img`. Format `set\|name` (e.g. `fas\|bolt`, `far\|heart`). Default `fas\|star`. |
| `img` | Media library ID — used **instead of** `icon` to render a small image where the icon would go. |
| `title` | The card headline. Supports dynamic values. |
| `title_tag` | HTML tag for the title — `h4` (default), `h1`–`h6`, `div`, `p`, `span`. |
| `title_size` | Custom CSS font-size for the title (e.g. `1.25rem`). |
| `content` | Description. **Tip**: this is an `editor`-typed param (rich HTML allowed), so pass it as the shortcode's inner content between the opening and closing tags rather than as a quoted attribute. |
| `link` | Optional link — makes the whole card clickable. JSON shape: `{"url":"...","target":"_blank","rel":"nofollow"}`. |

**Appearance**

| Param | What it does |
|-------|--------------|
| `style` | Visual style of the icon container — `default` (default, simple), `circle` (solid filled circle), `outlined` (outlined circle). |
| `color` | Icon color palette — `primary` (default, theme primary), `secondary`, `light` (theme border color), `contrast` (theme text color), `custom`. |
| `icon_color` | Custom HEX/RGBA for the icon when `color="custom"`. |
| `circle_color` | Custom HEX/RGBA for the icon's circle/background when `color="custom"`. |
| `size` | Icon size in CSS units. Default `2rem`. |
| `iconpos` | Icon position relative to the title/description — `top` (default), `left`, `right`. |
| `alignment` | Text alignment — `none` (default — left), `left`, `center`, `right`. Centred is typical when `iconpos="top"`. |

**Minimal example**

```text
[us_iconbox icon="fas|bolt" title="Fast"]Cold-start under 50ms.[/us_iconbox]
```

(The body is the rich `content` — passed as inner content of the shortcode.)

**Common combinations**

Three feature cards in a row, icon on top, centred text:

```text
[vc_row columns="3"]
  [vc_column][us_iconbox icon="fas|bolt"  title="Fast"     iconpos="top" alignment="center"]Cold-start under 50ms.[/us_iconbox][/vc_column]
  [vc_column][us_iconbox icon="fas|lock"  title="Secure"   iconpos="top" alignment="center"]End-to-end encryption.[/us_iconbox][/vc_column]
  [vc_column][us_iconbox icon="fas|heart" title="Friendly" iconpos="top" alignment="center"]Real humans on chat.[/us_iconbox][/vc_column]
[/vc_row]
```

Icon-left service card with custom colors:

```text
[us_iconbox icon="fas|truck" title="Same-day delivery" iconpos="left" alignment="left" style="circle" color="custom" icon_color="#fff" circle_color="#1a73e8"]Order before 14:00 for delivery today.[/us_iconbox]
```

**Anti-patterns**

- Using a non-existent `text` parameter for the body — the correct name is `content`, and it works best as inner content between `[us_iconbox]…[/us_iconbox]`.
- Using non-existent `style` values like `badge` or `desc` — only `default`, `circle`, `outlined` exist.
- Long paragraphs in `content` — the card should fit one screen; move long copy to a `vc_column_text` next to the iconbox.
- Different `iconpos` values across cards in the same row — visual rhythm breaks; pick one for the whole row.
- Setting both `icon` and `img` — `img` wins; pick one source up front.

### `us_image` — Image

**When to use**: a single image — hero illustration, product shot, screenshot, logo, decorative thumbnail. Supports linking, lazy-loading control, decorative styles (circle, shadow, phone-mockup frames), and captions from media metadata.

**Avoid when**:
- you want multiple images in a grid — use `[us_gallery]`;
- you want a single image as a row's full background — use `vc_row.us_bg_image` instead;
- you want a horizontally scrollable image strip — use `[us_image_slider]`;
- you need a lightbox click on a single image — `us_image` has no built-in lightbox; wrap it in `[us_popup]` with image content, or use `[us_gallery]` with a single ID and `items_click_action="popup_image"`.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `image` | Media library ID of the image. Required. Supports dynamic values (e.g. ACF / featured image). |
| `size` | WP image size preset — `thumbnail`, `medium`, `large` (default), `full`, or any registered custom size. |
| `align` | `none` (default), `left`, `center`, `right`. |
| `link` | Optional link wrapping the image. JSON shape: `{"url":"...","target":"_blank","rel":"nofollow"}`. Supports dynamic values. |
| `style` | Decorative frame — empty (default, none) / `circle` / `outlined` / `shadow-1` (simple shadow) / `shadow-2` (colored shadow) / `phone12` (phone mock-up, flat) / `phone6-1` (iPhone 6 black realistic) / `phone6-2` (iPhone 6 white realistic) / `phone6-3` / `phone6-4`. This list is hardcoded by the theme, not configurable per-site. |
| `meta` | `1` shows the image title and description from the media library. |
| `meta_style` | When `meta="1"`: `simple` (default — caption below the image) or `modern` (caption overlaid on the image). |
| `disable_lazy_loading` | `1` opts the image out of lazy-loading. Set this for above-the-fold hero images to avoid layout shift on first paint. |

**Minimal example**

```text
[us_image image="123" size="large"]
```

**Common combinations**

Centered product shot with the "Phone 12" mock-up frame:

```text
[us_image image="123" size="large" align="center" style="phone12"]
```

Above-the-fold hero image (no lazy-load), with caption overlay:

```text
[us_image image="123" size="full" disable_lazy_loading="1" meta="1" meta_style="modern"]
```

Linked image with a circle crop (good for avatars):

```text
[us_image image="123" size="medium" style="circle" link="url:%2Fteam"]
```

**Anti-patterns**

- Trying to use `onclick="lightbox"` — that parameter does not exist on `us_image`. For a click-to-zoom UX, either use `[us_gallery ids="..." items_click_action="popup_image"]` with a single image, or wrap `us_image` in `[us_popup]`.
- Forgetting to set `disable_lazy_loading="1"` on a hero image — visitors see a blank above-the-fold area on first paint.
- Using `size="full"` for thumbnail placement — wastes bandwidth on mobile.
- Missing alt text in the media library — `us_image` uses it; missing alt hurts accessibility and SEO.

### `us_separator` — Separator

**When to use**: introduce vertical space or a visible divider between content blocks. Two roles:

- **Spacer** — invisible vertical gap (no line);
- **Divider** — horizontal line with optional thickness/color.

**Avoid when**:
- you just need spacing inside a horizontal/vertical wrapper — use the `gap` param on `us_hwrapper`/`us_vwrapper`;
- you want a decorative shape between sections — use `vc_row.us_shape_*` (shape dividers).

**Key parameters**

| Param | What it does |
|-------|--------------|
| `size` | Vertical space size — preset (`small`/`medium`/`large`/`huge`) or `custom`. |
| `height` | Custom CSS height when `size="custom"` (e.g. `60px`, `4rem`). |
| `show_line` | `1` to draw a visible line, `0` for invisible spacer. |
| `line_width` | Width of the line (`100%`, `50%`, `200px`). |
| `thick` | Line thickness in px. |
| `style` | Line style — `solid` / `dashed` / `dotted` / `double`. |
| `color` | Line color (HEX, RGBA, or theme palette var). |

**Minimal example**

```text
[us_separator size="medium" show_line="1"]
```

**Anti-patterns**

- Using multiple consecutive `us_separator` blocks to "tune" spacing — set one `size="custom" height="..."` instead.
- Heavy decorative lines between every section — kills visual hierarchy. Use sparingly.

## Interactive

### `us_gallery` — Image Gallery

**When to use**: a multi-image gallery in one of several layouts — grid, masonry, METRO mosaic, or horizontal mosaic — with optional lightbox on click. Typical for portfolio cases, "behind the scenes" sections, photo lists.

**Avoid when**:
- you have one image — `[us_image]`;
- you want a sliding/carousel UX — `[us_image_slider]`;
- you want product cards (image + price + CTA) — that's `[us_product_list]` (out of this iteration's scope).

**Key parameters**

**Source**

| Param | What it does |
|-------|--------------|
| `ids` | Comma-separated media library IDs. Required (or use `include_post_thumbnail`). |
| `include_post_thumbnail` | `1` includes the current post's Featured image at the start. |
| `include_us_media_category` | Comma-separated category slugs to include (when using UpSolution Media Categories). |
| `exclude_us_media_category` | Comma-separated category slugs to exclude. |
| `orderby` | `post__in` (default — manual order from `ids`), `date`, `modified`, `rand`, `title`. |
| `order_invert` | `1` reverses the order (no effect for `post__in` or `rand`). |
| `quantity_type` | How many items to show — `all`, `layout_based` (smart, based on chosen layout), `custom`. |
| `quantity` | Item count when `quantity_type="custom"`. Default `12`. |

**Layout / appearance**

| Param | What it does |
|-------|--------------|
| `layout` | `grid` (default) / `masonry` / `metro_1`…`metro_5` / `mosaic_hor`. |
| `columns` | Column count for `grid` / `masonry` layouts. Default `4`. |
| `items_gap` | Gap between thumbnails (CSS units, e.g. `10px`, `1rem`). Default `10px`. |
| `items_ratio` | Aspect ratio per image — `1x1` (default) / `4x3` / `3x2` / `16x9` / `3x4` / `2x3` / `custom`. Hidden for `masonry`, `mosaic_hor`. |
| `items_ratio_width` / `items_ratio_height` | Numeric values when `items_ratio="custom"` (e.g. `21` / `9`). |
| `items_height` | Image height for `mosaic_hor` layout. Default `30cqw`. |
| `items_title` | `1` renders the image title under each thumbnail. |
| `img_fit` | `cover` (default — fill area, crops if needed) / `contain` (fit, may letterbox). |
| `img_size` | WP image size preset — `thumbnail`, `medium`, `large` (default), `full`, or custom. |

**Click behaviour**

| Param | What it does |
|-------|--------------|
| `items_click_action` | What happens when a thumbnail is clicked — `none` (default), `popup_image` (lightbox), `link` (custom URL). |
| `items_link` | Custom link target when `items_click_action="link"`. JSON shape. |

**Pagination** (optional)

| Param | What it does |
|-------|--------------|
| `pagination` | `none` (default) / `load_on_scroll` (infinite-scroll) / `load_on_btn` (load-more button). Only with `quantity_type="custom"`. |
| `pagination_btn_text` | Label for the load-more button. Default `Load More`. |
| `pagination_btn_style` | Per-site button style (Theme Options → Buttons). |

**Minimal example**

```text
[us_gallery ids="12,34,56,78" columns="4" items_click_action="popup_image"]
```

**Common combinations**

Masonry portfolio with custom click-through to a project page:

```text
[us_gallery ids="12,34,56,78,90" layout="masonry" columns="3" items_gap="1rem" items_click_action="link" items_title="1"]
```

METRO mosaic for a featured gallery row (no clicks, just visual):

```text
[us_gallery ids="11,12,13,14,15" layout="metro_2" items_gap="6px" items_click_action="none"]
```

**Anti-patterns**

- Using a non-existent `onclick` parameter — the correct name is `items_click_action`, with values `popup_image` (lightbox) / `link` / `none`.
- Using a non-existent `indents` parameter — the correct name is `items_gap`.
- 30+ images in one gallery without `pagination` — page weight balloons. Set `pagination="load_on_scroll"` or `"load_on_btn"`.
- Mixed aspect ratios across thumbnails without picking `items_ratio` — set a single ratio or use `masonry` to embrace the variation.

### `us_image_slider` — Image Slider

**When to use**: a slideshow of images with prev/next or thumbnail navigation, optional auto-rotation and full-screen view — hero rotations, screenshot carousels, before/after sets.

**Avoid when**:
- you want a grid of thumbnails — `[us_gallery]`;
- you want a slider of mixed-content cards (image + caption + button) — `[us_content_carousel]`;
- you only have one image — `[us_image]`.

**Key parameters**

**Source**

| Param | What it does |
|-------|--------------|
| `ids` | Comma-separated media library IDs. Required. Supports dynamic values. |
| `include_post_thumbnail` | `1` includes the current post's Featured image first. |
| `orderby` | `1` randomises the slide order (the param is a switch — set to `1` for random, `0` for the order given in `ids`). |
| `meta` | `1` shows title and description from the media library on each slide. |

**Image sizing**

| Param | What it does |
|-------|--------------|
| `has_ratio` | `1` enforces a fixed aspect ratio for all slides. When `0` (default), slides keep their natural size. |
| `ratio` | The ratio when `has_ratio="1"` — `1x1` (default), `4x3`, `3x2`, `16x9`, `2x3`, `3x4`, `custom`. |
| `ratio_width` / `ratio_height` | Custom ratio numbers when `ratio="custom"` (e.g. `21` / `9`). |
| `img_fit` | How each image fits the slide box — `scaledown` (default), `contain` (letterbox), `cover` (fill, may crop). |
| `img_size` | WP image size preset — `large` (default), `thumbnail`, `medium`, `full`, etc. |
| `style` | Decorative frame around each slide when `has_ratio="0"` — `none` (default), or a phone-mock-up style (`phone6-1`, `phone6-2`, …). Hardcoded set, same family as `us_image.style`. |
| `fullscreen` | `1` shows a button that opens the active slide in full-screen view. |

**Slider behaviour**

| Param | What it does |
|-------|--------------|
| `autoplay` | `1` enables auto-rotation. The two params below only apply when this is on. |
| `autoplay_period` | Time between automatic slide advances (e.g. `3s`, `5s`). Default `3s`. |
| `pause_on_hover` | `1` (default) pauses auto-rotation while the cursor is over the slider. |
| `arrows` | Prev/Next arrow visibility — `always` (default), and other options. |
| `nav` | Additional navigation — `none` (default), `dots`, `thumbs`. This is the replacement for the "show dots" toggle some other libraries use. |
| `thumbs_width` / `thumbs_gap` | Size and spacing of thumbnails when `nav="thumbs"`. |
| `transition` | `slide` (default) or `crossfade`. |
| `transition_speed` | Animation duration (e.g. `250ms`, `500ms`). |

**Minimal example**

```text
[us_image_slider ids="12,34,56" autoplay="1" autoplay_period="5s" arrows="always" nav="dots"]
```

**Common combinations**

Hero rotation, 16:9, crossfade with thumbs:

```text
[us_image_slider ids="11,12,13" has_ratio="1" ratio="16x9" transition="crossfade" autoplay="1" autoplay_period="6s" nav="thumbs"]
```

Screenshot carousel with full-screen viewer:

```text
[us_image_slider ids="21,22,23,24" img_fit="contain" fullscreen="1" nav="dots"]
```

**Anti-patterns**

- Using `interval` or `dots` — those parameters do not exist. Use `autoplay_period` for the rotation timing and `nav` (`dots`/`thumbs`/`none`) for the additional navigation.
- Setting `autoplay_period` under `3s` — visitors can't read meta captions before the next slide arrives.
- Slider at the very top of a page with `nav="none"` and `arrows` hidden — visitors don't realise there's more content.
- Mixing aspect ratios across slides without setting `has_ratio="1"` — slide heights jump on every transition.

### `us_counter` — Animated Counter

**When to use**: highlight a number that animates from an initial value to a final one when it enters the viewport — "1 200+ customers", "98% uptime", "10 years". Typical for stats/social-proof sections.

**Avoid when**:
- the number is static informational text — use `[us_text]`;
- you need to count down to a date — use `[us_countdown_timer]`.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `final` | Target value, **including any prefix/suffix as part of the string** — `99`, `$70`, `98%`, `1200+`, `35kg`. There is no separate prefix/suffix parameter. |
| `initial` | Starting value of the animation. Same shape as `final` (`0`, `$0`, `1%`). Visible when `animation="none"`. |
| `animation` | `none` (default — animate the number value) or `slide` (slide the digits vertically). |
| `duration` | Animation duration in seconds — `0.5s` to `4.0s` step `0.5s`. Default `2.0s`. |
| `align` | `none` / `left` / `center` / `right`. Default `center`. |
| `color` | `primary` / `secondary` / `heading` / `text` / `custom`. Picks a theme color. |
| `custom_color` | HEX/RGBA value when `color="custom"`. |
| `title` | Caption shown below the number. Supports dynamic values. |
| `title_tag` | HTML tag for the caption — `h6` (default), `h2`–`h5`, `div`, `span`. |
| `title_size` | Custom CSS font-size for the caption. |

**Minimal example**

```text
[us_counter final="1200+" title="Happy customers"]
```

**Common combinations**

Four stats in a row (note: units like `+`, `%`, `K` go inside `final`):

```text
[vc_row columns="4"]
  [vc_column][us_counter final="1200+" title="Customers" color="primary"][/vc_column]
  [vc_column][us_counter final="98%"   title="Uptime"    color="primary"][/vc_column]
  [vc_column][us_counter final="10"    title="Years"     color="primary"][/vc_column]
  [vc_column][us_counter final="50K"   title="Downloads" color="primary"][/vc_column]
[/vc_row]
```

**Anti-patterns**

- Decimal precision that nobody verifies (`1183.27`) — round to a memorable number.
- Vague suffixes (`many`, `lots of`) in `final` — defeats the purpose of a counter.

### `us_countdown_timer` — Countdown Timer

**When to use**: live timer counting down to a fixed datetime — sales, launches, webinars, "early bird closes in...".

**Avoid when**:
- the deadline is recurring (every Monday) — needs a custom widget;
- the value is static or animated from 0 to a target — use `[us_counter]`.

**Key parameters**

**Date** — the target moment is set by separate fields, not a single date string:

| Param | What it does |
|-------|--------------|
| `date_source` | `custom` (default — uses the `time_*` fields below). Additional values (the slug of an ACF datetime field on the current post) appear **only** when the ACF plugin is active. |
| `time_year` | Target year (4-digit). Default is the current year; the range rolls forward each year. |
| `time_month` | Target month (`01`–`12`). |
| `time_day` | Target day (`01`–`31`). |
| `time_hour` | Target hour (`00`–`23`). Default `00`. |
| `time_minute` | Target minute (`00`–`59`). Default `00`. |

**After expiry**

| Param | What it does |
|-------|--------------|
| `action_after_end` | `hide` (default — timer disappears) / `show_message` (replace timer with text). |
| `expired_message` | HTML shown when `action_after_end="show_message"`. The shortcode stores this value **base64-encoded** — write your message normally in the builder, it gets encoded automatically. |

**Appearance**

| Param | What it does |
|-------|--------------|
| `animation` | Digit transition — `none` (default), or one of the slide/zoom/flip variants. |
| `days_label` | Caption under (or beside) the days digits. Default `days`. Set empty to hide the days unit altogether. |
| `hours_label` | Caption for hours. Default `hours`. |
| `minutes_label` | Caption for minutes. Default `minutes`. |
| `seconds_label` | Caption for seconds. Default `seconds`. |
| `label_pos` | Caption position relative to the digits — `bottom` (default) or `aside`. |
| `label_size` | Caption font size (CSS units). Default `1rem`. |
| `label_weight` | Caption font weight (`100`–`900`, or theme default). |
| `label_color` | Caption text color (HEX/RGBA/palette var). |

**Minimal example**

```text
[us_countdown_timer time_year="2026" time_month="12" time_day="31" time_hour="23" time_minute="59" action_after_end="show_message" expired_message="Offer ended"]
```

**Common combinations**

Sale timer that disappears once expired:

```text
[us_countdown_timer time_year="2026" time_month="06" time_day="30" time_hour="23" time_minute="59" animation="slide" action_after_end="hide"]
```

Webinar timer with side-by-side labels (no seconds spinner):

```text
[us_countdown_timer time_year="2026" time_month="11" time_day="15" time_hour="18" time_minute="00" label_pos="aside" seconds_label=""]
```

**Anti-patterns**

- Past dates without `action_after_end="show_message"` — visitors see a row of zeros with no context.
- Showing the seconds caption for multi-day deadlines — the spinning seconds are distracting; set `seconds_label=""` or `label_pos="aside"`.
- Trying to pass a single ISO string (e.g. `date="2026-12-31"`) — that parameter does not exist; date is composed of `time_year` + `time_month` + `time_day` + `time_hour` + `time_minute`.

### `us_flipbox` — Flip Box

**When to use**: a card whose front shows a teaser (icon/image + title + short text) and whose back reveals extra detail (text + optional CTA) on hover or tap.

**Avoid when**:
- you have a lot of back-side text — users won't keep their cursor over the card;
- you need a static feature card — `[us_iconbox]` is simpler;
- the experience must work on touch — flipboxes are awkward there because hover doesn't exist.

**Key parameters**

**Front side**

| Param | What it does |
|-------|--------------|
| `front_title` | Front-side title. |
| `front_title_tag` | `h4` (default), `h1`–`h6`, `div`, `span`. |
| `front_desc` | Front-side description (multi-line). |
| `front_icon_type` | `none` (default), `font` (FA icon), `image` (uploaded). |
| `front_icon_name` | FA icon `set\|name` — used when `front_icon_type="font"`. |
| `front_icon_image` | Media ID — used when `front_icon_type="image"`. |
| `front_icon_pos` | `above_title` (default), and other positions relative to the title. |
| `front_bgcolor` / `front_textcolor` | Background and text colors. |
| `front_bgimage` | Background image media ID. |

**Back side** — same shape with `back_*` prefix: `back_title`, `back_title_tag`, `back_desc`, `back_bgcolor`, `back_textcolor`, `back_bgimage`.

**Link / CTA**

| Param | What it does |
|-------|--------------|
| `link_type` | `none` (default) / `container` (the whole card is a link) / `btn` (an explicit button on the back). |
| `link` | The link URL/target (JSON shape). Visible when `link_type="container"` or `"btn"`. |
| `btn_label` | Button text. Visible when `link_type="btn"`. |
| `btn_style` | Per-site button style. |

**Animation**

| Param | What it does |
|-------|--------------|
| `animation` | Flip style — `cardflip` (default), `cubetilt`, `cubeflip`, `coveropen`. |
| `direction` | Where the back comes from — `n`, `e`, `s`, `w`, `ne`, `se`, `sw`, `nw`. Default `w`. |
| `duration` | Animation duration in seconds (e.g. `0.5s`). |
| `easing` | Easing function — `ease`, `easeInOutExpo`, `easeInOutCirc`. |

**Minimal example**

```text
[us_flipbox front_icon_type="font" front_icon_name="fas|bolt" front_title="Fast" back_title="Sub-50ms" back_desc="Cold-start metrics from p99." link_type="btn" btn_label="See benchmark" link="url:%23benchmark"]
```

**Anti-patterns**

- Critical info hidden only on the back of a flipbox — duplicate it on the front or use a static block.
- Multiple flipboxes with different `direction` in one row — visually inconsistent.

### `us_ibanner` — Interactive Banner

**When to use**: a clickable image card with a hover-revealed overlay containing a title and description — promo tiles, category cards, "discover X" blocks. Often used in 2-/3-column rows. The whole banner is one link (no separate CTA button).

**Avoid when**:
- you want a plain image — `[us_image]`;
- you want a slideshow of banners — `[us_image_slider]`;
- you need an explicit call-to-action button on the card — `[us_iconbox]` (link) or a `[us_cta]` works better, since `us_ibanner` has no `btn_*` of its own.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `image` | Media library ID of the banner image. Required. |
| `size` | WP image size preset — `thumbnail`, `medium`, `large` (default), `full`, or any registered custom size. |
| `title` | Overlay heading shown on hover (default `Title`). |
| `title_size` | Custom CSS font-size for the title. |
| `title_tag` | Heading tag — `h2` (default), `h1`/`h3`–`h6`, `div`, `span`. |
| `desc` | Overlay description text (multi-line). |
| `link` | URL the whole banner clicks to. JSON shape: `{"url":"...","target":"_blank","rel":"nofollow"}`. |
| `ratio` | Aspect ratio of the banner — `1x1` (default), `2x1`, `3x2`, `4x3`, `3x4`, `2x3`, `1x2`. |
| `animation` | Hover-overlay animation — `melete` (default), `soter`, `phorcys`, `aidos`, `caeros`, `hebe`, `aphelia`, `nike`. |
| `easing` | Animation easing — `ease` (default), `easeInOutExpo`, `easeInOutCirc`. |

**Minimal example**

```text
[us_ibanner image="123" title="Summer Sale" desc="Up to 50% off" link="url:%23shop"]
```

**Common combinations**

Three category tiles in a row, 4:3 banners with the `soter` hover animation:

```text
[vc_row columns="3"]
  [vc_column][us_ibanner image="11" title="Apparel" link="url:%2Fcat%2Fapparel" ratio="4x3" animation="soter"][/vc_column]
  [vc_column][us_ibanner image="12" title="Shoes"   link="url:%2Fcat%2Fshoes"   ratio="4x3" animation="soter"][/vc_column]
  [vc_column][us_ibanner image="13" title="Bags"    link="url:%2Fcat%2Fbags"    ratio="4x3" animation="soter"][/vc_column]
[/vc_row]
```

**Anti-patterns**

- Heavy text in `desc` over a busy image — overlay readability drops. Keep `desc` short, or pre-darken the image.
- Different `ratio` values across banners in the same row — visual rhythm breaks; pick one ratio for the whole row.
- Trying to add a separate button overlay — `us_ibanner` doesn't have button params; the whole banner is the click target via `link`. For text + image + CTA-button cards, compose `us_image` + `us_text` + `us_btn` inside a column instead.

### `us_itext` — Interactive Text

**When to use**: animated heading where one phrase cycles through several alternatives — "We build [websites|apps|brands]". Great for hero headlines, taglines.

**Avoid when**:
- the headline must be static for SEO ranking — animated text still indexes, but reads strangely in metadata;
- you need plain styled prose — `[us_text]`.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `texts` | The phrase set. **Each alternate goes on its own line** (literal newlines inside the param value). The first line is shown first; the rest are cycled. |
| `tag` | Wrapping HTML tag — `h2` (default), `h1`/`h3`–`h6`, `div`, `p`, `span`. |
| `align` | `none` / `left` / `center` / `right`. Default `center`. |
| `animation_type` | Cycling animation — `fadeIn` (default), `zoomIn`, `slide`, `rotate`, `blur`, `reveal`, `zoomInChars`, `typingChars`. |
| `duration` | Single animation duration (e.g. `0.3s`). |
| `delay` | Pause between cycles (e.g. `5s`). |
| `disable_part_animation` | `1` keeps the whole line static (the multi-line `texts` becomes a single visible block). Default `0`. |
| `dynamic_bold` | `1` renders the changing word in bold. Only when `disable_part_animation="0"`. |
| `dynamic_color` | Color (HEX/RGBA/palette var) for the changing word. Only when `disable_part_animation="0"`. |

**Minimal example**

```text
[us_itext texts="We build websites
We build apps
We build brands" tag="h1" animation_type="typingChars"]
```

**Anti-patterns**

- 10+ alternates — visitors get dizzy before the message lands.
- Animating critical legal/marketing lines — risk of being mis-screen-shotted mid-cycle.

### `us_message` — Message Box

**When to use**: an inline notification/alert inside content — info banner, warning, success acknowledgement, error notice.

**Avoid when**:
- you need a modal popup — `[us_popup]`;
- you need a site-wide cookie/maintenance notice — those are configured in Theme Options;
- you need a friendly empty-state — a styled `[us_text]` may be enough.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `content` | Body of the message. Passed as the inner content of the shortcode (between opening and closing tags); HTML is allowed. |
| `color` | Color palette of the box — `blue` (default), `yellow`, `green`, `red`. These are visual colors, not semantic levels — pick the one whose meaning matches the message (red for errors, green for success, yellow for warnings, blue for info). |
| `icon` | Optional icon prefix (`set\|name`, e.g. `fas\|info-circle`, `fas\|exclamation-triangle`). |
| `closing` | `1` adds a dismiss button so the visitor can close the message; the dismissed state may not persist across reloads. Default `0`. |

**Minimal example**

```text
[us_message color="blue" icon="fas|info-circle"]New feature: dark mode is live.[/us_message]
```

**Common combinations**

Dismissible success notice after a form-like action:

```text
[us_message color="green" icon="fas|check-circle" closing="1"]Thanks — your message has been sent.[/us_message]
```

Warning that explains a constraint:

```text
[us_message color="yellow" icon="fas|exclamation-triangle"]This action cannot be undone.[/us_message]
```

**Anti-patterns**

- Using `color="red"` purely for visual emphasis on regular copy — visitors and screen readers will read it as an error. Reserve `red` for actual errors/blockers.
- Multiple stacked messages at the top of a page — pick the most important one; the rest become noise.
- Empty `content` with only an `icon` — the box looks broken; either remove the message or put a sentence in it.

### `us_popup` — Popup

**When to use**: trigger a modal overlay from a click on a button/icon/image, an external CSS selector, or after a delay on page load — newsletter sign-up, video player, embedded form, gallery focus.

**Avoid when**:
- the content is essential and must always be visible — popups hide it behind an action;
- you only need a tooltip — popups are heavier;
- you want auto-popups on every page-load — most users dismiss them instantly.

**Key parameters**

**Content source**

| Param | What it does |
|-------|--------------|
| `use_page_block` | If set to a `us_page_block` post ID, the popup reuses that block as content (ignores `title`/`content` below). |
| `title` | Popup heading. |
| `content` | Popup body — HTML allowed via the WP editor. Shortcodes inside work. |

**Trigger**

| Param | What it does |
|-------|--------------|
| `show_on` | What activates the popup — `btn` (default), `image`, `icon`, `selector`, `load`. |
| `btn_label` | Trigger button text. Visible when `show_on="btn"`. |
| `btn_style` | Per-site button style (Theme Options → Buttons). |
| `btn_icon` | Trigger icon (`set\|name`). Visible when `show_on="btn"` or `show_on="icon"`. |
| `btn_iconpos` | `left` / `right`. |
| `image` | Media ID for an image-trigger. Visible when `show_on="image"`. |
| `trigger_selector` | CSS selector of an external element that opens the popup. Visible when `show_on="selector"`. |
| `show_delay` | Auto-open delay in seconds. Visible when `show_on="load"`. |
| `show_once` | `1` shows the auto-open popup once per visitor (until `days_until_next_show` passes). |

**Appearance**

| Param | What it does |
|-------|--------------|
| `layout` | `default` / `fullscreen` / `left_panel` / `right_panel` / `top_panel` / `bottom_panel`. |
| `animation` | Opening animation — `fadeIn` (default), etc. |
| `closer_pos` | Close-button position — `outside` (default) / `inside` / `none`. |
| `popup_width` | Width when `layout` is not fullscreen/top/bottom — `600px`, `40rem`. |
| `popup_padding` | Inner padding (e.g. `5%`, `2rem`). |
| `overlay_bgcolor` | Backdrop color (default `rgba(0,0,0,0.85)`). |

**Minimal example**

```text
[us_popup show_on="btn" btn_label="Subscribe"]
  [us_cform]
[/us_popup]
```

**Anti-patterns**

- Popups inside popups — modal-in-modal traps users.
- Long-form content inside a popup — anything that needs scrolling should be a separate page.
- `show_on="load"` without `show_once="1"` — visitors see the same popup on every page-load.

### `us_progbar` — Progress Bar

**When to use**: visualise a percentage that animates when entering the viewport — skill levels, progress towards a goal, completion stats.

**Avoid when**:
- the value isn't a percentage — use `[us_counter]`;
- you need real-time progress (file upload) — that needs JS, not a static shortcode.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `count` | Current value displayed as a string — `50%`, `7/10`, `42`. Required. |
| `final_value` | Target value the bar fills to — `100%`, `10`, etc. The bar animates from 0 to this value's numeric part. |
| `hide_count` | `1` hides the current value next to the bar. Default `0`. |
| `hide_final_value` | `1` hides the target value. Default `1`. Visible only when `hide_count="0"`. |
| `title` | Label shown above the bar. |
| `title_tag` | HTML tag for the title — `h6` (default), `h2`–`h5`, `div`, `span`. |
| `title_size` | Custom title font-size (CSS units). |
| `style` | Visual style — `1`, `2`, `3`, `4`, `5`. |
| `color` | `primary` / `secondary` / `heading` / `text` / `custom`. |
| `bar_color` | Custom HEX/RGBA for the fill — used when `color="custom"`. |
| `size` | Bar thickness (e.g. `10px`, `0.5rem`). |

**Minimal example**

```text
[us_progbar count="80%" final_value="100%" title="Reliability" color="primary"]
```

**Anti-patterns**

- Five bars all at 90%+ — readers stop trusting the data.
- Mixing units across one cluster (% next to absolute counts) — confusing without context.
- Using `hide_count="1"` and `hide_final_value="1"` together — the user sees only a filled bar with no number.

### `us_scroller` — Page Scroller

**When to use**: turns a long single-page layout into a snap-scroll experience — one `vc_row` per "screen", scroll wheel and arrow keys advance to the next row, optional dot navigation jumps to any section. Typical use: one-page sites, landing pages, presentation-style scrolls.

**Avoid when**:
- the page has rows of mixed heights or text-heavy content — snap scroll skips past the bottom of tall rows;
- you only want a back-to-top button — there are simpler solutions;
- the layout is a normal multi-section page with a real footer flow — snap scroll trains users to wheel-jump and they miss content.

**Placement**: drop one `[us_scroller]` per page (typically near the top), with no children. It hooks the page's rows automatically.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `disable_width` | Screen width below which snap scrolling is disabled (default `768px`). On mobile the page falls back to normal scrolling. |
| `speed` | Animation duration between sections, in ms (default `1000ms`). Range 0–2000ms. |
| `dots` | `1` shows a vertical dot-navigation overlay. |
| `dots_style` | Dot visual style — `1` / `2` / `3` / `4` (default `1`). |
| `dots_pos` | Side of the screen for the dots — `left` or `right` (default `right`). |
| `dots_size` | Dot diameter (default `10px`). Accepts `px` or `rem`. |
| `dots_color` | Dot color. Empty inherits the theme accent. |
| `include_footer` | `1` adds a dot for the footer so visitors can jump straight to it. Only meaningful with `dots="1"`. |

**Minimal example**

```text
[us_scroller dots="1" dots_pos="right" dots_style="2"]
```

**Common combinations**

Slow, presentation-style scroll with footer in the dot strip:

```text
[us_scroller speed="1500ms" dots="1" dots_style="3" dots_size="14px" include_footer="1"]
```

**Anti-patterns**

- Two `us_scroller` instances on one page — the second one's hooks fight the first; keep it singular.
- Used on a page where rows are taller than the viewport — visitors lose the bottom half of every row.
- `disable_width="0"` (forces snap scroll on phones) — finger gestures expect inertia, not section snap.

### `us_color_scheme_switch` — Color Scheme Switch

**When to use**: an inline toggle that flips the visitor between two color schemes — typically light/dark. The two schemes themselves live in Theme Options → Colors; this shortcode only renders the UI control and persists the visitor's choice.

**Avoid when**:
- Theme Options → General → "Dark Theme" is set to anything other than "None" — that setting already wires up a dark-theme toggle site-wide, and this shortcode then surfaces a notice rather than a working switch;
- you want different colors on a specific page only — that's a per-section background/text override on `vc_row`, not a global scheme switch.

**Placement**: usually in a Header layout (next to the menu) or in a corner of the page. No children.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `color_scheme` | The scheme applied when the switch is **on**. Values come from Theme Options → Colors (per-install). Required. |
| `text_before` | Label shown to the left of the switch (default `Light`). |
| `text_after` | Label shown to the right of the switch (default `Dark`). |
| `inactive_switch_bg` | Background of the switch in the "off" state (default `#ddd`). |
| `active_switch_bg` | Background of the switch in the "on" state (default `#222`). |

**Minimal example**

```text
[us_color_scheme_switch color_scheme="dark"]
```

**Common combinations**

In a horizontal wrapper next to a button, with custom labels:

```text
[us_hwrapper inner_items_gap="1rem" valign="middle"]
  [us_color_scheme_switch color_scheme="dark" text_before="☀" text_after="☾"]
  [us_btn label="Sign in" link="url:%23login"]
[/us_hwrapper]
```

**Anti-patterns**

- Multiple instances on one page — they share state but render independent UIs that can briefly desync. Use one.
- Setting `color_scheme` to a non-existent scheme slug — the switch renders but does nothing. Verify the slug in Theme Options → Colors first.
- Using this when the "Dark Theme" theme-option is already enabled — the shortcode will display a "use the global setting instead" message rather than a working toggle.

## Other

### `us_cform` — Contact Form

**When to use**: a simple lead-gen form (Name, Email, Message) or any short multi-field form that mails the submission. Pure shortcode-driven — no separate form plugin needed.

**Avoid when**:
- you need conditional logic, multi-step or payment integration — use a dedicated plugin (Gravity Forms, Contact Form 7);
- you need a search box — `[us_search]`;
- you only need a newsletter opt-in tied to MailChimp/etc. — use the provider's embed.

**Key parameters**

**Fields**

| Param | What it does |
|-------|--------------|
| `items` | The form's fields. **URL-encoded JSON array** of field objects (see "Encoding the `items` group" below). If omitted, the default 3-field set (Name + Email + Message) is rendered. The submit button is **not** an item — it is configured by the `button_*` params below. |

**Button** (the submit button)

| Param | What it does |
|-------|--------------|
| `button_text` | Submit-button label. Default `Submit`. Supports dynamic values. |
| `button_style` | Visual style id from Theme Options → Buttons (e.g. `1`, `2`, `3`). Default `1`. |
| `button_size` | Custom CSS font-size for the submit button (e.g. `1.1rem`). |
| `button_size_mobiles` | Submit-button font-size on mobile. |
| `button_align` | `none` (default), `left`, `center`, `right`, `justify` (stretch full-width). Responsive. |
| `icon` | Submit-button icon (`set\|name`, e.g. `fas\|paper-plane`). |
| `iconpos` | `left` (default) or `right`. |

**Appearance**

| Param | What it does |
|-------|--------------|
| `us_field_style` | Field style id from Theme Options → Field Styles. Default `default`. |
| `fields_layout` | `ver` (default — vertical stack) or `hor` (horizontal — fields wrap inline). |
| `fields_gap` | Gap between fields. Default `1rem`. |
| `action_after_sending` | What happens after a successful submit — `show_message` (default), `show_reusable_block`, `redirect`, `open_popup`, `close_popup`. |
| `success_message` | Shown after submit when `action_after_sending="show_message"`. **Must be `base64_encode(rawurlencode("plain text"))`** — the runtime calls `rawurldecode(base64_decode($value, TRUE))`, and a value that does not pass strict base64 decoding becomes empty silently. HTML is allowed inside the plain text. Omit to use the theme's default localised string. |
| `reusable_block` | ID of a `us_page_block` post to render in place of the form when `action_after_sending="show_reusable_block"`. |
| `redirect_url` | Destination URL when `action_after_sending="redirect"`. |
| `popup_selector` | Class or ID of the popup to open when `action_after_sending="open_popup"` (e.g. `.my-popup`, `#my-popup`). |
| `hide_form_after_sending` | `1` removes the form from the DOM after `show_message` / `show_reusable_block`. Default `0`. |

**Mail**

| Param | What it does |
|-------|--------------|
| `receiver_email` | Recipient(s). Comma-separate for multiple addresses. Defaults to the site admin email. |
| `email_subject` | Subject line. Default `Message from [page_title]`. Placeholders `[page_title]`, `[page_url]` and field labels like `[field_list]` are replaced at send time. |
| `email_message` | Body of the outgoing email. **Same encoding as `success_message`** — `base64_encode(rawurlencode("html"))`. Default body contains `[field_list]` (auto-expands to all submitted field values) plus a link to the page. |
| `bcc_email` | Blind carbon copy recipient. |
| `reply_to` | Reply-To header. Empty → the value of the first `email` field becomes the Reply-To address. |
| `auto_respond` | `1` sends an acknowledgement email to the submitter. Default `0`. |
| `auto_respond_subject` | Subject of the acknowledgement email. |
| `auto_respond_message` | Body of the acknowledgement. Same `base64(rawurlencode(...))` encoding as `email_message`. |

**Field types** (the `type` of each `items[]` entry)

| Value | Renders | Notable per-type keys |
|-------|---------|-----------------------|
| `text` | single-line input | `inputmode` (`text` / `decimal` / `numeric` / `tel` / `url`), `placeholder`, `icon`, `is_used_as_from_name` (`"1"` uses this field's value as the email's `From:` display name) |
| `textarea` | multi-line input | `placeholder`, `icon` |
| `email` | email input with format validation | `placeholder`, `icon`, `is_used_as_from_email` (`"1"` uses this field's value as the email's `From:` address — see anti-patterns) |
| `date` | date picker | `date_format` (jQuery UI format, default `d MM yy`), `placeholder`, `icon` |
| `select` | dropdown | `values` (newline-separated string — see encoding notes) |
| `checkboxes` | multi-check group | `values` (newline-separated) |
| `radio` | radio group | `values` (newline-separated), `pre_select_first_value` (`"1"` selects the first option by default) |
| `file` | file upload | `accept` (extensions or MIME, e.g. `.pdf,.jpg` or `image/*`), `file_max_size` (default `10MB`) |
| `info` | static text block (not a real field, just a heading / note inline with other fields) | `value` (the text — plain) |
| `agreement` | required-consent checkbox (T&C, privacy etc.) | `value` (label text — plain, may contain inline HTML) |
| `captcha` | math captcha | `icon` |
| `reCAPTCHA` | Google reCAPTCHA v3 | (requires keys in Theme Options → Advanced) |

There is **no** `tel`, `checkbox`, `hidden` or `submit` type at the item level. For a phone field use `type="text"` with `inputmode="tel"`; the multi-check type is `checkboxes` (plural); the submit button is the `button_*` shortcode params, not an item.

**Common per-item keys** (apply across most types)

| Key | What it does |
|-----|--------------|
| `type` | Field type (see table above). Required. |
| `label` | Title shown above the field. Not applicable to `info` / `reCAPTCHA`. |
| `description` | Hint shown below the field. |
| `placeholder` | Empty-state text inside the field. Honoured by `text` / `email` / `date` / `textarea`. |
| `required` | `"1"` makes the field mandatory. Default `"0"`. |
| `cols` | Per-field width inside the form grid: `"1"` (full — default), `"2"` (1/2), `"3"` (1/3), `"4"` (1/4). Two consecutive `cols="2"` fields sit side by side; one `cols="2"` followed by `cols="1"` leaves a half-row gap on the right. |
| `icon` | Inline icon inside the field (`set\|name`). Available on text / email / date / textarea / select / captcha. |
| `move_label` | `"1"` floats the label above the field on focus. Available on text / email / date / textarea / captcha. |

**Encoding the `items` group**

At render time the template calls `json_decode( urldecode( $items ), TRUE )` — so `items` is a **URL-encoded JSON array of field objects**. Two practical shapes:

- **A. Single-quoted raw JSON** — readable, works when the JSON contains no `+` characters (PHP's `urldecode` turns `+` into a space) and no characters that would break the shortcode parser:

  ```text
  items="%5B%7B%22type%22%3A%22text%22%2C%22label%22%3A%22Your%20name%22%2C%22required%22%3A%221%22%7D%2C%7B%22type%22%3A%22email%22%2C%22label%22%3A%22Email%22%2C%22required%22%3A%221%22%7D%2C%7B%22type%22%3A%22textarea%22%2C%22label%22%3A%22Message%22%7D%5D"
  ```

- **B. URL-encoded JSON inside double quotes** — always safe, less readable. Use when item values contain `+`, `&`, multiline content, or other characters that could collide with shortcode/attribute parsing:

  ```text
  items="%5B%7B%22type%22%3A%22text%22%2C%22label%22%3A%22Your%20name%22%2C%22required%22%3A%221%22%7D%5D"
  ```

Authoring recipe — same two-step pattern as for `css="…"`:

1. Write the array as readable JSON: `[{"type":"text","label":"Name","required":"1"}, …]`.
2. Either drop it in between single quotes (Form A) or `rawurlencode` it and drop into double quotes (Form B).

Inside `values` strings, line breaks stay literal JSON `\n` escapes: `"values":"One\nTwo\nThree"`. The JSON decoder turns them into real newlines before the field template runs `explode("\n", $values)`. **`values` is plain — do not base64-encode it** (that's only for `success_message` / `email_message` / `auto_respond_message`).

Boolean-like switches (`required`, `is_used_as_from_email`, `is_used_as_from_name`, `pre_select_first_value`, `move_label`) take string `"0"` / `"1"`, not JSON booleans.

**Minimal example**

```text
[us_cform receiver_email="hello@example.com"]
```

(The default `items` set provides Name + Email + Message. The submit button defaults to `button_text="Submit"`. `success_message` falls back to the theme's default localised string when omitted.)

**Common combinations**

Lead form with phone (`text` + `inputmode="tel"`), a service dropdown, and a consent checkbox:

```text
[us_cform receiver_email="hello@example.com" button_text="Send request" items="%5B%7B%22type%22%3A%22text%22%2C%22label%22%3A%22Your%20name%22%2C%22required%22%3A%221%22%2C%22is_used_as_from_name%22%3A%221%22%7D%2C%7B%22type%22%3A%22email%22%2C%22label%22%3A%22Email%22%2C%22required%22%3A%221%22%2C%22is_used_as_from_email%22%3A%221%22%7D%2C%7B%22type%22%3A%22text%22%2C%22label%22%3A%22Phone%22%2C%22inputmode%22%3A%22tel%22%2C%22placeholder%22%3A%22%2B1%20555%20%E2%80%A6%22%7D%2C%7B%22type%22%3A%22select%22%2C%22label%22%3A%22Service%22%2C%22values%22%3A%22Bath%20%26%20Brush%5CnFull%20Haircut%5CnSpa%20Day%22%2C%22required%22%3A%221%22%7D%2C%7B%22type%22%3A%22textarea%22%2C%22label%22%3A%22Tell%20us%20about%20your%20pet%22%2C%22required%22%3A%221%22%7D%2C%7B%22type%22%3A%22agreement%22%2C%22value%22%3A%22I%20agree%20to%20be%20contacted%20about%20my%20request.%22%2C%22required%22%3A%221%22%7D%5D"]
```

Two-column form layout — name halves on top row, full-width message below:

```text
[us_cform items="%5B%7B%22type%22%3A%22text%22%2C%22label%22%3A%22First%20name%22%2C%22cols%22%3A%222%22%2C%22required%22%3A%221%22%7D%2C%7B%22type%22%3A%22text%22%2C%22label%22%3A%22Last%20name%22%2C%22cols%22%3A%222%22%2C%22required%22%3A%221%22%7D%2C%7B%22type%22%3A%22email%22%2C%22label%22%3A%22Email%22%2C%22cols%22%3A%222%22%2C%22required%22%3A%221%22%7D%2C%7B%22type%22%3A%22text%22%2C%22label%22%3A%22Phone%22%2C%22inputmode%22%3A%22tel%22%2C%22cols%22%3A%222%22%7D%2C%7B%22type%22%3A%22textarea%22%2C%22label%22%3A%22Message%22%2C%22cols%22%3A%221%22%2C%22required%22%3A%221%22%7D%5D"]
```

File-upload form (job application — CV attachment + cover letter):

```text
[us_cform receiver_email="careers@example.com" email_subject="Job application from [page_title]" items="%5B%7B%22type%22%3A%22text%22%2C%22label%22%3A%22Full%20name%22%2C%22required%22%3A%221%22%7D%2C%7B%22type%22%3A%22email%22%2C%22label%22%3A%22Email%22%2C%22required%22%3A%221%22%7D%2C%7B%22type%22%3A%22file%22%2C%22label%22%3A%22Upload%20CV%22%2C%22accept%22%3A%22.pdf%2C.doc%2C.docx%22%2C%22file_max_size%22%3A%225MB%22%2C%22required%22%3A%221%22%7D%2C%7B%22type%22%3A%22textarea%22%2C%22label%22%3A%22Cover%20letter%22%7D%5D"]
```

Custom success message — pre-encoded as `base64_encode(rawurlencode("Thanks — we'll reply within 24 hours."))`:

```text
[us_cform receiver_email="hello@example.com" success_message="VGhhbmtzJTIwJUUyJTgwJTk0JTIwd2UlMjdsbCUyMHJlcGx5JTIwd2l0aGluJTIwMjQlMjBob3Vycy4="]
```

**Anti-patterns**

- **Passing `success_message` / `email_message` / `auto_respond_message` as plain text** — the runtime runs strict `base64_decode`; non-base64 strings decode to `FALSE`, so the message disappears entirely with no fallback. Always pre-encode as `base64_encode(rawurlencode("plain text"))`, or omit the param to use the theme default.
- **Using the old attribute names** `btn_label` / `btn_style` / `field_style` / `email_to` — none of these exist. The real names are `button_text` / `button_style` / `us_field_style` / `receiver_email`.
- **Item types `tel` / `checkbox` / `hidden` / `submit`** — none exist at the item level. Phone is `type="text"` with `inputmode="tel"`; the multi-check type is `type="checkboxes"` (plural); the submit button is configured by `button_*` shortcode params, not an item.
- **Base64-encoding `values` on a `select` / `radio` / `checkboxes` item** — that param is plain newline-separated text in the JSON. The base64 layer applies only to `success_message` / `email_message` / `auto_respond_message`.
- **JSON booleans** (`"required":true`) — the framework expects the string `"1"` / `"0"`. Booleans get coerced inconsistently.
- 10+ fields in a lead form — conversion drops sharply past 4-5. Match fields to the offer.
- **`is_used_as_from_email="1"` plus strict SPF/DKIM on the sending host** — many mail providers silently drop messages whose `From:` is a domain they don't authorise. Prefer leaving `From:` as the site admin address and rely on the auto-populated `reply_to` (the email field's value) for replies.
- **Omitting `receiver_email`** on a multi-author install — the form lands in whoever happens to be the WP admin's inbox, which is rarely the right person.

### `us_cta` — Call To Action

**When to use**: a compact promotional block — large heading, sub-text and one (or two) buttons, framed as a section break inviting action. Typical pre-footer block.

**Avoid when**:
- the page already has a clear hero CTA — multiple `us_cta` blocks dilute focus;
- you only need a button — `[us_btn]`;
- you need a feature card — `[us_iconbox]`.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `title` | Headline (required). |
| `text` | Sub-text under the headline. |
| `btn_label` | Primary button text. |
| `btn_link` | Primary button link (JSON shape). |
| `btn_style` | Per-site button style. |
| `second_button` | `1` to add a secondary button (then `second_btn_label`, `second_btn_link`, `second_btn_style` apply). |
| `controls_align` | Position of the buttons relative to text — `bottom` / `right`. |
| `color_bg` | Background color/gradient. |

**Minimal example**

```text
[us_cta title="Ready to start?" text="Free for 14 days, no credit card." btn_label="Start now" btn_link="url:%23signup"]
```

**Anti-patterns**

- Vague titles (`Get started today!`) without saying what — pair with concrete value (`Start your free 14-day trial`).
- Two CTAs pointing to the same URL — one is enough.

### `us_dropdown` — Dropdown

**When to use**: a click/hover-activated dropdown panel anchored to a label or icon. Good for "More" links, language switchers, mini info panels with rich content.

**Avoid when**:
- you need a full navigation menu — `[us_additional_menu]`;
- you need a small inline reveal with heavy content — `[us_popup]` is better;
- you need an accordion list — `[vc_tta_accordion]`.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `source` | Where the dropdown content comes from — `own` (default; custom links via `links`), `sidebar` (a WP sidebar/widget area), `wpml` (language switcher), `polylang` (language switcher). |
| `links` (group) | Items shown in the panel when `source="own"`. Each item has `label`, `url`, `icon`. |
| `sidebar_id` | WP sidebar slug used when `source="sidebar"`. |
| `wpml_switcher` | Subset of the WPML widget to show — `flag`, `native_lang`, `display_lang`. Used when `source="wpml"`. |
| `polylang_switcher` | Same idea for Polylang — `flag`, `full_name`. Used when `source="polylang"`. |
| `link_title` | Trigger label (visible when `source="own"` or `source="sidebar"`). |
| `link_icon` | Trigger icon (`set\|name`). |
| `dropdown_open` | Activation — `click` (default) or `hover`. |
| `dropdown_dir` | Anchor side — `left` / `right` (default). |
| `dropdown_effect` | Open animation — `height` (default) or other transition. |

**Minimal example**

```text
[us_dropdown link_title="More" link_icon="fas|chevron-down" source="own"]
```

Build the `links` items via the builder UI — authoring the group JSON by hand is verbose.

**Anti-patterns**

- Critical content (prices, terms) hidden inside a dropdown — search engines and screen readers may miss it.
- Nested dropdowns — UX nightmare, especially on touch.
- `dropdown_open="hover"` on touch devices — hover doesn't exist.

### `us_person` — Team Member Card

**When to use**: a profile card on Team / About / Authors pages — portrait, name, role, short bio, optional social links.

**Avoid when**:
- you want a testimonial (different layout) — consider a styled `us_iconbox` or custom layout;
- you only need a name + photo as plain text — `us_text` + `us_image`.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `image` | Portrait media ID. |
| `name` | Person name (required). |
| `role` | Job title or role. |
| `description` | Short bio sentence. |
| `link` | Wraps name/photo in a profile link (JSON shape). |
| `style` | Visual style — `circle` / `square` / `card`. |
| `socials` | Inline list of social links (the dev spec has the exact `items`/`group` shape). |

**Minimal example**

```text
[us_person image="123" name="Jane Doe" role="Lead Designer" description="Builds the UI you actually want to use."]
```

**Anti-patterns**

- Inconsistent photo crops across cards in the same row — pre-crop to a single ratio in the media library.
- Listing all of someone's titles — pick the most relevant one for this page.

### `us_pricing` — Pricing Table

**When to use**: a full pricing comparison rendered as **a single shortcode** that lists all tiers in its `items` group — Starter / Pro / Business side-by-side, each with its own price, feature list and CTA. The shortcode handles column layout internally.

**Avoid when**:
- you have only one price to display — a `us_cta` with the price in the heading is lighter;
- you want each tier in a separate `vc_column` for full layout control — compose `us_vwrapper` + `us_text` + `us_btn` manually inside `vc_row columns="3"`. `us_pricing` is a one-piece table, not a per-card element.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `style` | Visual style of the whole table — `simple` (default), `cards`, `flat`. |
| `items` (group) | The tiers. Each item is a sub-structure with its own fields (see below). Add/reorder via the builder UI; authoring the group JSON by hand is verbose. |

**Per-item fields** (inside each `items` entry)

| Field | What it does |
|-------|--------------|
| `title` | Plan name (e.g. `Starter`, `Pro`, `Business`). |
| `type` | `1` highlights this tier as the featured/recommended plan; `0` (default) is a regular tier. |
| `price` | Price display — typically `29` or `$29` or `€29`. The currency symbol lives **inside** this string; there is no separate currency parameter. |
| `substring` | Price unit / period text shown next to the number — `/mo`, `per month`, `/yr`. |
| `features` | Feature list, **one item per line** (newlines inside the textarea). Each line becomes a row in the plan's feature list. |
| `btn_text` | CTA button label. |
| `btn_link` | CTA destination (JSON shape: `{"url":"...","target":"_blank"}`). |
| `btn_style` | Per-site button style (Theme Options → Buttons). Default `1`. |
| `btn_size` | Custom button font-size (CSS units). |
| `btn_icon` | Optional button icon (`set\|name`). |
| `btn_iconpos` | Icon position — `left` (default) or `right`. |

**Minimal example**

Single tier (just to show shape):

```text
[us_pricing style="cards"]
```

The `items` group is populated through the builder UI — there is no concise inline syntax for it. After the builder saves, the resulting shortcode includes a nested `items="..."` JSON payload.

**Common combinations**

A three-tier table with the middle plan featured: build it as **one** `us_pricing` shortcode with three `items`. The middle item sets `type="1"`. The shortcode renders all three side-by-side automatically — do not wrap them in `vc_row columns="3"`.

**Anti-patterns**

- Trying to render three pricing cards as three separate `[us_pricing]` shortcodes inside `vc_row columns="3"` — this is the wrong mental model. `us_pricing` is the whole table; tiers are its `items`.
- Splitting price and currency between separate fields — both live in `price` as one string.
- Hidden fees in fine print on the card — surface them or move to a "compare" page.

### `us_additional_menu` — Additional Menu

**When to use**: render a WP Nav Menu (configured under **Appearance → Menus**) as a secondary navigation inside content — footer columns, sidebars, sub-page lists, mega-menu fragments.

**Avoid when**:
- you need the site's main header navigation — that lives in the Header Builder, not in content;
- you only have 2-3 hardcoded links — `us_text` with `<a>` tags is enough.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `source` | The WP Nav Menu to render. **Per-site value** — depends on what menus exist under Appearance → Menus on the install. |
| `layout` | `ver` (vertical) / `hor` (horizontal). |
| `responsive_width` | Below this CSS width, the menu collapses to vertical. Leave empty to keep horizontal with overflow scroll. |
| `show_as_accordion` | (Only when `layout="ver"`) `1` displays sub-items as expandable accordion sections. |
| `main_style` | Item style — `links` / `blocks`. |
| `main_gap` | Gap between top-level items. |
| `sub_items` | `1` to render second-level (sub-menu) items. |

**Minimal example**

```text
[us_additional_menu source="footer-menu" layout="ver"]
```

(`footer-menu` is whatever slug the editor created in Appearance → Menus.)

**Anti-patterns**

- Hardcoding the menu structure inside `us_html` instead of `us_additional_menu` — admins can no longer edit it via Appearance → Menus.
- Using `layout="hor"` for a long list — items wrap or scroll horizontally, which feels broken.

### `us_search` — Search Form

**When to use**: a search input with submit icon. Standard places: site header (via Header Builder), inside a 404 page, on an archive sidebar.

**Avoid when**:
- you need a faceted product search — that's WooCommerce/Shop-list territory (out of this iteration);
- you only need a static "Search" link — `us_text` with an `<a>` tag.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `text` | Placeholder text shown inside the input (e.g. `Search docs…`). |
| `search_post_type` | Comma-separated list of post-type slugs to restrict search to (e.g. `post,product`). Empty = all. |
| `us_field_style` | Per-site field style (Theme Options → Field Styles). |
| `icon` | Submit icon (`fas\|search` by default). |
| `icon_pos` | Position of the search icon — `left` or `right`. |
| `field_bg_color` | Background color of the input. |
| `field_text_color` | Text color of the input. |
| `icon_size` | Icon size (CSS units, e.g. `18px`). |

Note: `us_search` is dual-purpose — it also appears inside the Header Builder where it gets extra context-only params (`layout`, `field_width`, responsive icon sizes). Those are header-only and not editable via `[us_search ...]` in `post_content`.

**Minimal example**

```text
[us_search text="Search docs…" icon="fas|search" icon_pos="right"]
```

**Anti-patterns**

- Two search forms on the same page — pick one location.
- Long placeholder text — gets truncated on mobile.

### `us_socials` — Social Links

**When to use**: a row of social-platform icons linking to your profiles — header strip, footer column, author bio.

**Avoid when**:
- you need a single share-button — use a sharing plugin or `us_btn` with a sharer URL;
- you want follower-count widgets — that's a different shortcode/plugin altogether.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `items` (group) | List of social entries. Each item: `{ type: <platform_slug>\|custom, url, title, icon (if custom), color (if custom) }`. Default item set is Facebook + Twitter. |
| `shape` | Icon container shape — `none` / `square` / `rounded` / `circle`. |
| `style` | `default` / `colored` / `outlined` / `solid`. |
| `icons_color` | `brand` (use platform default colors) / `text` / `link`. |
| `hover` | Hover effect — `fade` / `slide` / `none`. |
| `gap` | Gap between icons. |
| `hide_tooltip` | `1` to disable on-hover tooltip. |

**Minimal example**

Default Facebook + Twitter set (no params needed):

```text
[us_socials]
```

To customize, configure `items` via the builder UI — the JSON is verbose to author by hand.

**Anti-patterns**

- Linking to a social account that hasn't posted in 2 years — better to omit.
- 10+ platform icons in a row — pick 3-5 most active channels.

### `vc_video` — Video Embed

**When to use**: embed a YouTube/Vimeo/self-hosted video via its URL. Wrapped responsively by the theme. Use the **overlay** feature for performance — it shows a thumbnail with a play button and only loads the real video iframe after the user clicks.

**Avoid when**:
- you want a video as a row background — `vc_row.us_bg_video` is purpose-built for that;
- you only need a poster image without playback — `[us_image]`.

**Key parameters**

**Source**

| Param | What it does |
|-------|--------------|
| `link` | Full URL of the video — YouTube, Vimeo, or a direct file (mp4/webm/ogg). Required. Supports dynamic values. |

**Playback**

| Param | What it does |
|-------|--------------|
| `autoplay` | `1` autoplays the video. Most browsers require `muted="1"` for autoplay to actually run. Default `0`. |
| `muted` | `1` starts muted. Default `0`. |
| `loop` | `1` loops indefinitely. Default `0`. |
| `controls` | `1` shows player controls (default). Set `0` to hide them — visitors won't be able to pause/seek, so use sparingly. |
| `hide_video_title` | `1` hides the Vimeo title overlay (only honoured when the Vimeo owner has allowed it). |

**Aspect ratio & alignment**

| Param | What it does |
|-------|--------------|
| `ratio` | Aspect ratio — `initial` / `21x9` / `16x9` (default) / `4x3` / `3x2` / `1x1` / `9x16` / `custom`. |
| `ratio_width` / `ratio_height` | Numeric values when `ratio="custom"` (e.g. `21` / `9`). |
| `align` | `none` (default), `left`, `center`, `right`. |

**Lightweight overlay** (recommended for pages with multiple videos)

| Param | What it does |
|-------|--------------|
| `overlay_image` | Media library ID of a poster image. When set, the real iframe is **lazy-loaded** — only the poster is rendered on page-load; the actual video loads on click. This is the single biggest perf win for pages with embedded video. |
| `overlay_icon` | `1` (default) shows a play icon over the poster. Only relevant when `overlay_image` is set. |
| `overlay_icon_bg_color` | Background color of the play icon (HEX/RGBA). Default `rgba(0,0,0,0.5)`. |
| `overlay_icon_text_color` | Icon glyph color. Default `#fff`. |
| `overlay_icon_size` | Icon size (CSS units). Default `1.5rem`. |

**Minimal example**

```text
[vc_video link="https://www.youtube.com/watch?v=dQw4w9WgXcQ" align="center"]
```

**Common combinations**

Hero video with overlay (lazy-loaded, autoplay-on-click would happen anyway):

```text
[vc_video link="https://www.youtube.com/watch?v=dQw4w9WgXcQ" ratio="16x9" overlay_image="123"]
```

Silent looping background-like video (decorative):

```text
[vc_video link="https://example.com/intro.mp4" autoplay="1" muted="1" loop="1" controls="0" ratio="16x9"]
```

**Anti-patterns**

- Using the legacy `el_aspect` parameter — the correct name is `ratio`.
- Using `mute` — the correct name is `muted` (with the `d`).
- Autoplay without `muted="1"` — browsers block it; the video sits silent and doesn't start.
- Setting `controls="0"` on a non-decorative video — visitors can't pause; they'll bounce.
- Embedding 5+ videos on one page **without** `overlay_image` — every iframe loads up-front and pageweight balloons. Always use the overlay for any page with more than one video.

### `us_html` — Raw HTML

**When to use**: paste arbitrary HTML/JS/CSS into the page — third-party embed snippets (Calendly, Typeform, custom map widgets), inline `<script>`/`<style>` for one-off pages, structured-data JSON-LD.

**Avoid when**:
- you have a single styled paragraph or heading — `us_text` is the right call;
- the content is rich-edited prose — `vc_column_text`;
- the snippet is large and needs editor highlighting — keep it in a child-theme template and just place an anchor here.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `html` (content) | The raw HTML/JS body — base64-encoded under the hood, so any character is safe. Wrap your content between the opening and closing tag. |

**Minimal example**

```text
[us_html]
<script async src="https://example.com/widget.js"></script>
<div id="widget-host"></div>
[/us_html]
```

**Anti-patterns**

- Pasting tracking scripts that should live in `<head>` site-wide — put them in Theme Options → Code instead.
- Inline `<style>` that overrides theme variables on every page — extract to a child-theme stylesheet.
- Using `us_html` for everything — you lose the structured editing benefits of UpSolution shortcodes.

### `us_page_block` — Reusable Block

**When to use**: embed a saved Reusable Block (post type `us_page_block`) on a page — a single source-of-truth block that updates everywhere it is used. Typical uses: a shared footer CTA, a "trusted by" logo row, a pricing tier card reused across landing pages.

**Avoid when**:
- the content only appears on this page — author it inline;
- you need a real site-wide template part — that's a Header / Footer / Page Template in Theme Options, not a Reusable Block.

**Authoring**: create the block content first in **WP Admin → Reusable Blocks** (or via the REST endpoint for the `us_page_block` post type) and copy its post ID. The `id` attribute below takes that ID.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `id` | ID of the Reusable Block post to embed. Required. |
| `remove_rows` | Strip wrapping rows/columns so the embedded content inherits the host's layout context. Values: empty (default — keep all markup), `1` (drop rows inside the embedded block), `parent_row` (drop the row that wraps **this** `us_page_block` on the host page). |
| `force_fullwidth_rows` | `1` stretches embedded rows to the full container width regardless of their own `width` attribute. Only meaningful when `remove_rows != "1"`. |

**Minimal example**

```text
[us_page_block id="142"]
```

**Common combinations**

Drop the embedded block's outer row so it merges with the host column:

```text
[vc_row][vc_column]
  [us_text text="See plans"]
  [us_page_block id="142" remove_rows="1"]
[/vc_column][/vc_row]
```

**Anti-patterns**

- Referencing a draft or trashed Reusable Block — nothing renders and there is no visible error in the front-end.
- Using `us_page_block` for content that already changes per-page (CTA text, target URL) — the whole point is one source. If you need variants, build them as separate blocks.
- Nesting one `us_page_block` inside another more than one level deep — debugging the resulting cascade is painful and the editor cannot preview it.

### `vc_widget_sidebar` — Sidebar with Widgets

**When to use**: render a WordPress **Sidebar** (a registered widget area, configured at WP Admin → Appearance → Widgets) inside the page flow — typically a column in a blog template, or a "filters / recent posts / tag cloud" rail next to the main content.

**Avoid when**:
- the content is a single, page-specific block — use the relevant shortcode directly (`us_post_list`, `us_search`, …) instead of going through a widget area;
- you need post archives — a `us_post_list` is faster to configure and previews live in the builder;
- you want a free-form HTML block — `us_text` or `us_html` are simpler.

**Note**: this is the only `vc_*` element in the Other category that ships in this manifest. The `sidebar_id` dropdown is populated from registered widget areas at edit-time only — the list will be empty when generating shortcode markup outside the builder.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `sidebar_id` | Slug of the widget area to render. Default `default_sidebar`. Other values depend on what the active theme / plugins register. |
| `title` | Optional heading rendered above the widget area. |

**Minimal example**

```text
[vc_widget_sidebar sidebar_id="default_sidebar"]
```

**Common combinations**

Two-column blog page: post list left, sidebar right.

```text
[vc_row][vc_column width="2/3"]
  [us_post_list]
[/vc_column][vc_column width="1/3"]
  [vc_widget_sidebar sidebar_id="blog_sidebar" title="Recent posts"]
[/vc_column][/vc_row]
```

**Anti-patterns**

- Referencing a `sidebar_id` that isn't registered on the site — the shortcode silently renders nothing.
- Putting heavy interactive widgets (forms, carousels) inside a sidebar widget — the surrounding column may be narrow; test the rendered widget's behaviour at the column's actual width.

### `us_contacts` — Contact Info

**When to use**: a compact block listing address, phone, mobile, and email — designed for the footer "Get in touch" column, a contact-page side rail, or a header strip. Each non-empty attribute renders as one labelled line with an icon; empty attributes are hidden entirely.

**Avoid when**:
- you need a contact form — `[us_cform]`;
- you need a map with a pin — `[us_gmaps]`;
- you need social-platform icons — `[us_socials]`;
- you only have one line (e.g. just an email) — author it as `[us_iconbox]` with a free-form text and link.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `address` | Postal address line. Renders only if non-empty. Supports dynamic values (e.g. `{{custom_field}}`). |
| `phone` | Primary phone number. Rendered as a `tel:` link. Supports dynamic values. |
| `fax` | Despite the param name, this is the **Mobile** number in the UI (legacy naming). Rendered as a `tel:` link. Supports dynamic values. |
| `email` | Email address. Rendered as a `mailto:` link. Supports dynamic values. |

**Minimal example**

```text
[us_contacts address="221B Baker St, London" phone="+44 20 7946 0958" email="hello@example.com"]
```

**Common combinations**

Footer column, mobile-only field included:

```text
[us_contacts
  address="Office 14, 22 Marshala Zhukova"
  phone="+7 495 123 45 67"
  fax="+7 916 000 00 00"
  email="info@example.com"]
```

**Anti-patterns**

- Storing the email as plain text inside `us_text` — visitors can't tap to send mail, and you lose dynamic-value support.
- Filling `fax` thinking it's a fax number — it's the Mobile field. If you really need a fax line, put it in `address` or another `us_iconbox`.
- Wrapping the block in a link (`us_hwrapper link="…"`) — each line already has its own action; the outer link disables them.

### `us_gmaps` — Map

**When to use**: an interactive map embed pointing to one (or several) addresses, with optional info-window text. Typical placement: a contact page, a "find us" footer block, a multi-location showroom list.

**Avoid when**:
- you only need a static map image — Google's static API or a screenshot is lighter;
- you want a route / directions widget — `us_gmaps` only renders pins, not navigation;
- the only purpose is to surface the address text — use `[us_contacts address="…"]` (no map JS, no API needed).

**Providers**: two backends are supported via `provider`:
- `google` (default) — requires a Google Maps API key configured at **Theme Options → General → Google Maps API Key**. Without it, the embed renders the "for development purposes only" watermark.
- `osm` — OpenStreetMap (Leaflet). No API key required.

**Key parameters**

**Main marker**

| Param | What it does |
|-------|--------------|
| `marker_address` | Address or geo-coordinates (e.g. `38.6774156, 34.8520661`) for the primary pin. Required. |
| `marker_text` | HTML body for the marker's info window. **Must be base64-encoded** (the param's config has `encoded => TRUE`). `{{address}}` inside the body is replaced by the resolved address string. |
| `show_infowindow` | `1` opens the info window on load (rather than only on click). |
| `custom_marker_img` | Media-library ID (or URL) of a custom pin image. PNG/JPG/SVG. |
| `custom_marker_size` | Pin image size — one of `20`/`30`/`40`/`50`/`60`/`70`/`80` (pixels). Default `30`. |
| `markers` | Group of additional pins. JSON list; each item has `marker_address`, `marker_text` (textarea, not encoded), `marker_img`, `marker_size`. |

**Appearance**

| Param | What it does |
|-------|--------------|
| `provider` | `google` (default) or `osm`. Switches API and toggles which extra params apply. |
| `type` | (`provider="google"` only) Tile style — `roadmap` (default), `terrain`, `satellite`, `hybrid`. |
| `zoom` | Map zoom level 1–20. Default `14`. |
| `hide_controls` | `1` hides all map controls (zoom buttons, fullscreen). |
| `disable_zoom` | `1` disables zoom on mouse-wheel scroll. **Strongly recommended** when the map is in the page flow — otherwise visitors who scroll over it get trapped. |
| `disable_dragging` | `1` disables one-finger dragging on touch screens (visitor must use two fingers). |
| `map_style_json` | (`provider="google"` only) Snazzymaps-style JSON to recolor the map. **Base64-encoded**. |
| `layer_style` | (`provider="osm"` only) Tile-server URL template, e.g. `https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png`. See leaflet-providers for the catalog. |

**Sizing**

The map height comes from the Design Options group (custom CSS `height`). There is no `height` shortcode attribute — set it via the builder's Design panel or wrap the shortcode in a fixed-height container.

**Minimal example**

```text
[us_gmaps marker_address="1600 Amphitheatre Parkway, Mountain View, CA" zoom="15" disable_zoom="1"]
```

**Common combinations**

OpenStreetMap, no API key needed:

```text
[us_gmaps provider="osm" marker_address="55.7558, 37.6173" zoom="13" disable_zoom="1"]
```

With an info window (note the base64-encoded body):

```text
[us_gmaps marker_address="Berlin, Germany" show_infowindow="1"
  marker_text="PGgyPkJlcmxpbiBPZmZpY2U8L2gyPjxwPllvdXIgdHJ1c3RlZCB0ZWFtLjwvcD4="]
```

(`marker_text` decodes to `<h2>Berlin Office</h2><p>Your trusted team.</p>`.)

**Anti-patterns**

- Forgetting `disable_zoom="1"` — the map captures mouse-wheel scroll and visitors can't continue down the page.
- Pasting raw HTML into `marker_text` — it must be base64-encoded; non-encoded HTML reads as literal text and breaks the info window.
- Embedding the map without configuring a Google API key (with `provider="google"`) — the embed renders a "for development purposes only" watermark.
- Using `markers` for a single pin — use the top-level `marker_*` params; the group is for **additional** pins.

### `us_login` — Login

**When to use**: an inline WordPress login form (username + password) on a public page — typical for a customer portal landing page, a members-area gate, or a header dropdown that flips between "Sign in" and "My account" depending on auth state.

**Avoid when**:
- you only need a link to `wp-login.php` — that's a `[us_btn]` with `link="url:wp-login.php"`;
- you need a full registration form with custom fields — use a forms plugin (Gravity Forms, etc.) or WP's standard registration flow with `register` set;
- you want a social-login button row — that's a third-party plugin's territory.

**Auth state**: when the visitor is already logged in, the shortcode renders a logout link instead of the form (using `logout_redirect` if set).

**Key parameters**

| Param | What it does |
|-------|--------------|
| `us_field_style` | Per-site form-field style. Comes from Theme Options → Field Styles. Default `default`. |
| `register` | URL of the "Register" link shown under the form. Empty hides it. |
| `lost_password` | URL of the "Lost your password?" link. Empty falls back to `wp_lostpassword_url()`. |
| `login_redirect` | URL the visitor lands on after a successful login. Empty redirects to the home page. |
| `logout_redirect` | URL the visitor lands on after logging out (when the shortcode renders the logout link for an authenticated visitor). |
| `use_ajax` | `1` submits via AJAX. **Recommended when page caching is enabled for logged-in visitors** — otherwise the cached HTML may show the form to an already-logged-in user. |

**Minimal example**

```text
[us_login]
```

**Common combinations**

Cached site, AJAX submit, register link points to a custom signup page:

```text
[us_login use_ajax="1" register="https://example.com/signup/" login_redirect="https://example.com/dashboard/"]
```

**Anti-patterns**

- Placing `us_login` on a page that's behind the login itself — logged-in visitors get a logout link in a place they didn't expect.
- Mixing `us_login` with a forms plugin (Gravity Forms login form) on the same page — visitors see two competing forms.
- Leaving `use_ajax="0"` on a cached site — the form may auto-submit a stale nonce, or the page may show a "you are logged in" message to a logged-out visitor.
- Hard-coding `lost_password` to a third-party URL when WP can handle it natively — just leave it empty.

### `us_category_nav` — Category Navigation

**When to use**: a hierarchical list of taxonomy terms (post categories, product categories, custom taxonomies) with parent/child indentation, optional post counts, and an "accordion" mode that folds branches. Typical placement: a blog/shop sidebar, an archive landing page, a docs index.

**Avoid when**:
- you only need a flat list of all terms — `us_term_list` is the loop variant and is faster to render;
- you want a faceted filter that re-queries the listing — `us_list_filter` (paired with `us_post_list`);
- you want a horizontal main-menu — that's a WP menu rendered via `us_additional_menu`, not a category nav.

**Context**: on a category/term archive page, the **current** term and its ancestors are auto-expanded and highlighted; on a regular page, the whole tree (up to `max_parent_level`) renders.

**Key parameters**

**Source**

| Param | What it does |
|-------|--------------|
| `taxonomy` | Taxonomy slug to traverse. Default `category`. Other common values: `product_cat`, `portfolio_category`, custom taxonomy slugs. |
| `hide_empty` | `1` hides terms that have no published posts. |
| `show_count` | `1` shows the post count next to each term. |
| `max_parent_level` | How many ancestor levels above the current term to render (1–3, default `1`). Only meaningful on a term archive page. |
| `max_child_level` | How many descendant levels below the current term to render (1–3, default `1`). |

**Layout**

| Param | What it does |
|-------|--------------|
| `show_as_accordion` | `1` renders branches as a collapsible accordion (parent terms toggle open/close their children). |
| `accordion_allow_multiple_open` | `1` lets visitors keep several branches open at once. Only meaningful when `show_as_accordion="1"`. |
| `accordion_control_icon` | Toggle icon shape — `chevron` (default), `plus`, or `triangle`. |
| `accordion_control_position` | Icon side relative to the term title — `before` or `after` (default `after`). |
| `item_style` | `links` (default — plain text rows) or `blocks` (filled blocks with hover/active backgrounds). Switching to `blocks` unlocks the color params below. |
| `item_gap` | Gap between rows. Default `0.4rem`. Accepts `px`/`rem`/`em`. |
| `item_ver_indent` / `item_hor_indent` | Inner padding of each row, only applied when `item_style="blocks"`. |

**Colors** (only when `item_style="blocks"`, except `item_color_text` / `item_color_text_hover` which apply to both styles)

| Param | What it does |
|-------|--------------|
| `item_color_bg` | Block background. Default `_content_bg_alt` (theme token). |
| `item_color_text` | Term-name text color. Default `inherit`. |
| `item_color_bg_hover` | Block background on hover. Default `_content_border`. |
| `item_color_text_hover` | Term-name color on hover. |
| `item_color_bg_active` | Block background for the current term. |
| `item_color_text_active` | Term-name color for the current term. |

**Minimal example**

```text
[us_category_nav taxonomy="category" show_count="1"]
```

**Common combinations**

WooCommerce shop sidebar, accordion mode, only categories with products:

```text
[us_category_nav taxonomy="product_cat" hide_empty="1" show_count="1"
                 show_as_accordion="1" accordion_control_icon="plus"]
```

Block-style with custom hover colors:

```text
[us_category_nav taxonomy="category"
                 item_style="blocks"
                 item_color_bg="_content_bg_alt"
                 item_color_bg_hover="_primary"
                 item_color_text_hover="#ffffff"]
```

**Anti-patterns**

- Setting `max_parent_level="3"` on a deep taxonomy (e.g. a 5-level product tree) on a non-term page — the whole tree dumps into the sidebar and the column overflows. Pair with `show_as_accordion="1"` or pick a lower value.
- `show_count="1"` with `hide_empty="0"` — visitors see lots of `(0)`s. Either hide empties or hide counts.
- `taxonomy="post_tag"` and expecting hierarchy — tags are flat; the nav renders as a single-level list and `max_*_level` does nothing.

### `us_sharing` — Sharing Buttons

**When to use**: a row of social-network share buttons that post the current page (or a custom URL) to Facebook / X / LinkedIn / etc. Typical placement: under a blog post title, on a product page, in a "share this" footer block.

**Avoid when**:
- you want links to **your** social profiles — `[us_socials]` is that;
- you want a single "share via…" button — a forms plugin or a `us_btn` with a sharer URL is simpler;
- the page isn't publicly accessible — share targets resolve to 404 / login walls.

**Modes**:
- inline row (default styles `simple`, `solid`, `outlined`) — renders in the page flow;
- `type="fixed"` — sticky rail attached to the side of the viewport.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `providers` | Comma-separated list of platforms to show. Default `facebook,twitter`. Allowed values: `email`, `facebook`, `twitter`, `linkedin`, `pinterest`, `vk`, `whatsapp`, `xing`, `reddit`, `telegram`. |
| `type` | Visual style — `simple` (default — minimal icons), `solid` (filled circles), `outlined` (bordered), `fixed` (sticky side rail). |
| `align` | Inline alignment — `none` (default), `left`, `center`, `right`, `justify`. Ignored when `type="fixed"`. |
| `color` | Icon coloring — `default` (brand colors), `primary` (theme primary), `secondary` (theme secondary). |
| `text_selection` | `1` shows a floating share panel when the visitor selects text on the page (and the share posts the selected text). |
| `text_selection_post` | `1` restricts the text-selection panel to **inside the main post content** only — quoted UI text doesn't trigger it. Requires `text_selection="1"`. |
| `url` | Custom share URL. Empty (default) uses the current page URL. |

**Minimal example**

```text
[us_sharing providers="facebook,twitter,linkedin,telegram"]
```

**Common combinations**

Sticky side rail with solid brand colors:

```text
[us_sharing type="fixed" providers="facebook,twitter,linkedin,whatsapp,email" color="default"]
```

Centered row under a blog post, with text-selection sharing limited to the post body:

```text
[us_sharing align="center" providers="twitter,linkedin,reddit"
            text_selection="1" text_selection_post="1"]
```

**Anti-patterns**

- `providers` including platforms your audience doesn't use (Xing on a non-DACH site, VK outside Russia) — clutters the row.
- Setting a custom `url` and forgetting to update it when the page is renamed — the share posts a 404.
- Using `type="fixed"` on a page with a fixed-position chat widget on the same side — the two overlap.
- More than 5–6 platforms in one row — visitors don't pick from a dozen; pick the channels that actually drive traffic.

### `us_user_data` — User Data

**When to use**: renders a single field from a WordPress user — the post's author by default, or any other user in the current loop context. Typical placement: a "by {{author}}" line in a blog template, an author-bio card, an account-page greeting, a member directory entry.

**Avoid when**:
- you need a full author-card (avatar + name + bio + social) — `[us_person]` is purpose-built for that;
- you want a list of multiple users — that's `[us_user_list]` (out of this iteration's scope);
- you want a post field (date, category, title) — that's `[us_post_*]` shortcodes (also out of scope).

**Context**: this shortcode reads from the current user-loop item, or — if no loop is active — from the author of the current post. Inside a `us_user_list` item template, each iteration sets the current user.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `type` | What to render. One of: `display_name` (default), `first_name`, `last_name`, `nickname`, `user_email`, `user_url`, `description` (biographical info), `role`, `user_registered` (registration date), `post_count` (number of posts authored), `custom` (a usermeta field). |
| `custom_field` | Usermeta key to read, when `type="custom"`. |
| `post_type` | Comma-separated post type slugs to count, when `type="post_count"`. Default `post`. |
| `date_format` | PHP date format, when `type="user_registered"`. Default `F j, Y`. |
| `link` | Optional link wrapping the value. JSON shape `{"url":"...","target":"_blank"}`. The special sentinel `{"url":"elm_value"}` makes the value itself clickable (only for email/phone/website types — turns into `mailto:`/`tel:`/the URL). |
| `color_link` | `1` makes the link inherit the surrounding text color instead of the theme link color. |
| `tag` | HTML tag to wrap the value in. Default `div`. Use `h1`-`h6` for headings, `span` for inline. |
| `text_before` / `text_after` | Static text rendered before/after the value (e.g. `text_before="by "`). Supports dynamic values. |

**Minimal example**

Display the current post author's name:

```text
[us_user_data type="display_name"]
```

Author byline with prefix:

```text
[us_user_data type="display_name" text_before="by " tag="span"]
```

**Common combinations**

Clickable email link, inheriting text color:

```text
[us_user_data type="user_email" link='{"url":"elm_value"}' color_link="1"]
```

Post count for a specific custom post type, in an author-card sidebar:

```text
[us_user_data type="post_count" post_type="portfolio" text_after=" projects"]
```

Registration date, custom format:

```text
[us_user_data type="user_registered" date_format="M Y" text_before="Member since "]
```

**Anti-patterns**

- `type="custom"` without `custom_field` — renders nothing.
- `type="post_count"` with `post_type=""` — the count silently falls back to `post`, missing your CPTs.
- Wrapping with a generic `link` URL when the value should be the link (e.g. email) — use the `{"url":"elm_value"}` sentinel instead so the value itself becomes the `mailto:` link.
- Reading `description` and forgetting it may contain HTML — wrap in a `tag="div"` (the default), never `tag="span"` if the bio has paragraphs.

## Lists

### `us_post_list` — Post List

**When to use**: a query-driven grid of posts (or any custom post type) — blog index, news feed, portfolio archive, child-post listing, "favorites of the current user", etc. Pulls items via `WP_Query`, renders them through a saved Grid Layout, and optionally drives a Filter / Order / Search / Result-Counter / Reset companion placed elsewhere on the same page.

**Avoid when**:
- the items are products — use `us_product_list` (it has WooCommerce-aware sources, price filter, stock flags);
- the items are taxonomy terms or users — use `us_term_list` / `us_user_list`;
- you want a horizontal slider instead of a paginated grid — use `us_post_carousel` (same query params, no `pagination` / `type` / `columns` — those live on the carousel options);
- the children are arbitrary shortcodes (icon boxes, CTA blocks, etc.) not bound to posts — use `us_content_carousel` or plain `vc_row` columns.

**Source**: items are picked by the `source` attribute, then filtered by author / taxonomy / custom-field / offset conditions. Order, quantity and pagination form a second group; appearance (grid layout, columns, aspect ratio, animations) a third.

**Key parameters**

**Source / What to show**

| Param | What it does |
|-------|--------------|
| `source` | Pool to query — `all` (default), `post__in` (selected ids), `post__not_in` (all except selected), `child_posts_of_current`, `child_posts_of_selected`, `media`, `user_favorite_ids` (current visitor's favourites), `current_wp_query` (use the page's existing query — only valid on archive/search templates). |
| `ids` | Comma-separated post IDs used by `post__in` / `post__not_in` / `child_posts_of_selected`. |
| `post_type` | Comma-separated post types to query (default `post`). Examples: `page`, `us_portfolio`, `tribe_events`. Ignored when `source` is `child_posts_of_current` / `current_wp_query` / `media`. |
| `attachment_ids` | Comma-separated media IDs when `source="media"`. |
| `include_post_thumbnail` | `1` prepends the post's featured image when `source="media"`. |
| `post_author` | `any` (default), `include`, `exclude`, `current_author` (author of the current post), `current_user` (logged-in visitor). |
| `post_author_ids` | Comma-separated user IDs when `post_author="include"` / `"exclude"`. |
| `apply_url_params` | `1` lets companion filter / order / search shortcodes drive this list via URL params. Required if you want a Filter widget on the same page. |
| `ignore_sticky_posts` | `1` (default) skips sticky posts. |
| `exclude_children` | `1` excludes child posts of any post. |
| `exclude_current_post` | `1` (default) excludes the post currently being viewed. |
| `exclude_prev_posts` | `1` excludes posts already shown by an earlier `us_post_list` on the same page (de-dupe across blocks). |
| `exclude_past_events` | `1` hides past events (only meaningful for `post_type="tribe_events"`). |
| `enable_items_offset` + `items_offset` | Skip the first N posts (e.g. to leave room for a featured block above). |

**Taxonomy & custom-field filters**

| Param | What it does |
|-------|--------------|
| `tax_query_relation` | `none` (default), `AND` (all conditions must match), `OR` (any). |
| `tax_query` | JSON-encoded array of conditions. Each entry: `{ "operator": "IN"\|"AND"\|"NOT IN"\|"CURRENT", "taxonomy": "<slug>", "terms": "<id,id,…>", "include_children": "0"\|"1" }`. `CURRENT` re-uses the terms of the post being viewed. |
| `meta_query_relation` | `none` / `AND` / `OR`. |
| `meta_query` | JSON array of `{ "key": "<field>", "compare": "="\|"!="\|">"\|">="\|"<"\|"<="\|"LIKE"\|"NOT LIKE"\|"EXISTS"\|"NOT EXISTS", "value": "…" }`. |

**Order & quantity**

| Param | What it does |
|-------|--------------|
| `orderby` | `date` (default), `modified`, `title`, `author`, `comment_count`, `type`, `menu_order`, `rand`, `post__in` (preserve `ids` order), `current_wp_query` (preserve the archive order), `custom` (custom field). |
| `orderby_custom_field` | Custom-field name when `orderby="custom"`. |
| `orderby_custom_type` | `1` treats the custom-field values as numbers. |
| `order_invert` | `1` flips the order direction. |
| `show_all` | `1` ignores `quantity` and returns the whole result set. |
| `quantity` | Items to show (1–30, default `12`). Hidden when `show_all="1"` or `source="current_wp_query"`. |
| `posts_per_archive_page` | Posts per page when `source="current_wp_query"`; `0` (default) uses the WP Reading setting. |
| `no_items_action` | What to render when the query returns nothing — `message` (default), `page_block`, `hide_grid`. |
| `no_items_message` | The message text when `no_items_action="message"`. |
| `no_items_page_block` | Reusable-block id when `no_items_action="page_block"`. |

**Pagination**

| Param | What it does |
|-------|--------------|
| `pagination` | `none` (default), `numbered`, `numbered_ajax`, `load_on_btn`, `load_on_scroll`. |
| `pagination_style` | Style key from Theme Options → Buttons (numbered pagination only). |
| `pagination_btn_text` / `pagination_btn_size` / `pagination_btn_style` / `pagination_btn_fullwidth` | Load-More button label / size / style key / full-width toggle (only when `pagination="load_on_btn"`). |

**Appearance**

| Param | What it does |
|-------|--------------|
| `items_layout` | Grid Layout id (saved post type `us_grid_layout`). Default `blog_1`. This single param drives the entire card markup — image position, meta rows, hover, etc. |
| `type` | `grid` (default), `masonry`, `metro` (only works with 1×1 items). |
| `items_valign` | `1` vertically centers items in their grid cell (only when `type="grid"`). |
| `ignore_items_size` | `1` ignores any per-item custom size set in the Grid Layout (only when `type!="metro"`). |
| `columns` | 1–10, default `4`. Auto-overridden by responsive breakpoints. |
| `items_gap` | Gap between cards. Accepts `px` / `rem` / `em`. Default `1.5rem`. |
| `load_animation` | `none` (default), `fade`, `afc`, `afl`, `afr`, `afb`, `aft`, `hfc`, `wfc`. |
| `items_preload_style` | Placeholder while ajax-paginating / filtering — `spinner` (default), `fade`, `placeholders`, `none`. |
| `img_size` | Image size — `default` (as in Grid Layout) or any registered size (`thumbnail`, `medium`, `large`, `full`, theme sizes). |
| `title_size` | Override the title font size — CSS length (`1.2rem`, `24px`, …). |
| `items_ratio` | `default`, `1x1`, `4x3`, `3x2`, `16x9`, `2x3`, `3x4`, `custom`. With `custom`, set `items_ratio_width` / `items_ratio_height`. |
| `overriding_link` | Wraps the whole card in a link. URL-encoded JSON, same shape as other `link` params. Values: a custom URL, the post permalink, `popup_post` (open the post in a popup), `popup_image` (open the featured image). Disables every link inside the card. |
| `popup_page_template` / `popup_width` / `popup_arrows` | Popup behaviour when `overriding_link` opens a popup. |

**Responsive overrides**: `_columns` / `_items_gap` / `_columns_layout` etc. are read from the shared responsive pack — see [element-effects.md](element-effects.md) for the breakpoint syntax (`_columns_laptops`, `_columns_tablets`, `_columns_mobiles`).

**Minimal example**

```text
[us_post_list post_type="post" quantity="6" columns="3" items_layout="blog_1"]
```

**Common combinations**

Latest 9 posts from two categories, 3-up grid with Load-More:

```text
[us_post_list post_type="post" quantity="9" columns="3"
              tax_query_relation="OR"
              tax_query="%5B%7B%22operator%22%3A%22IN%22%2C%22taxonomy%22%3A%22category%22%2C%22terms%22%3A%2212%2C15%22%2C%22include_children%22%3A%221%22%7D%5D"
              pagination="load_on_btn" pagination_btn_text="Show more"]
```

Child posts of the current page, no pagination, masonry:

```text
[us_post_list source="child_posts_of_current" type="masonry"
              show_all="1" columns="2"]
```

Listing wired to URL params so a `us_list_filter` + `us_list_order` elsewhere on the page can drive it:

```text
[us_post_list post_type="post" apply_url_params="1"
              pagination="numbered_ajax" quantity="12"]
```

**Anti-patterns**

- Setting `source="current_wp_query"` on a regular page (not an archive / search template) — the query is empty and the list renders the "no results" branch.
- Hand-setting `columns="3"` and expecting it to win on desktop — that's correct, but the value is auto-overridden by `_columns_laptops` / `_columns_tablets` / `_columns_mobiles` from the responsive pack; set those too when you need a specific layout on smaller screens.
- Forgetting `apply_url_params="1"` when adding a Filter / Order / Search alongside — the companions emit URL params but the list will ignore them silently.
- Pairing `pagination="numbered_ajax"` with `source="current_wp_query"` — ajax pagination needs the list to own its own query.
- `type="metro"` with non-square Grid Layout items — they render but break out of their cells.

### `us_post_carousel` — Post Carousel

**When to use**: a horizontally-rotating slider of posts — "Latest news" strip on a homepage, "Related posts" rail, partner logos pulled from a CPT, etc. Same query model as [`us_post_list`](#us_post_list--post-list) but the result is an Owl carousel instead of a paginated grid.

**Avoid when**:
- the items are products / terms / users — use `us_product_carousel` / `us_term_carousel` / `us_user_carousel`;
- you want pagination, Load-More, masonry, METRO, or items-per-page control — those are `us_post_list` only (the carousel has no `pagination`, `type`, `columns`, `load_animation`, `items_preload_style`, `items_valign`, `ignore_items_size` — they are stripped from the carousel build);
- the slides are arbitrary blocks unrelated to posts — use `us_content_carousel`.

**Source / Order / No-results**: identical to `us_post_list` — see that entry for `source`, `post_type`, `ids`, `post_author`, `apply_url_params`, `exclude_*`, `tax_query*`, `meta_query*`, `orderby*`, `order_invert`, `show_all`, `quantity`, `posts_per_archive_page`, `no_items_action`, `no_items_message`, `no_items_page_block`. The `items_layout`, `items_gap`, `img_size`, `title_size`, `items_ratio*`, `overriding_link`, `popup_*` attributes also work the same way.

**Carousel-specific parameters**

| Param | What it does |
|-------|--------------|
| `items` | Slides visible at once on desktop — `auto` (for variable widths) or `1`–`10`. Default `3`. |
| `next_item_offset` | Px reveal of the next slide's edge (peek). Default `0px`. |
| `items_valign` | `stretch` (default), `top`, `middle`, `bottom`. |
| `center_item` | `1` puts the active slide in the middle (requires `items` ≥ 2). |
| `slide_by_one` | `1` (default) advances one slide at a time; `0` advances `items` at a time. |
| `autoheight` | `1` re-measures height to the active slide (only when `items="1"`). |
| `loop` | `1` wraps around at the ends. |
| `autoplay` | `1` enables auto-rotation. |
| `autoplay_pause_on_hover` / `autoplay_continual` / `autoplay_continual_css` / `autoplay_timeout` | Auto-rotation tweaks (only meaningful when `autoplay="1"`). `autoplay_timeout` accepts `s` units (default `3s`). |
| `transition_speed` | Slide transition duration in `ms` (default `350ms`). |
| `transition_animation` | `none` (default — sliding) or `fade` (only for `items="1"`). |
| `transition_timing_function` | CSS timing function name or `cubic-bezier(…)`. |
| `arrows` | `1` (default) shows prev/next arrows. |
| `arrows_style` | `circle` (default), `square`, or a button-style key from Theme Options → Buttons. |
| `arrows_size` | Arrow size — `px` / `rem` / `em`. Default `1.5rem`. |
| `arrows_ver_pos` | `middle` (default), `stretch`, `top_outside`, `top_inside`, `bottom_outside`, `bottom_inside`. |
| `arrows_hor_pos` | `on_sides_outside` (default), `on_sides_inside`, `left_inside`, `center`, `right_inside`. |
| `arrows_ver_offset` / `arrows_hor_offset` / `arrows_gap` | Fine-tune arrow placement. |
| `arrows_disabled` | `hide` (default) or `fade` for the disabled arrow when `loop="0"`. |
| `dots` | `1` shows pagination dots under the carousel. |
| `dots_style` | `circle` (default), `diamond`, `dash`, `smudge`. |
| `mouse_drag` / `touch_drag` | `1` (default) enables drag-swipe. |
| `responsive` | JSON array of breakpoint overrides — each entry `{ "breakpoint": "laptops"\|"tablets"\|"mobiles"\|"custom", "breakpoint_width": "1024px", "items": "1", "items_offset": "0px", "center_item": 0, "autoheight": 0, "loop": 0, "autoplay": 0, "arrows": 0, "dots": 0 }`. Settings apply below the chosen width. |

**Minimal example**

```text
[us_post_carousel post_type="post" quantity="8" items_layout="blog_1"
                  items="3" arrows="1" dots="1"]
```

**Common combinations**

"Related posts" rail — same category as the current post, auto-rotation, 1-up on mobile:

```text
[us_post_carousel source="current_wp_query" quantity="10"
                  tax_query_relation="AND"
                  tax_query="%5B%7B%22operator%22%3A%22CURRENT%22%2C%22taxonomy%22%3A%22category%22%2C%22terms%22%3A%22%22%2C%22include_children%22%3A%220%22%7D%5D"
                  exclude_current_post="1"
                  items="3" autoplay="1" autoplay_timeout="5s" loop="1"
                  responsive="%5B%7B%22breakpoint%22%3A%22tablets%22%2C%22items%22%3A%222%22%2C%22arrows%22%3A%221%22%2C%22dots%22%3A%220%22%7D%2C%7B%22breakpoint%22%3A%22mobiles%22%2C%22items%22%3A%221%22%2C%22arrows%22%3A%220%22%2C%22dots%22%3A%221%22%7D%5D"]
```

**Anti-patterns**

- Using `pagination` / `type` / `columns` / `load_animation` / `items_preload_style` here — none of them exist on the carousel; the params are silently dropped by the parent's `exclude_for_carousel` filter.
- `items="auto"` together with `center_item="1"` — centering needs a known item count.
- `transition_animation="fade"` with `items` ≠ `1` — fade is single-slide only; the carousel falls back to sliding without warning.
- Forgetting the `responsive` JSON — desktop `items="4"` becomes unreadable on phones.

### `us_product_list` — Product List

**When to use**: a WooCommerce-aware grid of products — shop landing, "Featured products" block, "On sale" section, upsells/cross-sells, or any custom product subset filtered by price / stock / category. Requires WooCommerce to be active (the shortcode is hidden from the builder otherwise).

**Avoid when**:
- the items are not products — use `us_post_list` (and pass `post_type="product"` only if you need raw post behaviour; the WooCommerce-specific filters below won't work);
- you want a horizontal slider — use `us_product_carousel` (same query model, no pagination / type / columns);
- you want the default WooCommerce shop archive layout — that's controlled by the theme's `shop_layout` Theme Option, not by a manual shortcode.

**Source / Order / Appearance**: most params mirror [`us_post_list`](#us_post_list--post-list) — see that entry for `apply_url_params`, `enable_items_offset` / `items_offset`, `meta_query*`, `orderby*`, `order_invert`, `show_all`, `quantity`, `posts_per_archive_page`, `no_items_*`, `pagination*`, `items_layout`, `type`, `items_valign`, `ignore_items_size`, `columns`, `items_gap`, `load_animation`, `items_preload_style`, `img_size`, `title_size`, `items_ratio*`, `overriding_link`, `popup_*`. The differences are listed below.

**WooCommerce-specific source**

| Param | What it does |
|-------|--------------|
| `source` | `all` (default), `post__in` (selected ids), `post__not_in`, `upsells` (the current product's upsells — only on a product page), `crosssell` (current product's cross-sells — only in cart), `recently_viewed`, `user_favorite_ids`, `current_wp_query`. |
| `ids` | Comma-separated product IDs for `post__in` / `post__not_in`. |
| `onsale_only` | `1` keeps only on-sale products. |
| `featured_only` | `1` keeps only featured products. |
| `exclude_out_of_stock` | `1` hides products with `outofstock` stock status. |
| `exclude_hidden` | `1` (default) hides products with the catalog-visibility "hidden". |
| `exclude_current_product` | `1` (default) excludes the product being viewed (ignored for `upsells` / `crosssell` / `current_wp_query`). |

**Price filter**

| Param | What it does |
|-------|--------------|
| `price_compare` | `none` (default), `greater`, `greater_equal`, `less`, `less_equal`, `equal`, `not_equal`, `in_range`. |
| `price` | The threshold price (or the minimum when `in_range`). |
| `price_max` | The maximum when `price_compare="in_range"`. |

**Taxonomies**: same `tax_query_relation` + `tax_query` shape as `us_post_list`, but the default taxonomy is `product_cat`; the dropdown is restricted to WooCommerce taxonomies (`product_cat`, `product_tag`, `pa_*` product attributes).

**Order**: extra `orderby` options on top of the post-list set — `price`, `rating`, `comment_count` (reviews), `recent_sales` (sales in last N days), `total_sales`, `menu_order`, `title`. When `orderby="recent_sales"`, set `orderby_recent_sales_days` (default `30`).

**Grid Layout default**: `items_layout="shop_standard"`. The selector is restricted to grid layouts of `blog` / `portfolio` / `shop` type. Default `columns="4"`.

**Minimal example**

```text
[us_product_list quantity="12" columns="4"]
```

**Common combinations**

Featured products grid, 3-up, no pagination:

```text
[us_product_list featured_only="1" exclude_out_of_stock="1"
                 quantity="6" columns="3" items_layout="shop_standard"]
```

On-sale block ordered by deepest discount (custom field via store plugin):

```text
[us_product_list onsale_only="1" quantity="8" columns="4"
                 orderby="recent_sales" orderby_recent_sales_days="14"]
```

Shop archive with a filter widget elsewhere on the page:

```text
[us_product_list source="current_wp_query" apply_url_params="1"
                 columns="4" items_layout="shop_standard"
                 pagination="numbered_ajax"]
```

**Anti-patterns**

- Using this on a site without WooCommerce — the shortcode is gated behind `class_exists('woocommerce')` and renders nothing.
- `source="upsells"` outside a single product page (or `crosssell` outside the cart) — there are no upsells to query, the list returns empty.
- `price_compare="in_range"` with only `price` set and no `price_max` — the upper bound defaults silently and the range may be wider than intended.
- `orderby="recent_sales"` without `orderby_recent_sales_days` — the window defaults to 30; pass an explicit value for predictable results.

### `us_product_carousel` — Product Carousel

**When to use**: a horizontally-rotating slider of products — "Featured", "On sale", "Related products" rail under a single product, upsells / cross-sells, a homepage shop teaser. Same query model as [`us_product_list`](#us_product_list--product-list) but the result is an Owl carousel; same WooCommerce gate.

**Avoid when**:
- items aren't products — use `us_post_carousel` / `us_term_carousel` / `us_user_carousel`;
- you need pagination, masonry, METRO, or full-grid columns — that's `us_product_list` (carousels strip those params via the parent's `exclude_for_carousel` filter).

**Source / Order / Appearance**: identical to `us_product_list` for all source params (`source`, `ids`, `onsale_only`, `featured_only`, `exclude_*`, `enable_items_offset`/`items_offset`, `price_compare`/`price`/`price_max`, `tax_query*`, `meta_query*`, `apply_url_params`), order params (`orderby`, `orderby_custom_field`, `orderby_recent_sales_days`, `orderby_custom_type`, `order_invert`, `show_all`, `quantity`, `no_items_*`), and item-level appearance params (`items_layout`, `items_gap`, `img_size`, `title_size`, `items_ratio*`, `overriding_link`, `popup_*`). The carousel-specific params (`items`, `next_item_offset`, `items_valign`, `center_item`, `slide_by_one`, `autoheight`, `loop`, `autoplay*`, `transition_*`, `arrows*`, `dots`, `dots_style`, `mouse_drag`, `touch_drag`, `responsive`) work as documented under [`us_post_carousel`](#us_post_carousel--post-carousel).

**Minimal example**

```text
[us_product_carousel quantity="10" items="4" arrows="1" dots="0"]
```

**Common combinations**

"Related products" carousel under a single product, same category, auto-rotate, 1-up on mobile:

```text
[us_product_carousel source="current_wp_query" quantity="12"
                     tax_query_relation="AND"
                     tax_query="%5B%7B%22operator%22%3A%22CURRENT%22%2C%22taxonomy%22%3A%22product_cat%22%2C%22terms%22%3A%22%22%2C%22include_children%22%3A%220%22%7D%5D"
                     exclude_current_product="1"
                     items="4" autoplay="1" loop="1"
                     responsive="%5B%7B%22breakpoint%22%3A%22tablets%22%2C%22items%22%3A%222%22%7D%2C%7B%22breakpoint%22%3A%22mobiles%22%2C%22items%22%3A%221%22%7D%5D"]
```

Featured-products strip with custom-styled arrows:

```text
[us_product_carousel featured_only="1" quantity="8"
                     items="4" items_gap="20px"
                     arrows="1" arrows_style="square"
                     dots="0" loop="1"]
```

**Anti-patterns**

- Setting `pagination` here — it's stripped on the parent's `exclude_for_carousel` pass; users won't see a Load-More button even if the attribute appears in the markup.
- `items="auto"` plus `center_item="1"` — centering needs a fixed item count.
- Forgetting `responsive` overrides — 4 product cards squashed into a 320px viewport are unusable.

### `us_term_list` — Term List

**When to use**: a grid of taxonomy terms rendered through a Grid Layout — "Browse by category" tiles on a shop / blog landing, portfolio category cards, an A–Z directory of CPT terms. One card per term, with the term's name, count, description, image (if assigned in the term meta), and a link to the term archive.

**Avoid when**:
- you want a hierarchical sidebar with parent/child indentation — use `us_category_nav` (folds branches, auto-expands the current term);
- you want a faceted filter that re-queries a `us_post_list` — use `us_list_filter` instead;
- you want a horizontal slider — use `us_term_carousel`.

**Key parameters**

**Source**

| Param | What it does |
|-------|--------------|
| `source` | `all` (default), `include` (selected term IDs), `exclude` (all except selected), `current_term` (child terms of the term currently being viewed), `current_post` (terms attached to the post being viewed). |
| `taxonomy` | Taxonomy slug — `category`, `post_tag`, `product_cat`, `product_tag`, `us_portfolio_category`, or any custom taxonomy. Default `category`. Hidden when `source="current_term"` (taxonomy is implied by context). |
| `term_ids` | Comma-separated term IDs for `source="include"` / `"exclude"`. |
| `include_children` | `1` recurses into child terms. Ignored when `source="include"` / `"current_post"`. |
| `hide_empty` | `1` hides terms with no posts. |
| `exclude_current` | `1` excludes the term being viewed (on a term archive). |

**Order & quantity**

| Param | What it does |
|-------|--------------|
| `orderby` | `name` (default), `count` (post count), `include` (preserves `term_ids` order), `menu_order` (WooCommerce drag-order), `rand`, `custom` (custom field). |
| `orderby_custom_field` / `orderby_custom_type` | Custom-field name + `1` to sort numerically. |
| `order_invert` | `1` flips direction. |
| `limit_number` | `1` enables the `number` cap. |
| `number` | Max number of terms when `limit_number="1"`. 1–30, default `12`. |

**Custom-field filter**: `meta_query_relation` (`none` / `AND` / `OR`) + `meta_query` JSON, same shape as `us_post_list`.

**No-results**: `no_items_action` (`message` / `page_block` / `hide_grid`) + `no_items_message` / `no_items_page_block`.

**Appearance**

| Param | What it does |
|-------|--------------|
| `items_layout` | Grid Layout id — restricted to `blog` / `tile` / `text` / `side` / `portfolio` types. Default `blog_1`. |
| `type` | `grid` (default), `masonry`, `metro`. |
| `items_valign` | `1` centers items vertically. |
| `columns` | 1–10, default `3`. |
| `items_gap` | Gap. Default `10px`. |
| `load_animation` | Same enum as `us_post_list`. |
| `img_size` | `default` or any registered image size. |
| `title_size` | CSS length override for the term-name font size. |
| `items_ratio*` | Same as `us_post_list`. |
| `overriding_link` | Wraps the card in a link. Dynamic value options: the term archive page (`post`), `popup_post` (open the archive in a popup), `custom_field|us_tile_link`. |
| `popup_*` | Popup behaviour when `overriding_link` opens a popup. |

**Minimal example**

```text
[us_term_list taxonomy="category" hide_empty="1" columns="3"]
```

**Common combinations**

"Shop by category" tiles on a homepage, 4 columns, hide empties, fixed order via selected IDs:

```text
[us_term_list taxonomy="product_cat" source="include"
              term_ids="15,18,21,23" orderby="include"
              columns="4" items_layout="tile_1"
              items_ratio="1x1"]
```

Child terms of the current product category, on a category archive page:

```text
[us_term_list source="current_term" hide_empty="1"
              columns="3" items_layout="blog_1"]
```

**Anti-patterns**

- `source="current_term"` on a non-term page — there is no current term, so the list returns empty silently.
- `taxonomy="post_tag"` with `include_children="1"` — tags are flat; the param has no effect.
- Using this as a hierarchical sidebar — use `us_category_nav` instead (Term List always renders as a flat grid).

### `us_term_carousel` — Term Carousel

**When to use**: a horizontally-rotating slider of taxonomy terms — "Browse by category" rail, portfolio-category teaser, A–Z directory in a tight column. Same query model as [`us_term_list`](#us_term_list--term-list); Owl carousel instead of a paginated grid.

**Avoid when**:
- you want a static grid — use `us_term_list`;
- you want a hierarchical sidebar — use `us_category_nav`.

**Source / Order / Appearance**: identical to `us_term_list` for `source`, `taxonomy`, `term_ids`, `include_children`, `hide_empty`, `exclude_current`, `orderby`, `orderby_custom_field`, `orderby_custom_type`, `order_invert`, `limit_number`, `number`, `meta_query*`, `no_items_*`, `items_layout`, `items_gap`, `img_size`, `title_size`, `items_ratio*`, `overriding_link`, `popup_*`. The carousel params (`items`, `next_item_offset`, `items_valign`, `center_item`, `slide_by_one`, `autoheight`, `loop`, `autoplay*`, `transition_*`, `arrows*`, `dots`, `dots_style`, `mouse_drag`, `touch_drag`, `responsive`) work as documented under [`us_post_carousel`](#us_post_carousel--post-carousel).

**Minimal example**

```text
[us_term_carousel taxonomy="product_cat" hide_empty="1" items="4" arrows="1"]
```

**Common combinations**

"Shop by category" carousel, 4-up desktop / 2-up tablet / 1-up mobile:

```text
[us_term_carousel taxonomy="product_cat" hide_empty="1"
                  items_layout="tile_1" items_ratio="1x1"
                  items="4" loop="1" arrows="1" dots="0"
                  responsive="%5B%7B%22breakpoint%22%3A%22tablets%22%2C%22items%22%3A%222%22%7D%2C%7B%22breakpoint%22%3A%22mobiles%22%2C%22items%22%3A%221%22%2C%22arrows%22%3A%220%22%2C%22dots%22%3A%221%22%7D%5D"]
```

**Anti-patterns**

- `source="current_term"` on a page that isn't a term archive — empty carousel.
- `items="auto"` plus `center_item="1"` — centering needs a fixed item count.
- Setting grid-only params (`type`, `columns`, `load_animation`) here — they're stripped on build.

### `us_user_list` — User List

**When to use**: a grid of registered WordPress users rendered through a user-type Grid Layout — "Our team" page, contributor index, author directory. Cards typically show avatar / display name / role / bio / a link to the author archive.

**Avoid when**:
- you want a curated team page with hand-written titles and photos — use `us_person` cards inside a row, those are not bound to the WP users table;
- you want a horizontal slider — use `us_user_carousel`;
- you want the author of a single post — use `us_post_author` (a different element, out of scope here).

**Key parameters**

**Source**

| Param | What it does |
|-------|--------------|
| `source` | `all` (default), `include` (selected user IDs), `exclude`, `role__in` (selected roles), `role__not_in`, `current_post_author` (author of the post being viewed). |
| `user_ids` | Comma-separated user IDs for `source="include"` / `"exclude"`. |
| `role` | Comma-separated role slugs (`administrator`, `editor`, `author`, `subscriber`, `customer`, …) for `source="role__in"` / `"role__not_in"`. Default `administrator`. |
| `has_published_posts` | `1` keeps only users with at least one published post (any post type). |
| `exclude_current` | `1` excludes the currently viewed author archive's user. |

**Order & quantity**

| Param | What it does |
|-------|--------------|
| `orderby` | `display_name` (default), `post_count`, `registered`, `rand`, `include` (preserves `user_ids` order), `custom`. |
| `orderby_custom_field` / `orderby_custom_type` | Custom user-meta key + `1` to sort numerically. |
| `order_invert` | `1` flips direction. |
| `show_all` | `1` ignores `number`. |
| `number` | Max users, 1–30, default `12`. |

**Custom-field filter**: `meta_query_relation` (`none` / `AND` / `OR`) + `meta_query` JSON, same shape as `us_post_list`. The keys are entries from the `wp_usermeta` table, not post meta.

**No-results**: `no_items_action` (`message` / `hide_grid` — _no_ `page_block` option here) + `no_items_message`.

**Appearance**

| Param | What it does |
|-------|--------------|
| `items_layout` | Grid Layout id — restricted to `user`-type layouts. Default `user_1`. |
| `columns` | 1–10, default `3`. |
| `items_gap` | Gap. Default `10px`. |
| `load_animation` | Same enum as `us_post_list`. |
| `overriding_link` | Wraps the card in a link. Dynamic options are smaller than for posts — typically a custom URL or a popup; there is no built-in "author archive" dynamic value. |
| `popup_width` / `popup_arrows` | Popup behaviour when `overriding_link` opens a popup. |

**Notes**

- There are no `type` (grid/masonry/metro) or `items_ratio` params on `us_user_list` — the layout is always a plain grid; aspect ratio is controlled by the Grid Layout itself.

**Minimal example**

```text
[us_user_list source="role__in" role="editor,author" columns="3"]
```

**Common combinations**

"Our team" page — selected users, fixed order, 4 columns:

```text
[us_user_list source="include" user_ids="12,7,18,4,9"
              orderby="include" columns="4" items_layout="user_1"]
```

Active contributors only (one published post and up):

```text
[us_user_list source="role__in" role="author,contributor"
              has_published_posts="1"
              orderby="post_count" order_invert="1"
              number="12" columns="3"]
```

**Anti-patterns**

- Using this for hand-crafted team bios where most "team members" aren't WP users — the directory will be incomplete; use `us_person` blocks instead.
- Pairing with `us_list_filter` / `us_list_order` — those are wired to post lists (they emit URL params consumed by `WP_Query`); they will not drive a `WP_User_Query`.
- `no_items_action="page_block"` — not available on user lists; use `message` or `hide_grid`.

### `us_user_carousel` — User Carousel

**When to use**: a horizontally-rotating slider of registered users — "Meet the team" rail on a homepage, contributors strip on a blog landing. Same query model as [`us_user_list`](#us_user_list--user-list); Owl carousel instead of a grid.

**Avoid when**:
- you want a static grid — use `us_user_list`;
- you want curated cards not tied to the WP users table — use `us_person` inside `us_content_carousel`.

**Source / Order / Appearance**: identical to `us_user_list` for `source`, `user_ids`, `role`, `has_published_posts`, `exclude_current`, `orderby*`, `order_invert`, `show_all`, `number`, `meta_query*`, `no_items_*`, `items_layout`, `items_gap`, `load_animation`, `overriding_link`, `popup_*`. The carousel params (`items`, `next_item_offset`, `items_valign`, `center_item`, `slide_by_one`, `autoheight`, `loop`, `autoplay*`, `transition_*`, `arrows*`, `dots`, `dots_style`, `mouse_drag`, `touch_drag`, `responsive`) work as documented under [`us_post_carousel`](#us_post_carousel--post-carousel).

**Minimal example**

```text
[us_user_carousel source="role__in" role="editor,author"
                  items="3" arrows="1" loop="1"]
```

**Common combinations**

Team strip with auto-rotation, 1-up on mobile:

```text
[us_user_carousel source="include" user_ids="12,7,18,4,9"
                  orderby="include" items_layout="user_1"
                  items="4" autoplay="1" autoplay_timeout="5s" loop="1"
                  responsive="%5B%7B%22breakpoint%22%3A%22tablets%22%2C%22items%22%3A%222%22%7D%2C%7B%22breakpoint%22%3A%22mobiles%22%2C%22items%22%3A%221%22%7D%5D"]
```

**Anti-patterns**

- Setting `columns` here — there is no `columns` param on user carousels; `items` controls slides visible at once.
- Pairing with `us_list_filter` — filter widgets drive post queries, not user queries.

### `us_list_filter` — List Filter

**When to use**: a faceted filter widget for a post / product list on the same page — narrow by post type, author, category / tag (or any taxonomy), price, stock status, custom field, date. Filter selections are pushed into URL params and consumed by a sibling `us_post_list` / `us_product_list` that has `apply_url_params="1"`. Typical placement: a shop sidebar, an archive header, an "Advanced search" page.

**Avoid when**:
- the visitor should pick *one* sort key, not a filter — that's `us_list_order`;
- they should type free-form text — that's `us_list_search`;
- you just need a hierarchical category nav, not a multi-facet widget — that's `us_category_nav`;
- the page has no `us_post_list` / `us_product_list` with `apply_url_params="1"` — the filter has nothing to drive.

**Wiring**: by default Filter looks for the *first* List on the page (`list_to_filter="first"`); for multiple lists, set `list_to_filter="selector"` and target the list element with `list_selector_to_filter=".my-list"` (CSS class or ID, the `el_class` on the `us_post_list` is the usual hook). The target list **must** have `apply_url_params="1"`, otherwise the URL params change but the list ignores them.

**Key parameters**

**Filter items** — `items` is a JSON-encoded group; each entry is one filter row in the widget. Per-entry params:

| Entry param | What it does |
|-------------|--------------|
| `source` | The field to filter by. Built-in keys: `post_type`, `post_author`, `post_date`, `post_modified`. WooCommerce keys (when active): `price`, `instock`, `onsale`, `featured`. Any registered taxonomy slug is also valid (`category`, `post_tag`, `product_cat`, custom taxonomy slugs). |
| `post_type` | Comma-separated post types to offer when `source="post_type"`. |
| `post_author` | `all` (default) / `include` (offer selected authors only) / `exclude`. Pair with `post_author_ids`. |
| `term_compare` | For taxonomy sources — `all` (default), `include`, `exclude`. Pair with `term_ids` and optionally `term_show_children` / `term_exclude_children`. |
| `selection_type` | UI control for taxonomy / post-type / author / bool sources — `checkbox` (default), `radio`, `dropdown`, `range_slider`, `range_input`. |
| `term_operator` | `OR` (default — any selected term matches) or `AND` (all must match). Checkbox UI only. |
| `bool_value_label` | Label next to the checkbox for `instock` / `onsale` / `featured`. |
| `numeric_selection_type` | For numeric sources (`price`, custom numeric fields) — `range_slider` (default), `range_input`, `checkbox`, `radio`, `dropdown`. |
| `num_values_range` / `num_step_size` / `num_min_value` / `num_max_value` / `text_before_value` / `text_after_value` | Numeric tweaks (bucket size, slider step, min/max, prefix/suffix). |
| `date_selection_type` | For date sources — `date_picker` (default), `checkbox`, `radio`, `dropdown`, `range_slider`, `range_input`. |
| `date_picker_fields` | `exact` (default), `start`, `end`, `start_end`. |
| `date_values_format` | jQuery UI datepicker format. Default `d MM yy`. |
| `date_values_range` / `date_month_format` / `date_invert_order` | Bucketing for grouped date filters. |
| `label` | Override the row title (leave blank for the default — taxonomy name / "Author" / "Price" / etc.). |
| `first_value_label` | Adds a synthetic first entry to the value list that represents the "no filter applied" state — appears as an "All" / "Any" pill, checked by default. Default `"Any"`. Use this on a single-row radio filter as the proper "show everything" affordance (the dedicated `us_list_filter_reset` element is only worth adding when there are multiple filter rows). |
| `has_search` / `search_placeholder` | Show a search field inside the values list (checkboxes and radios only). |
| `values_as_btn` | `1` renders values as buttons (checkboxes and radios only). When set, `values_btn_style` and `values_btn_cols` (below) become meaningful. |
| `values_btn_style` | Style applied to each value pill. Accepts **two kinds of values**: a built-in non-themed filter-pill style — `style_1` (outlined, brand-colored when active — CSS in `common/css/elements/grid-filter.css:69–79`), `style_2` (text-link colored, alt-bg when active, solid brand on hover — `:81–99`), `style_3` (underline-only tabs — `:101–122`); OR a numeric key from Theme Options → Buttons (`"1"`, `"2"`, …) which applies the full themed-button class `w-btn us-btn-style_N` to every value (typically too heavy for a filter strip). Default `style_1`. The branching happens at `templates/elements/list_filter.php:805` via `is_numeric($value)` — `"style_2"` and `"2"` are **not** equivalent. |
| `values_btn_cols` | Layout of the pill row. `auto` (default — natural flex row, pills size to content) is what you want for a horizontal category strip. A number `2`–`5` switches to a fixed-column CSS grid (`grid-template-columns: repeat(N, 1fr)`) — only set this when you genuinely want a uniform-width grid (vertical sidebar with many short labels, etc.); with three pills in a horizontal strip and `values_btn_cols="4"`, you get three pills and an empty fourth cell. **Must be set explicitly** when `values_as_btn=1` — us-core reads the key without a null-coalesce and emits a `Undefined array key "values_btn_cols"` PHP Notice otherwise (see [composition-rules §3.5](../composition-rules.md#35-group-json-attributes)). |
| `show_color_swatch` / `hide_color_swatch_label` | Show color swatches for taxonomy terms that have a colour set in term meta. |

**Layout / Appearance**

| Param | What it does |
|-------|--------------|
| `layout` | `ver` (default — vertical, sidebar) or `hor` (horizontal — header bar). |
| `item_layout` | `default` (titles on top), `toggle` (titles collapse / expand groups), `dropdown` (titles as dropdowns), `no_titles`. |
| `dropdown_field_style` | Field style key from Theme Options → Form Field Styles (only when `item_layout="dropdown"`). |
| `values_drop` | `hover` (default) or `click` (when `item_layout="dropdown"`). |
| `align` | `none` (default), `left`, `center`, `right`, `justify`. Only when `layout="hor"`. |
| `items_gap` | Gap between filter rows. Default `1.5em`. |
| `values_max_height` | Max height of each values list (scroll inside). |
| `us_field_style` | Field style key for dropdown / range inputs. |

**Mobiles**: at and below `mobile_width` (default `600px`) the whole widget collapses into a single button labelled `mobile_button_label` (default "Filters") that opens an off-canvas drawer. Tweak with `mobile_button_style` / `mobile_button_icon` / `mobile_button_iconpos` / `mobile_button_badge_color`. Set `mobile_width=""` to disable the mobile collapse.

**More Options**

| Param | What it does |
|-------|--------------|
| `list_to_filter` | `first` (default) — auto-target the first list on the page; `selector` — explicit. |
| `list_selector_to_filter` | CSS class or ID of the list element when `list_to_filter="selector"`. |
| `change_url_params` | `1` (default) writes selections into the URL — required for shareable / bookmarkable filtered states and for browser back/forward. |
| `scroll_to_list` | `1` (default) scrolls to the list after a filter change. |
| `faceted_filtering` | `1` adapts available values to the visible result set (greys out empty options). Requires running the filter indexer in Theme Options → Advanced; an inline message reminds you. |
| `hide_post_count` / `hide_disabled_values` / `hide_disabled_items` | Faceted-only display tweaks. |
| `post_type_for_values` | Restrict the source of values to specific post types when faceted filtering is **off**. |

**Minimal example**

```text
[us_list_filter items="%5B%7B%22source%22%3A%22product_cat%22%2C%22term_compare%22%3A%22all%22%2C%22selection_type%22%3A%22checkbox%22%2C%22label%22%3A%22%22%7D%2C%7B%22source%22%3A%22price%22%2C%22numeric_selection_type%22%3A%22range_slider%22%2C%22num_step_size%22%3A%2210%22%2C%22label%22%3A%22%22%7D%5D"]
```

**Common combinations**

Shop sidebar with category checkboxes, price slider, in-stock toggle:

```text
[us_list_filter layout="ver"
                items="%5B%7B%22source%22%3A%22product_cat%22%2C%22term_compare%22%3A%22all%22%2C%22selection_type%22%3A%22checkbox%22%2C%22term_operator%22%3A%22OR%22%2C%22label%22%3A%22%22%7D%2C%7B%22source%22%3A%22price%22%2C%22numeric_selection_type%22%3A%22range_slider%22%2C%22num_step_size%22%3A%2210%22%2C%22label%22%3A%22%22%7D%2C%7B%22source%22%3A%22instock%22%2C%22selection_type%22%3A%22checkbox%22%2C%22bool_value_label%22%3A%22In%20stock%20only%22%7D%5D"
                faceted_filtering="1"]
```

Horizontal filter bar above a blog grid, targeting a specific list by class:

```text
[us_list_filter layout="hor" align="center"
                items="%5B%7B%22source%22%3A%22category%22%2C%22term_compare%22%3A%22all%22%2C%22selection_type%22%3A%22radio%22%2C%22label%22%3A%22%22%7D%2C%7B%22source%22%3A%22post_date%22%2C%22date_selection_type%22%3A%22date_picker%22%2C%22date_picker_fields%22%3A%22start_end%22%2C%22label%22%3A%22%22%7D%5D"
                list_to_filter="selector" list_selector_to_filter=".news-grid"]
```

Portfolio category-pill bar (single facet, idiomatic — `first_value_label` gives an "All" pill as part of the filter itself; `values_btn_cols="auto"` keeps the row to a natural flex of as many pills as you have; `style_2` uses the built-in light text-link pill style instead of a heavy themed button):

```text
[us_list_filter layout="hor" item_layout="no_titles" align="center" items_gap="0px" change_url_params="0"
                items="%5B%7B%22source%22%3A%22us_portfolio_category%22%2C%22term_compare%22%3A%22all%22%2C%22selection_type%22%3A%22radio%22%2C%22term_operator%22%3A%22OR%22%2C%22values_as_btn%22%3A%221%22%2C%22values_btn_style%22%3A%22style_2%22%2C%22values_btn_cols%22%3A%22auto%22%2C%22first_value_label%22%3A%22All%22%2C%22label%22%3A%22%22%7D%5D"
                list_to_filter="selector" list_selector_to_filter=".my-projects-grid"]
```

decodes to:

```json
[{"source":"us_portfolio_category","term_compare":"all","selection_type":"radio","term_operator":"OR","values_as_btn":"1","values_btn_style":"style_2","values_btn_cols":"auto","first_value_label":"All","label":""}]
```

**Anti-patterns**

- Forgetting `apply_url_params="1"` on the target list — selections appear in the URL but the list never updates.
- Setting `faceted_filtering="1"` without running the filter indexer in Theme Options → Advanced — values look static and never grey out.
- Two filters on the same page both with `list_to_filter="first"` — both target the same list; use `selector` + per-list classes for multi-list pages.
- Numeric filter on a string custom field — values look right in the UI, but `WP_Query`'s numeric compare returns nothing.
- Pairing a **single-row filter** (one `items` entry, e.g. a portfolio category strip) with `us_list_filter_reset` for "show all". This filter already renders a per-row reset link (`<a class="w-filter-item-reset">Reset</a>` inside the row, hidden until a value is selected) — that is the right "back to all" affordance for a single facet. `us_list_filter_reset` is meant for compound widgets with several sources; on a single-row filter it's a redundant second control and is easily mis-labelled as a filter *value* like "All". See the [`us_list_filter_reset`](#us_list_filter_reset--list-filter-reset) anti-patterns.

### `us_list_filter_reset` — List Filter Reset

**When to use**: a "Reset All" button that clears every filter on the same page, optionally with chips for the currently selected values (each chip removes its own value when clicked). Typical placement: directly above or below a `us_list_filter` widget, or next to a `us_list_result_counter` in the toolbar of a shop / blog listing.

**Avoid when**:
- there is no `us_list_filter` on the page — the button has nothing to reset and renders as inert markup;
- you want a free-text search reset — `us_list_search` has its own clear control;
- you want to reset only one filter row — there is no per-row reset; this element clears the lot. Use the per-value chips (`show_selected_values="1"`) for granular removal.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `reset_all_label` | Button label. Default "Reset All". |
| `reset_all_style` | Button style — `style_1` (default), `style_2`, or a key from Theme Options → Buttons. |
| `show_selected_values` | `1` (default) renders a chip per active filter value next to the button; clicking a chip removes only that value. |
| `selected_values_style` | Chip style — `style_1` (default), `style_2`, or a Theme Options → Buttons key. |
| `selected_values_pos` | `before` (default) — chips render before the Reset All button; `after` — after. |
| `values_gap` | Gap between chips. Default `10px` (`px` / `em` / `rem`). |

**Minimal example**

```text
[us_list_filter_reset]
```

**Common combinations**

Shop toolbar with result counter + reset chips + reset button:

```text
[us_list_result_counter]
[us_list_filter_reset reset_all_label="Clear filters"
                      show_selected_values="1"
                      selected_values_pos="before"]
```

Compact "Clear" pill on a horizontal filter bar:

```text
[us_list_filter_reset reset_all_label="Clear"
                      reset_all_style="style_2"
                      show_selected_values="0"]
```

**Anti-patterns**

- Placing this without a `us_list_filter` on the page — the button has no active state and never lights up.
- `show_selected_values="1"` plus dozens of taxonomy terms — the chip strip can run wider than the toolbar; pair with `values_max_height` on the filter or use `show_selected_values="0"`.
- **Adding this when the page has only one filter row.** `us_list_filter_reset` is for compound filter widgets — *multiple* sources (post-type + price + stock + date + category, or several taxonomy facets) where the visitor benefits from a single "clear everything" affordance. A page whose only filter is a single `us_list_filter` with one `items` entry — e.g. a portfolio category strip — does **not** need it. The `us_list_filter` itself already renders a per-row reset link (`<a class="w-filter-item-reset">Reset</a>` inside the filter row, default-hidden, shown when any value is selected) which is the correct "back to show-all" affordance for a single facet. Adding `us_list_filter_reset` next to a single-facet filter just produces a second, redundant control — and tempts the author to relabel it as a filter value (see next bullet).
- **Disguising the reset as a filter value with `reset_all_label="All"`** (or "Все", "Any", a category-like name) next to a row of category buttons. To the visitor it reads as "show everything in this category" — a *filter value*, not a reset. They click it, every facet on the page clears with no warning. Keep the label clearly state-clearing: `"Reset"`, `"Reset all"`, `"Clear filters"`, `"Очистить"`. If the design genuinely calls for an "All categories" pill in the same row of category buttons, model it as part of the `us_list_filter` (`selection_type="radio"` already gives an unselected "any" state via the first-value entry, and the filter's per-item reset link is the proper "show all for this row" affordance) — do not press `us_list_filter_reset` into that role.

### `us_list_order` — List Order

**When to use**: a sort dropdown that lets visitors re-order a sibling `us_post_list` / `us_product_list` (or any post-driven list) — "Sort by: Newest / Price ↑ / Price ↓ / Popularity". The element writes the chosen key into a URL param consumed by the list (the list must have `apply_url_params="1"`). Typical placement: shop / blog toolbar, archive header.

**Avoid when**:
- you want filtering by *value* (in-stock yes/no, category) — that's `us_list_filter`;
- the listing has only one natural order (e.g. a static "Our values" block) — skip the dropdown;
- the listing is a user / term list — those queries do not consume the order URL params emitted by this element.

**Key parameters**

**Options** — `orderby_items` is a JSON-encoded group; each entry is one dropdown option. Per-entry params:

| Entry param | What it does |
|-------------|--------------|
| `value` | Sort key. Built-in: `date`, `modified`, `title`, `author`, `comment_count`, `type`, `menu_order`. WooCommerce: `price`, `total_sales`, `rating`. Or `custom` (custom field). |
| `custom_field` | Custom-field key when `value="custom"`. |
| `custom_field_numeric` | `1` treats the custom-field value as a number. |
| `invert` | `1` flips this option's direction (e.g. cheapest first vs. most expensive). |
| `label` | Override the option label (leave blank for the default — "Date of creation", "Price", etc.). |

The element auto-prepends a "first value" entry (label `Default`) that clears the param and falls back to the list's own `orderby`.

**Appearance**

| Param | What it does |
|-------|--------------|
| `first_label` | Label of the "default" entry. Default "Default". |
| `text_before` | Static text rendered before the dropdown — e.g. "Sort by:". |
| `width_full` | `1` stretches the control to the column width. |
| `change_url_params` | `1` (default) writes the selection into the URL — required for shareable / bookmarkable state. |
| `scroll_to_list` | `1` (default) scrolls to the list after a change. |
| `us_field_style` | Field style key from Theme Options → Form Field Styles. |

**Minimal example**

```text
[us_list_order orderby_items="%5B%7B%22value%22%3A%22date%22%2C%22invert%22%3A%221%22%2C%22label%22%3A%22%22%7D%2C%7B%22value%22%3A%22title%22%2C%22invert%22%3A%220%22%2C%22label%22%3A%22%22%7D%5D"]
```

**Common combinations**

Shop sort dropdown with four options (newest / price asc / price desc / popularity):

```text
[us_list_order text_before="Sort by:"
               orderby_items="%5B%7B%22value%22%3A%22date%22%2C%22invert%22%3A%221%22%2C%22label%22%3A%22Newest%22%7D%2C%7B%22value%22%3A%22price%22%2C%22invert%22%3A%220%22%2C%22label%22%3A%22Price%3A%20low%20to%20high%22%7D%2C%7B%22value%22%3A%22price%22%2C%22invert%22%3A%221%22%2C%22label%22%3A%22Price%3A%20high%20to%20low%22%7D%2C%7B%22value%22%3A%22total_sales%22%2C%22invert%22%3A%221%22%2C%22label%22%3A%22Popularity%22%7D%5D"]
```

Blog sort with a custom-field option (numeric):

```text
[us_list_order orderby_items="%5B%7B%22value%22%3A%22date%22%2C%22invert%22%3A%221%22%2C%22label%22%3A%22%22%7D%2C%7B%22value%22%3A%22custom%22%2C%22custom_field%22%3A%22reading_time%22%2C%22custom_field_numeric%22%3A%221%22%2C%22invert%22%3A%220%22%2C%22label%22%3A%22Shortest%20reads%22%7D%5D"
               us_field_style="1"]
```

**Anti-patterns**

- Target list doesn't have `apply_url_params="1"` — the dropdown changes the URL but the list never re-orders.
- Duplicate entries with `value="price"` but no `invert` distinction — the dropdown shows two visually identical options.
- Pairing with `us_user_list` / `us_term_list` expecting it to drive them — only post-driven lists react.

### `us_list_search` — List Search

**When to use**: a free-text search box that filters a sibling `us_post_list` / `us_product_list` by the standard WordPress `s` URL param — "Search the blog", "Find a product". Live-search (filter as you type) is on by default; the target list must have `apply_url_params="1"`.

**Avoid when**:
- you want a site-wide search box that goes to the WP search results page — use `us_search` (header search element);
- you want faceted filtering by value (category / price / stock) — use `us_list_filter`;
- the target listing is a user / term list — these queries don't consume `s`.

**Wiring**: same as `us_list_filter` — `list_to_search="first"` (default) auto-targets the first list on the page; `list_to_search="selector"` with `list_selector_to_search=".my-list"` lets you target a specific list element.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `list_to_search` | `first` (default) or `selector`. |
| `list_selector_to_search` | CSS class or ID of the target list. Required when `list_to_search="selector"`. |
| `live_search` | `1` (default) filters while the visitor types; `0` requires Enter / submit. |
| `change_url_params` | `1` (default) writes the query into the URL for shareable / bookmarkable state. |
| `text` | Placeholder text. Default "Search". |
| `icon` | Search icon. Default `fas|search`. Format: `<style>|<name>` (`fas`, `far`, `fal`, `fab`). |
| `icon_pos` | `right` (default) or `left`. |
| `icon_size` | Icon size. Default `18px`. |
| `us_field_style` | Field style key from Theme Options → Form Field Styles. |

**Minimal example**

```text
[us_list_search text="Search posts…"]
```

**Common combinations**

Shop toolbar with a search field that filters the products grid in place:

```text
[us_list_search text="Search products"
                icon="fas|search" icon_pos="left"
                live_search="1" change_url_params="1"
                us_field_style="1"]
```

Page with two lists — search drives the second one explicitly:

```text
[us_list_search list_to_search="selector"
                list_selector_to_search=".docs-grid"
                text="Search docs"]
```

**Anti-patterns**

- Confusing this with `us_search` — `us_search` is the global header search; `us_list_search` filters one list on the page and never navigates away.
- Live search across very large lists (thousands of items) without pagination — each keystroke triggers an ajax request; pair with `pagination="numbered_ajax"` and a reasonable `quantity`.
- `change_url_params="0"` on a page where visitors should be able to bookmark the filtered state — the URL stays clean but the share-back behaviour is lost.

### `us_list_result_counter` — List Result Counter

**When to use**: a small "1 – 12 of 47 results" line shown above or next to a `us_post_list` / `us_product_list`. Updates in place when the visitor filters / sorts / searches the list. Typical placement: shop or blog toolbar.

**Avoid when**:
- the listing has no Filter / Order / Search companion and a fixed item count — the counter is redundant and adds noise;
- you want the total to include unfiltered results too — use the `[total_unfiltered]` placeholder in `text` (otherwise only the filtered total is shown).

**Wiring**: same `list_to_count` / `list_selector_to_count` selector as `us_list_search` / `us_list_filter`.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `list_to_count` | `first` (default) or `selector`. |
| `list_selector_to_count` | CSS class or ID of the target list. Required when `list_to_count="selector"`. |
| `text` | Template string. Default `[lower] - [upper] of [total] results`. Placeholders: `[lower]` (first index on the current page), `[upper]` (last index), `[total]` (filtered total), `[total_unfiltered]` (total before filters). |
| `text_single` | Replacement when there is exactly one result. Default "1 result". |
| `text_no_results` | Replacement when there are zero results. Leave blank to hide the element completely (the list itself shows its own `no_items_message`). |

**Minimal example**

```text
[us_list_result_counter]
```

**Common combinations**

Shop toolbar showing filtered vs. catalog total:

```text
[us_list_result_counter text="Showing [lower]–[upper] of [total] ([total_unfiltered] in catalog)"
                        text_single="1 product"
                        text_no_results="No products match these filters."]
```

Compact "of N" badge for a blog grid:

```text
[us_list_result_counter text="[total] articles"
                        text_single="1 article"
                        text_no_results=""]
```

**Anti-patterns**

- Setting `text=""` — the element renders empty markup. Use `text_no_results=""` to hide it only on zero results.
- Using `[total]` and `[total_unfiltered]` interchangeably — `[total]` is the count *after* the active filters; on an unfiltered page they're equal, but they diverge as soon as the visitor narrows the list.
- Placing two counters with `list_to_count="first"` on a multi-list page — both attach to the same list. Use `selector` + class hooks for multi-list layouts.

## Post Elements

> **Section context — where to use these.**
>
> Every shortcode in this section is **designed for Page Templates** — that is, posts of the `us_content_template` type (managed under **WP Admin → Templates → Page Templates**, then assigned to single / archive / shop layouts via **Theme Options → Pages Layout / Archives Layout / Shop Layout**). Reusable Blocks (`us_page_block`) that get included from a Page Template inherit the same context.
>
> Each element looks up its value on the **current post in the loop**:
>
> - on a single post, page or CPT — the post being viewed;
> - on an archive / search / Grid Layout card — the post for the current loop iteration;
> - on a term archive — the term being viewed (the title / content elements adapt to term data).
>
> Using them **outside a Page Template** (e.g. dropped directly into the body of a regular page or post) is **not forbidden** — the shortcode parser will run them — but it is rarely useful: the "current post" then resolves to the page hosting the shortcode itself, so e.g. `[us_post_title]` on a page named "About" just outputs "About", `[us_post_taxonomy]` outputs that page's terms (usually none), and `[us_post_navigation]` walks the page hierarchy instead of a post sequence. Reach for these elements only when you know which post the loop will resolve to and that's exactly the value you want surfaced.
>
> The one element with a hard gate is `us_post_content` — the builder UI only exposes it when editing a `us_content_template` or `us_page_block`. The rest of the section is technically droppable anywhere; the guidance above is editorial, not enforced.

### `us_post_content` — Post Content

**When to use**: outputs the body of the current post in a templated layout — a Page Template (`us_content_template` post type) for single posts / pages / CPTs / archives, a Reusable Block (`us_page_block`) rendered inside one, or a custom archive layout. The element renders the post's excerpt, a trimmed slice, or the full content with optional "Show More" toggle.

**Avoid when**:
- you're authoring a regular page and just want some prose — write directly in a `vc_column_text` or `us_text`; this element re-renders the *parent* post's content and on a normal page that would be the page itself (an infinite loop in some setups, plus a stripped paragraph wrapper);
- you want short, hand-curated text for a hero / CTA — use `us_text`;
- you want to display the *term* description on a taxonomy archive — `us_post_content` also handles that case automatically when the rendering context is a term archive (it falls back to `term_description` from the dummy data shape), but for a hand-built term page you'd be better off using `us_text`.

**Context gate**: the builder UI only exposes this element when editing a `us_content_template` or `us_page_block`. The shortcode tag itself works anywhere, but its output depends on the loop context — outside the canonical template post types, the result is whichever post WordPress thinks is "current" at render time.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `type` | What to render — `excerpt_content` (default — excerpt, fall back to a trimmed slice of the content), `excerpt_only` (excerpt or nothing), `part_content` (force a trimmed slice regardless of excerpt), `full_content`. |
| `excerpt_length` | Word count for excerpt modes. `0` (default) keeps the full excerpt with HTML tags; any positive value strips HTML and trims to N words. |
| `length` | Word count for the trimmed content modes (`excerpt_content` fallback, `part_content`). Default `30`. HTML, line breaks and shortcodes are stripped. |
| `remove_rows` | Only meaningful for `type="full_content"`. `''` (default — keep the post's own row structure), `1` (strip every `vc_row` / `vc_column` *inside* the post content — useful when the content is already inside another layout grid), `parent_row` (strip the `vc_row` *containing* this element — for hero overlays). |
| `force_fullwidth_rows` | `1` stretches preserved rows to full viewport width. Ignored when `remove_rows="1"`. |
| `show_more_toggle` | `1` clips long content and shows a "Show More" link. |
| `show_more_toggle_height` | Visible-content height when clipped. Default `200px`. Px only. |
| `show_more_toggle_text_more` / `show_more_toggle_text_less` | Link labels (defaults "Show More" / "Show Less"). Leave `_less` blank to make the expansion one-way. |
| `show_more_toggle_alignment` | `none` (default), `left`, `center`, `right`. |

**Minimal example**

```text
[us_post_content type="full_content"]
```

**Common combinations**

Excerpt with 25-word cap, used in a card grid Page Template:

```text
[us_post_content type="excerpt_content" excerpt_length="25" length="25"]
```

Hero block above the single-post layout — strip the row this element sits in so the post's own rows can take over the page:

```text
[us_post_content type="full_content" remove_rows="parent_row"]
```

Long single-post body with a 400-px clip and a Show More toggle:

```text
[us_post_content type="full_content"
                 show_more_toggle="1"
                 show_more_toggle_height="400px"
                 show_more_toggle_text_more="Read more"
                 show_more_toggle_text_less="Collapse"]
```

**Anti-patterns**

- Dropping this on a regular page expecting it to render *other* content — it always resolves to the **current** post; use `us_page_block` to embed a different reusable block, or `[us_post_content]` inside a Page Template that's *assigned* to a layout.
- `remove_rows="1"` together with `force_fullwidth_rows="1"` — `force_fullwidth_rows` is automatically hidden when rows are stripped; the attribute is silently ignored.
- `excerpt_length="0"` on `excerpt_content` — fine when you control the excerpt, but on posts without an excerpt the *content* fallback inherits `length`, not `excerpt_length`; set `length` too.
- `show_more_toggle="1"` with `type="excerpt_only"` — there's nothing to expand to; the toggle never shows.

### `us_post_image` — Post Image

**When to use**: renders the **current** post's featured image inside a Page Template (`us_content_template`), Reusable Block (`us_page_block`), or Grid Layout card. Honours theme image sizes, optional placeholder for posts without a thumbnail, optional gallery-on-hover preview, and an overriding link (typically the post permalink or a popup).

**Avoid when**:
- you want a fixed image picked by hand — use `us_image` (takes a media-library ID, not a post context);
- you want a slider of gallery images, not a single thumbnail — use `us_image_slider` or a Grid Layout with `media_preview` baked in;
- the page isn't bound to a single post object — the element resolves to the loop's current post; outside that context it renders nothing (or, with `placeholder="1"`, the empty-state image).

**Key parameters**

| Param | What it does |
|-------|--------------|
| `thumbnail_size` | Image size to request. Default `large`. Any registered size: `thumbnail`, `medium`, `large`, `full`, or theme-specific (`us_350_350_crop`, `us_600_0`, etc.). |
| `placeholder` | `1` renders the theme's placeholder image when the post has no featured image. `0` (default) renders nothing. |
| `media_preview` | `1` shows the post's WP-gallery images on hover (or the video player for video-format posts). |
| `gallery_images_amount` | Max gallery images to preview (2–10, default `10`). Only when `media_preview="1"`. |
| `circle` | `1` clips the image to a circle. |
| `stretch` | `1` (default) stretches the image to the column width. Hidden when an aspect ratio is set on the parent. |
| `disable_lazy_loading` | `1` opts out of lazy loading (use sparingly — hero images at the top of the viewport benefit from this, lists below the fold do not). |
| `link` | Where the image links to. URL-encoded JSON, same shape as other `link` params. Common values: `{"type":"post"}` (default — the post permalink), `{"type":"homepage"}`, `{"type":"popup_image"}` (opens the image in a popup), `{"url":""}` (no link). |

**Minimal example**

```text
[us_post_image thumbnail_size="us_600_0" placeholder="1"]
```

**Common combinations**

Card thumbnail linked to the post, with gallery hover preview:

```text
[us_post_image thumbnail_size="us_350_350_crop"
               link="%7B%22type%22%3A%22post%22%7D"
               media_preview="1" gallery_images_amount="5"
               placeholder="1"]
```

Circular avatar-style image for a "Team member" CPT card:

```text
[us_post_image thumbnail_size="us_200_200_crop" circle="1"
               link="%7B%22type%22%3A%22post%22%7D"]
```

Hero featured image that opens in a lightbox:

```text
[us_post_image thumbnail_size="full" stretch="1"
               link="%7B%22type%22%3A%22popup_image%22%7D"
               disable_lazy_loading="1"]
```

**Anti-patterns**

- Using this on a page that isn't bound to a single post or a loop iteration — the element silently renders nothing (without `placeholder="1"`) and the column looks broken.
- `media_preview="1"` plus `link={"type":"popup_image"}` — the popup steals the hover; only one of the two interactions can win. Use one or the other.
- `circle="1"` plus `stretch="1"` on a wide column — the circle becomes an ellipse; pair with a forced 1×1 aspect ratio on the parent column (or use a Grid Layout that handles it).
- `disable_lazy_loading="1"` on every card of a long list — defeats the point and tanks LCP.

### `us_post_title` — Post Title

**When to use**: outputs the **current** post / page / CPT / term's title inside a Page Template, Reusable Block, archive layout, or Grid Layout card. Picks the HTML tag, alignment, link target, and an optional shortened length for tight grids.

**Avoid when**:
- you want a fixed, hand-written heading — use `us_text` (its `tag` param plays the same role and the value is whatever you type, not the post title);
- the page isn't bound to a post object — there is no title to resolve.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `tag` | HTML tag — `h1`, `h2` (default), `h3`, `h4`, `h5`, `h6`, `div`, `p`, `span`. Use `h1` exactly once per page (typically the single-post hero); cards under a parent heading should use `h3` / `h4`. |
| `align` | `none` (default — inherit), `left`, `center`, `right`. |
| `link` | Where the title links to. URL-encoded JSON. Common values: `{"type":"post"}` (default — post permalink), `{"type":"homepage"}`, `{"type":"elm_value"}` (when the post's title looks like an email / phone / URL — turns it into a `mailto:` / `tel:` / external link), `{"url":""}` (no link). |
| `color_link` | `1` (default) keeps the link colour equal to the text colour; `0` uses the theme's link colour. |
| `shorten_length` | `1` clips the title at `shorten_length_count` characters and appends "…". |
| `shorten_length_count` | Character cap when `shorten_length="1"`. 1–60, default `30`. |
| `show_count` | `1` appends the term's post count after the title. Only meaningful when the title is a term name (i.e. when this element is inside a Grid Layout for a `us_term_list` / `us_term_carousel`). |

**Minimal example**

```text
[us_post_title tag="h2" link="%7B%22type%22%3A%22post%22%7D"]
```

**Common combinations**

Single-post hero, h1, no link (it's the destination):

```text
[us_post_title tag="h1" align="center" link="%7B%22url%22%3A%22%22%7D"]
```

Card title in a 4-up blog grid — h4, linked, clipped to 40 chars:

```text
[us_post_title tag="h4" link="%7B%22type%22%3A%22post%22%7D"
               shorten_length="1" shorten_length_count="40"]
```

Term card with the post count badge:

```text
[us_post_title tag="h3" show_count="1"
               link="%7B%22type%22%3A%22post%22%7D"]
```

**Anti-patterns**

- Using `tag="h1"` in a Page Template that's assigned to **archive** layouts — every card in the archive gets an `h1`, killing the page outline.
- `shorten_length_count="10"` on a long-title blog — visitors see "Five things ab…" and can't tell posts apart. Pair with a generous Grid Layout image so the card has secondary cues.
- `show_count="1"` on a single-post Page Template — there's no term context, the count never renders.
- `link={"type":"elm_value"}` on a normal post — it only kicks in for titles that *parse* as email / phone / URL (typically used for directory CPTs).

### `us_post_custom_field` — Post Custom Field

**When to use**: renders the value of an arbitrary custom field (post meta) for the **current** post — ACF fields, theme-provided "Additional Settings" (`us_tile_icon`, `us_tile_additional_image`), Testimonial sub-fields, or any raw `wp_postmeta` key. Typical placement: Page Template / Grid Layout card / Reusable Block, surfacing per-post values that aren't covered by Title / Date / Taxonomy / Author.

**Avoid when**:
- the value is the post date / title / image / taxonomy / author — use the dedicated `us_post_date` / `us_post_title` / `us_post_image` / `us_post_taxonomy` / `us_post_author` (they handle formatting, links and i18n properly);
- you want a price / stock / rating from WooCommerce — those have their own elements (out of scope here);
- the field is an ACF type the element can't render (`clone`, `file`, `gallery`, `google_map`, `group`, `link`, `message`, `post_object`, `relationship`, `tab`, `taxonomy`, `true_false`, `user`) — those are explicitly filtered out of the selector.

**Key parameters**

**Source**

| Param | What it does |
|-------|--------------|
| `key` | Field id. Built-in: `us_tile_additional_image`, `us_tile_icon` (Additional Settings); `us_testimonial_author`, `us_testimonial_role`, `us_testimonial_company`, `us_testimonial_rating` (Testimonial fields, when the Testimonial CPT is enabled). ACF fields appear as their field name. `custom` falls back to a raw meta key entered in `custom_key`. |
| `custom_key` | The `wp_postmeta` key when `key="custom"`. |
| `hide_empty` | `1` removes the element entirely when the field has no value. |

**Image / repeater handling** (only when `key` points at an image or ACF repeater field)

| Param | What it does |
|-------|--------------|
| `display_type` | `1` renders an ACF repeater as a table. |
| `has_ratio` / `ratio` / `ratio_width` / `ratio_height` | Force the image aspect ratio. `ratio` enum: `1x1`, `4x3`, `3x2`, `16x9`, `2x3`, `3x4`, `custom`. |
| `stretch` | `1` stretches the image to the column width when no ratio is set. |
| `disable_lazy_loading` | `1` opts out of lazy loading. |
| `thumbnail_size` | Image size — `thumbnail`, `medium`, `large` (default), `full`, or any theme-registered size. |

**Checkbox handling** (only when `key` points at an ACF checkbox)

| Param | What it does |
|-------|--------------|
| `list_display_options` | `comma_separated` (default), `unordered_list`, `ordered_list`, `separate_divs`. |

**Linking**

| Param | What it does |
|-------|--------------|
| `link` | Wrap the value in a link. URL-encoded JSON. Useful values: `{"type":"elm_value"}` (auto-detect email/phone/URL in the value), `{"type":"popup_image"}` (image fields), `{"type":"custom_field|<another_key>"}` (use another field as the URL), `{"url":""}` (no link). |
| `hide_with_empty_link` | `1` hides the element when the linked custom field is empty. Only meaningful when `link` references a custom field. |
| `color_link` | `1` (default) inherits the surrounding text colour for the link. |

**Appearance**

| Param | What it does |
|-------|--------------|
| `tag` | HTML tag for the value wrapper — `div` (default), `span`, `p`, `h2`–`h6`. Ignored for non-comma-separated checkboxes. |
| `icon` | FontAwesome icon prepended to the value. Format `<style>|<name>` (e.g. `fas|envelope`). |
| `text_before` / `text_before_tag` | Static prefix text (e.g. "Price: ") and its HTML tag. `_tag` only renders when the outer `tag` is `div`. |
| `text_after` / `text_after_tag` | Static suffix text (e.g. " min") and its HTML tag. |

**Minimal example**

```text
[us_post_custom_field key="custom" custom_key="duration"
                      text_before="" text_after=" min"]
```

**Common combinations**

ACF price field formatted as currency, hidden when empty:

```text
[us_post_custom_field key="price" hide_empty="1"
                      text_before="$" tag="span"
                      icon="fas|tag"]
```

Star-rating from the Testimonial CPT (no link, no extra text):

```text
[us_post_custom_field key="us_testimonial_rating"]
```

Image field with forced 16:9 ratio and lightbox link:

```text
[us_post_custom_field key="featured_attachment" has_ratio="1" ratio="16x9"
                      thumbnail_size="large"
                      link="%7B%22type%22%3A%22popup_image%22%7D"]
```

ACF email field, click-to-mail:

```text
[us_post_custom_field key="contact_email" tag="span"
                      icon="fas|envelope"
                      link="%7B%22type%22%3A%22elm_value%22%7D"
                      hide_empty="1"]
```

**Anti-patterns**

- Using `key="custom"` with a `custom_key` that points at one of the gated ACF types (`group`, `gallery`, `post_object`, …) — the element renders nothing or a serialized PHP value. Pick a different field, or use the dedicated element for that data shape.
- `hide_empty="1"` on `us_testimonial_rating` — explicitly gated off (a `0` rating is still a value); use Display Logic instead.
- Image-field params (`has_ratio`, `thumbnail_size`) on a text custom field — silently ignored.
- `link={"type":"elm_value"}` on a numeric / freeform field — the auto-detect runs once on each value; if the value isn't a parseable email / phone / URL, no link is emitted.

### `us_post_date` — Post Date

**When to use**: outputs the **current** post's publish or modified date (or any ACF date / date-time / time-picker field) in a Page Template / Grid Layout card / Reusable Block. Supports human-readable formatting ("Today at 11:04", "3 months ago"), classic WP date formats, or a fully custom format string.

**Avoid when**:
- you want a hand-picked, fixed date — write text in `us_text` instead;
- the date is an event start / end date and the site uses The Events Calendar — use `us_event_date` (its format and TEC integration are wired in);
- you want a per-post custom date with no plugin support — use `us_post_custom_field` with the appropriate `key` (and the value will be rendered as a plain string).

**Key parameters**

| Param | What it does |
|-------|--------------|
| `type` | Which date to show — `published` (default — date of creation), `modified` (date of last update). When ACF is active, every ACF date-picker / date-time-picker / time-picker field is also listed here by its field name. |
| `format` | Output format — `smart` ("Today at 11:04", "Yesterday at 08:55"), `time_diff` (default — "5 hours ago", "3 months ago"), `default` (the site's WP "Date Format" setting), or one of the presets `jS F Y`, `j M, G:i`, `m/d/Y`, `j.m.y`. `custom` enables `format_custom`. |
| `format_custom` | PHP `date()`-style format string when `format="custom"`. Default `F j, Y`. WordPress's [date and time formatting docs](https://wordpress.org/support/article/formatting-date-and-time/) apply. |
| `icon` | Optional FontAwesome icon prepended to the date. Format `<style>|<name>` (e.g. `far|calendar`). |
| `text_before` / `text_after` | Static prefix / suffix text (e.g. "Posted on " / " UTC"). Both honour dynamic-value tokens. |

**Minimal example**

```text
[us_post_date format="time_diff"]
```

**Common combinations**

Blog card metadata — "Posted 3 days ago" with a calendar icon:

```text
[us_post_date type="published" format="time_diff"
              icon="far|calendar" text_before="Posted "]
```

Single-post header with a localised long-form date:

```text
[us_post_date type="published" format="default"
              text_before="Published on "]
```

"Last updated" line under a doc article:

```text
[us_post_date type="modified" format="jS F Y"
              text_before="Last updated: "]
```

ACF date field rendered with a custom format:

```text
[us_post_date type="event_start_date"
              format="custom" format_custom="l, F jS"
              icon="far|calendar-check"]
```

**Anti-patterns**

- `format="time_diff"` on long-archived posts — "7 years ago" reads as unmaintained content; prefer `default` or a year-aware preset on evergreen pages.
- `type="modified"` on every card — visitors see "Updated 5 minutes ago" after every minor edit; use `published` for blog-card meta unless freshness is the point.
- `format="custom"` with a format string that includes timezone characters (`e`, `T`) — WordPress already calls `date_i18n`, the timezone is baked in; redundant characters render literally.

### `us_post_taxonomy` — Post Taxonomy

**When to use**: outputs the **current** post's terms in one taxonomy — "Categories: Design, Marketing", "Tags: #foo #bar", product categories on a shop card, custom-taxonomy chips on a CPT card. Renders as comma-separated text or as a row of button-styled badges, with optional colour swatches from term meta.

**Avoid when**:
- you want a list of *all* terms in a taxonomy, not the ones attached to the current post — use `us_term_list` / `us_term_carousel`;
- you want a hierarchical sidebar of categories — use `us_category_nav`;
- the page isn't bound to a single post object — there's nothing to look up.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `taxonomy_name` | Taxonomy slug. Default `category`. Common values: `post_tag`, `product_cat`, `product_tag`, `us_portfolio_category`, custom taxonomy slugs. |
| `style` | `simple` (default — text values with a separator) or `badge` (each term becomes a button-styled pill). |
| `btn_style` | Pill style when `style="badge"` — `badge` (default — theme's badge style), or a numeric key from Theme Options → Buttons (`"1"`, `"2"`, …). |
| `separator` | Text inserted between values when `style="simple"`. Default `, `. Common alternatives: ` • `, ` / `, ` &middot; `. |
| `link` | Where each term links to. URL-encoded JSON. Default `{"type":"archive"}` (the term-archive page). Set to `{"url":""}` to render the values without links. |
| `color_link` | `1` (default) inherits the surrounding text colour for the links. |
| `icon` | Optional FontAwesome icon prepended to the *first* value. Format `<style>|<name>`. |
| `text_before` / `text_after` | Static prefix / suffix (e.g. "Filed under: " / "."). |
| `show_color_swatch` | `1` shows a colour swatch next to each term, sourced from the term's "Color Swatch" meta (set in the term edit screen). |
| `hide_color_swatch_label` | `1` hides the term name when `show_color_swatch="1"` — useful for product-attribute swatches. |
| `apply_swatch_colors` | `1` uses the swatch colours as the badge background (only meaningful with `style="badge"`). |

**Minimal example**

```text
[us_post_taxonomy taxonomy_name="category"]
```

**Common combinations**

Blog card meta — categories as comma-separated text with a folder icon:

```text
[us_post_taxonomy taxonomy_name="category"
                  style="simple" separator=", "
                  icon="fas|folder" text_before="In "]
```

Tag chips under an article, button style 2:

```text
[us_post_taxonomy taxonomy_name="post_tag"
                  style="badge" btn_style="2"
                  text_before="Tags: "]
```

Product colour swatches with no labels (visual-only attribute strip):

```text
[us_post_taxonomy taxonomy_name="pa_color"
                  style="badge" btn_style="badge"
                  show_color_swatch="1"
                  hide_color_swatch_label="1"
                  apply_swatch_colors="1"
                  link="%7B%22url%22%3A%22%22%7D"]
```

**Anti-patterns**

- `taxonomy_name="category"` on a post type that doesn't use the default `category` taxonomy (e.g. `product`, `us_portfolio`) — the element renders empty silently. Pass the correct slug.
- `style="simple"` with `show_color_swatch="1"` — swatches require the pill markup; switch to `style="badge"`.
- `apply_swatch_colors="1"` on terms without a colour in their meta — pills fall back to the default badge colour; no error, just no effect.
- Heavy `btn_style="3"` (or any themed-button style) on a long tag list — pills become unreadable. Keep filter / meta rows on simple styles.

### `us_post_author` — Post Author

**When to use**: outputs the **current** post's author — display name, optional avatar, optional posts count / website link / biographical info, optional icon. Typical placement: under a blog-post title ("by Jane Doe"), in an author-card row at the bottom of a single-post layout, or in a Grid Layout card's meta row.

**Avoid when**:
- you want a list / grid of users — use `us_user_list` / `us_user_carousel`;
- you want hand-curated team bios that aren't tied to WP users — use `us_person`;
- the page has no post in context — the element resolves to whoever the current loop says is "the author" (usually empty on standalone pages).

**Key parameters**

| Param | What it does |
|-------|--------------|
| `link` | Where the author name links to. URL-encoded JSON, supports dynamic values. Default `{"type":"author_page"}` (the WP author archive). Set `{"url":""}` for no link. |
| `color_link` | `1` (default) inherits the surrounding text colour for the link. |
| `avatar` | `1` shows the author's Gravatar / profile picture. |
| `avatar_width` | Avatar size. Default `96px`. Px only. |
| `avatar_pos` | `top` (default — avatar above the name) or `left` (avatar beside the name). |
| `posts_count` | `1` shows "N posts" next to the name. |
| `website` | `1` shows the URL the author entered in their profile's "Website" field. |
| `info` | `1` shows the author's "Biographical Info". |
| `icon` | Optional FontAwesome icon prepended to the name. Format `<style>|<name>` (e.g. `fas|user`). |

**Minimal example**

```text
[us_post_author]
```

**Common combinations**

Blog card meta — "by Jane Doe", with a small user icon:

```text
[us_post_author icon="fas|user"
                avatar="0" link="%7B%22type%22%3A%22author_page%22%7D"]
```

Bottom-of-post author card — large avatar on the left, bio underneath:

```text
[us_post_author avatar="1" avatar_width="120px" avatar_pos="left"
                info="1" website="1" posts_count="1"]
```

Single-post hero byline — name only, no link, no avatar:

```text
[us_post_author link="%7B%22url%22%3A%22%22%7D"]
```

**Anti-patterns**

- `avatar="1"` on a 12-card grid — every cell loads a Gravatar request; pair with a tight avatar size and consider hiding on mobile via Display Logic.
- `info="1"` in a Grid Layout card — bios are paragraphs of text, cards become uneven. Reserve `info`/`website` for the post page itself.
- `avatar_width` in non-px units — only px are accepted; other units render at default.
- `link="%7B%22type%22%3A%22author_page%22%7D"` on a single-author site — every link goes to the same archive; consider `{"url":""}` instead.

### `us_post_comments` — Post Comments

**When to use**: either the *amount* of comments (a small "5 comments" badge for a card meta row), or the *full comments template* — list of existing comments plus the reply form — rendered through the theme's `comments.php`. Typical placement: blog-card meta strip (`layout="amount"`), single-post body (`layout="comments_template"`).

**Avoid when**:
- you want a generic discussion widget unrelated to WP comments — out of scope;
- you want comments on a page that isn't bound to a post — there's no thread to render.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `layout` | `comments_template` (default — list + reply form via the theme template) or `amount` (just the count). |
| `hide_zero` | `1` hides the element when the post has no comments. Only meaningful when `layout="amount"`. |
| `number` | `1` shows just the number (`12`) instead of the full string (`12 Comments`). `layout="amount"` only. |
| `link` | Where the count links to. URL-encoded JSON. Default `{"type":"post_comments"}` (jumps to the comments anchor on the post page). Other useful values: `{"type":"post"}`, `{"url":""}` (no link). `layout="amount"` only. |
| `color_link` | `1` (default) inherits the surrounding text colour. |
| `icon` | FontAwesome icon prepended to the count. Format `<style>|<name>` (e.g. `far|comment`). `layout="amount"` only. |

**Minimal example**

```text
[us_post_comments layout="amount" icon="far|comment"]
```

**Common combinations**

Blog card meta — comment count linked to the post's comments section, hidden when zero:

```text
[us_post_comments layout="amount" number="0"
                  link="%7B%22type%22%3A%22post_comments%22%7D"
                  icon="far|comment"
                  hide_zero="1"]
```

Single-post body — full comments template at the bottom:

```text
[us_post_comments layout="comments_template"]
```

Compact numeric badge above the title:

```text
[us_post_comments layout="amount" number="1"
                  icon="fas|comments"]
```

**Anti-patterns**

- `layout="comments_template"` on an archive Page Template — every card renders its own comments list (and the duplicate `<form id="commentform">` IDs break the page). Use `layout="amount"` on archives, `layout="comments_template"` only on the single-post template.
- `hide_zero="1"` plus `number="1"` — visitors see nothing, no context. Either keep a label ("0 comments" is a valid CTA to be the first), or drop the element entirely on no-comments posts via Display Logic.
- Pairing `layout="comments_template"` with `link` / `icon` / `number` — those params are only read in `amount` mode; harmless but noisy.

### `us_post_navigation` — Post Prev/Next Navigation

**When to use**: a pair of "← Previous Post" / "Next Post →" links rendered under a single-post Page Template, optionally constrained to the same taxonomy term. Two layouts: inline simple links, or fixed-position arrows pinned to the left and right edges of the viewport.

**Avoid when**:
- you want a full numeric pagination of an archive — that's `pagination` on `us_post_list` (`numbered` / `numbered_ajax`), not this element;
- the page is an archive / search / standalone — there is no surrounding post sequence to step through;
- the post belongs to a non-chronological CPT (a sortable directory, a manual-order portfolio) — "prev/next" by date order won't match visitor expectations.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `layout` | `simple` (default — two links rendered inline where the element sits) or `sided` (links float to the left and right edges of the viewport, persisting as the visitor scrolls). |
| `invert` | `1` swaps the prev/next positions (next on the left, prev on the right). Useful in RTL languages or specific design preferences. |
| `in_same_term` | `1` restricts navigation to the same taxonomy term — useful for series, course chapters, category-locked browsing. |
| `taxonomy` | Taxonomy slug used when `in_same_term="1"`. Default `category`. |
| `prev_post_text` | Subtitle above the previous-post title. Default "Previous Post". `layout="simple"` only. |
| `next_post_text` | Subtitle above the next-post title. Default "Next Post". `layout="simple"` only. |

**Minimal example**

```text
[us_post_navigation]
```

**Common combinations**

End-of-post inline navigation, same-category browsing:

```text
[us_post_navigation layout="simple"
                    in_same_term="1" taxonomy="category"
                    prev_post_text="Previous article"
                    next_post_text="Next article"]
```

Floating side arrows for a long-form blog (always visible while scrolling):

```text
[us_post_navigation layout="sided"]
```

Course-chapter navigation locked to a custom "course" taxonomy:

```text
[us_post_navigation layout="simple"
                    in_same_term="1" taxonomy="course"
                    prev_post_text="Previous chapter"
                    next_post_text="Next chapter"]
```

**Anti-patterns**

- Using `layout="sided"` on a narrow viewport without responsive overrides — the arrows can overlap card content. Pair with Display Logic to hide on mobile.
- `in_same_term="1"` with a taxonomy that's not assigned to many posts — first / last items in the term get a one-sided strip (prev only, next missing), which can look broken.
- Placing this on a `us_content_template` assigned to *archive* layouts — it resolves against each card's neighbours, which is rarely what authors want. Reserve for the *single* layout.

### `us_post_views` — Post Views

**When to use**: shows the **current** post's view count — a "1.2K views" badge in a card meta row, an "Read by N people" line on a single post. Requires a post-views counter integration on the site (the bundled Post Views Counter plugin support, or any plugin that writes the standard `views` post meta the theme reads).

**Avoid when**:
- the site doesn't track post views — the element renders `0` for every post, which is misleading;
- you want a UTM-style site-wide stat — out of scope; this is one number per post.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `result_thousand_short` | `1` formats large counts with a "K" suffix (`1.2K` instead of `1,234`). Useful for tight card meta rows. |
| `result_thousand_separator` | Character between thousand groups when `result_thousand_short="0"`. Default `,` (renders `12,345`). Set to ` ` for `12 345`, or `.` for European formats. |
| `icon` | FontAwesome icon prepended to the count. Format `<style>|<name>` (e.g. `fas|eye`). |
| `text_before` / `text_after` | Static prefix / suffix (e.g. "Read by " / " people"). Both honour dynamic-value tokens. |

**Minimal example**

```text
[us_post_views icon="fas|eye" text_after=" views"]
```

**Common combinations**

Card meta — eye icon + short thousand format:

```text
[us_post_views icon="far|eye"
               result_thousand_short="1"
               text_after=" views"]
```

Single-post body line:

```text
[us_post_views text_before="Read by "
               result_thousand_separator=","
               text_after=" people"]
```

**Anti-patterns**

- Using this on a site without a view-counter plugin or theme integration — the value is `0` for every post, which advertises low traffic. Either install a counter plugin or hide this element via Display Logic.
- `result_thousand_short="1"` plus `result_thousand_separator=","` — the separator is ignored once values short-form to `K`; keep one or the other in mind for clarity.

### `us_breadcrumbs` — Breadcrumbs

**When to use**: a "Home › Section › Subsection › *current page*" trail at the top of any post / page / archive. Auto-computed from the page hierarchy and the current taxonomy / post-type relationship — you don't list the items by hand. Typical placement: just under the site header, inside a slim row with a small bottom margin.

**Avoid when**:
- the site is a single landing page — there's no hierarchy worth showing;
- you want a hand-crafted nav with custom items — write the markup directly in `us_text` or use `vc_widget_sidebar` with a custom-menu widget.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `home` | Label of the first item, the homepage link. Default "Home". Set to **blank** to hide the homepage link entirely (the trail will start from the next level). Supports dynamic-value tokens (e.g. for translations). |
| `show_current` | `1` appends the current page's title as the last (non-link) crumb. `0` (default) stops one level earlier. |
| `align` | `none` (default — inherit), `left`, `center`, `right`. |
| `separator_type` | `icon` (default) or `custom` (a typed symbol). |
| `separator_icon` | Icon between crumbs when `separator_type="icon"`. Default `far|angle-right`. Format `<style>|<name>`. |
| `separator_symbol` | Text between crumbs when `separator_type="custom"`. Default `/`. Common alternatives: ` › `, ` » `, ` &middot; `, ` | `. |

**Minimal example**

```text
[us_breadcrumbs]
```

**Common combinations**

Compact left-aligned trail with `›` separators and the current page shown:

```text
[us_breadcrumbs home="Home"
                show_current="1"
                align="left"
                separator_type="custom"
                separator_symbol=" › "]
```

Shop archive header — home label blanked because the page title already says "Shop":

```text
[us_breadcrumbs home=""
                show_current="0"
                separator_type="icon"
                separator_icon="fas|chevron-right"]
```

**Anti-patterns**

- Setting `home=" "` (a single space) expecting to hide the homepage link — only an **empty** value hides it; a space renders as a clickable space character.
- `show_current="1"` on a page where the title is already in the H1 directly above — the page title appears twice, two characters apart, looking like a bug.
- Custom `separator_symbol=" - "` with literal spaces — the surrounding values lean too close; use ` - ` with non-breaking spaces or switch to `separator_type="icon"`.

### `us_add_to_favs` — "Add to Favorites" Button

**When to use**: a per-post "Add to Favorites" / "In Favorites" toggle that stores the post in the visitor's favourites list (in `localStorage` for guests, in user meta when logged in — controlled by the `us_allow_guest_favs` PHP filter at the site level). Typical placement: blog / shop / portfolio card meta row, single-post hero, or a dedicated "Save" button under the title. Pair with `us_post_list` / `us_product_list` using `source="user_favorite_ids"` to render the saved list on a "My favorites" page.

**Avoid when**:
- the site has no concept of personal collections (a single-page brochure, a campaign LP) — the button has no destination;
- you want a Like / Vote / Reaction count — out of scope; this is a personal-saves toggle, not a public counter;
- the page isn't bound to a post object — the button has no target to favourite.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `style` | Button style. `0` (default) — the theme's default button style; or a numeric key from Theme Options → Buttons (`"1"`, `"2"`, …). |
| `show_icon` | `1` (default) shows the heart icon next to the label. `0` for label-only. |
| `label_before_adding` | Label when the post is *not yet* in favourites. Default "Add to Favorites". |
| `label_after_adding` | Label when the post *is* in favourites. Default "In Favorites". |
| `message_after_adding` | Optional toast message shown after a successful add. Supports `<a>`, `<strong>`, `<br>`. Dynamic-value tokens allowed. Leave blank to skip the toast. |
| `message_for_non_registered` | Toast for guest visitors when `us_allow_guest_favs` is filtered to `false` site-wide. Default "Please log in to add items to your favorites." Only present in the schema when guest favourites are disabled. |

**Minimal example**

```text
[us_add_to_favs]
```

**Common combinations**

Card meta — compact icon-only "save" toggle:

```text
[us_add_to_favs style="0"
                show_icon="1"
                label_before_adding=""
                label_after_adding=""]
```

Hero CTA next to the post title:

```text
[us_add_to_favs style="2"
                show_icon="1"
                label_before_adding="Save for later"
                label_after_adding="Saved"
                message_after_adding="Added to your favorites. <a href='/my-favorites/'>View list</a>"]
```

Guest-disabled site — pushes visitors to log in:

```text
[us_add_to_favs label_before_adding="Save"
                message_for_non_registered="Please <a href='/login/'>log in</a> to save items."]
```

**Anti-patterns**

- Empty label *and* `show_icon="0"` — the button renders as a 0×0 blank; visitors can't see it.
- `message_after_adding` with full HTML (`<div>`, `<p>`, `<strong style="…">`) — only `<a>`, `<strong>`, `<br>` survive sanitisation. Use inline text + one anchor.
- Adding this on a page that isn't bound to a single post — search results, the blog index, a hand-built "About" page — there's no meaningful "current post" to save; visitors end up favouriting whatever object WordPress happens to set up at render time (typically the host page itself), which is rarely the intent. The canonical placement is inside a Page Template (`us_content_template`) wired to single-post / single-product / single-CPT layouts, or a Grid Layout card where each iteration has a real post in the loop.
- Expecting the favourites list to persist across browsers for *guests* — it lives in `localStorage`. Only logged-in users get cross-device persistence.

### `us_event_date` — Event Date and Time

**When to use**: outputs an event's date / time (start, end, or the formatted "start–end" range) for a post from **The Events Calendar** (`tribe_events` CPT). Typical placement: an event card in a `us_post_list` filtered to `post_type="tribe_events"`, or the single-event Page Template.

**Avoid when**:
- the site doesn't have The Events Calendar active — the element is gated by `class_exists('Tribe__Events__Query')` and won't appear in the builder UI;
- you want a regular post's publish / modified date — use `us_post_date`;
- you want a custom date field unrelated to TEC — use `us_post_custom_field` with the appropriate `key`.

**Key parameters**

| Param | What it does |
|-------|--------------|
| `type` | What to show — `default` (the TEC-formatted "Start – End" string, honouring all-day / multi-day rules), `start` (start date only), `end` (end date only). |
| `format` | PHP `date()`-style format for `start` / `end` (hidden when `type="default"` — TEC owns the format there). Empty (default) → TEC's date format setting. Examples: `F j, Y`, `D, j M G:i`, `Y-m-d`. |
| `icon` | FontAwesome icon prepended to the date. Format `<style>|<name>` (e.g. `far|calendar`). |
| `text_before` / `text_after` | Static prefix / suffix (e.g. "Starts on " / " UTC"). Dynamic-value tokens allowed. |

**Minimal example**

```text
[us_event_date]
```

**Common combinations**

Event card meta — calendar icon + the TEC default range:

```text
[us_event_date type="default" icon="far|calendar"]
```

"Doors open at …" line on a single event page:

```text
[us_event_date type="start" format="l, F jS \a\t g:i a"
               icon="far|clock"
               text_before="Doors open: "]
```

"Until …" badge on a multi-day event card:

```text
[us_event_date type="end" format="j M Y"
               text_before="Through "]
```

**Anti-patterns**

- Using this on a regular post / page — the TEC lookup returns nothing; the element renders empty. Pair with Display Logic gated on `post_type=tribe_events` or use it only inside the Events single template.
- Setting `format` when `type="default"` — silently ignored (TEC controls the range format). Switch to `start` or `end` to take over the format.
- Custom `format` with timezone characters that TEC also strips — verify in the live preview; some characters look right in the schema but TEC sanitises the output.

