+++ title = "Setting Up Blogging with Emacs" [categories] tags = [ "emacs" ] categories = [ "apps" ] +++ I\'d like to blog more notes on stuff I do and it would be nice to have a smooth workflow in my editor of choice. It is too late to explain a lot, but all these things were proudly found elsewhere. See the references list at the end of this post. # Creating the blog project To deploy to github as a personal blog you have to create a repo in the form **\.github.io**. Since I name my projects the same as the repos the name was a quick choice. The structure is as follows: ``` -+- blog -+- posts -+- | +- org-template -+- | +- css -+- +- public -+- +- .github -+- workflow --- main.yml +- publish.el +- Makefile ``` # Configuring org-publish This is what the **publish.el** file is for. Prepare some snippets for the HTML pages First off, a link to the CSS: ``` lisp (setq website-html-head "") ``` Let\'s also add a navigation menu at the top of each page: ``` lisp (setq website-html-preamble "") ``` And a footer : ``` lisp (setq website-html-postamble "
Copyright 2020 %a (%v HTML).
Last updated %C.
Built with %c.
") ``` And now we can all tie it together by creating the **org-publish-project-alist**: ``` lisp (setq org-publish-project-alist `(("posts" ;; configure project structure :base-directory "blog/posts/" :base-extension "org" :publishing-directory "public/" :recursive t :publishing-function org-html-publish-to-html ;; configure index creation :auto-sitemap t :sitemap-title "Blog Index" :sitemap-filename "index.org" :sitemap-style tree :sitemap-file-entry-format "%d - %t" :sitemap-sort-files anti-chronologically :html-doctype "html5" :html-html5-fancy t :html-head ,website-html-head :html-preamble ,website-html-preamble :html-postamble ,website-html-postamble :author "Peter Tillemans" :email "pti@snamellit.com" :with-creator t) ("blog-static" :base-directory "blog/posts/" :base-extension "png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf" :publishing-directory "public_html/" :recursive t :publishing-function org-publish-attachment) ("css" :base-directory "blog/css/" :base-extension "css" :publishing-directory "public/css" :publishing-function org-publish-attachment :recursive t) ("all" :components ("posts" "css" "blog-static")))) ``` # Make local testing easy The commands to build the blog are not hard, but hard to remember and hard to type. Let\'s make a makefile to help: ``` makefile .PHONY: all publish publish_no_init all: publish publish: publish.el @echo "Publishing... with current Emacs configurations." emacs --batch --load publish.el --funcall org-publish-all publish_no_init: @echo "Publishing... with --no-init" emacs --batch --no-init --load publish.el --funcall org-publish-all clean: @echo "Cleaning up..." rm -rf public @rm -rvf *.elc @rm -rvf public @rm -rvf ~/.org-timestamps/* serve: publish @echo "Serving site" python -m http.server --directory public ``` For local testing just do: ``` sh $ make clean serve ``` If the only change is new content then not cleaning is much faster. # Deploy to Github Pages A slightly modified version of the initial workflow will do the publishing: ``` yaml # This is a basic workflow to help you get started with Actions name: CI # Controls when the action will run. Triggers the workflow on push or pull request # events but only for the master branch on: push: branches: [ master ] pull_request: branches: [ master ] # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: # This workflow contains a single job called "build" build: # The type of runner that the job will run on runs-on: ubuntu-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: - uses: actions/checkout@master with: fetch-depth: 1 - name: build uses: docker://iquiw/alpine-emacs if: github.event.deleted == false with: args: emacs --batch --load publish.el --funcall org-publish-all - name: deploy uses: peaceiris/actions-gh-pages@v1.1.0 if: success() env: GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} PUBLISH_BRANCH: gh-pages PUBLISH_DIR: ./public ``` Note that you need to put a secret **PERSONAL~ACCESSTOKEN~** with an access token which has basic push access to the repo to push the built site to the gh-pages branch. For the emacs call, I just copied the command from the **Makefile**. After a push the site is usually up by the time I check, say in about a minute. # Setting up a Capture Template This proved to be the hardest part to get working. I am using **Doom Emacs** so I wrap everything in **with-eval-after-load**. The challenge was that the title is needed to create the slug for the filename and then again as title for the post. So my ugly solution is to stuff it in a variable and get the variable back in the template. ``` lisp (with-eval-after-load 'org-capture (defvar snamellit/blog-title "test-title") (setq snamellit-blog-template "#+title: %(progn snamellit-blog-title) #+date: %t #+author: Peter Tillemans #+email: pti@snamellit.com %?") (defun snamellit/capture-blog-post-file () (let* ((title (read-from-minibuffer "Post Title: ")) (slug (replace-regexp-in-string "[^a-z0-9]+" "-" (downcase title)))) (setq snamellit/blog-title title) (format "~/Projects/ptillemans.github.io/blog/posts/%s-%s.org" (format-time-string "%Y-%m-%d" (current-time)) slug))) (add-to-list 'org-capture-templates '("b" "Blog Post" plain (file snamellit/capture-blog-post-file) (file "~/.doom.d/tpl-blog-post.org")))) ``` The **tpl-blog-post.org** template file : ``` #+title: %(progn snamellit/blog-title) #+date: %<%Y-%m-%d> %? ``` It is very minimal and I\'d like to keep it that way. # In use To create a blog post - SPC-X b will create the post - Give a title for the post - A template file is created (unfortunately in plain text) - Enter the idea, hook and save with C-c C-c - Open the org file with SPC-f r (open recent file) - Flesh out the post using org-mode goodness - save, commit and push to git After push the github action will bring it live # References Following links were useful in setting this up: - [How to blog with Emacs Org mode](https://opensource.com/article/20/3/blog-emacs) - [GitHub Pages documentation](https://docs.github.com/en/free-pro-team@latest/github/working-with-github-pages/about-github-pages) - [The Org Mode Manual](https://orgmode.org/org.html) - [The Meg in Progress post on building a static blog with org-mode.](https://meganrenae21.github.io/Meg-in-Progress/posts/blogging-with-org-mode.html) - [Website with org-mode](https://thenybble.de/projects/orgsite.html) - [Richard Kallos\' post on site generation with Org Mode](https://rkallos.com/blog/2017/01/02/static-site-generation-with-org-mode/) - [Blogging with Org mode](https://www.brautaset.org/articles/2017/blogging-with-org-mode.html) - [Org Capture Tricks from Storax](https://storax.github.io/blog/2016/05/02/org-capture-tricks/)