PHPackages                             idoneo/cms-core - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. idoneo/cms-core

ActiveLibrary[Framework](/categories/framework)

idoneo/cms-core
===============

Multi-tenant CMS foundation with Teams support, Livewire components and Filament integration for Laravel.

v2.0.0(4mo ago)051AGPL-3.0-or-laterPHPPHP ^8.2

Since Dec 8Pushed 4mo agoCompare

[ Source](https://github.com/diego-mascarenhas/cms-core)[ Packagist](https://packagist.org/packages/idoneo/cms-core)[ Docs](https://github.com/diego-mascarenhas/cms-core)[ RSS](/packages/idoneo-cms-core/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (16)Versions (38)Used By (0)

CMS-Core
========

[](#cms-core)

[![Latest Version on Packagist](https://camo.githubusercontent.com/89b91a49f85545513b486ef0c6a705cb7ab8fa3f518fdc3611e85a01ca664165/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f69646f6e656f2f636d732d636f72652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/idoneo/cms-core)[![Total Downloads](https://camo.githubusercontent.com/610b9dc95bdc3a78f6f8e04180987cef6a177480f2b2ccd3835ff6f587854d3d/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f69646f6e656f2f636d732d636f72652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/idoneo/cms-core)[![License](https://camo.githubusercontent.com/1fa769277cadf5961d18b9a60e38284b0a8f8c0ef0d84ba9f3ec5709cbfc75ca/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f69646f6e656f2f636d732d636f72652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/idoneo/cms-core)

Multi-tenant CMS foundation with Teams support, Livewire components and Filament integration for Laravel.

Features
--------

[](#features)

- **BelongsToCurrentTeam** trait for automatic team scoping
- **TeamSwitcher** Livewire component with alphabetical sorting
- **CmsCorePlugin** for Filament panels with user menu
- **Spatie Laravel Tags** integration for tagging and categorization
- Toggle teams feature via environment variable

Installation
------------

[](#installation)

### Create New Project

[](#create-new-project)

To create a new Laravel project with CMS-Core from scratch:

```
composer create-project laravel/laravel my-project
cd my-project
composer require idoneo/cms-core
php artisan cms-core:install --fresh --seed
npm install && npm run build
```

This will:

- Create a new Laravel project
- Install CMS-Core package (with Jetstream, Filament, Livewire, and Spatie packages)
- Configure Jetstream with Livewire + Teams
- Install Filament panel (with Spanish locale)
- Register Jetstream routes automatically (`profile.show`, `teams.show`, `teams.create`, etc.)
- Publish Spatie Permission migrations
- Publish Spatie Tags migrations
- Publish Spatie Media Library migrations
- Publish Teams migrations (included in CMS-Core)
- Publish Post model
- Publish CMS-Core config files
- Configure authentication to use Filament login
- Set application locale to Spanish
- Run all migrations
- Create admin user ( / Simplicity!)
- Install and build npm assets

### Install in Existing Project

[](#install-in-existing-project)

If you already have a Laravel project, install the package:

```
composer require idoneo/cms-core
php artisan cms-core:install --fresh --seed
npm install && npm run build
```

**Note:** The `--fresh` flag will drop all existing tables. If you want to keep your data, use:

```
php artisan cms-core:install --seed
php artisan migrate
```

### Update Existing Installation

[](#update-existing-installation)

To update CMS-Core resources (migrations, config, views, translations) in an existing project:

```
composer update idoneo/cms-core
php artisan cms-core:update
php artisan migrate
npm run build
```

**Options:**

- `--migrations`: Only publish migrations
- `--force`: Force publish even if files exist

### Manual Setup

[](#manual-setup)

If you need more control:

```
# Install dependencies
composer require idoneo/cms-core

# Install Jetstream manually
php artisan jetstream:install livewire --teams

# Publish CMS-Core assets
php artisan vendor:publish --tag="cms-core"

# Run migrations
php artisan migrate

# Build assets
npm install && npm run build
```

Register the plugin in your `AdminPanelProvider`:

```
use Idoneo\CmsCore\Filament\CmsCorePlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        ->plugin(CmsCorePlugin::make())
```

Tags System
-----------

[](#tags-system)

This package includes Spatie Laravel Tags for tagging and categorization. See [docs/TAGS.md](docs/TAGS.md) for complete documentation.

Quick example:

```
use Spatie\Tags\HasTags;
use Filament\Forms\Components\SpatieTagsInput;

class Post extends Model
{
    use HasTags;
}

// In Filament Resource
SpatieTagsInput::make('tags')
    ->label('Tags')

// For categorization
SpatieTagsInput::make('categories')
    ->type('categories')
        // ... other configuration
}
```

### Default Credentials

[](#default-credentials)

After running with `--seed` flag:

FieldValueEmail`hola@humano.app`Password`Simplicity!`Configuration
-------------

[](#configuration)

Add to your `.env` file:

```
# Show/hide teams UI features (default: false)
# Note: Users always have a personal team (Jetstream requirement)
# This setting only controls UI visibility (team switcher, create team, team settings)
APP_TEAMS=false
```

When `APP_TEAMS=false`:

- ✅ Users still have a personal team (required by Jetstream)
- ❌ Team switcher is hidden
- ❌ "Create New Team" option is hidden
- ❌ "Team Settings" option is hidden

When `APP_TEAMS=true`:

- ✅ All team features visible
- ✅ Users can create multiple teams
- ✅ Team switcher appears in user menu

### Brand Logos

[](#brand-logos)

CMS-Core automatically configures brand logos for your Filament panel if you place logo files in `public/custom/`:

**Supported files:**

- `logo-light.svg` - Logo for light mode
- `logo-dark.svg` - Logo for dark mode

**Setup:**

1. Create the `public/custom/` directory (if it doesn't exist)
2. Place your logo files: ```
    public/
    └── custom/
        ├── logo-light.svg
        └── logo-dark.svg

    ```
3. The logos will be automatically detected and configured on the next page load

**Note:** Only SVG files are supported. The plugin automatically detects and configures the logos without any additional configuration needed.

Usage
-----

[](#usage)

### BelongsToCurrentTeam Trait

[](#belongstocurrentteam-trait)

Add to models that should be scoped by team:

```
use Idoneo\CmsCore\Traits\BelongsToCurrentTeam;

class Project extends Model
{
    use BelongsToCurrentTeam;
}
```

This automatically:

- Filters queries by `current_team_id`
- Sets `team_id` on create
- Provides `forTeam()` and `withoutTeamScope()` methods

### TeamSwitcher Component

[](#teamswitcher-component)

Include in your Blade views:

```
@if(\Idoneo\CmsCore\CmsCore::teamsEnabled())

@endif
```

### Filament Plugin

[](#filament-plugin)

Register in your Panel Provider:

```
use Idoneo\CmsCore\Filament\CmsCorePlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        ->plugins([
            CmsCorePlugin::make(),
        ]);
}
```

### Helper Methods

[](#helper-methods)

```
use Idoneo\CmsCore\CmsCore;

// Check if teams are enabled
CmsCore::teamsEnabled();

// Get configured models
CmsCore::teamModel();
CmsCore::userModel();
```

### Team Roles Configuration

[](#team-roles-configuration)

After installation, configure team roles in `app/Providers/JetstreamServiceProvider.php`:

```
protected function configurePermissions(): void
{
    Jetstream::defaultApiTokenPermissions(['read']);

    Jetstream::role('admin', 'Administrator', [
        'create',
        'read',
        'update',
        'delete',
    ])->description('Administrator users can perform any action.');

    Jetstream::role('member', 'Member', [
        'read',
        'create',
        'update',
    ])->description('Members have standard access to create and manage content.');

    Jetstream::role('viewer', 'Viewer', [
        'read',
    ])->description('Viewers can only read and view content.');
}
```

These are **suggested roles** that work for most use cases. You can customize them:

- Rename roles (e.g., "member" → "employee", "student", "collaborator")
- Add new roles
- Modify permissions per role

### Panel Access Control

[](#panel-access-control)

By default, all authenticated users can access the Filament panel. To restrict access, implement `FilamentUser` in your User model:

```
use Filament\Models\Contracts\FilamentUser;
use Filament\Panel;

class User extends Authenticatable implements FilamentUser
{
    public function canAccessPanel(Panel $panel): bool
    {
        // Allow all authenticated users (default behavior)
        return true;

        // Or restrict by email domain
        // return str_ends_with($this->email, '@yourdomain.com');

        // Or use roles with Spatie Permission
        // return $this->hasRole('admin');
    }
}
```

API Documentation
-----------------

[](#api-documentation)

CMS-Core provides a RESTful API for accessing posts with authentication via Sanctum tokens.

### Authentication

[](#authentication)

All API endpoints require authentication using a Bearer token. You can generate a token in two ways:

#### Option 1: Generate Token via Artisan Command (Recommended)

[](#option-1-generate-token-via-artisan-command-recommended)

Generate a token and add it to your `.env` file:

```
# Generate token for admin user (default)
php artisan cms-core:api-token

# Or specify a user email
php artisan cms-core:api-token --email=hola@humano.app --name="API Token"
```

**Output example:**

```
API Token generated successfully!

Token Name: API Token
User: hola@humano.app

Add this to your .env file:
APP_TOKEN=1|abc123def456ghi789jkl012mno345pqr678stu901vwx234yz

⚠️  Save this token now! You won't be able to see it again.

```

**Copy the token and add it to your `.env` file:**

```
APP_TOKEN=1|abc123def456ghi789jkl012mno345pqr678stu901vwx234yz
```

**Then use it in your curl requests:**

```
# Replace YOUR_TOKEN with the token from .env
curl -X GET "http://localhost:8000/api/posts" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Accept: application/json"
```

#### Option 2: Generate Token via User Profile

[](#option-2-generate-token-via-user-profile)

Generate a token in your user profile settings at `/user/api-tokens` or via Jetstream's API token management interface.

**Headers:**

```
Authorization: Bearer {your-token}
Content-Type: application/json
Accept: application/json

```

Troubleshooting
---------------

[](#troubleshooting)

### Teams Feature Not Showing

[](#teams-feature-not-showing)

If you have `APP_TEAMS=true` in your `.env` but the teams options don't appear in the user menu, run the diagnostic command:

```
php artisan cms-core:diagnose
```

This will check:

- ✓ Config file exists
- ✓ Teams configuration (ENV, config, CmsCore helper)
- ✓ Jetstream routes registration
- ✓ Current user and team setup

**Common solutions:**

```
# 1. Clear config cache
php artisan config:clear

# 2. Verify .env has APP_TEAMS=true (no spaces)
echo "APP_TEAMS=true" >> .env

# 3. Republish config
php artisan vendor:publish --tag=cms-core-config --force

# 4. Clear cache again
php artisan config:clear

# 5. Restart server (if using php artisan serve)
```

Accept: application/json

```

**Note:** If you set `APP_TOKEN` in your `.env`, you can use that token directly. The system will automatically authenticate the user associated with that token.

#### Quick Start Example

1. **Generate a token:**
```bash
php artisan api:token --email=hola@humano.app

```

2. **Copy the output token to your `.env` file:**

```
APP_TOKEN=1|abc123def456ghi789...
```

3. **Test the API with curl:**

```
# List all published posts
curl -X GET "http://localhost:8000/api/posts" \
  -H "Authorization: Bearer 1|abc123def456ghi789..." \
  -H "Accept: application/json"

# Or use the token from .env (if you have it exported)
curl -X GET "http://localhost:8000/api/posts" \
  -H "Authorization: Bearer $APP_TOKEN" \
  -H "Accept: application/json"
```

### Endpoints

[](#endpoints)

#### List Posts

[](#list-posts)

Get a paginated list of posts with optional filters.

**GET** `/api/posts`

**Query Parameters:**

- `status` (optional): Filter by status (`draft`, `published`, `archived`). Default: `published`
- `category` (optional): Filter by category name
- `tag` (optional): Filter by tag name
- `search` (optional): Search in title, excerpt, and content
- `per_page` (optional): Number of items per page (1-100, default: 15)
- `page` (optional): Page number (default: 1)

**Example Request:**

```
# Using token from .env (APP_TOKEN)
curl -X GET "http://localhost:8000/api/posts?status=published&category=Tutorials&per_page=10" \
  -H "Authorization: Bearer $(php artisan tinker --execute='echo env(\"APP_TOKEN\");')" \
  -H "Accept: application/json"

# Or using a token directly
curl -X GET "http://localhost:8000/api/posts?status=published&category=Tutorials&per_page=10" \
  -H "Authorization: Bearer 1|your-token-here" \
  -H "Accept: application/json"

# Simple example (replace YOUR_TOKEN with your actual token)
curl -X GET "http://localhost:8000/api/posts" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Accept: application/json"
```

**Example Response:**

```
{
  "data": [
    {
      "id": 1,
      "title": "My First Post",
      "slug": "my-first-post",
      "excerpt": "This is an excerpt...",
      "content": "Full content here...",
      "status": "published",
      "published_at": "2024-01-15T10:00:00Z",
      "created_at": "2024-01-15T09:00:00Z",
      "updated_at": "2024-01-15T09:30:00Z",
      "author": {
        "id": 1,
        "name": "John Doe",
        "email": "john@example.com"
      },
      "featured_image": {
        "url": "https://...",
        "thumb": "https://...",
        "web": "https://..."
      },
      "gallery": [
        {
          "url": "https://...",
          "thumb": "https://...",
          "web": "https://..."
        }
      ],
      "categories": [
        {
          "id": 1,
          "name": "Tutorials",
          "slug": "tutorials"
        }
      ],
      "tags": [
        {
          "id": 2,
          "name": "Laravel",
          "slug": "laravel"
        }
      ]
    }
  ],
  "links": {
    "first": "https://...",
    "last": "https://...",
    "prev": null,
    "next": "https://..."
  },
  "meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 5,
    "per_page": 10,
    "to": 10,
    "total": 50
  }
}
```

#### Get Post by Slug

[](#get-post-by-slug)

Get a single post by its slug.

**GET** `/api/posts/{slug}`

**Example Request:**

```
# Using token from .env (APP_TOKEN)
curl -X GET "http://localhost:8000/api/posts/my-first-post" \
  -H "Authorization: Bearer $(php artisan tinker --execute='echo env(\"APP_TOKEN\");')" \
  -H "Accept: application/json"

# Or using a token directly
curl -X GET "http://localhost:8000/api/posts/my-first-post" \
  -H "Authorization: Bearer 1|your-token-here" \
  -H "Accept: application/json"

# Simple example (replace YOUR_TOKEN with your actual token)
curl -X GET "http://localhost:8000/api/posts/my-first-post" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Accept: application/json"
```

**Example Response:**

```
{
  "data": {
    "id": 1,
    "title": "My First Post",
    "slug": "my-first-post",
    "excerpt": "This is an excerpt...",
    "content": "Full content here...",
    "status": "published",
    "published_at": "2024-01-15T10:00:00Z",
    "created_at": "2024-01-15T09:00:00Z",
    "updated_at": "2024-01-15T09:30:00Z",
    "author": {
      "id": 1,
      "name": "John Doe",
      "email": "john@example.com"
    },
    "featured_image": {
      "url": "https://...",
      "thumb": "https://...",
      "web": "https://..."
    },
    "gallery": [],
    "categories": [],
    "tags": []
  }
}
```

### Team Scoping

[](#team-scoping)

If teams are enabled (`APP_TEAMS=true`), the API automatically filters posts by the authenticated user's current team. Users can only access posts from their current team.

### Error Responses

[](#error-responses)

**401 Unauthorized:**

```
{
  "message": "Unauthenticated."
}
```

**404 Not Found:**

```
{
  "message": "No query results for model [App\\Models\\Post] {slug}"
}
```

**422 Validation Error:**

```
{
  "message": "The given data was invalid.",
  "errors": {
    "status": ["The selected status is invalid."]
  }
}
```

### Complete cURL Examples

[](#complete-curl-examples)

Here are ready-to-use curl examples (replace `YOUR_TOKEN` with your actual token):

**List all published posts:**

```
curl -X GET "http://localhost:8000/api/posts" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Accept: application/json"
```

**List posts with filters:**

```
curl -X GET "http://localhost:8000/api/posts?status=published&category=Tutorials&search=laravel&per_page=5" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Accept: application/json"
```

**Get a specific post by slug:**

```
curl -X GET "http://localhost:8000/api/posts/my-first-post" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Accept: application/json"
```

**Filter by tag:**

```
curl -X GET "http://localhost:8000/api/posts?tag=laravel" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Accept: application/json"
```

**Pretty print JSON response (using jq):**

```
curl -X GET "http://localhost:8000/api/posts" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Accept: application/json" | jq
```

Requirements
------------

[](#requirements)

- PHP ^8.2
- Laravel ^11.0 | ^12.0
- Livewire ^3.0
- Laravel Jetstream with Teams (recommended)

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

If you discover a security vulnerability, please send an e-mail to Diego Mascarenhas Goytía via . All security vulnerabilities will be promptly addressed.

License
-------

[](#license)

Licensed under the [GNU Affero General Public License v3.0 (AGPL-3.0)](https://www.gnu.org/licenses/agpl-3.0.html).

### Additional Terms

[](#additional-terms)

By deploying this software, you agree to notify the original author at  or by visiting [linkedin.com/in/diego-mascarenhas](https://linkedin.com/in/diego-mascarenhas/). Any modifications or enhancements must be shared with the original author.

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance74

Regular maintenance activity

Popularity8

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity59

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Recently: every ~15 days

Total

36

Last Release

142d ago

Major Versions

v1.4.4 → v2.0.02026-02-11

### Community

Maintainers

![](https://www.gravatar.com/avatar/fa190334db1e228625e2df973f74328681cde2469306e3f6f7e519375e04a600?d=identicon)[idoneo](/maintainers/idoneo)

---

Top Contributors

[![diego-mascarenhas](https://avatars.githubusercontent.com/u/1038571?v=4)](https://github.com/diego-mascarenhas "diego-mascarenhas (51 commits)")

---

Tags

spatielaravelcmslivewiremulti-tenantfilamentjetstreamTeams

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/idoneo-cms-core/health.svg)

```
[![Health](https://phpackages.com/badges/idoneo-cms-core/health.svg)](https://phpackages.com/packages/idoneo-cms-core)
```

###  Alternatives

[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3914.6k](/packages/rawilk-profile-filament-plugin)[nasirkhan/laravel-starter

A CMS like modular Laravel starter project.

1.4k2.7k](/packages/nasirkhan-laravel-starter)[stephenjude/filament-jetstream

A Laravel starter kit built with Filament inspired by Jetstream.

17760.2k3](/packages/stephenjude-filament-jetstream)[statikbe/laravel-filament-flexible-content-blocks

The Laravel Filament Flexible Content Blocks package helps you to easily create content in Filament for any model, with predefined or custom blocks, and foreach block an extendable Blade view component.

17625.5k4](/packages/statikbe-laravel-filament-flexible-content-blocks)[a2insights/filament-saas

Filament Saas for A2Insights

171.7k](/packages/a2insights-filament-saas)[slimani/filament-media-manager

A media manager plugin for Filament.

126.9k](/packages/slimani-filament-media-manager)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
