Catalog npm
PACKAGE EXPLORERView in registry

@0x30-ch/collection-tree

npm

Strapi plugin to easily sort your collections

cmscollectionhierarchypluginsortstrapitree
Versions collected10
Direct dependencies15From release 2.0.2
Last observed20 Oct, 22:34 UTC

README

Current package documentation

Strapi Collection Tree Plugin

A Strapi 5 plugin that enables hierarchical tree structures and flat sorting for your collections with drag-and-drop. Manage categories, menus, nested content, tags, and any data that benefits from ordered or hierarchical organization.

Plugin Demo License TypeScript Version

Features

  • Hierarchical Tree Structures: Transform any collection into a nested tree using self-referential relations
  • Flat Sorting: Collections without parent/children relations get flat drag-and-drop reordering (root-level only)
  • Drag & Drop Interface: Reorder and nest entries with visual feedback (powered by SortableJS)
  • Tree Connector Lines: Visual L-shaped connectors showing parent-child relationships
  • Expand / Collapse: Per-node and bulk expand/collapse controls (auto-collapses above 100 nodes)
  • Per-Locale Tree Ordering: Manage independent tree orders per locale — a locale dropdown appears when the content type is localized
  • Scope Filtering: Filter tree by published status (published or all)
  • Configurable Label Field: Choose which attribute (title, name, etc.) to display as the node label
  • Full i18n: All UI strings use react-intl for internationalization
  • Content API: Public endpoints for flat and nested tree data retrieval with locale support

Installation

npm install @0x30-ch/collection-tree
# or
yarn add @0x30-ch/collection-tree
# or
pnpm add @0x30-ch/collection-tree

Configuration

1. Add the Custom Field

In the Strapi Content-Type Builder, add the Tree custom field to your collection type. Configure:

  • Label field: Which attribute to show as the node label (e.g., title, name)
  • Scope: Which entries participate in the tree (published or all)

2. Set Up Relations (Optional — for Nesting)

For hierarchical (nested) trees, your content type must have self-referential relations:

  • A manyToOne relation named parent pointing to itself
  • A oneToMany relation named children pointing to itself (inverse of parent)

The plugin uses the join table created by these relations to store sort order. Root node sort order is stored in the tree integer custom field itself.

If no parent/children relations are defined, the plugin works in flat mode — all entries are sorted at root level using only the tree column. The admin UI hides nesting controls (chevrons, child drop zones, expand/collapse all) automatically.

3. Restart Your Server

After configuration, restart your Strapi server to apply the schema changes.

Usage

Admin Interface

  1. Navigate to the Collection Tree page in the admin panel sidebar
  2. Select a collection from the left sidebar
  3. Switch locale using the dropdown in the toolbar (appears only for localized content types with multiple locales)
  4. Drag & drop entries to reorder them at the same level or nest them under a parent (nesting only available when parent/children relations exist)
  5. Expand/collapse nodes using the chevron or the bulk toggle button
  6. Save your changes — order is saved independently per locale

Per-Locale Tree Ordering

Strapi 5 i18n creates separate database rows per locale, so each locale naturally has its own tree order. The plugin:

  • Fetches available locales from the i18n plugin on mount
  • Shows a locale dropdown in the header toolbar when the active content type is localized and multiple locales exist
  • Defaults to the default locale
  • Passes the selected locale to both fetch and save API calls
  • Non-localized content types show no locale dropdown

Admin API

The plugin exposes three admin API endpoints (authenticated via admin::isAuthenticatedAdmin):

MethodPathPurpose
GET/collection-tree/content-typesList content types with tree fields (includes isLocalized and supportsNesting flags)
GET/collection-tree/nodesFetch tree nodes (uid, field, labelField, scope, locale params)
PUT/collection-tree/nodesSave tree order (uid, field, nodes[], scope, locale body)

Content API (Public)

Two public endpoints for retrieving sorted tree data in your frontend:

MethodPathPurpose
GET/api/collection-tree/flatFlat list with depth and parentId fields
GET/api/collection-tree/nestedNested structure with children arrays

Query parameters (both endpoints):

ParamTypeDescription
uidstring(required) Content type UID (e.g. api::category.category)
fieldstringTree field name (auto-detected if omitted)
labelFieldstringLabel attribute to use
scopestringpublished (default) or all
localestringLocale code (e.g. en, fr) — defaults to default locale for localized types
fieldsstringComma-separated fields to include
populatestringComma-separated relations to populate, or *

Example:

# Flat list for French locale
GET /api/collection-tree/flat?uid=api::category.category&locale=fr

# Nested tree, published only
GET /api/collection-tree/nested?uid=api::category.category&scope=published&fields=title,slug&populate=image

Development

Prerequisites

  • Node.js >= 18.0.0
  • Strapi 5.x
  • TypeScript support

Setup

git clone https://github.com/0x30-ch/strapi-plugins.git
cd strapi-plugins
pnpm install

# Start development
pnpm dev

# Build plugin
cd packages/collection-tree
npm run build

# Type checking
npm run test:ts:front  # Frontend types
npm run test:ts:back   # Backend types

# Verify plugin structure
npm run verify

Project Structure

packages/collection-tree/
├── admin/                     # Frontend (React + Strapi Design System v2)
│   ├── src/
│   │   ├── components/
│   │   │   └── tree/          # Tree UI components
│   │   │       ├── styles.ts         # Styled-components (connectors, cards)
│   │   │       ├── TreeNodeItem.tsx   # Single node (chevron, handle, label, badge)
│   │   │       ├── TreeList.tsx       # Recursive ReactSortable wrapper
│   │   │       ├── TreeSidebar.tsx    # Left sidebar with content type list
│   │   │       └── TreeContent.tsx    # Main area (header, expand/collapse, tree)
│   │   ├── hooks/
│   │   │   └── useTreeData.ts        # Fetch/save logic + state management + locale
│   │   ├── pages/
│   │   │   └── TreePage.tsx          # Thin orchestrator with locale dropdown
│   │   ├── types/
│   │   │   └── index.ts              # Shared types (ContentTypeSummary, FlatNode, TreeNode, Locale)
│   │   ├── utils/
│   │   │   ├── getTranslation.ts     # i18n helper
│   │   │   └── treeUtils.ts          # Pure functions (buildTree, flattenTree, etc.)
│   │   └── translations/
│   │       └── en.json               # English translations
│   └── tsconfig.json
├── server/                    # Backend logic
│   ├── src/
│   │   ├── controllers/       # API controllers (tree.ts, tree-public.ts)
│   │   ├── services/          # Core service (resolveTreeModel, getNodes, updateNodes)
│   │   ├── routes/            # Route definitions (admin-api.ts, content-api.ts)
│   │   ├── utils/             # Tree helpers
│   │   └── config/            # Plugin configuration
│   └── tsconfig.json
└── package.json

Architecture

Relation-Based Tree Model (Nested Mode)

The plugin uses self-referential relations for hierarchical trees:

  • Parent relation (manyToOne): Each entry can have one parent
  • Children relation (oneToMany): Each entry can have many children (inverse of parent)
  • Join table: Strapi creates a join table for the relation, storing parent_id, child_id, and an order column
  • Root sort order: Root nodes (no parent) store their sort index in the tree custom field column
  • Nested sort order: Child nodes store their sort index in the join table's order column

Flat Mode (No Relations)

When a content type has a tree custom field but no self-referential parent/children relations:

  • All entries are treated as root nodes
  • Sort order is stored solely in the tree custom field column
  • The admin UI disables nesting: no chevrons, no child drop zones, no expand/collapse controls
  • Drag-and-drop reordering works at root level only

Locale Support

  • Strapi 5 i18n creates separate database rows per locale (each with its own id)
  • Join table parent-child relationships are implicitly per-locale since the IDs are locale-specific
  • The tree column (root ordering) is per-row, so per-locale by nature
  • The service accepts an optional locale parameter — when provided, queries filter by locale; when omitted, falls back to the default locale

Scope Support

ScopeDescription
publishedPublished entries only (default)
allAll entries (drafts + published)

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT License - see LICENSE file for details.

Acknowledgments

  • Strapi - Headless CMS framework
  • SortableJS - Drag-and-drop functionality
  • 0x30 - Original plugin author

Support

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 10

Collected releases
VersionPublishedDirect dependenciesOpen version
2.0.2Registry latest10 Feb 202615
2.0.19 Feb 202615
2.0.09 Feb 202615
1.0.624 Aug 202517
1.0.524 Aug 202517
1.0.422 Aug 202517
1.0.322 Aug 202517
1.0.222 Aug 202517
1.0.121 Aug 202517
1.0.021 Aug 202517

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

PENDING
0x30-ch/strapi-plugins

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 22:34 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:0940f1788eb680d261a7a939b31405f05214b4ce4040650f81718310c248e560