How to add new menu between HOME and CREATE EVENT and link to External site

Hi Gurus,

I want to add new menu item in indico
How to add new menu between HOME and CREATE EVENT and link to External site.

thanks in advance.

You need to write a plugin for this which uses the signal to define a new TopMenuItem with a weight between 90 (“Create Event”) and 100 (“Home”).

A very basic example for such a plugin would be this:

from indico.core import signals
from indico.core.plugins import IndicoPlugin
from import TopMenuItem

class MyCustomTopMenuLinkPlugin(IndicoPlugin):
    """My Custom Top Menu Link

    Add a new top menu link.

    def init(self):
        super(MyCustomTopMenuLinkPlugin, self).init()
        self.connect(, self._extend_top_menu, sender='top-menu')

    def _extend_top_menu(self, sender, **kwargs):
        return TopMenuItem('my-menu-item', 'Title of the item', 'https://your-url', weight=95)

Save this file in a new folder as, and create a containing this:

from setuptools import setup

and a setup.cfg containing this:

name = indico-plugin-my-custom-top-menu-link
version = 2.3
description = Indico plugin that adds a custom top menu link
license = MIT

py_modules = indico_my_custom_top_menu_link
zip_safe = false
install_requires =

indico.plugins =
    my_custom_top_menu_link = indico_my_custom_top_menu_link:MyCustomTopMenuLinkPlugin

Then, from the src folder of an indico development environment, run ./bin/maintenance/ plugin ../path/to/your/custom/plugin/folder

This will build a .whl file in dist/, which you can copy to your indico server, install it using pip install whatever.whl and then you just need to add my_custom_top_menu_link to the PLUGINS list in indico.conf.

Note: I have not tested any of the code above. There may be typos/bugs. Ideally you try it out on a local dev instance first!

PS: It would be nice if someone implemented a more fancy plugin where those custom menu items can be configured in the plugin settings, but if all you need is a custom menu item then this is the way to go. You’ll need to add a as well though to expose the plugin

1 Like

Thank you so much for the guidance. Tested above code on development server got following error messages:

  1. env not activated.
[indico@localhost ~]$ cd  dev/indico/
[indico@localhost indico]$ cd src/
[indico@localhost src]$ ./bin/maintenance/ plugin /opt/indico/dev/indico/plugins/external_link
Traceback (most recent call last):
  File "./bin/maintenance/", line 19, in <module>
    import click
ImportError: No module named click
  1. env activated
(env) [indico@localhost src]$ ./bin/maintenance/ plugin /opt/indico/dev/indico/plugins/external_link
Traceback (most recent call last):
  File "./bin/maintenance/", line 327, in <module>
  File "/opt/indico/dev/indico/env/lib/python2.7/site-packages/click/", line 829, in __call__
    return self.main(*args, **kwargs)
  File "/opt/indico/dev/indico/env/lib/python2.7/site-packages/click/", line 782, in main
    rv = self.invoke(ctx)
  File "/opt/indico/dev/indico/env/lib/python2.7/site-packages/click/", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/opt/indico/dev/indico/env/lib/python2.7/site-packages/click/", line 1066, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/opt/indico/dev/indico/env/lib/python2.7/site-packages/click/", line 610, in invoke
    return callback(*args, **kwargs)
  File "/opt/indico/dev/indico/env/lib/python2.7/site-packages/click/", line 33, in new_func
    return f(get_current_context().obj, *args, **kwargs)
  File "./bin/maintenance/", line 289, in build_plugin
    clean, output = git_is_clean_plugin()
  File "./bin/maintenance/", line 167, in git_is_clean_plugin
    rv = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
  File "/usr/lib64/python2.7/", line 575, in check_output
    raise CalledProcessError(retcode, cmd, output=output)
subprocess.CalledProcessError: Command '['git', 'diff', '--stat', '--color=always']' returned non-zero exit status 129

What happens if you run git diff --stat --color=always manually in the plugin’s folder? Any error? Maybe it’s not a git repo?

PS: Please paste shell output in triple-backtick fences and not using the quote option. Especially tracebacks are much less readable that way…

(env) [indico@localhost plugins]$ git diff --stat --color=always
warning: Not a git repository. Use --no-index to compare two paths outside a working tree
usage: git diff --no-index [<options>] <path> <path>

Diff output format options
    -p, --patch           generate patch
    -s, --no-patch        suppress diff output
    -u                    generate patch
    -U, --unified[=<n>]   generate diffs with <n> lines context
    -W, --function-context
                          generate diffs with <n> lines context
    --raw                 generate the diff in raw format
    --patch-with-raw      synonym for '-p --raw'
    --patch-with-stat     synonym for '-p --stat'
    --numstat             machine friendly --stat
    --shortstat           output only the last line of --stat
    -X, --dirstat[=<param1,param2>...]
                          output the distribution of relative amount of changes for each sub-directory

git init to create one. You may also want to consider putting your plugig on github (can also be a private repo) so you have a backup of it and keep track of your changes.

(env) [indico@localhost plugins] git init hint: Using 'master' as the name for the initial branch. This default branch name hint: is subject to change. To configure the initial branch name to use in all hint: of your new repositories, which will suppress this warning, call: hint: hint: git config --global init.defaultBranch <name> hint: hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and hint: 'development'. The just-created branch can be renamed via this command: hint: hint: git branch -m <name> Initialized empty Git repository in /opt/indico/dev/indico/plugins/.git/ (env) [indico@localhost plugins] git diff --stat --color=always

I’d rather do it inside the external_link folder… especially if plugins contains anything else.

Anyway having a repo is all you need. The build script has a switch to skip the check if everything is committed so use that (it’s listed in --help) for now; if you want to actually keep the plugin code in a repo, check some beginner documentation on git online (explaining git would be way out of scope here)

Thanks for the advises but I am confused how will it solve the error messages shown while trying to install the script unless I make changes to the python code.

PS: uploaded the code on Github.

the build script checks if there are no uncommitted changes, and that check fails if there is no git repo (we should fix that of course ;))

please help me how to fix it. I am complete new comer here thanks.

I would expect this to work now that the git command won’t fail…

change the folder name to match with github name? like indico_external_link

(env) [indico@localhost src]$ ./bin/maintenance/ plugin /opt/indico/dev/indico/plugins/external_link
plugin has no assets
plugin has no translations
cleaning build dirs
building wheel
Error: build failed
running bdist_wheel
running build
running build_py
creating build
error: could not create ‘build’: Permission denied

(env) [indico@localhost src]$

any chance one of the folders are owned by root instead of your normal user?

1 Like

yes it was owned by root changing it to indico:apache made it. No errors now.

(env) [indico@localhost src] ./bin/maintenance/ plugin /opt/indico/dev/indico/plugins/external_link plugin has no assets plugin has no translations cleaning build dirs building wheel cleaning build dirs (env) [indico@localhost src]

What is the right way to add it in indico.conf? /opt/indico/etc/indico.conf

I did following and restarted the services systemctl restart uwsgi.service httpd.service indico-celery.service

STATIC_FILE_METHOD = ‘xsendfile’
PLUGINS my_custom_top_menu_link

but got

Internal Server Error

PLUGINS = {'my_custom_top_menu_link'}
1 Like

Error persists.
my conf file:

General settings

SQLALCHEMY_DATABASE_URI = ‘postgresql:///indico’
SECRET_KEY = ‘a\x84\xa1\x87K\nG\x18jT\xcb\xb2\x8a\xab\xa8 \xfd\x85\xec\xe93\x95\xc7\xd6\xff\x0er\x0c"\xa7\x10\x1d’
CELERY_BROKER = ‘redis://’
REDIS_CACHE_URL = ‘redis://’
DEFAULT_TIMEZONE = ‘America/New_York’
CACHE_DIR = ‘/opt/indico/cache’
TEMP_DIR = ‘/opt/indico/tmp’
LOG_DIR = ‘/opt/indico/log’
STORAGE_BACKENDS = {‘default’: ‘fs:/opt/indico/archive’}

Email settings

SMTP_SERVER = (‘’, 25)

STATIC_FILE_METHOD = ‘xsendfile’
PLUGINS = {‘my_custom_top_menu_link’}

got following error message:

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.

Try running indico shell; this should show you the actual error you got. Also, indico setup list-plugins will show you the names of your installed plugins.

You did pip install it? Just to clarify:

  • if you want to test the plugin locally, you do pip install -e ../path/to/plugins/external_link
  • if you want to install the wheel you built on your production indico instance, then you copy the .whl file and use pip install NAME.whl

which of these is triple back ticks?