PHPackages                             fromholdio/silverstripe-resourceful - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. fromholdio/silverstripe-resourceful

ActiveSilverstripe-vendormodule[Utility &amp; Helpers](/categories/utility)

fromholdio/silverstripe-resourceful
===================================

2.0.0(2mo ago)0288BSD-3-ClausePHP

Since May 7Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/fromholdio/silverstripe-resourceful)[ Packagist](https://packagist.org/packages/fromholdio/silverstripe-resourceful)[ Docs](https://github.com/fromholdio/silverstripe-resourceful)[ RSS](/packages/fromholdio-silverstripe-resourceful/feed)WikiDiscussions master Synced yesterday

READMEChangelog (9)Dependencies (10)Versions (12)Used By (0)

SilverStripe Resourceful
========================

[](#silverstripe-resourceful)

A powerful configuration-driven module for SilverStripe that eliminates repetitive inheritance pattern setup. Resourceful provides a consistent UX and ORM structure for fields and relations that can inherit from parent objects or fall back to site-wide defaults.

Table of Contents
-----------------

[](#table-of-contents)

- [Overview](#overview)
- [Why This Module?](#why-this-module)
- [Requirements](#requirements)
- [Installation](#installation)
- [Core Concepts](#core-concepts)
- [Quick Start](#quick-start)
- [Configuration](#configuration)
- [Usage](#usage)
- [Advanced Features](#advanced-features)
- [API Reference](#api-reference)
- [Real-World Examples](#real-world-examples)
- [License](#license)

Overview
--------

[](#overview)

Resourceful solves a common problem in hierarchical SilverStripe projects: providing users with the ability to inherit values or relations from parent pages or use site-wide defaults, without writing repetitive boilerplate code for each field.

**What it provides:**

- **Configuration-driven inheritance** - Define inheritance patterns in YAML
- **Automatic CMS fields** - Generates "Inherit from parent" checkboxes and source selectors
- **Flexible source options** - Local, parent, site, or custom sources
- **Consistent UX** - Same interface pattern across all inheritable fields
- **Zero boilerplate** - No repetitive code for each inheritable field

Why This Module?
----------------

[](#why-this-module)

Without Resourceful, implementing field inheritance requires:

1. **Database fields** for each inheritable value:

    ```
    'SidebarArea_DoInherit' => 'Boolean',
    'SidebarArea_Source' => 'Varchar(10)',
    'SidebarArea_Local' => 'has_one relation',
    ```
2. **Getter methods** with inheritance logic:

    ```
    public function getSidebarArea() {
        if ($this->SidebarArea_DoInherit && $this->Parent()->exists()) {
            return $this->Parent()->getSidebarArea();
        }
        switch ($this->SidebarArea_Source) {
            case 'site': return SiteConfig::curr()->SidebarArea();
            case 'local': return $this->SidebarArea_Local();
            case 'none': return null;
        }
    }
    ```
3. **CMS fields** with display logic:

    ```
    $fields->addFieldToTab('Root.Sidebar',
        CheckboxField::create('SidebarArea_DoInherit', 'Inherit from parent')
    );
    $wrapper = Wrapper::create(
        OptionsetField::create('SidebarArea_Source', 'Source', [...])
    );
    $wrapper->displayIf('SidebarArea_DoInherit')->isNotChecked();
    // ... more field logic
    ```

**With Resourceful**, all of this becomes:

```
Page:
  resourceful:
    SidebarArea:
      sources:
        inherit: 'parent'
        select: 'site|local|none'
        default: 'site'
      relations:
        site: '->getSidebarConfig'
      cms_fields:
        tab_path: 'Root.Sidebar'
```

```
public function getSidebarArea() {
    return $this->getResourcefulValue('SidebarArea');
}
```

That's it. Resourceful handles everything else.

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

[](#requirements)

- SilverStripe CMS ^6.0
- PHP 8.3+
- fromholdio/silverstripe-checkboxfieldgroup ^1.2.0
- fromholdio/silverstripe-cms-fields-placement ^1.2.0
- unclecheese/display-logic ^4.0.0

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

[](#installation)

```
composer require fromholdio/silverstripe-resourceful
```

Core Concepts
-------------

[](#core-concepts)

### Sources

[](#sources)

A **source** is where a value comes from. Resourceful provides built-in sources:

- **`local`** - Value stored directly on this object
- **`parent`** - Inherited from parent object (hierarchical)
- **`site`** - Site-wide default (from SiteConfig or custom)
- **`none`** - No value (null)
- **`default`** - Use the configured default source

### Inheritance

[](#inheritance)

When **inherit** is enabled, the value is retrieved from the parent object recursively until a non-inheriting value is found.

### Source Selection

[](#source-selection)

Users can **select** which source to use via CMS fields (unless forced by configuration).

### Configuration Structure

[](#configuration-structure)

Each resourceful field has:

- **Name** - The field name (e.g., 'SidebarArea')
- **Sources** - Which sources are available and which is default
- **Values** - How to retrieve values from each source (field names or methods)
- **Relations** - How to traverse to parent/site objects
- **CMS Fields** - Where to place fields in the CMS

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

[](#quick-start)

### 1. Apply Extension

[](#1-apply-extension)

```
use Fromholdio\Resourceful\Extensions\ResourcefulExtension;
use SilverStripe\CMS\Model\SiteTree;

class Page extends SiteTree
{
    private static $extensions = [
        ResourcefulExtension::class,
    ];
}
```

### 2. Configure Resourceful Field

[](#2-configure-resourceful-field)

```
Page:
  resourceful:
    SidebarContent:
      sources:
        inherit: 'parent'
        select: 'site|local|none'
        default: 'site'
      relations:
        site: 'Site'
      cms_fields:
        tab_path: 'Root.Sidebar'
```

### 3. Add Database Fields

[](#3-add-database-fields)

```
class Page extends SiteTree
{
    private static $db = [
        'SidebarContent_DoInherit' => 'Boolean',
        'SidebarContent_Source' => 'Varchar(10)',
        'SidebarContent_Local' => 'HTMLText',
    ];

    private static $defaults = [
        'SidebarContent_DoInherit' => true,
        'SidebarContent_Source' => 'default',
    ];
}
```

### 4. Create Getter Method

[](#4-create-getter-method)

```
public function getSidebarContent(): ?string
{
    return $this->getResourcefulValue('SidebarContent');
}
```

### 5. Use in Templates

[](#5-use-in-templates)

```

        $SidebarContent

```

That's it! Resourceful automatically:

- Generates CMS fields with inheritance checkbox
- Handles source selection UI
- Traverses parent hierarchy
- Falls back to site default
- Manages display logic

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

[](#configuration)

### Basic Configuration

[](#basic-configuration)

```
Page:
  resourceful:
    FieldName:
      enabled: true  # Enable/disable this resourceful field
      sources:
        force: null  # Force a specific source (overrides user selection)
        inherit: 'parent'  # Enable inheritance from parent
        select: 'site|local|none'  # Available sources for user selection
        default: 'site'  # Default source when none selected
      values:
        local: 'FieldName_Local'  # Field name for local value
        parent: 'FieldName'  # Field name on parent
        site: 'FieldName'  # Field name on site config
      relations:
        parent: 'Parent'  # Relation to parent object
        site: 'Site'  # Relation to site object
      cms_fields:
        tab_path: 'Root.Main'  # Where to place CMS fields
      source_field_class: 'SilverStripe\Forms\OptionsetField'  # Field class for source selector
```

### Source Configuration

[](#source-configuration)

**`sources.force`** - Force a specific source, ignoring user selection:

```
sources:
  force: 'site'  # Always use site default
```

**`sources.inherit`** - Enable inheritance from parent:

```
sources:
  inherit: 'parent'  # Inherit from parent when checkbox checked
```

**`sources.select`** - Available sources for user selection:

```
sources:
  select: 'site|local|none'  # User can choose between these
```

**`sources.default`** - Default source when none selected:

```
sources:
  default: 'site'  # Default to site-wide value
```

### Value Configuration

[](#value-configuration)

**Field names**:

```
values:
  local: 'FieldName_Local'  # Database field on this object
  parent: 'FieldName'  # Field name on parent object
  site: 'FieldName'  # Field name on site config
```

**Method names** (prefix with `->`):

```
values:
  local: '->getLocalFieldName'  # Call method instead of field
  site: '->getSiteFieldName'
```

**Multiple fallbacks** (pipe-separated):

```
values:
  local: '->getFieldName|FieldName_Local'  # Try method first, then field
```

**Forced inheritance** (set `{inherit}` to `true`):

```
values:
  '{inherit}': true  # Force inheritance, no checkbox shown
```

When `'{inherit}': true`:

- No DoInherit checkbox shown in CMS
- Inheritance always active (automatic fallback)
- Local field still shown for user input
- No DoInherit database field needed

### Relation Configuration

[](#relation-configuration)

**Relation names**:

```
relations:
  parent: 'Parent'  # has_one relation to parent
  site: 'Site'  # has_one relation to site
```

**Method names** (prefix with `->`):

```
relations:
  parent: '->getParentObject'  # Call method to get parent
  site: '->getSiteConfig'  # Call method to get site
```

**Required relations**:

```
relations:
  '{require}': 'parent|site'  # These sources require relation to exist
```

### CMS Fields Configuration

[](#cms-fields-configuration)

**Tab path**:

```
cms_fields:
  tab_path: 'Root.Main'  # Place in Main tab
```

**Field placement** (relative to another field):

```
cms_fields:
  placement: 'before'  # or 'after'
  field: 'Content'  # Place before/after this field
```

**Settings fields** (for Settings tab):

```
settings_fields:
  tab_path: 'Root.Settings'
```

Usage
-----

[](#usage)

### In PHP

[](#in-php)

#### Getting Values

[](#getting-values)

```
// Get resourceful value (handles inheritance automatically)
$value = $page->getResourcefulValue('FieldName');

// Check if field is enabled
if ($page->isResourcefulEnabled('FieldName')) {
    // Field is enabled
}

// Check if field is inheritable
if ($page->isResourcefulInheritable('FieldName')) {
    // Field can inherit from parent
}

// Check if field is currently inheriting
if ($page->isResourcefulInherited('FieldName')) {
    // Field is inheriting from parent
}
```

#### Working with Resourceful Instance

[](#working-with-resourceful-instance)

```
// Get Resourceful instance
$resourceful = $page->getResourceful('FieldName');

// Get current source
$source = $resourceful->getSource();  // 'local', 'parent', 'site', 'none'

// Get value from specific source
$localValue = $resourceful->getSourceValue('local');
$siteValue = $resourceful->getSourceValue('site');

// Check if source is available
if ($resourceful->isSourceAvailable('parent')) {
    // Parent source is available
}

// Get available sources
$sources = $resourceful->getAvailableSources();  // ['local', 'site', 'none']
```

### In Templates

[](#in-templates)

```

        $SidebarContent

    Inheriting from parent

        Inherited content

        Local content

```

### Custom Getter Methods

[](#custom-getter-methods)

Create custom getter methods for cleaner templates:

```
public function getSidebarContent(): ?string
{
    return $this->getResourcefulValue('SidebarContent');
}

public function getSidebarArea(): ?EvoElementalArea
{
    return $this->getResourcefulValue('SidebarArea');
}
```

Then in templates:

```

    $SidebarContent

        $Me

```

Advanced Features
-----------------

[](#advanced-features)

### Custom Source Methods

[](#custom-source-methods)

Define custom methods to retrieve values:

```
Page:
  resourceful:
    SidebarArea:
      values:
        local: '->getLocalSidebarArea'
        site: '->getSiteSidebarArea'
      relations:
        site: '->getSidebarConfig'
```

```
public function getLocalSidebarArea(): ?EvoElementalArea
{
    return $this->SidebarArea_Local();
}

public function getSiteSidebarArea(): ?EvoElementalArea
{
    return $this->getSidebarConfig()->SidebarArea();
}

public function getSidebarConfig(): SiteConfig
{
    return SiteConfig::current_site_config();
}
```

### Custom CMS Fields

[](#custom-cms-fields)

Override automatic field generation:

```
public function getSidebarAreaCMSFields(): FieldList
{
    return FieldList::create(
        // Your custom fields
    );
}
```

### Per-Source CMS Fields

[](#per-source-cms-fields)

Add fields that appear only when a specific source is selected:

```
public function getCMSFields_SidebarArea_local(
    bool $isInherited,
    ?string $selectedSource,
    bool $isDefault,
    ?string $fieldName,
    ?string $relationName
): FieldList {
    return FieldList::create(
        // Fields for local source
        HTMLEditorField::create('SidebarContent_Local', 'Sidebar Content')
    );
}

public function getCMSFields_SidebarArea_site(
    bool $isInherited,
    ?string $selectedSource,
    bool $isDefault,
    ?string $fieldName,
    ?string $relationName
): FieldList {
    return FieldList::create(
        // Fields for site source (read-only preview, etc.)
        ReadonlyField::create('SitePreview', 'Site Default',
            $this->getSiteConfig()->SidebarContent
        )
    );
}
```

### Forcing Sources

[](#forcing-sources)

Force a specific source via configuration:

```
HomePage:
  resourceful:
    SidebarArea:
      sources:
        force: 'none'  # Home page never has sidebar
```

Or force with fallback:

```
Page:
  resourceful:
    SidebarArea:
      sources:
        force: 'parent|site'  # Try parent, fallback to site
```

### Forced Inheritance (No Checkbox)

[](#forced-inheritance-no-checkbox)

Force inheritance without showing a checkbox:

```
Page:
  resourceful:
    HeroHeadline:
      sources:
        inherit: 'page'
        select: 'local'
        default: 'local'
      values:
        '{inherit}': true  # Force inheritance, no checkbox
        page: 'Title'  # Inherit from Title field
```

**Result**:

- No DoInherit checkbox shown
- Only local text field shown
- Inheritance always active (automatic fallback)
- When local field is empty, uses Title field value
- No DoInherit database field needed

**Use Case**: Automatic fallback to another field without user choice (e.g., use page title as hero headline if custom headline is empty)

**Database Fields**:

```
private static $db = [
    'HeroHeadline_Local' => 'Varchar(255)',  // Only local field needed
];
```

**Comparison with Optional Inheritance**:

```
# Optional inheritance (shows checkbox)
HeroLede:
  values:
    '{inherit}': 'HeroLede_DoInherit'  # Field name = checkbox shown
    page: 'Lede'

# Forced inheritance (no checkbox)
HeroHeadline:
  values:
    '{inherit}': true  # Boolean true = no checkbox
    page: 'Title'
```

### Disabling Auto-Placement

[](#disabling-auto-placement)

Disable automatic CMS field placement:

```
Page:
  do_auto_place_resourceful_cms_fields: false
```

Then manually place fields:

```
public function getCMSFields(): FieldList
{
    $fields = parent::getCMSFields();

    // Manually place resourceful fields
    $resourceful = $this->getResourceful('SidebarArea');
    $fields = $resourceful->placeCMSFields($fields);

    return $fields;
}
```

### Multiple Resourceful Fields

[](#multiple-resourceful-fields)

Configure multiple fields at once:

```
Page:
  resourceful:
    SidebarArea:
      sources:
        inherit: 'parent'
        select: 'site|local|none'
        default: 'site'
      cms_fields:
        tab_path: 'Root.Sidebar'

    FooterArea:
      sources:
        inherit: 'parent'
        select: 'site|local|none'
        default: 'site'
      cms_fields:
        tab_path: 'Root.Footer'

    HeaderImage:
      sources:
        inherit: 'parent'
        select: 'local|none'
        default: 'local'
      cms_fields:
        tab_path: 'Root.Main'
```

### Multisite Support

[](#multisite-support)

Resourceful automatically detects multisite modules:

```
Page:
  resourceful:
    SidebarArea:
      relations:
        site: 'Site'  # Automatically uses Site relation if multisite installed
```

If multisite is not installed, falls back to `SiteConfig::current_site_config()`.

API Reference
-------------

[](#api-reference)

### ResourcefulExtension

[](#resourcefulextension)

Applied to DataObjects that use resourceful fields.

#### Methods

[](#methods)

```
// Get Resourceful instance
public function getResourceful(string $name): Resourceful

// Check if enabled
public function isResourcefulEnabled(string $name): bool

// Get value
public function getResourcefulValue(string $name)

// Check if inheritable
public function isResourcefulInheritable(string $name): bool

// Check if inherited
public function isResourcefulInherited(string $name): bool

// Get source field options
public function getResourcefulSourceFieldOptions(string $name): ?array
```

### Resourceful Class

[](#resourceful-class)

Core class that handles resourceful logic.

#### Factory Methods

[](#factory-methods)

```
// Create instance
public static function inst(DataObject $dObj, string $name): Resourceful

// Get all resourceful field names
public static function getAllNames(DataObject $dObj): ?array

// Set defaults for all fields
public static function setAllFieldDefaults(DataObject $dObj): void

// Place all CMS fields
public static function placeAllCMSFields(FieldList $fields, DataObject $dObj): FieldList

// Place all settings fields
public static function placeAllSettingsFields(FieldList $fields, DataObject $dObj): FieldList
```

#### Configuration Methods

[](#configuration-methods)

```
// Get configuration data
public function getConfigData(): ?array

// Get specific config value
public function getConfigValue(string $key, ?array $data = null)

// Check if enabled
public function isEnabled(): bool

// Get field names
public function getFieldName(): string
public function getDoInheritFieldName(): ?string
public function getSourceFieldName(): ?string
```

#### Source Methods

[](#source-methods)

```
// Get current source
public function getSource(): ?string

// Get value
public function getValue()

// Check inheritance
public function isInheritable(): bool
public function isInherited(): bool

// Get specific sources
public function getInheritSource(): ?string
public function getDefaultSource(): ?string
public function getForceSource(): ?string
public function getSelectSources(): ?array
public function getSelectedSource(): ?string

// Get value from source
public function getSourceValue(?string $source)

// Get relation for source
public function getSourceRelation(?string $source): ?DataObject

// Check source availability
public function isSourceAvailable(?string $source): bool
public function getAvailableSources(): ?array
```

#### CMS Field Methods

[](#cms-field-methods)

```
// Get CMS fields
public function getCMSFields(): ?FieldList
public function getDoInheritCMSField(): ?CheckboxFieldGroup
public function getSourceCMSField(): ?FormField
public function getCMSFieldsForSource(string $source): ?FieldList

// Place CMS fields
public function placeCMSFields(FieldList $fields, bool $doRemoveFields = false): FieldList
public function placeSettingsFields(FieldList $fields, bool $doRemoveFields = false): FieldList
public function removeCMSFields(FieldList $fields): FieldList
```

Real-World Examples
-------------------

[](#real-world-examples)

### Example 1: Inheritable Sidebar

[](#example-1-inheritable-sidebar)

```
Page:
  extensions:
    - Fromholdio\Resourceful\Extensions\ResourcefulExtension

  resourceful:
    SidebarArea:
      sources:
        inherit: 'parent'
        select: 'site|local|none'
        default: 'site'
      relations:
        site: '->getSidebarConfig'
      cms_fields:
        tab_path: 'Root.Sidebar'
```

```
class Page extends SiteTree
{
    private static $db = [
        'SidebarArea_DoInherit' => 'Boolean',
        'SidebarArea_Source' => 'Varchar(10)',
    ];

    private static $has_one = [
        'SidebarArea_Local' => SidebarElementalArea::class,
    ];

    private static $defaults = [
        'SidebarArea_DoInherit' => true,
        'SidebarArea_Source' => 'default',
    ];

    public function getSidebarArea(): ?EvoElementalArea
    {
        return $this->getResourcefulValue('SidebarArea');
    }

    public function getSidebarConfig(): SiteConfig
    {
        return SiteConfig::current_site_config();
    }
}
```

```
SilverStripe\SiteConfig\SiteConfig:
  extensions:
    - Fromholdio\Resourceful\Extensions\ResourcefulExtension

  has_one:
    SidebarArea: SidebarElementalArea
```

**Result**: Pages can inherit sidebar from parent, use site-wide default, use custom local sidebar, or have no sidebar.

### Example 2: Header Image with Parent Inheritance

[](#example-2-header-image-with-parent-inheritance)

```
Page:
  resourceful:
    HeaderImage:
      sources:
        inherit: 'parent'
        select: 'local|none'
        default: 'local'
      cms_fields:
        placement: 'before'
        field: 'Content'
```

```
class Page extends SiteTree
{
    private static $db = [
        'HeaderImage_DoInherit' => 'Boolean',
        'HeaderImage_Source' => 'Varchar(10)',
    ];

    private static $has_one = [
        'HeaderImage_Local' => Image::class,
    ];

    public function getHeaderImage(): ?Image
    {
        return $this->getResourcefulValue('HeaderImage');
    }
}
```

**Result**: Pages can inherit header image from parent or use their own.

### Example 3: Multiple Areas with Resourceful

[](#example-3-multiple-areas-with-resourceful)

```
Page:
  resourceful:
    SideArea:
      sources:
        inherit: 'parent'
        select: 'site|local|none'
        default: 'site'
      relations:
        site: '->getSideAreaConfig'
      cms_fields:
        tab_path: 'Root.SidebarTabSet.SidebarMainTab'

    BelowArea:
      sources:
        inherit: 'parent'
        select: 'site|local|none'
        default: 'site'
      relations:
        site: '->getBelowAreaConfig'
      cms_fields:
        tab_path: 'Root.FooterTabSet.FooterMainTab'
```

```
class Page extends SiteTree
{
    private static $db = [
        'SideArea_DoInherit' => 'Boolean',
        'SideArea_Source' => 'Varchar(10)',
        'BelowArea_DoInherit' => 'Boolean',
        'BelowArea_Source' => 'Varchar(10)',
    ];

    private static $has_one = [
        'SideArea_Local' => SideElementalArea::class,
        'BelowArea_Local' => BlocksElementalArea::class,
    ];

    public function getSideArea(): ?EvoElementalArea
    {
        return $this->getResourcefulValue('SideArea');
    }

    public function getBelowArea(): ?EvoElementalArea
    {
        return $this->getResourcefulValue('BelowArea');
    }

    public function getSideAreaConfig(): SiteConfig
    {
        return SiteConfig::current_site_config();
    }

    public function getBelowAreaConfig(): SiteConfig
    {
        return SiteConfig::current_site_config();
    }
}
```

**Result**: Both sidebar and footer areas can independently inherit from parent or use site defaults.

### Example 4: Forced Inheritance for Hero Fields

[](#example-4-forced-inheritance-for-hero-fields)

```
Page:
  resourceful:
    HeroHeadline:
      sources:
        inherit: 'page'
        select: 'local'
        default: 'local'
      values:
        '{inherit}': true  # Forced inheritance
        page: 'Title'
      cms_fields:
        tab_path: 'Root.HeroTabSet.HeroMainTab'

    HeroLede:
      sources:
        inherit: 'page'
        select: 'local'
        default: 'local'
      values:
        '{inherit}': 'HeroLede_DoInherit'  # Optional inheritance
        page: 'Lede'
      cms_fields:
        tab_path: 'Root.HeroTabSet.HeroMainTab'
```

```
class Page extends SiteTree
{
    private static $db = [
        'HeroHeadline_Local' => 'Varchar(255)',  // No DoInherit field
        'HeroLede_DoInherit' => 'Boolean',       // Has DoInherit field
        'HeroLede_Local' => 'Text',
    ];

    public function getHeroHeadline(): string
    {
        return $this->getResourcefulValue('HeroHeadline');
    }

    public function getHeroLede(): string
    {
        return $this->getResourcefulValue('HeroLede');
    }
}
```

**Result**:

- **HeroHeadline**: Always falls back to page Title if empty (no checkbox)
- **HeroLede**: User can choose to inherit from page Lede or use custom (checkbox shown)

License
-------

[](#license)

BSD-3-Clause

Support
-------

[](#support)

- **GitHub**:
- **Issues**:

Contributing
------------

[](#contributing)

Contributions are welcome! Please open an issue or pull request on GitHub.

###  Health Score

44

—

FairBetter than 90% of packages

Maintenance88

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity55

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 ~145 days

Recently: every ~212 days

Total

11

Last Release

62d ago

Major Versions

1.x-dev → 2.0.02026-05-03

### Community

Maintainers

![](https://www.gravatar.com/avatar/40e135ad117686bee39707c1d9286cc5e915e219c26a10d13858ca44d14f1eb0?d=identicon)[dizzystuff](/maintainers/dizzystuff)

---

Top Contributors

[![dizzystuff](https://avatars.githubusercontent.com/u/576903?v=4)](https://github.com/dizzystuff "dizzystuff (27 commits)")

---

Tags

silverstripe

### Embed Badge

![Health badge](/badges/fromholdio-silverstripe-resourceful/health.svg)

```
[![Health](https://phpackages.com/badges/fromholdio-silverstripe-resourceful/health.svg)](https://phpackages.com/packages/fromholdio-silverstripe-resourceful)
```

###  Alternatives

[silverstripe/cms

The SilverStripe Content Management System

5253.6M1.4k](/packages/silverstripe-cms)[silverstripe/userforms

UserForms enables CMS users to create dynamic forms via a drag and drop interface and without getting involved in any PHP code

1371.1M85](/packages/silverstripe-userforms)[symbiote/silverstripe-gridfieldextensions

A collection of useful grid field components

951.9M272](/packages/symbiote-silverstripe-gridfieldextensions)[symbiote/silverstripe-advancedworkflow

Adds configurable workflow support to the CMS, with a GUI for creating custom workflow definitions.

46302.4k9](/packages/symbiote-silverstripe-advancedworkflow)[silverstripe/tagfield

Tag field for SilverStripe

561.3M50](/packages/silverstripe-tagfield)[jonom/silverstripe-betternavigator

Front-end utility menu for Silverstripe websites featuring administration and development tools

60435.1k13](/packages/jonom-silverstripe-betternavigator)

PHPackages © 2026

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