SHORT ANSWER
STEP number 1 . Place the cursor on the parent.
STEP # 2 : Mx org-sort-entries RET a RET
STEP # 3 : Mx org-sort-entries RET o RET
STEP # 4 : Crack open your favorite drink and have a drink.
SEPARATE RESPONSE
To extend the response to @pmr (i.e. sort the selected region), you can also consider using the main headers to organize the subheadings. For example, I like to do several sortings - first alphabetically, then in order, third in priority and fourth in time. For subheadings that do not contain deadlines and contain only one type of todo status, for my needs itβs enough to sort only alphabetically. The following is an example function that I use to sort the entire buffer containing various main headers and subheadings. Here is the cheat sheet from org-sort-entries :
Sort: [a]lpha [n]umeric [p]riority p[r]operty todo[o]rder [f]unc [t]ime [s]cheduled [d]eadline [c]reated A/N/P/R/O/F/T/S/D/C means reversed.
NOTE : org-sort-entries uses current-time when sorting records based on a timestamp if the record does not contain a timestamp. The consequence of using current-time is that records that fail to record will be sorted before future tasks that contain timestamps when sorting with the t , c , s or d parameters. To weight undated records so that they are sorted after dated records, you can use a later date than current-time . The corresponding let-bound variable is defined as (now (current-time)) , and its use in the function is written as (org-float-time now) . This can be addressed in many different ways - for example, by changing the code containing (org-float-time now) , with something that dates from an artificial date in the future - for example, (org-time-string-to-seconds "<2030-12-31 Tue>") .
(defun lawlist-sort () (when (save-excursion (goto-char (point-max)) (re-search-backward "^\\* CONTACTS" nil t) (re-search-forward "^\\*\\* \\(Planning\\)" nil t)) (goto-char (point-max)) (re-search-backward "^\\* CONTACTS" nil t) (org-sort-entries t ?a) ) (when (save-excursion (goto-char (point-max)) (re-search-backward "^\\* DONE" nil t) (re-search-forward "^\\*\\* \\(None\\)" nil t)) (goto-char (point-max)) (re-search-backward "^\\* DONE" nil t) (org-sort-entries t ?a) ) (when (save-excursion (goto-char (point-max)) (re-search-backward "^\\* UNDATED" nil t) (re-search-forward "^\\*\\* \\(Someday\\)" nil t)) (goto-char (point-max)) (re-search-backward "^\\* UNDATED" nil t) (org-sort-entries t ?a) ) (when (save-excursion (goto-char (point-max)) (re-search-backward "^\\* EVENTS" nil t) (re-search-forward "^\\*\\* \\(Reference\\|Delegated\\|Postponed\\|Waiting\\)" nil t)) (goto-char (point-max)) (re-search-backward "^\\* EVENTS" nil t) (org-sort-entries t ?a) (org-sort-entries t ?o) (org-sort-entries t ?p) (org-sort-entries t ?t) ) (when (save-excursion (goto-char (point-max)) (re-search-backward "^\\* TASKS" nil t) (re-search-forward "^\\*\\* \\(Active\\|Next Action\\|Hold\\|Canceled\\)" nil t)) (goto-char (point-max)) (re-search-backward "^\\* TASKS" nil t) (org-sort-entries t ?a) (org-sort-entries t ?o) (org-sort-entries t ?p) (org-sort-entries t ?t) ) )
Here is an example of how to sort and reorganize the entire buffer containing the main headers and subheadings. This is especially useful if the user needs to synchronize with the Toodledo server using the org-toodledo : https://github.com/christopherjwhite/org-toodledo To speed up the process of reorganizing the buffer containing hundreds of subheadings, the user may wish to consider suppressing messages by changes in responsible functions, however this is beyond the scope of this answer.
(setq org-todo-keywords '( (sequence "Active(a)" "Next Action(n)" "Canceled(c)" "Hold(h)" "Reference(r)" "Delegated(d)" "Waiting(w)" "Postponed(P)" "Someday(s)" "Planning(p)" "|" "None(N)") )) (defun lawlist-reorganize () (interactive) (with-current-buffer (get-buffer "test.org") (setq buffer-read-only nil) (lawlist-refile-tasks) (lawlist-refile-events) (lawlist-refile-undated) (lawlist-refile-contacts) (lawlist-refile-done) (lawlist-sort) (goto-char (point-min)) (save-buffer) (setq buffer-read-only t))) (defun lawlist-refile-tasks () (interactive) (let* ( (org-archive-location "/Users/HOME/Desktop/test.org::* TASKS") (org-archive-save-context-info nil)) (goto-char (point-min)) (unless (re-search-forward "^\\* TASKS" nil t) (goto-char (point-max)) (insert "* TASKS\n\n")) (goto-char (point-max)) (while (re-search-backward "^\\*\\* \\(Active\\|Next Action\\|Hold\\|Canceled\\)" nil t) (org-archive-subtree)))) (defun lawlist-refile-events () (let* ( (org-archive-location "/Users/HOME/Desktop/test.org::* EVENTS") (org-archive-save-context-info nil)) (goto-char (point-min)) (unless (re-search-forward "^\\* EVENTS" nil t) (goto-char (point-max)) (insert "* EVENTS\n\n")) (goto-char (point-max)) (while (re-search-backward "^\\*\\* \\(Reference\\|Delegated\\|Postponed\\|Waiting\\)" nil t) (org-archive-subtree)))) (defun lawlist-refile-undated () (let* ( (org-archive-location "/Users/HOME/Desktop/test.org::* UNDATED") (org-archive-save-context-info nil)) (goto-char (point-min)) (unless (re-search-forward "^\\* UNDATED" nil t) (goto-char (point-max)) (insert "* UNDATED\n\n")) (goto-char (point-max)) (while (re-search-backward "^\\*\\* \\(Someday\\)" nil t) (org-archive-subtree)))) (defun lawlist-refile-done () (let* ( (org-archive-location "/Users/HOME/Desktop/test.org::* DONE") (org-archive-save-context-info nil)) (goto-char (point-min)) (unless (re-search-forward "^\\* DONE" nil t) (goto-char (point-max)) (insert "* DONE\n\n")) (goto-char (point-max)) (while (re-search-backward "^\\*\\* \\(None\\)" nil t) (org-archive-subtree)))) (defun lawlist-refile-contacts () (let* ( (org-archive-location "/Users/HOME/Desktop/test.org::* CONTACTS") (org-archive-save-context-info nil)) (goto-char (point-min)) (unless (re-search-forward "^\\* CONTACTS" nil t) (goto-char (point-max)) (insert "* CONTACTS\n\n")) (goto-char (point-max)) (while (re-search-backward "^\\*\\* \\(Planning\\)" nil t) (org-archive-subtree))))
Here is an example of a cleanup function to set the correct distance between records and remove any empty lines at the end of the buffer. The regex suggests that the headings and subheadings are all left and left:
(defun lawlist-cleanup () (interactive) (let ((query-replace-lazy-highlight nil)) (replace-regexp "\n+\\*\\* " "\n\n** " nil (point-min) (point-max)) (replace-regexp "\n+\\* " "\n\n\n* " nil (point-min) (point-max)) (goto-char (point-max)) (delete-blank-lines) (let ((trailnewlines (abs (skip-chars-backward "\n\t")))) (if (> trailnewlines 0) (delete-char trailnewlines))) ))
This decision does not depend on the choice of regions, but instead acts on each main heading and organizes everything under this main heading - i.e. all subheadings are organized. The code in this answer will rearrange the records, updating them under the correct main heading. For example, if the task is completed, the completed subtitle will be ** None - the code will search for all subtitles with ** None and move them to the main * DONE header, and then sort them alphabetically.
Main headings: * TASKS ; * EVENTS ; * SOMEDAY ; * CONTACTS ; * DONE .
The following subheadings were chosen because they are the method of getting things, and the Toodledo server uses the same methodology: ** Active ; ** Next Action ; ** Hold ; ** Canceled ; ** Reference ; ** Delegated ; ** Postponed ; ** Waiting ; ** Someday ; ** Planning ; ** None .
* TASKS ** Active ** Next Action ** Hold ** Canceled * EVENTS ** Reference ** Delegated ** Postponed ** Waiting * SOMEDAY ** Someday * CONTACTS ** Planning * DONE ** None