https://github.com/artisanpack-ui/visual-editor
Empower your users with a modern, intuitive visual editor. This package provides a complete block-based editing experience, allowing for the creation of dynamic, beautiful content. Visual editors are becoming a crucial part of any content management system, enabling website owners to see how the page looks as they are creating it.
https://github.com/artisanpack-ui/visual-editor
block-editor laravel laravel-package livewire page-builder php visual-editor wysiwyg
Last synced: 12 days ago
JSON representation
Empower your users with a modern, intuitive visual editor. This package provides a complete block-based editing experience, allowing for the creation of dynamic, beautiful content. Visual editors are becoming a crucial part of any content management system, enabling website owners to see how the page looks as they are creating it.
- Host: GitHub
- URL: https://github.com/artisanpack-ui/visual-editor
- Owner: ArtisanPack-UI
- License: mit
- Created: 2026-02-01T23:11:21.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2026-06-08T23:07:07.000Z (12 days ago)
- Last Synced: 2026-06-08T23:07:51.442Z (12 days ago)
- Topics: block-editor, laravel, laravel-package, livewire, page-builder, php, visual-editor, wysiwyg
- Language: TypeScript
- Size: 5.27 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 22
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# ArtisanPack UI Visual Editor
A Gutenberg-powered visual editor for Laravel applications. Brings the
WordPress block editor to any Eloquent model, plus a full site editor
for templates, template parts, global styles, navigation menus, and
patterns.
V1.0 ships:
- **Post editor** — block-based content editing on any model that opts
in via the `HasBlockContent` trait.
- **Site editor** — templates, template parts, theme.json-backed global
styles, navigation menus, and patterns; mounted at `/visual-editor/site`.
- **42 forked core blocks** under the `artisanpack/*` namespace.
`core/*` markup pasted from upstream auto-converts on insert.
- **Three renderer packages** — Blade (server-side), React, and Vue —
for rendering saved block content on the public site.
- **First-class pairing** with [`artisanpack-ui/cms-framework`](https://github.com/ArtisanPack-UI/cms-framework)
for Posts, Pages, site-meta, navigation, and global-styles persistence.
Both packages remain usable standalone.
Full documentation: see [`docs/`](docs/). Start with [Quick Start](docs/Quick-Start.md), or browse the [documentation home](docs/home.md) for the full surface.
---
## Installation
```bash
composer require artisanpack-ui/visual-editor
php artisan migrate
```
For the site editor (recommended for most apps):
```bash
composer require artisanpack-ui/cms-framework
php artisan migrate
```
See the [Installation Guide](docs/Installation-Guide.md) and [Quick Start](docs/Quick-Start.md) for the full setup.
---
## Version compatibility
The visual-editor and `artisanpack-ui/cms-framework` packages ship as a
version pair — both packages need to be present, and both need to be on
a compatible major version, for the site-editor integration to work.
Install one without the other and the site-editor's install gate (#432)
surfaces a "cms-framework required" page instead of mounting.
| visual-editor | cms-framework | Notes |
| ------------- | ------------- | ---------------------------------------------- |
| v1.x | v1.x | Site-editor integration (this release) |
| v0.x | v0.x | Pre-v1 — no site-editor integration |
Bumping the major on either package without bumping the partner is
unsupported.
---
## Peer dependencies
The editor UI is built on [`@artisanpack-ui/react`](https://www.npmjs.com/package/@artisanpack-ui/react),
which is styled with DaisyUI and Tailwind CSS. Host applications
embedding the editor must have the following installed and loaded:
- `tailwindcss` `^4.0.0`
- `daisyui` `^5.0.0`
---
## Usage
Add the `HasBlockContent` trait to any model and register it in
`config/artisanpack/visual-editor.php`:
```php
use ArtisanPackUI\VisualEditor\Concerns\HasBlockContent;
class Post extends Model
{
use HasBlockContent;
}
```
```php
// config/artisanpack/visual-editor.php
return [
'resources' => [
'posts' => App\Models\Post::class,
],
];
```
Mount the editor in a Blade view:
```blade
```
The site editor mounts automatically at `/visual-editor/site` when
cms-framework is installed and the configured `SiteEditorAccessGate`
permits the request.
See [`docs/post-editor/Blade-Component.md`](docs/post-editor/Blade-Component.md) for the full
component reference and [`docs/site-editor.md`](docs/site-editor.md) for
the site-editor surface.
---
## Documentation
📚 **[Complete Documentation](docs/home.md)**
### Getting Started
- **[Installation Guide](docs/Installation-Guide.md)** — Setup and configuration
- **[Quick Start](docs/Quick-Start.md)** — Ship your first post in under an hour
- **[Configuration](docs/Configuration.md)** — Full configuration reference
### Core Concepts
| Topic | Doc |
|-------|-----|
| `HasBlockContent` + resource map | [`docs/content-model.md`](docs/content-model.md) |
| Blade / React / Vue renderers | [`docs/renderers.md`](docs/renderers.md) |
| Filters, actions, browser events | [`docs/Hooks-and-Events.md`](docs/Hooks-and-Events.md) |
| Migration & WP import | [`docs/migration.md`](docs/migration.md) |
| Common problems | [`docs/troubleshooting.md`](docs/troubleshooting.md) |
### Post Editor
| Topic | Doc |
|-------|-----|
| Surface tour | [`docs/post-editor.md`](docs/post-editor.md) |
| Quick start | [`docs/post-editor/Getting-Started.md`](docs/post-editor/Getting-Started.md) |
| `` reference | [`docs/post-editor/Blade-Component.md`](docs/post-editor/Blade-Component.md) |
| Embedding in Livewire | [`docs/post-editor/Livewire-Integration.md`](docs/post-editor/Livewire-Integration.md) |
| Embedding in Inertia (React/Vue) | [`docs/post-editor/Inertia-Integration.md`](docs/post-editor/Inertia-Integration.md) |
| Theming editor chrome | [`docs/post-editor/Theming.md`](docs/post-editor/Theming.md) |
### Site Editor
| Topic | Doc |
|-------|-----|
| Surface tour | [`docs/site-editor.md`](docs/site-editor.md) |
| Quick start | [`docs/site-editor/Getting-Started.md`](docs/site-editor/Getting-Started.md) |
| `SiteEditorAccessGate` contract | [`docs/site-editor/Access-Gate.md`](docs/site-editor/Access-Gate.md) |
| Template hierarchy + parts | [`docs/site-editor/Templates.md`](docs/site-editor/Templates.md) |
| theme.json-backed global styles | [`docs/site-editor/Global-Styles.md`](docs/site-editor/Global-Styles.md) |
| Menus, locations, fallbacks | [`docs/site-editor/Navigation.md`](docs/site-editor/Navigation.md) |
| Synced vs unsynced patterns | [`docs/site-editor/Patterns.md`](docs/site-editor/Patterns.md) |
### Blocks
| Topic | Doc |
|-------|-----|
| Block library overview | [`docs/blocks.md`](docs/blocks.md) |
| Authoring custom blocks | [`docs/blocks/Custom-Blocks.md`](docs/blocks/Custom-Blocks.md) |
| Per-breakpoint values | [`docs/blocks/Responsive-Design-Tools.md`](docs/blocks/Responsive-Design-Tools.md) |
| Per-state overrides | [`docs/blocks/State-Design-Tools.md`](docs/blocks/State-Design-Tools.md) |
### Developer Resources
- **[Developer Guide](docs/Developer-Guide.md)** — Extending the editor
- **[Hooks and Events](docs/Hooks-and-Events.md)** — Filters, actions, and browser events
---
## Gutenberg adoption — transient shims
The V1 editor adopts the upstream `@wordpress/*` packages. Some of those
packages expect a WordPress backend that this package doesn't provide,
so we ship temporary shims under `resources/js/visual-editor/vendor/`:
- **`core-data-shim.ts`** — aliased in `vite.config.ts` as
`@wordpress/core-data`. Provides the entity registrations and
selectors Gutenberg expects (`getEntityRecord`, `getEntityRecords`,
resolvers, permissions stubs). Templates, template parts, navigation,
patterns, global styles, attachments, and site-meta are wired through
to the package's REST surface.
- **`media-upload-stub.tsx`** — registers `editor.MediaUpload` via
`@wordpress/hooks` so the media-library picker on `core/image` is
routed through a stub or the real
`registerArtisanpackMediaBridge(MediaModal, uploadMedia)` bridge.
Both shims will be replaced over the V1.x release line as the cms-framework
side surfaces real backings. Every selector or filter implemented here is
one to re-verify against Gutenberg upgrades. See
[`docs/troubleshooting.md`](docs/troubleshooting.md#2-core-data-shim-entities-and-missing-data).
---
## Block defaults
V1 ships a frozen allow-list of forked blocks under the `artisanpack/*`
namespace. The defaults in `config/artisanpack/visual-editor.php` expose every block
that landed during the Phase I block fork — `@wordpress/block-library`'s
`registerCoreBlocks()` is no longer called, and the editor registers
only the in-package forks discovered under
`resources/js/visual-editor/blocks/`. See [`docs/blocks.md`](docs/blocks.md)
for the full block library overview and the `core/*` → `artisanpack/*`
mapping.
The forked allow-list covers the content, media, layout, widget, entity,
loop/feed, comments, query/pagination, and authentication clusters.
Entity blocks (`artisanpack/post-*`, `artisanpack/site-*`,
`artisanpack/template-part`, `artisanpack/navigation`) and the loop /
feed cluster (`artisanpack/query`, `artisanpack/post-template`,
`artisanpack/archives`, `artisanpack/categories`,
`artisanpack/tag-cloud`) need an entity in scope to render meaningful
content — pair the editor with
[`artisanpack-ui/cms-framework`](https://github.com/ArtisanPack-UI/cms-framework)
and they resolve against Posts / Pages / templates / site settings
end-to-end. Standalone, they fall back to empty shells rather than
crashing.
`disabled_blocks` is empty by default: with the I7 cutover (#415) the
editor no longer registers any `core/*` block, so there's nothing to
deny-list. New `@wordpress/block-library` releases similarly bring no
new registrations into this package — additions land only when a fork
is added to the in-package blocks directory and to the allow-list.
`from:core/*` transforms ship on each fork so existing `core/*` markup
pasted from upstream converts on insert.
Override the defaults by publishing the config to
`config/artisanpack/visual-editor.php` and editing the `enabled_blocks`
/ `disabled_blocks` arrays. The deny-list always wins over the allow-list.
---
## Using with cms-framework
The visual editor is fully usable standalone, but pairs with
[`artisanpack-ui/cms-framework`](https://github.com/ArtisanPack-UI/cms-framework)
to unlock:
- Editable `Post` and `Page` content out of the box.
- A real backing for `core/site-*` blocks (site title, tagline, logo, icon).
- Working `core/post-*`, `core/query`, taxonomy widget, and navigation
blocks.
- Templates, template parts, patterns, global styles, and menus
persisted via cms-framework's models.
- Seeded `visual_editor.*` permissions.
```bash
composer require artisanpack-ui/visual-editor artisanpack-ui/cms-framework
php artisan migrate
```
Both packages are loosely coupled — cms-framework's editor wiring is
guarded by `class_exists(\ArtisanPackUI\VisualEditor\VisualEditor::class)`,
so each remains usable on its own. See
[`docs/site-editor/Getting-Started.md`](docs/site-editor/Getting-Started.md)
for the site-editor pairing walkthrough.
---
## Extensibility
### `ap.visual-editor.resources`
Register slug → Eloquent model class mappings used by
`/visual-editor/api/{resource}/{id}/content`. Filter contributions are
merged with `config('artisanpack.visual-editor.resources')`; the static
config wins on key collision so host-app overrides always take
precedence. Models must use
`ArtisanPackUI\VisualEditor\Concerns\HasBlockContent` — invalid entries
surface as `InvalidArgumentException` on first request rather than at
boot, so a contributor's standalone install never trips host boot.
```php
addFilter('ap.visual-editor.resources', function (array $resources): array {
return array_merge([
'posts' => App\Models\Post::class,
], $resources);
});
```
Full contract: [`docs/content-model.md`](docs/content-model.md#2-the-resource-map) and
[`docs/Hooks-and-Events.md`](docs/Hooks-and-Events.md#ap-visual-editor-resources).
### `ap.icons.register-icon-sets`
Editor chrome icons resolve through `artisanpack-ui/icons`. Register
additional icon sets in a service provider — see the
[`artisanpack-ui/icons`](https://github.com/ArtisanPack-UI/icons) docs.
---
## i18n
Editor strings use `@wordpress/i18n` with the `artisanpack-visual-editor`
text domain. The domain is initialized via `bootI18n()` in
`resources/js/visual-editor/vendor/i18n.ts`.
Regenerate the placeholder `.pot` catalog with:
```bash
npm run i18n:extract
```
The extractor scans `resources/js/visual-editor/**/*.{ts,tsx}` for
`__/_x/_n/_nx` calls bound to the text domain and writes
`languages/artisanpack-visual-editor.pot`.
---
## Contributing
As an open source project, this package is open to contributions from
anyone. Please [read through the contributing
guidelines](CONTRIBUTING.md) to learn more about how you can contribute
to this project.