> For the complete documentation index, see [llms.txt](https://docs.acpt.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.acpt.io/integrations/abilities-api/custom-content-types.md).

# Custom Content Types

acpt/list-tables, acpt/get-table, acpt/save-table, acpt/sync-table, acpt/delete-table, acpt/get-table-status, acpt/list-table-groups, acpt/get-table-group, acpt/save-table-group, acpt/delete-table-gro

Category: `acpt-content-model` · Default capability: `manage_options`

These 15 abilities cover the three CCT layers: **table groups** (the container that binds tables to a WordPress context), **tables** (schema definitions), and **records** (rows).

{% hint style="info" %}
The abilities are always registered, but the operations they perform need the **CCT feature enabled** (ACPT → Settings → Content settings) and a **valid ACPT license**. Without them, a call returns a normal failure envelope rather than an error.
{% endhint %}

{% hint style="warning" %}
Saving a table only writes its **definition**. The physical MySQL table is not created or altered until you call `acpt/sync-table`. Because a sync runs live DDL, `acpt/sync-table` and both `acpt/delete-*` abilities are annotated **destructive** (`D`) — an MCP host will surface an extra confirmation, and WordPress's REST layer requires `DELETE` for them.
{% endhint %}

## Table groups

| Ability                   | R/D | What it does                                                                          |
| ------------------------- | --- | ------------------------------------------------------------------------------------- |
| `acpt/list-table-groups`  | R   | Returns all table groups, including their location/visibility rules and member tables |
| `acpt/get-table-group`    | R   | Returns a single table group by name                                                  |
| `acpt/save-table-group`   |     | Creates a table group, or updates it if the name already exists                       |
| `acpt/delete-table-group` | D   | Deletes a table group; member tables are **detached, not deleted**                    |

### acpt/list-table-groups

No input required.

```php
$result = wp_get_ability('acpt/list-table-groups')->execute();
```

### acpt/get-table-group

| Property | Type   | Required |
| -------- | ------ | -------- |
| `name`   | string | Yes      |

### acpt/save-table-group

Accepts the full table-group shape — `name`, `label`, `display` (`STANDARD` / `ACCORDION` / `VERTICAL_TABS` / `HORIZONTAL_TABS`), and `locationRules[]` (each rule: `belongsTo`, `operator`, `find`). Identity is by `name`: send the same `name` again to update in place. Omitted top-level fields are preserved on an update.

```php
$result = wp_get_ability('acpt/save-table-group')->execute([
    'name'          => 'catalog',
    'label'         => 'Catalog',
    'display'       => 'STANDARD',
    'locationRules' => [
        ['belongsTo' => 'POST_TYPE', 'operator' => '==', 'find' => 'product'],
    ],
]);
```

### acpt/delete-table-group

| Property | Type   | Required |
| -------- | ------ | -------- |
| `name`   | string | Yes      |

## Tables

| Ability                 | R/D | What it does                                                                                             |
| ----------------------- | --- | -------------------------------------------------------------------------------------------------------- |
| `acpt/list-tables`      | R   | Returns all table definitions (schema metadata only, not physical sync status)                           |
| `acpt/get-table`        | R   | Returns a single table definition by name                                                                |
| `acpt/get-table-status` | R   | Returns whether the physical table is `not_created` / `synced` / `not_synced`, plus the pending SQL diff |
| `acpt/save-table`       |     | Creates a table definition, or updates it if the name already exists — **definition only**               |
| `acpt/sync-table`       | D   | Creates or alters the physical database table to match its stored definition (no-op if already in sync)  |
| `acpt/delete-table`     | D   | Deletes the table **definition** (metadata only — does not drop the physical table)                      |

### acpt/save-table

Accepts the table schema: `name`, `label`, `tableGroupId` (create the group first with `acpt/save-table-group` and pass its id — preferred over the deprecated flat `location` shim), `columns[]`, `indexes[]`, `foreignKeys[]`, primary-key strategy, and the timestamp / soft-delete toggles. The column, index, and foreign-key shapes match the [CCT documentation](/custom-content-types/columns.md); a partial update merges onto the stored definition rather than replacing it.

```php
// 1. save the definition
wp_get_ability('acpt/save-table')->execute([
    'name'         => 'products',
    'label'        => 'Products',
    'tableGroupId' => $groupId,
    'columns'      => [
        ['name' => 'title', 'type' => 'VARCHAR', 'length' => 255, 'nullable' => false],
        ['name' => 'price', 'type' => 'DECIMAL', 'nullable' => true],
    ],
]);

// 2. build/alter the physical table
wp_get_ability('acpt/sync-table')->execute(['name' => 'products']);
```

### acpt/get-table / acpt/get-table-status / acpt/delete-table

| Property | Type   | Required |
| -------- | ------ | -------- |
| `name`   | string | Yes      |

## Table records

Every record ability takes `table_name`, and the CRUD operations require the matching flag (`read` / `create` / `update` / `delete`) enabled in the table's **Expose via REST API** setting — the same gate as the [CCT REST API](/developers/rest-api.md#custom-content-types-table-records).

| Ability                    | R/D | What it does                          |
| -------------------------- | --- | ------------------------------------- |
| `acpt/list-table-records`  | R   | Returns paginated records for a table |
| `acpt/get-table-record`    | R   | Returns a single record by id         |
| `acpt/create-table-record` |     | Creates a record                      |
| `acpt/update-table-record` |     | Updates a record                      |
| `acpt/delete-table-record` | D   | Deletes a record                      |

### acpt/list-table-records

| Property     | Type    | Required |
| ------------ | ------- | -------- |
| `table_name` | string  | Yes      |
| `page`       | integer | No       |
| `per_page`   | integer | No       |
| `order_by`   | object  | No       |
| `where`      | object  | No       |
| `s`          | string  | No       |
| `only_ids`   | boolean | No       |

### acpt/get-table-record / acpt/delete-table-record

| Property     | Type              | Required |
| ------------ | ----------------- | -------- |
| `table_name` | string            | Yes      |
| `id`         | string or integer | Yes      |

### acpt/create-table-record / acpt/update-table-record

| Property     | Type              | Required      |
| ------------ | ----------------- | ------------- |
| `table_name` | string            | Yes           |
| `id`         | string or integer | `update` only |
| `data`       | object            | Yes           |

```php
$result = wp_get_ability('acpt/create-table-record')->execute([
    'table_name' => 'products',
    'data'       => ['title' => 'Widget', 'price' => 9.99],
]);
```
