Maps of Content
approvedby mkshp-dev
Dynamically generate Maps of Content (MOC) by extracting matching list items from notes in your vault. - This plugin has not been manually reviewed by Obsidian staff.
Maps of Content
This plugin provides a dynamic way to extract elements (like lists, tasks, headings, paragraphs, or blockquotes) from your Markdown files that match a specific word filter, automatically generating Map of Content (MOC) indexes in your vault.
The plugin supports dynamic MOCs generated from a folder + filter configuration, multiple output styles/element types, advanced filter expressions, grouping, sorting, and limiting results. It also includes an interactive MOC Creation Wizard and the ability to bake dynamic results into static markdown.
It accomplishes this by adding a new moc markdown code block processor.
Features
- Dynamic Output: Automatically generated Map of Content indexes in your vault based on live queries.
- Multiple Element Types: Extract entire lists, tasks, headings, paragraphs, or blockquotes.
- Advanced Filtering: Use logical operators (
AND,OR,NOT, parentheses) and property/frontmatter-based filters (properties(...)). - Result Shaping: Structure output by using
groupBy,sort, andlimitoptions. - MOC Creation Wizard: Easily generate your MOC queries via a visual interface.
- Bake to Markdown: Replace a dynamic
mocblock with the permanently rendered static markdown content.
How to use
In any of your notes, add a code block with the language set to moc and provide a YAML-based configuration.
Here is an example:
```moc
folder: Diary
element: List
filter: contains("MOC")
recursive: true
```
Configuration Options
folder(required): The folder path within your vault to search for files. E.g.,DiaryorNotes/Meetings.element(required): The type of element to extract. Can be set toList,Task,Heading,Paragraph, orBlockquote.filter(required): The filter condition to apply to each element. See the Advanced Filter Examples section below for more details.contains("text"): Matches elements containing the specified text (case-sensitive). (Note:has_wordandhas_textare supported as backward-compatible aliases).matches("regex"): Matches elements using a regular expression (supports optional slash-delimited format with flags, e.g.matches("/pattern/i")).has_tag("#tag"): Matches elements containing the specified tag (fully tag-aware, case-insensitive, and matches subtags like#tag/subtag).is_completed(): Matches only completed tasks (whenelementisTask).is_incomplete(): Matches only incomplete tasks (whenelementisTask).
recursive(optional): A boolean (trueorfalse) that determines whether the search should include subfolders within the specifiedfolder. If omitted, it defaults tofalse.groupBy(optional): Group the results by a specific property. Supported values:folder,cday(creation day),mday(modification day),tag.sort(optional): Sort the matched files. Specified as a space-separated string containing the field and direction:<field> <direction>.- Supported fields:
name,ctime(creation time),mtime(modification time). - Supported directions:
asc,desc. E.g.,name ascorctime desc.
- Supported fields:
limit(optional): A positive integer specifying the maximum number of files to process and extract from.
Advanced Filter Examples
The plugin's filter language supports rich composition, including boolean logic (AND, OR, NOT), grouping with parentheses, and checking frontmatter variables.
-
Boolean Logic & Grouping:
has_tag("#todo") AND (contains("urgent") OR is_incomplete()) -
Negation:
has_tag("#project") AND NOT contains("archived") -
Frontmatter/Properties: Use
properties(key == value)to filter notes by their YAML frontmatter before extracting elements.properties(status == "active") AND has_tag("#meeting")
Dynamic Parameters
You can dynamically include the current note's parameters in the folder and filter options using the following variables:
{{this.filename}}: Expands to the current note's name (without the.mdextension).{{this.folder}}: Expands to the name of the folder containing the current note.{{this.path}}: Expands to the full path of the current note (without the.mdextension).
For example, to list elements from the Diary folder that contain the current note's name:
```moc
folder: Diary
element: List
filter: has_word("{{this.filename}}")
recursive: true
```
Grouping, Sorting, and Limiting
You can shape the structure and volume of your MOC output directly from the code block configuration.
-
Group results by their tags:
```moc folder: Ideas element: Heading filter: has_word("feature") groupBy: tag ``` -
Sort results by creation time and limit to the 5 most recent files:
```moc folder: Daily Notes element: Task filter: is_incomplete() sort: ctime desc limit: 5 ```
MOC Creation Wizard
If you don't want to write the YAML configuration by hand, the plugin includes a MOC Creation Wizard.
You can invoke the wizard by using the "Create map of content block" command from the Obsidian command palette, or by clicking the list icon in the left ribbon.
The wizard provides a visual form to select your target folder, element type, write your filters (with auto-completion), and apply optional result shaping (groupBy, sort, limit). When submitted, it will insert the proper moc code block at your cursor.
Bake to Markdown
Dynamic moc blocks render queries on the fly. However, you might want to freeze the output at a specific point in time so it won't change if the source files are updated.
When a dynamic MOC is rendered in Reading mode, you will see a "Bake" button at the bottom of the block. Clicking this button will irreversibly transform the dynamic moc block and its generated contents into static markdown text directly inside your note.
This workflow is useful when you want to archive a query's results, share the text without requiring the plugin, or modify the generated output by hand.
Result
The plugin will scan all markdown files in the specified folder. For any files containing elements that match your filter, it will dynamically render a section.
The rendered output includes:
- A header with a link back to the source file where the elements were found.
- The matching elements themselves.
Note: The original
moccode block is replaced in reading/preview mode with the dynamically generated content.
Support
If you find this plugin helpful, consider supporting its development!
For plugin developers
Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.