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.







