Download the PHP package nomadicjosh/vihzhuo without Composer
On this page you can find all versions of the php package nomadicjosh/vihzhuo. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download nomadicjosh/vihzhuo
More information about nomadicjosh/vihzhuo
Files in nomadicjosh/vihzhuo
Package vihzhuo
Short Description A drag and drop pagebuilder to manage pages in any PHP project.
License MIT
Homepage https://github.com/nomadicjosh/vihzhuo
Informations about the package vihzhuo
Vihzhuo
Vihzhuo is a framework-agnostic drag-and-drop page builder for PHP applications. It is a fork of PHPageBuilder, modernized for PHP 8.4, strict types, PSR-7 HTTP messages through qubus/http, GrapesJS 0.23, and PHPStan level max.
Vihzhuo provides:
- a website manager for creating pages, routes, layouts, and translations;
- a GrapesJS page builder with blocks, block settings, responsive previews, an asset manager, a Style Manager, and a built-in rich-text editor;
- convention-based themes, layouts, HTML blocks, and server-rendered PHP blocks;
- PSR-7 entry points that can run standalone or behind an existing framework;
- replaceable authentication, routing, storage records, repositories, caching, themes, and page-builder services;
- extension APIs for blocks, layouts, CSS, and JavaScript supplied by application code or Composer packages.
Table of contents
- Requirements
- Installation
- Configuration
- Running Vihzhuo
- Integrating with an existing project or framework
- Creating a theme
- Creating a layout
- Creating blocks
- Block settings and field types
- Nested blocks and shortcodes
- Custom block models and controllers
- Block JavaScript
- Adding CSS and JavaScript assets
- Registering blocks and layouts from application code
- Customizing GrapesJS
- Routing and multilingual pages
- Uploads and the Asset Manager
- Caching
- Security notes
- Development and quality checks
Requirements
- PHP 8.4 or newer;
- PDO and the PDO driver for your database;
- JSON and fileinfo PHP extensions;
- Composer 2;
- a writable uploads directory;
- Node.js 20 or newer only when rebuilding the browser assets.
The checked-in dist/ directory contains the browser assets needed by an application. Application users do not need Node.js unless they modify Vihzhuo's JavaScript or Sass sources.
Installation
Install the package:
When working from this repository instead of consuming a release:
Copy the example configuration and adjust it for the application:
Create the pages, page_translations, uploads, and settings tables. config/create-tables.sql contains the MySQL/MariaDB schema. When using SQLite or another PDO database, create equivalent tables and preserve the column names and unique constraints used by that schema.
The application must make these locations writable by the PHP process when enabled:
Configuration
The complete annotated example is in config/config.example.php. The most important options are:
| Key | Purpose |
|---|---|
general.base_url |
Absolute application URL, including a subdirectory when applicable. |
general.language |
Default locale, such as en. |
general.assets_url |
Public URL prefix through which Vihzhuo serves its dist/ files. |
general.uploads_url |
Public URL prefix used for uploaded files. |
storage.use_database |
Enables the built-in PDO-backed repositories. The default manager requires it. |
storage.database.driver |
Database driver name. Use sqlite to enable SQLite foreign keys. |
storage.database.dsn |
PDO DSN, for example sqlite:/absolute/path/site.sqlite or mysql:host=127.0.0.1;dbname=site;charset=utf8mb4. |
storage.database.username / password |
PDO credentials; these may be null for SQLite. |
storage.database.options |
Optional PDO options. |
storage.database.prefix |
Optional prefix prepended to Vihzhuo table names. |
storage.uploads_folder |
Absolute directory used by the image Asset Manager. |
auth.use_login |
Enables the bundled session login flow. |
auth.class |
Class implementing AuthContract. |
auth.url |
URL of the login endpoint. |
website_manager.use_website_manager |
Enables the bundled page-management interface. |
website_manager.class |
Class implementing WebsiteManagerContract. |
website_manager.url |
Base URL of the manager. |
pagebuilder.class |
Class implementing PageBuilderContract. |
pagebuilder.url |
URL of the GrapesJS editor. |
pagebuilder.actions.back |
Destination of the editor's Back button. |
page.class |
Page record implementing PageContract. |
page.table |
Pages table name without the configured prefix. |
page.translation.* |
Translation class, table, and page foreign key. |
cache.enabled |
Enables rendered-page caching. |
cache.folder |
Absolute cache directory. |
cache.class |
Class implementing CacheContract. |
theme.folder |
Absolute parent directory containing all themes. |
theme.folder_url |
Public URL corresponding to theme.folder. |
theme.active_theme |
Folder name of the active theme. |
router.class |
Class implementing RouterContract. |
class_replacements |
Map of concrete Vihzhuo classes to compatible application replacements. |
A typical PDO configuration is:
Do not store production credentials directly in a committed configuration file. Populate them from the host application's secret or environment configuration.
Running Vihzhuo
Standalone PSR-7 front controller
Vihzhuo consumes a Psr\Http\Message\ServerRequestInterface and returns a Psr\Http\Message\ResponseInterface. A standalone SAPI entry point can use the factories and emitter supplied by qubus/http:
A complete example is available in examples/index.php.
All manager, page-builder, public-page, upload, and Vihzhuo asset requests must reach this front controller. With PHP's development server:
Using the example /admin URLs, open:
In Apache, Nginx, Caddy, or another web server, configure the usual front-controller fallback so URLs such as /admin/pagebuilder, /assets/pagebuilder/app.js, and public page routes are sent to public/index.php when they are not physical files.
Integrating with an existing project or framework
Frameworks that expose PSR-7 requests
Pass the framework request directly to Vihzhuo and return its response:
For frameworks using a different request/response implementation, use that framework's PSR-7 bridge at the boundary. Keep Vihzhuo itself on PSR-7 messages.
Letting the host application own authentication and routing
Set auth.use_login to false, protect the manager routes with the host application's authorization middleware, and use the split handlers instead of handleRequest():
handleAuthenticatedRequest() recognizes the configured website_manager.url and pagebuilder.url. It does not perform an authorization check; the host application must do that before calling it.
If the host already resolved a page and only needs the editor response:
To render an already resolved page without using the database router:
Replacing services
Services can be configured by interface-compatible class:
Vihzhuo also exposes explicit setters for dependency injection:
Concrete internal classes can be replaced where Vihzhuo uses phpb_instance():
Replacement classes should extend the original concrete class unless the configuration point explicitly requires an interface.
See UPGRADE.md for the typed contracts and other breaking changes from the original library.
Creating a theme
theme.folder points to the directory containing theme folders, and theme.active_theme chooses one of them:
A full theme can contain:
Blocks are discovered directly under blocks/, blocks/elements/, blocks/php/, and blocks/archived/. Layouts are discovered directly under layouts/.
Theme translation files return arrays and are merged over the built-in language file:
Use phpb_theme_asset() whenever a layout or PHP block needs the public URL of a theme file:
Static HTML can use the equivalent shortcode:
Creating a layout
A layout is a folder under layouts/ containing view.php and, optionally, config.php.
public/themes/acme/layouts/main/config.php:
The title appears in the page form. Without it, Vihzhuo derives a title from the layout slug.
public/themes/acme/layouts/main/view.php:
The layout receives these variables:
| Variable | Type | Purpose |
|---|---|---|
$page |
PageContract |
Current page record and translated metadata. |
$renderer |
PageRenderer |
Advanced block/body rendering and shortcode parsing. |
$body |
string |
Editable page content, or its rendered frontend HTML. Output this without escaping. |
Layout CSS links remain available inside the GrapesJS canvas. External layout scripts are transferred into the canvas script configuration and loaded in their original order.
Creating blocks
There are two block kinds, selected by the view filename.
| View | Behavior | PHP block settings |
|---|---|---|
view.html |
Editable HTML. GrapesJS stores the edited markup with the page. | No; settings are intentionally omitted for HTML blocks. |
view.php |
Dynamic/server-rendered block. Vihzhuo stores settings and rerenders it after a setting changes. | Yes. |
Static HTML block
Create public/themes/acme/blocks/hero/config.php:
Create public/themes/acme/blocks/hero/view.html:
The block is discovered automatically. Common text, link, and image components receive the editor controls appropriate to their element type.
Dynamic PHP block with settings
Create public/themes/acme/blocks/callout/config.php:
Create public/themes/acme/blocks/callout/view.php:
BaseModel::setting() escapes values by default, making it appropriate for normal HTML text and attributes. Only use $block->setting('name', true) for intentionally trusted HTML that has been sanitized by the application.
Dynamic block views receive:
| Variable | Type | Purpose |
|---|---|---|
$block |
BaseModel or custom model |
Settings and application data for this block instance. |
$page |
PageContract |
Current page. |
$renderer |
BlockRenderer |
Render another block programmatically. |
$hasSkeleton |
bool |
Whether the model enabled skeleton rendering. |
$hasDynamicSkeleton |
bool |
Whether the skeleton contains dynamic preview content. |
Block configuration reference
| Key | Type | Meaning |
|---|---|---|
title |
string |
Sidebar label. Defaults to a title derived from the slug. |
category |
string |
Sidebar category. Defaults to the translated default category. |
icon |
string |
Font Awesome class used when no generated thumbnail exists. |
hidden |
bool |
When true, the block can be rendered by another block but is hidden from the block picker. |
settings |
array |
Settings shown for dynamic view.php blocks. |
wrapper |
string |
Trusted HTML tag used to wrap a styled dynamic block; defaults to div. |
cache |
bool |
Set to false when this block makes a rendered page unsafe to cache. |
cache_lifetime |
positive int |
Maximum cache lifetime, in minutes, for a rendered page containing this block. When multiple cached blocks specify a lifetime, the shortest lifetime wins. The default upper limit is one week (10,080 minutes). |
whitelist |
list<string> |
Only register the block when the current full URL contains one of these trusted domain/string values. |
namespace |
string |
Namespace containing this block's optional Model and Controller classes. |
cache_lifetime only affects rendered-page caching when global caching is enabled and the block permits caching. Omit it to retain the current page lifetime. Use a positive whole number to shorten the lifetime; numeric strings are accepted for compatibility. To prevent a page containing the block from being cached at all, set 'cache' => false instead of setting the lifetime to zero.
For example, if a page contains one block with a 60-minute lifetime and another with a 15-minute lifetime, the complete rendered page expires after 15 minutes:
Example of a block available only on selected installations:
Block settings and field types
Settings belong to dynamic view.php blocks. Each key becomes the setting name stored for that block instance.
Common setting options
| Key | Required | Purpose |
|---|---|---|
type |
No | Control type; defaults to text. |
label |
Yes | Label displayed in the Settings tab. Entries without a label are ignored. |
value |
No | Initial/default value. |
placeholder |
No | Placeholder for controls that support one. |
options |
For select |
List of selectable values. |
The PHP block adapter supports these useful field types:
| Type | Result | Notes |
|---|---|---|
text |
Single-line text input | Default type. |
number |
Numeric input | Stored as a string when rendered by the block model. |
select |
Select menu | Requires options. |
checkbox |
Boolean checkbox | Checked state is represented by the setting attribute; use an empty default for unchecked. |
color |
Color picker | Produces a CSS color value such as #2563eb. |
yes_no |
Vihzhuo Yes/No select | Normalized to values 0 and 1. |
GrapesJS also supports button and custom trait types. A button requires a JavaScript command and therefore should be registered by a GrapesJS plugin rather than serialized in a PHP block configuration. Applications that need additional PHP configuration keys can replace BlockAdapter or register a custom trait type during vihzhuo:grapesjs:before-init.
Complete field example
Select options may use the demo-friendly value/label form shown above or GrapesJS's id/name form:
Changing a setting updates the block attributes, posts the block data to the configured page-builder endpoint, rerenders the PHP view, and reselects the replacement block in the canvas.
Application code may replace the complete settings definition at runtime before rendering the editor:
When overriding settings dynamically, supply the complete settings array; it replaces the file-based settings definition rather than merging individual fields.
Nested blocks and shortcodes
Dynamic blocks and layouts may render other blocks using shortcodes.
Render a child block
Use a stable, unique id for repeated child instances:
Additional shortcode attributes become setting values for that block render:
Blocks intended only as nested implementation details can set 'hidden' => true in config.php.
Add a nested drop zone
Use [blocks-container] where editors should be able to drop arbitrary child blocks inside a dynamic block:
It is converted to <div phpb-blocks-container></div> and receives the appropriate GrapesJS drop behavior.
Other shortcodes
| Shortcode | Result |
|---|---|
[block slug="hero" id="home-hero"] |
Renders a theme or extension block. |
[blocks-container] |
Creates a nested block drop zone. |
[theme-url] |
Active theme's public URL. |
[page id="12"] |
Route of page ID 12 on public output. |
Shortcode nesting is limited to 25 levels to catch accidental circular block references.
Custom block models and controllers
Dynamic blocks use BaseModel and BaseController by default. Add model.php or controller.php only when the block needs application logic.
Set an explicit namespace in the block's config.php:
model.php must contain a Model class extending BaseModel:
The view can call the custom method:
A model may set the inherited $doNotRender, $hasSkeleton, or $hasDynamicSkeleton properties during initialization when the corresponding behavior is required.
controller.php must contain a Controller class extending BaseController:
Custom models and controllers are trusted server-side code. Vihzhuo validates that they extend the corresponding base class before using them.
Block JavaScript
A block may provide one of these public script files:
It may also provide an editor-specific version:
If there is no builder script, Vihzhuo uses the public script in the editor. PHP script views receive $renderer.
Block scripts run with instance-specific variables:
The editor executes builder scripts as components are mounted or updated. On public output, the renderer scopes each script behind a run-script event. If the host theme does not already provide a block-script bootstrap, add one near the end of the layout:
Prefer layout assets for shared libraries. Use block scripts only for behavior tied to a particular rendered block instance.
Adding CSS and JavaScript assets
Theme assets
Put normal frontend assets inside the active theme and reference them from the layout:
These assets are part of both the public layout and the GrapesJS canvas preview.
Assets supplied by application code or a package
Register trusted asset URLs before handling the request:
Render the registrations in the theme layout:
Registered URLs and attributes are trusted developer configuration; do not construct them from user input.
Page-builder UI assets and hooks
PageBuilder::customStyle() and customScripts() customize the editor shell rather than the public page:
Call these methods before rendering or handling a page-builder request.
Registering blocks and layouts from application code
Composer packages and application modules can provide blocks and layouts without copying them into the active theme:
Register several at once:
An extension block/layout folder follows the same file conventions as a theme folder. Give custom PHP block classes an explicit namespace in their block configuration.
Registrations must happen before the theme is enumerated—normally before calling handleRequest().
See examples/blocks directory for complete static and dynamic extension block examples.
Customizing GrapesJS
The default editor uses GrapesJS 0.23, grapesjs-touch, and Vihzhuo's built-in RTE. The RTE includes formatting, links, font color, font size, and HTML source editing. The CKEditor plugin remains bundled for opt-in compatibility but is not active by default.
Static configuration overrides
Define window.customConfig before Vihzhuo initializes the editor:
The custom configuration is deeply merged over the server defaults.
Before and after initialization hooks
Use vihzhuo:grapesjs:before-init to mutate final configuration and register plugin functions:
Use vihzhuo:grapesjs:ready when the initialized editor API is required:
Install these listeners through PageBuilder::customScripts('head', ...) or another script loaded before the inline page-builder initialization code.
Custom traits
Register a GrapesJS trait type in a plugin:
To expose extra trait configuration from PHP config.php, extend and replace Vihzhuo\Modules\GrapesJS\Block\BlockAdapter.
Routing and multilingual pages
The bundled DatabasePageRouter resolves routes stored in page_translations.
Supported route forms include:
Exact routes are checked before named parameters, and named parameters are checked before wildcards. Read named values in PHP with:
Or retrieve all values:
Active languages are read from the languages website setting. If it is absent, general.language is used. The Website Manager lets administrators enable languages and stores title, metadata, and route translations for each page.
Useful helpers include:
Custom routing is supported by implementing RouterContract and configuring router.class, or by resolving a PageContract in the host framework and calling the page builder/renderer directly.
Uploads and the Asset Manager
The bundled Asset Manager accepts PNG, JPEG, GIF, and WebP images. Upload handling:
- reads a PSR-7
UploadedFileInterface; - verifies the detected MIME type with fileinfo;
- creates a random public identifier;
- stores metadata in the
uploadstable; - stores files below
storage.uploads_folder; - serves files through
general.uploads_urlwith path-containment checks.
Make sure the uploads route reaches handlePublicRequest() or the complete handleRequest() handler.
To add a theme image that is not user-uploaded, place it in the theme and use phpb_theme_asset() instead of the Asset Manager.
Caching
Enable file-backed rendered-page caching with:
The default maximum lifetime is one week. A dynamic block can shorten it:
Disable caching for pages containing request-specific content:
Saving or updating a page invalidates its cached route variants. During development, ?ignore_cache bypasses reads and writes, while ?refresh_cache bypasses the current cached response so it can be regenerated.
Security notes
- Protect the manager and page-builder routes with authentication and authorization.
- Replace the example password and keep credentials outside version control.
- Point
theme.folder,storage.uploads_folder, andcache.folderat intentional, application-owned directories. - Use
phpb_e()for HTML text and attributes. - Use
phpb_json()when embedding PHP data in a<script>element. BaseModel::setting()escapes by default; only allow raw HTML after application-level sanitization.- Treat theme templates, registered assets, block scripts, configuration files, and GrapesJS plugins as trusted developer code.
- Validate custom block model data before rendering it.
- Custom record/repository implementations must honor the typed contracts and their security boundaries.
Development and quality checks
Rebuild authored JavaScript and Sass:
Run PHP quality checks:
The browser integration smoke test is tests/Browser/grapesjs-smoke.html. Serve the repository through HTTP before opening it so its relative assets load correctly.
Runtime templates are syntax-checked separately because their variables are injected at the view boundary. The typed application, front-controller example, and PHP tests are covered by PHPStan level max.
For migration details, see UPGRADE.md.
License
Vihzhuo is licensed under the MIT License.