A new Riff-radio.org site with a static approach.

extending.html 77KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1">
  6. <title>Extending Nikola | Riff</title>
  7. <link href="../assets/css/all-nocdn.css" rel="stylesheet" type="text/css">
  8. <link rel="alternate" type="application/rss+xml" title="RSS" href="../rss.xml">
  9. <link rel="canonical" href="http://media.pagelibre.org/riff/site/pages/extending.html">
  10. <link rel="icon" href="../favicon.ico" sizes="16x16">
  11. <!--[if lt IE 9]><script src="../assets/js/html5.js"></script><![endif]--><meta name="author" content="The Nikola Team">
  12. <meta property="og:site_name" content="Riff">
  13. <meta property="og:title" content="Extending Nikola">
  14. <meta property="og:url" content="http://media.pagelibre.org/riff/site/pages/extending.html">
  15. <meta property="og:description" content="Version:
  16. 8.2.3
  17. Author:
  18. Roberto Alsina &lt;ralsina@netmanagers.com.ar&gt;
  19. Contents
  20. Available Plugin Categories
  21. Command Plugins
  22. TemplateSystem Plugins
  23. Task Plugins
  24. PageCompiler Plugins
  25. MetadataExtractor P">
  26. <meta property="og:type" content="article">
  27. <meta property="article:published_time" content="2012-03-30T23:00:00-03:00">
  28. </head>
  29. <body>
  30. <a href="#content" class="sr-only sr-only-focusable">Skip to main content</a>
  31. <!-- Menubar -->
  32. <div class="blog-masthead">
  33. <div class="container">
  34. <!-- This keeps the margins nice -->
  35. <nav class="blog-nav" role="navigation"><a href="../index.html" class="blog-nav-item">Accueil</a>
  36. <a href="about.html" class="blog-nav-item">About Riff</a>
  37. <a href="../rss.xml" class="blog-nav-item">RSS feed</a>
  38. </nav>
  39. </div>
  40. <!-- /.container -->
  41. </div>
  42. <!-- End of Menubar -->
  43. <div class="container" id="content" role="main">
  44. <div class="body-content">
  45. <div class="blog-header">
  46. <h1 class="blog-title">
  47. <a href="http://media.pagelibre.org/riff/site/">
  48. <span id="blog-title">Riff</span>
  49. </a>
  50. </h1>
  51. <p class="lead blog-description">Riff la radio rock</p>
  52. </div>
  53. <!--Body content-->
  54. <div class="row">
  55. <div class="col-sm-8 blog-main">
  56. <article class="post-text storypage" itemscope="itemscope" itemtype="http://schema.org/Article"><header><h2 class="p-name entry-title blog-post-title" itemprop="headline name"><a href="#" class="u-url">Extending Nikola</a></h2>
  57. </header><div class="e-content entry-content" itemprop="articleBody text">
  58. <dl class="docinfo simple">
  59. <dt class="version">Version<span class="colon">:</span>
  60. </dt>
  61. <dd class="version">8.2.3</dd>
  62. <dt class="author">Author<span class="colon">:</span>
  63. </dt>
  64. <dd class="author"><p>Roberto Alsina &lt;<a class="reference external" href="mailto:ralsina@netmanagers.com.ar">ralsina@netmanagers.com.ar</a>&gt;</p></dd>
  65. </dl>
  66. <nav class="contents alert alert-primary float-md-right" id="contents" role="doc-toc"><p class="topic-title">Contents</p>
  67. <ul class="simple">
  68. <li>
  69. <p><a class="reference internal" href="extending.html#available-plugin-categories" id="toc-entry-1">Available Plugin Categories</a></p>
  70. <ul>
  71. <li><p><a class="reference internal" href="extending.html#command-plugins" id="toc-entry-2">Command Plugins</a></p></li>
  72. <li><p><a class="reference internal" href="extending.html#templatesystem-plugins" id="toc-entry-3">TemplateSystem Plugins</a></p></li>
  73. <li><p><a class="reference internal" href="extending.html#task-plugins" id="toc-entry-4">Task Plugins</a></p></li>
  74. <li><p><a class="reference internal" href="extending.html#pagecompiler-plugins" id="toc-entry-5">PageCompiler Plugins</a></p></li>
  75. <li><p><a class="reference internal" href="extending.html#metadataextractor-plugins" id="toc-entry-6">MetadataExtractor Plugins</a></p></li>
  76. <li><p><a class="reference internal" href="extending.html#restextension-plugins" id="toc-entry-7">RestExtension Plugins</a></p></li>
  77. <li><p><a class="reference internal" href="extending.html#markdownextension-plugins" id="toc-entry-8">MarkdownExtension Plugins</a></p></li>
  78. <li><p><a class="reference internal" href="extending.html#signalhandler-plugins" id="toc-entry-9">SignalHandler Plugins</a></p></li>
  79. <li><p><a class="reference internal" href="extending.html#configplugin-plugins" id="toc-entry-10">ConfigPlugin Plugins</a></p></li>
  80. <li><p><a class="reference internal" href="extending.html#commentsystem-plugins" id="toc-entry-11">CommentSystem Plugins</a></p></li>
  81. <li><p><a class="reference internal" href="extending.html#shortcode-plugins" id="toc-entry-12">Shortcode Plugins</a></p></li>
  82. <li><p><a class="reference internal" href="extending.html#postscanner-plugins" id="toc-entry-13">PostScanner Plugins</a></p></li>
  83. </ul>
  84. </li>
  85. <li><p><a class="reference internal" href="extending.html#plugin-index" id="toc-entry-14">Plugin Index</a></p></li>
  86. <li><p><a class="reference internal" href="extending.html#path-link-resolution-mechanism" id="toc-entry-15">Path/Link Resolution Mechanism</a></p></li>
  87. <li><p><a class="reference internal" href="extending.html#template-hooks" id="toc-entry-16">Template Hooks</a></p></li>
  88. <li>
  89. <p><a class="reference internal" href="extending.html#shortcodes" id="toc-entry-17">Shortcodes</a></p>
  90. <ul>
  91. <li><p><a class="reference internal" href="extending.html#template-based-shortcodes" id="toc-entry-18">Template-based Shortcodes</a></p></li>
  92. </ul>
  93. </li>
  94. <li><p><a class="reference internal" href="extending.html#state-and-cache" id="toc-entry-19">State and Cache</a></p></li>
  95. <li><p><a class="reference internal" href="extending.html#logging" id="toc-entry-20">Logging</a></p></li>
  96. <li><p><a class="reference internal" href="extending.html#template-and-dependency-injection" id="toc-entry-21">Template and Dependency Injection</a></p></li>
  97. </ul></nav><p class="lead">Nikola is extensible. Almost all its functionality is based on plugins,
  98. and you can add your own or replace the provided ones.</p>
  99. <p>Plugins consist of a metadata file (with <code class="docutils literal">.plugin</code> extension) and
  100. a Python module (a <code class="docutils literal">.py</code> file) or package (a folder containing
  101. a <code class="docutils literal">__init__.py</code> file.</p>
  102. <p>To use a plugin in your site, you just have to put it in a <code class="docutils literal">plugins</code>
  103. folder in your site.</p>
  104. <p>Plugins come in various flavours, aimed at extending different aspects
  105. of Nikola.</p>
  106. <section id="available-plugin-categories"><h2><a class="toc-backref" href="extending.html#toc-entry-1" role="doc-backlink">Available Plugin Categories</a></h2>
  107. <section id="command-plugins"><h3><a class="toc-backref" href="extending.html#toc-entry-2" role="doc-backlink">Command Plugins</a></h3>
  108. <p>When you run <code class="docutils literal">nikola <span class="pre">--help</span></code> you will see something like this:</p>
  109. <pre class="code console"><a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-1"></a><span class="gp">$</span> nikola <span class="nb">help</span>
  110. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-2"></a><span class="go">Nikola is a tool to create static websites and blogs. For full documentation and more</span>
  111. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-3"></a><span class="go">information, please visit https://getnikola.com/</span>
  112. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-4"></a>
  113. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-5"></a>
  114. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-6"></a><span class="go">Available commands:</span>
  115. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-7"></a><span class="go">nikola auto automatically detect site changes, rebuild</span>
  116. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-8"></a><span class="go"> and optionally refresh a browser</span>
  117. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-9"></a><span class="go">nikola bootswatch_theme given a swatch name from bootswatch.com and a</span>
  118. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-10"></a><span class="go"> parent theme, creates a custom theme</span>
  119. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-11"></a><span class="go">nikola build run tasks</span>
  120. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-12"></a><span class="go">nikola check check links and files in the generated site</span>
  121. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-13"></a><span class="go">nikola clean clean action / remove targets</span>
  122. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-14"></a><span class="go">nikola console start an interactive python console with access to</span>
  123. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-15"></a><span class="go"> your site and configuration</span>
  124. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-16"></a><span class="go">nikola deploy deploy the site</span>
  125. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-17"></a><span class="go">nikola dumpdb dump dependency DB</span>
  126. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-18"></a><span class="go">nikola forget clear successful run status from internal DB</span>
  127. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-19"></a><span class="go">nikola help show help</span>
  128. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-20"></a><span class="go">nikola ignore ignore task (skip) on subsequent runs</span>
  129. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-21"></a><span class="go">nikola import_blogger import a blogger dump</span>
  130. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-22"></a><span class="go">nikola import_feed import a RSS/Atom dump</span>
  131. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-23"></a><span class="go">nikola import_wordpress import a WordPress dump</span>
  132. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-24"></a><span class="go">nikola init create a Nikola site in the specified folder</span>
  133. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-25"></a><span class="go">nikola list list tasks from dodo file</span>
  134. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-26"></a><span class="go">nikola mincss apply mincss to the generated site</span>
  135. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-27"></a><span class="go">nikola new_post create a new blog post or site page</span>
  136. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-28"></a><span class="go">nikola run run tasks</span>
  137. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-29"></a><span class="go">nikola serve start the test webserver</span>
  138. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-30"></a><span class="go">nikola strace use strace to list file_deps and targets</span>
  139. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-31"></a><span class="go">nikola theme manage themes</span>
  140. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-32"></a><span class="go">nikola version print the Nikola version number</span>
  141. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-33"></a>
  142. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-34"></a><span class="go">nikola help show help / reference</span>
  143. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-35"></a><span class="go">nikola help &lt;command&gt; show command usage</span>
  144. <a name="rest_code_6fc228dc86544900b3254eb5bab7e47e-36"></a><span class="go">nikola help &lt;task-name&gt; show task usage</span>
  145. </pre>
  146. <p>That will give you a list of all available commands in your version of Nikola.
  147. Each and every one of those is a plugin. Let's look at a typical example:</p>
  148. <p>First, the <code class="docutils literal">serve.plugin</code> file:</p>
  149. <pre class="code ini"><a name="rest_code_ba62f591ee56474b8dad401ec415b819-1"></a><span class="k">[Core]</span>
  150. <a name="rest_code_ba62f591ee56474b8dad401ec415b819-2"></a><span class="na">Name</span> <span class="o">=</span> <span class="s">serve</span>
  151. <a name="rest_code_ba62f591ee56474b8dad401ec415b819-3"></a><span class="na">Module</span> <span class="o">=</span> <span class="s">serve</span>
  152. <a name="rest_code_ba62f591ee56474b8dad401ec415b819-4"></a>
  153. <a name="rest_code_ba62f591ee56474b8dad401ec415b819-5"></a><span class="k">[Documentation]</span>
  154. <a name="rest_code_ba62f591ee56474b8dad401ec415b819-6"></a><span class="na">Author</span> <span class="o">=</span> <span class="s">Roberto Alsina</span>
  155. <a name="rest_code_ba62f591ee56474b8dad401ec415b819-7"></a><span class="na">Version</span> <span class="o">=</span> <span class="s">0.1</span>
  156. <a name="rest_code_ba62f591ee56474b8dad401ec415b819-8"></a><span class="na">Website</span> <span class="o">=</span> <span class="s">https://getnikola.com</span>
  157. <a name="rest_code_ba62f591ee56474b8dad401ec415b819-9"></a><span class="na">Description</span> <span class="o">=</span> <span class="s">Start test server.</span>
  158. </pre>
  159. <aside class="admonition note"><p class="admonition-title">Note</p>
  160. <p>If you want to publish your plugin on the Plugin Index, <a class="reference external" href="https://github.com/getnikola/plugins/blob/master/README.md">read
  161. the docs for the Index</a>
  162. (and the .plugin file examples and explanations).</p>
  163. </aside><p>For your own plugin, just change the values in a sensible way. The
  164. <code class="docutils literal">Module</code> will be used to find the matching Python module, in this case
  165. <code class="docutils literal">serve.py</code>, from which this is the interesting bit:</p>
  166. <pre class="code python"><a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-1"></a><span class="kn">from</span> <span class="nn">nikola.plugin_categories</span> <span class="kn">import</span> <span class="n">Command</span>
  167. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-2"></a>
  168. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-3"></a><span class="c1"># You have to inherit Command for this to be a</span>
  169. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-4"></a><span class="c1"># command plugin:</span>
  170. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-5"></a>
  171. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-6"></a><span class="k">class</span> <span class="nc">CommandServe</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
  172. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-7"></a> <span class="sd">"""Start test server."""</span>
  173. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-8"></a>
  174. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-9"></a> <span class="n">name</span> <span class="o">=</span> <span class="s2">"serve"</span>
  175. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-10"></a> <span class="n">doc_usage</span> <span class="o">=</span> <span class="s2">"[options]"</span>
  176. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-11"></a> <span class="n">doc_purpose</span> <span class="o">=</span> <span class="s2">"start the test webserver"</span>
  177. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-12"></a>
  178. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-13"></a> <span class="n">cmd_options</span> <span class="o">=</span> <span class="p">(</span>
  179. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-14"></a> <span class="p">{</span>
  180. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-15"></a> <span class="s1">'name'</span><span class="p">:</span> <span class="s1">'port'</span><span class="p">,</span>
  181. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-16"></a> <span class="s1">'short'</span><span class="p">:</span> <span class="s1">'p'</span><span class="p">,</span>
  182. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-17"></a> <span class="s1">'long'</span><span class="p">:</span> <span class="s1">'port'</span><span class="p">,</span>
  183. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-18"></a> <span class="s1">'default'</span><span class="p">:</span> <span class="mi">8000</span><span class="p">,</span>
  184. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-19"></a> <span class="s1">'type'</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span>
  185. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-20"></a> <span class="s1">'help'</span><span class="p">:</span> <span class="s1">'Port number'</span><span class="p">,</span>
  186. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-21"></a> <span class="p">},</span>
  187. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-22"></a> <span class="p">{</span>
  188. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-23"></a> <span class="s1">'name'</span><span class="p">:</span> <span class="s1">'address'</span><span class="p">,</span>
  189. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-24"></a> <span class="s1">'short'</span><span class="p">:</span> <span class="s1">'a'</span><span class="p">,</span>
  190. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-25"></a> <span class="s1">'long'</span><span class="p">:</span> <span class="s1">'--address'</span><span class="p">,</span>
  191. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-26"></a> <span class="s1">'type'</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
  192. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-27"></a> <span class="s1">'default'</span><span class="p">:</span> <span class="s1">'127.0.0.1'</span><span class="p">,</span>
  193. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-28"></a> <span class="s1">'help'</span><span class="p">:</span> <span class="s1">'Address to bind'</span><span class="p">,</span>
  194. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-29"></a> <span class="p">},</span>
  195. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-30"></a> <span class="p">)</span>
  196. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-31"></a>
  197. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-32"></a> <span class="k">def</span> <span class="nf">_execute</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">options</span><span class="p">,</span> <span class="n">args</span><span class="p">):</span>
  198. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-33"></a> <span class="sd">"""Start test server."""</span>
  199. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-34"></a> <span class="n">out_dir</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">'OUTPUT_FOLDER'</span><span class="p">]</span>
  200. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-35"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isdir</span><span class="p">(</span><span class="n">out_dir</span><span class="p">):</span>
  201. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-36"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"Error: Missing '</span><span class="si">{0}</span><span class="s2">' folder?"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">out_dir</span><span class="p">))</span>
  202. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-37"></a> <span class="k">return</span> <span class="mi">1</span> <span class="c1"># Exit code on failure. (return 0 not necessary)</span>
  203. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-38"></a> <span class="k">else</span><span class="p">:</span>
  204. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-39"></a> <span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">out_dir</span><span class="p">)</span>
  205. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-40"></a> <span class="n">httpd</span> <span class="o">=</span> <span class="n">HTTPServer</span><span class="p">((</span><span class="n">options</span><span class="p">[</span><span class="s1">'address'</span><span class="p">],</span> <span class="n">options</span><span class="p">[</span><span class="s1">'port'</span><span class="p">]),</span>
  206. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-41"></a> <span class="n">OurHTTPRequestHandler</span><span class="p">)</span>
  207. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-42"></a> <span class="n">sa</span> <span class="o">=</span> <span class="n">httpd</span><span class="o">.</span><span class="n">socket</span><span class="o">.</span><span class="n">getsockname</span><span class="p">()</span>
  208. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-43"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"Serving HTTP on"</span><span class="p">,</span> <span class="n">sa</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="s2">"port"</span><span class="p">,</span> <span class="n">sa</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s2">"..."</span><span class="p">)</span>
  209. <a name="rest_code_e3a6b6d51a3347a7adb07cea08cec1b1-44"></a> <span class="n">httpd</span><span class="o">.</span><span class="n">serve_forever</span><span class="p">()</span>
  210. </pre>
  211. <p>As mentioned above, a plugin can have options, which the user can see by doing
  212. <code class="docutils literal">nikola help command</code> and can later use, for example:</p>
  213. <pre class="code console"><a name="rest_code_3c9de002787e43998e18ec2797969dbc-1"></a><span class="gp">$</span> nikola <span class="nb">help</span> serve
  214. <a name="rest_code_3c9de002787e43998e18ec2797969dbc-2"></a><span class="go">nikola serve [options]</span>
  215. <a name="rest_code_3c9de002787e43998e18ec2797969dbc-3"></a><span class="go">start the test webserver</span>
  216. <a name="rest_code_3c9de002787e43998e18ec2797969dbc-4"></a>
  217. <a name="rest_code_3c9de002787e43998e18ec2797969dbc-5"></a><span class="go">Options:</span>
  218. <a name="rest_code_3c9de002787e43998e18ec2797969dbc-6"></a><span class="go"> -p ARG, --port=ARG</span>
  219. <a name="rest_code_3c9de002787e43998e18ec2797969dbc-7"></a><span class="go"> Port number [default: 8000]</span>
  220. <a name="rest_code_3c9de002787e43998e18ec2797969dbc-8"></a><span class="go"> -a ARG, --address=ARG</span>
  221. <a name="rest_code_3c9de002787e43998e18ec2797969dbc-9"></a><span class="go"> Address to bind [default: 127.0.0.1]</span>
  222. <a name="rest_code_3c9de002787e43998e18ec2797969dbc-10"></a>
  223. <a name="rest_code_3c9de002787e43998e18ec2797969dbc-11"></a><span class="gp">$</span> nikola serve -p <span class="m">9000</span>
  224. <a name="rest_code_3c9de002787e43998e18ec2797969dbc-12"></a><span class="go">Serving HTTP on 127.0.0.1 port 9000 ...</span>
  225. </pre>
  226. <p>So, what can you do with commands? Well, anything you want, really. I have implemented
  227. a sort of planet using it. So, be creative, and if you do something interesting,
  228. let me know ;-)</p>
  229. </section><section id="templatesystem-plugins"><h3><a class="toc-backref" href="extending.html#toc-entry-3" role="doc-backlink">TemplateSystem Plugins</a></h3>
  230. <p>Nikola supports Mako and Jinja2. If you prefer some other templating
  231. system, then you will have to write a <code class="docutils literal">TemplateSystem</code> plugin. Here's how they work.
  232. First, you have to create a <code class="docutils literal">.plugin</code> file. Here's the one for the Mako plugin:</p>
  233. <pre class="code ini"><a name="rest_code_c5c3f7f326704b998816809be8814ef2-1"></a><span class="k">[Core]</span>
  234. <a name="rest_code_c5c3f7f326704b998816809be8814ef2-2"></a><span class="na">Name</span> <span class="o">=</span> <span class="s">mako</span>
  235. <a name="rest_code_c5c3f7f326704b998816809be8814ef2-3"></a><span class="na">Module</span> <span class="o">=</span> <span class="s">mako</span>
  236. <a name="rest_code_c5c3f7f326704b998816809be8814ef2-4"></a>
  237. <a name="rest_code_c5c3f7f326704b998816809be8814ef2-5"></a><span class="k">[Documentation]</span>
  238. <a name="rest_code_c5c3f7f326704b998816809be8814ef2-6"></a><span class="na">Author</span> <span class="o">=</span> <span class="s">Roberto Alsina</span>
  239. <a name="rest_code_c5c3f7f326704b998816809be8814ef2-7"></a><span class="na">Version</span> <span class="o">=</span> <span class="s">0.1</span>
  240. <a name="rest_code_c5c3f7f326704b998816809be8814ef2-8"></a><span class="na">Website</span> <span class="o">=</span> <span class="s">https://getnikola.com</span>
  241. <a name="rest_code_c5c3f7f326704b998816809be8814ef2-9"></a><span class="na">Description</span> <span class="o">=</span> <span class="s">Support for Mako templates.</span>
  242. </pre>
  243. <aside class="admonition note"><p class="admonition-title">Note</p>
  244. <p>If you want to publish your plugin on the Plugin Index, <a class="reference external" href="https://github.com/getnikola/plugins/blob/master/README.md">read
  245. the docs for the Index</a>
  246. (and the .plugin file examples and explanations).</p>
  247. </aside><p>You will have to replace "mako" with your template system's name, and other data
  248. in the obvious ways.</p>
  249. <p>The "Module" option is the name of the module, which has to look something like this,
  250. a stub for a hypothetical system called "Templater":</p>
  251. <pre class="code python"><a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-1"></a><span class="kn">from</span> <span class="nn">nikola.plugin_categories</span> <span class="kn">import</span> <span class="n">TemplateSystem</span>
  252. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-2"></a>
  253. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-3"></a><span class="c1"># You have to inherit TemplateSystem</span>
  254. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-4"></a>
  255. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-5"></a><span class="k">class</span> <span class="nc">TemplaterTemplates</span><span class="p">(</span><span class="n">TemplateSystem</span><span class="p">):</span>
  256. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-6"></a> <span class="sd">"""Wrapper for Templater templates."""</span>
  257. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-7"></a>
  258. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-8"></a> <span class="c1"># name has to match Name in the .plugin file</span>
  259. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-9"></a> <span class="n">name</span> <span class="o">=</span> <span class="s2">"templater"</span>
  260. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-10"></a>
  261. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-11"></a> <span class="c1"># A list of directories where the templates will be</span>
  262. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-12"></a> <span class="c1"># located. Most template systems have some sort of</span>
  263. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-13"></a> <span class="c1"># template loading tool that can use this.</span>
  264. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-14"></a> <span class="k">def</span> <span class="nf">set_directories</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">directories</span><span class="p">,</span> <span class="n">cache_folder</span><span class="p">):</span>
  265. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-15"></a> <span class="sd">"""Sets the list of folders where templates are located and cache."""</span>
  266. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-16"></a> <span class="k">pass</span>
  267. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-17"></a>
  268. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-18"></a> <span class="c1"># You *must* implement this, even if to return []</span>
  269. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-19"></a> <span class="c1"># It should return a list of all the files that,</span>
  270. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-20"></a> <span class="c1"># when changed, may affect the template's output.</span>
  271. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-21"></a> <span class="c1"># usually this involves template inheritance and</span>
  272. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-22"></a> <span class="c1"># inclusion.</span>
  273. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-23"></a> <span class="k">def</span> <span class="nf">template_deps</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">template_name</span><span class="p">):</span>
  274. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-24"></a> <span class="sd">"""Returns filenames which are dependencies for a template."""</span>
  275. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-25"></a> <span class="k">return</span> <span class="p">[]</span>
  276. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-26"></a>
  277. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-27"></a> <span class="k">def</span> <span class="nf">render_template</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">template_name</span><span class="p">,</span> <span class="n">output_name</span><span class="p">,</span> <span class="n">context</span><span class="p">):</span>
  278. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-28"></a> <span class="sd">"""Renders template to a file using context.</span>
  279. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-29"></a>
  280. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-30"></a><span class="sd"> This must save the data to output_name *and* return it</span>
  281. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-31"></a><span class="sd"> so that the caller may do additional processing.</span>
  282. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-32"></a><span class="sd"> """</span>
  283. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-33"></a> <span class="k">pass</span>
  284. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-34"></a>
  285. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-35"></a> <span class="c1"># The method that does the actual rendering.</span>
  286. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-36"></a> <span class="c1"># template_name is the name of the template file,</span>
  287. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-37"></a> <span class="c1"># context is a dictionary containing the data the template</span>
  288. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-38"></a> <span class="c1"># uses for rendering.</span>
  289. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-39"></a> <span class="k">def</span> <span class="nf">render_template_to_string</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">template</span><span class="p">,</span> <span class="n">context</span><span class="p">):</span>
  290. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-40"></a> <span class="sd">"""Renders template to a string using context. """</span>
  291. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-41"></a> <span class="k">pass</span>
  292. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-42"></a>
  293. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-43"></a> <span class="k">def</span> <span class="nf">inject_directory</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">directory</span><span class="p">):</span>
  294. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-44"></a> <span class="sd">"""Injects the directory with the lowest priority in the</span>
  295. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-45"></a><span class="sd"> template search mechanism."""</span>
  296. <a name="rest_code_5a519bdb6ea7424d9da26e9afd8e3eba-46"></a> <span class="k">pass</span>
  297. </pre>
  298. <p>You can see a real example in <a class="reference external" href="https://github.com/getnikola/nikola/blob/master/nikola/plugins/template/jinja.py">the Jinja plugin</a></p>
  299. </section><section id="task-plugins"><h3><a class="toc-backref" href="extending.html#toc-entry-4" role="doc-backlink">Task Plugins</a></h3>
  300. <p>If you want to do something that depends on the data in your site, you
  301. probably want to do a <code class="docutils literal">Task</code> plugin, which will make it be part of the
  302. <code class="docutils literal">nikola build</code> command. These are the currently available tasks, all
  303. provided by plugins:</p>
  304. <aside class="sidebar"><p class="sidebar-title">Other Tasks</p>
  305. <p>There are also <code class="docutils literal">LateTask</code> plugins, which are executed later,
  306. and <code class="docutils literal">TaskMultiplier</code> plugins that take a task and create
  307. more tasks out of it.</p>
  308. </aside><pre class="code console"><a name="rest_code_fc9ffb7c69224daeb0a3e5d7b2feb52d-1"></a><span class="gp">$</span> nikola list
  309. <a name="rest_code_fc9ffb7c69224daeb0a3e5d7b2feb52d-2"></a><span class="go">Scanning posts....done!</span>
  310. <a name="rest_code_fc9ffb7c69224daeb0a3e5d7b2feb52d-3"></a><span class="go">copy_assets</span>
  311. <a name="rest_code_fc9ffb7c69224daeb0a3e5d7b2feb52d-4"></a><span class="go">copy_files</span>
  312. <a name="rest_code_fc9ffb7c69224daeb0a3e5d7b2feb52d-5"></a><span class="go">create_bundles</span>
  313. <a name="rest_code_fc9ffb7c69224daeb0a3e5d7b2feb52d-6"></a><span class="go">post_render</span>
  314. <a name="rest_code_fc9ffb7c69224daeb0a3e5d7b2feb52d-7"></a><span class="go">redirect</span>
  315. <a name="rest_code_fc9ffb7c69224daeb0a3e5d7b2feb52d-8"></a><span class="go">render_galleries</span>
  316. <a name="rest_code_fc9ffb7c69224daeb0a3e5d7b2feb52d-9"></a><span class="go">render_listings</span>
  317. <a name="rest_code_fc9ffb7c69224daeb0a3e5d7b2feb52d-10"></a><span class="go">render_pages</span>
  318. <a name="rest_code_fc9ffb7c69224daeb0a3e5d7b2feb52d-11"></a><span class="go">render_posts</span>
  319. <a name="rest_code_fc9ffb7c69224daeb0a3e5d7b2feb52d-12"></a><span class="go">render_site</span>
  320. <a name="rest_code_fc9ffb7c69224daeb0a3e5d7b2feb52d-13"></a><span class="go">render_sources</span>
  321. <a name="rest_code_fc9ffb7c69224daeb0a3e5d7b2feb52d-14"></a><span class="go">render_taxonomies</span>
  322. <a name="rest_code_fc9ffb7c69224daeb0a3e5d7b2feb52d-15"></a><span class="go">robots_file</span>
  323. <a name="rest_code_fc9ffb7c69224daeb0a3e5d7b2feb52d-16"></a><span class="go">scale_images</span>
  324. <a name="rest_code_fc9ffb7c69224daeb0a3e5d7b2feb52d-17"></a><span class="go">sitemap</span>
  325. </pre>
  326. <p>These have access to the <code class="docutils literal">site</code> object which contains your timeline and
  327. your configuration.</p>
  328. <p>The critical bit of Task plugins is their <code class="docutils literal">gen_tasks</code> method, which <code class="docutils literal">yields</code>
  329. <a class="reference external" href="https://pydoit.org/tasks.html">doit tasks</a>.</p>
  330. <p>The details of how to handle dependencies, etc., are a bit too much for this
  331. document, so I'll just leave you with an example, the <code class="docutils literal">copy_assets</code> task.
  332. First the <code class="docutils literal">task_copy_assets.plugin</code> file, which you should copy and edit
  333. in the logical ways:</p>
  334. <pre class="code ini"><a name="rest_code_8abe88df87fb424cbe0e5131ed77debd-1"></a><span class="k">[Core]</span>
  335. <a name="rest_code_8abe88df87fb424cbe0e5131ed77debd-2"></a><span class="na">Name</span> <span class="o">=</span> <span class="s">copy_assets</span>
  336. <a name="rest_code_8abe88df87fb424cbe0e5131ed77debd-3"></a><span class="na">Module</span> <span class="o">=</span> <span class="s">task_copy_assets</span>
  337. <a name="rest_code_8abe88df87fb424cbe0e5131ed77debd-4"></a>
  338. <a name="rest_code_8abe88df87fb424cbe0e5131ed77debd-5"></a><span class="k">[Documentation]</span>
  339. <a name="rest_code_8abe88df87fb424cbe0e5131ed77debd-6"></a><span class="na">Author</span> <span class="o">=</span> <span class="s">Roberto Alsina</span>
  340. <a name="rest_code_8abe88df87fb424cbe0e5131ed77debd-7"></a><span class="na">Version</span> <span class="o">=</span> <span class="s">0.1</span>
  341. <a name="rest_code_8abe88df87fb424cbe0e5131ed77debd-8"></a><span class="na">Website</span> <span class="o">=</span> <span class="s">https://getnikola.com</span>
  342. <a name="rest_code_8abe88df87fb424cbe0e5131ed77debd-9"></a><span class="na">Description</span> <span class="o">=</span> <span class="s">Copy theme assets into output.</span>
  343. </pre>
  344. <aside class="admonition note"><p class="admonition-title">Note</p>
  345. <p>If you want to publish your plugin on the Plugin Index, <a class="reference external" href="https://github.com/getnikola/plugins/blob/master/README.md">read
  346. the docs for the Index</a>
  347. (and the .plugin file examples and explanations).</p>
  348. </aside><p>And the <code class="docutils literal">task_copy_assets.py</code> file, in its entirety:</p>
  349. <pre class="code python"><a name="rest_code_c033780b5b47427f9b622b01c7471f12-1"></a><span class="kn">import</span> <span class="nn">os</span>
  350. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-2"></a>
  351. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-3"></a><span class="kn">from</span> <span class="nn">nikola.plugin_categories</span> <span class="kn">import</span> <span class="n">Task</span>
  352. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-4"></a><span class="kn">from</span> <span class="nn">nikola</span> <span class="kn">import</span> <span class="n">utils</span>
  353. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-5"></a>
  354. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-6"></a><span class="c1"># Have to inherit Task to be a task plugin</span>
  355. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-7"></a><span class="k">class</span> <span class="nc">CopyAssets</span><span class="p">(</span><span class="n">Task</span><span class="p">):</span>
  356. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-8"></a> <span class="sd">"""Copy theme assets into output."""</span>
  357. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-9"></a>
  358. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-10"></a> <span class="n">name</span> <span class="o">=</span> <span class="s2">"copy_assets"</span>
  359. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-11"></a>
  360. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-12"></a> <span class="c1"># This yields the tasks</span>
  361. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-13"></a> <span class="k">def</span> <span class="nf">gen_tasks</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  362. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-14"></a> <span class="sd">"""Create tasks to copy the assets of the whole theme chain.</span>
  363. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-15"></a>
  364. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-16"></a><span class="sd"> If a file is present on two themes, use the version</span>
  365. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-17"></a><span class="sd"> from the "youngest" theme.</span>
  366. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-18"></a><span class="sd"> """</span>
  367. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-19"></a>
  368. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-20"></a> <span class="c1"># I put all the configurations and data the plugin uses</span>
  369. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-21"></a> <span class="c1"># in a dictionary because utils.config_changed will</span>
  370. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-22"></a> <span class="c1"># make it so that if these change, this task will be</span>
  371. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-23"></a> <span class="c1"># marked out of date, and run again.</span>
  372. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-24"></a>
  373. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-25"></a> <span class="n">kw</span> <span class="o">=</span> <span class="p">{</span>
  374. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-26"></a> <span class="s2">"themes"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">THEMES</span><span class="p">,</span>
  375. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-27"></a> <span class="s2">"output_folder"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">'OUTPUT_FOLDER'</span><span class="p">],</span>
  376. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-28"></a> <span class="s2">"filters"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">'FILTERS'</span><span class="p">],</span>
  377. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-29"></a> <span class="p">}</span>
  378. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-30"></a>
  379. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-31"></a> <span class="n">tasks</span> <span class="o">=</span> <span class="p">{}</span>
  380. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-32"></a> <span class="k">for</span> <span class="n">theme_name</span> <span class="ow">in</span> <span class="n">kw</span><span class="p">[</span><span class="s1">'themes'</span><span class="p">]:</span>
  381. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-33"></a> <span class="n">src</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">utils</span><span class="o">.</span><span class="n">get_theme_path</span><span class="p">(</span><span class="n">theme_name</span><span class="p">),</span> <span class="s1">'assets'</span><span class="p">)</span>
  382. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-34"></a> <span class="n">dst</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">kw</span><span class="p">[</span><span class="s1">'output_folder'</span><span class="p">],</span> <span class="s1">'assets'</span><span class="p">)</span>
  383. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-35"></a> <span class="k">for</span> <span class="n">task</span> <span class="ow">in</span> <span class="n">utils</span><span class="o">.</span><span class="n">copy_tree</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">dst</span><span class="p">):</span>
  384. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-36"></a> <span class="k">if</span> <span class="n">task</span><span class="p">[</span><span class="s1">'name'</span><span class="p">]</span> <span class="ow">in</span> <span class="n">tasks</span><span class="p">:</span>
  385. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-37"></a> <span class="k">continue</span>
  386. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-38"></a> <span class="n">tasks</span><span class="p">[</span><span class="n">task</span><span class="p">[</span><span class="s1">'name'</span><span class="p">]]</span> <span class="o">=</span> <span class="n">task</span>
  387. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-39"></a> <span class="n">task</span><span class="p">[</span><span class="s1">'uptodate'</span><span class="p">]</span> <span class="o">=</span> <span class="n">task</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'uptodate'</span><span class="p">,</span> <span class="p">[])</span> <span class="o">+</span> \
  388. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-40"></a> <span class="p">[</span><span class="n">utils</span><span class="o">.</span><span class="n">config_changed</span><span class="p">(</span><span class="n">kw</span><span class="p">)]</span>
  389. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-41"></a> <span class="n">task</span><span class="p">[</span><span class="s1">'basename'</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span>
  390. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-42"></a> <span class="c1"># If your task generates files, please do this.</span>
  391. <a name="rest_code_c033780b5b47427f9b622b01c7471f12-43"></a> <span class="k">yield</span> <span class="n">utils</span><span class="o">.</span><span class="n">apply_filters</span><span class="p">(</span><span class="n">task</span><span class="p">,</span> <span class="n">kw</span><span class="p">[</span><span class="s1">'filters'</span><span class="p">])</span>
  392. </pre></section><section id="pagecompiler-plugins"><h3><a class="toc-backref" href="extending.html#toc-entry-5" role="doc-backlink">PageCompiler Plugins</a></h3>
  393. <p>These plugins implement markup languages, they take sources for posts or pages and
  394. create HTML or other output files. A good example is <a class="reference external" href="https://github.com/getnikola/plugins/tree/master/v8/misaka">the misaka plugin</a> or the built-in
  395. compiler plugins.</p>
  396. <p>They must provide:</p>
  397. <dl class="simple">
  398. <dt><code class="docutils literal">compile</code></dt>
  399. <dd>
  400. <p>Function that builds a file.</p>
  401. </dd>
  402. <dt><code class="docutils literal">create_post</code></dt>
  403. <dd>
  404. <p>Function that creates an empty file with some metadata in it.</p>
  405. </dd>
  406. </dl>
  407. <p>If the compiler produces something other than HTML files, it should also implement <code class="docutils literal">extension</code> which
  408. returns the preferred extension for the output file.</p>
  409. <p>These plugins can also be used to extract metadata from a file. To do so, the
  410. plugin must set <code class="docutils literal">supports_metadata</code> to <code class="docutils literal">True</code> and implement <code class="docutils literal">read_metadata</code> that will return a dict containing the
  411. metadata contained in the file. Optionally, it may list <code class="docutils literal">metadata_conditions</code> (see <a class="reference internal" href="extending.html#metadataextractor-plugins">MetadataExtractor Plugins</a> below)</p>
  412. </section><section id="metadataextractor-plugins"><h3><a class="toc-backref" href="extending.html#toc-entry-6" role="doc-backlink">MetadataExtractor Plugins</a></h3>
  413. <p>Plugins that extract metadata from posts. If they are based on post content,
  414. they must implement <code class="docutils literal">_extract_metadata_from_text</code> (takes source of a post
  415. returns a dict of metadata). They may also implement
  416. <code class="docutils literal">split_metadata_from_text</code>, <code class="docutils literal">extract_text</code>. If they are based on filenames,
  417. they only need <code class="docutils literal">extract_filename</code>. If <code class="docutils literal">support_write</code> is set to True,
  418. <code class="docutils literal">write_metadata</code> must be implemented.</p>
  419. <p>Every extractor must be configured properly. The <code class="docutils literal">name</code>, <code class="docutils literal">source</code> (from the
  420. <code class="docutils literal">MetaSource</code> enum in <code class="docutils literal">metadata_extractors</code>) and <code class="docutils literal">priority</code>
  421. (<code class="docutils literal">MetaPriority</code>) fields are mandatory. There might also be a list of
  422. <code class="docutils literal">conditions</code> (tuples of <code class="docutils literal">MetaCondition, arg</code>), used to check if an
  423. extractor can provide metadata, a compiled regular expression used to split
  424. metadata (<code class="docutils literal">split_metadata_re</code>, may be <code class="docutils literal">None</code>, used by default
  425. <code class="docutils literal">split_metadata_from_text</code>), a list of <code class="docutils literal">requirements</code> (3-tuples: import
  426. name, pip name, friendly name), <code class="docutils literal">map_from</code> (name of <code class="docutils literal">METADATA_MAPPING</code> to
  427. use, if any) and <code class="docutils literal">supports_write</code> (whether the extractor supports writing
  428. metadata in the desired format).</p>
  429. <p>For more details, see the definition in <code class="docutils literal">plugin_categories.py</code> and default extractors in <code class="docutils literal">metadata_extractors.py</code>.</p>
  430. </section><section id="restextension-plugins"><h3><a class="toc-backref" href="extending.html#toc-entry-7" role="doc-backlink">RestExtension Plugins</a></h3>
  431. <p>Implement directives for reStructuredText, see <a class="reference external" href="https://github.com/getnikola/nikola/blob/master/nikola/plugins/compile/rest/media.py">media.py</a> for a simple example.</p>
  432. <p>If your output depends on a config value, you need to make your post record a
  433. dependency on a pseudo-path, like this:</p>
  434. <pre class="code text"><a name="rest_code_9ac74e87bd9840bcb263f3d32ac5ffc4-1"></a>####MAGIC####CONFIG:OPTIONNAME
  435. </pre>
  436. <p>Then, whenever the <code class="docutils literal">OPTIONNAME</code> option is changed in conf.py, the file will be rebuilt.</p>
  437. <p>If your directive depends or may depend on the whole timeline (like the
  438. <code class="docutils literal"><span class="pre">post-list</span></code> directive, where adding new posts to the site could make it
  439. stale), you should record a dependency on the pseudo-path
  440. <code class="docutils literal"><span class="pre">####MAGIC####TIMELINE</span></code>.</p>
  441. </section><section id="markdownextension-plugins"><h3><a class="toc-backref" href="extending.html#toc-entry-8" role="doc-backlink">MarkdownExtension Plugins</a></h3>
  442. <p>Implement Markdown extensions, see <a class="reference external" href="https://github.com/getnikola/nikola/blob/master/nikola/plugins/compile/markdown/mdx_nikola.py">mdx_nikola.py</a> for a simple example.</p>
  443. <p>Note that Python markdown extensions are often also available as separate
  444. packages. This is only meant to ship extensions along with Nikola.</p>
  445. </section><section id="signalhandler-plugins"><h3><a class="toc-backref" href="extending.html#toc-entry-9" role="doc-backlink">SignalHandler Plugins</a></h3>
  446. <p>These plugins extend the <code class="docutils literal">SignalHandler</code> class and connect to one or more
  447. signals via <a class="reference external" href="https://pythonhosted.org/blinker/">blinker</a>.</p>
  448. <p>The easiest way to do this is to reimplement <code class="docutils literal">set_site()</code> and just connect to
  449. whatever signals you want there.</p>
  450. <p>Currently Nikola emits the following signals:</p>
  451. <dl>
  452. <dt><code class="docutils literal">sighandlers_loaded</code></dt>
  453. <dd>
  454. <p>Right after SignalHandler plugin activation.</p>
  455. </dd>
  456. <dt><code class="docutils literal">initialized</code></dt>
  457. <dd>
  458. <p>When all tasks are loaded.</p>
  459. </dd>
  460. <dt><code class="docutils literal">configured</code></dt>
  461. <dd>
  462. <p>When all the configuration file is processed. Note that plugins are activated before this is emitted.</p>
  463. </dd>
  464. <dt><code class="docutils literal">scanned</code></dt>
  465. <dd>
  466. <p>After posts are scanned.</p>
  467. </dd>
  468. <dt>
  469. <code class="docutils literal">new_post</code> / <code class="docutils literal">new_page</code>
  470. </dt>
  471. <dd>
  472. <p>When a new post is created, using the <code class="docutils literal">nikola new_post</code>/<code class="docutils literal">nikola new_page</code> commands. The signal
  473. data contains the path of the file, and the metadata file (if there is one).</p>
  474. </dd>
  475. <dt>
  476. <code class="docutils literal">existing_post</code> / <code class="docutils literal">existing_page</code>
  477. </dt>
  478. <dd>
  479. <p>When a new post fails to be created due to a title conflict. Contains the same data as <code class="docutils literal">new_post</code>.</p>
  480. </dd>
  481. <dt><code class="docutils literal">deployed</code></dt>
  482. <dd>
  483. <p>When the <code class="docutils literal">nikola deploy</code> command is run, and there is at least one new
  484. entry/post since <code class="docutils literal">last_deploy</code>. The signal data is of the form:</p>
  485. <pre class="literal-block">{
  486. 'last_deploy: # datetime object for the last deployed time,
  487. 'new_deploy': # datetime object for the current deployed time,
  488. 'clean': # whether there was a record of a last deployment,
  489. 'deployed': # all files deployed after the last deploy,
  490. 'undeployed': # all files not deployed since they are either future posts/drafts
  491. }</pre>
  492. </dd>
  493. <dt><code class="docutils literal">compiled</code></dt>
  494. <dd>
  495. <p>When a post/page is compiled from its source to html, before anything else is done with it. The signal
  496. data is in the form:</p>
  497. <pre class="literal-block">{
  498. 'source': # the path to the source file
  499. 'dest': # the path to the cache file for the post/page
  500. 'post': # the Post object for the post/page
  501. }</pre>
  502. </dd>
  503. </dl>
  504. <p>One example is the <a class="reference external" href="https://github.com/getnikola/plugins/tree/master/v7/deploy_hooks">deploy_hooks plugin.</a></p>
  505. </section><section id="configplugin-plugins"><h3><a class="toc-backref" href="extending.html#toc-entry-10" role="doc-backlink">ConfigPlugin Plugins</a></h3>
  506. <p>Does nothing specific, can be used to modify the site object (and thus the config).</p>
  507. <p>Put all the magic you want in <code class="docutils literal">set_site()</code>, and don’t forget to run the one
  508. from <code class="docutils literal">super()</code>. Example plugin: <a class="reference external" href="https://github.com/getnikola/plugins/tree/master/v7/navstories">navstories</a></p>
  509. </section><section id="commentsystem-plugins"><h3><a class="toc-backref" href="extending.html#toc-entry-11" role="doc-backlink">CommentSystem Plugins</a></h3>
  510. <p>Can be used to add a new comment system. (It doesn’t do anything by itself.) It’s expected to provide templates named <code class="docutils literal">comment_helper_foo.tmpl</code>.</p>
  511. <p>Example plugin: <a class="reference external" href="https://github.com/getnikola/plugins/tree/master/v8/cactuscomments">cactuscomments</a></p>
  512. </section><section id="shortcode-plugins"><h3><a class="toc-backref" href="extending.html#toc-entry-12" role="doc-backlink">Shortcode Plugins</a></h3>
  513. <p>Shortcode Plugins are a simple way to create a custom shortcode handler.
  514. By default, the <code class="docutils literal">set_site</code> method will register the <code class="docutils literal">handler</code> method as a
  515. shortcode with the plugin’s <code class="docutils literal">name</code> as the shortcode name.</p>
  516. <p>See the <a class="reference internal" href="extending.html#shortcodes">Shortcodes</a> section for more details on shortcodes.</p>
  517. </section><section id="postscanner-plugins"><h3><a class="toc-backref" href="extending.html#toc-entry-13" role="doc-backlink">PostScanner Plugins</a></h3>
  518. <p>Get posts and pages from "somewhere" to be added to the timeline.
  519. There are currently two plugins for this: the built-in <code class="docutils literal">scan_posts</code>, and
  520. <code class="docutils literal">pkgindex_scan</code> (in the Plugin Index), which is used to treat .plugin/.theme
  521. + README.md as posts to generate the Plugin and Theme Indexes.</p>
  522. </section></section><section id="plugin-index"><h2><a class="toc-backref" href="extending.html#toc-entry-14" role="doc-backlink">Plugin Index</a></h2>
  523. <p>There is a <a class="reference external" href="https://plugins.getnikola.com/">plugin index</a>, which stores all
  524. of the plugins for Nikola people wanted to share with the world.</p>
  525. <p>You may want to read the <a class="reference external" href="https://github.com/getnikola/plugins/blob/master/README.md">README for the Index</a> if you want to
  526. publish your package there.</p>
  527. </section><section id="path-link-resolution-mechanism"><h2><a class="toc-backref" href="extending.html#toc-entry-15" role="doc-backlink">Path/Link Resolution Mechanism</a></h2>
  528. <p>Any plugin can register a function using <code class="docutils literal">Nikola.register_path_handler</code> to
  529. allow resolution of paths and links. These are useful for templates, which
  530. can access them via <code class="docutils literal">_link</code>.</p>
  531. <p>For example, you can always get a link to the path for the feed of the "foo" tag
  532. by using <code class="docutils literal"><span class="pre">_link('tag_rss',</span> 'foo')</code> or the <code class="docutils literal"><span class="pre">link://tag_rss/foo</span></code> URL.</p>
  533. <p>Here's the relevant code from the tag plugin.</p>
  534. <pre class="code python"><a name="rest_code_c3b874e131b54f6e96535b5ef0c56564-1"></a><span class="c1"># In set_site</span>
  535. <a name="rest_code_c3b874e131b54f6e96535b5ef0c56564-2"></a><span class="n">site</span><span class="o">.</span><span class="n">register_path_handler</span><span class="p">(</span><span class="s1">'tag_rss'</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">tag_rss_path</span><span class="p">)</span>
  536. <a name="rest_code_c3b874e131b54f6e96535b5ef0c56564-3"></a>
  537. <a name="rest_code_c3b874e131b54f6e96535b5ef0c56564-4"></a><span class="c1"># And these always take name and lang as arguments and return a list of</span>
  538. <a name="rest_code_c3b874e131b54f6e96535b5ef0c56564-5"></a><span class="c1"># path elements.</span>
  539. <a name="rest_code_c3b874e131b54f6e96535b5ef0c56564-6"></a><span class="k">def</span> <span class="nf">tag_rss_path</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">lang</span><span class="p">):</span>
  540. <a name="rest_code_c3b874e131b54f6e96535b5ef0c56564-7"></a> <span class="k">return</span> <span class="p">[</span><span class="n">_f</span> <span class="k">for</span> <span class="n">_f</span> <span class="ow">in</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">'TRANSLATIONS'</span><span class="p">][</span><span class="n">lang</span><span class="p">],</span>
  541. <a name="rest_code_c3b874e131b54f6e96535b5ef0c56564-8"></a> <span class="bp">self</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">'TAG_PATH'</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">slugify_name</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">lang</span><span class="p">)</span> <span class="o">+</span> <span class="s2">".xml"</span><span class="p">]</span> <span class="k">if</span>
  542. <a name="rest_code_c3b874e131b54f6e96535b5ef0c56564-9"></a> <span class="n">_f</span><span class="p">]</span>
  543. </pre></section><section id="template-hooks"><h2><a class="toc-backref" href="extending.html#toc-entry-16" role="doc-backlink">Template Hooks</a></h2>
  544. <p>Plugins can use a hook system for adding stuff into templates. In order to use
  545. it, a plugin must register itself. The following hooks currently exist:</p>
  546. <ul class="simple">
  547. <li><p><code class="docutils literal">extra_head</code> (not equal to the config option!)</p></li>
  548. <li><p><code class="docutils literal">body_end</code> (not equal to the config option!)</p></li>
  549. <li><p><code class="docutils literal">page_header</code></p></li>
  550. <li><p><code class="docutils literal">menu</code></p></li>
  551. <li><p><code class="docutils literal">menu_alt</code> (right-side menu in bootstrap, after <code class="docutils literal">menu</code> in base)</p></li>
  552. <li><p><code class="docutils literal">page_footer</code></p></li>
  553. </ul>
  554. <p>For example, in order to register a script into <code class="docutils literal">extra_head</code>:</p>
  555. <pre class="code python"><a name="rest_code_85abaedb49c6458da061ed02e63e3471-1"></a><span class="c1"># In set_site</span>
  556. <a name="rest_code_85abaedb49c6458da061ed02e63e3471-2"></a><span class="n">site</span><span class="o">.</span><span class="n">template_hooks</span><span class="p">[</span><span class="s1">'extra_head'</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">'&lt;script src="/assets/js/fancyplugin.js"&gt;'</span><span class="p">)</span>
  557. </pre>
  558. <p>There is also another API available. It allows use of dynamically generated
  559. HTML:</p>
  560. <pre class="code python"><a name="rest_code_3d80b5b30b83451486e9468e8cca60f5-1"></a><span class="c1"># In set_site</span>
  561. <a name="rest_code_3d80b5b30b83451486e9468e8cca60f5-2"></a><span class="k">def</span> <span class="nf">generate_html_bit</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">ftype</span><span class="o">=</span><span class="s1">'js'</span><span class="p">):</span>
  562. <a name="rest_code_3d80b5b30b83451486e9468e8cca60f5-3"></a> <span class="sd">"""Generate HTML for an asset."""</span>
  563. <a name="rest_code_3d80b5b30b83451486e9468e8cca60f5-4"></a> <span class="k">return</span> <span class="s1">'&lt;script src="/assets/</span><span class="si">{t}</span><span class="s1">/</span><span class="si">{n}</span><span class="s1">.</span><span class="si">{t}</span><span class="s1">"&gt;'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">n</span><span class="o">=</span><span class="n">name</span><span class="p">,</span> <span class="n">t</span><span class="o">=</span><span class="n">ftype</span><span class="p">)</span>
  564. <a name="rest_code_3d80b5b30b83451486e9468e8cca60f5-5"></a>
  565. <a name="rest_code_3d80b5b30b83451486e9468e8cca60f5-6"></a><span class="n">site</span><span class="o">.</span><span class="n">template_hooks</span><span class="p">[</span><span class="s1">'extra_head'</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">generate_html_bit</span><span class="p">,</span> <span class="kc">False</span><span class="p">,</span> <span class="s1">'fancyplugin'</span><span class="p">,</span> <span class="n">ftype</span><span class="o">=</span><span class="s1">'js'</span><span class="p">)</span>
  566. </pre>
  567. <p>The second argument to <code class="docutils literal">append()</code> is used to determine whether the function
  568. needs access to the current template context and the site. If it is set to
  569. <code class="docutils literal">True</code>, the function will also receive <code class="docutils literal">site</code> and <code class="docutils literal">context</code> keyword
  570. arguments. Example use:</p>
  571. <pre class="code python"><a name="rest_code_3b60727dbf4e432d81b289c0645bfb85-1"></a><span class="c1"># In set_site</span>
  572. <a name="rest_code_3b60727dbf4e432d81b289c0645bfb85-2"></a><span class="k">def</span> <span class="nf">greeting</span><span class="p">(</span><span class="n">addr</span><span class="p">,</span> <span class="n">endswith</span><span class="o">=</span><span class="s1">''</span><span class="p">,</span> <span class="n">site</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">context</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
  573. <a name="rest_code_3b60727dbf4e432d81b289c0645bfb85-3"></a> <span class="sd">"""Greet someone."""</span>
  574. <a name="rest_code_3b60727dbf4e432d81b289c0645bfb85-4"></a> <span class="k">if</span> <span class="n">context</span><span class="p">[</span><span class="s1">'lang'</span><span class="p">]</span> <span class="o">==</span> <span class="s1">'en'</span><span class="p">:</span>
  575. <a name="rest_code_3b60727dbf4e432d81b289c0645bfb85-5"></a> <span class="n">greet</span> <span class="o">=</span> <span class="sa">u</span><span class="s1">'Hello'</span>
  576. <a name="rest_code_3b60727dbf4e432d81b289c0645bfb85-6"></a> <span class="k">elif</span> <span class="n">context</span><span class="p">[</span><span class="s1">'lang'</span><span class="p">]</span> <span class="o">==</span> <span class="s1">'es'</span><span class="p">:</span>
  577. <a name="rest_code_3b60727dbf4e432d81b289c0645bfb85-7"></a> <span class="n">greet</span> <span class="o">=</span> <span class="sa">u</span><span class="s1">'¡Hola'</span>
  578. <a name="rest_code_3b60727dbf4e432d81b289c0645bfb85-8"></a>
  579. <a name="rest_code_3b60727dbf4e432d81b289c0645bfb85-9"></a> <span class="n">t</span> <span class="o">=</span> <span class="sa">u</span><span class="s1">' BLOG_TITLE = </span><span class="si">{0}</span><span class="s1">'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">site</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">'BLOG_TITLE'</span><span class="p">](</span><span class="n">context</span><span class="p">[</span><span class="s1">'lang'</span><span class="p">]))</span>
  580. <a name="rest_code_3b60727dbf4e432d81b289c0645bfb85-10"></a>
  581. <a name="rest_code_3b60727dbf4e432d81b289c0645bfb85-11"></a> <span class="k">return</span> <span class="sa">u</span><span class="s1">'&lt;h3&gt;</span><span class="si">{greet}</span><span class="s1"> </span><span class="si">{addr}{endswith}</span><span class="s1">&lt;/h3&gt;'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">greet</span><span class="o">=</span><span class="n">greet</span><span class="p">,</span> <span class="n">addr</span><span class="o">=</span><span class="n">addr</span><span class="p">,</span>
  582. <a name="rest_code_3b60727dbf4e432d81b289c0645bfb85-12"></a> <span class="n">endswith</span><span class="o">=</span><span class="n">endswith</span><span class="p">)</span> <span class="o">+</span> <span class="n">t</span>
  583. <a name="rest_code_3b60727dbf4e432d81b289c0645bfb85-13"></a>
  584. <a name="rest_code_3b60727dbf4e432d81b289c0645bfb85-14"></a><span class="n">site</span><span class="o">.</span><span class="n">template_hooks</span><span class="p">[</span><span class="s1">'page_header'</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">greeting</span><span class="p">,</span> <span class="kc">True</span><span class="p">,</span> <span class="sa">u</span><span class="s1">'Nikola Tesla'</span><span class="p">,</span> <span class="n">endswith</span><span class="o">=</span><span class="sa">u</span><span class="s1">'!'</span><span class="p">)</span>
  585. </pre>
  586. <p>Dependencies for template hooks:</p>
  587. <ul class="simple">
  588. <li><p>if the input is a string, the string value, alongside arguments to <code class="docutils literal">append</code>, is used for calculating dependencies</p></li>
  589. <li><p>if the input is a callable, it attempts <code class="docutils literal">input.template_registry_identifier</code>, then <code class="docutils literal">input.__doc__</code>, and if neither is available, it uses a static string.</p></li>
  590. </ul>
  591. <p>Make sure to provide at least a docstring, or a identifier, to ensure rebuilds work properly.</p>
  592. </section><section id="shortcodes"><h2><a class="toc-backref" href="extending.html#toc-entry-17" role="doc-backlink">Shortcodes</a></h2>
  593. <p>Some (hopefully all) markup compilers support shortcodes in these forms:</p>
  594. <pre class="code text"><a name="rest_code_81c68590ecd6426193834bc742049523-1"></a>{{% foo %}} # No arguments
  595. <a name="rest_code_81c68590ecd6426193834bc742049523-2"></a>{{% foo bar %}} # One argument, containing "bar"
  596. <a name="rest_code_81c68590ecd6426193834bc742049523-3"></a>{{% foo bar baz=bat %}} # Two arguments, one containing "bar", one called "baz" containing "bat"
  597. <a name="rest_code_81c68590ecd6426193834bc742049523-4"></a>
  598. <a name="rest_code_81c68590ecd6426193834bc742049523-5"></a>{{% foo %}}Some text{{% /foo %}} # one argument called "data" containing "Some text"
  599. </pre>
  600. <p>So, if you are creating a plugin that generates markup, it may be a good idea
  601. to register it as a shortcode in addition of to restructured text directive or
  602. markdown extension, thus making it available to all markup formats.</p>
  603. <p>To implement your own shortcodes from a plugin, you can create a plugin inheriting <code class="docutils literal">ShortcodePlugin</code>.
  604. By default, the <code class="docutils literal">set_site</code> method will register the <code class="docutils literal">handler</code> method as a
  605. shortcode with the plugin’s <code class="docutils literal">name</code> as the shortcode name. To have other
  606. shortcode names, you can call
  607. <code class="docutils literal">Nikola.register_shortcode(name, func)</code> with the following arguments:</p>
  608. <dl class="simple">
  609. <dt>
  610. <code class="docutils literal">name</code>:</dt>
  611. <dd>
  612. <p>Name of the shortcode ("foo" in the examples above)</p>
  613. </dd>
  614. <dt>
  615. <code class="docutils literal">func</code>:</dt>
  616. <dd>
  617. <p>A function that will handle the shortcode</p>
  618. </dd>
  619. </dl>
  620. <p>The shortcode handler <strong>must</strong> return a two-element tuple, <code class="docutils literal">(output, dependencies)</code></p>
  621. <dl class="simple">
  622. <dt>
  623. <code class="docutils literal">output</code>:</dt>
  624. <dd>
  625. <p>The text that will replace the shortcode in the document.</p>
  626. </dd>
  627. <dt>
  628. <code class="docutils literal">dependencies</code>:</dt>
  629. <dd>
  630. <p>A list of all the files on disk which will make the output be considered
  631. out of date. For example, if the shortcode uses a template, it should be
  632. the path to the template file.</p>
  633. </dd>
  634. </dl>
  635. <p>The shortcode handler <strong>must</strong> accept the following named arguments (or
  636. variable keyword arguments):</p>
  637. <dl class="simple">
  638. <dt>
  639. <code class="docutils literal">site</code>:</dt>
  640. <dd>
  641. <p>An instance of the Nikola class, to access site state</p>
  642. </dd>
  643. <dt>
  644. <code class="docutils literal">data</code>:</dt>
  645. <dd>
  646. <p>If the shortcut is used as opening/closing tags, it will be the text
  647. between them, otherwise <code class="docutils literal">None</code>.</p>
  648. </dd>
  649. <dt>
  650. <code class="docutils literal">lang</code>:</dt>
  651. <dd>
  652. <p>The current language.</p>
  653. </dd>
  654. </dl>
  655. <p>If the shortcode tag has arguments of the form <code class="docutils literal">foo=bar</code> they will be
  656. passed as named arguments. Everything else will be passed as positional
  657. arguments in the function call.</p>
  658. <p>So, for example:</p>
  659. <pre class="literal-block">{{% foo bar baz=bat beep %}}Some text{{% /foo %}}</pre>
  660. <p>Assuming you registered <code class="docutils literal">foo_handler</code> as the handler function for the
  661. shortcode named <code class="docutils literal">foo</code>, this will result in the following call when the above
  662. shortcode is encountered:</p>
  663. <pre class="literal-block">foo_handler("bar", "beep", baz="bat", data="Some text", site=whatever)</pre>
  664. <section id="template-based-shortcodes"><h3><a class="toc-backref" href="extending.html#toc-entry-18" role="doc-backlink">Template-based Shortcodes</a></h3>
  665. <p>Another way to define a new shortcode is to add a template file to the
  666. <code class="docutils literal">shortcodes</code> directory of your site. The template file must have the
  667. shortcode name as the basename and the extension <code class="docutils literal">.tmpl</code>. For example, if you
  668. want to add a new shortcode named <code class="docutils literal">foo</code>, create the template file as
  669. <code class="docutils literal">shortcodes/foo.tmpl</code>.</p>
  670. <p>When the shortcode is encountered, the matching template will be rendered with
  671. its context provided by the arguments given in the shortcode. Keyword arguments
  672. are passed directly, i.e. the key becomes the variable name in the template
  673. namespace with a matching string value. Non-keyword arguments are passed as
  674. string values in a tuple named <code class="docutils literal">_args</code>. As for normal shortcodes with a
  675. handler function, <code class="docutils literal">site</code> and <code class="docutils literal">data</code> will be added to the keyword arguments.</p>
  676. <p>Example:</p>
  677. <p>The following shortcode:</p>
  678. <pre class="code text"><a name="rest_code_78887cdd58254883b05f3fd58cf55913-1"></a>{{% foo bar="baz" spam %}}
  679. </pre>
  680. <p>With a template in <code class="docutils literal">shortcodes/foo.tmpl</code> with this content (using Jinja2
  681. syntax in this example)</p>
  682. <pre class="code jinja"><a name="rest_code_fb1d3a1ec39d459a889fc8c7fcc88c32-1"></a><span class="x">&lt;div class="</span><span class="cp">{{</span> <span class="nv">_args</span><span class="o">[</span><span class="m">0</span><span class="o">]</span> <span class="k">if</span> <span class="nv">_args</span> <span class="k">else</span> <span class="s1">'ham'</span> <span class="cp">}}</span><span class="x">"&gt;</span><span class="cp">{{</span> <span class="nv">bar</span> <span class="cp">}}</span><span class="x">&lt;/div&gt;</span>
  683. </pre>
  684. <p>Will result in this output</p>
  685. <pre class="code html"><a name="rest_code_13ea22a2fa9842d6af6fed3495660b25-1"></a><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"spam"</span><span class="p">&gt;</span>baz<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
  686. </pre></section></section><section id="state-and-cache"><h2><a class="toc-backref" href="extending.html#toc-entry-19" role="doc-backlink">State and Cache</a></h2>
  687. <p>Sometimes your plugins will need to cache things to speed up further actions. Here are the conventions for that:</p>
  688. <ul class="simple">
  689. <li><p>If it's a file, put it somewhere in <code class="docutils literal"><span class="pre">self.site.config['CACHE_FOLDER']</span></code> (defaults to <code class="docutils literal">cache/</code>.</p></li>
  690. <li><p>If it's a value, use <code class="docutils literal">self.site.cache.set(key, value)</code> to set it and <code class="docutils literal">self.site.cache.get(key)</code> to get it.
  691. The key should be a string, the value should be json-encodable (so, be careful with datetime objects)</p></li>
  692. </ul>
  693. <p>The values and files you store there can <strong>and will</strong> be deleted sometimes by the user. They should always be
  694. things you can reconstruct without lossage. They are throwaways.</p>
  695. <p>On the other hand, sometimes you want to save something that is <strong>not</strong> a throwaway. These are things that may
  696. change the output, so the user should not delete them. We call that <strong>state</strong>. To save state:</p>
  697. <ul class="simple">
  698. <li><p>If it's a file, put it somewhere in the working directory. Try not to do that please.</p></li>
  699. <li><p>If it's a value, use <code class="docutils literal">self.site.state.set(key, value)</code> to set it and <code class="docutils literal">self.state.cache.get(key)</code> to get it.
  700. The key should be a string, the value should be json-encodable (so, be careful with datetime objects)</p></li>
  701. </ul>
  702. <p>The <code class="docutils literal">cache</code> and <code class="docutils literal">state</code> objects are rather simplistic, and that's intentional. They have no default values: if
  703. the key is not there, you will get <code class="docutils literal">None</code> and like it. They are meant to be both threadsafe, but hey, who can
  704. guarantee that sort of thing?</p>
  705. <p>There are no sections, and no access protection, so let's not use it to store passwords and such. Use responsibly.</p>
  706. </section><section id="logging"><h2><a class="toc-backref" href="extending.html#toc-entry-20" role="doc-backlink">Logging</a></h2>
  707. <p>Plugins often need to produce messages to the screen. All plugins get a logger object (<code class="docutils literal">self.logger</code>) by default,
  708. configured to work with Nikola (logging level, colorful output, plugin name as the logger name). If you need, you can
  709. also use the global (<code class="docutils literal">nikola.utils.LOGGER</code>) logger, or you can instantiate custom loggers with
  710. <code class="docutils literal">nikola.utils.get_logger</code> or the <code class="docutils literal">nikola.log</code> module.</p>
  711. </section><section id="template-and-dependency-injection"><h2><a class="toc-backref" href="extending.html#toc-entry-21" role="doc-backlink">Template and Dependency Injection</a></h2>
  712. <p>Plugins have access to two injection facilities.</p>
  713. <p>If your plugin needs custom templates for its features (adding pages, displaying stuff, etc.), you can put them in the
  714. <code class="docutils literal">templates/mako</code> and <code class="docutils literal">templates/jinja</code> subfolders in your plugin’s folder. Note that those templates have a very low
  715. priority, so that users can override your plugin’s templates with their own.</p>
  716. <p>If your plugin needs to inject dependencies, the <code class="docutils literal">inject_dependency(target, dependency)</code> function can be used to add a
  717. <code class="docutils literal">dependency</code> for tasks which basename == <code class="docutils literal">target</code>. This facility should be limited to cases which really need it,
  718. consider other facilities first (eg. adding post dependencies).</p>
  719. </section>
  720. </div>
  721. </article>
  722. </div>
  723. <div class="col-sm-3 col-sm-offset-1 blog-sidebar">
  724. <div class="sidebar-module sidebar-module-inset">
  725. <h4>About</h4>
  726. <div id="shoutcastdiv">
  727. <script type="text/javascript">
  728. refreshdiv();
  729. </script>
  730. </div>
  731. </div>
  732. <div class="sidebar-module">
  733. <h4>Links</h4>
  734. <ol class="list-unstyled">
  735. <li><a href="http://getbootstrap.com/examples/blog/">Bootstrap Blog Theme</a></li>
  736. <li><a href="https://getnikola.com/">Nikola</a></li>
  737. <li><a href="https://twitter.com/mdo">@mdo</a></li>
  738. <li><a href="https://twitter.com/Kwpolska">@Kwpolska</a></li>
  739. <li><a href="https://twitter.com/GetNikola">@GetNikola</a></li>
  740. </ol>
  741. </div>
  742. </div>
  743. <!--End of body content-->
  744. </div>
  745. </div>
  746. </div>
  747. <footer class="blog-footer" id="footer">
  748. Contents © 2023 <a href="mailto:contact@riff-radio.org">Riff</a> - Powered by <a href="https://getnikola.com" rel="nofollow">Nikola</a>
  749. </footer><script src="../assets/js/all-nocdn.js"></script><!-- fancy dates --><script>
  750. moment.locale("en");
  751. fancydates(0, "YYYY-MM-DD HH:mm");
  752. </script><!-- end fancy dates --><script>
  753. baguetteBox.run('div#content', {
  754. ignoreClass: 'islink',
  755. captions: function(element) {
  756. return element.getElementsByTagName('img')[0].alt;
  757. }});
  758. </script><script type="text/javascript" src="../refresh.js"></script>
  759. </body>
  760. </html>