log1x/sage-directives
Sage Directives adds a collection of handy Laravel Blade directives to Sage 10 WordPress themes—@role, @user, @post, @loop, @title, @thumbnail, @svg and more—letting you write cleaner templates with familiar WordPress and Laravel helpers instead of verbose PHP.
log1x/sage-directives is a companion package for Sage 10/11 + Acorn themes. It is not a general-purpose Laravel package — the asset directives resolve through Sage's manifest (Bud/Vite) and the WordPress directives call WP/ACF functions — so treat it as "Blade ergonomics for WordPress" rather than something you'd drop into a vanilla Laravel app.
Minimal steps:
composer require log1x/sage-directives from the theme directory (Acorn auto-discovers the service provider).yarn build / yarn dev) so a manifest exists — the asset directives will fail loudly otherwise.resources/views/*.blade.php.{{-- before --}}
<img src="{{ get_theme_file_uri('resources/images/hero.jpg') }}" alt="Hero" class="w-full">
{{-- after --}}
@image('images/hero.jpg', 'Hero', ['class' => 'w-full'])
Where to look first:
@asset, @svg, @image, @js, @jsdelivr, @style, @inline, @wphead, @wpfooter, @query/@endquery, @loop/@endloop, @posts/@endposts, and the ACF family @field, @sub, @group, @hasfield, @repeater, @options, @shortcode).vendor/log1x/sage-directives/src/Directives/ — one class per directive, which is the fastest way to confirm a signature when the README is thin.Asset pipeline first. Use @asset for anything hashed through the manifest, @js/@style for enqueued bundles, and @inline when you need the file's contents (critical CSS, sprite sheets). Keeping these in Blade beats sprinkling get_theme_file_uri() / asset() calls through templates.
@style('app.css')
@js('app.js')
@inline('resources/styles/critical.css') {{-- inlined into the document --}}
Images and icons. @svg() inlines a file from resources/images, which lets you style icons with Tailwind currentColor instead of shipping a sprite:
@svg('images/icons/chevron-down.svg', 'w-4 h-4 text-gray-500')
@image() takes (path, alt, options) where options are extra HTML attributes:
@image('images/card.jpg', $post->post_title, [
'class' => 'rounded-lg',
'loading' => 'lazy',
'data-src' => $cdnUrl,
])
As of v2.0.7, the options array tolerates empty strings, variables, and function calls in values — previously the option parsing could choke on these, which meant people worked around it with raw <img> tags or @php blocks. If you have any of those workarounds, they can be cleaned up.
WordPress loops as Blade blocks. @query/@endquery plus @loop/@endloop keep control flow readable and avoid while (have_posts()) in templates. Pair with @posts for secondary queries and the_field-style directives for ACF.
ACF composition. The ACF directives nest naturally — @group → @sub, @repeater → @sub — and @hasfield/@endhasfield guards are how you avoid have_rows() boilerplate. Prefer these over get_field() inside @php blocks; they read like the field schema.
Component boundary. Directives compose fine inside anonymous Blade components and @included partials, since they compile to plain PHP emitted at render time. Pass directive output into components as props where you want the escaping rules to live in one place.
{{ }} — {{ @svg(...) }} will render a compiled string. Use {!! !!} only if you are wrapping something that itself returns markup.@asset/@js/@style read the built manifest. A fresh clone with no dist/ is the #1 cause of "file not found" style errors in CI or on a teammate's machine — add a build step before any view:cache in deploy scripts.storage/framework/views. If a directive change doesn't appear, clear compiled views (wp acorn view:clear, or delete the compiled files) before debugging the package.Blade::directive('image', ...) will shadow the package's; grep before naming your own.@svg vs @asset roots differ. @svg reads from resources/images (source files), while @image/@asset go through the manifest (built output). Mixing them up produces "file exists but directive can't find it".@hasfield or @if (function_exists('get_field')).src/Directives; for project-specific behavior, prefer registering your own Blade::directive in a service provider over forking, and keep custom directives in a dedicated provider so the package can be upgraded freely.@image option parsing (empty strings, variables, function calls) plus a docs typo fix. No breaking changes, no deprecations — a drop-in from 2.0.6. The only behavior change you might notice is that templates which previously fell back to raw markup for dynamic @image options can now use the directive directly.How can I help you explore Laravel packages today?