# Shortcode Builder

> **This feature is available in GravityOps Search Premium.**

## Overview

The Shortcode Builder is a visual, point-and-click tool built directly into the GravityOps Search admin page. It lets you construct `[gravops_search]` shortcodes interactively without writing any shortcode syntax by hand. Every attribute, search filter, display option, and output template is wired to a live UI control, and the shortcode preview updates in real time as you configure it.

Navigate to **GravityOps → GravityOps Search → Shortcode Builder** to open it.

---

## Building a shortcode

### 1. Target forms

Choose which Gravity Forms to search:

- **All forms** — check "All forms" to query every form on the site (`target="0"`).
- **Specific forms** — leave the checkbox unchecked and tick one or more forms from the list. The first selected form is the *primary form* and drives the field-aware UI (field dropdowns, sort options, entry meta display, etc.). You can reorder the selection or mark a different form as primary using the "Make primary" button on each chip.

### 2. Attributes

The **Attributes** card covers the core shortcode settings:

| Setting                       | Shortcode attribute                              |
|-------------------------------|--------------------------------------------------|
| Match mode (ALL / ANY)        | `search_mode`                                    |
| Search empty values           | `search_empty`                                   |
| Sort by / direction / numeric | `sort_key`, `sort_direction`, `sort_is_num`      |
| Secondary sort                | `secondary_sort_key`, `secondary_sort_direction` |
| Limit                         | `limit`                                          |
| Unique results only           | `unique`                                         |
| Result separator              | `separator`                                      |
| Default value(s)              | `default`                                        |
| Wrap in admin entry link      | `link`                                           |

### 3. Search filters

Three buttons let you add different kinds of filter rows:

- **+ Add filter** — filter by a specific field ID or entry property chosen from a dropdown.
- **+ By label** — filter by field label. The builder emits `search_label` and resolves to the actual field ID(s) at runtime, so the shortcode works across multiple forms even when field IDs differ.
- **+ By type** — filter by field type (e.g., `email`, `text`, `select`). The builder emits `search_type`.

Each row has:

- **Mode selector** (`By ID` / `By Label` / `By Type`) — set when the row was added; can be changed at any time. Switching mode resets the field/label/type value.
- **Field / label / type input** — for By ID rows, a dropdown populated from the primary form's fields, entry properties, and detected entry meta (including Gravity Flow workflow keys). For By Label or By Type rows, a free-text input.
- **Operator** — available operators adjust to the field type for By ID rows (numeric fields get `gt`, `lt`, etc.; boolean fields get `=` and `!=` only). By Label and By Type rows show the full operator list.
- **Value** — plain text, a number, a date picker, or a comma-separated list for `in` / `not in` operators.

Rows can be reordered by dragging the numbered handle on the left. Click **Remove** to delete a row.

#### Field match (label and type rows)

When at least one By Label or By Type row is present, a **Field match** setting appears:

| Value             | Behaviour                                                                           |
|-------------------|-------------------------------------------------------------------------------------|
| `first` (default) | Resolves to the **first** field in each target form with the matching label or type |
| `all`             | Resolves to **every** field in each target form with the matching label or type     |

This emits `field_match="all"` in the shortcode when set to "All matches"; the attribute is omitted when using the default `first`.

#### Operator and content ordering

When shortcodes mix search types, content pipe positions and operator positions follow this order: By ID rows first, then By Label rows, then By Type rows. The builder handles this automatically — the live shortcode preview always reflects the correct ordering.

#### Validation hints

The validator warns when:
- A By Label or By Type row has no label/type set.
- Label or type filters span multiple forms without `search_mode="any"` — different field IDs resolve per form, so ANY mode is usually correct in this case.

### 4. Display

Switch between the two output modes using the tabs under the **Display** card:

**Simple field list** — tick one or more fields, entry properties, entry meta keys, or special values (`meta`, `num_results`). Each entry outputs those values in order. Use "Discover available meta keys for this form" to run a quick introspection query that lists every key present in the most recent entry.

The field list groups items under:
- **Entry properties** — standard GF entry fields (ID, date created, payment status, etc.)
- **Fields — [Form title]** — all fields on the primary form, including sub-inputs for Name and Address fields.
- **Entry Meta — [Form title]** — extra meta keys detected in the form's most recent entry (e.g., Gravity Flow workflow step meta, custom plugin meta). This section only appears when at least one entry exists.
- **Special** — `meta` (dump all available keys) and `num_results` (count of matched entries).

**Template builder** — stack blocks to assemble a per-entry output template:

| Block type        | What it does                                                                     |
|-------------------|----------------------------------------------------------------------------------|
| Text              | Literal text inserted verbatim                                                   |
| Field placeholder | Inserts a field, property, or meta value: `{13}`, `{gos:workflow_step_id}`, etc. |
| HTML wrapper      | Wraps child blocks in an HTML element with optional attrs/classes                |
| Nested shortcode  | Emits a `{{shortcode}}` that the plugin resolves after placeholder substitution  |
| Special           | `{num_results}` or `{gos:num_results}`                                           |

Blocks can be nested inside HTML wrappers and reordered by dragging. The field placeholder picker includes the same **Entry Meta** group as the simple field list, giving you access to Gravity Flow and other plugin meta in templates.

---

## Sidebar tools

### Live shortcode preview

Displays the current shortcode. Click **Display Shortcode** to refresh, or **Copy Shortcode** to copy it to the clipboard with one click.

### Validation

Runs automatically and flags common issues:

- **Error** (red) — the shortcode will not work correctly as configured (e.g., no form selected, pipe character in a value, bare `gos:id` used with a text key, By Label/Type row with no value set).
- **Warning** (yellow) — likely unintended configuration (e.g., `in` operator with no values, label/type filters spanning multiple forms without `search_mode="any"`).
- **Info** (blue) — informational notes (e.g., multi-form mode, `limit="all"` performance reminder, default/display count mismatch).

### Test run

Click **▶ Run shortcode** to render the current shortcode on the server and preview the output in the panel. This is a live query — it reflects the actual entries in your database.

### Save shortcode

Enter a name and click **Save** to persist the current shortcode and its builder state to the **Saved Shortcodes** tab. Saved shortcodes are stored site-wide and visible to all users with the appropriate capability.

### Presets

Presets are personal (per-user) saves of the full builder state. They are useful for storing partially-built configurations or frequently reused setups that you want to come back to without saving a final shortcode. Presets are separate from Saved Shortcodes.

**Starter templates** give you a pre-configured state as a starting point for common patterns.

---

## Saved Shortcodes tab

Navigate to **GravityOps → GravityOps Search → Saved Shortcodes** to manage all shortcodes saved from the builder.

Each card shows:

- **Name** and the date it was saved.
- **Shortcode** — click anywhere on the code block to copy it to the clipboard. The block flashes green on a successful copy.
- **Edit in Builder** — loads the saved state back into the Shortcode Builder tab so you can modify it and re-save.
- **Delete** — removes the entry after a confirmation prompt.

---

## Data storage and cleanup

| Data             | Where stored                           | Removed on uninstall |
|------------------|----------------------------------------|----------------------|
| Saved shortcodes | `wp_options` (`gosp_saved_shortcodes`) | Yes                  |
| Per-user presets | `wp_usermeta` (`gosp_sb_presets`)      | Yes — all users      |
