Published on

Add Navigation Icons to TYPO3

Authors

Navigation icons can be a great addition to your TYPO3 website, providing a visual representation of different pages in the navigation menu. This guide shows two approaches to add a per-page navigation icon field to the TYPO3 backend and how to use it in your frontend templates.

Simplest Way

Step 1: Prepare the Database

Create or modify the <your-ext>/ext_tables.sql file and add a new field to the pages table:

CREATE TABLE pages
(
    nav_icon varchar(255) DEFAULT '' NOT NULL,
);

Step 2: Prepare the Language Label

In your extension's <your-ext>/Resources/Private/Language/Backend.xlf file, add a label for the new field:

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<xliff version="1.0">
    <file source-language="en" datatype="plaintext" original="messages" date="2023-08-01T09:11:39Z" product-name="theme">
        <header />
        <body>
            <trans-unit id="field.nav_icon">
                <source>Navigation Icon</source>
            </trans-unit>
        </body>
    </file>
</xliff>

Step 3: Add TCA Configuration

Add the TCA for the new nav_icon field in Configuration/TCA/Overrides/pages.php:

<?php

$GLOBALS['TCA']['pages']['columns'] = array_replace_recursive(
    $GLOBALS['TCA']['pages']['columns'],
    [
        'nav_icon' => [
            'label' => 'LLL:EXT:theme/Resources/Private/Language/Backend.xlf:field.nav_icon',
            'config' => [
                'type' => 'select',
                'renderType' => 'selectSingle',
                'fileFolderConfig' => [
                    'folder' => 'EXT:theme/Resources/Public/Icons/Navigation/',
                    'allowedExtensions' => 'svg',
                ],
                'fieldWizard' => [
                    'selectIcons' => [
                        'disabled' => false,
                    ],
                ],
            ],
            'l10n_mode' => 'exclude',
        ],
    ]
);

\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes('pages', 'nav_icon', '1,3,4', 'after:nav_title');

More Control over Values

The above method returns only the SVG name as the value. If you want more control over the values stored, you can use the itemsProcFunc option in TCA to dynamically generate the list of icons.

Step 1: Update TCA Configuration

Modify the TCA configuration for the nav_icon field:

<?php

$GLOBALS['TCA']['pages']['columns'] = array_replace_recursive(
    $GLOBALS['TCA']['pages']['columns'],
    [
        'nav_icon' => [
            'label' => 'LLL:EXT:theme/Resources/Private/Language/Backend.xlf:field.nav_icon',
            'config' => [
                'type' => 'select',
                'renderType' => 'selectSingle',
                'itemsProcFunc' => \YourVendor\Theme\Service\TcaIconService::class . '::__invoke',
                'fieldWizard' => [
                    'selectIcons' => [
                        'disabled' => false,
                    ],
                ],
            ],
            'l10n_mode' => 'exclude',
        ],
    ]
);

Step 2: Implement the Icon Service

Create Classes/Service/TcaIconService.php in your extension:

<?php

declare(strict_types=1);

namespace YourVendor\Theme\Service;

use Symfony\Component\Finder\Finder;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;

final class TcaIconService
{
    public function __invoke(&$params): void
    {
        $finder = new Finder();

        $themePrefix = 'EXT:theme/';
        $folderPath = 'Resources/Public/Icons/Navigation/';
        $iconFolder = $themePrefix . $folderPath;
        $finder->files()->in(ExtensionManagementUtility::extPath('theme') . $folderPath);

        foreach ($finder as $file) {
            $params['items'][] = [
                'label' => $file->getFilenameWithoutExtension(),
                'value' => $iconFolder . $file->getFilename(),
                'icon'  => $iconFolder . $file->getFilename(),
            ];
        }
    }
}

Accessing nav_icon in Frontend Template

Use the value in your Fluid or other frontend templates:

<img src="{data.nav_icon}" />

Or debug the value:

<f:debug>{page.data.nav_icon}</f:debug>

That’s it! You now have a flexible way to choose navigation icons per page in the TYPO3 backend and render them in your frontend.