> On Jul 6, 2026, at 21:20, Derek Chen-Becker <[email protected]> wrote:
> 
> Hi Perry, thanks for the patch. In the docstring for the 
> `org-export-after-includes-function' you have a typo with "Bable". Also, 
> would it be possible to add a unit test?

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/lisp/org-table.el b/lisp/org-table.el
index 9aeb53822..1f180bf53 100644
--- a/lisp/org-table.el
+++ b/lisp/org-table.el
@@ -5867,6 +5867,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..9fe88b617 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,14 @@ 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.")
+
 (defvar org-export-before-parsing-functions nil
   "Abnormal hook run before parsing an export buffer.
 
@@ -3104,6 +3113,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

Reply via email to