The most advanced customization can be accomplished by writing a custom plugin. With a plugin, you can customize anything in Redmine. Of course, to write a full-featured plugin, you need to be familiar with Ruby, Rails, the Redmine API, JavaScript, HTML, CSS, the concept of web development, and so on. But who said that you need a full-featured plugin?
As you already know, the files of a plugin are kept in a separate directory that is named after the plugin and located under the plugins
directory of Redmine. So, when Redmine is upgraded, such files remain untouched. On the other side, many users put their customizations into the Redmine core files that are overridden on upgrades. So why not use a special plugin for this instead?
The Redmine plugin API is quite flexible. In particular, it allows you to:
This makes it possible to use a plugin as a tool for customization. And for this, you do not need to write any complicated Ruby code—you can simply use small code snippets to activate different capabilities of the plugin. That's what you'll learn in this section.
Of course, to be able to customize the look and feel, you need to be familiar with HTML at least. Familiarity with CSS is optional, but it will be very useful.
Before creating a plugin, you need to choose a name for it. I'll use the name mastering_redmine
.
Next, you need to create a subdirectory for the plugin in the plugins
directory of Redmine. The created subdirectory must have the name of the plugin. In other words, the full path for my plugin will be /opt/redmine/redmine-3.2.0/plugins/mastering_redmine
.
After this, in the newly created directory, you need to create the init.rb
file (the entry point for the plugin) and put the following code into it:
require 'redmine' Rails.logger.info 'Starting Mastering Redmine Plugin for Redmine' Redmine::Plugin.register :mastering_redmine do name 'Mastering Redmine customization' author 'Andriy Lesyuk' author_url 'http://www.andriylesyuk.com' description 'Website customization using the plugin.' url 'http://mastering-redmine.com' version '2.0.0' end
Of course, you need to use your plugin name instead of :mastering_redmine
(but keep the colon at the beginning). What should be changed in the rest of the code, I believe, is quite clear.
When you're done, restart Redmine. Now you should see your plugin listed on the Plugins page of the Administration menu, as shown in the following screenshot:
At the moment, this plugin does nothing (besides putting itself into the plugin list), but that's only for now.
Redmine uses the Model-View-Controller (MVC) architecture, in which view files store the interface information. Most of the content of these files is just HTML code (the rest of the content is eRuby, JavaScript, and so on). All such files are located under the app/views
directory of Redmine. Moreover, any such file can be overridden just by copying it to the corresponding path under the plugin's app/views
directory (in this case, the original file remains unchanged). So, let's see how this works by reviewing one of the most common customization tasks—adding a logo to the Redmine interface.
First, you need to create a directory for images in your plugin. Its path has to be assets/images
. After you have done this, put the logo image into this directory.
Next, create the app/views/layouts
directory in the plugin and copy the app/views/layouts/base.html.erb
file from Redmine there (thus, the full target path in my case is plugins/mastering_redmine/app/views/layouts/base.html.erb
).
Now, open your copy of the base.html.erb
file and find this line of code (it's line 44 currently):
<h1><%= page_header_title %></h1>
This code renders the title of the page. Now, add the following line of code before that line:
<%= image_tag('mastering-redmine.png', :plugin => :mastering_redmine, :style => 'float: left; padding-right: 1em;') %>
Here, mastering-redmine.png
is the name of the logo image and :mastering_redmine
(the colon is important) is the name of the plugin.
Alternatively, the logo can be added using CSS (for example, by creating a custom theme). Thus, it can be specified as a background image for the #header
block. However, if the #header
area already has a background image (such an image can be set, for example, by a theme), the logo will override it. Anyway, the advantage of this method is that this customization most likely won't need to be updated after an upgrade of Redmine.
After saving the changes, you need to restart Redmine to apply them. Now, if you reload any Redmine page, you should see something like this:
Redmine comes with support for hooks. Hooks are callbacks that can be used to inject custom content into some predefined places of certain Redmine views. If possible, it is better to use a hook to add a content to the view instead of making a copy of the view file. This is because, for hooks, you need to provide only the content itself and they are not affected by upgrades. So, let's check out how this works through another real-life example—let's add a message to the login page (for example, it can contain login instructions).
To be able to use hooks, you need to add a hook listener to the plugin. To do this, create the lib
directory in the plugin and put the mastering_redmine_hook.rb
file into it (actually, you can use any filename). Now, add the following code into the newly created file:
class MasteringRedmineHook < Redmine::Hook::ViewListener render_on :view_account_login_top, :partial => 'mastering_redmine/login' end
Here, the name of the class, that is, MasteringRedmineHook
, reflects the filename (your class name should reflect your filename too), :view_account_login_top
is the name of the hook that is called on the login form, and the :partial
option is set to the path to the view file that contains the custom content.
Now, you need to create the view file with the custom content that has to be added to the login form. First, you need to create the mastering_redmine
directory in app/views
, and then create the _login.html.erb
file in it (note the _
character at the beginning of the filename—it is required). Here, the name of the directory, mastering_redmine
, and the name of file, _login.html.erb
, are what forms the value of the :partial
option. Now put your custom content, which can be just HTML, into this newly created file.
The Hooks Manager plugin
This plugin provides a nice interface for specifying custom content for many Redmine hooks (no need to write a plugin). Check it out at http://projects.andriylesyuk.com/project/redmine/hooks-manager.
Finally, you need to register the hook listener. To do this, just add the following line of code into the init.rb
file (below require 'redmine'
):
require_dependency 'mastering_redmine_hook'
Here, mastering_redmine_hook
is the filename of the hook listener without extension.
Now, if you restart Redmine and go to the login page, you should see something like this:
Let's quickly check out what other hooks are provided by Redmine. The following table lists some of them:
Hook |
Location |
---|---|
|
Bottom of the left column, on the welcome page |
|
Bottom of the right column, on the welcome page |
|
Below the login form |
|
Below the content, on each page |
|
Bottom of the left column, on the project overview page |
|
Bottom of the right column, on the project overview page |
|
Above the form, on the new issue page |
A complete list of hooks that are provided by Redmine can be found at http://www.redmine.org/projects/redmine/wiki/Hooks_List#View-hooks.