- Documentation >
- Administration >
- Back office >
- Back office menus >
- Add menu item
To add a new menu entry in the back office, you need to use an event subscriber and subscribe to one of the events dispatched when building menus.
The following example shows how to add a "Content list" item to the main top menu and list all content items there, with a shortcut button to edit them.
Create event subscriber
First, create an event subscriber in src/EventSubscriber/MyMenuSubscriber.php
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 | <?php declare(strict_types=1);
namespace App\EventSubscriber;
use Ibexa\AdminUi\Menu\Event\ConfigureMenuEvent;
use Ibexa\AdminUi\Menu\MainMenuBuilder;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class MyMenuSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
ConfigureMenuEvent::MAIN_MENU => ['onMainMenuConfigure', 0],
];
}
public function onMainMenuConfigure(ConfigureMenuEvent $event): void
{
$menu = $event->getMenu();
$customMenuItem = $menu[MainMenuBuilder::ITEM_CONTENT]->addChild(
'main__content__custom_menu',
[
'extras' => [
'orderNumber' => 100,
],
],
);
$customMenuItem->addChild(
'all_content_list',
[
'label' => 'Content List',
'route' => 'all_content_list.list',
'attributes' => [
'class' => 'custom-menu-item',
],
'linkAttributes' => [
'class' => 'custom-menu-item-link',
],
]
);
}
}
|
This subscriber subscribes to the ConfigureMenuEvent::MAIN_MENU
event (see line 14).
It creates a subitem with the identifier main__content__custom_menu
(lines 22-23).
Then, under this subitem, it creates an all_content_list
menu item (lines 31-32).
Add route
Next, configure the route that the menu item leads to:
| all_content_list.list:
path: /all_content_list/{page}
defaults:
page: 1
_controller: App\Controller\AllContentListController::listAction
|
Create controller
The route indicates a controller that fetches all visible content items and renders the view.
Create the following controller file in src/Controller/AllContentListController.php
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 | <?php declare(strict_types=1);
namespace App\Controller;
use Ibexa\AdminUi\Form\Factory\FormFactory;
use Ibexa\Contracts\AdminUi\Controller\Controller;
use Ibexa\Contracts\Core\Repository\SearchService;
use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery;
use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion;
use Ibexa\Core\Pagination\Pagerfanta\LocationSearchAdapter;
use Pagerfanta\Pagerfanta;
use Symfony\Component\HttpFoundation\Response;
class AllContentListController extends Controller
{
private SearchService $searchService;
private FormFactory $formFactory;
public function __construct(SearchService $searchService, FormFactory $formFactory)
{
$this->searchService = $searchService;
$this->formFactory = $formFactory;
}
public function listAction(int $page = 1): Response
{
$query = new LocationQuery();
$query->query = new Criterion\Visibility(Criterion\Visibility::VISIBLE);
$paginator = new Pagerfanta(
new LocationSearchAdapter($query, $this->searchService)
);
$paginator->setMaxPerPage(8);
$paginator->setCurrentPage($page);
$editForm = $this->formFactory->contentEdit();
return $this->render('@ibexadesign/all_content_list.html.twig', [
'totalCount' => $paginator->getNbResults(),
'articles' => $paginator,
'form_edit' => $editForm->createView(),
]);
}
}
|
Add template
Finally, create the templates/themes/admin/list/all_content_list.html.twig
file indicated in line 37 in the controller:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77 | {% extends '@ibexadesign/ui/layout.html.twig' %}
{% block title %}{{ 'Content List'|trans }}{% endblock %}
{%- block breadcrumbs -%}
{% include '@ibexadesign/ui/breadcrumbs.html.twig' with { items: [
{ value: 'breadcrumb.admin'|trans(domain='messages')|desc('Admin') },
{ value: 'url.list'|trans|desc('Content List') }
]} %}
{%- endblock -%}
{%- block header -%}
{% include '@ibexadesign/ui/page_title.html.twig' with {
title: 'url.list'|trans|desc('Content List'),
} %}
{%- endblock -%}
{%- block content -%}
<section class="container ibexa-container">
{% set body_rows = [] %}
{% for article in articles.currentPageResults %}
{% set col_edit %}
<button class="btn ibexa-btn ibexa-btn--ghost ibexa-btn--content-edit"
title="{{ 'dashboard.table.all.content.edit'|trans|desc('Edit Content') }}"
data-content-id="{{ article.contentInfo.id }}"
data-version-no="{{ article.contentInfo.currentVersionNo }}"
data-language-code="{{ article.contentInfo.mainLanguageCode }}">
<svg class="ibexa-icon ibexa-icon--small ibexa-icon--edit">
<use xlink:href="{{ ibexa_icon_path('edit') }}"></use>
</svg>
</button>
{% endset %}
{% set body_rows = body_rows|merge([{
cols: [
{ content: article.contentInfo.name },
{ content: article.contentInfo.contentType.name },
{ content: article.contentInfo.modificationDate|ibexa_full_datetime },
{ content: article.contentInfo.publishedDate|ibexa_full_datetime },
{ content: col_edit, raw: true },
],
}]) %}
{% endfor %}
{% include '@ibexadesign/ui/component/table/table.html.twig' with {
headline: 'Content List',
head_cols: [
{ content: 'Content name'|trans },
{ content: 'Content type'|trans },
{ content: 'Modified'|trans },
{ content: 'Published'|trans },
{ content: '' },
],
class: 'ibexa-table',
body_rows
} %}
{% if articles.haveToPaginate %}
{% include '@ibexadesign/ui/pagination.html.twig' with {
'pager': articles
} %}
{% endif %}
</section>
{{ form_start(form_edit, {
'action': path('ibexa.content.edit'),
'attr':
{ 'class': 'ibexa-edit-content-form'}
}) }}
{{ form_widget(form_edit.language, {'attr': {'hidden': 'hidden', 'class': 'language-input'}}) }}
{{ form_end(form_edit) }}
{% include '@ibexadesign/content/modal/version_conflict.html.twig' %}
{%- endblock -%}
{% block javascripts %}
{{ encore_entry_script_tags('ibexa-admin-ui-dashboard-js', null, 'ibexa') }}
{%- endblock -%}
|
This template uses the reusable table template to render a table that fits the style of the back office.
You can configure the columns of the table in the head_cols
variable and the regular table rows in body_rows
.
In this case, body_rows
contains information about the content item provided by the controller, and an edit button.