;;; build-site.el --- Publish my website using org-publish -*- lexical-binding: t; -*- ;; Author: Zaine Qayyum ;; Created: 2025-08-08 ;; Purpose: Build and publish my static site from Org files. ;;; Commentary: ;; Run this file with: ;; emacs -Q --script build-site.el ;;; Code: (require 'package) (add-to-list 'load-path "~/master-folder/org_files/org_web/lisp/") (require 'recently-updated) (require 'tags) (require 'sidenotes) (require 'sitemaps) (setq package-user-dir (expand-file-name "./.packages")) (setq package-archives '(("melpa" . "https://melpa.org/packages/") ("elpa" . "https://elpa.gnu.org/packages/"))) (require 'ox-publish) (require 'cl-lib) (require 'org) (require 'ox) (require 'ox-html) (package-initialize) (unless package-archive-contents (package-refresh-contents)) (package-install 'htmlize) (add-to-list 'load-path "~/master-folder/org_files/org_web/") (require 'htmlize) (defvar z-shared-head " " ) (setq org-export-global-macros (append '(("sidenote" . "@@html:$2@@") ("epigraph" . "@@html:
$1
$2
@@") ("epigraph_single" . "@@html:
$1
@@") ("epigraph3" . "@@html:
$1
$2, $3
@@") ("kbd" . "@@html:$1@@@@latex:\\texttt{$1}@@") ("margimg" . "@@html:@@") ("countdown" . "@@html:@@") org-export-global-macros))) (defvar z-preamble " \"Web
\"Site
Updated: %C
" ) (defvar z-postamble "") (defun z/comments-file-p (file) "Return non-nil if FILE has comments enabled. A file has comments if: - It has a #+COMMENTS: keyword with value \"t\" (case-insensitive)." (when (file-exists-p file) (with-temp-buffer (insert-file-contents file) (org-mode) (let* ((keywords (org-collect-keywords '("COMMENTS"))) (comments (cadr (assoc "COMMENTS" keywords)))) (print keywords) (and comments (string-match-p "^\\s-*t\\s-*$" (downcase comments))))))) (defun z/comments-file-slug (file) "Return page slug from #+SLUG: or fallback to filename." (with-temp-buffer (insert-file-contents file) (org-mode) (let* ((keywords (org-collect-keywords '("SLUG"))) (slug (cadr (assoc "SLUG" keywords)))) (if (and slug (string-match-p "\\S-" slug)) slug (file-name-base file))))) (defun z/org-html-insert-comments-into-body (body backend info) "Insert comments section at the end of the document body." (when (org-export-derived-backend-p backend 'html) (let ((input-file (plist-get info :input-file))) (if (and input-file (z/comments-file-p input-file)) (let* ((slug (z/comments-file-slug input-file)) (comments-html (format "

Comments

" slug))) (concat body comments-html)) body)))) (defun z/org-html-add-body-classes (output backend info) "Add layout-related classes to based on file metadata." (when (org-export-derived-backend-p backend 'html) (let* ((input-file (plist-get info :input-file)) (classes (delq nil (list (when (and input-file (z/wip-file-p input-file)) "wip") (when (and input-file (z/no-sidenotes-file-p input-file)) "no-sidenotes"))))) (if classes (replace-regexp-in-string "]*\\)>" (format "" (string-join classes " ")) output) output)))) (add-to-list 'org-export-filter-final-output-functions #'z/org-html-add-body-classes) (add-to-list 'org-export-filter-body-functions #'z/org-html-insert-comments-into-body) (setq org-html-htmlize-output-type 'css) (org-export-define-derived-backend 'z-html 'html :filters-alist '((:filter-final-output . z/insert-filetags-after-title))) (defun z/org-main-prep (_project) (z/generate-recently-updated-org 26)) (defun z/z-publish-to-html (plist filename pub-dir) "Publish FILENAME to HTML using the z-html backend." (org-publish-org-to 'z-html filename ".html" plist pub-dir)) ;; Define the publishing project (setq org-publish-project-alist `(("org-main" :recursive t :base-directory "~/master-folder/org_files/org_web/" :publishing-function z/z-publish-to-html :publishing-directory "~/master-folder/org_files/org_web/output" :base-extension "org" :auto-sitemap t :sitemap-filename "sitemap.org" :sitemap-title "Sitemap" :sitemap-sort-files chronologically :html-preamble ,z-preamble :html-postamble ,z-postamble :html-head ,z-shared-head :preparation-function z/org-main-prep ) ("org-categories-sitemap" :recursive t :base-directory "~/master-folder/org_files/org_web/home" :publishing-directory "~/master-folder/org_files/org_web/output/home" :base-extension "org" :auto-sitemap t :sitemap-filename "categories.org" :sitemap-title "Categories" :sitemap-function z/categories-sitemap :html-preamble ,z-preamble :html-postamble ,z-postamble :html-head ,z-shared-head ) ("org-posts" :base-directory "~/master-folder/org_files/org_web/posts" :publishing-directory "~/master-folder/org_files/org_web/output/posts/" :recursive t :base-extension "org" :publishing-function z/z-publish-to-html :with-author nil :with-creator nil :html-validation-link nil :with-toc t :section-numbers t :html-preamble ,z-preamble :html-postamble ,z-postamble :auto-sitemap t :sitemap-filename "posts-list.org" :sitemap-title "Posts List" :sitemap-style list :sitemap-function z/posts-sitemap :sitemap-sort-files anti-chronologically :html-head ,z-shared-head ) ("org-blogs" :base-directory "~/master-folder/org_files/org_web/blogs" :publishing-directory "~/master-folder/org_files/org_web/output/blogs/" :recursive t :base-extension "org" :publishing-function z/z-publish-to-html :with-author nil :with-creator nil :html-validation-link nil :html-preamble ,z-preamble :html-postamble ,z-postamble :auto-sitemap t :sitemap-filename "blogs-list.org" :sitemap-title "Blogs List" :sitemap-style list :sitemap-function z/blogs-sitemap :sitemap-sort-files anti-chronologically :html-head ,z-shared-head ) ("org-books" :base-directory "~/master-folder/org_files/org_web/books/" :publishing-directory "~/master-folder/org_files/org_web/output/books/" :recursive t :base-extension "org" :publishing-function z/z-publish-to-html :with-author nil :with-creator nil :html-validation-link nil :html-preamble ,z-preamble :html-postamble ,z-postamble :auto-sitemap t :sitemap-filename "books-list.org" :sitemap-title "Books List" :sitemap-style list :sitemap-function z/books-sitemap :sitemap-sort-files anti-chronologically :html-head ,z-shared-head ) ("org-2025" :base-directory "~/master-folder/org_files/org_web/blogs/2025/" :publishing-directory "~/master-folder/org_files/org_web/output/blogs/2025/" :recursive t :base-extension "org" :publishing-function z/z-publish-to-html :with-author nil :with-creator nil :html-validation-link nil :html-preamble ,z-preamble :html-postamble ,z-postamble :auto-sitemap t :sitemap-filename "2025-list.org" :sitemap-title "2025 List" :sitemap-style list :sitemap-function z/2025-sitemap :sitemap-sort-files anti-chronologically :html-head ,z-shared-head ) ("org-career" :base-directory "~/master-folder/org_files/org_web/posts/career/" :publishing-directory "~/master-folder/org_files/org_web/output/posts/career/" :recursive t :base-extension "org" :publishing-function z/z-publish-to-html :with-author nil :with-creator nil :html-validation-link nil :html-preamble ,z-preamble :html-postamble ,z-postamble :auto-sitemap t :sitemap-filename "career-list.org" :sitemap-title "Career List" :sitemap-style list :sitemap-function z/career-sitemap :sitemap-sort-files anti-chronologically :html-head ,z-shared-head ) ("wip-pages" :base-directory "~/master-folder/org_files/org_web/" :publishing-directory "~/master-folder/org_files/org_web/output/" :recursive t :base-extension "org" :publishing-function z/z-publish-to-html :with-author nil :with-creator nil :html-validation-link nil :html-preamble ,z-preamble :html-postamble ,z-postamble :auto-sitemap t :sitemap-filename "wip.org" :sitemap-title "Work in progress" :sitemap-style list :sitemap-function z/wip-sitemap :sitemap-sort-files anti-chronologically :html-head ,z-shared-head ) ("org-tags" :base-directory "~/master-folder/org_files/org_web/tags" :publishing-directory "~/master-folder/org_files/org_web/output/tags" :recursive t :base-extension "org" :publishing-function org-html-publish-to-html :with-author nil :with-creator nil :html-preamble ,z-preamble :html-postamble ,z-postamble :html-head ,z-shared-head) ("org-assets" :base-directory "~/master-folder/org_files/org_web/assets/" :base-extension "css\\|js\\|png\\|jpg\\|gif\\|svg\\|pdf\\|woff\\|woff2\\|ttf" :publishing-directory "~/master-folder/org_files/org_web/output/assets/" :recursive t :publishing-function org-publish-attachment) )) (delete-directory "~/master-folder/org_files/org_web/output/" t) (delete-directory "~/master-folder/org_files/org_web/tags/" t) (message "Directory deleted") (z/write-tag-pages) (org-publish-all t) (message "Build complete!") ;;; build-site.el ends here