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

Base Laravel Package

typicms/base

TypiCMS Base is the core foundation for TypiCMS, a modular, multilingual content management system built on Laravel. It provides shared CMS infrastructure, localization, and module support for building flexible, maintainable websites.

View on GitHub
Deep Wiki
Context7

Getting Started

TypiCMS is a modular CMS, and typicms/base is the core package that every site depends on. You rarely install typicms/base into an existing Laravel app by hand — the normal entry point is the project skeleton (composer create-project typicms/typicms) which pulls in the base package alongside a set of first-party modules (pages, news, events, projects, galleries, contacts, blocks).

Minimal boot sequence:

composer create-project typicms/typicms my-site
cd my-site
cp .env.example .env
php artisan key:generate
# configure DB_*, then:
php artisan typicms:install   # publishes config, runs migrations, seeds roles/admin user
php artisan storage:link
php artisan serve

The install command is the single most important thing to run — without it you get a bare Laravel app with a config/typicms.php but no tables, no admin role, and no seeded admin account. Log in at /admin with the seeded user.

Where to look first, in this order:

  1. config/typicms.php — the contract for the whole system. The keys you will touch daily are locales (a code => label map), fallback_locale, template (which Blade layout/theme the public side renders), per_page, and the module list that decides which modules are actually mounted.
  2. Modules/ (or vendor/typicms/* if not yet published) — each module is a self-contained mini-app: Models/, Repositories/, Http/Controllers/{Admin,Public}, Http/Requests, resources/views/{admin,public} and its own routes.php / admin.php.
  3. TypiCMS\Modules\Core\Models\Traits — HasTranslations, Sluggable, Publishable, Positionable, HasMedias, HasFiles, Tag. Almost every "how do I make my model behave like a TypiCMS model" question is answered here.
  4. routes/web.php in the skeleton, plus the TypiCMS facade — the frontend router and the TypiCMS::pages() / TypiCMS::menus() helpers.

First use case: create a Page in /admin, then render it. TypiCMS deliberately keeps the public rendering in your Blade files, so a first win is dropping this into resources/views/default/page.blade.php:

<article>
    <h1>{{ $page->title }}</h1>
    {!! $page->present()->body !!}
</article>

That single line teaches you the two central conventions: translated attributes are accessed as plain properties (locale-resolved), and rich content is rendered through a presenter, not echoed raw.

Implementation Patterns

The module is the unit of work. Every feature in TypiCMS is a module, and the framework's conventions only make sense once you internalise the anatomy:

Modules/News/
├── Models/News.php
├── Models/NewsTranslation.php
├── Repositories/NewsRepository.php            # interface + Eloquent impl
├── Http/Controllers/Admin/NewsController.php
├── Http/Controllers/Public/NewsController.php
├── Http/Requests/NewsRequest.php
├── resources/views/admin/{index,form}.blade.php
├── resources/views/public/{index,show}.blade.php
├── routes.php                                 # frontend routes
├── admin.php                                  # admin routes (auto-prefixed)
└── Providers/NewsServiceProvider.php

When you need a custom content type (say, "Jobs"), do not invent a parallel structure. Duplicate the News module, rename namespaces/tables/routes, register it in config/typicms.php, and you inherit admin CRUD, translation UI, media attachment, publishing, positioning, and search indexing for free. This is the single highest-leverage pattern in the package.

Multilingual content is table-per-model. Translations live in a sibling *_translations table; the model declares public $translatedAttributes = ['title', 'slug', 'body', 'status'] and uses HasTranslations. Day-to-day this means:

$news->title;                              // current locale, with fallback
$news->translate('fr')->title;             // explicit locale
$news->getTranslation('body', 'en');       // without mutating current locale
$news->saveTranslation(['title' => '...'], 'fr');

URLs are locale-scoped and slugged per locale, so route definitions go through the TypiCMS:: helpers rather than hardcoded paths — /fr/nouvelles/mon-article and /en/news/my-article resolve to the same row.

Thin controllers, fat repositories. Admin controllers extend BaseAdminController and mostly delegate. If you need custom filtering, override $repository->getById() or add a query scope on the model — pushing query logic into the controller breaks pagination, search, and the JSON/API responses the admin grid expects.

Publishing and scheduling is a trait, not a boolean. Add the Publishable trait + status, start_date, end_date columns and TypiCMS handles "draft / published / scheduled" in both the admin UI and all public queries. You never need to filter where('status', 'published') yourself on the public side.

Media and files. HasMedias / HasFiles give you polymorphic attachments. Attach in admin, read in Blade:

$model->medias;                 // collection, ordered by position
$model->image();                // first media as an image helper/URL
$model->files;                  // downloadable documents

Menus, blocks and settings are shared services. Instead of hardcoding navigation, seed a Menu and render it:

@foreach (TypiCMS::menus() as $menu)
    @include('core::public._menu', ['menu' => $menu])
@endforeach

Settings similarly: setting('site_title') or via the facade, cached per request and cleared on save.

Integration tips.

  • Publish views before editing: php artisan vendor:publish --tag=views (check --tag names per module). TypiCMS resolves Modules/Foo/resources/views before the vendor copy, so overriding is a matter of creating the file in the right place.
  • Use model observers rather than controller hooks — the package itself uses them for cache invalidation, search indexing, and slug generation.
  • If you add a field to an existing module, remember three places: migration, $translatedAttributes (or $fillable for non-translated), and the admin form partial. Miss the second and the field silently never persists.
  • Expose JSON by adding an API route that returns $model->toArray() — translations are included automatically when $translatedAttributes is set.

Gotchas and Tips

Module registration is config, not filesystem. A module folder sitting on disk does nothing until it appears in config/typicms.php (and in composer.json autoload/modules_statuses for module-manager based versions). Symptom: "my routes return 404 but the model works in tinker."

Config and route caching will bite you. After editing config/typicms.php, adding a module, or changing locales, run:

php artisan config:clear && php artisan route:clear && php artisan view:clear
php artisan cache:clear

The response cache (keyed by URL + locale) and the search index both survive a simple page refresh, so a change that "isn't showing up" is almost always a cache, not a bug.

Slugs don't regenerate on rename. TypiCMS generates the slug once from the title when it's empty. Renaming a published page leaves the old URL intact — usually correct, occasionally infuriating. Override generateSlug() on the model if you need different behaviour, and be aware per-locale slugs mean a rename in English doesn't affect the French URL.

Fallback locale is silent. With fallback_locale set, a missing French translation renders the English text rather than an empty string. This is great for launch, bad for QA — check $model->hasTranslation('fr') or $model->translation('fr') when you need to distinguish.

Migrations are published, not versioned per-app. typicms:install copies package migrations into database/migrations. Re-running it or upgrading the base package can produce duplicate table errors. On upgrades: diff the published migrations against the vendor ones, don't blindly migrate:fresh in anything resembling production.

Uploads need the storage symlink. Media and file fields will "save" but render broken images if php artisan storage:link hasn't run, or if FILESYSTEM_DISK differs from what the HasMedias trait expects. Also check config/filesystems.php public disk URL — TypiCMS historically assumed /storage.

Admin access is role-gated. A user exists but sees a 403 on /admin: check the role/permission assignment, not the auth guard. The seeded admin is the only superuser — creating a second admin from tinker requires attaching the role explicitly.

Debugging tips.

  • TypiCMS::getPage() / TypiCMS::pages() are the fastest way to inspect what the router resolved on the public side.
  • Enable query logging around BaseRepository calls — the biggest N+1 source is translations and medias. Eager load with ->with('translations', 'medias').
  • When an admin form field doesn't appear, check the *Request class rules() and the form partial — the base form builder renders from the request's field map in some versions.

Extension points, ranked by safety:

  1. Publish and override views/module config (zero risk).
  2. Model observers and custom repositories (low risk).
  3. Your own module cloned from an existing one (medium risk — you own the upgrade path).
  4. Editing vendor/typicms/* (don't; the next composer update erases it).

Version pinning matters more than usual here. Releases are infrequent, and the base package's Laravel constraint moves with them. Pin typicms/base and all typicms/* modules to compatible versions together, and read the changelog before a minor bump — module/base mismatches are the most common source of "works in staging, white screen in prod."

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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource