How hooks work
When Redmine encounters a hook call it:- Looks up every registered listener that implements a method with the hook’s name.
- Calls that method on each listener, passing a
contexthash with relevant objects. - Collects the return values and, in view hooks, concatenates them into the HTML output.
call_hook is available as a helper method that joins all listener responses into a single html_safe string:
call_hook returns an array of results:
Listener types
- ViewListener
- Listener
Inherit from
Redmine::Hook::ViewListener when your hook handler needs to render HTML. This base class includes ActionView helpers, URL helpers, and ApplicationHelper so you can build links, render partials, and use Redmine helpers.render_on is a convenience macro that generates a hook method that renders the given partial. The entire context hash is passed as local variables to the partial.You can also write the method by hand:Registering a listener
Listeners register themselves automatically when they are defined (via theinherited callback in Redmine::Hook::Listener). You just need to make sure the file is loaded. The standard place is inside the plugin’s init.rb:
plugins/my_plugin/lib/ — it will be autoloaded by Redmine’s plugin loader.
Context hash
Every hook method receives acontext hash. Redmine always populates the following keys:
| Key | Type | Description |
|---|---|---|
:project | Project or nil | Current project |
:request | ActionDispatch::Request | Current HTTP request |
:controller | ActionController::Base | Current controller instance |
:hook_caller | Object | The object that called the hook (view or controller) |
Calling hooks from your own plugin views
You can define and call your own hooks to let other plugins extend your plugin::view_my_plugin_things_show_bottom using a ViewListener.
Common view hooks
These hooks are called from Redmine’s built-in views. Hook names follow the patternview_<controller>_<action>_<location>.
Issue hooks
Issue hooks
| Hook | Location |
|---|---|
:view_issues_show_details_bottom | Below the issue attributes table on the issue detail page |
:view_issues_show_description_bottom | Below the issue description |
:view_issues_form_details_top | Top of the issue form details section |
:view_issues_form_details_bottom | Bottom of the issue form details section |
:view_issues_new_top | Top of the new issue form |
:view_issues_edit_top | Top of the edit issue form |
:view_issues_edit_notes_bottom | Below the notes field on the edit form |
:view_issues_index_bottom | Bottom of the issue list |
:view_issues_sidebar_issues_bottom | Bottom of the issues sidebar |
:view_issues_sidebar_planning_bottom | Bottom of the planning sidebar section |
:view_issues_sidebar_queries_bottom | Bottom of the queries sidebar section |
:view_issues_bulk_edit_details_bottom | Bottom of the bulk-edit form |
:view_issues_context_menu_start | Start of the issue context menu |
:view_issues_context_menu_end | End of the issue context menu |
:view_issues_history_journal_bottom | Below each journal entry |
:view_issues_history_changeset_bottom | Below each changeset entry |
:view_issues_history_time_entry_bottom | Below each time entry in history |
Project hooks
Project hooks
| Hook | Location |
|---|---|
:view_projects_form | Inside the project form |
:view_projects_show_left | Left column of the project overview |
:view_projects_show_right | Right column of the project overview |
:view_projects_show_sidebar_bottom | Bottom of the project sidebar |
:view_projects_sidebar_queries_bottom | Bottom of the project queries sidebar |
:view_projects_settings_members_table_header | Extra column header in the members table |
:view_projects_settings_members_table_row | Extra column cell in the members table |
Layout hooks
Layout hooks
| Hook | Location |
|---|---|
:view_layouts_base_html_head | Inside <head> — use to add stylesheets or meta tags |
:view_layouts_base_body_top | Immediately after <body> opens |
:view_layouts_base_content | Main content area |
:view_layouts_base_body_bottom | Just before </body> — use to add scripts |
User and account hooks
User and account hooks
| Hook | Location |
|---|---|
:view_account_login | On the login form |
:view_my_account | On the My Account page |
:view_my_account_contextual | Contextual area on My Account |
:view_my_account_preferences | Preferences section on My Account |
:view_my_page_splitcontent | Split content area on My Page |
:view_my_page_contextual | Contextual area on My Page |
:view_users_form | Inside the user administration form |
:view_users_form_preferences | User preferences section in the admin form |
Other view hooks
Other view hooks
| Hook | Location |
|---|---|
:view_settings_general_form | Inside the general settings form |
:view_custom_fields_form_upper_box | Top of the custom field form |
:view_timelog_edit_form_bottom | Bottom of the time log edit form |
:view_wiki_show_sidebar_bottom | Bottom of the wiki sidebar |
:view_search_index_options_content_bottom | Bottom of the search options |
:view_welcome_index_left | Left area of the welcome page |
:view_welcome_index_right | Right area of the welcome page |
:view_calendars_show_bottom | Bottom of the calendar view |
:view_repositories_show_contextual | Contextual area on the repository page |
Common controller hooks
Controller hooks let you run code at specific points during request processing.| Hook | When |
|---|---|
:controller_issues_new_before_save | Before a new issue is saved |
:controller_issues_new_after_save | After a new issue is saved |
:controller_issues_bulk_edit_before_save | Before each issue is saved during bulk edit |
:controller_account_success_authentication_after | After a user successfully authenticates |
:controller_timelog_edit_before_save | Before a time entry is saved |
:controller_wiki_edit_after_save | After a wiki page is saved |
:controller_messages_new_after_save | After a new forum message is saved |
:controller_messages_reply_after_save | After a forum reply is saved |
:controller_custom_fields_new_after_save | After a custom field is created |
:controller_custom_fields_edit_after_save | After a custom field is updated |
:controller_journals_edit_post | After a journal entry is edited |
:after_plugins_loaded | After all plugins have finished loading |
