Integrating my publishing system using org-publish
Seems like I may need to purge my web site source, or maybe use a less-intense system.
This commit is contained in:
parent
465fb840c1
commit
0afe98086d
4 changed files with 619 additions and 2 deletions
|
@ -19,6 +19,7 @@ This creates [[file:~/.emacs.d/init.el][~/.emacs.d/init.el]] that starts the pro
|
|||
- [[file:ha-org-word-processor.org][ha-org-word-processor.org]] :: attempts to make Org files /visually/ look like what one might see in a word processor, including turning off the colors for headers, and instead increasing their size.
|
||||
- [[file:ha-org-clipboard.org][ha-org-clipboard.org]] :: automatically converting HTML from a clipboard into Org-formatted content.
|
||||
- [[file:ha-org-journaling.org][ha-org-journaling.org]] :: for writing journal entries and tasks.
|
||||
- [[file:ha-org-publishing.org][ha-org-publishing.org]] :: code for publishing my website, [[http://howardism.org][www.howardism.org]].
|
||||
- [[file:ha-org-sprint.org][ha-org-sprint.org]] :: functions for working with the my Org-focused sprint files.
|
||||
- [[file:ha-remoting.org][ha-remoting.org]] :: my interface to systems using SSH and Vterm.
|
||||
- [[file:ha-feed-reader.org][ha-feed-reader.org]] :: configuration of elfeed as well as my RSS feeds.
|
||||
|
|
|
@ -49,7 +49,8 @@ Let's get the Straight project working with =use-package=:
|
|||
While that enables the =:straight t= extension to =use-package=, let's just have that be the default:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package straight
|
||||
:custom (straight-use-package-by-default t))
|
||||
:custom (straight-use-package-by-default t
|
||||
straight-default-vc 'git))
|
||||
#+END_SRC
|
||||
See the details in [[https://dev.to/jkreeftmeijer/emacs-package-management-with-straight-el-and-use-package-3oc8][this essay]].
|
||||
** Basic Libraries
|
||||
|
@ -113,7 +114,7 @@ The following loads the rest of my org-mode literate files. I add them as they a
|
|||
"ha-org-word-processor.org"
|
||||
"ha-org-clipboard.org"
|
||||
"ha-org-journaling.org"
|
||||
;; "org-publishing.org"
|
||||
"ha-org-publishing.org"
|
||||
"ha-org-sprint.org"
|
||||
"ha-capturing-notes.org"
|
||||
"ha-programming.org"
|
||||
|
|
414
elisp/ox-rss.el
Normal file
414
elisp/ox-rss.el
Normal file
|
@ -0,0 +1,414 @@
|
|||
;;; ox-rss.el --- RSS 2.0 Back-End for Org Export Engine
|
||||
|
||||
;; Copyright (C) 2013-2015 Bastien Guerry
|
||||
|
||||
;; Author: Bastien Guerry <bzg@gnu.org>
|
||||
;; Keywords: org, wp, blog, feed, rss
|
||||
|
||||
;; This file is not yet part of GNU Emacs.
|
||||
|
||||
;; This program is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This library implements a RSS 2.0 back-end for Org exporter, based on
|
||||
;; the `html' back-end.
|
||||
;;
|
||||
;; It requires Emacs 24.1 at least.
|
||||
;;
|
||||
;; It provides two commands for export, depending on the desired output:
|
||||
;; `org-rss-export-as-rss' (temporary buffer) and `org-rss-export-to-rss'
|
||||
;; (as a ".xml" file).
|
||||
;;
|
||||
;; This backend understands two new option keywords:
|
||||
;;
|
||||
;; #+RSS_EXTENSION: xml
|
||||
;; #+RSS_IMAGE_URL: http://myblog.org/mypicture.jpg
|
||||
;;
|
||||
;; It uses #+HTML_LINK_HOME: to set the base url of the feed.
|
||||
;;
|
||||
;; Exporting an Org file to RSS modifies each top-level entry by adding a
|
||||
;; PUBDATE property. If `org-rss-use-entry-url-as-guid', it will also add
|
||||
;; an ID property, later used as the guid for the feed's item.
|
||||
;;
|
||||
;; The top-level headline is used as the title of each RSS item unless
|
||||
;; an RSS_TITLE property is set on the headline.
|
||||
;;
|
||||
;; You typically want to use it within a publishing project like this:
|
||||
;;
|
||||
;; (add-to-list
|
||||
;; 'org-publish-project-alist
|
||||
;; '("homepage_rss"
|
||||
;; :base-directory "~/myhomepage/"
|
||||
;; :base-extension "org"
|
||||
;; :rss-image-url "http://lumiere.ens.fr/~guerry/images/faces/15.png"
|
||||
;; :html-link-home "http://lumiere.ens.fr/~guerry/"
|
||||
;; :html-link-use-abs-url t
|
||||
;; :rss-extension "xml"
|
||||
;; :publishing-directory "/home/guerry/public_html/"
|
||||
;; :publishing-function (org-rss-publish-to-rss)
|
||||
;; :section-numbers nil
|
||||
;; :exclude ".*" ;; To exclude all files...
|
||||
;; :include ("index.org") ;; ... except index.org.
|
||||
;; :table-of-contents nil))
|
||||
;;
|
||||
;; ... then rsync /home/guerry/public_html/ with your server.
|
||||
;;
|
||||
;; By default, the permalink for a blog entry points to the headline.
|
||||
;; You can specify a different one by using the :RSS_PERMALINK:
|
||||
;; property within an entry.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'ox-html)
|
||||
(declare-function url-encode-url "url-util" (url))
|
||||
|
||||
;;; Variables and options
|
||||
|
||||
(defgroup org-export-rss nil
|
||||
"Options specific to RSS export back-end."
|
||||
:tag "Org RSS"
|
||||
:group 'org-export
|
||||
:version "24.4"
|
||||
:package-version '(Org . "8.0"))
|
||||
|
||||
(defcustom org-rss-image-url "http://orgmode.org/img/org-mode-unicorn-logo.png"
|
||||
"The URL of the an image for the RSS feed."
|
||||
:group 'org-export-rss
|
||||
:type 'string)
|
||||
|
||||
(defcustom org-rss-extension "xml"
|
||||
"File extension for the RSS 2.0 feed."
|
||||
:group 'org-export-rss
|
||||
:type 'string)
|
||||
|
||||
(defcustom org-rss-categories 'from-tags
|
||||
"Where to extract items category information from.
|
||||
The default is to extract categories from the tags of the
|
||||
headlines. When set to another value, extract the category
|
||||
from the :CATEGORY: property of the entry."
|
||||
:group 'org-export-rss
|
||||
:type '(choice
|
||||
(const :tag "From tags" from-tags)
|
||||
(const :tag "From the category property" from-category)))
|
||||
|
||||
(defcustom org-rss-use-entry-url-as-guid t
|
||||
"Use the URL for the <guid> metatag?
|
||||
When nil, Org will create ids using `org-icalendar-create-uid'."
|
||||
:group 'org-export-rss
|
||||
:type 'boolean)
|
||||
|
||||
;;; Define backend
|
||||
|
||||
(org-export-define-derived-backend 'rss 'html
|
||||
:menu-entry
|
||||
'(?r "Export to RSS"
|
||||
((?R "As RSS buffer"
|
||||
(lambda (a s v b) (org-rss-export-as-rss a s v)))
|
||||
(?r "As RSS file" (lambda (a s v b) (org-rss-export-to-rss a s v)))
|
||||
(?o "As RSS file and open"
|
||||
(lambda (a s v b)
|
||||
(if a (org-rss-export-to-rss t s v)
|
||||
(org-open-file (org-rss-export-to-rss nil s v)))))))
|
||||
:options-alist
|
||||
'((:description "DESCRIPTION" nil nil newline)
|
||||
(:keywords "KEYWORDS" nil nil space)
|
||||
(:with-toc nil nil nil) ;; Never include HTML's toc
|
||||
(:rss-extension "RSS_EXTENSION" nil org-rss-extension)
|
||||
(:rss-image-url "RSS_IMAGE_URL" nil org-rss-image-url)
|
||||
(:rss-categories nil nil org-rss-categories))
|
||||
:filters-alist '((:filter-final-output . org-rss-final-function))
|
||||
:translate-alist '((headline . org-rss-headline)
|
||||
(comment . (lambda (&rest args) ""))
|
||||
(comment-block . (lambda (&rest args) ""))
|
||||
(timestamp . (lambda (&rest args) ""))
|
||||
(plain-text . org-rss-plain-text)
|
||||
(section . org-rss-section)
|
||||
(template . org-rss-template)))
|
||||
|
||||
;;; Export functions
|
||||
|
||||
;;;###autoload
|
||||
(defun org-rss-export-as-rss (&optional async subtreep visible-only)
|
||||
"Export current buffer to a RSS buffer.
|
||||
|
||||
If narrowing is active in the current buffer, only export its
|
||||
narrowed part.
|
||||
|
||||
If a region is active, export that region.
|
||||
|
||||
A non-nil optional argument ASYNC means the process should happen
|
||||
asynchronously. The resulting buffer should be accessible
|
||||
through the `org-export-stack' interface.
|
||||
|
||||
When optional argument SUBTREEP is non-nil, export the sub-tree
|
||||
at point, extracting information from the headline properties
|
||||
first.
|
||||
|
||||
When optional argument VISIBLE-ONLY is non-nil, don't export
|
||||
contents of hidden elements.
|
||||
|
||||
Export is done in a buffer named \"*Org RSS Export*\", which will
|
||||
be displayed when `org-export-show-temporary-export-buffer' is
|
||||
non-nil."
|
||||
(interactive)
|
||||
(let ((file (buffer-file-name (buffer-base-buffer))))
|
||||
(org-icalendar-create-uid file 'warn-user)
|
||||
(org-rss-add-pubdate-property))
|
||||
(org-export-to-buffer 'rss "*Org RSS Export*"
|
||||
async subtreep visible-only nil nil (lambda () (text-mode))))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-rss-export-to-rss (&optional async subtreep visible-only)
|
||||
"Export current buffer to a RSS file.
|
||||
|
||||
If narrowing is active in the current buffer, only export its
|
||||
narrowed part.
|
||||
|
||||
If a region is active, export that region.
|
||||
|
||||
A non-nil optional argument ASYNC means the process should happen
|
||||
asynchronously. The resulting file should be accessible through
|
||||
the `org-export-stack' interface.
|
||||
|
||||
When optional argument SUBTREEP is non-nil, export the sub-tree
|
||||
at point, extracting information from the headline properties
|
||||
first.
|
||||
|
||||
When optional argument VISIBLE-ONLY is non-nil, don't export
|
||||
contents of hidden elements.
|
||||
|
||||
Return output file's name."
|
||||
(interactive)
|
||||
(let ((file (buffer-file-name (buffer-base-buffer))))
|
||||
(org-icalendar-create-uid file 'warn-user)
|
||||
(org-rss-add-pubdate-property))
|
||||
(let ((outfile (org-export-output-file-name
|
||||
(concat "." org-rss-extension) subtreep)))
|
||||
(org-export-to-file 'rss outfile async subtreep visible-only)))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-rss-publish-to-rss (plist filename pub-dir)
|
||||
"Publish an org file to RSS.
|
||||
|
||||
FILENAME is the filename of the Org file to be published. PLIST
|
||||
is the property list for the given project. PUB-DIR is the
|
||||
publishing directory.
|
||||
|
||||
Return output file name."
|
||||
(let ((bf (get-file-buffer filename)))
|
||||
(if bf
|
||||
(with-current-buffer bf
|
||||
(org-icalendar-create-uid filename 'warn-user)
|
||||
(org-rss-add-pubdate-property)
|
||||
(write-file filename))
|
||||
(find-file filename)
|
||||
(org-icalendar-create-uid filename 'warn-user)
|
||||
(org-rss-add-pubdate-property)
|
||||
(write-file filename) (kill-buffer)))
|
||||
(org-publish-org-to
|
||||
'rss filename (concat "." org-rss-extension) plist pub-dir))
|
||||
|
||||
;;; Main transcoding functions
|
||||
|
||||
(defun org-rss-headline (headline contents info)
|
||||
"Transcode HEADLINE element into RSS format.
|
||||
CONTENTS is the headline contents. INFO is a plist used as a
|
||||
communication channel."
|
||||
(unless (or (org-element-property :footnote-section-p headline)
|
||||
;; Only consider first-level headlines
|
||||
(> (org-export-get-relative-level headline info) 1))
|
||||
(let* ((author (and (plist-get info :with-author)
|
||||
(let ((auth (plist-get info :author)))
|
||||
(and auth (org-export-data auth info)))))
|
||||
(htmlext (plist-get info :html-extension))
|
||||
(hl-number (org-export-get-headline-number headline info))
|
||||
(hl-home (file-name-as-directory (plist-get info :html-link-home)))
|
||||
(hl-pdir (plist-get info :publishing-directory))
|
||||
(hl-perm (org-element-property :RSS_PERMALINK headline))
|
||||
(anchor (org-export-get-reference headline info))
|
||||
(category (org-rss-plain-text
|
||||
(or (org-element-property :CATEGORY headline) "") info))
|
||||
(pubdate0 (org-element-property :PUBDATE headline))
|
||||
(pubdate (let ((system-time-locale "C"))
|
||||
(if pubdate0
|
||||
(format-time-string
|
||||
"%a, %d %b %Y %H:%M:%S %z"
|
||||
(org-time-string-to-time pubdate0)))))
|
||||
(title (or (org-element-property :RSS_TITLE headline)
|
||||
(replace-regexp-in-string
|
||||
org-bracket-link-regexp
|
||||
(lambda (m) (or (match-string 3 m)
|
||||
(match-string 1 m)))
|
||||
(org-element-property :raw-value headline))))
|
||||
(publink
|
||||
(or (and hl-perm (concat (or hl-home hl-pdir) hl-perm))
|
||||
(concat
|
||||
(or hl-home hl-pdir)
|
||||
(file-name-nondirectory
|
||||
(file-name-sans-extension
|
||||
(plist-get info :input-file))) "." htmlext "#" anchor)))
|
||||
(guid (if org-rss-use-entry-url-as-guid
|
||||
publink
|
||||
(org-rss-plain-text
|
||||
(or (org-element-property :ID headline)
|
||||
(org-element-property :CUSTOM_ID headline)
|
||||
publink)
|
||||
info))))
|
||||
(if (not pubdate0) "" ;; Skip entries with no PUBDATE prop
|
||||
(format
|
||||
(concat
|
||||
"<item>\n"
|
||||
"<title>%s</title>\n"
|
||||
"<link>%s</link>\n"
|
||||
"<author>%s</author>\n"
|
||||
"<guid isPermaLink=\"false\">%s</guid>\n"
|
||||
"<pubDate>%s</pubDate>\n"
|
||||
(org-rss-build-categories headline info) "\n"
|
||||
"<description><![CDATA[%s]]></description>\n"
|
||||
"</item>\n")
|
||||
title publink author guid pubdate contents)))))
|
||||
|
||||
(defun org-rss-build-categories (headline info)
|
||||
"Build categories for the RSS item."
|
||||
(if (eq (plist-get info :rss-categories) 'from-tags)
|
||||
(mapconcat
|
||||
(lambda (c) (format "<category><![CDATA[%s]]></category>" c))
|
||||
(org-element-property :tags headline)
|
||||
"\n")
|
||||
(let ((c (org-element-property :CATEGORY headline)))
|
||||
(format "<category><![CDATA[%s]]></category>" c))))
|
||||
|
||||
(defun org-rss-template (contents info)
|
||||
"Return complete document string after RSS conversion.
|
||||
CONTENTS is the transcoded contents string. INFO is a plist used
|
||||
as a communication channel."
|
||||
(concat
|
||||
(format "<?xml version=\"1.0\" encoding=\"%s\"?>"
|
||||
(symbol-name org-html-coding-system))
|
||||
"\n<rss version=\"2.0\"
|
||||
xmlns:content=\"http://purl.org/rss/1.0/modules/content/\"
|
||||
xmlns:wfw=\"http://wellformedweb.org/CommentAPI/\"
|
||||
xmlns:dc=\"http://purl.org/dc/elements/1.1/\"
|
||||
xmlns:atom=\"http://www.w3.org/2005/Atom\"
|
||||
xmlns:sy=\"http://purl.org/rss/1.0/modules/syndication/\"
|
||||
xmlns:slash=\"http://purl.org/rss/1.0/modules/slash/\"
|
||||
xmlns:georss=\"http://www.georss.org/georss\"
|
||||
xmlns:geo=\"http://www.w3.org/2003/01/geo/wgs84_pos#\"
|
||||
xmlns:media=\"http://search.yahoo.com/mrss/\">"
|
||||
"<channel>"
|
||||
(org-rss-build-channel-info info) "\n"
|
||||
contents
|
||||
"</channel>\n"
|
||||
"</rss>"))
|
||||
|
||||
(defun org-rss-build-channel-info (info)
|
||||
"Build the RSS channel information."
|
||||
(let* ((system-time-locale "C")
|
||||
(title (plist-get info :title))
|
||||
(email (org-export-data (plist-get info :email) info))
|
||||
(author (and (plist-get info :with-author)
|
||||
(let ((auth (plist-get info :author)))
|
||||
(and auth (org-export-data auth info)))))
|
||||
(date (format-time-string "%a, %d %b %Y %H:%M:%S %z")) ;; RFC 882
|
||||
(description (org-export-data (plist-get info :description) info))
|
||||
(lang (plist-get info :language))
|
||||
(keywords (plist-get info :keywords))
|
||||
(rssext (plist-get info :rss-extension))
|
||||
(blogurl (or (plist-get info :html-link-home)
|
||||
(plist-get info :publishing-directory)))
|
||||
(image (url-encode-url (plist-get info :rss-image-url)))
|
||||
(ifile (plist-get info :input-file))
|
||||
(publink
|
||||
(concat (file-name-as-directory blogurl)
|
||||
(file-name-nondirectory
|
||||
(file-name-sans-extension ifile))
|
||||
"." rssext)))
|
||||
(format
|
||||
"\n<title>%s</title>
|
||||
<atom:link href=\"%s\" rel=\"self\" type=\"application/rss+xml\" />
|
||||
<link>%s</link>
|
||||
<description><![CDATA[%s]]></description>
|
||||
<language>%s</language>
|
||||
<pubDate>%s</pubDate>
|
||||
<lastBuildDate>%s</lastBuildDate>
|
||||
<generator>%s</generator>
|
||||
<webMaster>%s (%s)</webMaster>
|
||||
<image>
|
||||
<url>%s</url>
|
||||
<title>%s</title>
|
||||
<link>%s</link>
|
||||
</image>
|
||||
"
|
||||
title publink blogurl description lang date date
|
||||
(concat (format "Emacs %d.%d"
|
||||
emacs-major-version
|
||||
emacs-minor-version)
|
||||
" Org-mode " (org-version))
|
||||
email author image title blogurl)))
|
||||
|
||||
(defun org-rss-section (section contents info)
|
||||
"Transcode SECTION element into RSS format.
|
||||
CONTENTS is the section contents. INFO is a plist used as
|
||||
a communication channel."
|
||||
contents)
|
||||
|
||||
(defun org-rss-timestamp (timestamp contents info)
|
||||
"Transcode a TIMESTAMP object from Org to RSS.
|
||||
CONTENTS is nil. INFO is a plist holding contextual
|
||||
information."
|
||||
(org-html-encode-plain-text
|
||||
(org-timestamp-translate timestamp)))
|
||||
|
||||
(defun org-rss-plain-text (contents info)
|
||||
"Convert plain text into RSS encoded text."
|
||||
(let (output)
|
||||
(setq output (org-html-encode-plain-text contents)
|
||||
output (org-export-activate-smart-quotes
|
||||
output :html info))))
|
||||
|
||||
;;; Filters
|
||||
|
||||
(defun org-rss-final-function (contents backend info)
|
||||
"Prettify the RSS output."
|
||||
(with-temp-buffer
|
||||
(xml-mode)
|
||||
(insert contents)
|
||||
(indent-region (point-min) (point-max))
|
||||
(buffer-substring-no-properties (point-min) (point-max))))
|
||||
|
||||
;;; Miscellaneous
|
||||
|
||||
(defun org-rss-add-pubdate-property ()
|
||||
"Set the PUBDATE property for top-level headlines."
|
||||
(let (msg)
|
||||
(org-map-entries
|
||||
(lambda ()
|
||||
(let* ((entry (org-element-at-point))
|
||||
(level (org-element-property :level entry)))
|
||||
(when (= level 1)
|
||||
(unless (org-entry-get (point) "PUBDATE")
|
||||
(setq msg t)
|
||||
(org-set-property
|
||||
"PUBDATE" (format-time-string
|
||||
(cdr org-time-stamp-formats)))))))
|
||||
nil nil 'comment 'archive)
|
||||
(when msg
|
||||
(message "Property PUBDATE added to top-level entries in %s"
|
||||
(buffer-file-name))
|
||||
(sit-for 2))))
|
||||
|
||||
(provide 'ox-rss)
|
||||
|
||||
;;; ox-rss.el ends here
|
201
ha-org-publishing.org
Normal file
201
ha-org-publishing.org
Normal file
|
@ -0,0 +1,201 @@
|
|||
#+TITLE: Publishing my Website with Org
|
||||
#+AUTHOR: Howard X. Abrams
|
||||
#+EMAIL: howard.abrams@gmail.com
|
||||
#+DATE: 2020-12-22
|
||||
#+FILETAGS: :emacs:
|
||||
|
||||
A literate programming file for publishing my website using org.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :exports none
|
||||
;;; org-publishing.el --- Publishing my website using org. -*- lexical-binding: t; -*-
|
||||
;;
|
||||
;; Copyright (C) 2020 Howard X. Abrams
|
||||
;;
|
||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||
;; Maintainer: Howard X. Abrams <howard.abrams@gmail.com>
|
||||
;; Created: December 22, 2020
|
||||
;;
|
||||
;; This file is not part of GNU Emacs.
|
||||
;;
|
||||
;; *NB:* Do not edit this file. Instead, edit the original literate file at:
|
||||
;; ~/other/hamacs/org-publishing.org
|
||||
;; And tangle the file to recreate this one.
|
||||
;;
|
||||
;;; Code:
|
||||
#+END_SRC
|
||||
* Introduction
|
||||
While the Emacs community have a plethora of options for generating a static website from org-formatted files, I keep my pretty simple, and just use the standard =org-publish= feature.
|
||||
|
||||
While the following packages come with Emacs, they aren't necessarily loaded:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :results silent
|
||||
(require 'ox-rss)
|
||||
(require 'ox-publish)
|
||||
#+END_SRC
|
||||
|
||||
Variable settings:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(setq org-export-with-broken-links t
|
||||
org-mode-websrc-directory "/Volumes/Personal/dropbox/website"
|
||||
org-mode-publishing-directory (concat (getenv "HOME") "/website-public/"))
|
||||
#+END_SRC
|
||||
* The Projects
|
||||
I separate my /website/ into distinct projects separately built:
|
||||
|
||||
- =blog-content= :: The bulk of rendering my =website= org files into HTML
|
||||
- =blog-static= :: All of the assets, like images are easily copied in place
|
||||
- =blog-rss= :: Regenerate the feeder files
|
||||
- =org-notes= :: Optionally render a non-web site collection of notes.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(setq org-publish-project-alist
|
||||
`(("all"
|
||||
:components ("blog-content" "blog-static" "org-notes" "blog-rss"))
|
||||
|
||||
("blog-content"
|
||||
:base-directory ,org-mode-websrc-directory
|
||||
:base-extension "org"
|
||||
:publishing-directory ,org-mode-publishing-directory
|
||||
:recursive t
|
||||
:publishing-function org-html-publish-to-html
|
||||
:preparation-function org-mode-blog-prepare
|
||||
:export-with-tags nil
|
||||
:headline-levels 4
|
||||
:auto-preamble t
|
||||
:auto-postamble nil
|
||||
:auto-sitemap t
|
||||
:sitemap-title "Howardisms"
|
||||
:section-numbers nil
|
||||
:table-of-contents nil
|
||||
:with-toc nil
|
||||
:with-author nil
|
||||
:with-creator nil
|
||||
:with-tags nil
|
||||
:with-smart-quotes t
|
||||
|
||||
:html-doctype "html5"
|
||||
:html-html5-fancy t
|
||||
;; :html-preamble org-mode-blog-preamble
|
||||
;; :html-postamble org-mode-blog-postamble
|
||||
;; :html-postamble "<hr><div id='comments'></div>"
|
||||
:html-head "<meta http-equiv=\"X-Clacks-Overhead\" content=\"GNU Terry Pratchett\" />
|
||||
<link href='http://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
|
||||
<link href='http://fonts.googleapis.com/css?family=Source+Serif+Pro:400,700&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
|
||||
<link href='http://fonts.googleapis.com/css?family=Source+Code+Pro:400,700' rel='stylesheet' type='text/css'>
|
||||
<link rel=\"stylesheet\" href=\"/css/styles.css\" type=\"text/css\"/>\n"
|
||||
:html-head-extra "<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js\"></script>
|
||||
<script src=\"/js/magic.js\"></script>
|
||||
<link rel=\"icon\" href=\"/img/dragon.svg\">
|
||||
<link rel=\"shortcut icon\" href=\"/img/dragon-head.png\">
|
||||
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />"
|
||||
:html-head-include-default-style nil)
|
||||
|
||||
("blog-static"
|
||||
:base-directory ,org-mode-websrc-directory
|
||||
:base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf\\|svg"
|
||||
:publishing-directory ,org-mode-publishing-directory
|
||||
:recursive t
|
||||
:publishing-function org-publish-attachment)
|
||||
|
||||
("blog-rss"
|
||||
:base-directory ,org-mode-websrc-directory
|
||||
:base-extension "org"
|
||||
:rss-image-url "http://howardism.org/img/dragon-head.png"
|
||||
:publishing-directory ,org-mode-publishing-directory
|
||||
:publishing-function (org-rss-publish-to-rss)
|
||||
:html-link-home "http://www.howardism.org/"
|
||||
:html-link-use-abs-url t
|
||||
:with-toc nil
|
||||
:exclude ".*"
|
||||
:include ("index.org"))
|
||||
|
||||
("org-notes"
|
||||
:base-directory "~/technical/"
|
||||
:base-extension "org"
|
||||
:publishing-directory ,(concat org-mode-publishing-directory "/notes/")
|
||||
:recursive t
|
||||
:publishing-function org-html-publish-to-html
|
||||
:headline-levels 4 ; Just the default for this project.
|
||||
:auto-preamble t
|
||||
:auto-sitemap t ; Generate sitemap.org automagically...
|
||||
:makeindex t
|
||||
:section-numbers nil
|
||||
:style "<link rel=\"stylesheet\" href=\"../css/styles.css\" type=\"text/css\"/> <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js\" type=\"text/javascript\"></script> <link href=\"http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/smoothness/jquery-ui.css\" type=\"text/css\" rel=\"stylesheet\" /> <script src=\"https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js\" type=\"text/javascript\"></script> <script =\"text/javascript\" src=\"js/magic.js\"></script>"
|
||||
:table-of-contents nil
|
||||
:with-author nil
|
||||
:with-creator nil
|
||||
:with-tags nil)
|
||||
|
||||
("org-notes-static"
|
||||
:base-directory "~/technical/"
|
||||
:base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf"
|
||||
:publishing-directory ,(concat org-mode-publishing-directory "/other/")
|
||||
:recursive t
|
||||
:publishing-function org-publish-attachment)))
|
||||
#+END_SRC
|
||||
* Including Sections
|
||||
In the project definitions, I reference a =pre-= and =postamble= that allow me to inject some standard HTML file headers and footers:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun org-mode-blog-preamble (options)
|
||||
"The function that creates the preamble top section for the blog.
|
||||
OPTIONS contains the property list from the org-mode export."
|
||||
(message "Preamble options: %s" (princ options))
|
||||
(let ((base-directory (plist-get options :base-directory)))
|
||||
(org-babel-with-temp-filebuffer (expand-file-name "top-bar.html" base-directory) (buffer-string))))
|
||||
|
||||
(defun org-mode-blog-postamble (options)
|
||||
"The function that creates the postamble, or bottom section for the blog.
|
||||
OPTIONS contains the property list from the org-mode export."
|
||||
(let ((base-directory (plist-get options :base-directory)))
|
||||
(org-babel-with-temp-filebuffer (expand-file-name "bottom.html" base-directory) (buffer-string))))
|
||||
#+END_SRC
|
||||
|
||||
Another helper function for the content of website is to make sure to update =index.org=, so that the RSS gets generated.
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun org-mode-blog-prepare (&optional options)
|
||||
"`index.org' should always be exported so touch the file before publishing."
|
||||
(let* ((base-directory (plist-get options :base-directory))
|
||||
(buffer (find-file-noselect (expand-file-name "index.org" base-directory) t)))
|
||||
(with-current-buffer buffer
|
||||
(set-buffer-modified-p t)
|
||||
(save-buffer 0))
|
||||
(kill-buffer buffer)))
|
||||
#+END_SRC
|
||||
* Keybindings
|
||||
Make it easy to publish all or just some of my website:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(general-evil-define-key 'normal org-mode-map
|
||||
:prefix "SPC m"
|
||||
"p" '(:ignore t :which-key "publishing")
|
||||
"p a" '("all" . org-publish-all)
|
||||
"p p" '("project" . org-publish-project))
|
||||
#+END_SRC
|
||||
|
||||
And let's put a /leader key/ sequence for my favorite file on my website:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(ha-leader
|
||||
"f h" '(:ignore t :which-key "howards")
|
||||
"f h w" '("website index" . (lambda ()
|
||||
(find-file (expand-file-name "index.org" "~/website")))))
|
||||
#+END_SRC
|
||||
* Technical Artifacts :noexport:
|
||||
Let's =provide= a name so we can =require= it:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :exports none
|
||||
(provide 'ha-org-publishing)
|
||||
;;; ha-org-publishing.el ends here
|
||||
#+END_SRC
|
||||
|
||||
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
||||
|
||||
#+DESCRIPTION: A literate programming version for publishing my website using org.
|
||||
|
||||
#+PROPERTY: header-args:sh :tangle no
|
||||
#+PROPERTY: header-args:emacs-lisp :tangle yes
|
||||
#+PROPERTY: header-args :results none :eval no-export :comments no mkdirp yes
|
||||
|
||||
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil date:nil
|
||||
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
|
||||
#+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js
|
Loading…
Reference in a new issue