PHPackages                             venveo/craft-characteristic - 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. venveo/craft-characteristic

ActiveCraft-plugin[Utility &amp; Helpers](/categories/utility)

venveo/craft-characteristic
===========================

Drill-drown on element characteristics

1.0.0-beta.12(2y ago)563[5 PRs](https://github.com/venveo/craft-characteristic/pulls)MITPHPCI failing

Since Jan 28Pushed 3mo ago3 watchersCompare

[ Source](https://github.com/venveo/craft-characteristic)[ Packagist](https://packagist.org/packages/venveo/craft-characteristic)[ RSS](/packages/venveo-craft-characteristic/feed)WikiDiscussions master Synced today

READMEChangelog (10)Dependencies (1)Versions (25)Used By (0)

Characteristic plugin for Craft CMS
===================================

[](#characteristic-plugin-for-craft-cms)

Characteristic provides a new way of storing and querying complex descriptive relationships and attributes for elements.

You can think of it as an "attribute-value" system, where an attribute may be applied to an element (think "Tags") and a specific value may applied to that attribute (Think, a Super Table fields with a tag or category and a text field)

For example, consider you have a list of local restaurants and you want to build a system to help visitors pick a restaurant with their requirements. You *could* create a series of tags or categories, such:

- "Has outdoor seating"
- "Serves pizza"
- "Cash only"

However, this data is completely unaware of context and is really just a cloud of ideas. Further, what if we wanted to introduce price points, such as "$", "$$", "$$$", "$$$$", "$$$$$"

Do we now create a new category group or do we just toss it in with the others? If we create a new group, we have to now write more code.

Characteristic solves this by creating two new element types, sorted into groups. The "Characteristic" element can be applied like a tag, once applied, a "Characteristic Value" can be applied. This value is free-form and new elements will be created as new distinct values are created ***PER-CHARACTERISTIC***.

For example, as a developer, I would create a Characteristic Group called "Restaurant Finder Attributes" and within it, the content editors can define their characteristics like any other element:

- "Accepts Cash"
- "Price Level"
- "Seating Outdoors"
- "Which dish looks most delicious?"
- "How many vodka-tonics before I get banned?"

Through the use of a custom field, I can now apply these characteristics as needed with values, as needed. Notice the last option above: it asks to pick a photo that I like. This works because both characteristics and characteristic values can supply their own field layouts per group!

Characteristic provides a helper with a Twig variable called "Drilldown"

The drilldown tool allows you to provide an element query, such as: `craft.entries.section('restaurants')`

and receive access to the most relevant characteristic and its options. The helper also manages a "state" based on selected options, allowing you to quickly create a "Quiz" to find the most suitable element.

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

[](#requirements)

This plugin requires Craft CMS 3.4.0 or later.

Using Characteristic
--------------------

[](#using-characteristic)

### The Drilldown Helper

[](#the-drilldown-helper)

```
{# Any arbitrary base element query #}
{% set query = craft.entries.section('restaurants') %}

{# Create an instance of the drilldown helper for the characteristic group with the handle `restaurantCharacteristics` #}
{% set drilldown = craft.characteristic.drilldown('restaurantCharacteristics', query) %}

{% set state = drilldown.state %}

{% set current = drilldown.currentCharacteristic %}

{# Get a text field called characteristicDescription off of the characteristic #}
{{ current.characteristicDescription }}

{# Get all of the options available for the current characteristic #}
{% set options = drilldown.currentOptions.all() %}

    {% for option in options %}
{# Use the applyToDrilldownState method to create a URL for this value based on the current state #}
        {{ option.value }}

{# Grab a featuredImage Asset field off of the option #}
        {% if option.featuredImage.exists() %}

        {% endif %}
    {% endfor %}

{# Optional URL to skip the question with picking an answer #}
    Skip Question

Current Result Set

{% if drilldown.results.count() == 1 %}
You did it!
{% endif %}

{% for item in drilldown.results.all() %}
    {{ item.title }}
{% endfor %}
```

### The characteristics field

[](#the-characteristics-field)

The field returns a CharacteristicLinkBlockQuery pre-configured for the element.

#### Get all characteristics on an entry and show them as a table

[](#get-all-characteristics-on-an-entry-and-show-them-as-a-table)

```

        Characteristic
        Value

    {% set blocks = entry.restaurantAttributes.all() %}
    {% for block in blocks %}

        {{ block.characteristic.title }}
        {# We're going to create a string out of the characteristic value's text value #}
        {{ block.values.all()|column('value')|join(', ') }}

    {% endfor %}

```

### Querying for elements

[](#querying-for-elements)

There are a few different ways to query for elements with certain characteristics.

You could use the native Craft relationships, for example:

```
{% set characteristic = craft.characteristic.characteristics.handle('price').one() %}
{% set value = characteristic.values.value('$').one() %}
{# Get the first restaurant with a price "$" #}
{% set restaurants = craft.entries.section('restaurants').relatedTo(['and', {targetElement: characteristic.id}, {targetElement: value.id}]) %}
{{ restaurants.one().title }}
```

### Terminology &amp; Concepts

[](#terminology--concepts)

#### Characteristic Group

[](#characteristic-group)

Contains a collection of Characteristics, its Values, and Links. Allows you maintain a separation of Characteristics that are unrelated. For example: 'Product Characteristics', 'Restaurant Characteristics'

#### Characteristic

[](#characteristic)

An Element that represents the descriptive attribute to assign to another element. For example: "Material", "Flow Rate", "Open on Sundays". A Characteristic may have custom fields.

#### Characteristic Value

[](#characteristic-value)

An Element that represents a potential value for a Characteristic. Each Characteristic Value is relative to a specific Characteristic. A Characteristic Value has a `value` attribute that is a text string that is unique to each Characteristic. For example: "Yes", "No", "1.25".

#### Characteristic Link Block

[](#characteristic-link-block)

An Element that contains the linkage between a particular Characteristic, a number of Characteristic Values, the field it was created from, as well as the element its attached to.

#### Characteristic Field

[](#characteristic-field)

A custom field that allows you to create Characteristic Links. It may be used on any element that supports field layouts (Entries, Products, Categories, etc.). When used in templating, it returns a Query object for Characteristic Links that is configured for the soruce element and field.

###  Health Score

35

—

LowBetter than 80% of packages

Maintenance55

Moderate activity, may be stable

Popularity13

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 98.2% 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 ~118 days

Recently: every ~318 days

Total

12

Last Release

993d ago

### Community

Maintainers

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

---

Top Contributors

[![Mosnar](https://avatars.githubusercontent.com/u/3810939?v=4)](https://github.com/Mosnar "Mosnar (168 commits)")[![jrm98](https://avatars.githubusercontent.com/u/2946458?v=4)](https://github.com/jrm98 "jrm98 (3 commits)")

---

Tags

craftcraft-plugincraft3craftcmsplugincmsCraftcraftcmscraft-plugincharacteristic

### Embed Badge

![Health badge](/badges/venveo-craft-characteristic/health.svg)

```
[![Health](https://phpackages.com/badges/venveo-craft-characteristic/health.svg)](https://phpackages.com/packages/venveo-craft-characteristic)
```

###  Alternatives

[verbb/navigation

Create navigation menus for your site.

90683.7k17](/packages/verbb-navigation)[verbb/formie

The most user-friendly forms plugin for Craft.

101372.9k40](/packages/verbb-formie)[verbb/comments

Add comments to your site.

13753.1k](/packages/verbb-comments)[verbb/tablemaker

Create customizable and user-defined table fields.

40168.8k1](/packages/verbb-tablemaker)[supercool/tablemaker

Create customizable and user-defined table fields.

40141.7k](/packages/supercool-tablemaker)[pennebaker/craft-architect

CraftCMS plugin to generate content models from JSON/YAML data.

72148.5k5](/packages/pennebaker-craft-architect)

PHPackages © 2026

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