PHPackages                             whilesmart/eloquent-taxonomy - 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. [Database &amp; ORM](/categories/database)
4. /
5. whilesmart/eloquent-taxonomy

ActiveLibrary[Database &amp; ORM](/categories/database)

whilesmart/eloquent-taxonomy
============================

Polymorphic tags and hierarchical categories for Laravel applications

039[1 issues](https://github.com/whilesmartphp/eloquent-taxonomy/issues)PHPCI passing

Since Mar 16Pushed 3mo agoCompare

[ Source](https://github.com/whilesmartphp/eloquent-taxonomy)[ Packagist](https://packagist.org/packages/whilesmart/eloquent-taxonomy)[ RSS](/packages/whilesmart-eloquent-taxonomy/feed)WikiDiscussions main Synced 3w ago

READMEChangelogDependenciesVersions (1)Used By (0)

Eloquent Taxonomy
=================

[](#eloquent-taxonomy)

Polymorphic tags and hierarchical categories for Laravel applications.

Features
--------

[](#features)

- **Flat Tags**: Typed, polymorphic many-to-many tags attachable to any model
- **Hierarchical Categories**: Nested parent/child tree with ancestors and descendants
- **Polymorphic Relationships**: Works with any Eloquent model via traits
- **Typed Namespaces**: Separate tag/category namespaces with the `type` field (e.g. `priority`, `skill`, `blog`)
- **Query Scopes**: `withAnyTag`, `withAllTags`, `inCategory`, `inAnyCategory`
- **Customizable Models**: Override Tag and Category models via config
- **Middleware Hooks**: Before/after hooks on all controller actions
- **Configurable Routes**: Enable/disable, set prefix and middleware
- **Laravel 10+, 11+, 12+ Support**

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

[](#installation)

```
composer require whilesmart/eloquent-taxonomy
```

### Publish Configuration (Optional)

[](#publish-configuration-optional)

```
php artisan vendor:publish --tag=taxonomy-config
```

### Run Migrations

[](#run-migrations)

```
php artisan migrate
```

Quick Start
-----------

[](#quick-start)

### Tags

[](#tags)

Add the `HasTags` trait to any model:

```
use Whilesmart\Taxonomy\Traits\HasTags;

class Post extends Model
{
    use HasTags;
}
```

Attach, detach, and query tags:

```
$post->attachTag('laravel');
$post->attachTags(['laravel', 'php', 'vue']);
$post->detachTag('vue');
$post->syncTags(['laravel', 'react']);

$post->hasTag('laravel');           // true
$post->hasAnyTag(['vue', 'react']); // true

// Typed tags (namespaced)
$post->attachTag('urgent', 'priority');
$post->tagsOfType('priority');

// Query scopes
Post::withAnyTag(['laravel', 'vue'])->get();
Post::withAllTags(['laravel', 'php'])->get();
```

### Categories

[](#categories)

Add the `HasCategories` trait to any model:

```
use Whilesmart\Taxonomy\Traits\HasCategories;

class Article extends Model
{
    use HasCategories;
}
```

Create hierarchical categories:

```
use Whilesmart\Taxonomy\Models\Category;

$tech = Category::create(['name' => 'Technology', 'slug' => 'technology']);
$php = Category::create(['name' => 'PHP', 'slug' => 'php', 'parent_id' => $tech->id]);
$laravel = Category::create(['name' => 'Laravel', 'slug' => 'laravel', 'parent_id' => $php->id]);
```

Attach and query categories:

```
$article->attachCategory($tech);
$article->attachCategory('php'); // by slug
$article->detachCategory($tech);
$article->syncCategories([$tech->id, $php->id]);

$article->hasCategory('php');   // true

// Query scopes
Article::inCategory('technology')->get();
Article::inAnyCategory(['technology', 'science'])->get();
```

Navigate the tree:

```
$tech->children;         // [PHP]
$php->parent;            // Technology
$laravel->ancestors();   // [Technology, PHP]
$tech->descendants;      // recursive children
$tech->hasChildren();    // true
$tech->isRoot();         // true

// Get full tree (roots with nested descendants)
Category::tree();                // all roots
Category::tree('blog');          // roots of type 'blog'
```

### Using Both

[](#using-both)

A model can use both traits:

```
class Product extends Model
{
    use HasTags, HasCategories;
}
```

Configuration
-------------

[](#configuration)

```
// config/taxonomy.php
return [
    'models' => [
        'tag' => \Whilesmart\Taxonomy\Models\Tag::class,
        'category' => \Whilesmart\Taxonomy\Models\Category::class,
    ],

    'register_routes' => true,
    'route_prefix' => '',
    'route_middleware' => ['auth:sanctum'],

    'middleware_hooks' => [
        // App\Hooks\TaxonomyHook::class,
    ],
];
```

### Custom Models

[](#custom-models)

Extend the base models and update config:

```
class Tag extends \Whilesmart\Taxonomy\Models\Tag
{
    // custom logic
}
```

```
// config/taxonomy.php
'models' => [
    'tag' => App\Models\Tag::class,
],
```

### Middleware Hooks

[](#middleware-hooks)

Implement `MiddlewareHookInterface` to intercept controller actions:

```
use Whilesmart\Taxonomy\Interfaces\MiddlewareHookInterface;

class TaxonomyHook implements MiddlewareHookInterface
{
    public function before(Request $request, string $action): ?Request
    {
        // modify request or return null to skip
        return $request;
    }

    public function after(Request $request, JsonResponse $response, string $action): JsonResponse
    {
        // modify response
        return $response;
    }
}
```

API Routes
----------

[](#api-routes)

When routes are enabled:

```
GET    /tags                    List tags (filter: ?type=)
POST   /tags                    Create tag
DELETE /tags/{id}               Delete tag

GET    /categories              List categories (filter: ?type=, ?tree=true)
POST   /categories              Create category
GET    /categories/{id}         Show category with children
PUT    /categories/{id}         Update category
DELETE /categories/{id}         Delete category

```

Database Schema
---------------

[](#database-schema)

### Tags

[](#tags-1)

ColumnTypeDescriptionnamestringDisplay nameslugstringURL-friendly identifiertypestring (nullable)Namespace for groupingcolorstring (nullable)Hex color for UImetadataJSON (nullable)Flexible datasort\_orderintegerDisplay orderingUnique constraint: `(slug, type)`

### Categories

[](#categories-1)

ColumnTypeDescriptionparent\_idFK (nullable)Self-referencing for hierarchynamestringDisplay nameslugstringURL-friendly identifiertypestring (nullable)Namespace for groupingdescriptiontext (nullable)Descriptioniconstring (nullable)Icon identifiercolorstring (nullable)Hex color for UImetadataJSON (nullable)Flexible datasort\_orderintegerDisplay orderingUnique constraint: `(slug, type)`

Testing
-------

[](#testing)

```
make test       # Run tests via Docker
make pint       # Run code formatter
make check      # Run all checks (pint + tests)
```

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

[](#requirements)

- PHP 8.2+
- Laravel 10.0, 11.0, or 12.0

License
-------

[](#license)

MIT License

Credits
-------

[](#credits)

Developed by the Whilesmart Team

###  Health Score

21

—

LowBetter than 18% of packages

Maintenance54

Moderate activity, may be stable

Popularity11

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity12

Early-stage or recently created project

 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.

### Community

Maintainers

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

---

Top Contributors

[![nfebe](https://avatars.githubusercontent.com/u/14317775?v=4)](https://github.com/nfebe "nfebe (2 commits)")

### Embed Badge

![Health badge](/badges/whilesmart-eloquent-taxonomy/health.svg)

```
[![Health](https://phpackages.com/badges/whilesmart-eloquent-taxonomy/health.svg)](https://phpackages.com/packages/whilesmart-eloquent-taxonomy)
```

###  Alternatives

[jdorn/sql-formatter

a PHP SQL highlighting library

3.9k116.5M113](/packages/jdorn-sql-formatter)[propel/propel1

Propel is an open-source Object-Relational Mapping (ORM) for PHP5.

8351.6M87](/packages/propel-propel1)

PHPackages © 2026

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