summaryrefslogtreecommitdiff
path: root/docs/plugins.rst
blob: 29d67e24e5eca14ce0f7639cbe6e07b0f0093f1f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
.. _plugins:

Plugins
#######

Beginning with version 3.0, Pelican supports plugins. Plugins are a way to add
features to Pelican without having to directly modify the Pelican core.

How to use plugins
==================

To load plugins, you have to specify them in your settings file. There are two
ways to do so. The first method is to specify strings with the path to the
callables::

    PLUGINS = ['package.myplugin',]

Alternatively, another method is to import them and add them to the list::

    from package import myplugin
    PLUGINS = [myplugin,]

If your plugins are not in an importable path, you can specify a ``PLUGIN_PATH``
in the settings. ``PLUGIN_PATH`` can be an absolute path or a path relative to
the settings file::

    PLUGIN_PATH = "plugins"
    PLUGINS = ["list", "of", "plugins"]

Where to find plugins
=====================

We maintain a separate repository of plugins for people to share and use.
Please visit the `pelican-plugins`_ repository for a list of available plugins.

.. _pelican-plugins: https://github.com/getpelican/pelican-plugins

Please note that while we do our best to review and maintain these plugins,
they are submitted by the Pelican community and thus may have varying levels of
support and interoperability.

How to create plugins
=====================

Plugins are based on the concept of signals. Pelican sends signals, and plugins
subscribe to those signals. The list of signals are defined in a subsequent
section.

The only rule to follow for plugins is to define a ``register`` callable, in
which you map the signals to your plugin logic. Let's take a simple example::

    from pelican import signals

    def test(sender):
        print "%s initialized !!" % sender

    def register():
        signals.initialized.connect(test)

List of signals
===============

Here is the list of currently implemented signals:

=============================   ============================   ===========================================================================
Signal                          Arguments                       Description
=============================   ============================   ===========================================================================
initialized                     pelican object
finalized                       pelican object                  invoked after all the generators are executed and just before pelican exits
                                                                usefull for custom post processing actions, such as:
                                                                - minifying js/css assets.
                                                                - notify/ping search engines with an updated sitemap.
generator_init                  generator                       invoked in the Generator.__init__
readers_init                    readers                         invoked in the Readers.__init__
article_generator_context        article_generator, metadata
article_generator_preread        article_generator               invoked before a article is read in ArticlesGenerator.generate_context;
                                                                use if code needs to do something before every article is parsed
article_generator_init          article_generator               invoked in the ArticlesGenerator.__init__
article_generator_finalized     article_generator               invoked at the end of ArticlesGenerator.generate_context
get_generators                  generators                      invoked in Pelican.get_generator_classes,
                                                                can return a Generator, or several
                                                                generator in a tuple or in a list.
page_generate_context           page_generator, metadata
page_generator_init             page_generator                  invoked in the PagesGenerator.__init__
page_generator_finalized        page_generator                  invoked at the end of PagesGenerator.generate_context
content_object_init             content_object                  invoked at the end of Content.__init__ (see note below)
content_written                 path, context                   invoked each time a content file is written.
=============================   ============================   ===========================================================================

The list is currently small, so don't hesitate to add signals and make a pull
request if you need them!

.. note::

   The signal ``content_object_init`` can send a different type of object as
   the argument. If you want to register only one type of object then you will
   need to specify the sender when you are connecting to the signal.

   ::

       from pelican import signals
       from pelican import contents

       def test(sender, instance):
               print "%s : %s content initialized !!" % (sender, instance)

       def register():
               signals.content_object_init.connect(test, sender=contents.Article)

.. note::

   After Pelican 3.2, signal names were standardized.  Older plugins
   may need to be updated to use the new names:

   ==========================  ===========================
   Old name                    New name
   ==========================  ===========================
   article_generate_context    article_generator_context
   article_generate_finalized  article_generator_finalized
   article_generate_preread    article_generator_preread
   pages_generate_context      page_generator_context
   pages_generate_preread      page_generator_preread
   pages_generator_finalized   page_generator_finalized
   pages_generator_init        page_generator_init
   static_generate_context     static_generator_context
   static_generate_preread     static_generator_preread
   ==========================  ===========================

Recipes
=======

We eventually realised some of the recipes to create plugins would be best
shared in the documentation somewhere, so here they are!

How to create a new reader
--------------------------

One thing you might want is to add the support for your very own input
format. While it might make sense to add this feature in pelican core, we
wisely chose to avoid this situation, and have the different readers defined in
plugins.

The rationale behind this choice is mainly that plugins are really easy to
write and don't slow down pelican itself when they're not active.

No more talking, here is the example::

    from pelican import signals
    from pelican.readers import BaseReader

    # Create a new reader class, inheriting from the pelican.reader.BaseReader
    class NewReader(BaseReader):
        enabled = True  # Yeah, you probably want that :-)

        # The list of file extensions you want this reader to match with.
        # In the case multiple readers use the same extensions, the latest will
        # win (so the one you're defining here, most probably).
        file_extensions = ['yeah']

        # You need to have a read method, which takes a filename and returns
        # some content and the associated metadata.
        def read(self, filename):
            metadata = {'title': 'Oh yeah',
                        'category': 'Foo',
                        'date': '2012-12-01'}

            parsed = {}
            for key, value in metadata.items():
                parsed[key] = self.process_metadata(key, value)

            return "Some content", parsed

    def add_reader(readers):
        readers.reader_classes['yeah'] = NewReader

    # this is how pelican works.
    def register():
        signals.readers_init.connect(add_reader)


Adding a new generator
----------------------

Adding a new generator is also really easy. You might want to have a look at
:doc:`internals` for more information on how to create your own generator.

::

    def get_generators(generators):
        # define a new generator here if you need to
        return generators

    signals.get_generators.connect(get_generators)