Plugins are a great way to foster innovation in software projects, because they
allow independent developers to solve several problems without the need to
understand/interact with the entire code base; by writing a plugin that
implements a documented interface developers are able to add features without
having to worry with the existing infrastructure.
We are introducing plugins to make it easier for developers to create
innovative features for Noosfero.
It is important that such plugin architecture is accompanied by clear and
Intended policy for plugins
Although plugins are supposed to be independent from the main product, we
suggest to keep plugins code together with Noosfero main code instead of
distributing them independently to help everyone involved in having a proper
Quality Assurance environment.
Plugins must have automated tests, and when there's a need to make changes in
Noosfero's core code, we should be able to run tests for all the plugins so
that we know whether those changes affected any of the plugins. If that's the
case, the developer doing the changes can change the plugins accordingly, or at
least contact the plugin authors/maintainers asking for help. If plugins are
spread over the internet and not tested together with Noosfero, then we run the
risk of having Noosfero version/plugin version combinations that don't work and
thus cause frustrations on users.
Features that may be added via plugins
A Noosfero plugins must be able to:
- add new types of blocks
- example: "this plugin adds a StatusNet block that can display your microblog posts"
- perform actions whenever a content is created/updated/deleted/viewed
- example: "this plugin can post an update to your microblog (identi.ca/StatusNet/Twitter/etc) whenever you create a new blog post (or content in general)"
- perform actions whenever a profile is created/updated/deleted/viewed
- add elements to the visualization of a content
- example: "this plugin adds a 'Share in Service X' button to all your posts."
- provide new items for the control panel of profiles, as well as the implementation of those items (configuration screens plus a configuration saving backend).
- example: each community may be able to register related source code repositories to be monitored according to a defined set of software metrics.
- provide new visualizations for a profile.
- example: if communities can register source code repositories to be monitored through its control panel, a possible visualization of the profile could be statistics about those repositories.
- provide new attributes for content items
- provide new attributes for profiles
- provide new ways of user authentication
- example: a corporate social networking website may require that users must login with their corporate LDAP credentials
- provide new REST API handlers.
- provide new markup languages besides Textile (e.g. Markdown, Foswiki's wiki notation etc) -- this would require refactoring how the Textile article currently works.
- provide new ways of displaying the environment's home page (currently you have either static text or a "news site")
- provide new ways of displaying a profile's homepage (currently you can only put a user-created content there; even if it's a blog it's somehow limiting)
Questions and Solutions
- Possible Solution: the plugin may have a sub-dir called
public and that will be sym-linked inside the noosfero public dir:
load_plugins method may test and create this sym-links on the noosfero start.
- How a plugin can extend the database? If a plugin can "provide new attributes for profiles" that will be good to search by this, but ... how?
- A plugin can add extra content to pages, like a button "Share in Service X" to all the posts, but how the plugin will do this?
- Possible Solution: The noosfero templates must mark places where a plugin may add content with a method called with the place id.
Example to add the "Share in Service X" button on all blog post footers:
<%= plugin_extra_content :blog_post_head %>
<h2><%= @page.title %></h2>
<%= @page.tags %>
<%= plugin_extra_content :blog_post_poshead %>
<%= @page.content %>
<%= plugin_extra_content :blog_post_footer %>
</div><!-- end class="blog-post" --> Then, the plugin may register a lambda of html generetor to run on some place with the view context:
a piece of
register_content_render :blog_post_footer do |this_plugin, post|
link_to _("Share in Service X"), "http://serviceX.org/?src="+post.url+"&key="+this_plugin.key, :class=>"bt-serviceX";
end About the proposed methods:
register_content_render(<place_id>, <lambda-html-generator | html-in-a-string>)
That is a supperClass Plugin method to allow the plugins to say where extra content must be added, and make it adaptable to the context.
That is a view helper method to put the registered plugins exta content in place. This method will ever give the plugin reference as the first argument and other local context objects on the sequence.
- How to authomatic collect the important local context objects in the
- Possible Solution: ???
- Comment: the second argument on the plugin lambda may be a hash with the context objects...
The Plugins Architecture topic
describes the base architecture implemented and will help how to make your own plugin