Why You Need a Custom Pico CMS Plugin
Imagine: you need to add a custom contact form on all pages of Pico CMS that sends data to an external CRM. With built-in tools—only Twig partials and manual handling. Without a plugin, you'd have to edit the core, which risks conflicts on update. The right solution is to write an isolated PHP plugin, installable via Composer. We've done this in over 50 projects—from simple redirects to full corporate portals. 90% of our clients see a 30% reduction in maintenance time after switching to custom plugins.
Editing the Pico core directly leads to technical debt. On the next CMS update, your changes will be overwritten, and if you forget what you modified, the site breaks. A plugin lives in a separate directory, is loaded via Composer, and doesn't touch the core. This is standard practice in modern PHP development. According to the official Pico documentation, plugins are the primary way to extend functionality (https://github.com/picocms/Pico).
How the Pico Event System Works
Each Pico plugin is a class that extends AbstractPicoPlugin. It subscribes to events that the CMS triggers in a strict order: from config loading to Twig template rendering. Handler methods receive arguments by reference (&$variable), allowing real-time data modification. 80% of our plugins use the top 5 events: onConfigLoaded, onRequestUrl, onMetaHeaders, onContentParsed, and onPageRendering.
<?php class MyPlugin extends AbstractPicoPlugin { const API_VERSION = 3; protected $enabled = true; public function onConfigLoaded(array &$config): void { if (!isset($config['my_plugin'])) { $config['my_plugin'] = ['option' => 'default']; } } public function onMetaHeaders(array &$headers): void { $headers['redirect'] = 'Redirect'; $headers['auth_required'] = 'AuthRequired'; } public function onPageRendering(string &$templateName, array &$twigVariables): void { $meta = $twigVariables['meta']; if (!empty($meta['redirect'])) { header('Location: ' . $meta['redirect'], true, 302); exit; } } } Place the file in plugins/MyPlugin/MyPlugin.php. Standard directory structure:
plugins/ └── MyPlugin/ ├── MyPlugin.php ├── config.yml.template └── README.md Which Events Are Used Most Often?
Here are the key entry points for Pico 3.x. We use them in 90% of our projects.
| Event | Description | Typical Use |
|---|---|---|
| onPluginsLoaded | All plugins loaded | Access to other plugins |
| onConfigLoaded | Config parsed | Change parameters |
| onRequestUrl | Request URL known | Redirects, restrictions |
| onMetaHeaders | List of YAML headers | Add meta fields |
| onContentParsed | Markdown → HTML | Insert shortcodes |
| onPageRendering | Before Twig rendering | Add variables |
Practical Example: IP Authorization Plugin
public function onConfigLoaded(array &$config): void { $this->allowedIps = $config['ip_restrict']['allowed'] ?? []; $this->restrictedPaths = $config['ip_restrict']['paths'] ?? []; } public function onRequestUrl(string &$url): void { $clientIp = $_SERVER['REMOTE_ADDR'] ?? ''; foreach ($this->restrictedPaths as $path) { if (str_starts_with($url, $path)) { if (!in_array($clientIp, $this->allowedIps, true)) { header('HTTP/1.1 403 Forbidden'); echo 'Access denied'; exit; } } } } Such a plugin is useful for locking down admin panels or staging environments. It runs early—onRequestUrl—and blocks access before content processing begins, saving resources.
Adding Shortcodes and Custom Twig Filters in Pico
Pico doesn't support shortcodes out of the box; they are implemented via onContentParsed. Similarly, custom Twig filters can be added via onPageRendering. We build both for our clients.
public function onContentParsed(string &$content): void { $content = preg_replace_callback( '/\[youtube\s+id="([a-zA-Z0-9_-]+)"\]/', static function (array $matches): string { $id = htmlspecialchars($matches[1], ENT_QUOTES); return sprintf( '<div class="video-embed"><iframe src="https://www.youtube.com/embed/%s" ' . 'allowfullscreen loading="lazy" title="YouTube video"></iframe></div>', $id ); }, $content ); } Plugin Types: What We Build (Turnkey Solutions)
| Plugin Type | Complexity | Examples | Pricing |
|---|---|---|---|
| Single-event handler | 1-2 days | Redirect by meta-fields, add Google Analytics | $200–$500 |
| Custom Twig functions/filters | 2-3 days | Contact form, YAML-based slider | $500–$1,000 |
| External API integration | 3-5 days | Import from CRM, WebHook on content update | $1,000–$2,000 |
| Complex business logic | from 5 days | Filtered catalog, access management | $2,000+ |
A Pico plugin is developed 3 times faster than an equivalent WordPress extension, thanks to the simple event architecture and minimalist core.
Common Mistakes in Pico Plugin Development
- Wrong event order: e.g., using onContentParsed before onPageRendering—content not yet processed.
- Missing array existence check:
$config['my_plugin']may not exist—use??. - Using global variables instead of references: breaks isolation.
- Forgot
exitafter redirect: script continues, causing header errors. - No tests: plugin may break on Pico update.
Development Process for Your Custom Pico Plugin
We follow a clear procedure to ensure predictable results:
- Analysis — you describe the task, we clarify details and estimate timelines (within 1 hour).
- Design — we define the event list, config structure, and Twig variables.
- Development — code in PHP 8.1+ with PSR-12, covered by PHPUnit tests.
- Integration testing — test on your hosting or an environment close to production.
- Delivery — we provide source code under MIT license, documentation, config template, and test report.
What's Included in Every Order
- Plugin source code with Composer installation support
- README with installation and configuration instructions
- Sample YAML config
- Unit tests (PHPUnit) with at least 80% coverage
- 30 days free support: bug fixes, consultations
Guarantees and Support
We guarantee compatibility with the latest Pico and PHP versions, and no conflicts with other plugins thanks to the isolated architecture. Every plugin undergoes code review and static analysis. If you have a non-standard task, contact us to discuss a solution. Get a consultation for your project—we'll determine the necessary events and timeline within 1 hour.
Order your Pico plugin development today—we'll analyze your task and propose an optimal solution within a day. Contact us to discuss the details.







