Pseudo-hierarchy using `#.index` tag and queries, and queries to get all tasks relating to current page and its subpages

There has been a lot of discussion about managing pages in logseq, specifically about ways on how to represent a hierarchy. My goal in this post is to showcase my method of showing (and querying for) hierarchy, in case someone else finds it useful. Btw, this is not an original idea, it is largely inspired by the index method by alex0.

Assumptions, disclaimers, and notes

  • I don’t use the graph view. But if you do, you should know that after doing the index hack, all the pages (children and grandchildren) would directly connect to the top level page, so it doesn’t show any hierarchy.

  • I have minimal programming experience. After looking at the logseq advanced query documentation, looking at a lot of code, and a bit of testing, I only guessed at what the attributes actually meant (please tell me where to find the list of all logseq block/page attributes and their descriptions :sob::sob::sob:). Because of this, the queries might not have the best syntax/method. Also, please forgive (and correct) my misuse of terminologies, if ever.

  • This is my first time posting in any forum, so please educate me on some manners/conventions/practices that you think I might need to know.

  • I use inline code not only for codes, but for whenever I want to emphasize that I have a strict definition for a certain word or phrase.

Charactaristics of the heirarchy that I am aiming for:

  1. If ever I decide that the hierarchy should be modified, it should be easy for me to do, like how easy for me it is to indent/de-indent blocks in a logseq page.
  2. I want to write things while keeping its context in mind. That’s why I want a visible hierarchy on the page I am writing on, like an index.
  3. I use hierarchies mainly for project pages, so I want a query to show all tasks relating to a page and its subpages.

How it works

The index block

If you haven’t read the index method, it’s simply an indented list of pages with a tag, in my case an #.index tag, at the top level of the block. This complies with the 1st characteristic I was aiming for, since it is quite literally a block in logseq.

4

Show index in subpages using an advanced query

Now to comply with the 2nd characteristic, I need to be able to display the index in the subpages. I do this using the following advanced query:

#+BEGIN_QUERY
{
:title [:b "index"]
:query [
            :find (pull ?iblock [*])
            :in $ ?pname %
            :where
            [?current-page :page/name ?pname]
            [?itag :page/name ".index"]
            [?iblock :block/refs ?itag]
            (get-children ?iblock ?pblock)
            [?pblock :block/refs ?current-page]
            ]
:inputs [:current-page
            [
                [(get-children ?parent ?child) [?child :block/parent ?parent]]
                [(get-children ?parent ?child) [?t :block/parent ?parent] 
                      (get-children ?t ?child)]
            ]
]
:breadcrumb-show? false
:table-view? false
:group-by-page? false
} 
#+END_QUERY

What the query looks like on a page:

I have a template that contains this query, so I can quickly query the index on any page whenever I need to. The queried index block is also editable inside any subpage (careful though because you might edit the code instead).

Query to search for tasks relating to a page and its subpages

For the 3rd characteristic, I might need to explain what I mean when I say “tasks relating to the page” For me, this means all task blocks which either tags the page, or is in the page. I also have some commented code which can give me tasks relating to any page that has the property tags:: the page.

The following query gives me tasks relating to the current page and tasks with importance relating to all the current page’s subpages. If you want to include all tasks (not just with importance) in all subpages, replace (getabctask ?b ?subpages)) to (getanytask ?b ?subpages)). It works on any page (top level or bottom??? level), as long as it is in an index block. (Sorry for the long code, please tell me if there are custom rules or functions in logseq)

#+BEGIN_QUERY
{ 
:title [:b "Tasks"]
:query [
    :find (pull ?b [*])
    :in $ ?pname %
    :where
    [?current-page :page/name ?pname]
    [?itag :page/name ".index"]
    (or-join [?pblock ?current-page ?itag]
        (and [?pblock :block/refs ?current-page]
            [?pblock :block/refs ?itag])
        (and [?iblock :block/refs ?itag]
            (get-children ?iblock ?pblock)
            [?pblock :block/refs ?current-page])
    )
    (or-join [?pblock ?b]
        (and (get-children ?pblock ?childblocks)
            [?childblocks :block/refs ?subpages]
            (getabctask ?b ?subpages)) ;;get tasks with priority relating to subpages
        (and (?pblock :block/refs ?page)
            (getanytask ?b ?page)) ;;get all tasks relating to current page
    )
]
:inputs [:current-page
    [
        [(get-children ?parent ?child) [?child :block/parent ?parent]]
        [(get-children ?parent ?child) [?t :block/parent ?parent] 
            (get-children ?t ?child)]
        ;;[(getanytask ?task ?page) ;;recursive search. I only have it here in case I want to use it
            ;;[?pagetaggedwith ?page/tags ?page]
            ;;(getanytask ?task ?pagetaggedwith)
        ;;]
        [(getanytask ?task ?page)
            (or [?task :block/refs ?page]
                (get-children ?page ?task))
            [?task :block/marker ?marker]
            [(contains?  #{"TODO" "DOING" "NOW" "WAITING" "LATER"} ?marker)]]
        [(getabctask ?task ?page)
            (getanytask ?task ?page)
            [?task :block/priority ?priority]
            [(contains? #{"A" "B" "C"} ?priority)]]
    ]
]
:result-transform (fn [result] ;;sort by priority
                      (sort-by (fn [h]
                                 (get h :block/priority "Z")) result))
:breadcrumb-show? false
:group-by-page? false
} 
#+END_QUERY

I also have a template for this, so I can quickly put it in any page. This is what the query looks like on a page.

Advantagous side effects

Pages as tasks

Since the index block is just a logseq block, you can put more than just page links. Which means I can make any block in the index block into a task. I have a query in my logseq journal that gets all DOING blocks, and tagging a project as DOING helps me remind myself what I am working on.

logseq doing project

If you have a master projects page, you can easily query for blocks tagged with #.index and is in a DOING state to show all projects that you are currently doing.

That wraps up my post. I hope I was not being redundant. I also hope that this can help or inspire someone in their own workflows, particularly those who are not familiar with advanced queries.