Option to treat specific blocks as pages

Premise

In Logseq references to pages are used to tag content.
But pages are also the “root blocks” because each block is a child of a page.

Problem

When trying to figure out if something must be a block or a page, the difference is:

  1. A block is placed in a context and in the outliner hierarchical structure and so it is great to organize stuff. But since they are not in the graph you would lose important connections (references in the block, in its children or its path).
  2. A page will be a node in the graph and every reference in it will be a connection. But a page is just a “root block” so you will lose the structure above.

Solution

Provide a way to display certain blocks in the graph as nodes and the references¹ as connections.

A way to trigger this could be to treat title:: property of blocks as special property: if present the block will be displayed in the graph with that title.


[1]: about references, at the moment blocks are tagged using references in their path; instead pages are linked (at least in the graph) to references in their children.

So which references should these titled blocks be linked to? I’m not sure, maybe all references (in path, in content, in properties and in children)?


To make it clear: I’m not looking for a way to reference those blocks by their title (so no need to make unique titles); those blocks would be referenced by IDs like the others.

Here there is an example:

- title:: The Picture of Dorian Gray
  author:: ((1234...))

- title:: Oscar Wilde
  id:: 1234...

Both The Picture of Dorian Gray and Oscar Wilde would appear in the graph as nodes and linked because the latter appear in a property of the former.

Maybe when a block with a title is referenced using ((id)), it could be rendered as its title instead of its content.


I think this should be enough to let us organize the nodes of our graph freely with the outliner structure instead of being forced to introduce pages that have not that structure because they are all “root blocks”.

I really like the idea of unifying block and page functionality, but I think your approach has some issues.

  • Let’s say you create a page test1 and fill the first block with blablabla
  • Then you create a second page test2
    • You fill the first block with title:: and leave the key blank for now
    • You fill the second block with lorem ipsum
    • Finally, you go back and fill the title property with title:: test1
  • Logseq will delete test2 and append its content to test1 like:
test1
- blablabla
- title:: test1
- lorem ipsum

With pages, this scenario is unlikely to happen because you create a page through the ctrl+k UI, which will open test1 if you type test1 rather than trying to create a duplicate page. And if you do change the title:: key of a page to an existing page, the resulting concatenation isn’t so bad because pages simply float around freely in the ether of Logseq’s graph database — they’re not attached to a tree hierarchy like blocks. If you have an identical title:: key on two blocks, should one of them be removed entirely from its tree and pasted into another? I don’t think that would work very well.

All I’m saying is that the title:: property for the blocks you describe should be assigned through a controlled UI like ctrl+k that prevents users from duplicating keys i.e. in a block’s right click menu. But then again, in all other parts of Logseq you can manually override what the UI is doing by changing properties in a page, and disallowing that here would create inconsistency.

You misunderstood my proposal… I don’t want to unify anything nor change the database schema. I’m simply asking that some blocks (still identified by their ID and reference by it) are treated as “node” like pages i.e.

  1. appear in the graph view
  2. can be used in queries, for example {{query (property author ((1234-1234)) )}}

I wasn’t talking about the database schema in that comment, just that duplicate title:: keys would cause issues.

But I’ve thought about it some more, and I feel like the data structure is important to address. Partial overlap in block/page functionality can be useful, but it also adds confusion — I think it’s better to go all the way if anything.

Right now:

  • Pages are blocks with a name (kind of)
  • Pages are free-floating nodes of association. Blocks are attached to a strict tree hierarchy

Your proposal addresses the first distinction. I saw some people in the other thread say that pages are the root blocks of a Logseq graph, but that’s not exactly true. You can stuff as much content as you want into a block, but pages are only a title. With Logseq’s current data structure, pages are wrappers for blocks. That means a page isn’t truly a block with a name — it’s a block wrapper with a name.

But that’s unnecessary. Why can’t Logseq just have blocks, which you can choose to name or not name? What if:

  • There were no pages
  • Instead, 3 types of blocks
    • Normal blocks (the normal, unnamed hierarchical blocks in current Logseq)
    • Title blocks (like your proposal → the blocks that have a title:: property but still belong to a hierarchy tree)
    • And root blocks. These would be exactly like pages, except they can store info other than a title. They would look like pages do now in the UI, except you can write content without a bullet under the title. That’s important because the title and content are now part of the same block — the title is not just a wrapper for all blocks inside. Only root blocks have their own .md file

You should be able to open a title block in the same way as pages look now, with all child blocks inside, and a link to the parent block at the bottom like the references section.

Root blocks (and opening title blocks in their own page-like UI) would also solve the longform writing issue, because now you can write without a bullet.

These changes should be compatible with existing Logseq graphs. Pages become root blocks, since root blocks can still function as simple block wrappers if there is no content without a bullet under the title. Title blocks don’t require any changes in the format either.

Actually, I’m gonna do a 180 and say just the block title:: feature might be better for now, along with other changes to properties vs page-properties (and tags).

I do think the block vs page concept is important to discuss in the future, but the normal block, title block, root block approach is probably too convoluted.

To rephrase the differences:

  • Pages are a label for a set of blocks. You can effectively think of pages as blocks with a name (do I want to refer to this knowledge with a label later?), but that’s not fully correct. Blocks store in-depth information — a page is just a title/wrapper.
  • Pages are free-floating nodes of association. Blocks are attached to a strict hierarchy tree

The title:: feature partially nulls the first distinction. However, a page is its title and its contained blocks. Content other than the title must belong to a block. With the title:: for blocks property, a block can have a title and content all on its own. The second distinction is what I tried to address with the root blocks idea, but now I’m not sure that would pragmatically work so well.

Yes, I understand your concern, but it’s based on a misunderstanding on your end. You said:

If you have an identical title:: key on two blocks, should one of them be removed entirely from its tree and pasted into another? I don’t think that would work very well.

In my proposal I specified that values of title:: have not to be unique, because they are not used to identify a block. A block is still identified and referenced only by its ID. What I am asking is that the title:: value is used as a label only when displaying the block in the graph view and when rendering its references (via ID).

When you say:

No, it doesn’t happen, nothing happens when giving to a block the same title:: value of a page, because that block is identified by its ID only.

I have discussed this widely in a thread called “unify block and pages”.

Pages are nodes. I’m asking to be able to turn certain blocks into nodes too without creating other pages/files to store them, but keeping them in their context, just it.

Not only the graph view piece: block references don’t work as good as page references in queries.

Basically the purpose is the same of my later proposal of aliases for blocks that we discussed on Discord and maybe that is a better approach.

For me it’s very important not to be forced to create a page (and a file) for everything that I want to 1. appear on graph view and more importantly 2. be used in queries.

I easily end up with tons of files that just have some page properties referencing other pages for the purpose of meaningful queries. Why shouldn’t I be able to define those inside a single file instead?

For example let’s say I want to look for all the books by Italian authors, currently I need at least this structure:

Books.md
- I promessi sposi
  author:: [[Alessandro Manzoni]]
- ...

Alessandro Manzoni.md
- nationality:: [[Italy]]

and so on with a page for each author.

What I am looking for instead:

Authors.md
- alias:: Alessandro Manzoni
  id:: 12345-12345-12345
  nationality:: [[Italy]]
- ...

Books.md
- alias:: I promessi sposi
  author:: ((12345-12345-12345))
- ...

So just two pages, Authors and Books instead of X+Y+Z+… where X is the number of authors, Y of books and so on for everything.

The fact that Logseq doesn’t treat block references the same as page references. For example in properties like:

key:: [[Foo]], [[Bar]]

Foo and Bar are both considered values of keys. But if Foo and Bar were not pages but blocks and referenced by their IDs:

key:: ((12345...)), ((67890...))

they are not considered distinct values.

If there is just Foo as value the following query:

(property key Foo)

to fit the block-based approach could be written as:

(property key "((12345...))")

and it works and the " " are mandatory because you have to look for that exact value.

Back to multiple values:

key:: ((12345...)), ((67890...))

a block with these doesn’t match any query except the one using " " to look exactly for all block references at once and in that exact order.

Also, when you reference a block in a property like this:

key:: ((12345-12345...))

it is not listed in that block references (the little number on the right of a block you can click to list all its references):

1 Like

But since we have

  1. pages that can be referenced by [[Page]] (this is a core feature I don’t think will ever go away)
  2. blocks that can be referenced with ((id)) stored inside pages files

let’s say ((id)) references will work well with queries etc in the future.

What is the simplest way to display certain blocks in the graph view if I want so?

@antintin The idea of having different block types is interesting, had similar thoughts before.

Note, a page currently can have content as well, which is page properties.
For example a page alias is stored in the file header without bullet point:

alias: MyAlias    <-- page-only content

- adsfda

Hence I would skip distinction between root block vs. page and have two types:

  1. blocks, that have a globally unique name / title::
  2. “normal” blocks referenced by ID

First point implies, you can give a unique name to any block (same as page titles):

- title: My block title
  Some block content

and reference this block by [[My block title]]. This is a bit more far-reaching than OP requested.
Uniqueness is enforced by application logic in the same way, pages cannot have equal names.

It would also be cool to have a third type of block “browseable blocks”:

- title:: /parentblock
  parent content
    - title:: /childblock
    child content

And reference this block by [[Root block/parentblock/childblock]].

You are right, reported:

But what would be saved in Markdown files? [[id]] like [[12345-12345-12345]]?

So I would have blocks like:

- [[12345-12345-12345]] is a [[abcde-abcde-abcde]] written by [[vwxyz-vwxyz-vwyz]].

?

Or do you mean that references like [[Name]] are stored in Markdown files, then Logseq look for a block with title:: Name as property?

In that case, when a block is saved as its own Markdown file? When it has a title:: property? But then if there are multiple blocks with titles in a tree, what is saved to files?

Or maybe every time a block gets a title:: property it is moved to its own Markdown file together with all its children and a reference is left in its place?

Indeed, that’s why I am looking for a way promote specific blocks to “nodes” like pages.

I think I will gather the differences between block and page references and report them individually, but I would still need a way to tell Logseq “display this block in the Graph View and link it to other nodes according to references to and by it”.

Otherwise I am doomed to have many Markdown files with just page properties referencing other pages, for the sake of a meaningful Graph View.

There are many reasons for tags and pages to be the same thing, and that design choice is very intentional.

What I don’t understand though is where these title blocks are going to be stored. You can’t just create a block on its own right now - it has to be attached to a page. That’s why I was thinking about the root block concept

Edit: oh you’re saying keep pages? Would you propose they can store more content than just properties without a block?

This has been discussed in a long thread (82 messages) called “Unify blocks and pages” by @venture-comp.

Can you please discuss this somewhere else? This thread is a specific feature request.

In general try not to derail threads to a different topic.

If the problem is the big number of files, treating some blocks as pages sounds like a hack (and it could become a bigger problem when collaborating). At the very least, it increases the confusion between pages and blocks. It then comes as no surprise that some people are willing to abandon pages altogether.

Theoretically, the number of pages should not matter, and their size should not be a criterion:

  • A big block is still a block, not a page.
  • A small page is still a page, not a block.
    • Multiple small pages are still pages, not blocks of another page.

The problem is not conceptual, so it should not question the conceptual distinction between pages and blocks (some explanation here). What if addressing the problem explicitly, having an option to save some pages together in the same file instead of one file per page, but otherwise treating them just like any other page? Similar to the option of hiding some pages from some views. Such options could be enabled either for a specific page or for all pages that have a specific property. In my opinion, that would be a cleaner solution.

The problem is that trees of blocks are perfect to organize objects hierarchically but those objects can’t be nodes of the graph; they can only be references to pages.

My workaround is manually compile indexes of page references (and other things) and a query in each page to see in which index it was mentioned, as showcased here:

The objects in your showcase (as well as the books and authors in your previous examples) are of the types of objects that deserve separate pages. And since an object may participate in multiple hierarchies, indices of page-references look like a natural thing to do. What is the downside in your current approach, that the requested feature would improve?