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

Aloia Cms Laravel Package

roelofjan-elsinga/aloia-cms

Aloia CMS is a lightweight flat-file CMS for Laravel. Manage pages and blog posts as Markdown files on disk with no database required, using a built-in admin panel, a simple content API, image handling, and easy customization for small sites and blogs.

View on GitHub
Deep Wiki
Context7

Getting Started

Aloia CMS is a flat-file CMS: there is no database, no admin scaffolding to build, and no Eloquent models to migrate. Content lives as .blade.md files inside your resources/views tree, which means your content and your templates are the same artefacts — a page file can @extends a layout, use Blade components, and still be edited by a non-developer through the bundled dashboard.

Minimum steps:

composer require roelofjan-elsinga/aloia-cms
php artisan vendor:publish --provider="RoelofJan\AloiaCms\AloiaCmsServiceProvider"

Then create your first page. A file at resources/views/pages/about.blade.md is served at /about; index.blade.md is served at /. The filename is the slug — there is no route file to edit.

---
title: About
description: Who we are
---
@extends('layouts.app')

@section('content')
# About us

We build **things**.
@endsection

Where to look first, in order:

  1. config/aloia-cms.php — the paths for pages, posts, categories, tags, menus, images and form submissions, plus the dashboard toggle. This is the file that determines whether the package fits your project.
  2. resources/views/pages — the content tree and therefore the sitemap. Directory nesting maps to URL nesting.
  3. The dashboard route (enabled by default and reachable from the browser) — this is what you demo to the client; confirm how it's authenticated before anything else.
  4. RoelofJan\AloiaCms\Models\{Page,Post,Category,Tag,Menu,Image,FormSubmission} — the read APIs you'll call from your own Blade views and controllers.

The first use case to reach for is a small brochure/marketing site or a blog for a single client where the copy changes weekly but the structure doesn't. You get a client-editable site in an afternoon with zero schema design, and the content is versioned in git alongside the code.

Implementation Patterns

One layout, many pages. Keep resources/views/layouts/app.blade.php as the only chrome. Every .blade.md page extends it and fills a section. This is the main advantage over a database CMS: pages are views, so @include, @foreach, components and directives all work inside authored content without a shortcode layer.

Listing dynamic content from a static page. Your blog index is just a page that queries the package's models:

@foreach (\RoelofJan\AloiaCms\Models\Post::published() as $post)
    <a href="{{ $post->url() }}">{{ $post->title() }}</a>
    <time>{{ $post->date() }}</time>
@endforeach

Treat these model calls as you would a repository: they hit the filesystem, so wrap them once in a small view composer or a Blog helper class rather than sprinkling model calls through templates. That gives you one place to add sorting, filtering by category/tag, and caching.

Hand-rolled pagination. There is no query builder to paginate. Collect the posts, slice them, and wrap in LengthAwarePaginator:

$posts = Post::published()->sortByDesc(fn ($p) => $p->date())->values();
$page = (int) request('page', 1);
$paginator = new LengthAwarePaginator(
    $posts->forPage($page, 10), $posts->count(), 10, $page,
    ['path' => request()->url()]
);

Taxonomy pages. Categories and tags are their own file-backed collections. Create /blog/category/{slug} style routes in your own routes/web.php that look up the category and filter posts by it — the package gives you the data, not the routes, for archives.

Forms. Post to the package's submission endpoint rather than building storage. Submissions land as files (and in the dashboard), and you read them back with FormSubmission::all(). This is the cheapest "contact us" implementation you'll ever ship, but decide early whether you want to be notified by email — file-backed submissions don't notify anyone, so wire a scheduled command or a Notification that polls for new files.

Menus for navigation. Define navigation once in a menu file and render it in the layout so pages and posts share the same nav with active-state logic. Avoid hardcoding nav links in the layout; that's the first thing clients ask you to change.

Deployment pattern for dashboard edits. Two workable models, pick one deliberately:

  • Content-as-code: editors work locally or in staging, content is committed, production is read-only. Simplest and most reliable; disable the dashboard in production.
  • Content-on-server: the dashboard is live in production, so the content directory must survive deploys. Symlink it out of releases/ into shared/ and point the config paths at the shared directory. Never let deploy:optimize or a fresh clone overwrite it.

Coexisting with your app's routes. Package routes and your own need an agreed order. Keep your application routes (auth, checkout, API) registered before the package's catch-all page resolution, and wrap the package's routes in the same middleware group as the rest of the site so sessions and locale carry through.

Caching. Pages are cheap but not free. Put response caching (or a static site generator) in front of the public routes, and include php artisan view:clear in your deploy script — compiled views of .blade.md files go stale otherwise.

Gotchas and Tips

  • Secure the dashboard before you do anything else. It is the highest-value target in the whole package. Confirm exactly which middleware protects it, put it behind an auth guard and an authorization gate, and only then put it in front of a client. Verify by hitting the route in an incognito window.
  • Route caching can hide new content. Page routes are derived from the filesystem. If routes are cached, files added later won't be reachable until the cache is rebuilt. Either clear route cache on deploy and after dashboard edits, or don't cache routes on content-heavy installs.
  • Blade compiles before Markdown, so @ and {{ }} in content bite. A literal email address or a Twitter handle in a post will throw a compile error or get eaten. Use @verbatim blocks or escape with @@ and {{ '@' }}. This is the single most common "the CMS is broken" report you'll get from an editor.
  • Renaming a file is a URL change. Slugs come from filenames, so a rename silently 404s every inbound link. Keep a redirects list (a config array or a small middleware) from day one, not after the first SEO complaint.
  • No revisions, no locks. Two editors saving the same file means last-write-wins with no warning, and the previous version only exists if it was committed. If more than one person edits regularly, put content in git and treat the dashboard as a convenience for one editor at a time.
  • YAML front matter quirks. Colons in titles need quoting, dates need a consistent format, and booleans like published: false are parsed by YAML, not PHP — published: "false" is a truthy string. Standardise on a front-matter template per content type.
  • Drafts are a flag, not a workflow. Publishing is a front-matter boolean; there's no preview URL, no scheduling, no editorial approval. If the client asks for those, that's the point to reconsider the tool.
  • Images are just files. No resizing, no responsive variants, no CDN. Serve them through your own intervention/CDN layer or accept the payload cost — a client uploading 4 MB phone photos straight into a page is the default outcome.
  • Scale ceilings. Every listing reads and parses files from disk. Fine at tens or low hundreds of posts; noticeable at thousands, and there's no full-text search. Cache aggressively and don't build a 5,000-post blog on it.
  • No multi-language story. The path-based content model makes i18n a manual convention (parallel directories, locale in front matter). If the project is bilingual at launch, budget for it explicitly.
  • Small-project risk. One maintainer, a modest user base, and version-to-version API drift on model method names and config keys. Pin the version in composer.json, read the changelog before upgrading, and keep your usage of the models behind a thin wrapper class so a breaking rename is a one-file fix.
  • Extension points worth knowing: configurable content paths (the key to the shared-directory deploy), custom front-matter fields (just read them off the model), and your own Blade layouts/components inside content files — that last one is where this package actually outperforms a database CMS, so lean on it for design-heavy marketing pages.
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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo