linksderisar/statamic-custom-select
A Statamic addon that adds a customizable select fieldtype for the control panel, giving editors a friendlier, configurable dropdown for choosing predefined options in your content models.
Because this addon has no public adoption signal (0 stars, 0 dependents), treat the first hour as reconnaissance rather than trusting a README.
Install and confirm auto-discovery
composer require linksderisar/statamic-custom-select
php artisan statamic:addons # confirm the addon is listed
Statamic auto-registers addons via extra.statamic in the package composer.json. If it does not appear, you are likely on Statamic 3/4/5 mismatch — check the statamic/statamic constraint in the package's composer.json before going further.
Look in this order
src/ServiceProvider.php — what the addon registers (fieldtype, config, views, routes, assets).src/Fieldtypes/*.php — the actual handle, $handle, component(), preload(), and augment().config/*.php — whether options are config-driven or blueprint-driven.resources/js/ — the Vue fieldtype component (its props tell you which blueprint keys matter).resources/views/ — any Antlers partials shipped with the package.Publish anything publishable
php artisan vendor:publish --provider="LinksDerisar\\StatamicCustomSelect\\ServiceProvider"
First use case — add the field to a blueprint and confirm it renders in the CP:
# resources/blueprints/collections/pages/page.yaml
tabs:
main:
sections:
- fields:
- handle: category
field:
type: custom_select # verify exact handle in src/Fieldtypes
display: Category
options:
news: News
blog: Blog
Load the entry edit screen. If the field renders but is empty, the fieldtype is reading options from config rather than the blueprint — jump to src/Fieldtypes/.
First use case to validate end-to-end: a single-select field on an entry, saved, then read in a template with {{ category }}. If that works, the augmentation path works.
Blueprint-first usage (most common). Define the field inline or via a reusable fieldset and include it:
# resources/fieldsets/seo_section.yaml
title: SEO
fields:
- handle: schema_type
field:
type: custom_select
display: Schema Type
clearable: true
options:
Article: Article
FAQPage: FAQPage
Product: Product
# in a blueprint
import:
- seo_section
This lets you change the option list in one place. Prefer this over repeating options: across blueprints.
Config-driven option sources. If the fieldtype ships a config file, you typically get a pattern like:
// config/custom-select.php
return [
'sources' => [
'categories' => fn () => \Statamic\Facades\Term::query()
->where('taxonomy', 'categories')
->get()
->mapWithKeys(fn ($t) => [$t->slug() => $t->title()])
->all(),
],
];
…and the blueprint references source: categories. Confirm the exact key names against src/Fieldtypes/ — this is the single most likely place the package diverges from convention.
Dynamic options in the blueprint itself. Statamic fieldtypes often accept closures; try:
- handle: author
field:
type: custom_select
options:
- value: "{{ id }}"
label: "{{ title }}"
If closures aren't supported, move them to config or a small custom fieldtype wrapper.
Reading values in Antlers. A plain select stores the stored key, not the label:
{{ if category }}
<span class="tag">{{ category }}</span>
{{ /if }}
If the fieldtype implements augmentation, you may get a LabeledValue-like object — test with {{ dump(category) }} locally before assuming {{ category }} prints the label. If it doesn't, wrap the label lookup:
{{ taxonomy:categories }}{{ if slug == category }}{{ title }}{{ /if }}{{ /taxonomy:categories }}
(or cache the map in a view composer).
Multiple selection. If max_items is exposed, treat the value as an array and iterate:
{{ categories }}
<li>{{ value }}</li>
{{ /categories }}
Conditional fields. Pair with Statamic's show_when / if in the blueprint to reveal the field only when relevant, instead of building branching logic into the fieldtype.
Reuse in GraphQL/REST. Run php artisan statamic:stache:clear after adding the field, then check the field appears in the collection's GraphQL type. Small addons frequently skip fieldtypeToGraphQL — if it's missing, you'll get the raw value only, which is often fine.
Cache blindness. After any blueprint, config, or addon change:
php artisan statamic:stache:clear
php artisan cache:clear
php artisan config:clear
Most "the field isn't showing up" reports are stache cache.
Asset build. If resources/js/ contains a Vue component but there's no dist/ (or a stale one), the CP will render nothing or a red box. Check vendor/linksderisar/statamic-custom-select/resources/dist exists; if not, run the package's own build (npm i && npm run build inside vendor/..., or better, fork and npm link).
Handle mismatch. The blueprint type: must match the fieldtype's $handle exactly, including namespace. Try both custom_select and linksderisar-custom-select / linksderisar.custom_select if one 404s in the CP with "Fieldtype not found".
Options shape. Statamic expects ['key' => 'Label'] in PHP and [{value, label}] in YAML. Mixed shapes silently produce blank dropdowns. When debugging, dd($field->config()) inside a temporary preload() is the fastest check.
Label vs. value in templates. The stored value is the key/slug. Don't assume the fieldtype augments. Explicitly map labels or store the label separately if editors need it displayed verbatim.
Version pinning. With 0 stars and 0 dependents, there is no community to catch breakage. Pin in composer.json ("linksderisar/statamic-custom-select": "1.*") and add a composer.lock review step to your upgrade process. If the repo goes quiet, vendor it into app/Fieldtypes/ — it's likely a few hundred lines.
Extension point to prefer. Rather than patching the vendor package, subclass it:
namespace App\Fieldtypes;
class CategorySelect extends \LinksDerisar\StatamicCustomSelect\Fieldtypes\CustomSelect
{
protected function getOptions(): array { /* your source */ }
}
then register in your own AppServiceProvider and use type: category_select. Safe across composer update.
Debugging flow when something's wrong: (1) does the field render? (2) do options render? (3) does saving persist? (4) does the template show it? Each step isolates CP-asset → fieldtype logic → YAML → augmentation, which is the four places this class of addon breaks.
Test in the CP, not just via console. Use php artisan tinker with Entry::find(...)->get('category') to confirm the stored value; divergence between that and the CP display points squarely at augmentation in the fieldtype.
Contribution angle. Given the zero-adoption status, the highest-leverage move is a small PR (or fork) adding a README example, a preload() that exposes option sources, and an augment() returning LabeledValue. That turns an unknown addon into an internal one you can reason about.
How can I help you explore Laravel packages today?