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

Bones Macros Laravel Package

genealabs/bones-macros

genealabs/bones-macros bundles reusable Laravel macros for GeneaLabs Bones projects, extending Blade, collections, and request helpers so common patterns become one-line calls and everyday boilerplate shrinks.

View on GitHub
Deep Wiki
Context7

Getting Started

The service provider is the documentation. This package is a thin wrapper: a single provider that calls Blade::directive(...) and/or Form::macro(...) at boot. There is no wiki worth reading. Open src/BonesMacrosServiceProvider.php (or equivalent) first and enumerate the registrations — that list is the only reliable inventory of macro names, argument signatures, emitted HTML, and whether values are escaped.

Check compatibility before you require it. Open the package's composer.json and read the illuminate/* and php constraints, plus whether it pulls in laravelcollective/html. Doing this first takes two minutes and saves you from an install that half-works on your Laravel version.

composer require genealabs/bones-macros

On Laravel 5.5+ the provider is auto-discovered via extra.laravel.providers. On anything older, register it manually in config/app.php:

GeneaLabs\BonesMacros\BonesMacrosServiceProvider::class,

Also check extra.laravel.aliases — if a facade alias ships with the package, discovery won't wire it up for you.

Confirm what loaded rather than assuming.

php artisan tinker
>>> array_keys(Blade::getCustomDirectives());
>>> array_keys(Form::getMacros());   // only if laravelcollective/html is present

Run that before and after installing. The diff is your real inventory and doubles as a collision audit against helpers you already have.

First use case: one internal form partial. Pick a settings page or an admin CRUD screen — something with no customer exposure — and convert exactly one form. Render it, view-source it, compare the markup against your CSS framework and your accessibility conventions. If the output doesn't match, you've spent an hour and you know to stop. Do not start with a checkout or registration form.

Implementation Patterns

Never let macro calls scatter across templates. Wrap each one in an app-owned partial or Blade component so the third-party name exists in exactly one file:

{{-- resources/views/components/field-text.blade.php --}}
@bonesTextInput([
    'name'  => $name,
    'label' => $label,
    'value' => old($name, $value ?? null),
])

Replacing the macro later with <x-form.input> becomes a one-file edit instead of a repo-wide grep.

Drive old() and error state explicitly at the call site. Macros render markup; they do not know about your validation lifecycle. Pass repopulated values and error strings in:

@bonesTextInput([
    'name'  => 'email',
    'value' => old('email', $user->email ?? null),
    'error' => $errors->first('email'),
])

If the macro signature doesn't accept an error argument, wrap it and post-process in the partial — or move that field to a native component. Verifying repopulation and error display is the single most important thing to check before rollout, because it's the one thing users notice immediately when it's broken.

Emit your own form scaffolding at the top of every form. Don't assume the macros handle it:

<form method="POST" action="{{ route('settings.update') }}">
    @csrf
    @method('PUT')
    ...
</form>

Missing CSRF on a POST produces a silent 419 on first submit — an easy hour to lose if you assumed the macro covered it.

Pair with FormRequests, not inline validation. Keep rules in FormRequest classes and authorization in policies. The macros should be confined to presentation; that keeps the third-party surface to markup only, which is the only surface you can reasonably audit.

Adopt one macro at a time, and measure each. Treat the package as a menu, not a framework. Convert a field, view-source the result, keep it only if it genuinely saved boilerplate. In practice two or three macros carry all the value; the rest are noise that adds upgrade liability for nothing.

Use partials for repeated form sections. If the package gives you anything reusable at a higher level (field groups, button rows), extract them into resources/views/partials/forms/ and reference from multiple screens. That's where the time savings actually compound — not in single fields.

Write HTML snapshot tests around your wrappers. This is what makes adoption defensible in an unmaintained package:

public function test_text_field_escapes_value(): void
{
    $html = $this->blade(
        '@include("components.field-text", ["name" => "q", "value" => \'"><script>alert(1)</script>\'])'
    );

    $html->assertDontSee('<script>alert(1)</script>', false);
}

These tests survive a later port to native components — same assertions, different implementation.

Prefer extract-and-port for anything long-lived. Given the adoption signals, the strongest day-to-day pattern is: read the source, reimplement the two or three macros you actually use as app-level Blade components under your own tests, and keep the package out of composer.json. It's a few hundred lines. That permanently removes the upgrade liability at modest cost.

Gotchas and Tips

Escaping is unproven until you've read every line. Hand-rolled form macros are a classic source of unescaped attribute injection. Grep the macro bodies for sprintf, string concatenation, and " interpolation, and confirm e() or htmlspecialchars is applied to attribute values. Test with " onfocus="alert(1) bound to old(). If it isn't escaped, that's stored XSS in a back-office form — a hard stop, not a nice-to-have.

CSRF and _method spoofing are not guaranteed. Check whether the macros emit @csrf and @method. If not, add them yourself at the top of every form. This is the most common "it worked yesterday" failure after adoption.

Macro name collisions fail silently. Blade::directive() and Form::macro() overwrite existing registrations with no warning. Diff array_keys(Blade::getCustomDirectives()) before and after install. A shadowed in-house helper produces subtly wrong markup that surfaces weeks later as a styling or attribute regression, and it's genuinely hard to trace back.

Registration is global and unconditional. Every macro is available in every view at boot — no opt-in, no scoping. That's another argument for owning a single app-level provider so you control what's in the global namespace.

The Form facade is the upgrade landmine. If this depends on laravelcollective/html, note that it's effectively unmaintained and the Form/Html facades are gone from framework proper. A Laravel major bump can break every form simultaneously. Pin the exact version and expect to freeze it.

Clear everything after any provider or config change:

php artisan config:clear
php artisan view:clear
composer dump-autoload

Blade caches compiled views aggressively. Stale compiled views are the #1 cause of "the macro works in tinker but not in the browser."

Discovery can silently skip in CI/production. composer install --no-dev with an optimized autoloader is the usual culprit when it works locally but not on deploy. php artisan package:discover is the diagnostic.

Debug the compiled output, not the template. storage/framework/views/*.php shows what the directive actually compiled to — fastest way to catch a directive that emits nothing, double-escapes, or produces malformed attributes.

Watch out for macros in non-Blade contexts. Form markup reused in mail templates, PDF generation, or API error rendering won't get the same treatment. Keep those on native markup so you don't get two diverging form dialects.

If you're overruled and must install it: vendor and pin. Use a path repository or private fork at an exact commit SHA. Never let a Packagist resolution sit directly on the form-rendering path of a production app.

Budget review time as real task effort. Absorbing the macro contract takes an afternoon. Inspecting the emitted HTML — escaping, error classes, aria-invalid, label/id association, required and autocomplete attributes — is the expensive part. Schedule it explicitly; it doesn't happen as background QA.

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.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
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
cgv/localized-resource