Rewriting
Template Refactoring Recipes
Use Forte's built-in rewrite passes to apply common Blade refactorings. Each recipe includes the transformation code and its before-and-after output.
#Renaming Components
When migrating to a new component library, you often need to rename component tags across your entire project. The RenameTag pass handles this for both HTML elements and Blade components:
<?php
use Forte\Facades\Forte;
use Forte\Rewriting\Passes\Elements\RenameTag;
$blade = <<<'BLADE'
<x-button type="submit">Save</x-button>
<x-button variant="danger">Delete</x-button>
BLADE;
$doc = Forte::parse($blade);
$result = $doc->apply(new RenameTag('x-button', 'x-ui-button'));
$result->render();
// '<x-ui-button type="submit">Save</x-ui-button>'
// '<x-ui-button variant="danger">Delete</x-ui-button>'
Wildcard patterns let you rename groups of components at once. For example, renaming all x-form-* components to x-ui-form-*:
<?php
use Forte\Facades\Forte;
use Forte\Rewriting\Passes\Elements\RenameTag;
$blade = '<x-form-input name="email" />';
$doc = Forte::parse($blade);
$result = $doc->apply(new RenameTag('x-form-*', fn ($tag) => str_replace('x-form-', 'x-ui-form-', $tag)));
$result->render(); // '<x-ui-form-input name="email" />'
#Migrating CSS Classes
When switching CSS frameworks or updating design tokens, you need to add or remove classes across many templates.
#Adding Utility Classes
The AddClass pass adds a class to every matching element. Use it to apply consistent spacing, typography, or other utility classes:
<?php
use Forte\Facades\Forte;
use Forte\Rewriting\Passes\Elements\AddClass;
use Forte\Rewriting\RewritePipeline;
$blade = <<<'BLADE'
<h1>Welcome</h1>
<p>Hello, world.</p>
BLADE;
$doc = Forte::parse($blade);
$result = $doc->apply(
new RewritePipeline(
new AddClass('h1', 'text-3xl font-bold'),
new AddClass('p', 'text-gray-600'),
)
);
$result->render();
// '<h1 class="text-3xl font-bold">Welcome</h1>'
// '<p class="text-gray-600">Hello, world.</p>'
#Swapping Classes
Combine RemoveClass and AddClass in a pipeline to swap one class for another:
<?php
use Forte\Facades\Forte;
use Forte\Rewriting\Passes\Elements\AddClass;
use Forte\Rewriting\Passes\Elements\RemoveClass;
use Forte\Rewriting\RewritePipeline;
$blade = '<div class="bg-blue-500">Banner</div>';
$doc = Forte::parse($blade);
$result = $doc->apply(
new RewritePipeline(
new RemoveClass('div', 'bg-blue-500'),
new AddClass('div', 'bg-indigo-600'),
)
);
$result->render(); // '<div class="bg-indigo-600">Banner</div>'
#Updating Attributes
Attribute passes let you add, replace, or remove element attributes without rebuilding the surrounding template.
#Setting Attributes
The SetAttribute pass sets an attribute on matching elements. If the attribute already exists, its value is replaced:
<?php
use Forte\Facades\Forte;
use Forte\Rewriting\Passes\Elements\SetAttribute;
$blade = '<img src="/photo.jpg">';
$doc = Forte::parse($blade);
$result = $doc->apply(new SetAttribute('img', 'loading', 'lazy'));
$result->render(); // '<img src="/photo.jpg" loading="lazy">'
#Removing Deprecated Attributes
The RemoveAttributes pass strips attributes from matching elements. Use it to clean up deprecated or unnecessary attributes:
<?php
use Forte\Facades\Forte;
use Forte\Rewriting\Passes\Elements\RemoveAttributes;
$blade = '<div style="color: red" onclick="alert(1)">Content</div>';
$doc = Forte::parse($blade);
$result = $doc->apply(new RemoveAttributes('div', ['style', 'onclick']));
$result->render(); // '<div>Content</div>'
#Restructuring Templates
Structural passes change element boundaries while preserving the content you want to keep.
#Wrapping Elements
The WrapElements pass wraps matching elements in a container. This is useful for adding layout wrappers:
<?php
use Forte\Facades\Forte;
use Forte\Rewriting\Passes\Elements\WrapElements;
$blade = <<<'BLADE'
<img src="/hero.jpg" alt="Hero">
<h1>Welcome</h1>
BLADE;
$doc = Forte::parse($blade);
$result = $doc->apply(
new WrapElements('img', 'figure', ['class' => 'hero-figure'])
);
$result->render();
// '<figure class="hero-figure"><img src="/hero.jpg" alt="Hero"></figure>'
// '<h1>Welcome</h1>'
#Unwrapping Elements
The UnwrapElements pass does the opposite: it removes the matched wrapper and promotes its children. Use it to flatten unnecessary nesting:
<?php
use Forte\Facades\Forte;
use Forte\Rewriting\Passes\Elements\UnwrapElements;
$blade = '<div class="wrapper"><p>Content</p></div>';
$doc = Forte::parse($blade);
$result = $doc->apply(new UnwrapElements('div'));
$result->render(); // '<p>Content</p>'
#Refactoring Directives
Directive passes update Blade control structures while keeping their opening and closing tokens synchronized.
#Renaming Directives
The RenameDirective pass renames both standalone directives and block directive pairs. It handles the closing directive automatically:
<?php
use Forte\Facades\Forte;
use Forte\Rewriting\Passes\Directives\RenameDirective;
$blade = <<<'BLADE'
@can('edit')
<button>Edit</button>
@endcan
BLADE;
$doc = Forte::parse($blade);
$result = $doc->apply(new RenameDirective('can', 'ability'));
$result->render();
// '@ability(\'edit\')'
// ' <button>Edit</button>'
// '@endability'
#Removing Directives
The RemoveDirective pass removes matching directives from the template. For block directives, both the opening and closing tags and all content between them are removed:
<?php
use Forte\Facades\Forte;
use Forte\Rewriting\Passes\Directives\RemoveDirective;
$blade = <<<'BLADE'
<nav>Menu</nav>
@auth
<p>Welcome back!</p>
@endauth
BLADE;
$doc = Forte::parse($blade);
$result = $doc->apply(new RemoveDirective('auth'));
$result->render(); // '<nav>Menu</nav>'
For inline directives, only the directive itself is removed:
<?php
use Forte\Facades\Forte;
use Forte\Rewriting\Passes\Directives\RemoveDirective;
$blade = '<div>@include("sidebar")<p>Content</p></div>';
$doc = Forte::parse($blade);
$result = $doc->apply(new RemoveDirective('include'));
$result->render(); // '<div><p>Content</p></div>'
#Multi-Step Refactoring Pipelines
For complex migrations, combine multiple passes into a single RewritePipeline. The pipeline applies each pass in order, and each subsequent pass sees the output of the previous one:
<?php
use Forte\Facades\Forte;
use Forte\Rewriting\Passes\Elements\AddClass;
use Forte\Rewriting\Passes\Elements\RenameTag;
use Forte\Rewriting\Passes\Elements\SetAttribute;
use Forte\Rewriting\RewritePipeline;
$blade = <<<'BLADE'
<b>Important</b>
<i>Note</i>
BLADE;
$doc = Forte::parse($blade);
$result = $doc->apply(
new RewritePipeline(
new RenameTag('b', 'strong'),
new RenameTag('i', 'em'),
new AddClass('strong', 'font-bold text-red-600'),
new SetAttribute('em', 'role', 'note'),
)
);
$result->render();
// '<strong class="font-bold text-red-600">Important</strong>'
// '<em role="note">Note</em>'
Because RewritePipeline itself implements AstRewriter, pipelines can be nested or composed with other rewriters. You can also add steps incrementally using the add method:
<?php
use Forte\Rewriting\Passes\Elements\AddClass;
use Forte\Rewriting\Passes\Elements\RenameTag;
use Forte\Rewriting\RewritePipeline;
$pipeline = new RewritePipeline;
$pipeline->add(new RenameTag('b', 'strong'));
$pipeline->add(new AddClass('strong', 'font-bold'));
$pipeline->count(); // 2
#Applying Transformations to Files
To refactor templates on disk, use Forte::parseFile to load a file with its path metadata, transform it, then write the result back:
<?php
use Forte\Facades\Forte;
use Forte\Rewriting\Passes\Elements\AddClass;
use Forte\Rewriting\RewritePipeline;
use Illuminate\Support\Facades\File;
$pipeline = new RewritePipeline(
new AddClass('table', 'min-w-full divide-y divide-gray-200'),
new AddClass('th', 'px-6 py-3 text-left text-xs font-medium text-gray-500'),
new AddClass('td', 'px-6 py-4 whitespace-nowrap'),
);
$files = File::glob(resource_path('views/**/*.blade.php'));
foreach ($files as $file) {
$doc = Forte::parseFile($file);
$result = $doc->apply($pipeline);
File::put($file, $result->render());
}
Always back up your templates or commit to version control before running batch transformations. The render method reproduces the original source faithfully for untouched nodes, but you should review the output to verify correctness.
#See Also
Continue with these related Forte guides:
- Rewrite Passes: Full API reference for all built-in passes
- Rewriters: Write custom rewriters for transformations beyond the built-in passes
- Enclaves: Apply transformations automatically to specific parts of your application
- Documents: The Document API for parsing and rendering templates