> On Jul 25, 2026, at 11:08, Ihor Radchenko <[email protected]> wrote:
>
> Derek Chen-Becker <[email protected]> writes:
>
>> Subject: [PATCH] Add new after-includes hook for org export
>
> The commit message is a bit off. We usually do something like
>
> org-export: Add new org-export-after-includes-functions hook
>
>> Provide a new hook that runs after include keywords, but before macros and
>> Babel code.
>>
>> * doc/org-manual.org: Update the org-export hooks section to describe the
>> new hook in relation to the other existing hooks.
>
> ORG-NEWS should be updated as well.
>
>> * lisp/org-table.el (orgtbl-to-generic): Disable the new hook during table
>> export just as we do with other hooks.
>
> This leads to compiler warning that should be suppressed.
>
>> +(defvar org-export-after-includes-functions nil
>> + "Abnormal hook run after includes but before macros.
>> +
>> +This is run after include keywords but before macros have been
>> +expanded and Babel code blocks executed, on a copy of the original
>> +buffer being exported. Visibility and narrowing are preserved. Point
>> +is at the beginning of the buffer.")
>
> The docstring should explain the arguments passed to the abnormal hook.
I took a crack at the ORG-NEWS update and fix the two issues. I don’t know how
to
do a pull request or the commit message.
> diff --git a/doc/org-manual.org b/doc/org-manual.org
> index bda84c49c..5706380b1 100644
> --- a/doc/org-manual.org
> +++ b/doc/org-manual.org
> @@ -16964,12 +16964,15 @@ for usage and configuration details.
>
> #+vindex: org-export-before-processing-hook
> #+vindex: org-export-before-processing-functions
> +#+vindex: org-export-after-includes-functions
> #+vindex: org-export-before-parsing-hook
> #+vindex: org-export-before-parsing-functions
> -The export process executes two hooks before the actual exporting
> +The export process executes three hooks before the actual exporting
> begins. The first hook, ~org-export-before-processing-functions~,
> runs before any expansions of macros, Babel code, and include keywords
> in the buffer. The second hook,
> +~org-export-after-includes-functions~, runs after the include keywords
> +but before the macros and Babel code. The last hook,
> ~org-export-before-parsing-functions~, runs before the buffer is
> parsed.
>
> @@ -17109,10 +17112,12 @@ export keywords, does not contribute to the export
> output.]:
> 3. Remove commented subtrees in the whole buffer (see [[*Comment
> Lines]]);
>
> -4. Replace macros in the whole buffer (see [[*Macro Replacement]]),
> +4. Execute ~org-export-after-includes-functions~ (see [[*Export hooks]]);
> +
> +5. Replace macros in the whole buffer (see [[*Macro Replacement]]),
> unless ~org-export-replace-macros~ is nil;
>
> -5. When ~org-export-use-babel~ is non-nil (default), process code
> +6. When ~org-export-use-babel~ is non-nil (default), process code
> blocks:
>
> - Leave code blocks inside archived subtrees (see [[*Internal
> diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
> index 5f5168e33..7d4875e6b 100644
> --- a/etc/ORG-NEWS
> +++ b/etc/ORG-NEWS
> @@ -319,6 +319,13 @@ entry, or displays it in another window if filtered out.
> # require user action for most Org mode users.
> # Sorted from most important to least important.
>
> +*** Abnormal hook added: org-export-after-includes-functions
> +
> +This is run after include keywords but before macros have been
> +expanded and Babel code blocks executed, on a copy of the original
> +buffer being exported. Visibility and narrowing are preserved. Point
> +is at the beginning of the buffer.
> +
> *** You may need to update =org-protocol= bookmarklets for browsers
>
> In Firefox 133 and Firefox 128.5 ESR, the previously suggested
> diff --git a/lisp/org-table.el b/lisp/org-table.el
> index 9aeb53822..3920b573e 100644
> --- a/lisp/org-table.el
> +++ b/lisp/org-table.el
> @@ -5853,6 +5853,7 @@ This may be either a string or a function of two
> arguments:
> (princ "\n")))))
> (let ((org-inhibit-startup t)) (org-mode))
> (defvar org-export-before-processing-functions) ; ox.el
> + (defvar org-export-after-includes-functions) ; ox.el
> (defvar org-export-process-citations) ; ox.el
> (defvar org-export-expand-links) ; ox.el
> (defvar org-export-filter-parse-tree-functions) ; ox.el
> @@ -5867,6 +5868,7 @@ This may be either a string or a function of two
> arguments:
> ;; We _do not_ disable `org-export-filter-parse-tree-functions'
> ;; (historically).
> (let ((org-export-before-processing-functions nil)
> + (org-export-after-includes-functions nil)
> (org-export-replace-macros nil)
> (org-export-use-babel nil)
> (org-export-before-parsing-functions nil)
> diff --git a/lisp/ox.el b/lisp/ox.el
> index 90c853d76..c3993ec9b 100644
> --- a/lisp/ox.el
> +++ b/lisp/ox.el
> @@ -2175,10 +2175,11 @@ keywords before output."
> ;; Filters properties are installed in communication channel with
> ;; `org-export-install-filters' function.
> ;;
> -;; Eventually, two hooks (`org-export-before-processing-functions' and
> -;; `org-export-before-parsing-functions') are run at the beginning of the
> -;; export process and just before parsing to allow for heavy structure
> -;; modifications.
> +;; Eventually, three hooks (`org-export-before-processing-functions',
> +;; `org-export-after-includes-functions' and
> +;; `org-export-before-parsing-functions') are run at the beginning of
> +;; the export process and just before parsing to allow for heavy
> +;; structure modifications.
>
>
> ;;;; Hooks
> @@ -2194,6 +2195,17 @@ is at the beginning of the buffer.
> Every function in this hook will be called with one argument: the
> backend currently used, as a symbol.")
>
> +(defvar org-export-after-includes-functions nil
> + "Abnormal hook run after includes but before macros.
> +
> +This is run after include keywords but before macros have been
> +expanded and Babel code blocks executed, on a copy of the original
> +buffer being exported. Visibility and narrowing are preserved. Point
> +is at the beginning of the buffer.
> +
> +Every function in this hook will be called with one argument: the
> +backend currently used, as a symbol.")
> +
> (defvar org-export-before-parsing-functions nil
> "Abnormal hook run before parsing an export buffer.
>
> @@ -3104,6 +3116,10 @@ still inferior to file-local settings."
> (org-export-backend-name backend))
> (org-export-expand-include-keyword nil nil nil nil (plist-get info
> :expand-links))
> (org-export--delete-comment-trees)
> + (save-excursion
> + (goto-char (point-min))
> + (run-hook-with-args 'org-export-after-includes-functions
> + (org-export-backend-name backend)))
> (when org-export-replace-macros
> (org-macro-initialize-templates org-export-global-macros)
> (org-macro-replace-all org-macro-templates parsed-keywords))
> diff --git a/testing/lisp/test-ox.el b/testing/lisp/test-ox.el
> index 79365ad29..e58c776e9 100644
> --- a/testing/lisp/test-ox.el
> +++ b/testing/lisp/test-ox.el
> @@ -1879,6 +1879,24 @@ Footnotes[fn:2], foot[fn:test] and [fn:inline:inline
> footnote]
> (org-element-property :end object)))))))))
> (org-export-as (org-test-default-backend)))))))
>
> +(ert-deftest test-org-export/after-includes-hook ()
> + "Test `org-export-after-includes-functions'."
> + (should
> + (equal "success\n"
> + (org-test-with-temp-text
> + (format "#+INCLUDE: \"%s/examples/macro-templates.org\"\n"
> org-test-dir)
> + (let* ((org-export-after-includes-functions
> + '((lambda (backend)
> + (goto-char (point-min))
> + ;; will fail if hook done before the include
> + (if (search-forward "Macro templates")
> + (progn
> + (goto-char (point-max))
> + ;; will not expand if hook executes after macros
> + (insert "{{{included-macro}}}"))))))
> + (output (org-export-as (org-test-default-backend))))
> + (substring output (string-match ".*\n\\'" output)))))))
> +
> (ert-deftest test-org-export/before-parsing-functions ()
> "Test `org-export-before-parsing-functions'."
> (should