ExpressionEngine Docs

Developing Prolets


Prolets are add-on components that live in the Dock and bring parts of an add-on’s functionality to content editors on the front end.

Here is an example of the add-on SEEO’s prolet, which easily allows editors to edit SEO data for the entry they are currently viewing: prolet example

Before adding a Prolet to your add-on, you need to already have an add-on in place. See Building An Add-On: Getting Started for how to generate the starter files for your add-on.

Creating An Amazing Prolet

Creating a Prolet is straightforward using the make:prolet command in the CLI.

$ php system/ee/eecli.php make:prolet

Follow the prompts to add a prolet to your add-on.

This will create a file in your add-on’s folder named pro.[addon_name].php

┣ pro.amazing_add_on.php

Anatomy Of A Prolet

Inside a prolet file, you are required to define the prolet class. The class name should consist of prolet name with the first letter capitalized followed by _pro postfix. So for the example above, the class name will be Sample_prolet_pro.

All prolets are required to implement ExpressionEngine\Addons\Pro\Service\Prolet\ProletInterface. The easiest way to achieve that is to make prolet extend abstract class ExpressionEngine\Addons\Pro\Service\Prolet\AbstractProlet.

When using the CLI, this file will be properly constructed for you.

When generated with the CLI, your prolet will initially look like this:


use ExpressionEngine\Addons\Pro\Service\Prolet\AbstractProlet;
use ExpressionEngine\Addons\Pro\Service\Prolet\ProletInterface;

class Amazing_add_on_pro extends AbstractProlet implements ProletInterface
    protected $name = 'Amazing Prolet';

    public function index()
        return 'This is a new prolet generated from the CLI.';


On each page load, prolets appear on the front-end as Dock buttons. If not specified otherwise, icon.svg from the add-on package folder is used as the Dock button. If you want to specify a different icon to use from the add-on’s folder, you can do that using protected $icon property or public function getIcon().

protected $icon = 'sample_prolet.png';


public function getIcon()
    return 'sample_prolet.png';


Each prolet is required to have a name, which is used as the title for the Dock button and also for the prolet’s popup window. It can be defined using protected $name property or public function getName(). Using the function is recommended because you are able to use the lang key in it, making the name translatable.

protected $name = 'Sample Prolet';


public function getName()
    return lang('sample_prolet');

Popup Window Size

If the prolet is opening a popup window (which is what currently all prolets are doing), you are able to specify the window size. Available options are footer, large and small (default). You do this using the protected $size property or public function getSize().

protected $size = 'footer';


public function getSize()
    return 'large';

Popup Window Buttons

By default, each prolet popup window is generated with a “Save” button in the footer that sends the “save” JavaScript event to the prolet. You can change that to display different buttons, or no buttons at all, using the protected $buttons property or public function getButtons().

protected $buttons = []; // No buttons will be shown


public function getButtons()
    return [
        ['text' => lang('do_something_cool'), 'event' => 'let_everyone_know'],
        ['text' => lang('do_something_else'), 'event' => 'keep_secret']

Controller Action

Prolets are required to contain a method which will generate the data to be outputted. By default, this is assumed to be the index() method. However you can specify a different function name using protected $action property or public function getAction().

protected $action = 'do_something_cool';


public function getAction()
    return 'do_something_else';

The prolet’s action method (public function index(); or function with name returned by getAction() as explained above) can return an array of data or a string.

If the data returned is of Array type, it is being passed to ExpressionEngine Pro’s shared form view, which is similar to ExpressionEngine’s Shared Form View, however you are only required to have sections key in the returned data array. The result will be a form with submission endpoint being set to same prolet controller action.

public function index()
    if (ee('Request')->isPost()) {
        //handle form submission
        return ee()->output->send_ajax_response(['success']);
    $vars['sections'] = array(
          'title' => 'site_name',
          'fields' => array(
            'site_name' => array(
            'type' => 'text',
            'value' => $site->site_label,
            'required' => TRUE
    return $vars;

If the data returned is of String type then this string is being wrapped in some required HTML and returned into the prolet popup window. In you need a form to be created, you would need to handle that (additionally you can use one of your actions as endpoint).

Prolets are expecting form submissions to return JSON upon successful response, which will close their windows.

Prolet Types

Essentially there are two types of prolets.

Non-initializable prolets are displayed and allow data manipulation on every page of website where the Dock is enabled.

Initializable prolets work the same way, but they are only displayed on pages where they have been initialized, which usually would happen by placing certain template tags in the template.

Initializable Prolets

Initializable prolets are required to implement ExpressionEngine\Addons\Pro\Service\Prolet\InitializableProletInterface.

use ExpressionEngine\Addons\Pro\Service\Prolet;

class Sample_prolet_pro extends Prolet\AbstractProlet implements Prolet\InitializableProletInterface
    protected $name = 'Sample prolet';

    public function index()
        return 'Hello world!';

In order for the prolet to be initialized, the template tag from your add-on needs to be called on page. In the programmatic code for that tag, you would need to place a call to ee('pro:Prolet')->initialize()

if (defined('IS_PRO') && IS_PRO) {
    ee('pro:Prolet')->initialize('sample_prolet', ['entry_id' => $entry_id]);

You would need to make sure to wrap the code in if (defined('IS_PRO') && IS_PRO) { conditional, so it would be run only on ExpressionEngine versions that support Pro and have it installed.

Two parameters need to be passed to ee('pro:Prolet')->initialize() function. First is the prolet name, in our example sample_prolet. Second is an array of data that is being passed to prolet via GET request (in our example we pass entry_id).