Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Visual Laravel Package

bagistoplus/visual

bagistoplus/visual is a Bagisto package that adds a visual page builder to the admin panel, letting merchants create and edit storefront pages, content blocks, and layouts with drag-and-drop controls—no code required. Built for Laravel/PHP.

View on GitHub
Deep Wiki
Context7

Getting Started

Install pinned, never floating. At alpha.31 the API surface is still moving, so a caret range will eventually upgrade you into someone else's refactor.

composer require bagistoplus/visual:2.0.0-alpha.31 --with-all-dependencies

Commit the lockfile. Then publish whatever the provider exposes — verify the provider FQCN against composer.json first rather than copy-pasting from prose:

php artisan vendor:publish          # interactive list is the fastest way to see what's publishable
php artisan vendor:publish --provider="BagistoPlus\Visual\VisualServiceProvider"
php artisan migrate                 # only if the package ships layout/revision tables

If the package requires a frontend build (Vite/TypeScript — the alpha.31 release ships a TS event mirror, so it almost certainly does), run the asset build before you touch a browser. Stale hashed assets are indistinguishable from "the editor didn't save."

Where to look first, in this order. Docs are thin; the source is the spec.

  1. src/*ServiceProvider.php — registrations, boots, and pushed middleware. The cache-bypass middleware lives in/behind this.
  2. config/visual.php (or equivalent) — the block/component registry and mode flags. This config file is the product surface; everything else is plumbing around it.
  3. routes/ — editor, preview, and asset endpoints. This tells you the auth story faster than any README.
  4. The design/preview mode middleware — alpha.31 fixed a middleware-order dependency here. Highest-risk code in the package.
  5. resources/views/ and resources/js/*.ts — Blade block templates and the event contract.

First use case: one promo block, end to end. Resist the pull toward the editor UI. Build a single presentational Blade block (title, body, image, CTA), register it in config, render it on a non-revenue page (a CMS page or a category page — never checkout), then:

  1. Generate a draft preview URL for an edit to that block.
  2. Open it in a clean browser with no editor session.
  3. Confirm it shows the draft headline (not published, not cached).
  4. Load the same block's public URL and confirm it shows the published headline.

If step 3 passes you've proven registry, rendering, and cache bypass — the three things the package actually exists to do. Everything else is elaboration.

Implementation Patterns

Keep blocks dumb, keep the registry authoritative. Blocks should be presentational Blade components taking flat props and running zero queries — resolve data one layer up in a controller or view composer. The registry in config is your governance: merchants pick from an approved catalogue, not an open canvas. Version blocks (promo.v1, promo.v2) rather than mutating props in place, because saved layouts in the database will reference the old shape long after the code has moved on.

One renderer, many surfaces. Funnel editor, preview, and published pages through a single Blade entry point that maps {type, props} → component. This gives you one place for sanitisation, analytics, lazy loading, and error boundaries, and it keeps all three output paths byte-identical by construction rather than by discipline.

{{-- resources/views/visual/render.blade.php --}}
@foreach ($layout['blocks'] as $block)
    <x-dynamic-component
        :component="config('visual.blocks.'.$block['type'].'.component')"
        :props="$block['props']" />
@endforeach

Treat draft preview as a URL, not a mode. The alpha.31 change — rendering editor edits without the editor client — is the single most useful day-to-day feature. It converts review from "screenshots in Slack" into "open this link." Build the workflow around it:

  • One short-lived, signed preview URL per draft.
  • QA sign-off against the preview URL, not against a staging branch.
  • Your regression test is behavioural, not structural:
$this->get($previewUrl)->assertOk()->assertSee('Draft headline');
$this->get($publicUrl)->assertOk()->assertDontSee('Draft headline');

Pin preview behaviour with a cache matrix test. The middleware-order-independent bypass closes one failure mode; it does not reach a CDN. Encode your stack as a matrix — {no cache, Laravel response cache} × {middleware ordering variants} × {guest, editor, preview-mode} — and re-run it on every alpha bump. This is cheapest insurance on the feature reviewers depend on.

Consume the event contract deliberately. Wishlist and compare now emit storefront events with a TypeScript mirror. Import the mirrored types in your frontend analytics rather than hand-rolling payload shapes, and add one parity assertion (a generated-type check, or a fixture asserted on both PHP and TS sides) so the two definitions cannot drift silently. Drift shows up as missing analytics weeks later, never as an error.

Canary editor access. Gate editor routes behind an env flag plus an allowlist of editor users. Roll out to one content type and one editor group first. Your rollback path must not require redeploying merchant content — composed layouts are data, and they will outlive any given version of this package.

Gotchas and Tips

Preview is a security boundary and the release notes don't describe it. Something now decides who may render unpublished content. Before you paste a preview link into a stakeholder channel, answer: is the URL signed, does it expire, is it scoped per user or per tenant, and can a forwarded link be replayed by an unauthenticated recipient? Threat-model this yourself — it is undocumented.

Cache bypass cuts both ways. Too broad and you bypass cache for ordinary traffic (origin load, abuse vector). Too narrow and reviewers see stale pages, which destroys the editorial trust the whole product rests on. Assert mode resolution explicitly, and add a header or log line that names which mode rendered a response — the single most valuable debugging affordance you can add on day one.

// Cheap, and pays for itself the first time a reviewer says "it's not updating"
response()->header('X-Visual-Mode', $this->resolvedMode()); // design|preview|published

Your CDN is out of scope. The package fixes Laravel-level caching. Cloudflare, Fastly, and any proxy in front of your app still serve what they serve. Verify against the public hostname, not php artisan serve:

curl -I "https://shop.example.com/category/sale?cb=$(date +%s)"

Alpha churn is the real cost, not the install. This is the 31st alpha of a major line with zero dependents upstream — you are the support organisation. Budget a re-validation pass per bump, read the changelog for breaking vs. additive changes, and keep the package off revenue-critical paths until you've characterised a few upgrade diffs.

Wrong-template bugs are almost always view-precedence bugs. Bagisto layers themes, and this package layers on top. When a block renders the wrong markup, inspect the resolved path before guessing:

php artisan view:clear
php artisan route:list | grep -i visual

then dump the view finder's candidate paths for that block name.

Watch block-level query counts on the composed page. A page that's fine with three blocks can quietly issue forty queries with twelve. Assert query counts on the composed page, not on individual blocks in isolation — the regression only exists in aggregate.

Don't debug a "failed save" until you've rebuilt assets. If block styles ship through a Vite/TS pipeline, stale hashed assets look exactly like a save failure. Confirm the manifest rebuilt and the cache-busted filename changed before you touch application code.

Ship a fork-ready posture. MIT, no visible commercial support path, zero dependents. Vendor the source into a private mirror so you can patch a blocked storefront without waiting on upstream, and keep your patches as a small, rebasable commit set. A divergent fork is the failure mode you're protecting against — the goal is a narrow set of local commits, not a permanent schism.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons