Plugins

Introduction

A plugin allows you to add new features to your site, to many plugins are available on our Market, and you can also create one if you can’t find one that matches your needs.

Creating a plugin

Before creating a plugin, it is recommended that you read the Laravel documentation.

When Azuriom is installed locally for plugin development, it’s highly recommended enabling debug to simplify development. This can be done by simply editing these 2 lines in the .env file:

APP_ENV=local
APP_DEBUG=true

Structuring a plugin

plugins/  <-- Folder containing the different installed plugins
|  example/  <-- Id of your plugin
|  |  plugin.json  <-- The main file of your theme containing the various information
|  |  assets/  <-- The folder containing the assets of your plugin (css, js, images, svg, etc)
|  |  database/
|  |  | migrations/ <-- The folder containing your plugin's migrations
|  |  resources/
|  |  |  lang/  <-- The folder containing the translations of your plugin
|  |  |  views/  <-- The folder containing the views of your plugin
|  |  routes/ <-- The folder containing the different routes of your plugin
|  |  src/ <-- The folder containing the sources of your plugin

The plugin.json file

The plugin.json file is required to load a plugin, and contains the different information of a plugin:

{
    "id": "example",
    "name": "Example",
    "version": "1.0.0",
    "description": "A great plugin.",
    "url": "https://azuriom.com",
    "authors": [
        "Azuriom"
    ],
    "azuriom_api": "1.0.0",
    "providers": [
        "\\Azuriom\\Plugin\\Example\\Providers\\ExampleServiceProvider",
        "\\Azuriom\\ Plugin\\Example\\Providers\\RouteServiceProvider"
    ]
}

Plugin ID

Each plugin must have an id, which must be unique and contain only numbers, lowercase letters and dashes. It is recommended to use the name as a basis for creating the id, for example if the name is Hello World, the id could be hello-world. Also, the plugin’s directory must have the same name as its id.

To create a plugin you can use the following command that will automatically generate the plugin’s folder and many files by default:

php artisan plugin:create <plugin name>

Dependencies

The dependencies section allows you to specify the plugins (using their id) that must be installed in order to use the plugin. A ? after the plugin name means that the plugin is optional, i.e., it does not need to be installed, but when it is, the version must match. It is also possible to specify a version of Azuriom using the value azuriom.

For example, this plugin needs Azuriom 0.4.0 or higher, the Shop plugin version 0.1.0 or higher. Also, when the Vote plugin is installed, it must be in version 0.2.0 or higher:

"dependencies": {
    "azuriom": "^0.4.0",
    "shop": "^0.1.0",
    "vote?": "^0.2.0"
}

Routes

Routes allow you to associate a URL with a particular action.

They are stored in the routes directory at the root of the plugin.

For more information on how routes work you can read the Laravel documentation.

Example:

Route::get('/support', 'SupportController@index')->name('index');
Please be careful not to use routes with closures, as these are not compatible with some internal optimizations.

Admin routes

For a route to be in the admin panel, just place it in the file routes/admin.php of the plugin.

Views

The views are the visible part of a plugin, they are the content files HTML of the plugin to display a page.

Azuriom using Laravel, views can be made using the Blade. If you don’t master Blade it is highly recommended reading its documentation, especially since it is quite short.

It is highly recommended NOT to use PHP syntax. when you work with Blade, because Blade does not bring you the traditional no advantages and only disadvantages.

To display a view you can use view('<plugin id>::<name of the view>'), of example view('support::tickets.index') to display the tickets.index view of the support plugin.

To define the layout of the page, it is necessary that the view extends the view containing the layout, you can either use the default layout (or the theme layout if there is one) with @extends('layouts.app'), or create your own layout and extend it.

Then put all the main content into the content section, and the title of the page in the title section.

@extends('layouts.app')

@section('title', 'Page name')

@section('content')
    <div class="container content">
        <h1>A title</h1>

        <p>A text</p>
    </div>
@endsection

Assets

The assets (CSS, JS, images, etc.) are located in the assets/ folder and can be used with the plugin_asset('<plugin id>', '<asset path>') function.

Assets can be included in the page via a Blade stack. in 2 different places on the page depending on the type of asset:

  • styles for CSS files (located in the <head>)
  • scripts for JS files (located in the <head>, don’t forget to add the defer attribute to the script, so they do not block the page rendering)

Example:

@push('scripts')
    <script src="{{ plugin_asset('vote', 'js/vote.js') }}" defer></script>
@endpush

Admin view

For a page to use the admin panel layout, just use the layout admin.layouts.admin, it is also recommended creating an admin folder in the resources folder and put the admin views in it.

Controllers

Controllers are a central part of a plugin, they are located in the folder src/Controllers at the root of the plugin, and they take care of to transform a request into the answer that will be sent back to the user.

For more information on how the controllers work you can read the Laravel documentation.

example:

<?php

namespace Azuriom\Plugin\Support\Controllers;

use Azuriom\Http\Controllers\Controller;
use Azuriom\Plugin\Support\Models\Ticket;

class TicketController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        // We're picking up all the tickets
        $tickets = Ticket::all();

        // We're return a view, pass him the tickets...
        return view('support::tickets.index', [
            'tickets' => $tickets,
        ]);
    }
}

Models

Templates represent an entry in a database table, and allow you to interact with the database.

You can also define in a model the different relationships of the model, For example, a ticket can have a user and a category, and have comments.

You can find more information about models (also called Eloquent on Laravel) in the Laravel documentation.

<?php

namespace Azuriom\Plugin\Support\Models;

use Azuriom\Models\Traits\HasTablePrefix;
use Azuriom\Models\Traits\HasUser;
use Azuriom\Models\User;
use Illuminate\Database\Eloquent\Model;

class Ticket extends Model
{
    use HasTablePrefix;
    use HasUser;

    /**
     * The table prefix associated with the model.
     *
     * @var string
     */
    protected $prefix = 'support_';

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'subject', 'category_id',
    ];

    /**
     * The user key associated with this model.
     *
     * @var string
     */
    protected $userKey = 'author_id';

    /**
     * Get the user who created this ticket.
     */
    public function author()
    {
        return $this->belongsTo(User::class, 'author_id');
    }

    /**
     * Get the category of this ticket.
     */
    public function category()
    {
        return $this->belongsTo(Category::class);
    }

    /**
     * Get the comments of this ticket.
     */
    public function comments()
    {
        return $this->hasMany(Comment::class);
    }
}

Service Provider

The service providers are the heart of a plugin, they are called at the initialization stage. of Laravel, and allow to save the different parts of a plugin (views, translations, middlewares, dependencies, etc.).

Service providers must be added to the providers part of the plugins.json:

{
    "providers": [
        "\\Azuriom\\Plugin\\Support\\Providers\\SupportServiceProvider"
    ]
}

You can find more information about the services provided in the Laravel documentation.

<?php

namespace Azuriom\Plugin\Support\Providers;

use Azuriom\Extensions\Plugin\BasePluginServiceProvider;

class SupportServiceProvider extends BasePluginServiceProvider
{
    /**
     * Register any plugin services.
     *
     * @return void
     */
    public function register()
    {
        $this->registerMiddlewares();

        //
    }

    /**
     * Bootstrap any plugin services.
     *
     * @return void
     */
    public function boot()
    {
        // $this->registerPolicies();

        $this->loadViews();

        $this->loadTranslations();

        $this->loadMigrations();

        $this->registerRouteDescriptions();

        $this->registerAdminNavigation();

        //
    }
}

Dependencies

Within your plugin directory run your usual composer require command.

Then add require_once __DIR__.'/../../vendor/autoload.php'; to the register method of the service provider of the plugin.

Make sure that the dependencies you require are not already provided by Azuriom to avoid versions conflicts and errors.

Migration

Migrations allow you to create, modify or delete tables in the database. data, they can be found in the database/migrations folder.

You can use the following command to automatically generate the migration file:

php artisan make:migration <migration name> --path plugins/<plugin id>/database/migrations 

You can find more information about migrations in the Laravel documentation.

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('support_tickets', function (Blueprint $table) {
            $table->increments('id');
            $table->string('subject');
            $table->unsignedInteger('author_id');
            $table->unsignedInteger('category_id');
            $table->timestamp('closed_at')->nullable();
            $table->timestamps();

            $table->foreign('author_id')->references('id')->on('users');
            $table->foreign('category_id')->references('id')->on('support_categories');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('support_tickets');
    }
};

Translations

Translations allow you to translate a plugin (amazing), they are found at in the resources/lang directory at the root of a plugin, in the language folder (en, fr, etc…).

You can find more information on translations in the Laravel documentation.

To retrieve a translation you can use the trans('<plugin id>::<filename>.<message>'), for example trans('support::messages.tickets.home') to display the tickets.home message, in the messages.php file of the support plugin:

<?php

return [
  'tickets' => [
    'home' => 'Your tickets',
  ],
];

Utilisateurs

It is recommended to register the main routes of your plugin so that they can be easily added in the navigation bar. To do this, simply call the $thiS->registerRouteDescriptions() method in the plugin provider and return the different routes in the routeDescriptions() method with the format [<route> => <description>]:

    /**
     * Bootstrap any plugin services.
     *
     * @return void
     */
    public function boot()
    {
        // ...

        $this->registerRouteDescriptions();
    }

    /**
     * Returns the routes that should be able to be added to the navbar.
     *
     * @return array
     */
    protected function routeDescriptions()
    {
        return [
            'support.tickets.index' => trans('support::messages.title'),
        ];
    }

Admin

To make your plugin’s admin pages appear in the navbar of the admin panel, you can register them by calling the method $this->registerAdminNavigation() and returning the different routes in the adminNavigation() method.

    /**
     * Bootstrap any plugin services.
     *
     * @return void
     */
    public function boot()
    {
        // ...

        $this->registerAdminNavigation();
    }

    /**
     * Return the admin navigations routes to register in the dashboard.
     *
     * @return array
     */
    protected function adminNavigation()
    {
        return [
            'support' => [
                'name' => trans('support::admin.title'), // Translation of the tab name
                'icon' => 'bi bi-joystick', // Bootstrap Icons icon
                'route' => 'support.admin.tickets.index', // Page's route
                'permission' => 'support.tickets', // (Optional) Permission required to view this page
            ],
        ];
    }