Кусочек кода из плагина Rainlab.User. Если предполагается набор действий для массового изменения состояния, то в интерфейсе их логично объединить в один пункт.

bulk-actions-octobercms.png

В контроллер необходимо добавить 2 метода. В index просто добавляем js код плагин, а в onBulkActions логика массовых изменений. Допускается только однозначные действия т.е. нет воможности показать модальное окно и уточнить действие у пользователя.

    public function index()
    {
        $this->addJs('/plugins/[vendorname]/[pluginname]/assets/js/bulk-actions.js');
        $this->asExtension('ListController')->index();
    }

    public function index_onBulkAction()
    {
        if (
            ($bulkAction = post('action')) &&
            ($checkedIds = post('checked')) &&
            is_array($checkedIds) &&
            count($checkedIds)
        ) {

            foreach ($checkedIds as $userId) {
                if (!$user = User::withTrashed()->find($userId)) {
                    continue;
                }

                switch ($bulkAction) {
                    case 'delete':
                        $user->forceDelete();
                        break;

                    case 'activate':
                        $user->attemptActivation($user->activation_code);
                        break;

                    case 'deactivate':
                        $user->delete();
                        break;

                    case 'restore':
                        $user->restore();
                        break;

                    case 'ban':
                        $user->ban();
                        break;

                    case 'unban':
                        $user->unban();
                        break;
                }
            }

            Flash::success(Lang::get('rainlab.user::lang.users.'.$bulkAction.'_selected_success'));
        }
        else {
            Flash::error(Lang::get('rainlab.user::lang.users.'.$bulkAction.'_selected_empty'));
        }

        return $this->listRefresh();
    }    

И в htm файл (стандартно это _list_toolbar.htm) панели инструментов:

    <div class="btn-group dropdown dropdown-fixed" data-control="bulk-actions">
        <button
            data-primary-button
            type="button"
            class="btn btn-default"
            data-request="onBulkAction"
            data-trigger-action="enable"
            data-trigger=".control-list input[type=checkbox]"
            data-trigger-condition="checked"
            data-request-success="$(this).prop('disabled', true).next().prop('disabled', true)"
            data-stripe-load-indicator>
            Массовые действия
        </button>
        <button
            type="button"
            class="btn btn-default dropdown-toggle"
            data-trigger-action="enable"
            data-trigger=".control-list input[type=checkbox]"
            data-trigger-condition="checked"
            data-toggle="dropdown">
            <span class="caret"></span>
        </button>
        <ul class="dropdown-menu" data-dropdown-title="Массовые действия">
            <li>
                <a href="javascript:;" class="oc-icon-trash-o" data-action="delete" data-confirm="<?= e(trans('rainlab.user::lang.users.delete_selected_confirm')) ?>">
                    <?= e(trans('rainlab.user::lang.users.delete_selected')) ?>
                </a>
            </li>
            <li role="separator" class="divider"></li>
            <li>
                <a href="javascript:;" class="oc-icon-user-plus" data-action="activate" data-confirm="<?= e(trans('rainlab.user::lang.users.activate_selected_confirm')) ?>">
                    <?= e(trans('rainlab.user::lang.users.activate_selected')) ?>
                </a>
            </li>
            <li role="separator" class="divider"></li>
            <li>
                <a href="javascript:;" class="oc-icon-user-times" data-action="deactivate" data-confirm="<?= e(trans('rainlab.user::lang.users.deactivate_selected_confirm')) ?>">
                    <?= e(trans('rainlab.user::lang.users.deactivate_selected')) ?>
                </a>
            </li>
            <li>
                <a href="javascript:;" class="oc-icon-user-plus" data-action="restore" data-confirm="<?= e(trans('rainlab.user::lang.users.restore_selected_confirm')) ?>">
                    <?= e(trans('rainlab.user::lang.users.restore_selected')) ?>
                </a>
            </li>
            <li role="separator" class="divider"></li>
            <li>
                <a href="javascript:;" class="oc-icon-ban" data-action="ban" data-confirm="<?= e(trans('rainlab.user::lang.users.ban_selected_confirm')) ?>">
                    <?= e(trans('rainlab.user::lang.users.ban_selected')) ?>
                </a>
            </li>
            <li>
                <a href="javascript:;" class="oc-icon-circle-o-notch" data-action="unban" data-confirm="<?= e(trans('rainlab.user::lang.users.unban_selected_confirm')) ?>">
                    <?= e(trans('rainlab.user::lang.users.unban_selected')) ?>
                </a>
            </li>
        </ul>
    </div>

В разрабатываемый плагин October CMS соответственно сам js плагин assets/js/bulk-actions.js

/*
 * Bulk actions plugin
 * 
 * Data attributes:
 * - data-control="bulk-actions" - enables the plugin on an element
 *
 * JavaScript API:
 * $('div').bulkActions()
 */

+function ($) { "use strict";

    // BULK ACTIONS CLASS DEFINITION
    // ============================

    var BulkActions = function(element, options) {
        this.options   = options
        this.$el       = $(element)

        // Init
        this.init()
    }

    BulkActions.DEFAULTS = {}

    BulkActions.prototype.init = function() {
        this.activeAction = null
        this.$primaryBtn = $('[data-primary-button]', this.$el)
        this.$toggleBtn = $('.dropdown-toggle', this.$el)
        this.$dropdownMenu = $('.dropdown-menu', this.$el)
        this.baseCss = this.$primaryBtn.attr('class')

        this.$primaryBtn.on('click', $.proxy(this.onClickPrimaryButton, this))
        this.$dropdownMenu.on('click', 'li > a', $.proxy(this.onClickMenuItem, this))

        this.setActiveItem($('li > a:first', this.$dropdownMenu))
    }

    BulkActions.prototype.onClickPrimaryButton = function() {
        if (!this.activeAction) {
            throw new Error('Bulk action not found')
        }

        this.$primaryBtn.data('request-data', {
            checked: $('.control-list').listWidget('getChecked'),
            action: this.activeAction
        })
    }

    BulkActions.prototype.onClickMenuItem = function(ev) {
        this.setActiveItem($(ev.target))
        this.$primaryBtn.click()
    }

    BulkActions.prototype.setActiveItem = function($el) {
        this.$toggleBtn.blur()
        this.activeAction = $el.data('action')
        this.$primaryBtn.text($el.text())
        this.$primaryBtn.attr('class', this.baseCss)
        this.$primaryBtn.addClass($el.attr('class'))
        this.$primaryBtn.data('request-confirm', $el.data('confirm'))
    }

    // BULK ACTIONS PLUGIN DEFINITION
    // ============================

    var old = $.fn.bulkActions

    $.fn.bulkActions = function (option) {
        var args = Array.prototype.slice.call(arguments, 1), result
        this.each(function () {
            var $this   = $(this)
            var data    = $this.data('oc.bulkactions')
            var options = $.extend({}, BulkActions.DEFAULTS, $this.data(), typeof option == 'object' && option)
            if (!data) $this.data('oc.bulkactions', (data = new BulkActions(this, options)))
            if (typeof option == 'string') result = data[option].apply(data, args)
            if (typeof result != 'undefined') return false
        })

        return result ? result : this
    }

    $.fn.bulkActions.Constructor = BulkActions

    // BULK ACTIONS NO CONFLICT
    // =================

    $.fn.bulkActions.noConflict = function () {
        $.fn.bulkActions = old
        return this
    }

    // BULK ACTIONS DATA-API
    // ===============

    $(document).render(function() {
        $('[data-control="bulk-actions"]').bulkActions()
    });

}(window.jQuery);