কনটেন্ট ও চেহারা

প্লাগিন

এই অধ্যায়টি এখনও অনুবাদ হয়নি, তাই ইংরেজিতে দেখানো হচ্ছে।

এই পাতায়

A plugin adds a feature to the site: an app, a contact form, a page of reviews, a second way of reading videos. The platforms the site downloads from (YouTube, TikTok ...) are not plugins but modules; they are explained in Platforms and modules.

Admin → Plugins

Each plugin has a card with its name, version, description and author, and the badges Enabled, Premium or Does not load.

  • Enable runs the plugin's own set-up (its tables and defaults) and starts it. A plugin that needs a newer version of the script says so, for example "needs AIO Downloader 1.5.0 or newer".
  • Disable stops it. Its settings and its data stay, so enabling it again brings everything back.
  • Settings (for plugins that have some) opens a form inside the card; Save settings stores it.
  • Open (for plugins with screens of their own) leads to those screens. They are also listed in the admin menu, in a group called Plugins above Settings; a red number there counts new items, such as reviews that wait for you.
  • The bin button deletes a plugin after you confirm: it is switched off, its folder and its saved settings are removed. Tables it made stay in the database.
  • Upload a plugin → Install plugin takes a ZIP with one folder that holds plugin.json and plugin.php. A newer ZIP of an installed plugin replaces its files and keeps its settings. A module or a theme uploaded here is recognised and put where it belongs.

Free and premium

A plugin is free unless its plugin.json says "tier": "premium". Free plugins work with every licence. A premium plugin shows Premium and, until your licence includes it, the line "Your licence does not include this premium plugin yet", with Enable greyed out. Add it to your licence on license.faruk.bd, press Check now on Admin → License, and it can be switched on (see The licence key). If the licence later loses it, the plugin stops running.

Uploading ZIP files can be switched off for a licence; the upload then says so.

When a plugin fails

  • Does not load: the plugin's files have an error. The badge shows on its card, Enable cannot be pressed, and the reason is in the Application log on System check ("Extension failed to load").
  • Fails while starting: the rest of the site keeps working and the log says "Plugin boot failed" with the reason. The plugin stays switched on, so press Disable until it is fixed or updated.
  • You cannot open the admin panel any more: rename the folder of the plugin by FTP or the File Manager so that it begins with an underscore, for example plugins/reviews → plugins/_reviews. The script skips such folders, so the plugin is off at once. Rename it back when it is fixed; its settings are still there.

The extensions on faruk.bd

All eleven are free on license.faruk.bd. Nine are plugins (Admin → Plugins); the two themes are switched on under Admin → Themes.

NameWhat it addsChapter
App BuilderAn installable web app at once, plus Android and iPhone projects; the Android app receives links shared from other apps.App Builder
yt-dlp BridgeRuns yt-dlp: private YouTube videos with the visitor's cookies, and a second chance when a module gives up.yt-dlp Bridge
External API FallbackAsks a Cobalt-compatible API when a module gives up.External API Fallback
Recent DownloadsA "Recently downloaded" strip on the home page and a download counter.Recent Downloads
Nova ThemeA complete second design; the theme of a new installation.Nova Theme
Midnight ThemeA darker, glassy variation of the classic layout.Midnight Theme
Contact FormA form for the Contact page with a spam wall without puzzles, an inbox, replies by e-mail.Contact Form
What's NewA public "What's new" page, written in every language of the site.What's New
ToolsSmall helpers for visitors; the first one joins a video and an audio file in the browser.Tools
Platform RequestsVisitors ask for a site to be supported and like each other's requests.Platform Requests
ReviewsStars and a few words, with approval, answers and a block on the home page.Reviews

Writing your own plugin

A plugin is a folder plugins/<slug>/; the folder name must equal the slug. It needs two files.

plugin.json describes it:

FieldMeaning
name, slug, version, descriptionwhat the Plugins page shows
author, author_uri"By ..." on the card
icona Bootstrap icon, for example bi-phone
requiresthe oldest script version it runs on
tierfree (the default) or premium

plugin.php returns an object that extends AbstractPlugin. In boot(), which runs on every request while the plugin is on, it registers what it needs:

  • hooks: add_filter() for html_head, html_footer, html_after_header, html_home_after_hero, html_page_after, html_results_before_formats, page_content, media_result, media_fallback, menu_items, admin_nav, site_credit_html, front_layout_vars, mail_transport and more; add_action() for download_start, media_fetched, settings_saved and cron;
  • pages: get('path', fn) and post(...), or front_route('path', fn) for a page at /<language>/path in every language, drawn with render_front_page($title, $html).

Other methods: install() runs when the plugin is enabled, uninstall() when it is disabled. settingsFields() lists the fields of its settings form; read them with $this->setting('name', $default). adminMenu() lists its admin screens (page, label, icon, count) and adminPage($page) draws them at /admin/plugin/<slug>/<page>. Texts go in languages/<code>.php (an array of key and text) and are printed with t('key').

A small example

This is the Recent Downloads plugin, shortened. Its plugin.json:

{
    "name": "Recent Downloads",
    "slug": "recent-downloads",
    "version": "1.0.0",
    "type": "feature",
    "description": "Shows a \"Recently downloaded\" strip on the homepage.",
    "author": "MD OMAR FARUK",
    "author_uri": "https://faruk.bd"
}

Its plugin.php:

<?php
declare(strict_types=1);

return new class extends AbstractPlugin {
    public function boot(): void
    {
        add_filter('html_home_after_hero', [$this, 'render'], 10);
    }

    public function settingsFields(): array
    {
        return [
            ['name' => 'count', 'label' => 'How many titles', 'type' => 'number', 'default' => '8'],
            ['name' => 'heading', 'label' => 'Heading', 'type' => 'text', 'default' => 'Recently downloaded'],
        ];
    }

    public function render(string $html): string
    {
        $n = max(1, min(30, (int) $this->setting('count', 8)));
        $rows = cache_remember('plugin:recent-downloads', 120, fn(): array => db_rows(
            'SELECT `title` FROM ' . table('history') . ' WHERE `title` <> "" ORDER BY `id` DESC LIMIT ' . $n));
        if (!$rows) {
            return $html;
        }
        $out = '<section class="section"><div class="container"><strong>'
            . e((string) $this->setting('heading', 'Recently downloaded')) . '</strong> ';
        foreach ($rows as $r) {
            $out .= '<span class="badge">' . e(str_limit((string) $r['title'], 40)) . '</span> ';
        }
        return $html . $out . '</div></section>';
    }
};

A filter receives the HTML so far and returns it with its own part added. Escape what you print with e(), keep boot() light, and never call a function of another plugin: it may be switched off.

Chat with Faruk
Faruk's Assistant Online — AI Powered