Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/.vuepress/config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const { description, base } = require('../../package');

const addonsSidebar = require('./sidebars/addons');
const atomicEditorSidebar = require('./sidebars/atomic-editor');
const cliSidebar = require('./sidebars/cli');
const contextMenuSidebar = require('./sidebars/context-menu');
const controlsSidebar = require('./sidebars/controls');
Expand Down Expand Up @@ -115,6 +116,10 @@ module.exports = {
text: 'The Editor',
link: '/editor/',
},
{
text: 'Atomic Editor',
link: '/atomic-editor/',
},
{
text: 'Editor Controls',
link: '/editor-controls/',
Expand Down Expand Up @@ -193,6 +198,7 @@ module.exports = {
],
sidebar: {
'/addons/': addonsSidebar,
'/atomic-editor/': atomicEditorSidebar,
'/cli/': cliSidebar,
'/context-menu/': contextMenuSidebar,
'/controls/': controlsSidebar,
Expand Down
21 changes: 21 additions & 0 deletions src/.vuepress/sidebars/atomic-editor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module.exports = [
{
title: 'Atomic Editor',
collapsable: false,
sidebarDepth: -1,
children: [
[ '', 'Introduction' ],
]
},
{
title: 'Global Classes',
collapsable: false,
sidebarDepth: -1,
children: [
[ 'global-classes/', 'Overview' ],
'global-classes/data-structures',
'global-classes/actions-filters',
'global-classes/rest-api',
]
},
];
80 changes: 80 additions & 0 deletions src/atomic-editor/global-classes/actions-filters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Actions / Filters

<Badge type="tip" vertical="top" text="Elementor Core" /> <Badge type="warning" vertical="top" text="Intermediate" />

## `elementor/global_classes/update`

Fired after every mutation of the global classes set.

```php
do_action(
'elementor/global_classes/update',
string $context, // 'frontend' | 'preview'
array $changes // [ 'added' => string[], 'deleted' => string[], 'modified' => string[], 'order' => bool ]
);
```

Register with `accepted_args = 2`.

```php
add_action( 'elementor/global_classes/update', function( $context, $changes ) {
foreach ( $changes['deleted'] as $class_id ) {
my_plugin_drop_cached_css( $class_id );
}
}, 10, 2 );
```

## `elementor/atomic-widgets/styles/register`

Fired during style registration. Register custom style sources into `Atomic_Styles_Manager`.

```php
do_action(
'elementor/atomic-widgets/styles/register',
\Elementor\Modules\AtomicWidgets\Styles\Atomic_Styles_Manager $manager,
array $post_ids
);
```

Register with `accepted_args = 2`. Use a `[ <your_key>, $post_id, $context ]` tuple per document.

## `elementor/atomic-widgets/styles/clear`

Fired when style caches should be invalidated. `$key` is a hierarchical tuple.

```php
do_action( 'elementor/atomic-widgets/styles/clear', array $key );
```

| Key | Meaning |
| --- | ------- |
| `[ 'global' ]` | Full clear, all documents and contexts. |
| `[ 'global', $context ]` | One context, all documents. |
| `[ 'global', $post_id ]` | One document, both contexts. |
| `[ 'global', $post_id, $context ]` | One document and context. |

```php
add_action( 'elementor/atomic-widgets/styles/clear', function( array $key ) {
if ( ( $key[0] ?? null ) !== 'global' ) {
return;
}
my_plugin_clear_global_cache( $key );
} );
```

## `elementor/kit/meta_to_preserve_on_kit_import`

Preserve kit-level metadata across kit imports.

```php
add_filter( 'elementor/kit/meta_to_preserve_on_kit_import', function( array $meta_keys ) {
$meta_keys[] = 'my_plugin_kit_meta_key';
return $meta_keys;
} );
```

Global Classes itself registers four keys here (order, frontend labels, preview labels, sync map).

## `elementor/atomic-widgets/settings/transformers/classes`

Unchanged contract; internally now resolves labels via `Global_Classes_Repository::all_labels()`.
90 changes: 90 additions & 0 deletions src/atomic-editor/global-classes/data-structures.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Data Structures

<Badge type="tip" vertical="top" text="Elementor Core" /> <Badge type="warning" vertical="top" text="Intermediate" />

## Contexts

Every read/write has two contexts: `frontend` (published) and `preview` (editor draft). They are stored under separate meta keys (`…` vs `…_preview`).

## Storage layout

```
wp_posts
├── post_type = e_global_class ← one row per class
│ └── wp_postmeta
│ ├── _elementor_global_class_id → "<class_id>"
│ ├── _elementor_global_class_data → { type, variants, … } (frontend)
│ ├── _elementor_global_class_data_preview → { type, variants, … } (preview)
│ ├── _elementor_global_class_using_documents → [ doc_post_id, … ] (reverse index, frontend)
│ └── _elementor_global_class_using_documents_preview → [ doc_post_id, … ] (reverse index, preview)
└── post_type = elementor_library | page | post | … (any document)
└── wp_postmeta
├── _elementor_used_global_class → class_id (multi-value, frontend)
├── _elementor_used_global_class_preview → class_id (multi-value, preview)
├── _elementor_global_class_usage_indexed → "1"
└── _elementor_global_class_usage_indexed_preview → "1"
```

The active Kit holds:

| Constant | Purpose |
| -------- | ------- |
| `Global_Classes_Order::META_KEY` | Global display order. |
| `Global_Classes_Labels::META_KEY_FRONTEND` | `class_id → label` map (frontend). |
| `Global_Classes_Labels::META_KEY_PREVIEW` | `class_id → label` map (preview). |
| `Global_Classes_Sync_Map::META_KEY` | Design-system sync map. |
| `Global_Classes_Post_IDs` storage | `class_id → e_global_class post ID` lookup. |

## Class item shape

```php
[
'id' => 'g-abc',
'label' => 'Card',
'type' => 'class',
'variants' => [ /* … */ ],
]
```

## Constants

```php
\Elementor\Modules\GlobalClasses\Global_Class_Post_Type::CPT; // 'e_global_class'
\Elementor\Modules\GlobalClasses\Global_Classes_REST_API::MAX_ITEMS; // 1000
```

## PHP repository

```php
use Elementor\Modules\GlobalClasses\Global_Classes_Repository;

$repository = Global_Classes_Repository::make();
$repository->set_preview( true ); // operate on preview/draft
$repository->set_preview( false ); // operate on published (default)
```

| Method | Returns | Notes |
| ------ | ------- | ----- |
| `all_labels()` | `array<string, string>` | `class_id → label`, in order. Cheap. |
| `get( $class_id )` | `?array` | Single item or `null`. |
| `get_by_ids( $class_ids )` | `array<string, array>` | Bulk fetch; missing IDs absent. |
| `get_order()` | `string[]` | Current ordered ID list. |
| `each_item( $cb, $skip_migration = false, $batch_size = 100 )` | `void` | Streams every class in display order. |
| `all( $force = false )` | `Global_Classes` | Heavy — avoid on hot paths. |
| `apply_changes( $touched_items, $changes, $order )` | `void` | Persists only touched items + order/labels diff. |
| `put( $items, $order )` | — | Replace-everything semantics; diffs internally. |
| `update_order_and_labels( $order, $new_labels )` | `void` | Updates kit-level order/labels only. |
| `delete_all()` | `void` | Removes every class in the current context. |

Both `apply_changes()` and `put()` fire `elementor/global_classes/update`.

## Style cache key

`Atomic_Global_Styles` registers global classes per document. The styles key is:

```
[ 'global', $post_id, $context ]
```

Broader forms also exist: `[ 'global' ]`, `[ 'global', $context ]`, `[ 'global', $post_id ]`.
9 changes: 9 additions & 0 deletions src/atomic-editor/global-classes/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Global Classes

<Badge type="tip" vertical="top" text="Elementor Core" /> <Badge type="warning" vertical="top" text="Intermediate" />

A Global Class is a reusable, named style definition applied across documents. Each class is stored as an `e_global_class` post; the kit holds only lightweight indexes (order, labels, sync map, post-id map).

* [Data Structures](./data-structures/)
* [Actions / Filters](./actions-filters/)
* [REST API](./rest-api/)
112 changes: 112 additions & 0 deletions src/atomic-editor/global-classes/rest-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# REST API

<Badge type="tip" vertical="top" text="Elementor Core" /> <Badge type="warning" vertical="top" text="Intermediate" />

All endpoints live under the `elementor/v1` namespace. All read endpoints accept an optional `context` argument: `frontend` (default) or `preview`. Read permission is `is_user_logged_in()`.

## `GET /elementor/v1/global-classes`

Lightweight index — labels only, in display order.

| Argument | Type | Required | Default |
| -------- | ---- | -------- | ------- |
| `context` | string | no | `frontend` |

```json
{
"data": [
{ "id": "g-abc", "label": "Card" },
{ "id": "g-def", "label": "Button" }
]
}
```

## `GET /elementor/v1/global-classes/post`

Full class definitions referenced by a specific document.

| Argument | Type | Required | Default |
| -------- | ---- | -------- | ------- |
| `post_id` | integer | yes | — |
| `context` | string | no | `frontend` |

```json
{
"data": {
"g-abc": { "id": "g-abc", "label": "Card", "type": "class", "variants": [ ] }
},
"meta": { "order": [ "g-abc" ] }
}
```

`meta.order` is the intersection of the global order with the IDs used by the document.

## `GET /elementor/v1/global-classes/styles`

Bulk fetch by ID list.

| Argument | Type | Required | Default |
| -------- | ---- | -------- | ------- |
| `ids` | string | yes | — |
| `context` | string | no | `frontend` |

`ids` is comma-separated. Missing IDs resolve to `null` in `data` and are omitted from `meta.order`.

```json
{
"data": {
"g-abc": { "id": "g-abc", "label": "Card", "type": "class", "variants": [ ] },
"g-missing": null
},
"meta": { "order": [ "g-abc" ] }
}
```

## `PUT /elementor/v1/global-classes`

Create, update, delete, and reorder.

| Argument | Type | Required | Default | Notes |
| -------- | ---- | -------- | ------- | ----- |
| `context` | string | no | `frontend` | |
| `changes` | object | yes | — | `{ added, deleted, modified, order? }`. `additionalProperties: false`. |
| `items` | object | yes | — | Map of `class_id → { id, label, type, variants }` for **touched** items only. |
| `order` | string[] | yes | — | Full ordered list of class IDs after the operation. |

**Permission:** `current_user_can( Add_Capabilities::UPDATE_CLASS )`.

**Responses:**

- `204 No Content` on success.
- `200 OK` with `{ "code": "DUPLICATED_LABEL", "modifiedLabels": { … } }` when duplicates were auto-renamed.
- `400 Bad Request` with `code: "invalid_items" | "invalid_order" | "global_classes_limit_exceeded"`. The limit error carries `meta.current_count` and `meta.max_allowed`.

Hard limit: **1000** classes. Set `changes.order = true` when reordering, or per-document style caches won't be invalidated.

```js
PUT /elementor/v1/global-classes
{
"context": "frontend",
"changes": {
"added": ["g-new"],
"deleted": [],
"modified": ["g-abc"],
"order": true
},
"items": {
"g-abc": { /* full item */ },
"g-new": { /* full item */ }
},
"order": [ "g-new", "g-abc", "g-def" ]
}
```

## `GET /elementor/v1/global-classes/usage`

Detailed usage report across the site.

| Argument | Type | Required | Default |
| -------- | ---- | -------- | ------- |
| `context` | string | no | `frontend` |

**Permission:** `current_user_can( 'manage_options' )`.
9 changes: 9 additions & 0 deletions src/atomic-editor/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Atomic Editor

<Badge type="tip" vertical="top" text="Elementor Core" /> <Badge type="warning" vertical="top" text="Intermediate" />

The Atomic Editor (a.k.a. Elementor v4) is the next-generation editor architecture, built around atomic widgets, a typed settings system, and per-document style generation.

## Sections

* [Global Classes](./global-classes/) — reusable style definitions applied across documents.
Loading