When trying to guide someone into adding a feature in Nikola, it hit me that while the way it's structured makes sense to me it is far from obvious.
So, this is a short document explaining what each piece of Nikola does and how it all fits together.
Most of Nikola is implemented as plugins using Yapsy. You can ignore that they are plugins and just think of them as regular python modules and packages with a funny little .plugin file next to them.
So, 90% of the time, what you want to do is either write a new plugin or extend an existing one.
There are several kinds of plugins, all implementing interfaces defined in nikola/plugin_categories.py and documented in Extending Nikola
If your plugin has a dependency, please make sure it doesn't make Nikola throw an exception when the dependency is missing. Try to fail gracefully with an informative message.
Nikola's goal is similar, deep at heart, to a Makefile. Take sources, compile them into something, in this case a website. Instead of a Makefile, Nikola uses doit
Doit has the concept of "tasks". The 1 minute summary of tasks is that they have:
So, what Nikola does, when you use the build command, is to read the configuration conf.py from the current folder, instantiate the Nikola class, and have it generate a whole list of tasks for doit to process. Then doit will decide which tasks need doing, and do them, in the right order.
The place where the tasks are generated is in Nikola.gen_tasks, which collects tasks from all the plugins inheriting BaseTask, massages them a bit, then passes them to doit.
So, if you want things to happen on build you want to create a Task plugin, or extend one of the existing ones.
Nikola has a concept of posts and stories. Both are more or less the same thing, except posts are added into RSS feeds and stories are not. All of them are in a list called "the timeline" formed by objects of class Post.
When you are creating a task that needs the list of posts and/or stories (for example, the RSS creation plugin) on task execution time, your plugin should call self.site.scan_posts() in gen_tasks to ensure the timeline is created and available in self.site.timeline. You should not modify the timeline, because it will cause consistency issues.
Your plugin can use the timeline to generate "stuff" (technical term). For example, Nikola comes with plugins that use the timeline to create a website (surprised?).
The workflow included with nikola is as follows (incomplete!):
You can add whatever you want to that list: just create a plugin for it.
You can also expand Nikola's capabilities at several points:
And of course, you can also replace or extend each of the existing plugins.