Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: more work on properties documentation #3001

Merged
merged 11 commits into from
Aug 1, 2024
187 changes: 110 additions & 77 deletions docs/Getting Started/Frontmatter Properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@ publish: true

Obsidian offers a facility called [Properties](https://help.obsidian.md/Editing+and+formatting/Properties).

The Obsidian documentation says:

> [!Quote]
> Properties allow you to organize information about a note. Properties contain structured data such as text, links, dates, checkboxes, and numbers. Properties can also be used in combination with [Community plugins](https://help.obsidian.md/Extending+Obsidian/Community+plugins) that can do useful things with your structured data.
Properties allow you to organize information about a note. Properties contain structured data such as text, links, dates, checkboxes, and numbers.

This is an example property section, and it *must* appear on the very first line of the markdown file:

Expand All @@ -35,6 +32,10 @@ name: value

In the Tasks documentation, we refer to these as Frontmatter Properties, to distinguish them from Task and Query properties.

## Why use Frontmatter Properties in Tasks queries?

For example, if you associate a tag with a project, you might want to put that tag in one place at the top of the file, instead of having to remember to add it on every single task line in the file.

## How does Tasks treat Frontmatter Properties?

- Frontmatter property values can be used in the following instructions:
Expand All @@ -53,65 +54,10 @@ In the Tasks documentation, we refer to these as Frontmatter Properties, to dist
- `property name` will find `Property Name`, for example.
- Tags in Frontmatter can be accessed with `task.file.property('tags')`
- `TAG` and `TAGS` are standardised to `tags`.
- The `#` prefix is added to all tag values in frontmatter.
- The `#` prefix is added to all tag values returned by this function.
- Aliases in Frontmatter are not yet standardised.
- If your vault contains a mixture of `alias`, `ALIAS` and `ALIASES`, your queries will need to be coded to handle both spellings, for now.
- Tasks reads both YAML and [JSON](https://help.obsidian.md/Editing+and+formatting/Properties#JSON+Properties) properties.

## How does Tasks interpret Frontmatter Properties?

Consider a file with the following example properties (or "Frontmatter"):

<!-- TODO this was copied from docs_sample_for_task_properties_reference.md - embed the content automatically in future... -->

```yaml
---
sample_checkbox_property: true
sample_date_property: 2024-07-21
sample_date_and_time_property: 2024-07-21T12:37:00
sample_list_property:
- Sample
- List
- Value
sample_number_property: 246
sample_text_property: Sample Text Value
sample_text_multiline_property: |
Sample
Text
Value
sample_link_property: "[[yaml_all_property_types_populated]]"
sample_link_list_property:
- "[[yaml_all_property_types_populated]]"
- "[[yaml_all_property_types_empty]]"
aliases:
- YAML All Property Types Populated
tags:
- tag-from-file-properties
creation date: 2024-05-25T15:17:00
project: Secret Project
---
```

The following table shows how most of those properties are interpreted in Tasks queries:

<!-- placeholder to force blank line before included text --><!-- include: TaskProperties.test.task_frontmatter_properties.approved.md -->

| Field | Type 1 | Example 1 |
| ----- | ----- | ----- |
| `task.file.hasProperty('creation date')` | `boolean` | `true` |
| `task.file.property('creation date')` | `string` | `'2024-05-25T15:17:00'` |
| `task.file.property('sample_checkbox_property')` | `boolean` | `true` |
| `task.file.property('sample_date_property')` | `string` | `'2024-07-21'` |
| `task.file.property('sample_date_and_time_property')` | `string` | `'2024-07-21T12:37:00'` |
| `task.file.property('sample_list_property')` | `string[]` | `['Sample', 'List', 'Value']` |
| `task.file.property('sample_number_property')` | `number` | `246` |
| `task.file.property('sample_text_property')` | `string` | `'Sample Text Value'` |
| `task.file.property('sample_text_multiline_property')` | `string` | `'Sample\nText\nValue\n'` |
| `task.file.property('sample_link_property')` | `string` | `'[[yaml_all_property_types_populated]]'` |
| `task.file.property('sample_link_list_property')` | `string[]` | `['[[yaml_all_property_types_populated]]', '[[yaml_all_property_types_empty]]']` |
| `task.file.property('tags')` | `string[]` | `['#tag-from-file-properties']` |

<!-- placeholder to force blank line after included text --><!-- endInclude -->
- Tasks reads both YAML and [JSON](https://help.obsidian.md/Editing+and+formatting/Properties#JSON+Properties) formats.

## Frontmatter Properties Examples

Expand Down Expand Up @@ -147,53 +93,140 @@ filter by function task.file.hasProperty('kanban-plugin')
filter by function ! task.file.hasProperty('kanban-plugin')
```

### More filtering examples
### Tracking projects

<!-- placeholder to force blank line before included text --><!-- include: CustomFilteringExamples.test.obsidian_properties_task.file.frontmatter_docs.approved.md -->
#### Use a `project` property

Suppose you have multiple files associated with a project, spread throughout your vault, and they all have a `project` property like this:

```yaml
---
project: Project 1
---
```

This search will find all tasks in those files:

```javascript
filter by function task.file.hasProperty('kanban-plugin')
filter by function task.file.property('project') === 'Project 1'
```

#### Use `#project/...` tag values

Some people prefer to use properties tags to identify projects. One advantage of tags is it is easy to add multiple values.

```yaml
---
tags:
- project/project-1
---
```

- find tasks in [Kanban Plugin](https://github.com/mgmeyers/obsidian-kanban) boards.
This exact-match search will find all tasks in such files:

```javascript
filter by function task.file.property("sample_list_property")?.length > 0
filter by function task.file.property('tags').includes('#project/project-1')
```

- find tasks in files where the list property 'sample_list_property' exists and has at least one list item.
If you wanted to use a sub-string search to find all tasks in files with any properties tag beginning `#project/` you could use [optional chaining (?.)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining) and the [nullish coalescing operator (??)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing) like this:

```javascript
filter by function task.file.property("sample_list_property")?.length === 0
filter by function task.file.property('tags')?.join(',').includes('#project/') ?? false
```

- find tasks in files where the list property 'sample_list_property' exists and has no list items.
Or you could use [template literals (Template strings)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) like this:

```javascript
filter by function task.file.property('creation date')?.includes('2024') ?? false
filter by function `${task.file.property('tags')}`.includes('#project/')
```

- find tasks in files where the date property 'creation date' includes string '2024'.
### Using date values

<!-- placeholder to force blank line after included text --><!-- endInclude -->
Obsidian supports [Date](https://help.obsidian.md/Editing+and+formatting/Properties#^date-time) and [Date & time](https://help.obsidian.md/Editing+and+formatting/Properties#^date-time) property values.

### More grouping examples
It stores them in the format shown in these examples:

<!-- placeholder to force blank line before included text --><!-- include: CustomGroupingExamples.test.obsidian_properties_task.file.frontmatter_docs.approved.md -->
```yaml
---
date: 2020-08-21
time: 2020-08-21T10:30:00
---
```

Currently, Tasks does nothing special with these, seeing them as string values.

#### Grouping by raw date values

A `creation date` property might be used like this, to group tasks by the date their file was created, according to the stored property values:

```javascript
group by function task.file.property('creation date') ?? 'no creation date'
```

- group tasks by 'creation date' date property.
#### Formatting date values using Moment.js

If you want to do date calculations on `Date` or `Date & time` values, you can use `window.moment(value)` to create a [Moment.js](https://momentjs.com) object.

For example:

```javascript
group by function \
const value = task.file.property('creation date'); \
return value ? window.moment(value).format('MMMM') : 'no month'
return value ? window.moment(value).format('YYYY MMMM') : 'no date'
```

## How does Tasks interpret Frontmatter Properties?

Consider a file with the following example properties (or "Frontmatter"):

<!-- TODO this was copied from docs_sample_for_task_properties_reference.md - embed the content automatically in future... -->

```yaml
---
sample_checkbox_property: true
sample_date_property: 2024-07-21
sample_date_and_time_property: 2024-07-21T12:37:00
sample_list_property:
- Sample
- List
- Value
sample_number_property: 246
sample_text_property: Sample Text Value
sample_text_multiline_property: |
Sample
Text
Value
sample_link_property: "[[yaml_all_property_types_populated]]"
sample_link_list_property:
- "[[yaml_all_property_types_populated]]"
- "[[yaml_all_property_types_empty]]"
aliases:
- YAML All Property Types Populated
tags:
- tag-from-file-properties
creation date: 2024-05-25T15:17:00
project: Secret Project
---
```

- group tasks by month in 'creation date' date property.
The following table shows how most of those properties are interpreted in Tasks queries:

<!-- placeholder to force blank line before included text --><!-- include: TaskProperties.test.task_frontmatter_properties.approved.md -->

| Field | Type 1 | Example 1 |
| ----- | ----- | ----- |
| `task.file.hasProperty('creation date')` | `boolean` | `true` |
| `task.file.property('creation date')` | `string` | `'2024-05-25T15:17:00'` |
| `task.file.property('sample_checkbox_property')` | `boolean` | `true` |
| `task.file.property('sample_date_property')` | `string` | `'2024-07-21'` |
| `task.file.property('sample_date_and_time_property')` | `string` | `'2024-07-21T12:37:00'` |
| `task.file.property('sample_list_property')` | `string[]` | `['Sample', 'List', 'Value']` |
| `task.file.property('sample_number_property')` | `number` | `246` |
| `task.file.property('sample_text_property')` | `string` | `'Sample Text Value'` |
| `task.file.property('sample_text_multiline_property')` | `string` | `'Sample\nText\nValue\n'` |
| `task.file.property('sample_link_property')` | `string` | `'[[yaml_all_property_types_populated]]'` |
| `task.file.property('sample_link_list_property')` | `string[]` | `['[[yaml_all_property_types_populated]]', '[[yaml_all_property_types_empty]]']` |
| `task.file.property('tags')` | `string[]` | `['#tag-from-file-properties']` |

<!-- placeholder to force blank line after included text --><!-- endInclude -->

Expand Down
7 changes: 5 additions & 2 deletions docs/Getting Started/Tags.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,12 @@ tags:
---
```

Tasks does not currently read this data. We are tracking this in [discussion #232](https://github.com/obsidian-tasks-group/obsidian-tasks/discussions/232).
Since Tasks X.Y.Z, Tasks **does** now read this data.

For now, see [Find tasks in notes with particular tag](https://github.com/obsidian-tasks-group/obsidian-tasks/blob/main/resources/sample_vaults/Tasks-Demo/How%20To/Find%20tasks%20in%20notes%20with%20particular%20tag.md) for a workaround using [[Dataview]] and Tasks together.
You can learn more in:

- [[Frontmatter Properties]], and the examples in that file
- [Find tasks in notes with particular tag](https://github.com/obsidian-tasks-group/obsidian-tasks/blob/main/resources/sample_vaults/Tasks-Demo/How%20To/Find%20tasks%20in%20notes%20with%20particular%20tag.md).

### Order of tags in task lines

Expand Down
1 change: 1 addition & 0 deletions docs/Quick Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ This table summarizes the filters and other options available inside a `tasks` b
| `filename (includes, does not include) <filename>`<br>`filename (regex matches, regex does not match) /regex/i`<br>`filename includes {{query.file.filename}}`<br>`filename includes {{query.file.filenameWithoutExtension}}` | `sort by filename` | `group by filename` | | `task.file.filename`<br>`task.file.filenameWithoutExtension`<br>`query.file.filename`<br>`query.file.filenameWithoutExtension` |
| `heading (includes, does not include) <string>`<br>`heading (regex matches, regex does not match) /regex/i` | `sort by heading` | `group by heading` | | `task.hasHeading`<br>`task.heading` |
| | | `group by backlink` | `hide backlink` | |
| **[[Frontmatter Properties]]** | | | | `task.file.hasProperty('property name')`<br>`task.file.property('property name')` |
| **[[Filters#Description\|Description]]**, **[[Filters#Tags\|Tags]]** and other odds and ends | | | | |
| `description (includes, does not include) <string>`<br>`description (regex matches, regex does not match) /regex/i` | `sort by description` | | | `task.description`<br>`task.descriptionWithoutTags` |
| `has tags`<br>`no tags`<br>`tag (includes, does not include) <tag>`<br>`tags (include, do not include) <tag>`<br>`tag (regex matches, regex does not match) /regex/i`<br>`tags (regex matches, regex does not match) /regex/i` | `sort by tag`<br>`sort by tag <tag_number>` | `group by tags` | `hide tags` | `task.tags` |
Expand Down
6 changes: 5 additions & 1 deletion docs/Scripting/Task Properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ For more information, including adding your own customised statuses, see [[Statu
> [!released]
> Access to the frontmatter properties was introduced in Tasks X.Y.Z.

These values are described in [[Frontmatter Properties]].
These are described in full in [[Frontmatter Properties]].

<!-- placeholder to force blank line before included text --><!-- include: TaskProperties.test.task_frontmatter_properties.approved.md -->

Expand All @@ -225,3 +225,7 @@ These values are described in [[Frontmatter Properties]].
| `task.file.property('tags')` | `string[]` | `['#tag-from-file-properties']` |

<!-- placeholder to force blank line after included text --><!-- endInclude -->

1. `task.file.hasProperty()` and `task.file.property()` were added in Tasks X.Y.Z
1. `task.file.hasProperty('property name')` returns true if the property `'property name'` is both present in the file and has a non-`null` value.
1. `task.file.property('property name')` returns either the value in the file, or `null` if there is no value.
Original file line number Diff line number Diff line change
@@ -1,15 +1,43 @@
# Access properties in frontmatter

## Accessing a custom property
These examples work with Tasks X.Y.Z and later.

## Accessing a custom property for grouping

Group by property `custom_number_prop`, with tasks from files without that property being un-grouped:

```tasks
folder includes Test Data
group by function task.file.frontmatter.custom_number_prop ?? 'not set'
group by function task.file.property('custom_number_prop')

limit groups 5
```

Group by property `custom_number_prop`, with a fixed gorup name for tasks from files without that property:

```tasks
folder includes Test Data
group by function task.file.property('custom_number_prop') ?? 'no "custom_number_prop" value'

limit groups 5
```

## Accessing tags

Group by each tag property value, and tasks with more than one tag are listed multiple times:

```tasks
folder includes Test Data
group by function task.file.property('tags')

limit groups 5
```

Group by tag property values, and tasks with more than one tag are listed only once

```tasks
folder includes Test Data
group by function task.file.frontmatter.tags
group by function task.file.property('tags').sort().join(', ')

limit groups 5
```
Loading