Programmatic way to link to all notes with a given header

What I’m trying to do

I’ve found a good workflow in Obsidian by operating around my daily notes. That’s been great overall, but I have to do a lot of manual work to see the big picture across files.

I’d like to take the step to build a “meetings” section by topic or person where the string I care about is the title of the file. From there, I’d like the following logic:

  • For a given file name
  • Find all search results for line:"# [string]"
  • Link and embed the section as ![[link#header]]

Things I have tried

  • I tried DataViewer at first but stopped once I read that headers are not indexed, so they can’t be queried.
  • I considered coding something but I’m not sure where to start here. I’m okay at Python but not familiar with JS.

Thanks for any guidance! I’m excited to get more familiarity with Obsidian.

So I’m using dataview for most of my queries, but there is one area it doesn’t shine and that is related to content reading of files. However, you’ve got the query searches which allows you to do searches as from the search bar within your files.

After using this template on a file name “Original query” in my test vault:

```query
line: "# <% tp.config.target_file.getShortName() %>"
```

I got this output:

This accomplishes the search related to the given file name, and linking back to that particular heading. However, it doesn’t use the dedicated link and embed option.

To properly achieve that embedding of sections you’ll need to dive into dataviewjs and scan all files extracting the headers, and if it’s found do the embed. However, dataview has been known for not handling embeds of non images very well. I’m not doing those kind of embeds, so I’ve not done any testing on this lately. There are scripts floating around this forum showing how to tackle file content from dataviewjs.

(On a side note: I’m kind of opposed to do mass embedding like this, but I guess that’s just me… :slight_smile: )

1 Like

That’s a cool approach and immediately works for me. The functionality I want that this is doesn’t unlock is a text search across the page that finds context about a conversation. I appreciate this workaround, but going to keep pursuing the original scope until I find it breaks :slight_smile:

In Obsidian’s js API, you can query a file’s metadata cache() which contains various metadata about a note, like links etc and among them you can find a headers list. Each Header is of type HeadingCache which contains the heading label itself, a level (indicating how many hashes it has) and a Position (line, column, offset) of both start and end characters of the heading.

That said, I wrote a script to try out Obsidian API within a dataviewjs block:

const given_file_name = "...path to filename.md";
const tfile = app.vault.getMarkdownFiles().filter(t=>t.path == given_file_name)[0];
const page_metadata = app.metadataCache.getFileCache(tfile);
const page_headings = page_metadata?.headings;
let heading_dv_array = dv.array(page_headings)
	.map((t)=>{
		return t.heading;
	});
await dv.list(heading_dv_array);

Disclaimer: I didn’t write safety checks etc, so this is just an example.

getMarkdownFiles gets you the list of notes in the vault and then you filter it to get the files whose path corresponds to what you want. You can do whatever here…check the folder matches, the filename, the full path, just starts with “some directory sequence/” etc.

getFileCache gives back the MetadataCache of the file you want and then we get the headings member array and make a dataview array with only the headings strings.

Then we can do a dv.array(…) to convert the page_headings to a dataview array and be able to use any queries that dv allows.

Since you have access to the header itself, you can create a link for it in Templater for example, templater with dataview in case you want this file to auto-update.

Relevant docs:
CachedMetadata API
HeadingCache API

1 Like

Thanks so much for the thoughts @npatch. I’m taking a slightly different approach at the moment – I think extending this plugin with the ability to set context levels as I described here will give me the functionality without going wild like @holroy was concerned about.

I’d love any advice on how to read the plugin and think about adding settings – it’s clear the plugin already has the behavior I need but I need to expose the options.

For one, the code in that plugin seems to basically invoke code from Obsidian. (setExtraContext function in main.ts).

Basically, it seems to be going over the list of entries the query itself shows and just enable context buttons, but since Search itself lacks a setting for how much context to show, ultimately the plugin can’t do more, unless Obsidian’s API from the links I showed above, can support it somehow, but I didn’t look into it.

UPDATE: some quick search queries in the API don’t show anything relevant to the extra context.

UPDATE2: And it seems Obsidian is not open source in the traditional sense. Supposedly Electron shows a minified/packed/obfuscated version of the code so good luck doing anything that way.

Likely this is something that has to be requested as a feature from Obsidian itself, otherwise you’d have to resort to the options me and @holroy mentioned.

1 Like

setExtraContext func

It calls the same function on children of the dom it constructs/shows.

FWIW, you can look into it more by opening the console in Obsidian, picking the context button elements and looking up their labels in the app.js file.

Unfortunately my familiarity with js syntax especially for prototype etc is very superficial, so I can’t make heads or tails about scope in the functions it ends up in (showMoreAfter and showMoreBefore).

Thank you for taking a look! I really appreciate it.

1 Like