This forum has moved to a new location and is in read-only mode. Please visit talk.octobercms.com to access the new location.

planetadeleste
planetadeleste

Creating collapsible sidenav menu

On this tutorial, I will try to explain how to make a similar System sidebar collapsible menu.

Register navigation with extra options

In the registerNavigation() function of your plugin, add some extra options on sideMenu items.

This is an example of one plugin I'm developing.

public function registerNavigation(){
    return [
      'realestate' => [
        'label'       => \Lang::get('pronet.realestate::lang.app.name'),
        'url'         => Backend::url('pronet/realestate/dashboard'),
        'icon'        => 'icon-building',
        'permissions' => ['pronet.realestate.*'],
        'order'       => 500,
        'sideMenu'    => [
          'owners'              => [
            'label'       => \Lang::choice('pronet.realestate::lang.owners.title', 2),
            'icon'        => 'fa fa-users',
            'url'         => Backend::url('pronet/realestate/owners'),
            'permissions' => ['pronet.realestate.access_owners'],
            'group'       => 'owners',
            'description' => \Lang::get('pronet.realestate::lang.owners.description'),
          ],
          'zones'               => [
            'label'       => \Lang::choice('pronet.realestate::lang.zones.title', 2),
            'icon'        => 'fa fa-map-marker',
            'url'         => Backend::url('pronet/realestate/zones'),
            'permissions' => ['pronet.realestate.access_zones'],
            'group'       => 'address',
            'description' => \Lang::get('pronet.realestate::lang.zones.description'),
          ],
          'types'               => [
            'label'       => \Lang::choice('pronet.realestate::lang.types.title', 2),
            'icon'        => 'fa fa-building-o',
            'url'         => Backend::url('pronet/realestate/types'),
            'permissions' => ['pronet.realestate.access_types'],
            'group'       => 'properties',
            'description' => \Lang::get('pronet.realestate::lang.types.description'),
          ],
          'attributecategories' => [
            'label'       => \Lang::choice('pronet.realestate::lang.attributecategories.title', 2),
            'icon'        => 'fa fa-folder-open',
            'url'         => Backend::url('pronet/realestate/attributecategories'),
            'permissions' => ['pronet.realestate.access_attributecategories'],
            'group'       => 'attributes',
            'description' => \Lang::get('pronet.realestate::lang.attributecategories.description'),
          ],
          'attributes' => [
            'label'       => \Lang::choice('pronet.realestate::lang.attributes.title', 2),
            'icon'        => 'fa fa-puzzle-piece',
            'url'         => Backend::url('pronet/realestate/attributes'),
            'permissions' => ['pronet.realestate.access_attributes'],
            'group'       => 'attributes',
            'description' => \Lang::get('pronet.realestate::lang.attributes.description'),
          ],
          'pricetypes' => [
            'label'       => \Lang::choice('pronet.realestate::lang.pricetypes.title', 2),
            'icon'        => 'fa fa-font',
            'url'         => Backend::url('pronet/realestate/pricetypes'),
            'permissions' => ['pronet.realestate.access_pricetypes'],
            'group'       => 'prices',
            'description' => \Lang::get('pronet.realestate::lang.pricetypes.description'),
          ],
          'currencies' => [
            'label'       => \Lang::choice('pronet.realestate::lang.currencies.title', 2),
            'icon'        => 'fa fa-money',
            'url'         => Backend::url('pronet/realestate/currencies'),
            'permissions' => ['pronet.realestate.access_currencies'],
            'group'       => 'prices',
            'description' => \Lang::get('pronet.realestate::lang.currencies.description'),
          ],
          'transactions' => [
            'label'       => \Lang::choice('pronet.realestate::lang.transactions.title', 2),
            'icon'        => 'fa fa-exchange',
            'url'         => Backend::url('pronet/realestate/transactions'),
            'permissions' => ['pronet.realestate.access_transactions'],
            'group'       => 'prices',
            'description' => \Lang::get('pronet.realestate::lang.transactions.description'),
          ],
        ]
      ]
    ];
}

The extra parameters are group, description, keywords. Description and keywords are used like in System menu.

// http://octobercms.com/docs/plugin/registration#backend-settings
The optional keywords parameter is used by the settings search feature. If keywords are not provided, the search uses only the settings item label and description.

The group parameter work like the category parameter in backend settings.

Create partial files

In the root of your plugin, create a directory named partials with this files:

/plugins/pronet/realestate/partials/
    - _sidebar.htm                  // <-- New sidebar wrapper
    - _sidebar_menu_toolbar.htm     // <-- Search form on top of sidebar
    - _sidebar_menu.htm             // <-- Sidebar menu        

Sidebar Wrapper (_sidebar.htm)

Remember to edit the plugin address to your plugin.

<div class="layout-cell sidenav-tree" data-control="sidenav-tree" data-search-input="#settings-search-input">
    <div class="layout">
        <div class="layout-row min-size">
            <?= $this->makePartial('@/plugins/pronet/realestate/partials/_sidebar_menu_toolbar.htm') ?>
        </div>
        <div class="layout-row">
            <div class="layout-cell">
                <div class="layout-relative">
                    <div class="layout-absolute">
                        <div class="control-scrollbar" data-control="scrollbar">
                            <?= $this->makePartial('@/plugins/pronet/realestate/partials/_sidebar_menu.htm') ?>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

Sidebar Search Form (_sidebar_menu_toolbar.htm)

<div class="layout control-toolbar">
    <div class="layout-cell">
        <div class="relative toolbar-item loading-indicator-container size-input-text">
            <input placeholder="<?= e(trans('system::lang.settings.search')) ?>" type="text" name="search" value="" 
                class="form-control icon search"
                id="settings-search-input"
                autocomplete="off"
                data-track-input
                data-load-indicator
                data-load-indicator-opaque
            />
        </div>
    </div>
</div>

Sidebar Menu (_sidebar_menu.htm)

<?php
    $sideMenuItems = BackendMenu::listSideMenuItems();
    if ($sideMenuItems):
        $collapsedGroups = explode('|',
    isset($_COOKIE['sidenav_treegroupStatus']) ? $_COOKIE['sidenav_treegroupStatus'] : null);
    $categories = [];
    foreach ($sideMenuItems as $sideItemCode => $item){
        if(!property_exists($item, 'group'))
            $item->group = 'default';
        if(!property_exists($item, 'keywords'))
            $item->keywords = '';
        if(!property_exists($item, 'description'))
            $item->description = '';
        $categories[$item->group][$sideItemCode] = $item;
    }
?>        
    <ul class="top-level">
    <?php foreach ($categories as $category => $items):
            $collapsed = in_array($category, $collapsedGroups);
    ?>
        <li data-group-code="<?= e($category) ?>" <?= $collapsed ? 'data-status="collapsed"' : null ?>>
            <div class="group">
                <h3><?= e(trans('pronet.realestate::lang.global.sidenav.' . $category)) ?></h3>
            </div>
            <ul>
            <?php foreach ($items as $item): ?>
                <li class="<?= BackendMenu::isSideMenuItemActive($item) ? 'active' : null ?>"
                    data-keywords="<?= e(trans($item->keywords)) ?>">
                    <a href="<?= $item->url ?>">
                        <i class="<?= $item->icon ?>"></i>
                        <span class="header"><?= e(trans($item->label)) ?></span>
                        <span class="description"><?= e(trans($item->description)) ?></span>
                    </a>
                </li>
            <?php endforeach ?>
            </ul>
        </li>
    <?php endforeach ?>
    </ul>
<?php endif; ?>

Register Sidenav Partial in Plugin.php

public function register()
{
    BackendMenu::registerContextSidenavPartial('Pronet.RealEstate', 'realestate', '@/plugins/pronet/realestate/partials/_sidebar.htm');
}

Final Result

If I don't forget nothing ;) and you write all, can see something like this:

System Menu

My Plugin Menu

Plugin Collapsible Sidenav

Sorry my english. I hope this help someone...

Shahiem
Shahiem

Nice, I'll try it out.

sercanvirlan
sercanvirlan

it works like a charm ! thanks !

that0n3guy
that0n3guy

Good stuff... I'll try this out.

Rob Ballantyne
Rob Ballantyne

Thank you this is excellent and I'll be making use of it in my upcoming plugins.

kattsoff
kattsoff

It's really good, thx for idea.

webmaster
webmaster

Thanks i test, just you should add use BackendMenu; in plugin.php

fgomezserna5031
fgomezserna5031

Great work!! Perfect explain :)

jprevot
jprevot

I have problem with registerContextSidenavPartial

this partial is in partials folder The partial '@/plugins/minerd/dgetp/partials/__sidebar.htm.htm' is not found.

kattsoff
kattsoff

jprevot said:

I have problem with registerContextSidenavPartial

this partial is in partials folder The partial '@/plugins/minerd/dgetp/partials/__sidebar.htm.htm' is not found.

You have two typo:

  • __sidebar with two underscores
  • __sidebar.htm.htm htm twice
mctorre
mctorre

It works perfect! Only thing is that you need to add use BackendMenu; in the Plugin.php file and the name of the files and how they are been called in the partials are not the same, so updating: public function register() { BackendMenu::registerContextSidenavPartial('Pronet.RealEstate', 'realestate', '@/plugins/pronet/realestate/partials/_sidebar.htm'); }

to

public function register() { BackendMenu::registerContextSidenavPartial('Pronet.RealEstate', 'realestate', '@/plugins/pronet/realestate/partials/_sidenav.htm'); }

and in the _sidenav.html:

$this->makePartial('@/plugins/pronet/realestate/partials/_sidebar_menu_toolbar.htm')

to

$this->makePartial('@/plugins/pronet/realestate/partials/_sidenav_menu_toolbar.htm')

and

$this->makePartial('@/plugins/alto/contacts/partials/_sidebar_menu.htm')

to

$this->makePartial('@/plugins/alto/contacts/partials/_sidenav_menu.htm')

tdeveloper0518483
tdeveloper0518483

I have done all the things but after that when I reload the page the sidebar menu disappears. I do not understand what I have done wrong. I have used builder plugin for creating plugins.Please help.

Last updated

ivix.ru
ivix.ru

tdeveloper0518483 said:

I have done all the things but after that when I reload the page the sidebar menu disappears. I do not understand what I have done wrong. I have used builder plugin for creating plugins.Please help.

That's because the original post data is kind of outdated now since October CMS Stable released. Things have been changed a little bit (especially markup & css).

Last updated

jprevot
ThomasL
ThomasL

So no usage in combination with the builder plugin? Should be part of the builder backend menu functions, isn`t it?

1-15 of 15

You cannot edit posts or make replies: the forum has moved to talk.octobercms.com.