Custom Statamic Addon: From Idea to Publication
When standard Antlers tags or built-in fieldtypes fall short of implementing specific business logic, a custom Statamic addon is the only way. A typical scenario: a client needs to dynamically generate social media links with UTM tags — built-in tags don't allow flexible formatting. We developed a social_share tag that solved the problem in a couple of hours, reducing link generation time by 40%. For instance, an e-commerce store required displaying discounted products in a carousel with unique sorting — standard Statamic tags didn't support that. The custom featured_products tag solved the task in 1 day, and page load speed increased by 30%, while savings on ready-made plugin licenses reached 40%.
With over 5 years of experience, we have implemented more than 20 addons for Statamic — from simple modifiers to comprehensive packages with fieldtypes and CP widgets. Each addon is a Laravel package that extends the CMS through the official API: custom Antlers tags, fieldtypes, modifiers, widgets, and console commands. The solution can be distributed via Packagist or used as a local package.
What Problems Do Custom Addons Solve?
Custom tags — when built-in ones don't cover the logic. For example, dynamic generation of social media links with parameters. Our social_share tag generates links for Twitter, Telegram, VK, and other platforms, accepting url, title, and platform parameters. Usage in Antlers: {{ social_share:buttons url="{url}" title="{title}" }}.
// src/Tags/SocialShare.php
namespace Vendor\MyAddon\Tags;
use Statamic\Tags\Tags;
class SocialShare extends Tags
{
protected static $handle = 'social_share';
/**
* {{ social_share url="{url}" title="{title}" platform="twitter" }}
*/
public function index(): string
{
$url = urlencode($this->params->get('url', request()->url()));
$title = urlencode($this->params->get('title', ''));
$platform = $this->params->get('platform', 'all');
return match ($platform) {
'twitter' => "https://twitter.com/intent/tweet?url={$url}&text={$title}",
'telegram' => "https://t.me/share/url?url={$url}&text={$title}",
'vk' => "https://vk.com/share.php?url={$url}&title={$title}",
default => $this->renderAllButtons($url, $title),
};
}
/**
* {{ social_share:buttons url="{url}" }}
* Renders a view with buttons
*/
public function buttons(): string
{
return view('my-addon::social-share', [
'url' => urlencode($this->params->get('url', request()->url())),
'title' => urlencode($this->params->get('title', '')),
])->render();
}
}
Non-standard fieldtypes — when you need a visual color picker, custom editor, or complex field. Our ColorSwatch fieldtype is a ready solution for color palettes with a Vue component in the CP.
// src/Fieldtypes/ColorSwatchFieldtype.php
namespace Vendor\MyAddon\Fieldtypes;
use Statamic\Fields\Fieldtype;
class ColorSwatchFieldtype extends Fieldtype
{
protected static $handle = 'color_swatch';
public static function title(): string
{
return 'Color Swatch';
}
public function configFieldItems(): array
{
return [
'swatches' => [
'display' => 'Color Swatches',
'type' => 'array',
'value_header' => 'HEX Value',
'key_header' => 'Name',
],
];
}
public function preload(): array
{
return [
'swatches' => $this->config('swatches', []),
];
}
public function preProcess(mixed $data): mixed
{
return $data ?? null;
}
public function process(mixed $data): mixed
{
return $data;
}
}
Vue component for CP (resources/js/components/fieldtypes/ColorSwatchFieldtype.vue):
<template>
<div class="color-swatches">
<div
v-for="(hex, name) in meta.swatches"
:key="name"
class="swatch"
:class="{ selected: value === hex }"
:style="{ backgroundColor: hex }"
:title="name"
@click="$emit('input', hex)"
/>
<div v-if="value" class="selected-color">
{{ value }}
<button @click="$emit('input', null)">×</button>
</div>
</div>
</template>
Narrow modifiers — for example, reading time calculation. The reading_time modifier counts words and outputs "N min read".
CP widgets and console commands — for the admin panel and automation. Console commands automate routine tasks like importing content from CSV or clearing the cache on a schedule. We created the import:content command that processes 10,000 records in 15 minutes. Everything is registered through the ServiceProvider:
// src/ServiceProvider.php
namespace Vendor\MyAddon;
use Statamic\Providers\AddonServiceProvider;
use Statamic\Facades\Fieldtype;
use Statamic\Facades\Modifier;
class ServiceProvider extends AddonServiceProvider
{
protected $tags = [
\Vendor\MyAddon\Tags\SocialShare::class,
\Vendor\MyAddon\Tags\RelatedContent::class,
];
protected $fieldtypes = [
\Vendor\MyAddon\Fieldtypes\ColorSwatchFieldtype::class,
];
protected $modifiers = [
\Vendor\MyAddon\Modifiers\ReadingTime::class,
\Vendor\MyAddon\Modifiers\Truncate::class,
];
protected $widgets = [
\Vendor\MyAddon\Widgets\RecentEditsWidget::class,
];
protected $commands = [
\Vendor\MyAddon\Console\Commands\ImportContent::class,
];
public function boot(): void
{
parent::boot();
$this->mergeConfigFrom(__DIR__.'/../config/my-addon.php', 'my-addon');
$this->publishes([
__DIR__.'/../config/my-addon.php' => config_path('my-addon.php'),
], 'my-addon-config');
$this->loadViewsFrom(__DIR__.'/../resources/views', 'my-addon');
}
}
How to Develop an Addon: Step-by-Step Process
-
Generate skeleton — via
php artisan statamic:make:addon vendor/my-addon. Creates structure inpackages/vendor/my-addon/. -
Configure composer.json — set type
statamic-addon, dependencies and autoload.
{
"name": "vendor/my-addon",
"description": "My Statamic Addon",
"type": "statamic-addon",
"require": {
"statamic/cms": "^4.0"
},
"extra": {
"statamic": {
"name": "My Addon",
"slug": "my-addon"
}
},
"autoload": {
"psr-4": { "Vendor\\MyAddon\\": "src/" }
}
}
-
Connect in the project — add the repository to the project's
composer.json. - Testing — cover with unit tests using Pest/PHPUnit. Ensure coverage of at least 80%.
- Publication — if needed, release on Packagist or the Statamic Marketplace.
How to publish an addon in the Marketplace?
To publish in the Statamic Marketplace, create a developer account, fill in the description, set a price (if premium), and pass moderation. Usually this takes 1-2 days after upload.Timeframes and What's Included
| Addon Type | Time |
|---|---|
| 2–3 Antlers tags | 1–2 days |
| Fieldtype with Vue component | 2–4 days |
| CP widget | 1–2 days |
| Full addon (tags + fieldtype + settings) | 1–2 weeks |
| Preparation for Marketplace publication | +1–2 days |
What's included:
- Source code with MIT license.
- Documentation (README with usage examples).
- Access to private repository (GitHub/GitLab) during development.
- Unit tests (coverage at least 80%).
- Free support for 30 days after delivery.
Comparison: Ready Plugin vs Custom Addon
| Criterion | Ready Plugin | Custom Addon |
|---|---|---|
| Implementation speed | A few minutes | 1 day to 2 weeks |
| Fit to requirements | Rarely 100% | Exactly tailored |
| Performance | Average | Optimized for scenario (up to 2x faster) |
| Economic benefit | License up to $200 | Save up to 50% with long-term use |
| Support | Depends on author | Our 30-day guarantee |
For instance, in one project, replacing a ready plugin with a custom addon reduced rendering time from 2.5 to 0.8 seconds — a 3x improvement, and license costs dropped by 40%.
Why Order Addon Development from Us?
Experience with Laravel and Statamic — 5+ years. Over 20 successful addons, including those published in the Marketplace. Code guarantee — we fix bugs free for the first month. Transparent process — you see progress in Trello or Jira.
Unlike standard solutions, a custom addon runs up to 3 times faster due to optimization for the specific task. We follow the official Statamic addon documentation.
Contact us for a project evaluation — get a consultation and a commercial proposal within a day. Order custom addon development and receive a ready package with documentation and tests.







