Overview
The ViewPlugin automatically registers view namespaces for your modules, allowing you to reference module views using the module-name::view.name syntax.
How It Works
The plugin discovers the resources/views directory in each module and registers it as a view namespace with Laravel’s view factory.
Discovery Process
- Find View Directories: Locates
resources/views directories in all modules
- Register Namespaces: Registers each directory with the module’s name as the namespace
- Integration: Works seamlessly with Laravel’s view system
Source Code
public function discover(FinderFactory $finders): iterable
{
return $finders
->viewDirectoryFinder()
->withModuleInfo()
->values()
->map(fn(ModuleFileInfo $dir) => [
'namespace' => $dir->module()->name,
'path' => $dir->getRealPath(),
]);
}
public function handle(Collection $data)
{
$data->each(fn(array $d) => $this->factory->addNamespace($d['namespace'], $d['path']));
}
Expected Module Structure
app-modules/
blog/
resources/
views/
posts/
index.blade.php
show.blade.php
create.blade.php
layouts/
app.blade.php
Activation
The plugin uses the AfterResolving attribute to activate after Laravel’s view factory is resolved:
#[AfterResolving(ViewFactory::class, parameter: 'factory')]
class ViewPlugin extends Plugin
{
public function __construct(
protected ViewFactory $factory,
) {
}
}
Usage Examples
Rendering Views
// In a controller
public function index()
{
return view('blog::posts.index', [
'posts' => Post::all(),
]);
}
// Return specific view
public function show(Post $post)
{
return view('blog::posts.show', compact('post'));
}
In Blade Templates
{{-- Include a module view --}}
@include('blog::posts.card', ['post' => $post])
{{-- Extend a module layout --}}
@extends('blog::layouts.app')
@section('content')
<h1>Blog Post</h1>
@endsection
{{-- Use view composer --}}
@each('blog::posts.card', $posts, 'post')
In Routes
Route::get('/posts', function () {
return view('blog::posts.index');
});
Route::view('/about', 'blog::pages.about');
Checking View Existence
if (view()->exists('blog::posts.custom')) {
return view('blog::posts.custom');
}
return view('blog::posts.default');
View Namespace Priority
When a view is requested, Laravel checks:
- Module’s
resources/views directory (registered by this plugin)
- Application’s
resources/views/vendor/{module} directory (for customization)
This allows you to override module views in your main application:
resources/
views/
vendor/
blog/
posts/
index.blade.php # Overrides module's index view
Integration with Blade Components
Module views work alongside Blade components. The BladePlugin handles component registration separately:
{{-- Use a module's traditional view --}}
@include('blog::posts.card')
{{-- Use a module's Blade component --}}
<x-blog::post-card :post="$post" />
View namespaces are registered automatically when modules are discovered. No manual configuration is required.
View Composers
You can register view composers for module views in your module’s service provider:
namespace Modules\Blog\Providers;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
use Modules\Blog\View\Composers\PostComposer;
class BlogServiceProvider extends ServiceProvider
{
public function boot(): void
{
// Compose specific view
View::composer('blog::posts.index', PostComposer::class);
// Compose all views in namespace
View::composer('blog::*', function ($view) {
$view->with('siteName', 'My Blog');
});
}
}
See Also