In this video, I talked about how we use Filament over at Unipage for our marketing website.
I've gotten a couple of requests to open-source the template, and here we are.
Clone the repository and run the following commands:
# Install dependencies
composer install
# Migrate the database & fill it with data
php artisan migrate
# Create a first user
php artisan filament:user
Visit /admin and log in with the user you just created. Now you can manage pages & articles in the Filament admin panel.
Blocks are a way to create reusable components that can be added to pages.
We have a dynamic Renderer component that can render any block that is added to the Components/blocks
directory.
Using a glob Vite is able to load all the blocks and make them available to render:
// Template
<component :is="getComponent(section.type)" :data="section.data" />
// Script
const blocks = import.meta.glob('./blocks/*.vue', { eager: true });
const makeComponent = (name) => {
return blocks[`./blocks/${name}.vue`].default;
}
const getComponent = (type) => {
const component = capitalize(snakeToCamel(type));
return makeComponent(component);
}
If you want to create a new block, eg. a Youtube block, you can create a new file in the Components/blocks
directory called YoutubeSection.vue
:
<template>
<div>
<iframe width="560" height="315" :src="props.data.url" frameborder="0" allowfullscreen></iframe>
</div>
</template>
<script setup>
const props = defineProps({
data: Object,
})
</script>
Next up, create a new block in the Filament/Blocks/RichContentBlocks directory:
<?php
namespace App\Filament\Blocks\RichContentBlocks;
use App\Filament\Blocks\BaseBlock;
use Filament\Forms;
use Filament\Forms\Form;
class YoutubeSection extends BaseBlock
{
static function schema(Form $form)
{
return [
Forms\Components\TextInput::make('url'),
];
}
}
And that should be it! If you add a YouTube section on a page, it should render this block.
No need to register it in the Renderer component nor in the RichContent BlockGroup, it will be picked up automatically.
KeyValue in Filament only allows for strings to be added, but we found this was a bit too limiting. In this template, a Setting is an eloquent model with a key/value and a group. In Filament, the value of the setting is mapped to a single block, and in the code you can access the setting as follows:
In PHP:
c('routes.blog'); // 'Routes' is the group, 'blog' is the key
In Vue:
<template>
<pre>$page.props.globals.routes.blog</pre>
</template>
<script setup>
import {usePage} from "@inertiajs/vue3";
const blog = usePage().props.globals.routes.blog;
</script>
You can configure 'defaults' in the Config model, and when you deploy the website it's important these defaults get copied over to the database so you can customize them in Filament. In your deploy script, add the following command:
php artisan app:ensure-default-settings
This starter kit is able to use the AWS serverless image handler to resize images on the fly. Set up this service by following the steps outlined here: https://aws.amazon.com/solutions/implementations/serverless-image-handler/
To activate the service, add the following environment variables to your .env
file:
# Configure S3 as the filesystem for the images
FILESYSTEM_DISK=s3
FILAMENT_FILESYSTEM_DISK=s3
# Configure AWS credentials
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...
AWS_DEFAULT_REGION=... # The region where your S3 bucket is deployed
AWS_BUCKET=... # The name of the S3 bucket
AWS_BUCKET_ROOT=... # The root folder in the S3 bucket where the images are stored, e.g. "images"
AWS_USE_PATH_STYLE_ENDPOINT=false
# The following variables are used by the frontend and should be added to .env
VITE_AWS_DEFAULT_REGION="${AWS_DEFAULT_REGION}"
VITE_AWS_BUCKET="${AWS_BUCKET}"
VITE_AWS_BUCKET_ROOT="${AWS_BUCKET_ROOT}"
VITE_CDN_URL=... # The URL of the CloudFront distribution that serves the images
And that's it, images uploaded to S3 will now be served through your serverless image handler.
resources/js/Helpers/Asset.js
is responsible for generating the URLs for the images, as the URL needs to be base64 encoded.
This starter kit is set up to use SSR with Laravel's Inertia.js.
Simply run:
yarn build
php artisan inertia:ssr
And you should be good to go.
This template uses https://github.com/spatie/laravel-sitemap to generate sitemaps, refer to the docs there.
This template uses https://github.com/spatie/laravel-responsecache to cache the entire response coming from a controller. By default, it is incompatible with Inertia, hence we created an InertiaAwareCacheProfile. Using this profile, the library is able to create 2 cached versions per page:
- An HTML representation (first visit)
- A JSON representation (subsequent visit using Inertia)
When pages/posts/settings are updated, we need to clear the cache 2 times (JSON + HTML) as seen here: https://github.com/SabatinoMasala/filament-marketing-starter/blob/0fb1b3bdbb4d6d325e31d23ab88ec413e5cb9888/app/Models/Page.php#L23-L24
Other than that, it's best practice to clear the entire cache when doing a deploy, so the new assets (js, css, images) are correctly loaded.
Feel free to send a PR to add your project to the list.