Documentation

How to build an add-on

Extend Linsei with your own code (without touching the core) using the hooks system. Full guide with a working example.

1. What an add-on is

An add-on is a folder inside plugins/ with a plugin.php file. Linsei loads it automatically on startup. Your code «hooks» into specific points of the program (the hooks) to add features, without modifying the core. That way your add-on survives Linsei updates.

plugins/ └─ my-addon/ └─ plugin.php

2. Minimal structure

Every plugin.php starts with this safety line (it prevents direct execution):

<?php if(!defined("PL_APP")){http_response_code(403);exit;} /* Add-on: My first add-on */ pl_add_action('dashboard_after', function ($isAdmin) { echo '<div class="card">Hello from my add-on!</div>'; });

Copy that folder into plugins/ and, on reloading the panel, you'll see your card. That's it: you have an add-on.

3. Actions and filters

There are two ways to hook in:

  • Actions (pl_add_action): run your code at a given moment (e.g. render something in the panel).
  • Filters (pl_add_filter): receive a value, transform it and return it (e.g. change the target URL).
// Action: do something pl_add_action('link_created', function ($slug, $url) { // e.g. notify a webhook }); // Filter: transform a value (always return it) pl_add_filter('link_destination', function ($url) { return $url; // here you could modify the URL });

4. Available hooks

HookTypeWhenArguments
initactionon every request-
admin_menuactionwhen the sidebar is drawn$user
dashboard_afteractionat the end of the home panel$isAdmin
links_toolbaractionLinks button bar-
link_form_fieldsactionin the link form$link
link_row_actionsactionactions on each row$link
help_afteractionat the end of Help-
link_createdactionwhen a link is created$slug, $url
link_savedactionon save (create/edit)$id, $post
link_clickedactionon every click$link
link_destinationfiltertransforms the target on shortening$url
link_redirectfilterdecides the redirect$decision, $link, $ctx
redirect_interstitialfilterHTML before redirecting$html, $link, $target, $ctx
Your own panel page: with pl_add_plugin_menu(title, url, icon, route) you add a menu entry, and in init you handle that route. Icons come from Bootstrap Icons.

5. Full example

This add-on colors each link in the Links list by its clicks: red for few visits, amber for so-so and green for many. Tweak $few and $many to taste:

<?php if(!defined("PL_APP")){http_response_code(403);exit;} /* Add-on: Visit traffic light */ pl_add_action('link_row_actions', function ($link) { $clicks = (int)($link['click_count'] ?? 0); $few = 10; // fewer than 10 clicks: red $many = 100; // more than 100 clicks: green if ($clicks < $few) { $color = '#dc2626'; } // red elseif ($clicks > $many) { $color = '#16a34a'; } // green else { $color = '#f59e0b'; } // amber echo '<span style="background:' . $color . ';color:#fff;' . 'border-radius:999px;padding:1px 8px;font-size:.75rem">' . $clicks . '</span>'; });

Letting the admin set the thresholds

To avoid hardcoding the numbers, read them from the settings store (the same one the core uses for SMTP) with pl_app_setting() and give the add-on its own page where the admin changes them:

<?php if(!defined("PL_APP")){http_response_code(403);exit;} /* Add-on: configurable traffic light */ // 1) In the traffic light, read the thresholds from the store (with defaults) $few = (int) pl_app_setting('semaforo_few', 10); $many = (int) pl_app_setting('semaforo_many', 100); // 2) On the add-on page, save whatever the admin submits if (($_POST['save'] ?? '') !== '') { pl_app_settings_save([ 'semaforo_few' => (int)($_POST['few'] ?? 10), 'semaforo_many' => (int)($_POST['many'] ?? 100), ]); } // 3) Add its entry to the panel menu (admin only) pl_add_plugin_menu('Traffic light', '/admin/traffic-light', 'bi-sliders', '/admin/traffic-light');
Where the values live: in data/settings.json, via pl_app_setting() and pl_app_settings_save() (the same store as the core SMTP). The admin changes the thresholds without touching the code.
Use your own prefix in your functions (e.g. pl_my_) to avoid clashing with other add-ons.

6. Package and share

When it works, zip the folder of your add-on into a .zip and upload it from the panel:

  1. Go to Add-ons.
  2. Click «Upload add-on» (top right).
  3. Pick your .zip and it installs instantly.
An add-on runs code on your server: upload only ones you trust. Only the admin can upload them.