Using Dataview on Obsidian Publish
On the homepage of my Obsidian Publish page, I have a section called "Recent Notes". But often I would create a note, and forget to update the list. At some point, I even got a message asking if the site was still active, since the Recent Notes section didn't seem to be changing. 😬
When our ability to remember a repetitive job fails, automation comes in!
Dataview Plugin on Obsidian Publish
To get recently edited notes in my local vault, I would use an Obsidian Dataview query like this:
TABLE WITHOUT ID
file.link AS Note, dateformat(file.mtime, "ff") AS Modified
FROM ""
WHERE publish
SORT file.mtime desc
LIMIT 7
This works well locally:
But on Publish it just renders a code block:
This is because the Dataview Plugin is not "installed" on Obsidian Publish. Publish sites can only render Markdown files; they do not support dynamic queries.
Outputting Markdown from Dataview Queries
Luckily for us, Dataview can output the result of a query in plain Markdown. The dv.queryMarkdown
method receives a query and returns Markdown:
await dv.queryMarkdown("LIST FROM #tag");
// => { successful: true, value: { "- [[Page 1]]\n- [[Page 2]]" } }
We can run this method in an Obsidian Templater template to write the Markdown output of a query to a file.
// Update Publish Files.md
<%*
const dv = app.plugins.plugins["dataview"].api;
const filename = "Recently Edited";
const query = `TABLE WITHOUT ID
file.link AS Note, dateformat(file.mtime, "ff") AS Modified
FROM ""
WHERE publish SORT file.mtime desc
LIMIT 7`;
const tFile = tp.file.find_tfile(filename);
const queryOutput = await dv.queryMarkdown(query);
// write query output to file
await app.vault.modify(tFile, queryOutput.value);
%>
Whenever this template is run, the Markdown result of the TABLE…
Dataview query is written to the file "Recently Edited".
Notice how Source Mode on the left displays a standard Markdown table.
Important: This code completely overwrites the target note.
Writing to multiple files
We can rewrite the code to support multiple filenames and queries:
// Update Publish Files.md
<%*
const dv = app.plugins.plugins["dataview"].api;
const openPublishPanel = app.commands.commands["publish:view-changes"].callback;
const fileAndQuery = new Map([
[
"Recently edited",
'TABLE WITHOUT ID file.link AS Note, dateformat(file.mtime, "ff") AS Modified FROM "50 Slipbox" OR "30 External" WHERE publish SORT file.mtime desc LIMIT 7',
],
[
"Recent new files",
'TABLE WITHOUT ID file.link AS Note, dateformat(file.ctime, "DD") AS Added FROM "50 Slipbox" OR "30 External" WHERE publish SORT file.ctime desc LIMIT 7',
],
]);
await fileAndQuery.forEach(async (query, filename) => {
const tFile = tp.file.find_tfile(filename);
const queryOutput = await dv.queryMarkdown(query);
// write query output to file
await app.vault.modify(tFile, queryOutput.value);
});
%>
When we run this template, the query outputs are written into the files Recently edited
and Recent new files
. You can add as many queries and filenames as you'd like!
I wanted to try out the new-ish Map()
syntax, but an array of objects would have worked as well! If you're unfamiliar with Maps in JavaScript, it is worth to read more on MDN.
Now we have a template that writes the Markdown output of multiple queries into corresponding files. But at this point, we still need to remember to run this template before uploading changes to Obsidian Publish.
Final template
To upload changes to Obsidian Publish, we would usually open the Command Palette and then run the Publish: Publish changes…
command.
But we can move this step into the "Update Publish Files" template, so that all of our Publish-related actions are in one place:
- The template first writes query results to the corresponding files,
- then opens the "Publish Changes" dialog
The "Update Publish Files" template now acts as a replacement for the Publish: Publish changes…
command.
In the Templater Options, we can assign a hotkey to our "Update Publish Files" template. I had CMD + P
bound to open the Publish panel. Now I assigned this hotkey to the template. I keep the muscle memory of publishing new notes, and every time the Dataview files are updated in the background.
Here is the final template, including some other improvements:
- Writes
publish: true
in the Frontmatter of the file and adds a comment, - Creates a file if the filename doesn't exist,
- Includes error handling and progress notifications.
// Update Publish Files.md
<%*
const dv = app.plugins.plugins["dataview"].api;
const openPublishPanel = app.commands.commands["publish:view-changes"].callback;
// Add as many filenames and queries as you'd like!
const fileAndQuery = new Map([
[
"Recently edited",
'TABLE WITHOUT ID file.link AS Note, dateformat(file.mtime, "ff") AS Modified FROM "50 Slipbox" OR "30 External" WHERE publish SORT file.mtime desc LIMIT 7',
],
[
"Recent new files",
'TABLE WITHOUT ID file.link AS Note, dateformat(file.ctime, "DD") AS Added FROM "50 Slipbox" OR "30 External" WHERE publish SORT file.ctime desc LIMIT 7',
],
]);
await fileAndQuery.forEach(async (query, filename) => {
if (!tp.file.find_tfile(filename)) {
await tp.file.create_new("", filename);
new Notice(`Created ${filename}.`);
}
const tFile = tp.file.find_tfile(filename);
const queryOutput = await dv.queryMarkdown(query);
const fileContent = `---\npublish: true\n---\n%% update via "Update Publish Files" template %% \n\n${queryOutput.value}`;
try {
await app.vault.modify(tFile, fileContent);
new Notice(`Updated ${tFile.basename}.`);
} catch (error) {
new Notice("⚠️ ERROR updating! Check console. Skipped file: " + filename , 0);
}
});
openPublishPanel();
%>
Result
On my Publish site, I have added five Dataview-powered query notes so far: Recently edited notes and recently created ones, books that I am currently reading and that I read recently, as well as a list of 80+ books that I read.
Dataview queries can be as complex as you like, even including images and tags.
I embedded a few of those notes into the homepage of my Publish page. Whenever I publish new notes with the template, those files are automatically updated.
Now when a reader stumbles upon the page, they immediately see the most recent notes — with minimal upkeep on my end!