The most advanced customization can be accomplished by writing a custom plugin. With a plugin you can customize literally anything in Redmine. Of course, to write a full-featured plugin you need to be familiar with Ruby, Rails, Redmine API, JavaScript, HTML, CSS, web development concept, and so on. But who said, that you need a full-featured plugin?
As you know, a plugin's files are kept in a separate directory named after the plugin and located in the plugins
subdirectory of the Redmine root. This way when Redmine gets upgraded, the plugin's files remain untouched. On the other side, many users put their customizations into Redmine core files, which get overwritten n upgrade. So why not put customizations into a plugin?
The Redmine plugin API is quite flexible and you allows to: overwrite any core view file without touching the original one; to add custom content to different views; load additional CSS style sheets, and so on. Therefore, a plugin can be used as a tool for customization. In fact, you do not need to write any complicated Ruby code to do this—just use small code snippets to activate different plugins capabilities. That's what we will learn in this topic.
Of course, to be able to customize Redmine's look and feel you need to be familiar, at least, with HTML. Familiarity with CSS is optional but will be very useful.
To be able to make use of the plugin capabilities we need to create a simple plugin first. Luckily, it's really simple.
Before proceeding, we need to choose a name for our plugin. Thus, for my website www.andriylesyuk.com, which runs Redmine too, I chose the name andriy_lesyuk
. So, for this demo plugin I will choose just packtpub
.
So now we will create a directory for our plugin in the plugins
subdirectory of the Redmine root directory, which is /opt/redmine
in my case. So the full path for the plugin will be /opt/redmine/plugins/packtpub
.
After this, in the newly created directory, we will create the init.rb
file (the entry point for the plugin) and put the following code in it:
require 'redmine' Rails.logger.info 'Starting Packt Publishing Plugin for Redmine' Redmine::Plugin.register :packtpub do name 'Packt Publishing customization' author 'Andriy Lesyuk' author_url 'http://www.andriylesyuk.com' description 'The demo of the customization using the plugin.' url 'http://redmine.packtpub.com' version '0.0.1' end
In place of :packtpub
write your plugin name (keep the colon at the beginning). What should be changed in the rest of the code, I believe, is quite clear.
When done, after restarting Redmine you should see your plugin in Administration | Plugins, as follows:
Of course, this plugin does nothing (besides putting itself into the plugin list), but that's all for now.
Redmine is using the Model-View-Controller (MVC) architecture, where "view" files store the layout information. Most of the content of these files is just HTML code (the rest is eRuby, JavaScript, and so on). All views are located under the app/views
path of Redmine. Any view can be overwritten just by copying the original view file into the appropriate path under the plugins app/views
. So, let's now see how this works by reviewing one of the most common customization tasks, adding a logo to the layout.
First we need to create a directory for images in our plugin. This must be the assets/images
directory. After creating it put the logo image into this directory.
When done, create the app/views
directory in the plugins root and copy the app/views/layouts/base.html.erb
file there from Redmine preserving the directory structure (thus, the full target location in my case is plugins/packtpub/app/views/layouts/base.html.erb
).
Now open the base.html.erb
file (the copy) and find the following line of code in there:
<h1><%= page_header_title %></h1>
This code renders the title of the page. Before this line, add the following line of code:
<%= image_tag('packtpub.png', :plugin => 'packtpub', :style => 'float: left; padding-right: 1em;') %>
Here packtpub.png
is the name of the image file and 'packtpub'
is the name of the plugin.
Alternatively, the logo can be added using CSS (for example, by creating a custom theme). To do this you can specify the background image for #header. However, the #header area should not already have the background image, which can be set, for example, by theme. The advantage of this method is that the customization, most likely, won't need to be updated after upgrades.
After saving changes, restarting Redmine, and reloading any Redmine page you will get something like the following screenshot:
Track changes you make to copies of Redmine core files, as you may need to replicate them, if Redmine core files get modified with an upgrade.
The Plugin Views Revisions plugin of Vitaly Klimov allows you to bind the modified view file with certain Redmine version, thus, making it active only until an upgrade (this way preventing Redmine from crashes). More information can be found at http://www.redmine.org/plugins/redmine_plugin_views_revisions.
Redmine comes with "hooks" support. Hooks can be used to inject custom content into some pre-defined places in certain Redmine views. If possible, it is better to use hooks to add the content to the view instead of copying and modifying the view file, as for hooks you need to provide only the custom content and they are not affected by upgrades. Let's see how this works in another real-life example—let's add login instructions to the login page.
To be able to use hooks we need to add the hook listener to the plugin. To do this create the lib
directory in the plugins root and place the packtpub_hook.rb
file in it (you can use anything in place of packtpub
in the filename). Now add the following code to the newly created file:
class PacktPubHook < Redmine::Hook::ViewListener render_on :view_account_login_top, :partial => 'packtpub/login' end
Here the name of the class, which is PacktPubHook
, reflects the filename. :view_account_login_top
is the hook, which gets called on the login form, and the :partial
option contains the path to the custom content view file.
Now we need to create the file, which will contain the custom content. So first we will create the packtpub
directory in app/views
and then place the _login.html.erb
file in it (note _
at the beginning of the filename—it is required). Now put your custom content, which can be just HTML, into the newly created file.
And finally we need to register our hook listener. To do this just add the following line of code to the init.rb
file (under require 'redmine'
):
require_dependency 'packtpub_hook'
Here packtpub_hook
is the filename of the hook listener without extension.
Now when you restart Redmine and go to the login page, you should see something like the following screenshot:
The warning above the form is added using the hook.
The following table lists some other hooks, which can be interesting fo you:
Location | |
---|---|
Bottom of the left column (the start page) | |
Bottom of the right column (the start page) | |
Below the form on the login page | |
Below the content on each page | |
Bottom of the left column (the project overview page) | |
Bottom of the right column (the project overview page) | |
Above the form on the new issue page |
A full list of hooks can be found at http://www.redmine.org/projects/redmine/wiki/Hooks_List#View-hooks.