DynSite: Dynamic Org 2 HTML Project definition

Table of Contents

This is a guide to using the dynamic org-to-html publishing project definition scheme called DynSite.

DynSite is an extension of the default project publishing scheme of orgmode. Instead of writing project definitions in emacs-lisp as is done in the original orgmode publishing scheme, the present extension allows one to define and customize the projects by putting them in folders and to define their custom parameters in plain text, using orgmode markup.

Overview: Features of the dynsite package

Minimal setup effort

The dynsite package builds on the standard org-publish scheme. It provides functions which simplify the definition of groups of projects. Instead of defining projects in emacs-lisp by creating lists of settings for folders and properties, one defines for each site one source folder and one target folder only. Any number of projects or subprojects can be defined inside a source folder. Dynsite scans all folders of a site, and creates projects for those folders which contain a file config.org, naming each project after the name of the folder that contains it. Projects in subfolders inherit the configuration parameters of their superfolder-projects.

Dynamic completion of relative paths in subfolders

An important feature is the automatic completion of relative paths of links, which keeps the links to css or other files consistent even in subfolders of a project. For example:

If the path to a css file, which is used for headers defining the page style of a all files in a site, is ./css/org.css, then normally a file which is placed in a subfolder of the projects' top folder must change the path of the css style link to ./../css/org.css. Org-mode > 8.0 provides a mechanism for doing this simpler described in the doc (http://orgmode.org/worg/org-tutorials/org-publish-html-tutorial.html) in paragraph /"Tired of export templates?"/. Dynsite provides a scheme that is simpler than that. In order to make any link update to a relative path to the root folder, one codes the "root folder" of the project with the string {{.}}. So instead of defining the style path in html-head as:

<link rel="stylesheet" href="./css/org.css" type="text/css"/>

one defines it as:

<link rel="stylesheet" href="{{.}}/css/org.css" type="text/css"/>

Dynsite adds a filter to org-export-filter-final-output-functions which converts the string . to a relative path consitently pointing to the original css file. The same holds for all other links inside the org files to be published.

Orgmode publishing and DynSite working principles

The html publishing scheme of orgmode allows one to define groups of files which share the same configuration (headers, footers, css style files etc.), so that these files are puglished together with one command. Such a group of files is called a project. It is possible to define many projects. One can publish a project with the command org-publish-project. To define a project in orgmode one has to code its specifications in emacs-lisp. Coding this is cumbersome, especially because any html strings that will be included in the files as headers, footers etc. must be coded as lisp-strings, which requires double-escaping html characters such as tag delimiters and other elements. The present tool, DynSite, makes the project definition process easier by letting one define a projects parameters in a config file written in org mode. It simplifies the specification of projects further by grouping these in subfolders of one folder. A group of projects contained under one folder is called a site. In DynSite, one defines one site by specifying the following three elements:

  1. Site source folder: The location of the folder which contains the project subfolders.
  2. Site target folder: The folder where these projects should be published as html.
  3. The method for uploading the published html files to the server.

The folder structure of the published files inide the site target folder is the same as the folder structure of the site source.

To define a project inside the Site source folder one creates a file named config.org in it. This file contains the configuration of the project, i.e. web page name, headers, footers, style etc. One can put a config.org file in any subfolder of the site, including a subfolder of a folder that already contains a project. Project characteristics are inherited. Projects are named after the name of the folder which contains them. For example, consider a site source folder named "mysite", containing the following folders and files:

mysite
   config.org
   index.org
   ...
   proj1/
      config.org
      proj1page1.org
      ...
   proj2/
      config.org
      proj2.org
      ...
      subproj1/
          config.org
          subproj1.org
          ...

The above folders and files define the projects mysite, proj1, proj2 and subproj1. subproj1 inherits its specifications from proj2. proj1 and proj2 inherit their style specifications from project mysite. DynSite provides commands for publishing all projects of a site, or a selected project by name.

One can define any number of sites in DynSite. But only one site is current at any time. One chooses the current site by its name with the command org-choose-site.

Quick setup

@<b>For a summary of all commands and quick configuration guide for setting up a site see here.@</b>

Defining a site

Here is the definition of a site which takes its source files (org) from ~/SitesSource/ and publishes the result in ~/Sites/. (Note: ~/Sites/ is the default folder for a user's personal home page files in MacOS X).

(org-install-site 
     '(
;; name of your site: 
	"my-site" 
;; path of the folder containing the all org project files:
	"~/SitesSource" 
;; path of the folder where the html files will be published:
	"~/Sites" 
;; this string will be used as address to upload files to web with rsync:
	"earlabor@earlab.org:public_html/larigot-tests/"
))

In MacOS X one can browse the resulting site by accessing it via the file protocol: file:////Users/username/Sites/index.html or, if Apache is running on the local computer, with: http://localhost/~username/ .

Site File Structure

Source and Target Folders

For each site defned with DynSite expects all org-to-html projects to be stored as subfolders of one single folder. For example, if one has 3 projects named project1, project2 and project3, one could place them in one folder named org as follows:

path contents
/users/user1/websites/org top folder containing all projects
/users/user1/website/org/project1 all files (and folders) of project1
/users/user1/website/org/project2 all files (and folders) of project2
/users/user1/website/org/project2 all files (and folders) of project3

These projects are published in subfolders of the single target folder specified in the site definition, preserving the same structure as the source folder.

It is possible to work with several different sites, where each site has its own source folder (the org project files), its own target folder (the published html files) and a url for uploading the rendered html files to a server using rsync. See Working with multiple sites below.

Project Definition

There is only one rule for defining a project:

If a folder is contained in the top folder containing all projects and this folder contains a file called config.org then this folder becomes a project folder.

This means: To define a new project for publishing, you must do 2 things:

  1. Create a folder for the project, which is contained inside the top folder holding all projects, or one of its subfolders
  2. Create a file called config.org inside the top level of the folder that contains the project.

The contents of the file config.org define the properties of the project, i.e. they customize the project. In orgmode, the publishing options of a project are defined as (emacs-lisp) properties. These are described in section "13.1.5 Options for the HTML/LaTeX exporters" of the org-info documentation (type "meta-x org-info" to enter the org-info documentation, then go to section (menu item) Publishing, subsection Configuration, subsubsection "Publishing options"). The config.org file lets one define these properties in a simpler way, without writing them as lisp expressions. This is done as follows:

A property consists of a name (the name of the property) and a value (the value of the property). In the config.org file, the name of the property is given as a top-level org-node entry and the value of the property is given as the contents of the entry. For example, to define the property "author" giving it the value "Tom Jones", one puts the following node in the config.org file:

* author
Tom Jones

A special case are properties whose values are not strings (such as the string "Tom Jones" above), but lisp objects such as numbers, functions or other types of objects. These are indicated in the config.org file by appending ":" to the name of the property, and are entered as expressions that are evaluated by lisp, in the same line as the property name. For example, If a property needs to have a numerical value, or an otherwise computed value, this value is written as an expression that can be evaluated by lisp, in a single line. For example, to set the property "section-numbers" to the value "nil", one writes:

* section-numbers: nil

Second example: To set the property "headline-levels" to 3, one writes:

* headline-levels: 3

Following example compares the configuration of a project using lisp source code with the same configuration done using config.org in DynSite.

;; Webtools project. Configuration using the original emacs-lisp code method of orgmode: 
(add-to-list 'org-publish-project-alist
	'("webtools"
	 :base-directory "~/Dropbox/orgshared/sites/org/earlab/tools/webtools/"
	 :base-extension "org"
	 :publishing-directory "~/Dropbox/orgshared/sites/html/earlab/tools/webtools/"
	 :section-numbers nil
	 :table-of-contents nil
	 :recursive t
	 :publishing-function org-publish-org-to-html
	 :headline-levels 1        
	 :auto-preamble t
	 :preamble 
	 "
<div id=\"toc\">
<a href=\"http://earlab.org/\">Earlab Home</a> | 
<a href=\"http://earlab.org/tools/webtools\">Web Tools Home</a> | 
<a href=\"http://earlab.org/tools/webtools/gettingstart.html\">Getting Started</a> | 
<a href=\"http://earlab.org/tools/webtools/javascript.html\">JavaScript</a> | 
<a href=\"http://earlab.org/tools/webtools/projects.html\">Projects</a> | 
<a href=\"http://earlab.org/tools/webtools/tutorials.html\">Tutorials</a> | 
<a href=\"http://earlab.org/tools/webtools/topics.html\">Topics</a> | 
<a href=\"http://earlab.org/tools/webtools/links.html\">Links</a> |  
</div> 

<div style = \"position: absolute; top: 10px; left: 10px; \">
 <FORM METHOD=\"POST\" ACTION=\"/tools/webtools/cgi-bin/3.0/search_engine.cgi\"><INPUT TYPE=\"text\" SIZE=\"20\" NAME=\"keywords\" MAXLENGTH=\"80\"><INPUT TYPE=\"SUBMIT\" VALUE=\"Search\"></FORM> 
</div>

"
	 :style "
<link rel=\"stylesheet\" href=\"http://ambiant.earlab.org/css/org.css\" type=\"text/css\"/>
"
	 :auto-index t
	 :table-of-contents t
	 :author "Ioannis Zannos & Aris Bezas"
	 :email  "zannos AT gmail DOT com  & aribezas AT gmail DOT com"
)
	)

;; Copy files from tool to ambiant workshop2011
(add-to-list 'org-publish-project-alist
	'("copy-webtools-files"
	 :base-directory "~/Dropbox/orgshared/sites/org/earlab/tools/webtools/"
	 :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf\\|zip"
	 :publishing-directory "~/Dropbox/orgshared/sites/html/earlab/tools/webtools/"
	 :recursive t
	 :publishing-function org-publish-attachment
	 )

       )

To define the same project using DynSite one writes the following text in the config.org file which is contained in the folder that holds the org files of he project:

* section-numbers: nil
* table-of-contents: nil
* recursive: t
* headline-levels: 1
* auto-preamble: t
* preamble
<div id="toc">
<a href="http://earlab.org/">Earlab Home</a> | 
<a href="http://earlab.org/tools/webtools">Web Tools Home</a> | 
<a href="http://earlab.org/tools/webtools/gettingstart.html">Getting Started</a> | 
<a href="http://earlab.org/tools/webtools/javascript.html">JavaScript</a> | 
<a href="http://earlab.org/tools/webtools/projects.html">Projects</a> | 
<a href="http://earlab.org/tools/webtools/tutorials.html">Tutorials</a> | 
<a href="http://earlab.org/tools/webtools/topics.html">Topics</a> | 
<a href="http://earlab.org/tools/webtools/links.html">Links</a> | 
</div>
* style
<link rel="stylesheet" href="./css/org.css" type="text/css"/>
* auto-index: t
* table-of-contents: t
* author: "Ioannis Zannos & Aris Bezas"
* email:  "zannos AT gmail DOT com  & aribezas AT gmail DOT com"

Note that the definition of the project is much shorter in config.org, because many items are automatically provided by DynSite based on the location and name of the folder which contains the project:

  • The name of the project is provided by the name of the folder that contains the config.org and the org content files.
  • The base directory is inferred automatically.
  • The publishing directory is inferred automatically.
  • The publishing function is provided automatically
  • The project for publishing configuration and media files (css, png, mp3, etc) is created automatically

You can add a site to the list of sites as follows (but this will not make it current):

(add-to-list 'org-sites org-current-site '(<site name> <org path> <html path> <upload url>))

Example:

(add-to-list 'org-sites '( "larigot-earlab" "~/Dropbox/orgshared/sites/org/larigot-tests" "~/Dropbox/orgshared/sites/html/larigot-tests" "earlabor@earlab.org:public_html/larigot-tests/"))

To add a site and make it current use the function org-install-site as described in the next section.

The Project List

Project inheritance

If a project folder a contains a folder b that defines another project, then the project defined in folder b inherits the properties of project a. The property values set in b overwrite any properties with the same name set by a. b is called a subproject of a, and a is called a superproject of b.

The name of each project is generated from the name of the folder that contains it, and the names of its superprojects, separated by "<". For example, if we have two projects contained in folders like this:

./mainproject ./mainproject/subproject

then the project contained in folder ./mainproject/subproject will be called subproject<mainproject.

Org and static projects

For each folder that contains a config.org file, DynSite generates three projects:

  1. A project for the org files of the site only. This contains the org files which will be translated to html.
  2. A "static" project containing non-org files of the site (css, jpeg, mp3, pdf or other files). These files are simply copied over to the target folder as-is, without any translation.
  3. A project including both the org-files and the non-org files.

The non-org file projects are named by appending "-static" to the name of the org project. The projects containing both the org and the non-org files are named by appending "-all" to the name of the org project.

Additionally there are generated 3 project groups: "all", "all-all", and "all-static" that contain all org, static and combined org/static projects of a site. The projects are named after the folder that contains them plus the list of superfolders, so as to be immediately identifiable. For example, the projects of the site defined in folder dynsite-org in the present documentation are:

"all-all"
All projects of the website.
"dynsite-org-all"
All projects of the dynsite project (= top project).
"dynsite-org"
The org files of the dynsite project, that is, the org files, which will be rendered in html.
"dynsite-org-static"
The static project of dynsite, that is, media and other files which are not rendered but only copied.
"subproject<dynsite-org-all"
All files of the project contained in folder subproject.
"subproject<dynsite-org"
Only the org files of the project subproject
"subproject<dynsite-org-static"
Only the static files of the project subproject

Installing a Site

Run this to install your own site in the list of sites and make it the current site to work on:

(org-install-site <site definition list>)

Example:

(org-install-site 
     '(
;; name of your site: 
	"larigot-earlab" 
;; path of the folder containing the all org project files:
	"~/Dropbox/orgshared/sites/org/larigot-tests" 
 ;; path of the folder where the html files will be published:
	"~/Dropbox/orgshared/sites/html/larigot-tests" 
 ;; this string will be used as address to upload files to web with rsync:
	"earlabor@earlab.org:public_html/larigot-tests/"
))

Publish+Upload a Site

(meta-x:) org-republish-and-upload-site

This command is bound to the keyboard shortcut super-meta-control-shift-p (where "super" is the cmd key on the mac or the windows key on windows, and meta is opt or alt or escape depending on your keyboard and emacs setup).

This is the most basic command for publishing a site. It generates all the projects of the site from the config.org files, publishes the projects, then opens a shell window and types the rsync command for uploading the site.

Working with multiple sites

Adding a site

The list of known org-publish websites is stored in variable org-sites. This is a list of the form:

((name org-site-root org-site-html org-site-url) (name org-site-root ...) ...) (see above at Installing a Site

Each element of the list has the form (name org-site-root org-site-html org-site-url), where:

  • name is the name of the site
  • org-site-root is the path of the root folder containing the org files
  • org-site-html is the path of the root folder which will hold the exported html files. If it is nil, it is deduced from org-site-root by adding a folder "html" inside the folder org-site-root.
  • org-site-url is the root url of the site, used to upload the site files with rsync

The default value of the org-sites list is:

(("default" "~/org" nil "earlabor@earlab.org:~/public_html/org/"))

This means that there is only one default site, named "default".

To add a new site definition to the list of known sites without making it current use the function add-to-list. Example:

(add-to-list 'org-sites '("site2" "~/site2" "~/site2_published" "tomjones@jones.com:~/public_html/"))

To add a site and make it current use the function org-install-site (see above Installing a Site)

Choosing one site to work with, from the list of known sites

  1. Type: meta-x org-choose-site
  2. Type the "tab" key to show all known sites

Choose a site by typing the initial names of its name and using the tab-key to autocomplete the rest of the name. Then type return to install the chosen site as current.

Generate projects

When adding a new project folder to a site, one must re-scan the folders of the site to add the new project to the list of projects of the site. The function org-build-projects scans the contents of the site folder for config.org files and builds all projects from their contents:

meta-x org-build-projects

This is bound to key: control-super-shift-b

Publish selected project

When a site is large, it may be time consuming to publish all projects each time that some file in one project has changed. To publish a single project from a site use function org-publish-filtering-subprojects:

meta-x org-publish-filtering-subprojects

This will let you choose a project interactively from the list of projects defined by the current site.

This function is bound to key super-B, that is: Command-key (cmd or windows icon) + shift key + b.

Utilities

Add project files to refile targets

meta-x org-publish-add-all-files-to-refile-targets

This adds all 1st and 2nd level sections of all files of all projects to refile targets, making them interactively accessible through a list by org-capture-goto-target (control-u control-c control-w).

Force export of all files

meta-x org-reset-all-project-files

Dired site directory

meta-x org-dired-site

Edit configuration files

meta-x org-publish-edit-all-configs

Author: Ioannis Zannos

Created: 2013-10-13 Sun 20:20

Emacs 24.3.1 (Org mode 8.0.7)

Validate XHTML 1.0