Version 6 (modified by 19 years ago) ( diff ) | ,
---|
Writing Plugins for Trac
Starting with version 0.9, you can develop plugins for Trac that extend the builtin functionality. The plugin functionality is based on the component architecture, so please read that document before continuing here.
Extension points
Trac offers an increasing number of extension points that allow you to plugin custom extensions for various functions. You can view a list of provided extension points on the page About Trac/Plugins (not available here yet).
Currently we have:
trac.core.IEnvironmentSetupParticipant
Allows plugins to participate in the creation and upgrade of the environment. Can be used to setup additional database tables or directories needed for the plugin to operatetrac.web.main.IRequestHandler
Allows plugins to add handlers for HTTP requests.trac.web.chrome.INavigationContributor
Allows plugins to extend the navigation menus of the web interface.trac.web.chrome.ITemplateProvider
Extension point interface for components that provide their own ClearSilver templates and accompanying static resources.trac.perm.IPermissionRequestor
Plugins can use this extension point to define additional "actions" for the permission system.trac.Timeline.ITimelineEventProvider
Allows plugins to contribute events to the timeline.trac.mimeview.api.IHTMLPreviewRenderer
Allows plugins to provide support for rendering specific content of a specific type as HTML (used for TracSyntaxColoring and image preview)trac.wiki.api.IWikiChangeListener
Allows plugins to observe creation, modification and deletion of wiki pages.trac.wiki.api.IWikiMacroProvider
Allows plugins to contribute WikiMacros to Trac.trac.wiki.api.IWikiSyntaxProvider
Plugins can extend this extension point to add custom syntax rules to the wiki formatting system. In particular, this allows registration of additional TracLinks types.
Note that plugins can themselves add new extension points, so the list above is incomplete by nature.
Adding custom plugins
To extend Trac with a custom plugin, you need to provide a component. For example, to add a new web module to Trac (i.e. a component that handles HTTP requests and extends the navigation bar), you'd start with something like the following code:
from trac.core import * from trac.web.chrome import INavigationContributor from trac.web.main import IRequestHandler class HelloWorldPlugin(Component): implements(INavigationContributor, IRequestHandler) # INavigationContributor methods def get_active_navigation_item(self, req): return 'helloworld' def get_navigation_items(self, req): yield 'mainnav', 'helloworld', '<a href="%s">Hello World</a>' \ % self.env.href.helloworld() # IRequestHandler methods def match_request(self, req): return req.path_info == '/helloworld' def process_request(self, req): req.send_response(200) req.send_header('Content-Type', 'text/plain') req.end_headers() req.write('Hello world!')
Look at the API documentation for the extension point interfaces to see what you're expected to return.
Component member variables
Every component that gets instantiated through the Trac environment gets three extra member variables for convenience:
env
: The environment, an instance of thetrac.env.Environment
class (see trac.env).config
: The configuration, an instance of thetrac.config.Configuration
class (see trac.config).log
: The configured logger, see the Python logging API for more information.
Deploying a custom plugin
To register a custom plugin with a Trac environment, you edit the trac.ini file to add a new configuration section for your plugin. Let's assume the above plugin is in a Python module with the name example.helloworld
[helloworld] module = example.helloworld
Your plugin should now get loaded and registered when Trac is run (when running under mod_python or tracd, you'll need to restart the server). This assumes that your module is on the Python path. If it is not, you can simply tell Trac where to look for it by using the path
option:
[helloworld] module = example.helloworld path = /home/cmlenz/src/trac-plugins
The name of the configuration section is not significant: Trac simply goes through all the sections and looks for an option called module
. But if your plugin also uses its own configuration options, you should of course document the name of the section where these options are expected to be found, and the admin will probably choose to put the module
and path
options in the same section:
[helloworld] module = example.helloworld path = /home/cmlenz/src/trac-plugins message = Hello world!
You can use this configuration option from the plugin as follows:
... class HelloWorldPlugin(Component): ... def process_request(self, req): req.send_response(200) req.send_header('Content-Type', 'text/plain') req.end_headers() req.write(self.config.get('helloworld', 'message')
Disabling built-in components
Sometimes you might want to write a plugin that completely replaces a built-in component, for example to develop an advanced variant of an existing module. Trac uses a list of default component to load, as specified in the default_components
list in trac.db_default. These built-in components are always loaded, and might therefore conflict with your replacement plugin.
You can however disable built-in components using a special trac.ini section called [disabled_components]
. This section contains the qualified name of the components to disable, along with a boolean value (yes/true/1 or no/false/0), where a positive value means the component is disabled, and a negative value means its enabled.
For example, to disable the built-in Wiki macro RecentChanges
, you'd include the following in trac.ini
:
[disabled_components] trac.wiki.macros.RecentChanges = yes
This mechanism uses string prefix matching, so you could even disable the complete Wiki module (although wiki formatting will still work in the remaining modules, of course):
[disabled_components] trac.wiki = yes
See also: TracDev, TracDev/ComponentArchitecture