#+title: Ox-Hugo Manual #+author: Kaushal Modi #+hugo_base_dir: . #+hugo_section: doc #+options: creator:t author:nil #+setupfile: doc-setupfile.org #+macro: imageclick [[file:./static/images/$1][file:/images/$1]] #+bibliography: ../test/site/content-org/cite/bib/orgcite.bib * Homepage :PROPERTIES: :EXPORT_TITLE: Org to Markdown for Hugo :EXPORT_FILE_NAME: _index :EXPORT_HUGO_TYPE: homepage :EXPORT_HUGO_SECTION: / :EXPORT_HUGO_MENU: :menu "1.main" :title "Homepage" :CUSTOM_ID: main :END: #+include: "./ox-hugo-manual.org::#introduction" :only-contents t #+begin_note See the [[https://ox-hugo.scripter.co/doc/examples/][Real World Examples]] section to quickly jump to sites generated using =ox-hugo= and their Org sources. #+end_note ** Screenshots #+include: "./ox-hugo-manual.org::#screenshots_intro" :only-contents t #+include: "./ox-hugo-manual.org::#screenshots" :only-contents t #+include: "./ox-hugo-manual.org::#demo" :minlevel 2 ** Installation #+include: "./ox-hugo-manual.org::#installation" :only-contents t ** Usage #+include: "./ox-hugo-manual.org::#usage" :only-contents t ** Thanks #+include: "./ox-hugo-manual.org::#thanks" :only-contents t - This site is powered by [[https://www.netlify.com][Netlify]]. ** Future Plans :noexport: There is a plan to create a =hugo.el= that would do things like: - New post creation using =org-capture= (port code from [[https://github.com/kaushalmodi/.emacs.d/blob/master/setup-files/setup-hugo.el][here]]). - Interactive functions to toggle /draft/ state, add/remove/increment/decrement /publishdate/ property. - Option to use template =config.toml= and some default hugo theme. So all a new user would need to do is to (i) have the =hugo= [[https://github.com/gohugoio/hugo/releases][binary]] in =PATH= (ii) define their =hugo= blog dir in the =defcustom= (iii) =M-x hugo=. - Set separate faces for titles based on /draft/ state and /futureness/. * Test Site :PROPERTIES: :EXPORT_HUGO_SECTION: / :EXPORT_HUGO_BUNDLE: test :EXPORT_FILE_NAME: _index :EXPORT_HUGO_MENU: :menu "1.main" :pre "" :post " ↗" :END: # Generate an empty _index.md in test/ for that subdirectory to get # generated. * Issues/Requests :PROPERTIES: :EXPORT_HUGO_SECTION: / :EXPORT_HUGO_BUNDLE: issues :EXPORT_FILE_NAME: _index :EXPORT_HUGO_MENU: :menu "1.main" :post " ↗" :END: * Changelog :PROPERTIES: :EXPORT_FILE_NAME: changelog :EXPORT_HUGO_MENU: :menu "1.main" :END: #+include: "../CHANGELOG.org::*Changelog" :only-contents t * Reused Sections ** Introduction :PROPERTIES: :CUSTOM_ID: introduction :END: =ox-hugo= is an Org exporter backend that exports Org to [[https://gohugo.io/][Hugo]]-compatible Markdown ([[https://github.com/russross/blackfriday][Blackfriday]]) and also generates the front-matter (in TOML or YAML format). The =ox-hugo= backend extends from a /parent/ backend =ox-blackfriday.el=. The latter is the one that primarily does the Blackfriday-friendly Markdown content generation. The main job of =ox-hugo= is to generate the front-matter for each exported content file, and then append that generated Markdown to it. There are, though, few functions that =ox-hugo.el= overrides over those by =ox-blackfriday.el=. ** Installation :PROPERTIES: :CUSTOM_ID: installation :END: This package requires at least GNU Emacs {{{min_emacs_version}}} and Org Mode {{{min_org_version}}}. It is available on Melpa ([[https://melpa.org/#/ox-hugo]]), and it's recommended to install this package from [[https://melpa.org/#/getting-started][Melpa]] (​_not_ Melpa /Stable/). You will need to /require/ the package after installing it to get the =ox-hugo= export options in the /Org Export Dispatcher/ menu (the one you see when you hit =C-c C-e= to initiate any export). You can do that by adding the below to your config: #+begin_src emacs-lisp (with-eval-after-load 'ox (require 'ox-hugo)) #+end_src *** Use Package If you use [[https://github.com/jwiegley/use-package][=use-package=]], you can do the below instead: #+begin_src emacs-lisp (use-package ox-hugo :ensure t ;Auto-install the package from Melpa :pin melpa ;`package-archives' should already have ("melpa" . "https://melpa.org/packages/") :after ox) #+end_src *** Spacemacs Spacemacs users can use =ox-hugo= by setting the variable =org-enable-hugo-support=. #+begin_src emacs-lisp (setq-default dotspacemacs-configuration-layers '((org :variables org-enable-hugo-support t))) #+end_src /This was verified to work on Spacemacs =develop= branch ([[https://github.com/kaushalmodi/ox-hugo/pull/440][ref]])./ ** Usage :PROPERTIES: :CUSTOM_ID: usage :END: #+begin_note Jump to the {{{doc(quick-start,,Quick Start)}}} section to quickly try out ~ox-hugo~ with Hugo. #+end_note *** Before you export :PROPERTIES: :CUSTOM_ID: before-you-export :END: Before you export check that these properties are set as you need: - HUGO_BASE_DIR :: Root directory of the source for the Hugo site. If this is set to =~/hugo/=, the exported Markdown files will be saved to =~/hugo/content//= directory[fn:section_more]. By default, the Markdown files reside in a hierarchy under the =content/= directory in the site root directory ([[https://gohugo.io/content-management/organization/][ref]]). If you try to export without setting this property, you will get this error: #+begin_example user-error: It is mandatory to set the HUGO_BASE_DIR property or the `org-hugo-base-dir' local variable #+end_example This property can be set by one of two ways: 1. Setting the ~#+hugo_base_dir:~ keyword in the Org file. 2. Setting the ~org-hugo-base-dir~ variable in a ~.dir-locals.el~ or File Local Variables. - HUGO_SECTION :: The default Hugo section name for all the posts. See [[https://gohugo.io/content-management/sections/][here]] for more information on Hugo sections. It is common for this property to be set to =posts= or =blog=. The default value is set using =org-hugo-default-section-directory=. See {{{doc(hugo-section,,Hugo Section)}}} for details. *Important*: If you choose to export an Org subtree as a post, you need to set the =EXPORT_FILE_NAME= subtree property. That property is used by this package to figure out where the current post starts. For that reason, *a subtree with =EXPORT_FILE_NAME= property cannot nest another subtree with that property*. If you can analogize with the [[https://en.wikipedia.org/wiki/Tree_(data_structure)][branch/leaf data structure terminlogy]], then the subtrees with =EXPORT_FILE_NAME= property need to be /leaf nodes/. [fn:section_more] The ~HUGO_SECTION~ is the bare-minimum requirement to specify the destination path. That path can be further tweaked using ~HUGO_BUNDLE~ key (and the associated ~EXPORT_HUGO_BUNDLE~ property), and the ~EXPORT_HUGO_SECTION_FRAG~ property (only for /per-subtree/ exports). *** Export bindings The common =ox-hugo= export bindings are: **** For both one-post-per-subtree and one-post-per-file flows - =C-c C-e H H= :: Export "What I Mean". This is same as calling the ~org-hugo-export-wim-to-md~ function interactively or via ~(org-hugo-export-wim-to-md)~ in Emacs Lisp. - If point is in a /valid Hugo post subtree/, export that subtree to a Hugo post in Markdown. A /valid Hugo post subtree/ is an Org subtree that has the =EXPORT_FILE_NAME= property set. *Note that a subtree with =EXPORT_FILE_NAME= property cannot nest a subtree with the same property set.* If you can analogize with the [[https://en.wikipedia.org/wiki/Tree_(data_structure)][branch/leaf data structure terminlogy]], then the subtrees with =EXPORT_FILE_NAME= property need to be /leaf nodes/. - If the file is intended to be exported as a whole (i.e. has the =#+title= keyword), export the whole Org file to a Hugo post in Markdown. - =C-c C-e H A= :: Export *all* "What I Mean". This is same as executing ~(org-hugo-export-wim-to-md :all-subtrees)~ in Emacs Lisp. - If the Org file has one or more 'valid Hugo post subtrees', export them to Hugo posts in Markdown. - If the file is intended to be exported as a whole (i.e. no 'valid Hugo post subtrees' at all, and has the =#+title= keyword), export the whole Org file to a Hugo post in Markdown. **** For only the one-post-per-file flow - =C-c C-e H h= :: Export the Org file to a Hugo post in Markdown. This is same as calling the ~org-hugo-export-to-md~ function interactively. /Also see the {{{doc(auto-export-on-saving,,Auto Exporting)}}} section./ *** Customization Options Do =M-x customize-group=, and select =org-export-hugo= to see the available customization options for this package. ** Screenshots Intro :PROPERTIES: :CUSTOM_ID: screenshots_intro :END: Before you read further, you can see below how =ox-hugo= translates Org to Markdown (Org on the left; exported Markdown with Hugo front-matter on the right). ** Screenshots :PROPERTIES: :CUSTOM_ID: screenshots :END: *** One post per Org subtree (preferred) :PROPERTIES: :CUSTOM_ID: screenshot-one-post-per-subtree :END: {{{imageclick(one-post-per-subtree.png)}}} - Files in above screenshot :: [[https://raw.githubusercontent.com/kaushalmodi/ox-hugo/main/test/site/content-org/screenshot-subtree-export-example.org][Org]] -> [[https://raw.githubusercontent.com/kaushalmodi/ox-hugo/main/test/site/content/writing-hugo-blog-in-org-subtree-export.md][Markdown]] *** One post per Org file :PROPERTIES: :CUSTOM_ID: screenshot-one-post-per-file :END: {{{imageclick(one-post-per-file.png)}}} - Files in above screenshot :: [[https://raw.githubusercontent.com/kaushalmodi/ox-hugo/main/test/site/content-org/writing-hugo-blog-in-org-file-export.org][Org]] -> [[https://raw.githubusercontent.com/kaushalmodi/ox-hugo/main/test/site/content/writing-hugo-blog-in-org-file-export.md][Markdown]] *** Editorial :PROPERTIES: :CUSTOM_ID: org-blogging-flow-editorial :END: The preferred way to organize the posts is as Org subtrees (also the main reason to write this package, as nothing like that was out there) as it makes the meta-data management for Hugo front-matter pretty effortless. If you are a /one Org-file per post/ type of a person, that flow works too! Just note that in this flow many of those =#+hugo_= properties need to be managed manually.. just as one would manage the front-matter in Markdown files --- See the Org versions in the above screenshots for comparison. ** Demo :PROPERTIES: :CUSTOM_ID: demo :END: [[https://github.com/kaushalmodi/ox-hugo/tree/main/test/site/content-org][Org source]] → [[https://github.com/kaushalmodi/ox-hugo/tree/main/test/site/content][=ox-hugo= Exported Markdown]] → [[https://ox-hugo.scripter.co/test/]] The test site uses a [[https://github.com/kaushalmodi/hugo-bare-min-theme][minimal]] theme written just for debug purposes (not extra aesthetics). The test site is designed to verify if all the content translates from Org to Markdown as expected. /See [[https://themes.gohugo.io/][Hugo Themes]] for examples of really good site prettification and presentation styles./ ** Note to Future Contributors :PROPERTIES: :CUSTOM_ID: note-to-future-contributors :EXPORT_FILE_NAME: contributing-guide :END: NOTE TO FUTURE CONTRIBUTORS: I plan to merge this package into GNU Elpa or Org source at some point. So you will need to assign your copyright to FSF in order to get your patches accepted. - [[https://www.gnu.org/licenses/why-assign.html][Why assign copyright to FSF?]] - [[https://www.gnu.org/prep/maintain/html_node/Copyright-Papers.html#Copyright-Papers][How to start this process]] As a bonus, once you have assigned your copyright to FSF, doors open up for your future contributions to Emacs too! *** Contribute to documentation *See {{{doc(requirements,#doc_contributor_reqs,Requirements for doc contributor)}}}.* 1. Clone this repo. 2. Add/edit documentation to =doc/ox-hugo-manual.org=. 3. Run =make doc=. - This generates the Markdown files for the =ox-hugo= documentation site and the .org files like =README.org= and =CONTRIBUTING.org= for GitHub. 4. Review the changes in the generated .org and .md files. 5. Commit *only the .org files*, push branch and create PR. - The =.org= → =.md= conversion is done by =ox-hugo= on Netlify. *** Contribute to code *See {{{doc(requirements,#code_contributor_reqs,Requirements for code contributor)}}}.* 1. Clone this repo. 2. Add/edit the .el files, *tests* in =test/site/content-org/=, and *documentation* to =doc/ox-hugo-manual.org=. 3. Run =make md doc=. 4. Review the changes in the generated .org and .md files. - Ignore the changes shown in =git diff= related to *only* the randomly generated Org ID's (like =org17de7a9=). 5. Commit (*don't push your branch yet!*). - As mentioned above, commit *only the .org files* for documentation. 6. Run test: =make -j1 test= (you *need* to =git commit= i.e. do the above step before this step). 7. Fix your commit(s) if the test fails.. repeat till you succeed. 8. Push your feature branch and create PR. ** Debug :PROPERTIES: :CUSTOM_ID: debug :END: If the =ox-hugo= exports do not work as expected, or if you get an error backtrace, 1. Open an [[https://github.com/kaushalmodi/ox-hugo/issues][Issue]]. 2. Describe the problem you are seeing. 3. Provide the debug info: - Do =M-x org-hugo-debug-info=, *That will copy the debug info in Markdown format to the kill ring.* So do *not* manually do any other kill (copy/cut) operation after that! - Paste the Markdown contents in the GitHub issue. - You can still hit the /Preview/ tab of the Issue before submitting it. ** Test :PROPERTIES: :CUSTOM_ID: test :END: ~ox-hugo~ is tested using two kinds of test suites: 1. Export all the test Org files (includes file-based and subtree-based export tests) to Markdown and /diff/ the exported Markdown against the committed reference versions. 2. Run ~ert~ based tests. Steps to run tests on your machine: 1. Clone this repo. 2. Ensure that ~pandoc~ (at least version {{{pandoc_version}}}) is installed (more info {{{doc(contributing-guide,#contribute-to-code,here)}}}). 3. Run ~make -j1 test~. This runs all the tests from the two kinds of test suites described above. *** ~ert~ tests - To run all ~ert~ based tests, run ~make ert~. - To run only the ~ert~ tests matching a string ~foo~, run ~make ert TEST_MATCH=foo~. ** Thanks :PROPERTIES: :CUSTOM_ID: thanks :END: - Matt Price ([[https://github.com/titaniumbones][@titaniumbones]]) - Puneeth Chaganti ([[https://github.com/punchagan][@punchagan]]) - Also thanks to ~http://whyarethingsthewaytheyare.com/setting-up-the-blog/~ (/not hyperlinking the link as it is insecure --- not https/), ~http://www.holgerschurig.de/en/emacs-blog-from-org-to-hugo/~ (/not hyperlinking the link as it is insecure --- not https/) and the [[https://github.com/chaseadamsio/goorgeous][=goorgeous=]] project by Chase Adams ([[https://github.com/chaseadamsio][@chaseadamsio]]) for inspiration to start this project. * Menus ** Early Questions :PROPERTIES: :EXPORT_HUGO_MENU: :menu "2.early_questions" :END: *** Why =ox-hugo=? :PROPERTIES: :EXPORT_FILE_NAME: why-ox-hugo :END: #+begin_verse > A picture is worth a thousand words. #+end_verse So let me show you this screenshot that took on my phone (running Emacs in Termux app on Android), showing the single Org file that serves as a source of this whole documentation site. {{{imageclick(ox-hugo-doc-source-viewing-in-Termux-Android.png)}}} ----- Using Org just as a markup like Markdown is a miniscule part of its complete feature-set. Org also allows stuff like: - Easy ordering/manipulation/commenting of subtrees - Creating tables (with even formulas like in Excel) - Directly including source code snippets from external files (instead of having to copy/paste them in) - Running code snippets within the Org file and embedding the results (Org Babel) - .. Using Org for content writing allows using built-in Org features to translate to Hugo front-matter: - Org uses an outline structure and can inherit meta data (tags and properties) from one subtree to children subtrees. - Using that feature, one can tag one tree as /emacs/, and everything under that tree (all posts under that) will get that tag automatically. - The same concept applies to inheriting any Org /property/ meta data like menu entry, category, section name, etc. - A subtree can be quickly marked to be in TODO state (default binding =C-c C-t=). A *TODO* post is marked as a /draft/ Hugo post. - The /menu-item weights/, /page weights/ and /taxonomy weights/ can be set to be auto-calculated so that the menu items or post order in the final HTML appear in the same order as the respective subtrees in Org. If the subtrees are re-ordered in Org, the weights get changed too. - One can have a subtree with section property set to "posts" and all post subtrees under that will go to that section. Similarly another parent subtree can have that property set to "articles", and so on. - Images can be displayed inline in the Org buffer. - After save hooks can be set up in Emacs so that each time I save the file, only the current subtree in Org gets exported to Markdown. With the Hugo server running with the =--navigateToChanged= switch (this allows auto-changing the preview to the last changed post), the flow is seamless -- Save the Org file and see the exact changed post in browser. - *All* posts can simply be subtrees in a single Org file. That way one can take advantage of Org subtree filtering and searching functions (=org-sparse-tree= bound to =C-c /= by default). - (and much more..) *** Do I need to re-write my whole blog in Org? :PROPERTIES: :EXPORT_FILE_NAME: do-I-need-to-re-write-my-whole-blog-in-org :EXPORT_HUGO_MENU_OVERRIDE: :title "Need to re-write my blog?" :END: If you are considering to try out =ox-hugo=, and if you have already been using Hugo, it is normal for this thought to cross your mind: #+begin_quote I already have dozens or hundreds of posts written in Markdown. Do I need to convert them to Org if I want to start using =ox-hugo=? #+end_quote The answer is *No*. This package will export your future posts written in Org to Markdown. And those files will live along with your already written Markdown posts. So converting existing Markdown files to Org would be purely the user's choice, your choice -- but that's by no means a necessity if you want to start using =ox-hugo=. .. And if at some point, you want to stop using =ox-hugo=, you still have the exported Markdown files. *** Deprecation Notices :PROPERTIES: :EXPORT_FILE_NAME: deprecation-notices :END: **** ~EXPORT_HUGO_SECTION*~ property is now ~EXPORT_HUGO_SECTION_FRAG~ -- <2022-04-07 Thu> :PROPERTIES: :CUSTOM_ID: export-hugo-section-frag :END: ***** Reason for this change The earlier ~EXPORT_HUGO_SECTION*~ property name was not a canonical Org property name because it had an \ast{} in its name. It came to light in {{{issue(615)}}} that an Org built-in feature [[info:org#Column View][Org Column]] was unable to filter/edit that property. Once that property was renamed to an asterisk-less name: ~EXPORT_HUGO_SECTION_FRAG~, Org Column started working (see the screenshot in {{{pr(616)}}}). ***** Changes needed in user Org files Replace "EXPORT_HUGO_SECTION*" with "*EXPORT_HUGO_SECTION_FRAG*" in all Org files. **** Org Hugo Auto Export feature now a /minor mode/ -- <2019-01-03 Thu> ***** Changes needed in user config 1. Do *not* require ~ox-hugo-auto-export~ any more! - For now, you will get a warning each time you do that /require/. But in few weeks, the old ~ox-hugo-auto-export.el~ file will be deleted from this project, and then doing that /require/ will throw an error. #+begin_note The ~ox-hugo-auto-export.el~ has been deleted from this project. So doing that /require/ will throw an error now. -- <2019-04-15 Mon> #+end_note 2. Make these changes in your ~.dir-locals.el~ or File Local Variables as applicable: |---------------------+----------------------------------------+-------------------------------------------| | Auto-export on save | Earlier | Now | |---------------------+----------------------------------------+-------------------------------------------| | *Enable* | ~(org-hugo-auto-export-on-save . t)~ | ~(eval . (org-hugo-auto-export-mode))~ | | *Disable* | ~(org-hugo-auto-export-on-save . nil)~ | ~(eval . (org-hugo-auto-export-mode -1))~ | |---------------------+----------------------------------------+-------------------------------------------| ***** Summary ~org-hugo-auto-export-mode~ is a new minor mode that now ships with ~ox-hugo~. So the user doesn't need to do anything special to install it --- it simply autoloads. As a bonus, now ~M-x org-hugo-auto-export-mode~ can be used to toggle the auto-exporting on and off in an Org buffer. For history behind this change, see {{{issue(247)}}}. \\ --- /*tl;dr*: doing the Right thing/ ** Getting Started :PROPERTIES: :EXPORT_HUGO_MENU: :menu "3.getting_started" :END: *** Quick Start :PROPERTIES: :EXPORT_FILE_NAME: quick-start :EXPORT_HUGO_MENU: :menu "3.getting_started" :pre "" :post "" :EXPORT_HUGO_USE_CODE_FOR_KBD: t :END: #+begin_description Quick start steps from downloading ~hugo~ to writing posts in Org mode in Emacs. #+end_description 1. Once you have [[https://gohugo.io/getting-started/quick-start/#step-1-install-hugo][installed =hugo=​]], or downloaded a binary of [[https://github.com/gohugoio/hugo/releases][its latest release (tested as of v0.91.2)]], type this to check that you have the =hugo= executable available: #+caption: Check that =hugo= is available #+name: code__hugo_version #+begin_src shell hugo version #+end_src #+begin_note Hugo version used when writing this post: #+begin_quote hugo v0.91.2-1798BD3F linux/amd64 BuildDate=2021-12-23T15:33:34Z VendorInfo=gohugoio #+end_quote #+end_note 2. =cd= to the directory in which you want to create your <<>>, and run: #+caption: Create =quickstart= hugo site directory #+name: code__hugo_new_site #+begin_src shell hugo new site quickstart cd quickstart #+end_src In this directory, you will find a =config.toml= which is referred to as the "<<>>" file in Hugo docs and the documentation you find on this site. 3. Follow {{{titleref(Installation,)}}} page to ensure that =ox-hugo= is installed and available in your Emacs session. 4. Pick any theme. Here we will arbitrarily pick one of the popular themes: [[https://github.com/adityatelange/hugo-PaperMod][PaperMod]]. - :sparkles: Using [[https://gohugo.io/hugo-modules/use-modules/][Hugo Modules]] :sparkles: :: This method is preferred, but requires the user to have ~go~ (at least version 1.12) installed. [[https://go.dev/doc/install][~go~ download link]]. Make your Hugo site a Hugo Module (one time thing): #+begin_src shell hugo mod init # example: hugo mod init github.com/user/reponame #+end_src Add this to your site config: #+begin_src conf-toml [module] [[module.imports]] path = "github.com/adityatelange/hugo-PaperMod" #+end_src And then run this in the terminal: #+begin_src shell hugo mod get -u #+end_src - Using ~git clone~ approach :: Clone the theme repo inside a ~themes/~ directory in your site dir. #+begin_src shell git clone https://github.com/adityatelange/hugo-PaperMod themes/PaperMod --depth=1 #+end_src Add this to your site config: #+begin_src conf-toml theme = "PaperMod" #+end_src 5. Append these lines to the site config: #+begin_src conf-toml [markup.goldmark.renderer] unsafe = true #+end_src See the page on {{{titleref(Goldmark,)}}} for some more info on the =unsafe = true= setting. 6. Create a separate directory for Org content in the Hugo site base directory -- let's call it =content-org=.<> #+begin_src shell # In Hugo site directory mkdir content-org #+end_src 7. Start the Hugo server in the Hugo site directory: #+begin_example hugo server --buildDrafts --navigateToChanged #+end_example You will see a message like: #+begin_quote Web Server is available at http://localhost:1313/ #+end_quote Navigate to that address in your browser. 8. Now, back in Emacs, with =ox-hugo= loaded, create a file called =all-posts.org= inside the =content-org/= created [[content-org-created][above]]. 9. Paste this in that file #+caption: Basic post in Org #+name: code__basic_post_in_org #+begin_src org ,#+hugo_base_dir: ../ ,* My first post :tag1:@category1: :PROPERTIES: :EXPORT_FILE_NAME: my-first-post :END: This is my post body #+end_src 10. Take the cursor to the post heading and using the default /Shift+left/ (~S-~) binding to mark that subtree as DONE. 11. Now save the file, take the cursor to the end of the post and type the bindings ~C-c C-e H H~. 12. You should see the site preview in your browser auto-update! 13. Now as you make changes in your post, save and do ~C-c C-e H H~ to see the post update in the browser. Here are some examples of Hugo sites generated with Markdown exported using ~ox-hugo~: - [[https://github.com/kaushalmodi/ox-hugo/tree/main/doc][=ox-hugo= documentation site (you're reading it)]] - [[https://github.com/kaushalmodi/ox-hugo/tree/main/test/site][=ox-hugo= test site]] - [[https://gitlab.com/kaushalmodi/kaushalmodi.gitlab.io][/scripter.co/ -- My blog]] *** Installation :PROPERTIES: :EXPORT_FILE_NAME: installation :END: #+include: "./ox-hugo-manual.org::#installation" :only-contents t *** Usage :PROPERTIES: :EXPORT_FILE_NAME: usage :END: #+include: "./ox-hugo-manual.org::#usage" :only-contents t *** Blogging Flow :PROPERTIES: :EXPORT_FILE_NAME: blogging-flow :END: There are 2 major blogging flows that can be used with this package: 1. One post per Org subtree (preferred) - Export only the *current* post Org subtree, or - Export all valid Hugo post subtrees in a loop. 2. One post per Org file - This works but you won't be able to leverage Org-specific benefits like tag and property inheritance, use of TODO states to translate to post =draft= state, auto weight calculation for pages, taxonomies and menu items, etc. See the [[*Org Capture Setup][Org Capture Setup]] page to see how to quickly create new posts. See the [[*Auto-export on Saving][Auto-export on saving]] page to learn how to setup up seeing live-preview of the Hugo-rendered HTML each time you do =C-x C-s= in the Org file. That section explains how to set that up for either of the above two blogging flows. *** Goldmark :PROPERTIES: :EXPORT_FILE_NAME: goldmark :END: Since Hugo v0.60.0, the default Markdown-parser has switched to the [[https://commonmark.org/][CommonMark]]-compliant [[https://github.com/yuin/goldmark][Goldmark]]. The previously default Markdown-parser [[https://github.com/russross/blackfriday][Blackfriday]] is not compliant with any spec, and has many bugs (for which ~ox-hugo~ needs to keep adding workarounds). See [[https://gohugo.io/news/0.60.0-relnotes/][these Hugo v0.60.0 release notes]] to learn more. So unless there's a strong reason for an ~ox-hugo~ user to keep on using Blackfriday, _please switch to Goldmark_. You will need to start using Hugo v0.60.0 or newer for that. **** Enable "unsafe" HTML :PROPERTIES: :CUSTOM_ID: enable-unsafe-html :END: Having said that, Goldmark/Hugo come with their own set of issues or regressions in the way the Markdown parsing happens when compared to Blackfriday, but they are not as bad compared to supporting Blackfriday. For ~ox-hugo~ to keep working well with Goldmark or Hugo v0.60+, it is _necessary_ to add this to your Hugo site's ~config.toml~: #+begin_src toml [markup.goldmark.renderer] unsafe = true #+end_src /While that setting sounds scary, all that does is allow have inline HTML in your Markdown, *as CommonMark allows!*/ *** Troubleshooting :PROPERTIES: :EXPORT_FILE_NAME: troubleshooting :END: **** Exports with mixed unix and dos/windows style line endings Based on your emacs configuration, you could end up exporting a Markdown file that has a mix of unix-style (~"\n"~) and dos-style (~"\r\n"~) line endings. This will confuse Hugo and it would then see unix-style newline as just a whitespace. So now the unix-style line breaks in Markdown that were supposed to create paragraph breaks will be /seen/ as just a whitespace and those paragraph breaks will disappear! One scenario where this is happen is if (i) you have a Windows OS, but (ii) you set the default ~buffer-file-coding-system~ (~C-x RET f~) to be ~utf-8-unix~, and then (iii) [[*Inlined SVGs][embedded a file like an SVG]] created in Windows. Here, your Org buffer will have unix-style line endings, but the SVG created outside Emacs will have dos-style line endings. So you end up exporting a file with mixed line endings. Here are some possible fixes: - Consistent line endings :: Figure out a way for the externally created file to have the line endings consistent with your Emacs buffers. Taking the above example, find a way for that SVG to have unix-style line endings as well. - ~org-export-coding-system~ :: If you are setting ~buffer-file-coding-system~ to be a non-default value in your OS environment, set ~org-export-coding-system~ to be that same value! - Override ~ox-hugo~ export coding system :: If you don't want to sync up these two variables, add the below advice to your Emacs config. /Below example overrides the export coding system to ~utf-8-unix~ assuming that the user has set the ~buffer-file-encoding-system~ to the same value./ #+name: code__ox_hugo_override_export_coding_system #+caption: Example of overriding the export coding system when exporting with ~ox-hugo~ #+begin_src emacs-lisp (defun my/org-hugo-export-to-md-always-utf-8-unix (orig-fun &rest args) (let ((org-export-coding-system 'utf-8-unix)) (apply orig-fun args))) (with-eval-after-load 'ox-hugo (advice-add 'org-hugo-export-to-md :around #'my/org-hugo-export-to-md-always-utf-8-unix)) ;; To remove the advice ;; (advice-remove 'org-hugo-export-to-md #'my/org-hugo-export-to-md-always-utf-8-unix) #+end_src ** Example :PROPERTIES: :EXPORT_HUGO_MENU: :menu "4.example" :END: *** Screenshots :PROPERTIES: :EXPORT_FILE_NAME: screenshots :END: #+include: "./ox-hugo-manual.org::#screenshots" :only-contents t *** Hugo test site for this package :PROPERTIES: :EXPORT_FILE_NAME: tests-site :EXPORT_HUGO_MENU_OVERRIDE: :title "Try the test site" :END: A [[https://github.com/kaushalmodi/ox-hugo/tree/main/test/site][site]] with bare-bones Hugo "theme" is used to live-test the package --- you'll know why theme is double-quoted once you try out the site on =hugo=. Check out the [[https://raw.githubusercontent.com/kaushalmodi/ox-hugo/main/test/site/content-org/all-posts.org][example single Org file]]. That is created for testing various Org->Hugo content and meta-data translation features. [[https://github.com/kaushalmodi/ox-hugo/tree/main/test/site/content/posts][Here]] are the exported Markdown files. **** How to try =ox-hugo= on that site? 1. Clone this repo: #+begin_example git clone -j8 https://github.com/kaushalmodi/ox-hugo #+end_example 2. Ensure that [[https://go.dev/doc/install][~go~]], and ~pandoc~ (at least version {{{pandoc_version}}}) are installed (more info {{{titleref(Requirements#code_contributor_reqs,here)}}}). 3. Start the =hugo= server: #+begin_example make serve HUGO_BASE_DIR=test/site #+end_example 4. Open =http://localhost:1337= in your browser. 5. In a different terminal, =cd= to the repo directory. 6. Run: #+begin_example make md #+end_example 7. In few seconds, hundreds of test posts will get created, with the =hugo server= aided preview in the browser zapping through each new created post. **** Alternative way 1. Clone this repo. #+begin_example git clone -j8 https://github.com/kaushalmodi/ox-hugo #+end_example 2. Ensure that [[https://go.dev/doc/install][~go~]] and ~pandoc~ (at least version {{{pandoc_version}}}) are installed (more info {{{titleref(Requirements#code_contributor_reqs,here)}}}). 3. =cd= to the =test/site/= directory and do: #+begin_example hugo server -D --navigateToChanged #+end_example 4. Above command will mention the localhost where the site is served. Open that in your browser. 5. In emacs, ~(require 'ox-hugo)~ or evaluate the ~ox-hugo.el~ from the cloned repo. 6. Open the {{{ox-hugo-test-file}}} file. 7. ~C-c C-e H A~ -- That will export *all* subtrees in the file to Markdown files. 8. In few seconds, hundreds of test posts will get created, with the ~hugo server~ aided preview in the browser zapping through each new created post. *** Real World Examples :PROPERTIES: :EXPORT_FILE_NAME: examples :EXPORT_HUGO_LAYOUT: examples :EXPORT_HUGO_CUSTOM_FRONT_MATTER: :after_content "_PS: You can also open an issue/PR if you need to get yourself removed from this list._" :END: Here are some examples of sites generated using *=ox-hugo= + Hugo*. If you too have a site generated using this package, and have the Org source of your site public, feel free to open a PR (updating just [[https://github.com/kaushalmodi/ox-hugo/blob/main/doc/data/users.toml][=users.toml=]]) to add yourself here (start the commit message with ~doc(realworld):~ string), or open an issue. ** Org to Hugo :PROPERTIES: :EXPORT_HUGO_MENU: :menu "5.org_to_hugo" :END: *** Org meta-data to Hugo front-matter :PROPERTIES: :EXPORT_FILE_NAME: org-meta-data-to-hugo-front-matter :EXPORT_HUGO_MENU_OVERRIDE: :title "Org→Hugo front-matter" :END: **** Front-matter format ~ox-hugo~ supports exporting the front-matter in [[https://github.com/toml-lang/toml][TOML]] (default) or YAML. To change the default to YAML for your exports, add this to the top of your Org files: #+begin_src org ,#+hugo_front_matter_format: yaml #+end_src - Subtree-based exports only :: If you want only specific subtrees to have the front-matter exported to YAML format, add this to that subtree's property drawer: #+begin_src org :PROPERTIES: :EXPORT_HUGO_FRONT_MATTER_FORMAT: yaml :END: #+end_src **** For subtree-based exports When organizing the posts as Org *subtrees*, many Hugo front-matter variables get set implicitly using the meta-data parsed from the posts in Org. Below, where /subtree/ is mentioned, it implies a *valid Hugo-post subtree* i.e. an Org subtree that has the =EXPORT_FILE_NAME= property set. #+caption: Hugo front-matter translation for subtree-based exports #+attr_html: :class sane-table |------------------------------------+----------------------------------------+----------------------------------------------------------------------------| | Hugo front-matter (TOML) | Org | Org description | |------------------------------------+----------------------------------------+----------------------------------------------------------------------------| | =title = "foo"= | =* foo= | Subtree heading | | =date = 2017-09-11T14:32:00-04:00= | =CLOSED: [2017-09-11 Mon 14:32]= | Auto-inserted =CLOSED= subtree property when switch to Org *DONE* state | | =date = 2017-07-24= | =:EXPORT_DATE: 2017-07-24= | Subtree property | | =publishDate = 2018-01-26= | =SCHEDULED: <2018-01-26 Fri>= | Auto-inserted =SCHEDULED= subtree property using default =C-c C-s= binding | | =publishDate = 2018-01-26= | =:EXPORT_HUGO_PUBLISHDATE: 2018-01-26:= | Subtree property | | =expiryDate = 2999-01-01= | =:EXPORT_HUGO_EXPIRYDATE: 2999-01-01:= | Subtree property | | =lastmod = = | =:EXPORT_HUGO_AUTO_SET_LASTMOD: t= | Subtree property | | =lastmod = = | =#+hugo_auto_set_lastmod: t= | Org keyword | | =tags = ["toto", "zulu"]= | =* foo :toto:zulu:= | Subtree heading tags | | =categories = ["x", "y"]= | =* foo :@x:@y:= | Subtree heading tags with =@= prefix | | =draft = true= | =* TODO foo= | Subtree heading Org TODO state set to =TODO=[fn:4]. | | =draft = false= | =* foo= or =* DONE foo= | Subtree heading Org TODO state not set or set to =DONE=[fn:4]. | | =weight = 123= (manual) | =:EXPORT_HUGO_WEIGHT: 123= | Manual setting of page weight | | =weight = 123= (auto-calc) | =:EXPORT_HUGO_WEIGHT: auto= | When set to =auto=, page weight is auto-calculated | | =tags_weight = 123= (manual) | =:EXPORT_HUGO_WEIGHT: :tags 123= | Manual setting of /FOO/ taxonomy weight, by setting to =:FOO VALUE= | | =tags_weight = 123= (auto-calc) | =:EXPORT_HUGO_WEIGHT: :tags auto= | When set to =:FOO auto=, /FOO/ taxonomy weight is auto-calculated | | =weight = 123= (in =[menu.foo]=) | =:EXPORT_HUGO_MENU: :menu foo= | Menu weight is auto-calculated unless specified | |------------------------------------+----------------------------------------+----------------------------------------------------------------------------| Also see the [[*Custom Front-matter Parameters][Custom Front-matter Parameters]] section. ***** Front-matter Precedence :PROPERTIES: :CUSTOM_ID: front-matter-precedence :END: - Precedence for =date= parsing :: 1. First transition to a /DONE/ state recorded in =:LOGBOOK:= (see {{{titleref(Drawers#logbook-dates,Dates parsed from ~:LOGBOOK:~ drawers)}}}) 2. =CLOSED= subtree property 3. =EXPORT_DATE= subtree property 4. =#+date:= keyword - Precedence for =lastmod= parsing :: 1. Last (second or later) transition to a /DONE/ state recorded in =:LOGBOOK:=, or timestamp of the last added note (see {{{titleref(Drawers#logbook-dates,Dates parsed from ~:LOGBOOK:~ drawers)}}}) 2. =lastmod= set automatically if =:EXPORT_HUGO_AUTO_SET_LASTMOD: t= *and* if it's not derived from the =:LOGBOOK:= drawer. 3. =EXPORT_HUGO_LASTMOD= subtree property or =#+hugo_lastmod:= keyword - Precedence for =draft= parsing :: 1. Org TODO state based /draft/ state 2. =EXPORT_HUGO_DRAFT= subtree property **** For file-based exports #+caption: Hugo front-matter translation for file-based exports #+attr_html: :class sane-table |----------------------------------+--------------------------------------| | Hugo front-matter (TOML) | Org | |----------------------------------+--------------------------------------| | =title = "foo"= | =#+title: foo= | | =date = 2017-07-24= | =#+date: 2017-07-24= | | =publishDate = 2018-01-26= | =#+hugo_publishdate: 2018-01-26= | | =expiryDate = 2999-01-01= | =#+hugo_expirydate: 2999-01-01= | | =lastmod = = | =#+hugo_auto_set_lastmod: t= | | =tags = ["toto", "zulu"]= | =#+hugo_tags: toto zulu= | | =categories = ["x", "y"]= | =#+hugo_categories: x y= | | =draft = true= | =#+hugo_draft: true= | | =draft = false= | =#+hugo_draft: false= | | =weight = 123= | =#+hugo_weight: 123= | | =tags_weight = 123= | =#+hugo_weight: :tags 123= | | =categories_weight = 123= | =#+hugo_weight: :categories 123= | | =weight = 123= (in =[menu.foo]=) | =#+hugo_menu: :menu foo :weight 123= | |----------------------------------+--------------------------------------| ***** Notes - The *auto calculation* of weights for pages, taxonomies and menu items works *only* for subtree-based exports. For the file-based exports, the weights have to be specified manually. Any /weight/ assignment to ="auto"= for file-based exports is ignored. - See [[#org-hugo-date-format][~org-hugo-date-format~]] for customizing the date formats for all /date/ front-matter parameters. - For setting custom front-matter parameters, see the [[*Custom Front-matter Parameters][Custom Front-matter Parameters]] section. *** Formatting :PROPERTIES: :EXPORT_FILE_NAME: formatting :END: Below table shows the translation of Org markup to Markdown markup in the exported =.md= files. See the Org source in [[https://raw.githubusercontent.com/kaushalmodi/ox-hugo/main/test/site/content-org/all-posts.org][=all-posts.org=]] under /Formatting/ -> /General/ heading and how it exports to Markdown in [[https://raw.githubusercontent.com/kaushalmodi/ox-hugo/main/test/site/content/posts/general-formatting.md][=general-formatting.md=]]. #+caption: Org markup to Markdown markup #+attr_html: :class sane-table |--------------------+--------------------------------------------------------------------| | Org | Markdown | |--------------------+--------------------------------------------------------------------| | =*bold*= | =**bold**= | | =/italics/= | =_italics_= | | ==monospace== | =`monospace`= | | =~key-binding~= | =`key-binding`= | | | - if =org-hugo-use-code-for-kbd= is nil [default] | | =~key-binding~= | =key-binding= | | | - if =org-hugo-use-code-for-kbd= is non-nil | | | - Requires *CSS* to render the == tag as something special. | | =+strike-through+= | =~~strike-through~~= | | =_underline_= | =underline= | | | - Requires *CSS* to render this =underline= class as an underline. | |--------------------+--------------------------------------------------------------------| *** Dates :PROPERTIES: :EXPORT_FILE_NAME: dates :EXPORT_HUGO_USE_CODE_FOR_KBD: t :END: **** Date Formats The =EXPORT_DATE= and other date-type properties support date in either the [[https://tools.ietf.org/html/rfc3339#section-5.8][RFC3339 date-time format]][fn:8] or the built-in Org time-stamp (default binding ~C-c .~). - RFC3339 date-time examples :: - =2017-09-12= - =2017-09-12T16:10:10= (data and time are separated by *T*) - =2017-09-12T16:10:10Z= (UTC time zone) - =2017-09-12T16:10:10-04:00= (UTC-04:00 time zone) - Org time stamp example :: - =<2020-05-17 Sun>= **** Defcustoms ***** =org-hugo-date-format= :PROPERTIES: :CUSTOM_ID: org-hugo-date-format :END: - Default value :: ="%Y-%m-%dT%T%z"= This variable sets the date format used for exporting /date/ front-matter parameters like =date=, =publishDate=, =expiryDate=, =lastmod=. Note that the date format *must match* the date specification from [[https://tools.ietf.org/html/rfc3339#section-5.8][RFC3339]]. Examples of RFC3339-compatible values for this variable: |---------------------------+-----------------------------| | Value | Example output | |---------------------------+-----------------------------| | =%Y-%m-%dT%T%z= (default) | =2017-07-31T17:05:38-04:00= | | =%Y-%m-%dT%T= | =2017-07-31T17:05:38= | | =%Y-%m-%d= | =2017-07-31= | |---------------------------+-----------------------------| Do =C-h v org-hugo-date-format= for more information (within Emacs, once the =ox-hugo= package is loaded). ***** =org-hugo-suppress-lastmod-period= - Default value :: =0.0= A suppressing period (in seconds) during which the =lastmod= parameter is not added to the front matter. The suppressing period is counted as a delta between the =date= and =lastmod= parameters. If the value is 86400.0, the =lastmod= parameter will not be added to the front matter within 24 hours from the value of =date= parameter. =lastmod= would be exported when you initially change the Org TODO state to =DONE= by saving the file automatically with the following conditions. Some users may not prefer this behavior. | Variable | Value | |----------------------------------+-------| | org-hugo-auto-set-lastmod | t | | org-log-done | time | In such case, you can suppress =lastmod= in the front-matter if you set =org-hugo-suppress-lastmod-period= to =60.0= or other appropriate value. Note that this variable is effective only if auto-setting of the =lastmod= parameter is enabled i.e. if =org-hugo-auto-set-lastmod= or =EXPORT_HUGO_AUTO_SET_LASTMOD= is non-nil. **** File-based Exports :PROPERTIES: :CUSTOM_ID: dates-file-based-exports :END: In Org files meant for file-based exports, you simply set a value for a =#+hugo_FOO= keyword (in most cases, for example =#+date= is one of the exceptions) to set the =FOO= parameter in the exported front-matter. #+caption: Dates translation from Org meta-data to Hugo front-matter (file-based exports) #+attr_html: :class sane-table |----------------------------------+----------------------------| | Org | Hugo front-matter (TOML) | |----------------------------------+----------------------------| | =#+date: 2017-07-24= | =date = 2017-07-24= | | =#+hugo_publishdate: 2018-01-26= | =publishDate = 2018-01-26= | | =#+hugo_expirydate: 2999-01-01= | =expiryDate = 2999-01-01= | | =#+hugo_lastmod: 2018-02-06= | =lastmod = 2018-02-06= | | =#+hugo_auto_set_lastmod: t= | =lastmod = = | |----------------------------------+----------------------------| **** Subtree-based Exports :PROPERTIES: :CUSTOM_ID: dates-subtree-based-exports :END: The date meta-data can be set as Org properties in post subtrees, similar to the keywords set for [[#dates-file-based-exports][File-based exports]]. But subtree-based exports allow an even concise way to set those dates. ***** Date This is interpreted from the Org /Special Property/ =CLOSED= (see [[info:org#Special Properties]]). The =CLOSED= property is inserted once the post-subtree's =TODO= state is set to =DONE= (~C-c C-t~), *if* the =org-log-done= variable is set to ='time= (default is /nil/). This option can also be enabled on a per-file-basis with =#+startup: logdone=. Here's an example: #+begin_src org ,* DONE My post CLOSED: [2018-01-23 Tue 14:10] Post content. #+end_src Above gets translated to =date = 2018-01-23T14:10:00-05:00= in front-matter (TOML). - NOTE :: Another variable =org-log-done-with-time= can be set to /nil/ (default to =t=) if you would like the =CLOSED= time stamp to contain only the date, and not the time. /You do not then need to explicitly set the =:EXPORT_DATE:= property./ ***** Publish Date This is interpreted from the Org Special Property =SCHEDULED=. The idea is that you schedule a task for a /future/ date, just as you would set a post to be published in /future/. This property is set using the default ~C-c C-s~ binding in Org. Here's an example: #+begin_src org ,* My future post SCHEDULED: <2060-01-26 Mon> Post content. #+end_src Above gets translated to =publishDate = 2060-01-26T00:00:00-05:00= in front-matter (TOML). /You do not then need to explicitly set the =:EXPORT_HUGO_PUBLISHDATE:= property./ ***** Expiry Date This is set using the =:EXPORT_HUGO_EXPIRYDATE:= property. ***** Last modified Like any other front-matter property, you can explicitly set the /last modified/ date too, using the =:EXPORT_HUGO_LASTMOD:= property. But what's the point of calling a property /last modified/, if you forget to manually update that property *each time* you update the post. SO =ox-hugo= takes care of that for you.. if you set the property =:EXPORT_HUGO_AUTO_SET_LASTMOD:= to a non-nil value. It's normal for one to choose to auto-set the /last modified/ date for all the posts. So instead of setting the above property for each post individually, it might be more convenient to simply put =#+hugo_auto_set_lastmod: t= at the top of the file. But note that if the =lastmod= date is parsed from the {{{titleref(Drawers#logbook-dates,~:LOGBOOK:~ drawer)}}} that value will take precedence, and the "auto set lastmod" feature will be disabled. *** Image Links :PROPERTIES: :EXPORT_FILE_NAME: image-links :END: This section will provides few alternatives for linking to images in Org files in a way that's compatible with =ox-hugo= and Hugo. For the sake of the below explanation, let's have the /HUGO_BASE_DIR/ (the directory containing the Hugo site's =config.toml= file) be =~/hugo/=. Then the Hugo /static/ directory will be =~/hugo/static/=. **** References to files in the /static/ directory :PROPERTIES: :CUSTOM_ID: references-to-files-in-the-static-directory :END: Now if you have a file =~/hugo/static/images/foo.png=, =ox-hugo= makes it convenient for you to reference that image by simply =/images/foo.png=. #+begin_note Note that this is *not* the default behavior of other Org exporters. #+end_note But in the case of Hugo, as the referenced file will /normally/ be in the Hugo /static/ directory, =ox-hugo= allows the =/images/foo.png= style of short reference *if* that is a valid path under that Hugo site's /static/ directory. See the below examples on how to reference images in different ways: ***** Inline image -- Unhyperlinked #+caption: Unhyperlinked image (don't click it) #+name: fig__unhyperlinked_image [[/images/org-mode-unicorn-logo-200px.png]] #+begin_src org [[/images/org-mode-unicorn-logo-200px.png]] #+end_src ***** Inline image -- Also hyperlinked to an image #+caption: Image hyperlinked to an image (click it!) #+name: fig__hyperlinked_image [[/images/org-mode-unicorn-logo-200px.png][file:/images/org-mode-unicorn-logo-50px.png]] #+begin_src org [[/images/org-mode-unicorn-logo-200px.png][file:/images/org-mode-unicorn-logo-50px.png]] #+end_src This style of link is normally used if you want to link a low resolution image to its higher resolution version. - NOTE 1 :: The =file:= prefix has to be used in the *Description component* of the Org link. - NOTE 2 :: The =file:= prefix can be used for the *Link component* of the Org link too --- it doesn't hurt. - NOTE 3 :: A space in the path in the *Description component* of the Org link has to be encoded to "%20". ***** Regular link to an image [[/images/org-mode-unicorn-logo-200px.png][Click here to see org-mode-unicorn-logo-200px.png]] #+begin_src org [[/images/org-mode-unicorn-logo-200px.png][Click here to see org-mode-unicorn-logo-200px.png]] #+end_src This style of linking will work for references to non-image files in the /static/ directory too. **** References to files *outside* the /static/ directory :PROPERTIES: :CUSTOM_ID: references-to-files-outside-the-static-directory :END: This is a unique feature of =ox-hugo=. (i) If a reference is made to a file outside the Hugo /static/ directory, *and* (ii) if it has one of the extensions listed in =org-hugo-external-file-extensions-allowed-for-copying=, then that file is copied by =ox-hugo= to the /static/ directory. Here is an example link: #+begin_src org [[~/some-dir/static/images/foo.png]] #+end_src ***** Source path contains =/static/= If you link to files outside of the Hugo =static= directory, just ensure that the path contains the string =/static/= /if you like to preserve the directory structure/. Necessary directories are then created inside the /static/ directory to preserve the structure. Example translations between outside =static= directory paths to the copied location inside =static=: #+caption: Where files get copied to if their path contains =static/= #+attr_html: :class sane-table |----------------------------------+-------------------------------------------+----------------------------------------------------------------------------------------------------------| | File location outside =static= | Copied-to location inside =static= | Explanation | |----------------------------------+-------------------------------------------+----------------------------------------------------------------------------------------------------------| | =~/temp/static/images/foo.png= | =/static/images/foo.png= | If the *outside* path has =/static/= in it, the directory structure after that is preserved when copied. | | =~/temp/static/img/foo.png= | =/static/img/foo.png= | (same as above) | | =~/temp/static/foo.png= | =/static/foo.png= | (same as above) | | =~/temp/static/articles/zoo.pdf= | =/static/articles/zoo.pdf= | (same as above) | |----------------------------------+-------------------------------------------+----------------------------------------------------------------------------------------------------------| See the {{{titleref(Usage#before-you-export,Usage → Before you export)}}} section to learn how to set the *HUGO_BASE_DIR*. ***** Source path does not contain =/static/= Here is an example link where the source path does not contain =/static/=: #+begin_src org [[~/some-dir/bar/foo.png]] #+end_src In this case, that file is copied directly to the =org-hugo-default-static-subdirectory-for-externals= sub-directory (=ox-hugo/= by default) within the Hugo static directory. No directory structure generation happens in this case. #+caption: Where files get copied to if their path *does not* contain =static/= #+attr_html: :class sane-table |--------------------------------+------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------| | File location outside =static= | Copied-to location inside =static= | Explanation | |--------------------------------+------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------| | =~/temp/bar/baz/foo.png= | =/static/ox-hugo/foo.png= | Here, as the *outside* path does not have =/static/= in it, the file is copied to the =ox-hugo/= dir in Hugo =static/= dir. | |--------------------------------+------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------| ***** Disable auto-copying This auto-copying behavior can be disabled completely by setting =org-hugo-external-file-extensions-allowed-for-copying= to /nil/.. but you might not want that if you keep your files *outside* the Hugo static directory. **** Hiding figure caption numbers The "Figure :" part of the figure captions can be hidden by adding this to the CSS: #+begin_src css .figure-number { display: none; } #+end_src **** Auto-prefixing description of links to figures with "Figure" See [[*Linking numbered elements]]. *** Source blocks :PROPERTIES: :EXPORT_FILE_NAME: source-blocks :END: =ox-hugo= tries to generate Markdown with fenced code blocks if possible. It also supports exporting source blocks with line numbers and/or highlighting enabled for specific lines. **** Code Fences By default, the =HUGO_CODE_FENCE= property is non-nil. So the code blocks will be exported with /CommonMark/ code fences when possible. For example, below Org source block: #+begin_src org ,#+begin_src emacs-lisp (message "Hello") ,#+end_src #+end_src will export to: #+begin_src md ```emacs-lisp (message "Hello") ``` #+end_src - Note :: It is necessary to set the Hugo site config variable =markup.highlight.codeFences= to =true= (which is the default at least as of [[https://github.com/gohugoio/hugo/commit/bfb9613a14ab2d93a4474e5486d22e52a9d5e2b3][Hugo v0.60.0]]) for syntax highlighting to work for fenced code blocks. **** Line numbers Line numbers can be enabled/configured using the Org =-n= / =+n= syntax. See [[info:org#Literal Examples]] for more information. Here are some examples fetched from the "Source blocks with line number annotation" test case in the {{{ox-hugo-test-file}}}. #+include: "../test/site/content-org/all-posts.org::#source-block-line-number-cases" :only-contents t ***** Line number Style (*linenos*) :PROPERTIES: :CUSTOM_ID: linenos :END: The value of ~linenos~ (Hugo's default value or the site-global value set in its ~config.toml~) can be overridden per source block using the ~:linenos~ parameter in that source block's header. #+name: tab__linenos_values #+caption: Possible values of ~:linenos~ |------------------+-----------------------------------------------------------------------------------------------------| | ~:linenos~ value | Description | |------------------+-----------------------------------------------------------------------------------------------------| | ~false~ | Disable line numbers. | | ~true~ | Enable line numbers with Hugo's default value of [[https://gohugo.io/functions/highlight/#options][~lineNumbersInTable~]]. | | ~inline~ | Enable line numbers where the line numbers and code are rendered in HTML ~
~ and ~~ tags. | | ~table~ | Enable line numbers where the line numbers and code are rendered in HTML tables. | |------------------+-----------------------------------------------------------------------------------------------------| *Example usage*: If a user has enabled the line numbers by default by adding this in their site's =config.toml=: #+begin_src toml [markup] [markup.highlight] lineNos = true #+end_src , they can disable line numbers for selected source blocks by adding ~:linenos false~ to their headers. #+begin_src org ,#+begin_src emacs-lisp :linenos false (message "hello") (message "bye") ,#+end_src #+end_src /The ~:linenos~ header arg works for example blocks too./ ***** Line numbers in HTML table The source block or code block rendering is done by Hugo using the [[https://github.com/alecthomas/chroma][chroma]] syntax highlighter. When the line numbers are enabled, the line numbers and code blocks can be rendered either in HTML tables (~lineNumbersInTable = true~) or in the ~div~ and ~span~ tags (~lineNumbersInTable = false~). See Hugo's default value of this config variable [[https://gohugo.io/getting-started/configuration-markup#highlight][here]]. To render the line numbers and code blocks in HTML tables regardless of Hugo's default value, add this to your site's ~config.toml~: #+name: code__line_numbers_in_table #+caption: Render line numbers and code blocks in HTML tables #+begin_src conf-toml [markup] [markup.highlight] lineNumbersInTable = true #+end_src To override the rendering of line numbers and code blocks to happen in ~
~ and ~~ tags, set ~lineNumbersInTable = false~ instead, but *this is not recommended*. /With ~lineNumbersInTable = false~, when the code blocks are copied in Firefox, extra blank lines get inserted after each line when pasted elsewhere. See [[https://bugzilla.mozilla.org/show_bug.cgi?id=1273836#c29][Bugzilla # 1273836]]./ **** Highlight Lines Implementing this feature was interesting, because while Org doesn't have a syntax to enable highlighting only specific lines, Hugo supports line highlighting using the =hl_lines= attribute for [[https://gohugo.io/content-management/syntax-highlighting#highlighting-in-code-fences][code fences]] (Hugo v0.60.0+) or its ~highlight~ shortcode. So the challenge was to present that "lines to be highlighted" information in the Org source in a nice format and then translate that to the =hl_lines= attribute with the required format at the time of exporting. It involved /hacking/ the =org-babel-exp-code=. See [[https://lists.gnu.org/archive/html/emacs-orgmode/2017-10/msg00300.html][this discussion on the =emacs-orgmode= thread]] if interested. This feature is implemented by using a parameter called =:hl_lines= in the header of source blocks. This parameter is specific to =ox-hugo=, and that's why implementing this needed that hack. If a user wants to highlight lines 1, and then 3 to 5, they would add =:hl_lines 1,3-5= to the source block header. ***** Noweb refences :noexport: Below 2 include statements fetch the noweb references used in the code inserted by other include statements in the following sections. They are included to get the /noweb/ references working but they do not need to be exported. #+include: "../test/site/content-org/all-posts.org::#source-block-with-line-numbers-examples" #+include: "../test/site/content-org/all-posts.org::#source-block-with-line-highlighting-examples" ***** Highlighting without line numbers #+include: "../test/site/content-org/all-posts.org::#source-blocks-with-highlighting-no-linenums" :only-contents t ***** Highlighting with line numbers The Org source for the below is similar to the above, except that the =-n= switch is also added to enable the line numbers. #+include: "../test/site/content-org/all-posts.org::#source-blocks-with-highlighting-with-linenums-not-starting-from-1" :only-contents t **** Hiding source block caption numbers The "Code Snippet :" part of the source block captions can be hidden by adding this to the CSS: #+begin_src css .src-block-number { display: none; } #+end_src **** Code References ~ox-hugo~ generates code references hyperlinked to line numbers of source and example blocks when using the ~(ref:REF)~ syntax in the blocks as explained in [[info:org#Literal Examples]]. #+begin_quote Org interprets strings like ~(ref:name)~ as labels, and use them as targets for special hyperlinks like ~[[(name)]]~ — i.e., the reference name enclosed in single parenthesis. You can also add a ~-r~ switch which removes the labels from the source code. #+end_quote #+begin_note One convenience feature added by ~ox-hugo~ is that the ~-n~ is always implied when code references are detected in the source or example blocks. #+end_note - Note :: It is the user's responsibility to ensure that all code ref labels used within a single post are unique. ***** Code references exported with labels As an example, this in Org source: # Below the '-l "((%s))"' switch is used to change the reference label # format so that the labels in the nested emacs-lisp src block in this # Org src block don't get parsed as this Org block's references. #+begin_src org -l "((%s))" ,#+begin_src emacs-lisp (save-excursion (ref:sc) (goto-char (point-min)) (ref:jump) ,#+end_src In line [[(sc)]] we remember the current position. [[(jump)][Line (jump)]] jumps to ~point-min~. #+end_src exports to: #+begin_src emacs-lisp (save-excursion (ref:sc) (goto-char (point-min)) (ref:jump) #+end_src In line [[(sc)]] we remember the current position. [[(jump)][Line (jump)]] jumps to ~point-min~. ***** Code references exported *without* labels When the ~-r~ switch is used in the header, the code ref labels are removed from the exported code block, and the labels in code ref link descriptions are replaced with line numbers. As an example, this in Org source: # Below the '-l "((%s))"' switch is used to change the reference label # format so that the labels in the nested emacs-lisp src block in this # Org src block don't get parsed as this Org block's references. #+begin_src org -l "((%s))" ,#+begin_src emacs-lisp -r (save-excursion (ref:sc1) (goto-char (point-min)) (ref:jump1) ,#+end_src In line [[(sc1)]] we remember the current position. [[(jump1)][Line (jump1)]] jumps to ~point-min~. #+end_src exports to: #+begin_src emacs-lisp -r (save-excursion (ref:sc1) (goto-char (point-min)) (ref:jump1) #+end_src In line [[(sc1)]] we remember the current position. [[(jump1)][Line (jump1)]] jumps to ~point-min~. **** ~highlight~ shortcode :PROPERTIES: :CUSTOM_ID: highlight-shortcode :END: #+begin_note By default, ~ox-hugo~ tries to avoid using this shortcode because it is buggy ({{{issue(161)}}}), and also it's better to export /CommonMark/ supported code fences than Hugo-specific shortcodes. #+end_note The Hugo [[https://gohugo.io/content-management/syntax-highlighting#highlight-shortcode][=highlight= shortcode]] is used instead of code fences if one of these is true: - ~HUGO_CODE_FENCE~ is set to /nil/. - "Blackfriday mode" is enabled (~HUGO_GOLDMARK~ is /nil/) *and* either of the [[*Line numbers][line numbering]], [[*Highlight Lines][line highlighting]] or [[*Code References][code ref]] features are enabled, or if the [[#linenos][=:linenos= parameter]] is specified in the source block header. *** Equations :PROPERTIES: :EXPORT_FILE_NAME: equations :EXPORT_HUGO_CUSTOM_FRONT_MATTER: :mathjax true :END: #+begin_description {{{latex}}} equations support #+end_description By default, the inline and block equations are exported to Markdown in a format that can be rendered using [[https://www.mathjax.org/#gettingstarted][MathJax]]. /You can find one MathJax config example [[#mathjax-config-example][below]]./ ~ox-hugo~ indirectly extends from ~ox-html~ and so it also inherits a different way of exporting {{{latex}}} equations --- by [[#exporting-equations-to-images][exporting them to images]]. **** Inline equations - Inline equations are wrapped between =\(= and =\)=. - =$= wrapping also works, but it is not preferred as it comes with restrictions like "there should be no whitespace between the equation and the =$= delimiters". So =$ a=b $= will not work (it will look like: $ a=b $), but =$a=b$= will work (it will look like: $a=b$). On the other hand, both =\(a=b\)= (it will look like: \(a=b\)) and =\( a=b \)= (it will look like: \( a=b \)) will work. - One-per-line equations are wrapped between =\[= and =\]= or =$$= delimiters. For example, below in Org: #+begin_src org LaTeX formatted equation: \( E = -J \sum_{i=1}^N s_i s_{i+1} \) #+end_src will look like this in Hugo rendered HTML (using MathJax): LaTeX formatted equation: \( E = -J \sum_{i=1}^N s_i s_{i+1 }\) Here's another example, taken from [[info:org#LaTeX fragments]]: #+begin_example If $a^2=b$ and \( b=2 \), then the solution must be either $$ a=+\sqrt{2} $$ or \[ a=-\sqrt{2} \] #+end_example Above renders to below using Mathjax: If $a^2=b$ and \( b=2 \), then the solution must be either $$ a=+\sqrt{2} $$ or \[ a=-\sqrt{2} \] #+begin_note Note that the last two equations show up on their own lines because those equations are wrapped in ~\[ .. \]~. #+end_note **** {{{latex}}} Environments =ox-hugo= support {{{latex}}} environments. So below in Org buffer: #+begin_src org \begin{equation} \label{eq:1} C = W\log_{2} (1+\mathrm{SNR}) \end{equation} #+end_src will render as below using MathJax: \begin{equation} \label{eq:1} C = W\log_{2} (1+\mathrm{SNR}) \end{equation} #+begin_note You can find many more equation examples at {{{testtag(equations)}}}. #+end_note ***** Referencing Equations Equation referencing will also work **but it requires MathJax**. [[#mathjax-config-example][Here]] is a MathJax configuration that is known to work for this referencing feature. =\label{SOMELABEL}= labeled equations can be referenced using =\ref{SOMELABEL}=[fn:12]. So =\ref{eq:1}= will render as \ref{eq:1} and link to the equation above. **** MathJax config example :PROPERTIES: :CUSTOM_ID: mathjax-config-example :END: Here's how MathJax is configured for this website: - hugo-onyx-theme [[https://github.com/kaushalmodi/hugo-onyx-theme/blob/master/layouts/partials/mathjax.html][~mathjax.html~ partial]] - MathJax config: [[https://github.com/kaushalmodi/hugo-onyx-theme/blob/master/static/js/mathjax-config.js][~js/mathjax-config.js~]] **** Exporting {{{latex}}} equations as images :PROPERTIES: :CUSTOM_ID: exporting-equations-to-images :END: If you prefer, you can using ~dvisvgm~ or ~dvipng~[fn:3] to export the equations to SVG or PNG images, and the equations in the Org file will be replaced by links to those images in the exported Markdown files. The method for exporting the equations to images is the same as that documented for ~ox-html~ in [[info:org#Math formatting in HTML export]]: - To export the equations to SVG, add ~#+options: tex:dvisvgm~ to the top of your Org file, or add ~:EXPORT_OPTIONS: tex:dvisvgm~ to the post subtree's property drawer. - Similarly, to export the equations to PNG, use the ~tex:dvipng~ option instead. #+begin_note Referencing to equations using ~\ref{..}~ will not work if equations are exported as images. #+end_note *** Tags and Categories :PROPERTIES: :EXPORT_FILE_NAME: tags-and-categories :END: **** Subtree-based Export ***** Tags :PROPERTIES: :CUSTOM_ID: tags--subtree-based-export :END: Tags for subtree-based exports can be set using the =EXPORT_HUGO_TAGS= property or the usual Org tags in the post subtree heading. #+name: tab__subtree_based_export_tag_precedence #+caption: Subtree-based export Tag parsing precedence |------------+----------------------------------------------------------------| | Precedence | Location of tags | |------------+----------------------------------------------------------------| | 1 | =EXPORT_HUGO_TAGS= property | | 2 | Tags in =#+filetags= + headings without =@= prefix (preferred) | |------------+----------------------------------------------------------------| By default, Org tags from parent headings, and the tags set in the =#+filetags= keyword get inherited (as the default value of =org-use-tag-inheritance= is =t=). #+begin_note If the tag inheritance doesn't work as expected, check the value of =org-use-tag-inheritance=. #+end_note ****** Example :PROPERTIES: :CUSTOM_ID: tags--subtree-based-export--example :END: #+name: code__tags_in_headings #+caption: Example of tags in headings #+begin_src org ,* My post :tag1:tag2: #+end_src ****** Marking files to not be exported Note that if you want to prevent a file from getting exported, you can assign a special tag to the whole file (example: =no_no_dont_export=). - For /per-subtree/ flow, that /don't export/ tag *has to be set using the =#+filetags= keyword*[fn:2]. - For /per-file/ flow, that same /dont' export/ tag *has to be set using the =#+hugo_tags= keyword* (because ~#+filetags~ keyword does not work for /per-file/ flow. See [[* File-based Export]]). Then in your export setup, add that special tag to the =org-export-exclude-tags= variable. You can grep through this repo for the special tag =dont_export_during_make_test= that is used to mark few Org files to not be exported when running the tests. ***** Categories :PROPERTIES: :CUSTOM_ID: categories--subtree-based-export :END: Categories for subtree-based exports can be set using the =EXPORT_HUGO_CATEGORIES= property or the usual Org tags in the post subtree heading (but tags with =@= prefix). #+name: tab__subtree_based_export_category_precedence #+caption: Subtree-based export Category parsing precedence |------------+-------------------------------------------------------------| | Precedence | Location of categories | |------------+-------------------------------------------------------------| | 1 | =EXPORT_HUGO_CATEGORIES= property | | 2 | Tags in =#+filetags= + headings with =@= prefix (preferred) | |------------+-------------------------------------------------------------| For subtree-based exports, the Hugo front-matter =categories= values are derived from Org tags set for the post subtree heading (if =EXPORT_HUGO_CATEGORIES= is not set), but only the ones prefixed with *@*. As with the tags, by default, the categories (Org tags with "@" prefix) from parent headings, and the ones set in the =#+filetags= keyword too get inherited (as the default value of =org-use-tag-inheritance= is =t=). #+begin_note If the tag inheritance doesn't work as expected, check the value of =org-use-tag-inheritance=. #+end_note ****** Example :PROPERTIES: :CUSTOM_ID: categories--subtree-based-export--example :END: #+name: code__categories_in_headings #+caption: Example of categories in headings #+begin_src org ,* My post :@cat1:@cat2: #+end_src #+name: code__tags_and_categories_in_subtree_based_export #+caption: Example of tags and categories in =#+filetags= + headings #+begin_src org ,#+filetags: tag1 tag2 @cat1 @cat2 ,* My post :tag3:@cat3: #+end_src Above, the "My post" will end up have all tags ("tag1", "tag2", "tag3") and all categories ("cat1", "cat2", "cat3") if =org-use-tag-inheritance= is =t=. **** Why use =#+filetags= and not =#+tags=? =#+tags= keyword has some special uses in Org documents. - List of available tags for the current file :: It's used for providing a list of tags at the top of an Org file which gets added to the pool of tags for auto-completion (see [[info:org#Setting Tags]] or =C-h i g (org) Setting Tags=). - Tag hierarchy definition :: The =#+tags= keyword is also used to define /Tag Hierarchies/. See [[info:org#Tag Hierarchy]] (or =C-h i g (org) Tag Hierarchy=). And the Org manual already has a dedicated keyword =#+filetags= to provide a list of tags to *apply* to the current file (see [[info:org#Tag Inheritance]] or =C-h i g (org) Tag inheritance=). So ~ox-hugo~ recognizes =#+filetags= and not =#+tags= to collect the tags assigned for the current post. **** File-based Export ***** Tags :PROPERTIES: :CUSTOM_ID: tags--file-based-export :END: Tags for file-based exports can be set using the =#+hugo_tags= or =#+filetags= keyword. #+name: tab__file_based_export_tag_precedence #+caption: File-based export Tag parsing precedence |------------+-----------------------------------------| | Precedence | Location of tags | |------------+-----------------------------------------| | 1 | =#+hugo_tags= keyword | | 2 | Tags in =#+filetags= without =@= prefix | |------------+-----------------------------------------| ***** Categories :PROPERTIES: :CUSTOM_ID: categories--file-based-export :END: Categories for file-based exports can be set using the =#+hugo_categories= or =#+filetags= keyword. #+begin_note Tags with =@= in =#+filetags= are parsed as Categories by =ox-hugo=. #+end_note #+name: tab__file_based_export_category_precedence #+caption: File-based export Category parsing precedence |------------+--------------------------------------| | Precedence | Location of categories | |------------+--------------------------------------| | 1 | =#+hugo_categories= keyword | | 2 | Tags in =#+filetags= with =@= prefix | |------------+--------------------------------------| ****** Example :PROPERTIES: :CUSTOM_ID: tags-categories--file-based-export--example :END: #+name: code__tags_and_categories_in_filetags_file_based_export #+caption: Example of tags and categories in =#+filetags= #+begin_src org ,#+filetags: tag1 tag2 @cat1 @cat2 #+end_src **** Hyphens and Spaces in Org tags (and categories) Hyphens and spaces are not allowed in Org tags (=* Heading :TAG:=). So =ox-hugo= converts: - *single underscores* to hyphens if =org-hugo-prefer-hyphen-in-tags= is set to non-nil (default). - *double underscores* to spaces if =org-hugo-allow-spaces-in-tags= is set to non-nil (default). So an Org tag *abc_def* will be exported as /tag/ *"abc-def"*, and *abc__def* will be exported as /tag/ *"abc def"*. The same applies to Org tags with prefix =@= which will be exported as /categories/. So *@abc_def* will be exported as /category/ *"abc-def"*, and *@abc__def* as /category/ *"abc def"*. To export a tag or category with an underscore, use 3 consecutive underscores. So an Org tag *abc___def* will be exported as /tag/ *"abc_def"* (and the same for categories). If you rather prefer to always export /single underscores/ as underscores, set =org-hugo-prefer-hyphen-in-tags= to nil. #+begin_note These two variables *also affect* the tags set via =#+filetags= keyword. #+end_note These variables do not affect the tags set via keywords =#+hugo_tags=, =#+hugo_categories= or =#+keywords= (or their respective subtree property forms), because Org keywords and properties allow using the hyphen and space (/in "double-quoted strings"/) characters. So the underscores in these keywords remain untransformed on export. **** Sub-heading Tags Sub-heading tags are exported wrapped in HTML ~span~ tags to the right of the exported heading if ~org-export-with-tags~ is non-nil (default) or if ~#+options: tags:t~ is used. The ~span~ tags are best formatted using CSS. Here's one example: #+begin_src css .tag span { background: lightgrey; font-size: small; padding: 0.1rem 0.2rem; margin: 0.2rem; } #+end_src {{{test-search(subheading-tags)}}} **** More Examples - [[https://raw.githubusercontent.com/kaushalmodi/ox-hugo/main/test/site/content-org/tags-and-categories.org][Org source]] - Exported Markdown -- [[https://raw.githubusercontent.com/kaushalmodi/ox-hugo/main/test/site/content/posts/inheriting-tags.md][=inheriting-tags.md=]], [[https://raw.githubusercontent.com/kaushalmodi/ox-hugo/main/test/site/content/posts/overriding-tags.md][=overriding-tags.md=]] - Hugo-generated HTML -- [[https://ox-hugo.scripter.co/test/posts/inheriting-tags/][Inheriting tags]], [[https://ox-hugo.scripter.co/test/posts/overriding-tags/][Overriding tags]] *** Table of Contents :PROPERTIES: :EXPORT_FILE_NAME: org-toc :END: Hugo can automatically parse the Markdown content and auto-create a Table of Contents. See its documentation on [[https://gohugo.io/content-management/toc/][Table of Contents]]. So =ox-hugo= does not generate the TOC using Org by default. The only advantage of using Hugo-generated TOC is that it does not clutter the Markdown source. Though, the advantage of Org-generated TOC is that you get finer control on: - *Where* to include the TOC --- Location of the =#+toc= keyword in the Org content. - How many headings to include in the TOC --- /Example: =#+toc: headlines 2=/ or =:EXPORT_OPTIONS: toc:2=. - Whether you want *all* the headings in the TOC to be numbered or not --- See =org-hugo-export-with-section-numbers=. - Whether you want *only some* headings numbered (both in post body and the TOC) --- Set the =UNNUMBERED= property of that heading to =t=. - Whether you want to list the sub-headings *only from the current heading in the post* --- /Example: ~#+toc: headlines 1 local~/. - Whether you want to list the sub-headings from a specified heading in the current post using the ~:target~ attribute. See [[info:org#Table of Contents]] for its example. If you want to use the Org-generated TOC instead of the Hugo-generated one, do one of the following: 1. As the default is to use the Hugo-generated TOC, the Org-generated TOC has to be enabled explicitly. To do this for all your ~ox-hugo~ generated posts, set the =org-hugo-export-with-toc= variable to a non-nil value like =t= or =2=. 2. Org-generated TOC can be enabled per-post by either setting the =EXPORT_OPTIONS= subtree property (for subtree-based exports) or the =OPTIONS= keyword (for file-based exports) to a non-nil value, like ~toc:t~ or ~toc:2~. 3. Above two options will insert the TOC between the front-matter and the Markdown content. If you'd like to insert the Org-generated TOC anywhere else in the post, you can do it using the =#+toc= keyword.. Example: =#+toc: headlines 2=. See [[info:org#Table of Contents]] for more information. /Note that =ox-hugo= does not support =#+toc: listings= and =#+toc: tables=./ **** "Table of Contents" heading :PROPERTIES: :CUSTOM_ID: toc-heading :END: The "Table of Contents" heading is inserted as a plain HTML ~div~ element. Users can customize the looks of that ~div~ by setting CSS rules for ~.ox-hugo-toc .heading~. Here is an example CSS rule for that: #+begin_src css .ox-hugo-toc .heading { font-size: 1.8em; font-weight: bold; text-align: center; } #+end_src **** Excluding Org-generated TOC from Hugo summaries As mentioned above, if you use Hugo-generated TOC, the advantage is that the TOC is not inserted physically in the content Markdown file. But with the Org-generated TOC, it *will* be. The disadvantage of that is that the =.Summary= in Hugo will consider the TOC! So your TOC will show up in places you don't expect.. like summaries in post lists, in twitter cards, etc. But.. there's a way to fix that, because =ox-hugo= inserts a special comment ~~ at the end of the inserted TOC. Using that special comment, this [[https://github.com/kaushalmodi/hugo-bare-min-theme/blob/master/layouts/partials/summary_minus_toc.html][=summary_minus_toc.html=]] partial tries to get the "summary you mean". This partial is used by the =ox-hugo= test site. - You can find examples of where this partial can be used in [[https://github.com/kaushalmodi/hugo-bare-min-theme/blob/master/layouts/partials/opengraph.html][=opengraph.html=]] and [[https://github.com/kaushalmodi/hugo-bare-min-theme/blob/master/layouts/partials/twitter_cards.html][=twitter_cards.html=]] partials, also used in the test site. /Note that you would need to use the =summary_minus_toc.html= partial wherever you do not intend to have TOC included in the summary (for example, in the Opengraph =og:description= meta tag)./ **** Hiding bullets when TOC has numbered headings Add this to the CSS to hide bullets in table of contents when the headings are numbered. Export options set like ~#+options: toc:t num:t~ will cause this. #+begin_src css /* Hide bullets in TOC when headings are numbered. */ .toc.has-section-numbers ul { list-style: none; } #+end_src *** Table Styling :PROPERTIES: :EXPORT_FILE_NAME: table-styling :END: Classic =ox-html= allows setting table attributes directly using =#+attr_html=. But specifying the attributes directly in the == tag is [[https://www.w3.org/TR/2011/WD-html-markup-20110113/table.html#table-constraints][admonished in HTML5]] .. /and so Hugo/Blackfriday do not allow any way to directly insert attributes *inside* the =
= tag./ So a workaround is used by =ox-hugo=.. it wraps the tables with =
= tags with classes, which a user can then use to style the tables using CSS.. /just as recommended by HTML5/ :smile:. =ox-hugo= can style different tables in different ways on the same page, with the help of =#+attr_html= and =#+attr_css= (*introduced in =ox-hugo=*) attributes. 1. =#+attr_html= is used to assign one or more classes to a table. #+begin_src org ,#+attr_html: :class sane-table #+end_src - Wraps the table in =
= tags with =sane-table= class. - Sets style from =#+attr_css=, if present, for =.sane-table table= scope. or #+begin_src org ,#+attr_html: :class zebra-striping sane-table #+end_src - Wraps the table in =
= tags with =zebra-striping= *and* =sane-table= classes. - Sets style from =#+attr_css=, if present, *only* for the =.zebra-striping table= scope i.e. only for the first class listed in that attribute. Specifying multiple classes to a table is useful if you want that table to inherit the styling from CSS rules for multiple classes. 2. =#+attr_css= is used to assign the specified styles to the class of the table it precedes. Examples: #+begin_src org ,#+attr_css: :width 80% #+end_src #+begin_src org ,#+attr_css: :text-align left #+end_src - If =#+attr_html= is used to specify the table class, the style is applied to the first of the list of classes (as explained above). - If =#+attr_html= is *not* used to set a custom class name for the table, the class name is auto-derived.. - If the table =#+caption= is present, the class name is =table-N= where "N" is the /Nth/ captioned table on that page. - If the table is not captioned, the class name is always =table-nocaption=. So.. if you want to have different styling for different tables, make sure that you either set their custom class name using =#+attr_html=, or caption them. - All tables exported with the =
= tags have the class =ox-hugo-table=. This can be useful if you want to set a common style for all those tables. - =#+attr_css= applies styling only to the =.CLASS table= scope. So if you want more styling i.e. for other elements like =td=, =tr=, etc, you would need to do that in an =#+export_begin html= block. Example: #+begin_src org ,#+begin_export hugo ,#+end_export ,#+caption: Table with verbatim CSS ,#+attr_html: :class my-table | h1 | h2 | h3 | |-----+-----+-----| | abc | def | ghi | #+end_src You can find many examples of table styling here: #+caption: Table Styling Examples #+attr_html: :class sane-table | Org Source | Exported Markdown | Hugo HTML | |----------------------------------------------------------------------------------------------+-------------------+-------------| | {{{ox-hugo-test-file}}} -- search for =* Table Styling= or =:EXPORT_FILE_NAME: table-styling= | [[https://raw.githubusercontent.com/kaushalmodi/ox-hugo/main/test/site/content/posts/table-styling.md][table-styling.md]] | [[https://ox-hugo.scripter.co/test/posts/table-styling/][Hugo output]] | ----- /Credit: [[https://css-tricks.com/complete-guide-table-element/][Guide to styling tables in HTML5-friendly manner]]/ --- /css-tricks.com/ **** Hiding table caption numbers The "Table :" part of the table captions can be hidden by adding this to the CSS: #+begin_src css .table-number { display: none; } #+end_src *** Details and summary :PROPERTIES: :EXPORT_FILE_NAME: details-and-summary :END: The "details" Org Special Block (~#+begin_details~ .. ~#+end_details~) is used for generating the Details disclosure elements [[https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details][~
~]] and ~~. The summaries nested in these "details" Org Special blocks are created using the "summary" Org Special block ~#+begin_summary~ .. ~#+end_summary~. **** Regular details disclosure #+begin_src org ,#+begin_details ,#+begin_summary Why is this in *green*? ,#+end_summary You will learn that later below in [[#details-css][CSS]] section. ,#+end_details #+end_src will render like below: #+begin_details #+begin_summary Why is this in *green*? #+end_summary You will learn that later below in [[#details-css][CSS]] section. #+end_details **** Details disclosure without details or without summary - If the ~details~ Special Block does not contain the ~summary~ Special Block, a details-only disclosure will be created. #+begin_src org ,#+begin_details Here are the /details/. ,#+end_details #+end_src will render like below: #+begin_details Here are the /details/. #+end_details #+begin_note In the absence of summary, most browsers will use a default string "Details" for the summary. #+end_note - If the ~details~ Special Block contains *only* the ~summary~ Special Block, a summary-only disclosure will be created. #+begin_src org ,#+begin_details ,#+begin_summary Some Summary ,#+end_summary ,#+end_details #+end_src will render like below: #+begin_details #+begin_summary Some Summary #+end_summary #+end_details #+begin_note Even if the details part is absent, the collapsing triangle will still be rendered. But nothing will show up when that triangle is uncollapsed.. /as the details portion is not there/. #+end_note **** Disclosure widget open by default The ~
~ disclosure widget is initially closed by default. But it can be made to show up opened by default by adding the ~:open t~ attribute like this: #+begin_src org ,#+attr_html: :open t ,#+begin_details ,#+begin_summary Some Summary ,#+end_summary Here are the /details/. ,#+end_details #+end_src will render like below: #+attr_html: :open t #+begin_details #+begin_summary Some Summary #+end_summary Here are the /details/. #+end_details #+begin_note For open-by-default disclosure widgets, the ~#+attr_html~ keyword specifically needs to contain ~:open t~. #+end_note **** CSS rules for these widgets :PROPERTIES: :CUSTOM_ID: details-css :END: - ~details summary~ will apply to the /summary/ portion of the disclosure widget. - ~details .details~ will apply to the /details/ portion of the disclosure widget. #+html: #+html: For instance, the CSS rules set using below caused all the disclosure /summaries/ to show in green, and all the disclosure /details/ to show in blue. #+begin_src org #+html: #+html: #+end_src #+html: #+html: *** Author :PROPERTIES: :EXPORT_FILE_NAME: author :END: The ~author~ front-matter parameter is designed to *always be a list or an array*, so that multiple authors can be supported. **** Default Author The ~author~ parameter is set to always export by default (as the default value of ~org-export-with-author~ is ~t~). The author name defaults to ~user-full-name~. You can choose to either customize this variable in your Emacs config, or manually set the author name by adding the below to the top of your Org file: #+begin_src org ,#+author: FirstName LastName #+end_src If using /per-subtree/ flow, and if you want to specify the author (or override the value set by the above ~#+author~ keyword) differently for all posts under a subtree, add below in that subtree's property drawer: #+begin_src org :PROPERTIES: :EXPORT_AUTHOR: Firstname LastName :END: #+end_src Either of above two author-setting methods will export to this TOML front-matter: #+begin_src toml author = ["FirstName LastName"] #+end_src **** Multiple Authors Multiple authors can be specified by either: - Using multiple ~#+author~ keywords, or #+begin_src org ,#+author: FAuthor1 LAuthor1 ,#+author: FAuthor2 LAuthor2 #+end_src - Specifying comma-separated authors, if setting them in subtree properties. #+begin_src org :PROPERTIES: :EXPORT_AUTHOR: FAuthor1 LAuthor1, FAuthor2 LAuthor2 :END: #+end_src Either of above two author-setting methods will export to this TOML front-matter: #+begin_src toml author = ["FAuthor1 LAuthor1", "FAuthor2 LAuthor2"] #+end_src **** Disabling exporting of ~author~ parameter Author exporting can be disabled using any of these ways: - To disable author exporting only for a specific Org file, add below to the top of that file: #+begin_src org ,#+options: author:nil #+end_src - If using /per-subtree/ flow, and if you want to disable author exporting only for posts under specific subtrees, add below in the property drawers of those: #+begin_src org :PROPERTIES: :EXPORT_OPTIONS: author:nil :END: #+end_src - To disable author exporting by default for all exporters (not just ~ox-hugo~), set ~org-export-with-author~ to ~nil~ in your Emacs config. **** Tweaking your Hugo template to support /list/ ~author~ #+begin_note The ~author~ front-matter parameter is *always* exported as a TOML/YAML *list*. #+end_note If you have Hugo posts with the ~author~ front-matter already set, it is possible that those values exist as single string values instead of lists. If so, you can use an ~author.html~ Hugo partial[fn:10] like below to parse the ~author~ parameter correctly, whether it's a plain string or a /slice/ (list) of strings. #+name: code__author_partial #+caption: ~author.html~ partial code that supports both ~string~ and ~slice~ (list) type ~author~ front-matter #+begin_src go-html-template {{ with .Params.author }} — {{ if (reflect.IsSlice .) }} {{ delimit . ", " }} {{ else }} {{ . }} {{ end }} {{ end }} #+end_src ***** Forcing ~author~ to be a /string/ (alternative 1) If you are not comfortable with Hugo templates, you can alternatively force the ~author~ param to be a plain /string/ instead of a /list/, by setting it as a /custom/ front-matter parameter: #+begin_src org ,#+author: ,#+hugo_custom_front_matter: :author "FirstName LastName" #+end_src - Note :: Remember to set the default author name to nil if doing this, by setting the ~#+author~ keyword (or ~:EXPORT_AUTHOR:~ property) to /nothing/. ***** Exporting the list of authors to ~authors~ front-matter instead of ~author~ (alternative 2) If your theme supports parsing a list of authors from an ~authors~ front-matter parameter (instead of ~author~), use the ~#+hugo_front_matter_key_replace~ feature as shown {{{titleref(Replace Front-matter Keys#replace-author-with-authors,here)}}}. *** Hugo Summary Splitter :PROPERTIES: :EXPORT_FILE_NAME: hugo-summary-splitter :END: #+begin_description Manual splitting of Hugo summary. #+end_description In Hugo, the point of split between the summary and main content can be specified using the ~<​!--more-->~ HTML snippet. See [[https://gohugo.io/content-management/summaries/#manual-summary-splitting][its documentation]] for more information. The recommended way to do that in the Org files you export using ~ox-hugo~ is to use ~#+hugo: more~. Here's an example: #+begin_src org My post summary. ,#+hugo: more My post content. #+end_src *** Drawers :PROPERTIES: :EXPORT_FILE_NAME: drawers :END: #+begin_description How Org Drawers get exported to front-matter. #+end_description #+begin_note This feature will work only if the ~org-hugo-front-matter-format~ is left at its default value of ~"toml"~. #+end_note See [[info:org#Drawers]] to learn more about the Org Drawers feature. **** ~:LOGBOOK:~ Drawer :PROPERTIES: :CUSTOM_ID: logbook-drawer :END: Ox-hugo supports parsing of these two kinds of information from the ~:LOGBOOK:~ drawers: 1. /TODO/ state changes saved to these drawers. 2. Notes saved to the ~:LOGBOOK:~ drawers. #+begin_note The ~:LOGBOOK:~ dates and notes exporting features work only if the ~org-log-note-headings~ variable is left uncustomized, at its default value. #+end_note These features work only if: 1. ~org-log-into-drawer~ (or the ~:LOG_INTO_DRAWER:~ subtree property) is set to a non-nil value[fn:13], *and* 2. Drawer exporting is enabled. You can enable that using ~#+options: d:t~ keyword or ~:EXPORT_OPTIONS: d:t~ subtree property[fn:14]. With ~:LOG_INTO_DRAWER:~ enabled, the ~:LOGBOOK:~ drawer (default name of this drawer) is created immediately after the Org heading whose state changed or under the heading where the ~org-add-note~ command (bound by default to ~C-c C-z~) was called. ***** Dates parsed from ~:LOGBOOK:~ /TODO/ state changes :PROPERTIES: :CUSTOM_ID: logbook-dates :END: - ~date~ :: This front-matter variable is updated with the timestamp associated with the *first* TODO state transition to one of the ~org-done-keywords~ values[fn:15] i.e. transition to /DONE/ state. - ~lastmod~ :: This front-matter variable is updated with the timestamp associated with the *last* TODO state transition to the /DONE/ state, or with the *last* added note (whichever is the latest). #+begin_note The ~date~ and ~lastmod~ values parsed from the ~:LOGBOOK:~ drawer state transitions will have the highest precedence. See {{{titleref(Org meta-data to Hugo front-matter#front-matter-precedence,Front-matter Precedence)}}} for more info. #+end_note ***** ~:LOGBOOK:~ Notes - Notes added to the ~:LOGBOOK:~ drawer under the post heading will be exported to the TOML Table Array ~[[logbook._toplevel.notes]]~ in the page front-matter. Here, *_toplevel* is a special/reserved TOML Table name to store notes associated with the post's main heading. - Notes added to the ~:LOGBOOK:~ drawer under a post's sub-heading will be exported to the TOML Table Array ~[[logbook..notes]]~ in the page front-matter. By design, Ox-hugo exports the ~:LOGBOOK:~ drawer notes as /data/ to the front-matter, and user is given the freedom on where and how to render that data. ***** ~logbook~ front-matter Hugo templating examples This section shared just one of the ways to render the ~logbook~ front-matter data using Hugo templates. Create ~layouts/partials/logbook_notes.html~ in your Hugo site repo with these contents: #+name: code__logbook_notes_partial #+caption: ~logbook_notes.html~ Hugo Partial #+begin_src go-html-template {{ with .page.Param .notes_param }}
{{ range . }}
{{ printf `<%s>` (time.Format "2006-01-02" .timestamp) | safeHTML }}
{{ .note | $.page.RenderString | emojify }}
{{ end }}
{{ end }} #+end_src This partial accepts a Hugo *dict* input argument with keys *page* and *notes_param*. ****** Example of rendering "_toplevel" notes Here's an example of how one could use that partial in the ~single.html~ template: #+name: code__rendering_toplevel_logbook_notes #+caption: Example of using ~logbook_notes.html~ Hugo Partial in ~single.html~ layout file #+begin_src go-html-template {{ partial "logbook_notes.html" (dict "page" $.Page "notes_param" "logbook._toplevel.notes") }} #+end_src Above, - The ~page~ key is passed the context of the current page: ~$.Page~. - The ~notes_param~ key is passed the hierarchical path to the /toplevel/ Logbook notes: ~"logbook._toplevel.notes"~. ****** Example of rendering notes under sub-headings Hugo's [[https://gohugo.io/templates/render-hooks/#heading-link-example][Render Hooks for Headings]] feature can be leveraged for rendering notes entered in ~:LOGBOOK:~ drawers under sub-headings in a post. Create ~layouts/_default/_markup/render-heading.html~ in your Hugo site repo with these contents: #+name: code__rendering_sub_heading_logbook_notes #+caption: Example of using ~logbook_notes.html~ Hugo Partial in ~render-heading.html~ #+begin_src go-html-template {{ .Text | safeHTML }} # {{ partial "logbook_notes.html" (dict "page" $.Page "notes_param" (printf "logbook.%s.notes" .PlainText)) }} #+end_src Above, the same ~logbook_notes.html~ partial is used but with the ~notes_param~ key set differently --- This time, it derives the hierarchical path to the ~logbook. .. .notes~ TOML Table Array using the Heading Render Hook's ~.PlainText~ variable. For example, if the sub-heading title is "Example of rendering notes under sub-headings", the value of ~.PlainText~ for that heading will be the same. *** COMMENT Hyperlinks :PROPERTIES: :EXPORT_FILE_NAME: hyperlinks :END: **** External Links **** Internal Links ** Enhancements :PROPERTIES: :EXPORT_HUGO_MENU: :menu "6.enhancements" :END: *** Auto-export on Saving :PROPERTIES: :EXPORT_FILE_NAME: auto-export-on-saving :END: Wouldn't it be awesome if you can see the live-preview of your Hugo-rendered post each time you saved your post in Org? Well.. you can do that with these steps, which apply to both /per-subtree/ and /per-file/ flows: **** First time setup ***** Step {{{n}}}: Enable minor mode =org-hugo-auto-export-mode= This minor mode is disabled by default. It can be enabled separately at project level or file level. #+begin_note Note that once you update the ~.dir-locals.el~ file or file-local Variables as shown below, you will be prompted by Emacs to tell it if those settings are safe. Hit ~!~ in that prompt to says /yes/ and to save that choice for future Emacs sessions. #+end_note ****** Enable for the whole project If you want to enable auto-exporting for the whole project, add this to the ~.dir-locals.el~ file in the project root: #+begin_src emacs-lisp (("content-org/" . ((org-mode . ((eval . (org-hugo-auto-export-mode))))))) #+end_src Above assumes that the Org files are in the /"content-org/"/ directory (at any nested level in there) relative to that =.dir-locals.el= file: #+begin_example ├── config.toml ├── content ├── content-org <-- Org files in there ├── static ├── themes └── .dir-locals.el #+end_example If you have the Org file directly in the project root or in the same directory as the ~.dir-locals.el~, add this in that file instead: #+begin_src emacs-lisp ((org-mode . ((eval . (org-hugo-auto-export-mode))))) #+end_src Note that with above, ~org-hugo-auto-export-mode~ will be enabled for *all* Org files in the project. If you do not want that, see [[* Enable only for an Org file]]. ******* Enabling for multiple projects To enable auto-exporting for multiple projects, simply add similar =.dir-locals.el= files to the root directories of those projects. Just ensure that the relative Org file directories, like the /"content-org/"/ in above example, are set correctly. ****** Enable only for an Org file Add below to the very-end of your Org file and *save the file*: #+begin_src org ,* Footnotes ,* COMMENT Local Variables :ARCHIVE: # Local Variables: # eval: (org-hugo-auto-export-mode) # End: #+end_src *About Footnotes*: Here I recommend adding the =* Footnotes= header[fn:5] too so that in case you add any Org footnotes, they go directly to that section you created. Otherwise, Org will auto-create a new /Footnotes/ heading *at the end of the file*.. and the /Local Variables/ heading would then no longer be at the end of the file. ****** Enable for the whole project except for few Org files 1. Enable the auto-exporting for the whole project as explained [[* Enable for the whole project][above]]. 2. Then add below to the end of the Org file where you need to disable the auto-exporting: #+begin_src org ,* Footnotes ,* COMMENT Local Variables :ARCHIVE: # Local Variables: # eval: (org-hugo-auto-export-mode -1) # End: #+end_src Note that this time, =org-hugo-auto-export-mode= is disabled to override its enabled state in =.dir-locals.el=. #+begin_note After updating the state of =org-hugo-auto-export-mode= using either of the above methods, remember to: 1. Save the Org file where you expect the auto-exporting to work. 2. Revert the buffer (~M-x revert-buffer~). That will ensure that the updated state for the =org-hugo-auto-export-mode= minor mode is effective. #+end_note **** Steps that /might/ need to be taken every time Once the initial setup is done, the following steps apply to both blogging flows. ***** Step {{{n}}}: Start the engines (Hugo Server) We start the =hugo server= so that we can see the live-preview each time the Org file is saved[fn:6]. Run below in your Hugo site root (the directory that contains the site =config.toml=) to start the server: #+begin_example hugo server -D --navigateToChanged #+end_example ***** Step {{{n}}}: Open your browser By default the site is served locally on port /1313/ on /localhost/. So the above step would have printed something like below at the end: #+begin_example Web Server is available at http://localhost:1313/ (bind address 127.0.0.1) #+end_example So open your favorite browser pointing to that address. **** FINAL step that needs to be taken every time ***** Step {{{n}}}: Save and be in awe If you are like me, you might not need to repeat steps 3 and 4 above, as you can leave the =hugo= server running in a separate terminal, and have a browser tab pinned to that localhost. So with that, have the Emacs and browser frames set up side-by-side, and edit your Org post. Hit =C-x C-s= and be in awe as the browser auto-refreshes to the *exact post you modified*! *** Org Capture Setup :PROPERTIES: :EXPORT_FILE_NAME: org-capture-setup :END: **** An Org Capture template If you do not want to manually type the =EXPORT_FILE_NAME= for each new post, here is an example Org Capture template can help: #+begin_src emacs-lisp ;; Populates only the EXPORT_FILE_NAME property in the inserted heading. (with-eval-after-load 'org-capture (defun org-hugo-new-subtree-post-capture-template () "Returns `org-capture' template string for new Hugo post. See `org-capture-templates' for more information." (let* ((title (read-from-minibuffer "Post Title: ")) ;Prompt to enter the post title (fname (org-hugo-slug title))) (mapconcat #'identity `( ,(concat "* TODO " title) ":PROPERTIES:" ,(concat ":EXPORT_FILE_NAME: " fname) ":END:" "%?\n") ;Place the cursor here finally "\n"))) (add-to-list 'org-capture-templates '("h" ;`org-capture' binding + h "Hugo post" entry ;; It is assumed that below file is present in `org-directory' ;; and that it has a "Blog Ideas" heading. It can even be a ;; symlink pointing to the actual location of all-posts.org! (file+olp "all-posts.org" "Blog Ideas") (function org-hugo-new-subtree-post-capture-template)))) #+end_src Above capture will auto-insert a heading prefixed with =TODO=. With =org-log-done= set to ='time=, on changing the =TODO= state to the =DONE= state (=C-c C-t=), a [[info:org#Special Properties][/Special Property/]] called =CLOSED= will be auto-inserted below the heading. Below is an example. #+begin_example ,*** DONE Narrowing the Author column in Magit :org:log: CLOSED: [2017-12-18 Mon 16:36] #+end_example =ox-hugo= auto-sets the =date= field in the front-matter to the time stamp in that =CLOSED= property. **** Alternative way: Export Hugo posts to a /Page Bundle/ organization :PROPERTIES: :CUSTOM_ID: org-capture-template-page-bundle :END: =ox-hugo= has /first-class/ support for the [[https://scripter.co/hugo-leaf-and-branch-bundles/][Page Bundles]] style of content organization, introduced in Hugo v0.32. If you prefer to have the exported posts to use the Page Bundles style of content organization, define the same =org-hugo-new-subtree-post-capture-template= as below: #+begin_src emacs-lisp (defun org-hugo-new-subtree-post-capture-template () "Returns `org-capture' template string for new Hugo post. See `org-capture-templates' for more information." (let* ((title (read-from-minibuffer "Post Title: ")) ;Prompt to enter the post title (fname (org-hugo-slug title))) (mapconcat #'identity `( ,(concat "* TODO " title) ":PROPERTIES:" ,(concat ":EXPORT_HUGO_BUNDLE: " fname) ":EXPORT_FILE_NAME: index" ":END:" "%?\n") ;Place the cursor here finally "\n"))) #+end_src **** Alternative way to set the =date= field :PROPERTIES: :CUSTOM_ID: org-capture-template-export-date :END: If you prefer to not insert time-stamps using the =DONE=-state switching (i.e. you have =org-log-done= at its default value of =nil=), you can explicitly insert the =EXPORT_DATE= property too using the below definition of =org-hugo-new-subtree-post-capture-template= instead. #+begin_src emacs-lisp (defun org-hugo-new-subtree-post-capture-template () "Returns `org-capture' template string for new Hugo post. See `org-capture-templates' for more information." (let* (;; http://www.holgerschurig.de/en/emacs-blog-from-org-to-hugo/ (date (format-time-string (org-time-stamp-format :long :inactive) (org-current-time))) (title (read-from-minibuffer "Post Title: ")) ;Prompt to enter the post title (fname (org-hugo-slug title))) (mapconcat #'identity `( ,(concat "* TODO " title) ":PROPERTIES:" ,(concat ":EXPORT_FILE_NAME: " fname) ,(concat ":EXPORT_DATE: " date) ;Enter current date and time ":END:" "%?\n") ;Place the cursor here finally "\n"))) #+end_src *** Images in Content :PROPERTIES: :EXPORT_FILE_NAME: images-in-content :END: Conventionally any static content for a Hugo site, like images, PDF files, and other attachments are put in the site =static/= directory. Files in that directory are served at the site root when the Hugo publishes that site. So all the content in there can be accessed using the root prefix =/=. So a =static/foo.png= file can be accessed at =/foo.png=. More detail for this conventional approach can be found in the documentation for [[#references-to-files-in-the-static-directory][referencing files in static directory]]. **** Images and Regular Pages OK, so with that short intro out of the way, =ox-hugo= supports putting the /attachment files/ in the same directory as the source Org files! In the below example, the left hand side shows the Org content and attachment file organization that the user would need to do manually. And the right hand side shows the structure that =ox-hugo= will generate in the =content/= and =static/= (the /conventional/ way discussed above) directories. #+begin_example ./content-org ├── images-in-content/ │ ├── images-in-content.org │ │ * Post 1 (Org subtree) → ./content/images-in-content/post1.md │ │ * Post 2 (Org subtree) → ./content/images-in-content/post2.md │ ├── gnu.png → ./static/ox-hugo/gnu.png │ └── org.png → ./static/ox-hugo/org.png ├── post3/ │ ├── post3.org → ./content/images-in-content/post3.md │ └── gnu-copy.png → ./static/ox-hugo/gnu-copy.png └── post4/ ├── post4.org → ./content/images-in-content/post4.md └── org-copy.png → ./static/ox-hugo/org-copy.png #+end_example Have a look at the [[https://raw.githubusercontent.com/kaushalmodi/ox-hugo/main/test/site/content-org/images-in-content/images-in-content.org][=content-org/images-in-content/images-in-content.org=]] file for an example of how to reference same-directory files (=gnu.png= and =org.png= in this example) in an Org file (/Hint: Just as you would do in a normal Org file/). The benefit of this /same-directory-attachment/ approach is that you don't need to use any directory prefix to reference those files (example: =[[file:gnu.png]]=). When =ox-hugo= exports those posts though, the images are auto-copied to the =static/ox-hugo/= directory[fn:1] and =/ox-hugo/= prefix is added to those file references in the exported Markdown files. Also as the image file references are valid within the Org file, you can see those images inline too! #+attr_html: :alt Screenshot of an Org mode buffer showing image in content [[file:/images/images-in-content-screenshot.png]] ***** Examples :PROPERTIES: :CUSTOM_ID: images-and-regular-bundles-examples :END: Whether you prefer the subtree-based approach or file-based approach for writing your posts in Org, there are examples for both in the =ox-hugo= test suite: - [[https://github.com/kaushalmodi/ox-hugo/tree/main/test/site/content-org/images-in-content][Org source]] - [[https://github.com/kaushalmodi/ox-hugo/tree/main/test/site/content/images-in-content][Exported Markdown]] **** Images and Page Bundles /See [[*Hugo Bundle][Hugo Bundle]] section on how to define those via ~ox-hugo~./ *Only for page bundles*, when a link points to a local attachment, and the image path contains the hugo bundle name, following attachment copying rules apply: - Assume that the bundle is a /Leaf Bundle/ and its name is ~bundle-1~ (~:EXPORT_HUGO_BUNDLE: bundle-1~) and that the image (attachment) path relative to the Org file is ~some-dir-1/bundle-1/some-dir-2/image.png~. - The attachment's path relative to "bundle-1" is retained and copied to the "bundle-1" directory in the content dir. The /path before/ the "bundle-1" in the attachment path is ignored. - So after the export, we will see a directory structure like this in the content dir: #+begin_example ./content .. └── bundle-1 ├── index.md └── some-dir-2/image.png #+end_example #+begin_note If the attachment path does _not_ contain the bundle name, it will be copied as usual to the ~static/~ directory (See the documentation for [[#references-to-files-in-the-static-directory][referencing files in static directory]]). #+end_note ***** Examples :PROPERTIES: :CUSTOM_ID: images-and-page-bundles-examples :END: #+begin_example ./content-org ├── posts.org │ * Bundle 1 (Org subtree) → ./content/bundle-1/index.md │ [[file:bundle-1/image1.png]] │ [[file:images/bundle-1/image.png]] │ │ * Bundle 2 (Org subtree) → ./content/bundle-2/index.md │ [[file:images/bundle-2/some-dir/image.png]] │ ├── bundle-1 │ └── image1.png → ./content/bundle-1/image1.png └── images/ ├── bundle-1 │ └── image2.png → ./content/bundle-1/image2.png └── bundle-2 └── some-dir └── image.png → ./content/bundle-2/some-dir/image.png #+end_example Another example from the test suite: - [[https://raw.githubusercontent.com/kaushalmodi/ox-hugo/main/test/site/content-org/images-in-content/images-in-content.org][~images-in-content.org::* Page Bundle with images in the same dir~]] | [[https://raw.githubusercontent.com/kaushalmodi/ox-hugo/main/test/site/content/images-in-content/page-bundle-images-in-same-dir/index.md][Exported Markdown]] | [[https://ox-hugo.scripter.co/test/images-in-content/page-bundle-images-in-same-dir/][HTML]] *** Replace Front-matter Keys :PROPERTIES: :EXPORT_FILE_NAME: replace-front-matter-keys :END: This is a =ox-hugo=-unique feature that allows you to replace any front-matter key name to accommodate for your favorite Hugo theme. #+hugo: more The syntax is: #+begin_src org ,#+hugo_front_matter_key_replace: oldkey1>newkey1 oldkey2>newkey2 #+end_src or, if you want this to apply only for a specific Org tree: #+begin_src org :EXPORT_HUGO_FRONT_MATTER_KEY_REPLACE: oldkey1>newkey1 oldkey2>newkey2 #+end_src Here are few use cases to better explain this feature. - Note :: I use property drawers in the below examples (used in subtree-based flow). But the same would work for the Org keyword equivalents in file-based flow too. **** {{{sec(1,)}}} Use =description= in Org file, but export as =summary= The /Description/ meta-data is standard in Org. Starting with *v0.55.0*, Hugo now supports ~summary~ as a built-in front-matter variable to directly specify the post /summary/. See Hugo commit [[https://github.com/gohugoio/hugo/commit/3a62d54745e2cbfda6772390830042908d725c71][3a62d547]] for details. #+begin_note ~ox-hugo~ has also been supporting the ~description~ front-matter variable. So support for the new ~summary~ front-matter variable, which is essentially a duplicate of ~description~, is not added explicitly. #+end_note As the ~summary~ parameter does not have explicit support in ~ox-hugo~, you would need to set it using the following property: #+begin_src org :EXPORT_HUGO_CUSTOM_FRONT_MATTER: :summary "Here is my post summary." #+end_src But instead, you can simply add this at the top of your Org file: #+begin_src org #+hugo_front_matter_key_replace: description>summary #+end_src and then use ~description~ to do the same: #+begin_src org :EXPORT_DESCRIPTION: Here is my post summary. #+end_src It gets even better if you use the {{{relref(*description* Org Special Block,org-special-blocks#description)}}}: #+begin_src org ,#+begin_description Here is my *post summary*. And this can be over /multiple lines/ too! ,#+end_description #+end_src By doing above, you would be using /description/ in your Org source, but that would get exported as /summary/ in the Markdown! :smile: **** {{{sec(1,)}}} Use Org tags, but export as =keywords= Here's another scenario.. you painstakingly set Org tags for all your posts, and then you switch to a theme that calls refers to your =tags= as =keywords= instead! Captain =HUGO_FRONT_MATTER_KEY_REPLACE= is here to help you again! :sunglasses: Just add this at the top of your Org file: #+begin_src org ,#+hugo_front_matter_key_replace: tags>keywords #+end_src **** {{{sec(1,)}}} Swap =tags= and =categories= And one more example.. you call them /tags/, the Hugo theme calls them /categories/, and vice-versa. What do you do? .. #+begin_src org ,#+hugo_front_matter_key_replace: tags>categories categories>tags #+end_src **** {{{sec(1,)}}} Removing front-matter keys during export :PROPERTIES: :CUSTOM_ID: removing-keys :END: In the front-matter key replacement syntax: #+begin_src org ,#+hugo_front_matter_key_replace: oldkey>newkey #+end_src If ~newkey~ is a special string *nil*, ~oldkey~ will be _removed_ from the exported front-matter. For example, if you want to remove the ~aliases~ front-matter from your exported files (but want to leave them in your Org files), simply add this to the top of your Org files: #+begin_src org ,#+hugo_front_matter_key_replace: aliases>nil #+end_src **** {{{sec(1,)}}} Replacing the ~author~ with ~authors~ in front-matter :PROPERTIES: :CUSTOM_ID: replace-author-with-authors :END: Some themes like [[https://github.com/HEIGE-PCloud/DoIt][DoIt]] support parsing a list of authors from an ~authors~ front-matter parameter. But ~ox-hugo~ always exports authors _as a list_ to the [[*Author][~author~ front-matter parameter]]. You can have ~ox-hugo~ export the list of authors to the ~authors~ front-matter by adding this to the top of your Org files: #+begin_src org ,#+hugo_front_matter_key_replace: author>authors #+end_src **** Examples You can find a bunch of examples if you search for /"Replace front-matter keys"/ in {{{ox-hugo-test-file}}}. - Those examples are exported as {{{testtag(replace)}}}. *** Org Cite Citations :PROPERTIES: :EXPORT_FILE_NAME: org-cite-citations :END: #+include: "../test/site/content-org/all-posts.org::*Org Cite Basic Example" :only-contents t #+begin_note The Ox-Hugo Pandoc Citation feature needs to be disabled for Org Cite based citation processing to work. So make sure that you don't have ~:EXPORT_HUGO_PANDOC_CITATIONS: t~ in your post tree or ~#+hugo_pandoc_citations: t~ in your Org file! #+end_note **** Citation Processor: CSL The [[https://citationstyles.org/][Citations Style Language]] (CSL) defines how the citations and bibliographies should be exported. Using CSL is optional, and dependent on an external package [[https://github.com/andras-simonyi/citeproc-el][~citeproc.el~]]. By default CSL is not enabled and the citations and bibliographies will be exported to Markdown in plain text i.e. without any emphasis, hyperlinking, etc. To enable <<>>: 1. Install ~citeproc~ from [[https://melpa.org/#/citeproc][Melpa]]. 2. Add this to the top of your Org file: ~#+cite_export: csl~ That's it! The Org built-in library ~oc-csl.el~ will autoload ~citeproc~ when it sees that ~#+cite_export~ keyword. With CSL processing enabled, the citations and bibliographies will now be exported in HTML embedded in the exported Markdown files. Check out the [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html#using-csl][/This Month in Org/ -- July 2021]] post for more information. **** Auto-inserting /Bibliography/ heading :PROPERTIES: :CUSTOM_ID: bibliography-heading :END: #+begin_mark If CSL-formatted exports are enabled #+end_mark , a Markdown heading named "References" will be auto-inserted above the /bibliography/ section. This section is exported if the Org file has {{{relref(~#print_bibliography:~ keyword,#printing-bibliography)}}}. This feature is controlled by the ~org-hugo-citations-plist~ property list variable. **** ~org-hugo-citations-plist~ :PROPERTIES: :CUSTOM_ID: org-hugo-citations-plist :END: This property list recognizes this property: - :bibliography-section-heading :: /(string)/ Heading to insert before the bibliography section. The default value is "References". Some users might choose to customize this value to "Bibliography". Here's an example of how that can be done in the Emacs config: #+name: code__customizing_bibliography_heading #+caption: Customizing bibliography heading #+begin_src emacs-lisp (with-eval-after-load 'ox-hugo (plist-put org-hugo-citations-plist :bibliography-section-heading "Bibliography")) #+end_src If this property is set to an empty string, this heading will not be auto-inserted. #+name: code__bibliography_no_heading #+caption: Disabling bibliography heading insertion #+begin_src emacs-lisp (with-eval-after-load 'ox-hugo (plist-put org-hugo-citations-plist :bibliography-section-heading "")) #+end_src **** Example Minimal example with ~org-cite~ citations: #+name: code_citation_org_cite #+caption: Example of ~org-cite~ citation #+begin_src org #+title: Citation using ~org-cite~ #+hugo_base_dir: ../ #+bibliography: /path/to/file.bib #+cite_export: csl [cite:@SomeCitation] Below, the "References" heading will be auto-inserted. #+print_bibliography: #+end_src *** Org Ref Citations :PROPERTIES: :EXPORT_FILE_NAME: org-ref-citations :END: [[https://github.com/jkitchin/org-ref][org-ref]] citations can be exported to Hugo-compatible markdown/HTML by calling ~(org-ref-process-buffer 'html)~ in the ~org-export-before-parsing-hook~ hook. Here's an example of how to do that using ~use-package~: #+begin_src emacs-lisp (use-package org-ref :ensure t :init (with-eval-after-load 'ox (defun my/org-ref-process-buffer--html (backend) "Preprocess `org-ref' citations to HTML format. Do this only if the export backend is `html' or a derivative of that." ;; `ox-hugo' is derived indirectly from `ox-html'. ;; ox-hugo <- ox-blackfriday <- ox-md <- ox-html (when (org-export-derived-backend-p backend 'html) (org-ref-process-buffer 'html))) (add-to-list 'org-export-before-parsing-hook #'my/org-ref-process-buffer--html))) #+end_src **** Example Minimal example with ~org-ref~ citations: #+name: code_citation_org_ref #+caption: Example of ~org-ref~ citation #+begin_src org #+title: Citation using ~org-ref~ #+hugo_base_dir: ../ [[cite:&SomeCitation]] Below, the "References" heading will be auto-inserted. [[bibliography:/path/to/file.bib]] #+end_src *** Pandoc Citations :PROPERTIES: :EXPORT_FILE_NAME: pandoc-citations :END: #+begin_note Org mode has built-in supporting for exporting citations starting #+begin_mark version 9.5 #+end_mark . See [[*Org Cite Citations][Org Cite Citations]] for more info. #+end_note The [[https://pandoc.org/][Pandoc]] Citations are prefixed with the *@* character. If the citation is ~@foo~, that particular /foo/ reference much be present in one of the specified bibliography files. #+begin_note Users need to have the ~pandoc~ executable[fn:7] present in the ~PATH~. #+end_note **** Enabling Pandoc based citation parsing is enabled by setting the ~#+hugo_pandoc_citations:~ keyword or ~:EXPORT_HUGO_PANDOC_CITATIONS:~ subtree property to ~t~. #+begin_note If a post has neither [[* Nocite][~nocite~]] meta-data, nor valid citation keys (~@foo~), the Pandoc parsing step is skipped *even if* the above Pandoc Citations parsing option is enabled. #+end_note **** Bibliography Bibliography files (~example.bib~) are specified using the ~#+bibliography:~ keyword or ~:EXPORT_BIBLIOGRAPHY:~ subtree property. *It is mandatory to specify at least one bibliography file.* Multiple comma-separated bibliography files can be specified. /Note that the path to these bibliography files is relative to the Org file directory./ **** Nocite ~nocite~ is a special Pandoc-specific meta-data which can be used to add extra citations even when they are not referenced in the post. It is set like any other list-type custom front-matter parameter (i.e. ~:LIST_PARAM '(ELEMENT1 ELEMENT2)~). See its example [[code__pandoc_citations_example][below]]. **** Link citations ~link-citations~ is a special Pandoc-specific meta-data which, when set to ~true~, enables linking of the citations in the post body to the corresponding reference in the "References" section. It is set like any other single-value custom front-matter parameter (i.e. ~:LIST_PARAM VALUE~). See its example [[code__pandoc_citations_example][below]]. **** Specifying Citation Style Language (CSL) By default, Pandoc uses /Chicago Manual of Style author-date/ as the [[https://citationstyles.org/][Citation Style Language]] ([[https://pandoc.org/MANUAL.html#citations][ref]]). This can be customized by using the Pandoc-specific meta-data ~csl~ to specify the new CSL file. It is set like any other single-value custom front-matter parameter (i.e. ~:LIST_PARAM VALUE~). See its example [[code__pandoc_citations_example][below]]. /Note that the path to the CSL file is relative to the Org file directory./ **** Removal of Pandoc-specific meta-data The Pandoc-specific meta-data mentioned above (~nocite~, ~link-citations~ and ~csl~) are added using HUGO_CUSTOM_FRONT_MATTER *only for Pandoc* to parse. Once they are used by ~pandoc~, those front-matter keys are deleted in the final Markdown file (Hugo has no use of those Pandoc-specific front-matter keys). **** Auto-insertion of headings When one or more citations are found by Pandoc, a top-level "References" section with matching references is automatically added at the end of the post. By default, ~ox-hugo~ will insert a Markdown heading with the string defined in ~org-hugo-pandoc-cite-references-heading~ before that Pandoc-inserted /References/ section. It's default value is ~References {#references}"~. If you want to prevent this Markdown heading auto-insertion, set this variable to an empty string (~""~). **** Example Here is a small example using Pandoc Citations: #+name: code__pandoc_citations_example #+caption: Example of using Pandoc Citations #+begin_src org ,* Citations Example :PROPERTIES: :EXPORT_FILE_NAME: citations-example :EXPORT_HUGO_PANDOC_CITATIONS: t :EXPORT_BIBLIOGRAPHY: cite/bib/bib1.bib, cite/bib/bib2.bib :EXPORT_HUGO_CUSTOM_FRONT_MATTER: :nocite '(@cite3 @cite4) :EXPORT_HUGO_CUSTOM_FRONT_MATTER+: :link-citations true :EXPORT_HUGO_CUSTOM_FRONT_MATTER+: :csl cite/csl/my-custom-csl-format.csl :END: Here is a test example file with an in-text citation where someone important says something important (e.g. @cite1). And here is another bit of blah with a footnote citation.[fn:1] ,* Footnotes [fn:1] See [@cite2]. #+end_src - Note :: Above example assumes ~cite/bib/bib1.bib~, ~cite/bib/bib2.bib~ and ~cite/csl/my-custom-csl.format.csl~ to exist in the same directory containing the Org file. See [[https://pandoc.org/MANUAL.html#citations][Pandoc Manual -- Citations]] for more details. **** How Pandoc Citations work 1. ~ox-hugo~ first exports the Org file/subtree to a Markdown file as usual. 2. ~pandoc~ then expands the ~@foo~ citations in that file and *rewrites* the whole Markdown file from the AST parsed by it. *** Custom Front-matter Parameters :PROPERTIES: :EXPORT_FILE_NAME: custom-front-matter :END: #+begin_description Setting custom front-matter parameters which have no special meaning to Hugo, but are used in user's themes. #+end_description - To set a custom front-matter parameter in a subtree, use the ~:EXPORT_HUGO_CUSTOM_FRONT_MATTER:~ property. - To set a custom front-matter parameter globally or for /per-file/ export flow, use the keyword ~#+hugo_custom_front_matter:~. For the rest of this section, the /property/ method for setting the custom front-matter will be used. But the same applies to the /keyword/ method too (except for property-specific ~:EXPORT_HUGO_CUSTOM_FRONT_MATTER+:~ syntax -- See ~(org) Property Syntax~ for more). **** Single value parameters ***** Syntax #+begin_src org :PROPERTIES: :EXPORT_HUGO_CUSTOM_FRONT_MATTER: :key1 value1 :key2 value2 :END: #+end_src Instead of appending all the key/value pairs on the same line, they can instead be broken down as shown below, by appending ~+~ to the property name. #+begin_src org :PROPERTIES: :EXPORT_HUGO_CUSTOM_FRONT_MATTER: :key1 value1 :EXPORT_HUGO_CUSTOM_FRONT_MATTER+: :key2 value2 :END: #+end_src If using the /keyword/ method instead, the same would be written as: #+begin_src org ,#+hugo_custom_front_matter: :key1 value1 ,#+hugo_custom_front_matter: :key2 value2 #+end_src /The above method of appending keywords will work for the other cases below too./ ***** Example #+begin_src org :PROPERTIES: :EXPORT_HUGO_CUSTOM_FRONT_MATTER: :feature true :END: #+end_src Above exports to TOML front-matter as: #+begin_src toml feature = true #+end_src **** List value parameters ***** Syntax #+begin_src org :PROPERTIES: :EXPORT_HUGO_CUSTOM_FRONT_MATTER: :key1 '(elem11 elem12) :key2 '(elem21 elem22) :END: #+end_src ***** Example #+begin_src org :PROPERTIES: :EXPORT_HUGO_CUSTOM_FRONT_MATTER: :animals '(dog cat "penguin" "mountain gorilla") :EXPORT_HUGO_CUSTOM_FRONT_MATTER+: :integers '(123 -5 17 1_234) :EXPORT_HUGO_CUSTOM_FRONT_MATTER+: :floats '(12.3 -5.0 -17E-6) :EXPORT_HUGO_CUSTOM_FRONT_MATTER+: :booleans '(true false) :END: #+end_src Above exports to TOML front-matter as: #+begin_src toml animals = ["dog", "cat", "penguin", "mountain gorilla"] integers = [123, -5, 17, 1_234] floats = [12.3, -5.0, -1.7e-05] booleans = [true, false] #+end_src **** Maps of single and list values Maps of keys with single or list values are supported. #+begin_note /Maps of maps/ or /TOML tables of tables/ are not supported. See [[* Front-matter Extra]] section for an alternative. #+end_note ***** Syntax #+begin_src org :PROPERTIES: :EXPORT_HUGO_CUSTOM_FRONT_MATTER: :key1 '((subkey11 . subval11) (subkey12 . (subelem121 subelem122))) :key2 '((subkey21 . subval21)) :END: #+end_src ***** Example #+begin_src org :PROPERTIES: :EXPORT_HUGO_CUSTOM_FRONT_MATTER: :versions '((emacs . "27.0.50") (hugo . "0.48")) :EXPORT_HUGO_CUSTOM_FRONT_MATTER+: :header '((image . "projects/Readingabook.jpg") (caption . "stay hungry, stay foolish")) :EXPORT_HUGO_CUSTOM_FRONT_MATTER+: :collection '((animals . (dog cat "penguin" "mountain gorilla")) (integers . (123 -5 17 1_234)) (floats . (12.3 -5.0 -17E-6)) (booleans . (true false))) :END: #+end_src Above exports to TOML front-matter as: #+begin_src toml [versions] emacs = "27.0.50" hugo = 0.48 [header] image = "projects/Readingabook.jpg" caption = "stay hungry, stay foolish" [collection] animals = ["dog", "cat", "penguin", "mountain gorilla"] integers = [123, -5, 17, 1_234] floats = [12.3, -5.0, -1.7e-05] booleans = [true, false] #+end_src **** Front-matter Extra You would use this feature only if you need to use some front-matter that ~ox-hugo~ cannot translate from native Org keywords/properties to TOML/YAML front-matter. A good example is if you need to add custom /map of map/ type front-matter (or TOML /tables of tables/). The front-matter specified in this manner is appended *verbatim* to the *end* of the ~ox-hugo~ generated front-matter. ***** TOML Extra front-matter Create a *toml* Org source block anywhere in your post, and add the special header args ~:front_matter_extra t~ to it. /The TOML front-matter is the default. So you do not need to set ~:EXPORT_HUGO_FRONT_MATTER_FORMAT: toml~./ #+begin_src org ,* Post with TOML front-matter (default) :PROPERTIES: :EXPORT_FILE_NAME: extra-front-matter-toml :END: The contents of the ~#+begin_src toml :front_matter_extra t~ TOML block here will get appended to the TOML front-matter. ,#+begin_src toml :front_matter_extra t [[foo]] bar = 1 zoo = "abc" [[foo]] bar = 2 zoo = "def" ,#+end_src #+end_src ***** YAML Extra front-matter Create a *yaml* Org source block anywhere in your post, and add the special header args ~:front_matter_extra t~ to it. #+begin_src org ,* Post with YAML front-matter :PROPERTIES: :EXPORT_FILE_NAME: extra-front-matter-yaml :EXPORT_HUGO_FRONT_MATTER_FORMAT: yaml :END: The contents of the ~#+begin_src yaml :front_matter_extra t~ YAML block here will get appended to the YAML front-matter. ,#+begin_src yaml :front_matter_extra t foo: - bar: 1 zoo: abc - bar: 2 zoo: def ,#+end_src #+end_src ***** Wrong format of extra front-matter The ~:front_matter_extra t~ source block LANG *has* to match your selected front-matter format. You cannot have a ~#+begin_src yaml :front_matter_extra t~ extra front-matter block if your front-matter format is YAML (and vice-versa). If that happens, that blocks gets exported neither to the Markdown body nor to the front-matter. **** More Examples You can find many other examples by looking at {{{testtag(custom-fm)}}}. *** Hugo Section :PROPERTIES: :EXPORT_FILE_NAME: hugo-section :END: #+begin_description Specifying the path under Hugo "content" to where the Markdown file should be exported. #+end_description **** Default By default, ~ox-hugo~ exports all the markdown files to ~/content/posts/~. The "posts" sub-directory default is set in the ~org-hugo-default-section-directory~ /defcustom/ variable which a user can customize. With the below Org file, the post will export to that "posts" sub-directory: #+begin_src org ,#+hugo_base_dir: . ,* My post :PROPERTIES: :EXPORT_FILE_NAME: my-post :END: This gets created in ~/content/posts/~. #+end_src Setting ~org-hugo-default-section-directory~ will affect globally---All your ~ox-hugo~ exported projects. **** Setting ~HUGO_SECTION~ per file :PROPERTIES: :CUSTOM_ID: hugo-section-keyword :END: If you need to override the default ~HUGO_SECTION~ only in an Org file, set the ~#+hugo_section~ keyword. #+begin_src org ,#+hugo_base_dir: . ,#+hugo_section: articles ,* My post :PROPERTIES: :EXPORT_FILE_NAME: my-post :END: This gets created in ~/content/articles/~. #+end_src **** Setting ~HUGO_SECTION~ per subtree (only /per-subtree/ flow) :PROPERTIES: :CUSTOM_ID: hugo-section-property :END: If you need to override *both* the default ~HUGO_SECTION~ and the Org file specific ~#+hugo_section~ keyword, set the ~EXPORT_HUGO_SECTION~ subtree property. #+begin_src org ,#+hugo_base_dir: . ,#+hugo_section: articles ,* About :PROPERTIES: :EXPORT_HUGO_SECTION: / :EXPORT_FILE_NAME: about :END: This gets created directly in ~/content/~. ,* My post :PROPERTIES: :EXPORT_FILE_NAME: my-post :END: This gets created in ~/content/articles/~. As the ~EXPORT_HUGO_SECTION~ property is not set, the ~#+hugo_section~ keyword value applies. ,* Notes :PROPERTIES: :EXPORT_HUGO_SECTION: notes :END: ,** My note :PROPERTIES: :EXPORT_FILE_NAME: my-note :END: This gets created in ~/content/notes/~. #+end_src The ~EXPORT_HUGO_SECTION~ does not need to be set in the same subtree as the post. The benefit of this is that you can have a parent subtree set the ~EXPORT_HUGO_SECTION~ value, and then have all the children subtrees inherit that value. See the "Notes" subtree in above example to see this inheritance in action. **** Section path fragments (only /per-subtree/ flow) :PROPERTIES: :CUSTOM_ID: hugo-section-fragments :END: The default Org Property behavior is that the value of a property set in the /closest parent/ wins. See the below example to understand that. #+name: code__using_only_EXPORT_HUGO_SECTION #+caption: Using only ~EXPORT_HUGO_SECTION~ #+begin_src org ,* Main section :PROPERTIES: :EXPORT_HUGO_SECTION: main :END: The parsed value of ~EXPORT_HUGO_SECTION~ property is ~"main"~ here. ,** Sub section 1 :PROPERTIES: :EXPORT_HUGO_SECTION: sub :END: The parsed value of ~EXPORT_HUGO_SECTION~ property is ~"sub"~ here. The earlier set ~"main"~ value in the parent of this subtree is lost. I would have liked the parent value ~"main"~ to get auto-prepended here. ,** Sub section 2 :PROPERTIES: :EXPORT_HUGO_SECTION: main/sub :END: The parsed value of ~EXPORT_HUGO_SECTION~ property is ~main/sub~ here. While this works, it gets a bit inconvenient to manually prefix the parent property value (~"main/"~ here) as the number of nesting levels increase. #+end_src But this is Emacs, and with the help of Emacs-Lisp and kind help from /Ihor Radchenko/ on the [[https://lists.gnu.org/r/emacs-orgmode/2018-10/msg00002.html][Org mailing list]], ~ox-hugo~ now has a solution to this! #+begin_verse > /Introducing *~EXPORT_HUGO_SECTION_FRAG~*/ :tada: #+end_verse If a subtree has the ~EXPORT_HUGO_SECTION_FRAG~ property set[fn:11], it is treated as a section path *fragment*. Such fragment properties will be concatenated with the *same* fragment properties further up in the parent hierarchy. The collective concatenated value of ~EXPORT_HUGO_SECTION_FRAG~ properties is further prefixed with the value of the good old ~HUGO_SECTION~ keyword/property that's effective in that subtree. #+begin_note ~EXPORT_HUGO_SECTION_FRAG~ *has to be set as a subtree property*. There is no Org keyword equivalent for this, because this property is designed (and makes sense) only for the /per-subtree/ flow. #+end_note So the final *section path* looks like this: #+begin_src goat /content/// └───────────────────── section path ─────────────────────────┘ #+end_src See the below example to get further clarity on this logic. #+name: code__using_hugo_section_fragments #+caption: Using ~EXPORT_HUGO_SECTION_FRAG~ with ~EXPORT_HUGO_SECTION~ #+begin_src org ,* Main section :PROPERTIES: :EXPORT_HUGO_SECTION: main :END: The /section path/ derived at this level is ~"main/"~. ,** Sub section 1 :PROPERTIES: :EXPORT_HUGO_SECTION_FRAG: sub1 :END: The /section path/ derived at this level is ~"main/sub1/"~. ,*** Sub section 1.1 :PROPERTIES: :EXPORT_HUGO_SECTION_FRAG: p1 :END: The /section path/ derived at this level is ~"main/sub1/p1/"~. ,*** Sub section 1.2 :PROPERTIES: :EXPORT_HUGO_SECTION_FRAG: p2 :END: The /section path/ derived at this level is ~"main/sub1/p2/"~. ,** Sub section 2 :PROPERTIES: :EXPORT_HUGO_SECTION_FRAG: sub2 :END: The /section path/ derived at this level is ~"main/sub2/"~. #+end_src *** Inlined SVGs :PROPERTIES: :EXPORT_FILE_NAME: inlined-svgs :END: Inlined SVGs are supported by a new HTML attribute introduced by ~ox-hugo~: *inlined*. Just add ~#+attr_html: :inlined t~ #+begin_mark above the SVG file link #+end_mark . Here's an example of inlining an SVG: #+begin_src org ,#+begin_src plantuml :file ../test/site/content-org/images/svg-with-hyperlinks.svg :exports results skinparam svgLinkTarget _parent start :[[https://ox-hugo.scripter.co/ ox-hugo homepage]]; stop ,#+end_src ,#+caption: An SVG with a *hyperlink* ,#+attr_html: :inlined t ,#+RESULTS: [[file:../test/site/content-org/images/svg-with-hyperlinks.svg]] #+end_src .. which results in: #+begin_src plantuml :file ../test/site/content-org/images/svg-with-hyperlinks.svg :exports results skinparam svgLinkTarget _parent start :[[https://ox-hugo.scripter.co/ ox-hugo homepage]]; stop #+end_src #+caption: An SVG with a *hyperlink* #+attr_html: :inlined t #+RESULTS: [[file:../test/site/content-org/images/svg-with-hyperlinks.svg]] *** CJK Support :PROPERTIES: :EXPORT_FILE_NAME: cjk-support :EXPORT_HUGO_ALIASES: chinese-support japanese-support :END: **** Auto-unwrapping of lines with multi-byte characters This issue came up on this [[https://emacs-china.org/t/ox-hugo-auto-fill-mode-markdown/9547][emacs-china thread]] .. the issue was that when consecutive lines in Org source had Chinese characters, in HTML the last character on one line got separated from the first character on the next line by a space, which is not grammatically correct in Chinese. So in such cases, those lines must be unwrapped _without any spaces_ to separate those characters across the lines. That of course would not be grammatically correct in English and even other languages with multi-byte characters (few examples: Hindi, Gujarati). So that line-unwrapping _with space removal_ is done *only if*, 1. The /locale/ is [[https://www.gnu.org/software/gettext/manual/html_node/Locale-Environment-Variables.html][auto-detected]] to be Chinese or Japanese via environment variables /LANGUAGE/, /LC_ALL/ or /LANG/, or 2. The /locale/ is *manually set* to Chinese or Japanese by setting it to *zh* or *ja* using ~#+hugo_locale:~ keyword (or ~EXPORT_HUGO_LOCALE~ property). *** Hugo Bundle :PROPERTIES: :EXPORT_FILE_NAME: hugo-bundle :END: #+begin_description Specifying the [[https://gohugo.io/content-management/page-bundles/][Hugo Page Bundle]] directory name containing the ~_index.md~ (/branch/ bundle index file) or ~index.md~ (/page/ bundle index file). #+end_description To make an ~ox-hugo~ export happen to a Hugo Page Bundle, set the ~:EXPORT_HUGO_BUNDLE:~ property to the "name of the bundle". For example, if the bundle needs to be generated as ~https://example.com/xyz/~, set ~:EXPORT_HUGO_BUNDLE: xyz~. - Leaf Bundle :: Set ~:EXPORT_FILE_NAME: index~ - Branch Bundle :: Set ~:EXPORT_FILE_NAME: _index~ #+begin_note For file-based flow, use ~#+hugo_bundle~ and ~#+export_file_name~ keywords instead. #+end_note **** Examples ***** Leaf Bundle :PROPERTIES: :CUSTOM_ID: leaf-bundle-example :END: Below will export to ~content/xyz/index.md~. #+begin_src org ,* Page title :PROPERTIES: :EXPORT_HUGO_BUNDLE: xyz :EXPORT_FILE_NAME: index :END: Content #+end_src ***** Branch Bundle :PROPERTIES: :CUSTOM_ID: branch-bundle-example :END: Below will export to ~content/uvw/_index.md~. #+begin_src org ,* Page title :PROPERTIES: :EXPORT_HUGO_BUNDLE: uvw :EXPORT_FILE_NAME: _index :END: Content #+end_src **** More Reading - [[https://scripter.co/hugo-leaf-and-branch-bundles/][scripter.co -- Hugo: Leaf and Branch Bundles]] *** Org Special Blocks :PROPERTIES: :EXPORT_FILE_NAME: org-special-blocks :EXPORT_OPTIONS: num:t :END: #+begin_description Special ~#+begin_..~ .. ~#+end_..~ constructs recognized by Ox-hugo. #+end_description **** HTML5 inline elements Org special blocks created using the HTML tags defined in ~org-blackfriday-html5-inline-elements~ will export as inline HTML. #+begin_src org ,#+begin_INLINETAG something ,#+end_INLINETAG #+end_src will export as: #+begin_src html something #+end_src For example, ~mark~ is one of those inline elements. So, #+begin_src org ,#+begin_mark This sentence is marked. ,#+end_mark #+end_src will export as: #+begin_src html This sentence is marked. #+end_src and render as: #+header: :trim-pre nil #+begin_mark This sentence is marked. #+end_mark **** HTML5 block elements Org special blocks created using the HTML tags defined in ~org-html-html5-elements~ will export as HTML blocks wrapped by those tags. #+begin_src org ,#+begin_BLOCKTAG something ,#+end_BLOCKTAG #+end_src will export as: #+begin_src html something #+end_src For example, [[https://developer.mozilla.org/en-US/docs/Web/HTML/Element/aside][~aside~]] is one of those HTML5 block elements. So, #+begin_src org ,#+begin_aside Some content for the ~aside~ block. ,#+end_aside We can even make the ~aside~ block /aside-like/ with [[https://developer.mozilla.org/en-US/docs/Web/HTML/Element/aside][this little CSS]]. #+end_src will export as: #+begin_src html We can even make the `aside` block _aside-like_ with [this little CSS](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/aside). #+end_src and render as: #+begin_export html #+end_export #+begin_aside Some content for the ~aside~ block. #+end_aside We can even make the ~aside~ block /aside-like/ with [[https://developer.mozilla.org/en-US/docs/Web/HTML/Element/aside][this little CSS]]. **** Details and Summary ~details~ is one of the HTML5 block elements, but it is treated as a separate case because we also need to support the nested inline ~summary~ tag in there. #+begin_src org ,#+begin_details ,#+begin_summary This is summary. ,#+end_summary Here are the details. ,#+end_details #+end_src See {{{relref(Details and Summary,details-and-summary)}}}. **** HTML Attributes HTML attributes can be added to the first /tag/ of any of the above Special Blocks using the ~#+attr_html~ syntax. The ~class~ attribute, for instance, is very handy. For example, if we want the marked text to have red foreground color, we can do: #+begin_src org ,#+begin_export html ,#+end_export ,#+attr_html: :class red ,#+begin_mark This marked text's foreground is red. ,#+end_mark #+end_src #+begin_note You may choose to have a CSS snippet like above either inline in the exported Markdown, or in your website's CSS file. #+end_note and that will render as: #+begin_export html #+end_export #+attr_html: :class red #+begin_mark This marked text's foreground is red. #+end_mark **** Description The ~#+begin_description~ .. ~#+end_description~ special block can be used to set the ~description~ front-matter variable. This allows the description to be written in a well-formatted fashion with Org markup and it can be multi-line too. As an example: #+begin_src org ,#+begin_description Here is my *post summary*. And this can be over /multiple lines/ too! ,#+end_description #+end_src Above will export as this in the TOML front matter: #+begin_src toml description = """ Here is my **post summary**. And this can be over _multiple lines_ too! """ #+end_src **** Hugo Paired Shortcodes See {{{relref(~HUGO_PAIRED_SHORTCODES~,shortcodes/#hugo-paired-shortcodes)}}}. **** Other Special Blocks (~div~ tags) :PROPERTIES: :CUSTOM_ID: special-blocks--div-tags :END: If the Special Block /tag/ used isn't found in ~org-blackfriday-html5-inline-elements~ or ~org-html-html5-elements~, that block exports just as an HTML ~div~ block. #+begin_src org ,#+begin_SOMETHING Content inside something. ,#+end_SOMETHING #+end_src exports as: #+begin_src html
Content inside something.
#+end_src and renders as: #+begin_something Content inside something. #+end_something If we want to reuse the ~.red~ CSS rule defined [[*HTML Attributes][above]], we can type: #+begin_src org ,#+begin_red This text will be in red. ,#+end_red #+end_src which will render as: #+begin_red This text will be in red. #+end_red /See the [[* Whitespace Trimming][Whitespace Trimming]] section if you need to export with ~~ tags instead of ~
~ tags./ **** Raw Org contents By default, the content inside the Org special blocks will have some default processing done by the exporter -- Org entities like ~\sum~ will be replaced by its HTML entity ~∑~, ~foo_{bar}~ will be replaced with ~foobar~, and so on. But the user might want to keep the contents of the special block as-as, in its raw form, for some special block types. If the user wants to do this for a special block of the /type/ FOO: #+name: code__example_special_block #+caption: An example /special block/ of type /FOO/ #+begin_src org ,#+begin_FOO Some content ,#+end_FOO #+end_src , they need to add ~("FOO" . (:raw t))~ to the customization variable ~org-hugo-special-block-type-properties~. By default , ~("katex" . (:raw t))~ is added to this list. So when using a special block like, #+name: code__example_katex_special_block #+caption: An example /special block/ of type /katex/ #+begin_src org ,#+begin_katex E = -J \sum\_{i=1}^N s\_i s\_{i+1} ,#+end_katex #+end_src , the equation in the content of that special block: ~E = -J \sum\_{i=1}^N s\_i s\_{i+1}~ will be exported to Markdown as-is. As an another example, if you have a special block for the [[https://mermaid-js.github.io/mermaid/][Mermaid diagramming markup]], and you need to write special blocks like below which has one of the HTML reserved characters (~>~), #+name: code__example_mermaid_special_block #+caption: An example /special block/ of type /mermaid/ #+begin_src org ,#+begin_mermaid flowchart TD Start --> Stop ,#+end_mermaid #+end_src you will need to export the content of that shortcode in raw Org. To do so, you can add something like this to your config: #+name: code__example_update_raw_special_block_prop #+caption: An example of updating a special block type's ~:raw~ property to ~t~ #+begin_src emacs-lisp (with-eval-after-load 'ox-hugo (add-to-list 'org-hugo-special-block-type-properties '("mermaid" . (:raw t)))) #+end_src **** TikZJax ~ox-hugo~ supports exporting raw /tikz/ snippet to Markdown which can be rendered to images using the [[https://tikzjax.com/][TikZJax]] project. To use this feature, ensure that the /TikZJax/ scripts are loaded in the HTML ~~ (you will need to tweak your site's Hugo template for that): #+caption: Sourcing TikZJax scripts in HTML head #+name: code__tikzjax_html_head #+begin_src html #+end_src Then simply put /tikz/ snippets in the Org source like so: #+caption: Example use of tikzjax special block #+name: code__tikzjax_special_block_example #+begin_src org ,#+begin_tikzjax \draw (0,0) circle (1in); ,#+end_tikzjax #+end_src {{{test-search(tikzjax)}}} **** Whitespace Trimming The default whitespace trimming around exported Org Special Blocks can be configured by setting the ~:trim-pre~ and ~:trim-post~ properties for specific special block types in the ~org-hugo-special-block-type-properties~ customization variable. - If ~:trim-pre~ is set to ~t~, whitespace before the block is removed. - If ~:trim-post~ is set to ~t~, whitespace after the block is removed. #+begin_note For the types not specified in ~org-hugo-special-block-type-properties~, the default behavior is like that of ~'(:trim-pre nil :trim-post nil)~. #+end_note Here's an example of specifying trimming options for a new special block type "sidenote": #+begin_src elisp (with-eval-after-load 'ox-hugo (add-to-list 'org-hugo-special-block-type-properties '("sidenote" . (:trim-pre t :trim-post t)))) #+end_src Here's an example of overriding properties for one of the types, say "mark": #+begin_src elisp (with-eval-after-load 'ox-hugo (setcdr (assoc "mark" org-hugo-special-block-type-properties) '(:trim-pre t :trim-post nil))) #+end_src Or, you can ~M-x customize-group~, select ~org-select-hugo~ and tweak this variable in that UI. The default values set this way can be overridden in the Org file by using the ~#+header:~ keyword above the special blocks. Below examples demonstrate the usage of this ~#+header~ keyword. #+begin_note If a special block tag is not recognized as an HTML block or inline element, or as a Hugo shortcode, it defaults to exporting [[#special-blocks--div-tags][with ~
~ tags]]. But if either pre or post trimming options are detected for a special block, it will export with ~~ tags. #+end_note #+include: "../test/site/content-org/all-posts.org::* Whitespace trimming around special blocks" :only-contents t *** Shortcodes :PROPERTIES: :EXPORT_FILE_NAME: shortcodes :EXPORT_OPTIONS: num:t :EXPORT_HUGO_PAIRED_SHORTCODES: alert2 :END: #+begin_description Support for Hugo Shortcodes in Org source #+end_description #+begin_note - Do _not_ use raw Hugo shortcodes in Org source. - *{{< .. >}}* and *{{% .. %}}* are not legal Org syntax. #+end_note Ox-hugo will not officially support verbatim use of Hugo shortcodes in Org source, like you would do in Hugo Markdown source. But here are few ways how you can either mimic them or include them indirectly. **** Org Special Blocks With a little bit of CSS and {{{relref(Org Special Blocks,org-special-blocks#other-special-blocks--div-tags)}}}, we can mimic some of the Hugo Shortcodes in Org itself. Here is some CSS inspired from the [[https://www.docsy.dev/docs/adding-content/shortcodes/#alert][Docsy theme's]] ~alert~ shortcode: <> #+begin_details #+begin_summary CSS for alert shortcode from Docsy theme #+end_summary #+begin_src css .alert { position: relative; padding: 0rem 1rem; margin-bottom: 1rem; border: 1px solid transparent; } .alert-warning { border-style: solid; border-color: #ed6a5a; border-width: 0 0 0 4px; } .alert-heading { font-family: sans-serif; font-size: 1.5rem; color: #ed6a5a; weight: bold; } #+end_src #+end_details #+begin_export html #+end_export With that CSS, and the below Org snippet: #+begin_src org ,#+attr_html: :class alert-warning ,#+begin_alert ,#+begin_alert-heading Warning ,#+end_alert-heading This is a warning. ,#+end_alert #+end_src we get this: #+attr_html: :class alert-warning #+begin_alert #+begin_alert-heading Warning #+end_alert-heading This is a warning. #+end_alert **** ~HUGO_PAIRED_SHORTCODES~ The Org Special Blocks export paired Hugo Shortcodes for a special block /tag/ that's added to the ~HUGO_PAIRED_SHORTCODES~ keyword. ***** Non-Markdown Shortcodes ({{< .. >}}) :PROPERTIES: :CUSTOM_ID: non-markdown-shortcodes :END: The content within these shortcodes is not parsed by the Hugo Markdown parser. See [[https://gohugo.io/content-management/shortcodes/#shortcodes-without-markdown][Hugo Doc -- Shortcodes Without Markdown]]. 1. Use ~:EXPORT_HUGO_PAIRED_SHORTCODES: myshortcode~ property or ~#+hugo_paired_shortcodes: myshortcode~ keyword to let the Org Special Block parsing logic know that "myshortcode" tag needs to be exported as a paired shortcode. 2. Use the Org Special Block: #+begin_src org ,#+begin_myshortcode Something ,#+end_myshortcode #+end_src Above will export as: #+begin_src md {{< myshortcode >}} Something {{< /myshortcode >}} #+end_src ****** Shortcodes with positional arguments If the Hugo shortcode accepts positional arguments, they need to be specified using the ~#+attr_shortcode~ keyword. For example, #+begin_src org ,#+attr_shortcode: argval1 "arg val 2" ,#+begin_myshortcode Something ,#+end_myshortcode #+end_src will export as: #+begin_src md {{< myshortcode argval1 "arg val 2" >}} Something {{< /myshortcode >}} #+end_src ****** Shortcodes with named arguments ~#+attr_shortcode~ keyword can be used to also specify a shortcode's /named/ arguments. For example, #+begin_src org ,#+attr_shortcode: :arg1 foo bar :arg2 color: red; text-align: center; ,#+begin_myshortcode Something ,#+end_myshortcode #+end_src will export as: #+begin_src md {{< myshortcode arg1="foo bar" arg2="color: red; text-align: center;" >}} Something {{< /myshortcode >}} #+end_src ***** Markdown Shortcodes ({{% .. %}}) :PROPERTIES: :CUSTOM_ID: markdown-shortcodes :END: #+begin_note All of the above applies to Markdown Shortcodes as well. #+end_note The content within these shortcodes *is* parsed by the Hugo Markdown parser. See [[https://gohugo.io/content-management/shortcodes/#shortcodes-with-markdown][Hugo Doc -- Shortcodes With Markdown]]. Only the syntax for specifying these shortcodes is different --- You need to prefix the shortcode with ~%~. Example: ~:EXPORT_HUGO_PAIRED_SHORTCODES: %myshortcode~ in the post subtree's property drawer or ~#+hugo_paired_shortcodes: %myshortcode~ as a keyword. ***** ~alert2~ shortcode example An ~alert2~ shortcode definition is saved to this site's ~layouts/shortcodes/alert2.html~ which looks like this: #+begin_src html
{{ .Inner }}
#+end_src ~:EXPORT_HUGO_PAIRED_SHORTCODES: alert2~ is added to this post's subtree in Org source so that the Org Special Block parser knows to treat that /tag/ differently (i.e. export as a non-Markdown Hugo shortcode). With that, this Org snippet: #+begin_src org ,#+attr_shortcode: warning ,#+begin_alert2 This is a warning. ,#+end_alert2 #+end_src exports as: #+begin_src md {{< alert2 warning >}} This is a warning. {{< /alert2 >}} #+end_src and renders as this: #+attr_shortcode: warning #+begin_alert2 This is a warning. #+end_alert2 /You might notice that the same [[alert-css][Alert CSS]] from the previous section is applied here too./ **** Quoting Hugo-specific exports The Org source should contain only Org syntax text which could be parsed in general by any of the built-in Org exporters. So ~ox-hugo~ does not recommend or support using raw Hugo shortcodes directly in Org source as shown below: #+begin_src md # Bad !! {{< alert2 warning >}} This is a warning. {{< /alert2 >}} #+end_src But many times, one might also want to use one of the unpaired Hugo shortcodes like [[https://gohugo.io/content-management/cross-references/#use-ref-and-relref][~relref~]]. These too, you cannot directly inline them but you can use one of these methods. ***** ~@@hugo:..@@~ :PROPERTIES: :CUSTOM_ID: inline-syntax :END: #+begin_src org This links to the @@hugo:[Org Special Blocks]({​{< relref "org-special-blocks" >}})@@ page. #+end_src Above renders to: This links to the @@hugo:[Org Special Blocks]({{< relref "org-special-blocks" >}})@@ page. See [[info:org#Quoting HTML tags]] for reference. /Using ~@@md:..@@~ or ~@@html:..@@~ will also export the same way./ ***** ~#+hugo:~ Keyword Sometimes, it might also be possible to export the whole line in the specified backend like so: #+begin_src org ,#+hugo: This links to the [Org Special Blocks]({​{< relref "org-special-blocks" >}}) page. #+end_src Above renders to: #+hugo: This links to the [Org Special Blocks]({{< relref "org-special-blocks" >}}) page. /Using ~#+md:..~ or ~#+html:..~ will also export the same way./ ***** ~#+begin_export hugo~ <<.embedding-shortcodes-discouraged>> #+begin_note This method is discouraged because we would then end up with Org text with a lot of content which can be exported for only Hugo consumption! #+end_note The earlier sections {{{relref(Org Special Blocks,#org-special-blocks)}}} and {{{relref(Hugo Paired Shortcodes,#hugo-paired-shortcodes)}}} are the recommended methods if you really want to blend Hugo shortcodes with your Org source. Even though discouraged, this method is documented for the sake of completeness. #+begin_src org ,#+begin_export hugo {{< alert2 warning >}} This is a warning. {{< /alert2 >}} ,#+end_export #+end_src renders as: #+begin_export hugo {{< alert2 warning >}} This is a warning. {{< /alert2 >}} #+end_export ****** Multi-line shortcodes Hugo supports unpaired shortcodes written over multiple lines. For example, if you have an unpaired shortcode called ~album~ which accepts multiple arguments, you can write it like below /(but it's [[.embedding-shortcodes-discouraged][discouraged]])/ for readability. #+begin_src org ,#+begin_export hugo {{< album position="horizontal" path="static/img/some/very/long/path" >}} ,#+end_export #+end_src **** Org Macros If you find yourself using the [[#inline-syntax][~@@hugo:..@@~ Inline Syntax]] a lot, you might appreciate the power of [[info:org#Macro Replacement][Org Macros]]. This is best shown using the same ~relref~ shortcode example .. <<.relref-org-macro>> Instead of always typing ~@@hugo:[Org Special Blocks]({​{< relref "org-special-blocks" >}})@@~, you can define an Org macro called ~relref~ like so: #+begin_src md ,#+macro: relref @@hugo:[@@ $1 @@hugo:]({{< relref "$2" >}})@@ #+end_src And then, #+begin_src org This links to the {{{relref(Org Special Blocks,org-special-blocks)}}} page. #+end_src will also render to: This links to the {{{relref(Org Special Blocks,org-special-blocks)}}} page. *** HTML Containers :PROPERTIES: :EXPORT_FILE_NAME: html-containers :END: #+begin_description Support ~HTML_CONTAINER~ and ~HTML_CONTAINER_CLASS~ similar to the way ~ox-html~ does, but also supporting property inheritance. #+end_description The ~HTML_CONTAINER~ and ~HTML_CONTAINER_CLASS~ properties can be added to any of the subtrees with the ~EXPORT_~ prefix. If a sub-tree has the property ~EXPORT_HTML_CONTAINER: section~, that sub-tree is exported as a heading surrounding with ~
~ and ~
~. By default, that ~section~ tag has the class "outline-NUM" where /NUM/ is the level of that heading in that post. Additionally, if it has the property ~EXPORT_HTML_CONTAINER_CLASS: foo~, the "foo" class gets added to that container tag as well. {{{test-search(container)}}} *** Anchors :PROPERTIES: :EXPORT_FILE_NAME: anchors :END: #+begin_description Anchors derived for sub-heading and other HTML elements in a page. #+end_description Hugo supports specifying custom ID's for headings in a page using the ~{#some-id}~ syntax. See its documentation on [[https://gohugo.io/content-management/cross-references/#heading-ids][Cross References: Heading IDs]] for reference. If the heading ID's are not specified using the above syntax, Hugo will generate them automatically. While that is OK in general, it becomes problematic when user generates [[* Table of Contents][TOC]] using Org, where the links to headings on the page need to be embedded, or uses Org internal or external links to reference other headings. So in order to make the user experience smooth, anchors for all headings are always derived withing ~ox-hugo~ and exported using the ~{#some-id}~ syntax. The functions used for deriving the anchors can be customized using the *~org-hugo-anchor-functions~* variable. This variable is a list of functions which can return the anchor string for a given Org heading element. The first function in the list to return a non-nil value wins. So this scheme can be used to set a precedence order that the user desires. This is the default precedence order: - ~org-hugo-get-page-or-bundle-name~ :: Use the heading's ~:EXPORT_FILE_NAME~ property if set, else return /nil/. - ~org-hugo-get-custom-id~ :: Use the heading's ~:CUSTOM_ID~ property if set, else return /nil/. - ~org-hugo-get-heading-slug~ :: Derive anchor using the heading's text. This could also return /nil/, if the heading has no alphanumeric characters or no text (empty string). - ~org-hugo-get-md5~ :: Derive anchor using the few 6 characters of /md5/ based on the heading title text. It returns the /md5/ of an empty string if nothing else works. That way, this function guarantees to return some non-empty string. Above precedence is set in the default value of ~org-hugo-anchor-functions~ --- ~'(org-hugo-get-page-or-bundle-name org-hugo-get-custom-id org-hugo-get-heading-slug org-hugo-get-md5)~. **** Other anchor functions - ~org-hugo-get-id~ :: This function returns the ID, if that property is set for a heading. If a user prefers to give higher precedence to Org ID than the heading-derived-slug, they can customize ~org-hugo-anchor-functions~ to ~'(org-hugo-get-page-or-bundle-name org-hugo-get-custom-id org-hugo-get-id org-hugo-get-heading-slug org-hugo-get-md5)~. Now if an Org heading looks like this: #+begin_src org ,** Heading in a post :PROPERTIES: :ID: 74283e7c-a20b-1c22-af88-e41ff8055d17 :END: #+end_src , it will be exported as below in Markdown: #+begin_src md ### Heading in a post {#74283e7c-a20b-1c22-af88-e41ff8055d17} #+end_src **** Target Links Org mode specifies the ~<>~ syntax in [[info:org#Internal Links]]. By default, a target named "foo" <>(~<>~) will create an HTML anchor with a prefix (like ~org-target--~). See [[foo][this link]] to that "foo" target. But if the target name is prefixed with a ".", like ".bar" <<.bar>>(~<<.bar>>~), the HTML anchor with #+begin_mark not have that prefix #+end_mark . See [[.bar][this link]] to that ".bar" target. This special feature allows you to create an HTML anchor anywhere in your document which you might then refer from a different post by using something like the {{{relref(~relref~ Org macro,shortcodes#relref-org-macro)}}}. *** Multi-lingual Support :PROPERTIES: :EXPORT_FILE_NAME: multi-lingual-support :END: #+begin_description Support for translation of some ~ox-hugo~ inserted strings based on ~org-export-translate~ machinery designed in ~ox.el~. #+end_description ~ox-hugo~ relies on the ~org-export-dictionary~ variable from the core Org Export library ~ox.el~ to derive translated strings for these: - Source block caption prefix /"Code Snippet"/ - Figure caption prefix /"Figure"/ - Table caption prefix /"Table"/ - Table of contents {{{titleref(Table of Contents#toc-heading,heading)}}} /"Table of Contents"/ - Bibliography {{{titleref(Org Cite Citations#bibliography-heading,heading)}}} /"References"/ The translation language is detected from the ~#+language:~ keyword present in the Org file or the ~:EXPORT_LANGUAGE:~ property in the post subtree. For reference, see the ~LANGUAGE~ keyword documentation in [[info:org#Export Settings]]. *** Linking numbered elements :PROPERTIES: :EXPORT_FILE_NAME: linking-numbered-elements :END: #+begin_description How to link numbered elements like source blocks, tables or figures. #+end_description If you need to link to any of these elements, they need to have the ~#+name~ keyword. The ~#+caption~ is optional. Below, you will find examples of the supported numbered elements, and how to link to them. **** Code block (~src-block~) #+begin_src org ,#+name: code__hello ,#+caption: Saying "Hello" in ~emacs-lisp~ ,#+begin_src emacs-lisp (message "Hello") ,#+end_src Link to the above code block: [[code__hello]] #+end_src **** Table (~table~) #+begin_src org ,#+name: tab__simple_table ,#+caption: Simple Table |----------+----------+----------| | Header 1 | Header 2 | Header 3 | |----------+----------+----------| | abc | def | ghi | |----------+----------+----------| Link to the above table: [[tab__simple_table]] #+end_src **** Figure #+begin_src org ,#+name: fig__some_figure ,#+caption: Some Figure [[./images/some_figure.png]] Link to the above figure: [[fig__some_figure]] #+end_src See [[*Image Links]] for more details. **** Auto-prefixing element type names in links When links are made to any of these numbered elements, ~ox-hugo~ has an option to prefix the link descriptions with that element's type name. #+name: tab__element_prefixes_en #+caption: Default prefixes (English) for the supported elements |---------------------------+--------------| | Element Type | Prefix (en) | |---------------------------+--------------| | ~src-block~ or code block | Code Snippet | | ~table~ | Table | | figure[fn:9] | Figure | |---------------------------+--------------| To enable this auto-prefixing feature, set ~org-hugo-link-desc-insert-type~ to a non-nil value. #+name: code__enable_auto_prefixing_link_desc_with_type_names #+caption: Enable auto-prefixing of link descriptions with the referenced element's type name #+begin_src emacs-lisp (with-eval-after-load 'ox-hugo (setq org-hugo-link-desc-insert-type t)) #+end_src This feature has language support too. If the ~#+language~ keyword is set to a language code other than ~en~ (example: ~de~), the translations of the element type names get exported. The translations are based on the ~org-export-dictionary~ variable from ~ox.el~. *** Menu Front-matter :PROPERTIES: :EXPORT_FILE_NAME: menu-front-matter :END: #+begin_description Support for exporting to ~menu~ front-matter. #+end_description In Hugo, the global ~site~ variable contains a dictionary called ~Menus~. Within ~Menus~, a /Menu Name/ is used to reference a collection or slice of /Menu Entries/. Each of those /Menu Entries/ are associated with a /Page/. One can visualize the relationship of those objects in this manner: #+name: code__hugo_menu_entry_visualization #+caption: Visualization of Hugo Menu Entries #+begin_src text site Menus | +--------------+ +-- "Menu Name 1" --> | Menu Entry 1 +----> Page 1 | +--------------+ | | Menu Entry 2 +----> Page 2 | +--------------+ | | .. +----> .. | +--------------+ | | +--------------+ +-- "Menu Name 2" --> | Menu Entry a +----> Page a | +--------------+ | | Menu Entry b +----> Page b | +--------------+ . | .. +----> .. +--------------+ #+end_src So on each /Page/, the user can specify the keys of the associated /Menu Entry/ using the ~menu~ front-matter. #+begin_note A /Menu Entry/ is uniquely associated with a /Page/. #+end_note Here are the valid keys for that ~menu~ config as derived from the [[https://gohugo.io/variables/menus/#menu-entry-variables][Menu Entry Variables]] documentation: #+name: tab__menu_config_keys #+caption: Menu Entry /keys/ and associated variables accessible from Hugo template |------------------+-------------------------------+-----------------------------------------------------------------------------------------| | Menu Entry /Key/ | Menu Entry /Variable/ | Brief Description | |------------------+-------------------------------+-----------------------------------------------------------------------------------------| | ~[menu.NAME]~ | ~.Menu~ | Name of the Menu containing the current Menu Entry | | ~url~ | ~.URL~ | /URL/ that this Menu Entry points to, defaults to page's ~.RelPermalink~ | | ~identifier~ | ~.Identifier~ | /Identifier/ is the unique string used to identify this Menu Entry | | ~name~ | ~.Name~ | /Name/ of this Menu Entry, defaults to page's ~.LinkTitle~ | | ~pre~ | ~.Pre~ | HTML string that can be used to /prefix/ the Menu Entry ~.Name~ | | ~post~ | ~.Post~ | HTML string that can be used to /postfix/ the Menu Entry ~.Name~ | | ~weight~ | ~.Weight~ | /Weight/ for this Menu Entry, used for sorting menus in a sidebar | | ~parent~ | ~.Parent~ | Name or Identifier of this Menu Entry's /Parent/ Menu Entry | | ~title~ | ~.Title~ (this is a function) | Used to set this Menu Entry's link's ~title~ attribute, defaults to page's ~.LinkTitle~ | |------------------+-------------------------------+-----------------------------------------------------------------------------------------| **** ~:EXPORT_HUGO_MENU:~ and ~#+hugo_menu:~ In Org mode, these Menu Entry keys are specified using the ~:EXPORT_HUGO_MENU:~ property (subtree-based exports) or ~#+hugo_menu:~ keyword (file-based exports). They are set in this /property list/ form: #+begin_src org :EXPORT_HUGO_MENU: :menu <:key 1> <:key 2> .. #+end_src The ~:menu~ key is mandatory because that's used to specify the current Page's Menu Entry's parent Menu name. The rest of the property list keys map directly with the Menu Entry keys shown below: #+name: tab__menu_front_matter_keys #+caption: ~menu~ Front Matter keys |--------------------------------------------+-------------------------+-----------------------------------------------------------| | ~:EXPORT_HUGO_MENU:~ or ~#+hugo_menu:~ key | Menu Entry Front-matter | Note | |--------------------------------------------+-------------------------+-----------------------------------------------------------| | ~:menu VAL~ | ~[menu.VAL]~ | *mandatory* | | ~:identifier VAL~ | ~identifier = VAL~ | Gets auto-set to the /sanitized/ post title if not set | | ~:weight VAL~ | ~weight = VAL~ | Gets auto-set based on post subtree's location if not set | | ~:url VAL~ | ~url = VAL~ | /optional/ | | ~:pre VAL~ | ~pre = VAL~ | /optional/ | | ~:name VAL~ | ~name = VAL~ | /optional/ | | ~:post VAL~ | ~post = VAL~ | /optional/ | | ~:parent VAL~ | ~parent = VAL~ | /optional/ | | ~:title VAL~ | ~title = VAL~ | /optional/ | |--------------------------------------------+-------------------------+-----------------------------------------------------------| ***** General use example For subtree-based exports, it would be common to specify the container Menu name in a parent subtree and let that value trickle down to the nest post subtrees as a result of Org property inheritance. It would look something like this: #+name: code__common_menu_setting #+caption: Common style of setting the ~menu~ front-matter #+begin_src org ,* Posts under the ~main~ Menu :PROPERTIES: :EXPORT_HUGO_MENU: :menu main :END: ,** Post 1 :PROPERTIES: :EXPORT_FILE_NAME: post-1 :END: ,** Post 2 :PROPERTIES: :EXPORT_FILE_NAME: post-2 :END: #+end_src When these posts are exported, the ~menu~ front-matter in them will look something like this: #+name: code__common_menu_setting_post_1_fm #+caption: ~menu~ in "Post 1" front-matter #+begin_src toml [menu] [menu.main] weight = 3001 identifier = "post-1" #+end_src #+name: code__common_menu_setting_post_2_fm #+caption: ~menu~ in "Post 2" front-matter #+begin_src toml [menu] [menu.main] weight = 3002 identifier = "post-2" #+end_src Note that the ~weight~ and ~identifier~ were set automatically by ~ox-hugo~ as they were not specified. ***** Example where more ~menu~ keys are specified For a post with the below property (subtree-based export): #+begin_src org :EXPORT_HUGO_MENU: :menu "something here" :weight 80 :parent posts :identifier foo1 #+end_src , the ~menu~ in the exported front-matter will look like below: #+begin_src toml [menu] [menu."something here"] parent = "posts" weight = 80 identifier = "foo1" #+end_src **** Overriding Menu Entry keys #+begin_note This feature is applicable only to subtree-based flow. #+end_note Use the ~:EXPORT_HUGO_MENU_OVERRIDE:~ property if you need to override only some of the inherited Menu Entry keys. Here's an example Org snippet: #+name: code__hugo_menu_override_org #+caption: Example of using ~:EXPORT_HUGO_MENU_OVERRIDE:~ #+begin_src org ,* Parent subtree :PROPERTIES: :EXPORT_HUGO_MENU: :menu "something here" :parent posts :END: ,** Post 1 :PROPERTIES: :EXPORT_FILE_NAME: foo :EXPORT_HUGO_MENU_OVERRIDE: :identifier "abc" :weight 100 :END: ,** Post 2 :PROPERTIES: :EXPORT_FILE_NAME: bar :EXPORT_HUGO_MENU_OVERRIDE: :weight 1 :END: #+end_src With above, "Post 1" ~menu~ front-matter will be exported as: #+name: code__hugo_menu_override_post_1 #+caption: ~menu~ in "Post 1" front-matter with overridden ~identifier~ and ~weight~ values #+begin_src toml [menu] [menu."something here"] parent = "posts" weight = 100 identifier = "abc" #+end_src , and "Post 2" ~menu~ front-matter will be exported as: #+name: code__hugo_menu_override_post_2 #+caption: ~menu~ in "Post 2" front-matter with overridden ~weight~ value #+begin_src toml [menu] [menu."something here"] identifier = "post-2" parent = "posts" weight = 1 #+end_src ** Meta :PROPERTIES: :EXPORT_HUGO_MENU: :menu "7.meta" :END: *** Search :PROPERTIES: :EXPORT_HUGO_SECTION: / :EXPORT_FILE_NAME: search :EXPORT_HUGO_LAYOUT: search :EXPORT_HUGO_MENU: :menu "0.search" :title "Click to Search" :EXPORT_HUGO_CUSTOM_FRONT_MATTER: :sitemap '((priority . 0.1)) :EXPORT_HUGO_OUTPUTS: html json :END: Results from static site search implemented using /Fusejs/, /jquery/ and /mark.js/. -- [[https://gist.github.com/eddiewebb/735feb48f50f0ddd65ae5606a1cb41ae][Source]] *** Meta Features :PROPERTIES: :EXPORT_FILE_NAME: meta-features :END: - [X] Extensive tests! -- [[https://github.com/kaushalmodi/ox-hugo/tree/main/test/site/content-org][test/site/content-org]] (=make test=) - [X] GitHub Actions Integration -- Checks with emacs versions starting from 25.3, with the latest stable version of Org mode. - [X] [[https://ox-hugo.scripter.co][Documentation site]] -- Generated using =ox-hugo= itself (=make doc_md hugo_doc=). - [X] GitHub repo files: [[https://github.com/kaushalmodi/ox-hugo/blob/main/README.org][~README.org~]] and [[https://github.com/kaushalmodi/ox-hugo/blob/main/CONTRIBUTING.org][~CONTRIBUTING.org~]] -- Generated using =ox-org= (=make doc_gh=). - [X] [[../test/][Test site]] -- Regenerated after each commit to this repo (=make test=). - [X] Passes =make test= and generates documentation using =make doc= in [[https://termux.com/][Termux]] app on Android too. - [X] Passes =checkdoc= and =package-lint= ([[https://github.com/purcell/package-lint/issues/89][/almost/]]). *** Requirements :PROPERTIES: :EXPORT_FILE_NAME: requirements :END: Any user who wants to clone this repo and run the test or doc site locally will need to have a [[https://go.dev/doc/install][recent version of Go installed]]. Go isn't a requirement for ~ox-hugo~ or ~hugo~ to work in general. But because the test and doc sites use [[https://gohugo.io/hugo-modules/use-modules/][Hugo Modules]] approach for managing the theme and component dependencies, Go is required for that. **** Requirements for doc contributor :PROPERTIES: :CUSTOM_ID: doc_contributor_reqs :END: #+begin_note - Minimum required ~hugo~ version: {{{min_hugo_version}}} #+end_note **** Requirements for code contributor :PROPERTIES: :CUSTOM_ID: code_contributor_reqs :END: #+begin_note - Org mode version used for tests: {{{org_mode_version}}} - Minimum required ~hugo~ version: {{{min_hugo_version}}} - ~pandoc~ version {{{pandoc_version}}} #+end_note - About Pandoc :: /While the end-user does not need Pandoc installed on their machine, a code contributor needs to have ~pandoc~ installed[fn:7]. These are needed for ~make md~ and ~make -j1 test~ steps to work as they use/test the [[*Pandoc Citations][Pandoc Citations]] feature too./ *** Contributing Guide :PROPERTIES: :EXPORT_FILE_NAME: contributing-guide :END: #+include: "./ox-hugo-manual.org::#note-to-future-contributors" :only-contents t *** Debug :PROPERTIES: :EXPORT_FILE_NAME: debug :END: #+include: "./ox-hugo-manual.org::#debug" :only-contents t *** Test :PROPERTIES: :EXPORT_FILE_NAME: test :END: #+include: "./ox-hugo-manual.org::#test" :only-contents t * COMMENT Older manually written changelog :ARCHIVE: ** v0.8 <2018-01-26 Fri> *** Features - Support exporting content files and attachments (images, documents) to Page Bundles organization structure (Hugo v0.32+) -- {{{issue(111)}}}. - Support exporting =resources= front-matter (Hugo v0.33+) -- {{{issue(115)}}}. - Support exporting =headless= front-matter (Hugo v0.35+). - Advanced table styling is now possible by specifying =#+attr_html= and =#+attr_css= (this one is unique to =ox-hugo=) above Org tables. See its [[https://ox-hugo.scripter.co/doc/table-styling/][documentation]] -- {{{issue(93)}}}. - Similarly, support =#+attr_html= and =#+attr_css= for paragraphs, example blocks, source blocks, plain lists and quote blocks too -- {{{issue(113)}}}. - Now =publishDate= front-matter property gets auto-derived from the =SCHEDULED= special property if associated with the valid Hugo post subtree -- {{{commit(0807f42d)}}}. - Date values can now be easily set using the =C-c .= binding in the =HUGO_PUBLISHDATE= and =HUGO_EXPIRYDATE= properties too. - Export source blocks and table captions -- {{{issue(38)}}}. Here's a suggested CSS for the captions: #+begin_src css figcaption, .src-block-caption, .table-caption { font-style: italic; text-align: center; } #+end_src - Export descriptive or definition lists in Blackfriday-friendly Markdown format -- {{{issue(114)}}}. - Support Org Special Blocks like in HTML and [[info:org#Special blocks in LaTeX export]] -- {{{issue(105)}}}. Here's one little example: #+begin_src org ,#+begin_mark /Some/ *marked* text ,#+end_mark #+end_src - Allow setting =:EXPORT_HUGO_SECTION:= in the valid Hugo post subtree itself. - Enable replacing any key in the front-matter with anything; it's even possible to swap the keys now (tags↔categories: {{{commit(fb21e82c)}}}). New keyword: =HUGO_FRONT_MATTER_KEY_REPLACE= -- see {{{commit(b72a5fb0)}}}. - Now all the Org keyword values that should get merged, get merged -- {{{commit(38eba6d5)}}}. - Add =title= as a valid property of =menu= front-matter (Hugo v0.32+). *** Backward-incompatible changes - A "better user-experience" change.. now you do not need to use /double-underscores/ as /space/ replacement in =#+hugo_tags=, =#+hugo_categories= and =#+keywords=. See this commit for details and examples -- {{{commit(319435db)}}}. *** Fixes - Fix =HUGO_LEVEL_OFFSET= not getting set -- {{{issue(117)}}}, thanks {{{user(shimmy1996)}}}! - Fix internal subtree counter not getting reset after a file-based export. - Fix clickable image links with =#+name= -- {{{commit(fef0ec50)}}}. - Make title text rendering more robust.. now Markdown markup characters like =*=, =_= and =`= show up fine, verbatim, in the title. - Make em dash, en dash, horizontal ellipsis render in post titles too -- {{{hugoissue(4175)}}} (/Upstream bug fix/), and in source block captions and table captions too. - Fix double-escaping of =#= and =![= in Markdown export -- {{{issue(110)}}} (/fix in upstream =ox-md.el=/). *** Meta - Re-write the logic for parsing meta-data for various kinds of dates, and optimize the logic for parsing newline separated lists like tags and categories. - The =hugo-bare-min-theme= used for the test site is made more portable (at some point, that theme might be moved to a separate repo). ** v0.7 <2017-12-18 Mon> *** Features - *Now C-c C-e H H works for both per-subtree and per-file flows* -- {{{commit(b1b5d28b)}}}. - Support Org heading based internal links -- {{{issue(88)}}}. - Support list values for custom front-matter variables -- {{{issue(99)}}}. - Support specifying multiple [[https://gohugo.io/templates/output-formats/][hugo output formats]] .. Now the =outputs= front-matter variable is a list. - Support the Org =#+author= and =#+creator= keywords and their respective Org Export Options -- {{{issue(106)}}}. - Support Org Export Snippets and Export Blocks -- {{{commit(1149f20cd)}}}. - Now post titles can be set to =nil= i.e. be not be a part of the front-matter .. /because you can/. - Improve the messages printed by =ox-hugo= on doing per-subtree or per-file exports.. the progress of files exported using per-subtree flow is now clearer, and the name of the file exported using per-file flow is now explicit.. Helps when you batch export a dozen files with a mix of these 2 flows. *** Backward-incompatible changes - Obsolete /org-hugo-export-subtree-\ast{}/ functions and replace them with /org-hugo-export-wim-\ast{}/ (What I Mean) functions. See the doc string of =org-hugo-export-wim-to-md= for details. If you are using the [[https://ox-hugo.scripter.co/doc/auto-export-on-saving/][Auto-export on saving]] flow, note the function name change there too! *** Fixes - Fix number of backticks in code fence when code contains code fence (/pathological corner case/). - Better document the =HUGO_CODE_FENCE= keyword -- {{{issue(102)}}}. - Don't render =(c)=, =(r)=, =(tm)= inside Latex equations -- {{{issue(104)}}} (/Upstream bug workaround/). - Better recognition of TOML-compatible integers and floats in meta data for front-matter so that valid integers/floats don't get unnecessarily double-quoted. *** Meta - Add a [[https://github.com/kaushalmodi/hugo-debugprint/blob/master/layouts/partials/debugprint.html][=debugprint.html=]] partial to help pretty-print various Hugo objects like Page Params, File and SiteInfo for debug on the test site. - The test site now has [[https://ox-hugo.scripter.co/test/tags/][tags]] and [[https://ox-hugo.scripter.co/test/categories/][categories]] pages. - Add few real world example posts containing complex Latex equations: [[https://ox-hugo.scripter.co/test/real-examples/multifractals-in-ecology-using-r/][1]], [[https://ox-hugo.scripter.co/test/real-examples/nn-intro/][2]]. - Turns out =ox-hugo= works on emacs 24.4 too (/but please upgrade to the latest Emacs and Org stable versions!/). ** v0.6 <2017-11-09 Thu> *** Features - Support the =num= export option. Now you can prefix all post headings (or some not.. the ones with =UNNUMBERED= property set to =t=) with their section numbers -- {{{issue(76)}}}. - Org TOC's are now exported as unordered Markdown lists. This allows having TOC's with unnumbered headings too! This also enables prefixing the section headings with their full section numbers, and also having only selected headings unnumbered (both in the post body and the TOC). - Add support for exporting internal links to source blocks, tables and images by their block names! -- {{{issue(29)}}}. - Org table column alignment markers (==, ==, ==) are now exported to equivalent Markdown tables.. so a center-aligned column in Org buffer will remain center-aligned in the final HTML too! -- {{{issue(95)}}}. - Allow setting multiple Hugo aliases for a post. Also infer the section name from inherited =HUGO_SECTION= values (subtree-based exports) for those alias prefixes. - Prevent a footnote ref to appear by itself on a newline (based on wrapping) in the browser -- {{{issue(96)}}}. - If Hugo shortcodes are used specifically in Markdown (=md=) source blocks, they will be auto-escaped (useful when you want to document/talk about some Hugo shortcode in a blog post) -- {{{issue(94)}}}. - If an Org table has just 1 row, don't make it render as a header row in the final HTML. - If you have a case where you need to have an Org source block instead a quote block, and then a source block after that quote block (/I know, a very common case../ :wink:), Blackfriday barfs ({{{bfissue(407)}}}). But we now have a workaround, which /just works/ -- {{{issue(98)}}}. - Now =ATTR_HTML= above even hyper-linked images works (earlier it worked only above non-hyper-linked images). *** Backward-incompatible changes - Org TOC's are exported as unordered Markdown lists instead of ordered Markdown lists, and now full section numbers (like 1.2.3) are shown in the TOC instead of just the last digit (like 3.) -- {{{commit(4be378e7)}}}. - The =num= Org export option is default to =nil= (only for =ox-hugo=). So Org TOC's are exported without section numbers by default. To get section numbers, set =num= to =t= or =onlytoc=. *** Fixes - Now exporting 1-row Org tables works too. - Add missing http/https/ftp prefix for hyper-linked images. *** Meta - Add documentation on how you can have {{{titleref(Images in Content,Images live in the same directory as Org source)}}} -- {{{issue(91)}}}. - Now only Org files for the [[https://ox-hugo.scripter.co][documentation site]] need to be committed to git. =ox-hugo= then exports those to Markdown, and then Hugo publishes those to HTML (as before) --- all on Netlify. - Be sure to check out the moderately revamped [[https://ox-hugo.scripter.co/test/][Test Site]]. That might be of interest even if you want to check out what the new features and changes look like, without first installing/updating =ox-hugo= yourself :smile:. ** v0.5 <2017-11-06 Mon> *** Features - Export TOC as a Markdown ordered list. See {{{titleref(Table of Contents,)}}} -- {{{issue(88)}}}. - =#+attr_html= above http/https/ftp links is now supported (useful for specifying the =target=, =rel=, attributes, for example). ** v0.4.1 <2017-10-29 Sun> *** Features - Support specifying the =:height= parameter in the =#+attr_html= above image links. That eventually gets transformed to the =height= parameter in the =figure= tag in the HTML generated by Hugo. This feature requires building Hugo from its master branch with commit [[https://github.com/gohugoio/hugo/commit/488631fe0abc3667355345c7eb98ba7a2204deb5][488631fe]] (or Hugo v0.31+). *** Fixes - Fix =EXPORT_HUGO_SECTION= not getting inherited {{{issue(90)}}}. ** v0.4 <2017-10-28 Sat> *** Backward-incompatible changes - Restore the default Org behavior of =#+tags=. Now that keyword (and the =EXPORT_TAGS= property) is *not* used by =ox-hugo=. Fixes {{{issue(89)}}}. - File-based exports must now use =#+hugo_tags= to set the post tags. - Subtree-based exports can use the =EXPORT_HUGO_TAGS= property to override Org-style tags on the same heading (and the ones inherited from Org-style tags from any of the parent subtrees and =#+filetags=). - Note that for subtree-based exports, =#+filetags= can be used to set tags globally in the file. Earlier =#+tags= was used for that purpose. - Subtree-based exports can use the =EXPORT_HUGO_CATEGORIES= property to override Org-style categories (tags with "@" prefix) on the same heading (and the ones inherited from Org-style categories from any of the parent subtrees and =#+filetags=). - Note that for subtree-based exports, =#+filetags= can be used to set categories (tags with "@") globally in the file. See the new section added to documentation: {{{titleref(Tags and Categories,)}}}. *** Features - Support specifying the =:width= parameter in the =#+attr_html= above image links. That eventually gets transformed to the =width= parameter in the =figure= tag in the HTML generated by Hugo. ** v0.3.2 <2017-10-24 Tue> *** Fixes - Fix issue with heading metadata parsing (ALLTAGS, CLOSED, TODO) when a post Org heading was immediately followed by that post's sub-heading. This issue was seen in subtree-based exports {{{issue(87)}}}. ** v0.3.1 <2017-10-19 Thu> *** Fixes - Fix the source block line number annotation when the line numbers increased in number of digits in the same code block. ** v0.3 <2017-10-18 Wed> *** Features - Source blocks can now be exported with line numbers and/or highlighting! See {{{titleref(Source blocks,)}}} for details. ** v0.2.3 <2017-10-11 Wed> *** Fixes - =org-hugo-slug= earlier stripped off only the =code= HTML tag (~ .. ~) from the input string, if present. Now it does that for *any* HTML tag, like =span=. For example, this HTML gets stripped off from the above heading (only inside =org-hugo-slug= when deriving the slug string): ~<2017-10-11 Wed>~. ** v0.2.2 <2017-10-10 Tue> *** Backward-incompatible changes - Now =ox-hugo= by default requires text, to be sub/super-scripted, to be wrapped in ={}=. So now =a_b= will be exported as =a_b=, but =a_{b}= will be exported as =ab=. To revert back to the earlier behavior, user needs to add =#+options: ^:t= to their Org file. ** v0.2.1 <2017-09-28 Thu> *** Fixes - Single column tables now export correctly {{{issue(84)}}}. - Ignore =HUGO_WEIGHT= set to =auto= for /per-file/ exports {{{issue(83)}}}. ** v0.2 <2017-09-27 Wed> *** Features - Add support for all Hugo =figure= shortcode parameters {{{issue(79)}}}. - New option =org-hugo-delete-trailing-ws= defaults to =t=; now Hugo deletes trailing white-spaces by default. - New options =org-hugo-default-static-subdirectory-for-externals= and =org-hugo-external-file-extensions-allowed-for-copying= (related to {{{issue(69)}}}). *** Fixes - Remove =HUGO_STATIC_IMAGE= option; fix attachment re-write {{{issue(69)}}}. - Fix incorrectly inserted hard line-breaks {{{issue(72)}}}. Added a new option =HUGO_PRESERVE_FILLING=. - Fix error happening when a post title was set to an empty string [ [[https://github.com/kaushalmodi/ox-hugo/commit/ba9e8365f6ee42f030ed806bf5ec42d6acce4c76][ba9e8365]] ]. *** Backward-incompatible changes - Switch the default value of =org-hugo-use-code-for-kbd= option to =nil= [ [[https://github.com/kaushalmodi/ox-hugo/commit/88ba15ae9bc809b0983315446c88fecfda3534e5][88ba15ae]] ]. ** v0.1.3 <2017-09-13 Wed> - Now a HUGO key value set to ="nil"=, like =#+hugo_code_fence: nil=, will evaluate as /nil/ instead of /t/, as now =org-hugo--plist-get-true-p= is used to parse boolean keys instead of =plist-get=. ** v0.1.2 <2017-09-12 Tue> - Make DateTime matching better; new internal variable =org-hugo--date-time-regexp=. Earlier time zones ahead of UTC (with =+= sign) were not detected as dates in =org-hugo--quote-string= and thus were unnecessarily quoted. ** v0.1.1 <2017-09-11 Mon> - Use CLOSED log drawer info if available to set the date in front-matter {{{issue(68)}}}. - Code optimization: Use of =org-entry-get= at places instead of maintaining global variables. * Footnotes [fn:15] The default value of the buffer-local variable ~org-done-keywords~ in any Org buffer is ~("DONE")~. [fn:14] See the *'d'* option in [[info:org#Export Settings]]. [fn:13] See [[info:org#Tracking TODO state changes]] for more information. [fn:3] The ~dvisvgm~ and ~dvipng~ executables ship with TexLive distributions. [fn:12] This same MathJax setup is used on the =ox-hugo= test site too. [fn:11] If you are looking for ~EXPORT_HUGO_SECTION*~ property, that has been deprecated; please see {{{titleref(Deprecation Notices#export-hugo-section-frag)}}}. [fn:10] You can find the same (or similar) ~author.html~ partial used in the [[https://github.com/kaushalmodi/hugo-onyx-theme][Hugo theme]] used for this doc site. [fn:9] "figure" is not exactly a proper "Org element". A "figure" is a standalone figure link in an Org paragraph. [fn:8] The [[https://github.com/toml-lang/toml#local-date-time][TOML date-time]] uses the same RFC3339 format. [fn:7] The Pandoc Citations feature was last tested with Pandoc version {{{pandoc_version}}}. If you are running an older version, the quickest way to install might be to simply download the latest release archive from [[https://github.com/jgm/pandoc/releases][Pandoc releases]], extract it and put the ~pandoc~ executable in one of the directories in your /PATH/. [fn:6] If you are still using a Hugo version older than 0.25, update now! -- Because that version added support for the awesome =--navigateToChanged= switch. [fn:5] I am assuming that the value of ~org-footnote-section~ in your Emacs setup is the default value ~"Footnotes"~. If it's not, change the "Footnotes" heading in that example accordingly. [fn:4] The ~TODO~ / ~DONE~ keyword is used in this example as they are the defaults in ~org-todo-keywords~. If you have customized your ~org-todo-keywords~, or are customizing them using other means like the per-file ~#+seq_todo~ setting, use those instead. Use your custom "DONE" keyword (it should be a part of ~org-done-keywords~) instead of the default ~DONE~. And similarly, use your custom "TODO" keyword instead of the default ~TODO~ (ensure that it is *not* in ~org-done-keywords~). [fn:2] For only subtree-based exports, you can set that special tag as Org style tags too. Example: ~* I don't want to export this post :no_no_dont_export:~.. and don't forget to add that tag to =org-export-exclude-tags= too! [fn:1] To understand why the attachment files get copied to the =static/ox-hugo/= directory, have a look at the documentation for {{{titleref(Image Links#references-to-files-outside-the-static-directory,referencing files outside static directory)}}}. * COMMENT Local Variables :ARCHIVE: # Local Variables: # eval: (toggle-truncate-lines 1) # eval: (org-hugo-auto-export-mode -1) # End: