Giter Site home page Giter Site logo

kaushalmodi / ox-hugo Goto Github PK

View Code? Open in Web Editor NEW
855.0 23.0 130.0 7.5 MB

A carefully crafted Org exporter back-end for Hugo

Home Page: https://ox-hugo.scripter.co

License: GNU General Public License v3.0

Emacs Lisp 94.83% HTML 1.44% Makefile 2.27% CSS 0.10% TeX 1.35%
hugo elisp org-mode exporter markdown blackfriday static-site-generator emacs org blog

ox-hugo's Introduction

Ox-Hugo: A carefully crafted Org exporter back-end for Hugo

https://github.com/kaushalmodi/ox-hugo/actions/workflows/test.yml/badge.svg https://melpa.org/packages/ox-hugo-badge.svg https://img.shields.io/badge/License-GPL%20v3-blue.svg

If you have any questions or if you have anything interesting to share related to ox-hugo, feel free to do so on Discussions!

ox-hugo is an Org exporter backend that exports Org to Hugo-compatible Markdown (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.


See the Real World Examples section to quickly jump to sites generated using ox-hugo and their Org sources.

Table of Contents

Screenshots

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).

One post per Org subtree (preferred)

https://raw.githubusercontent.com/kaushalmodi/ox-hugo/main/doc/static/images/one-post-per-subtree.png

Files in above screenshot
Org -> Markdown

One post per Org file

https://raw.githubusercontent.com/kaushalmodi/ox-hugo/main/doc/static/images/one-post-per-file.png

Files in above screenshot
Org -> Markdown

Editorial

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.

Documentation

ox-hugo uses itself to generate its documentation!

https://ox-hugo.scripter.co/

You can generate the same too! Simply clone this repo and do make doc_md.

Make sure you visit the above link to read more on:

Source of the Documentation site

The documentation site is published by first using ox-hugo to export from Org to Markdown, and then finally hugo. So no Markdown files are committed in the =doc/content/= directory.

Demo

Org source=ox-hugo= Exported Markdownhttps://ox-hugo.scripter.co/test/

The test site uses a 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 Hugo Themes for examples of really good site prettification and presentation styles.

Installation

This package requires at least GNU Emacs 26.3 and Org Mode 9.0. It is available on Melpa (https://melpa.org/#/ox-hugo), and it’s recommended to install this package from 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:

(with-eval-after-load 'ox
  (require 'ox-hugo))

Use Package

If you use =use-package=, you can do the below instead:

(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)

Spacemacs

Spacemacs users can use ox-hugo by setting the variable org-enable-hugo-support.

(setq-default dotspacemacs-configuration-layers
              '((org :variables
                  org-enable-hugo-support t)))

This was verified to work on Spacemacs =develop= branch (ref).

Usage

Before you export

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/<HUGO_SECTION>/ directory[fn:-1-section_more]. By default, the Markdown files reside in a hierarchy under the content/ directory in the site root directory (ref).

If you try to export without setting this property, you will get this error:

user-error: It is mandatory to set the HUGO_BASE_DIR property
            or the `org-hugo-base-dir' local variable
    

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 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 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 branch/leaf data structure terminlogy, then the subtrees with EXPORT_FILE_NAME property need to be leaf nodes.

[fn:-1-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 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 Auto Exporting section.

Customization Options

Do M-x customize-group, and select org-export-hugo to see the available customization options for this package.

Thanks

  • Matt Price (@titaniumbones)
  • Puneeth Chaganti (@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 =goorgeous= project by Chase Adams (@chaseadamsio) for inspiration to start this project.

ox-hugo's People

Contributors

ahendriksen avatar andreyorst avatar coldnight avatar ctanas avatar e-eight avatar edkolev avatar elbaulp avatar enigmacurry avatar haozeke avatar hungpham2511 avatar jethrokuan avatar kaushalmodi avatar lizhuohua avatar paretooptimaldev avatar pi-kappa-devel avatar punchagan avatar ragnargrootkoerkamp avatar robin-wils avatar rossabaker avatar ryancummings avatar shimmy1996 avatar shombando avatar spcbfr avatar steventammen avatar syohex avatar takaxp avatar titaniumbones avatar winny- avatar wych42 avatar zzamboni avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ox-hugo's Issues

best way to publish subtrees

I'm not clear on how to tell org-publish how to publish all subtrees in a file, in the context of org-publish-project-alist. Do you have an idea how htis would be done? We are sort of sidestepping hte normal org publishing mechanism, right?

Allow specifying categories via Org tags

Just as C-c C-q foo sets the foo tag in the post front matter, C-c C-q @bar should set the bar category in the front matter. The key is the special character @ at the beginning of the Org tag.

Fix window scrolling when exporting the subtree

With point in any valid Hugo post subtree, C-c C-e H H will cause the window to scroll and change from its prior position. save-excursion only keeps the point in place with respect to the buffer, but the location of point in the window changes.

still working on this?

Hi Kaushal, just wondering if you were still working on this and if so what plans you have. I'm in the process of moving from Wordpress to Hugo and setting up my publishing framework with some ugly code munged from the links youcite i nthe README. I would love to use a mature/systainable exporter instead if you're going to be writing one... but will stick with my crappy system if I have to.
My code quality is so low I'm not sure I can offer much help but at least I could be enthusiastic!

ox-hugo should export to hugo content dir by default

If we're using ox-hugo, it's because we want the output to end up in a Hugo blog. Rather than export in the current directory of org files, send straight to Hugo.

Behaviour should be controlled by a defcustom, and should also be settable as file-local.

Fix bold in italics

Org:

-   /This is italics, and *this is bold too*, and back to plain
    italics./

Converts to:

-   *This is italics, and **this is bold too**, and back to plain
    italics.*

But that does not work; this works:

-   _This is italics, and **this is bold too**, and back to plain
    italics._

write function to walk headlines and export all to hugo

One to-do item in README is exporting all the posts in a given file to hugo. I have some similar code I've used for other projects, buti t's pretty brittle so it would be nice to write something better.

I'm actually not sure of the state of any of these defuns as I have lost track of my progress/lack thereof, but here are two versions:

(defun mwp-org-export-all-subtrees ()
  (interactive)
  (org-element-map (org-element-parse-buffer)'headline
    (lambda (headline)
      (let ((begin (org-element-property :begin headline))
            (level (org-element-property :level headline))
            (commentedp (org-element-property :commentedp headline))
            (tags (org-element-property :tags headline)))
        (unless (or (> level 1)
                    commentedp
                    (member "noexport" tags)
                    ;; I would prefer to get the exclude-tags dynamically but
                    ;; I'm not sure how to do it properly -- need to access exclude-tags somehow
                    ;; (cl-loop for k in (plist-get options :exclude-tags)
                    ;;          thereis (member k  tags))
                    )
          (save-excursion
            (goto-char begin)
            (org-gfm-publish-to-gfm nil t )))))))
(defun mwp-org-export-all-subtrees-to-hugo ()
  (interactive)
  (org-element-map (org-element-parse-buffer)'headline
    (lambda (headline)
      ;;(message "%s" headline)
      (let ((begin (org-element-property :begin headline))
            (level (org-element-property :level headline))
            (commentedp (org-element-property :commentedp headline))
            (title (or (org-element-property :HUGO_TITLE headline)
                       (org-element-property :TITLE headline)
                       (org-element-property :raw_value headline)))
            
            (tags (org-element-property :tags headline)))
        (unless (or (> level 1)
                    commentedp
                    (member "noexport" tags)
                    ;; I would prefer to get the exclude-tags dynamically but
                    ;; I'm not sure how to do it properly -- need to access exclude-tags somehow
                    ;; (cl-loop for k in (plist-get options :exclude-tags)
                    ;;          thereis (member k  tags))
                    )
          (save-excursion
            (goto-char begin)
            (let
                ((outfile (concat
                           (or (org-element-property :EXPORT_FILE_NAME headline)
                               (replace-regexp-in-string " " "-" (org-element-property :raw_value headline))
                               ) ".md")))
            (org-export-to-file 'hugo outfile nil t nil)
            )))))))

I have something that sort of worts, but it's a bit ugly and also pretty brittle.

Add tests

As the features are added, we need to ensure that older features are not broken.

I don't know how exactly we'll test this. But may be have test.org and test-golden.md, and then ensure that the exported test.md matches test-golden.md?

  • Add tests
  • Make them auto-checking fa50ff0
  • Run make test using Travis 59f0003
  • Run for multiple Emacs versions 59f0003

Enable export of images to /static/ directory

Add a defcustom which allows images (and maybe also other local links?) to be exported to the /static/ directory, and the link target to be rewritten to point to the new file.

  • add defcustom
  • add export option(s)
  • modify export behaviour, either by rewriting org-md-link from ox-md.el, or by adding an export filter.

cf. also #3 which also affects image export.

The top-most Markdown heading level in a post should be level-2

Always translate level N Org headline to level N+1 Markdown headline because Markdown level 1 headline and HTML title both get the HTML <h1> tag, and we do not want the top-most heading of a post to look the exact same as the post's title.

So, within a post, * Heading 1 should translate to ## Heading 1 in Markdown.

Support Org > mmark

mmark is supported in Hugo since v0.15 [Release Notes].

I haven't yet used mmark.

Also given the popularity of mmark (162 stars as of today) vs blackfriday (2470 stars), marking it as a wishlist item. So it won't be implemented unless someone jumps in to help develop the support.

Implicit menu weight

[Reference]

@titaniumbones What if we remove the ability to specify the weight using :weight? Just as we derive Hugo meta-data from Org-ness (like heading -> title, TODO -> draft, etc.), we can derive the weight implicitly from the order of headings.

If a user needs to change the weight, they would simply need to reorder the headings.

So order of Org headings would then be the same as the menu order.

WDYT?

Error when exporting: Symbol’s function definition is void: when-let*

ox-hugo is a great idea, thanks.

Forgive me if I've missed something obvious, but when I run org-hugo-export-subtree-to-md using the all-posts.org example file I see the following error and no files are rendered:

[ox-hugo] Exporting ‘Post 1’ ..
helm-M-x: Symbol’s function definition is void: when-let*

I don't know the best way to post my environment info, but I'm using Spacemacs (tried both master (0.200.9) and develop as of today.

Emacs (emacs-plus via Homebrew) 25.2.1

Fix incorrect smart quotes

This Org:

** Footnotes 1
:PROPERTIES:
:EXPORT_DATE: 2017-07-21
:EXPORT_FILE_NAME: footnotes-1
:END:
This is some text[fn:1].

/Note to self: You *cannot* name an Org heading 'Footnotes'; that's
reserved by Org to store all the footnotes./
* Footnotes
[fn:1] First footnote

converts to this Markdown:

This is some text[^fn:1].

_Note to self: You **cannot** name an Org heading &rsquo;Footnotes&rsquo;; that&rsquo;s
reserved by Org to store all the footnotes._

[^fn:1]: First footnote

Note that right-single quotes are used on both sides of Footnotes here: &rsquo;Footnotes&rsquo;;.

Disabling smart quotes in Org export fixes this.

Support multiple section posts in the same Org file

Example:

* Posts
:PROPERTIES:
:EXPORT_HUGO_SECTION: posts
:END:
** Post 1
:PROPERTIES:
:EXPORT_FILE_NAME: post-1
:END:
* Articles
:PROPERTIES:
:EXPORT_HUGO_SECTION: articles
:END:
** Article 1
:PROPERTIES:
:EXPORT_FILE_NAME: article-1
:END:

What's the best way to add frontmatter to a post?

@helloyi's implementation uses a somewhat complex parser that ends with a simple concat command.

I think a good solution would have the following characteristics:

  • use the built-in export-filter system (seems more elegant) (fixed in #8)
  • allow user-defined export properties. The other implementation defines a small set of properties and writes them to the front of the file. A better solution would be to allow any :HUGO_ properties to be included in the export, since different hugo themes & sites support different export props.

(also, I hope it's ok to be filing all these issues -- if you'd rather communicate some other way let me know!)

Support footnotes

In Org:

Something[fn:1].
* Footnotes
[fn:1] Some footnote

should translate to

Something[^fn:1].

[^fn:1]: Some footnote

Auto-generate the config.toml

  • If a config.toml does not exist, auto-generate it from a template.
  • Option to auto-generate the config.toml during each export, basically user will not be allowed to manually update the config.toml. All config.toml options need to be parsed somehow from the source Org file.

Date should be optional in the front-matter?

Hugo (or some themes?) allows for posts/pages to not have a date in the front-matter. But, ox-hugo seems to always add the current date, even when a post doesn't have EXPORT_DATE set. Should this be configurable?

Walk headlines should not export just level 1 headlines

If I have

* Section A
** Section A Post 1
** Section A Post 2
* Section B
** Section B Post 1
** Section B Post 2

it should export one .md file for each "Post" heading.

Need to now figure out how to mark a subtree as a "Post" subtree.

Implement derived backend

Given #3, it seems best to simply implement a new derived backend that properly exports blackfriday-flavoured markdown. ox-gfm.el is about 350 lines of code, and most of it can be reused. It would be nice to just derive from ox-gfm and change the few lines that need changing,, but since it's not part of org-mode right now that may be difficult.

Heres ox-gfm:
https://github.com/larstvei/ox-gfm/blob/master/ox-gfm.el

Would be nice to also generate the front matter in a more standard ox fashion. I'm not sure how front matter is usually handled by org exporters, but https://github.com/yyr/org-mode/blob/master/lisp/ox-html.el bay be a place to look.

Support setting ordered list item numbers

Org syntax:

1. Item 1
2. Item 2
3. [@10] Item 10!

or (the actual numbers used in the list don't actually matter)

1. Item 1
1. Item 2
1. [@10] Item 10!

Reference

  • Ordered list items start with a numeral followed by either a period or a right parenthesis, such as 1. or 1). If you want a list to start with a different value (e.g., 20), start the text of the item with [@20]. Those constructs can be used in any item of the list in order to enforce a particular numbering.

Better support for html attributes

We will often want to add classes and other HTML attributes to HTML nodes like images and possibly headlines, etc, using the org :HTML_*: syntax. Some markdown parsers like kramdown support this, but blackfriday does not. One workaround would be to call out to the ox-html exporter whenever an HTML attriute is detected in an org element. THis seems kind of arduous. Another, very partial, solution would be to support the standard Hugo figure shortcode, which supports several attributes. There might also be a better, more general solution I haven't figured out.

There's some discussion of this on Github:

table syntax in Hugo differs from vanilla md and gfm

  • vanilla markdown has now table syntax
  • gfm table syntax is
| Heading| Column2|
|----------|----------|
| content | content |

in Hugo's Blackfriday parser, table syntax is

 Heading| Column2
----------/---------
 content | content 

So probably ox-hugo needs to supply its own table parser.

Single subtree exports with wrong file name

Single subtree exports should name the .md file based on the exported headline. But instead it takes the source Org file name.

If I have a foo.org with a subtree with heading Post 1, the exported file should be named something like post_1.md, not foo.md.

Do C-c C-e H H to export only the current subtree.

Deicde how to treat figures

the figure shortcode in Hugo allows images to be embedded in a <figure> tag. Org has its own captioning sy ntax, which AFAIK is not implemented in the markdown exporters. We should decide how to manage this.

Hugo doesn't render code blocks in lists that have Markdown list syntax

Example:

+++
title = "Source block with list syntax in a list"
date = 2017-08-01
tags = ["upstream"]
categories = ["fixme"]
draft = false
+++

As of today (<span class="timestamp-wrapper"><span class="timestamp">&lt;2017-08-02 Wed&gt;</span></span>), an upstream bug in _Blackfriday_
([Issue #239](https://github.com/russross/blackfriday/issues/239)) causes fenced code blocks in lists to not render
correctly if they contain Markdown syntax lists.

Below is an example of such a case:

-   List item 1

    ```md
    - List item 1 in code block
    - List item 2 in code block
    ```
-   List item 2
-   List item 3

Caused by Blackfriday russross/blackfriday#239.

Allow adding custom front matter to posts

Some themes allow using custom front matter fields, other than the standard ones -- for example this theme (screenshot) allows marking posts as best posts

There could be a convention for the headline properties to add these custom fields - something like :EXPORT_FRONT_MATTER_{KEY}: value exporting to key = "value"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.