Skip to content

Commit

Permalink
Documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
ttempleton committed Oct 30, 2018
1 parent d5c6b1d commit 3dfafd8
Show file tree
Hide file tree
Showing 8 changed files with 339 additions and 0 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,13 @@ Let block types have the ability to contain child block types. You can filter wh

<img src="docs/assets/feature5-1.png" width="790">
<img src="docs/assets/feature5-2.png" width="622">

## Documentation
- [Installation](docs/installation.md)
- [Creating Neo Fields](docs/creating-neo-fields.md)
- [Templating](docs/templating.md)
- [Eager Loading](docs/eager-loading.md)
- [Resources](docs/resources.md)
- [API](docs/api.md)
- [FAQ](docs/faq.md)
- [Changelog](CHANGELOG.md)
96 changes: 96 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# API

## Element Query

Like Matrix field values, Neo field values are [element queries](https://docs.craftcms.com/v3/dev/element-queries/). As Neo fields contain structure, this API contains a bit more than the Matrix field.

### Parameters

| Parameter | Description |
|--------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|
| `ancestorOf` | Only fetch blocks that are an ancestor of a given block. Accepts a `Block` object. |
| `ancestorDist` | Only fetch blocks that are a given number of levels above the block specified by the `ancestorOf` parameter. |
| `level` | Only fetch blocks located at a certain level. |
| `descendantOf` | Only fetch blocks that are an descendant of a given block. Accepts a `Block` object. |
| `descendantDist` | Only fetch blocks that are a given number of levels below the block specified by the `descendantOf` parameter. |
| `id` | Only fetch the block with the given ID. |
| `limit` | Limits the results to _X_ blocks. |
| `nextSiblingOf` | Only fetch the block which is the next sibling of the given block. Accepts either a `Block` object or a block's ID. |
| `offset` | Skips the first _X_ blocks. |
| `positionedAfter` | Only fetch blocks which are positioned after the given block. Accepts either a `Block` object or a block's ID. |
| `positionedBefore` | Only fetch blocks which are positioned before the given block. Accepts either a `Block` object or a block's ID. |
| `prevSiblingOf` | Only fetch the block which is the previous sibling of the given block. Accepts either a `Block` object or a block's ID. |
| `relatedTo` | Only fetch blocks that are related to certain other elements. (See [Relations](https://docs.craftcms.com/v3/relations.html) for the syntax options.) |
| `search` | Only fetch blocks that match a given search query. (See [Searching](https://docs.craftcms.com/v3/searching.html) for the syntax and available search attributes.) |
| `siblingOf` | Only fetch blocks which are siblings of the given block. Accepts either a `Block` object or a block's ID. |
| `status` | Only fetch blocks with the given status. Possible values are `'enabled'`, `'disabled'`, and `null`. The default value is `'enabled'`. `null` will return all blocks regardless of status. |
| `type` | Only fetch blocks that belong to a given block type(s), referenced by its handle. |
| `typeId` | Only fetch blocks that belong to a given block type(s), referenced by its ID. |

--

## Neo Block

### Properties

| Property | Description |
|------------------|-------------------------------------------------------------------------------------------------------------|
| `ancestors` | Alias of `getAncestors()`. |
| `children` | Alias of `getChildren()`. |
| `collapsed` | Whether the block is collapsed in the control panel. |
| `dateCreated` | A `DateTime` object of the date the block was created. |
| `dateUpdated` | A `DateTime` object of the date the block was last updated. |
| `descendants` | Alias of `getDescendants()`. |
| `enabled` | Whether the block is enabled. |
| `field` | Alias of `getField()`. |
| `fieldId` | The ID of the field that the block belongs to. |
| `hasDescendants` | Whether the block has any descendants. This will return `true` even if all of the descendants are disabled. |
| `id` | The block's ID. |
| `level` | The block's level. |
| `next` | Alias of `getNext()`. |
| `nextSibling` | Alias of `getNextSibling()`. |
| `owner` | Alias of `getOwner()`. |
| `ownerId` | The ID of the element that the block belongs to. |
| `parent` | Alias of `getParent()`. |
| `prev` | Alias of `getPrev()`. |
| `prevSibling` | Alias of `getPrevSibling()`. |
| `siblings` | Alias of `getSiblings()`. |
| `type` | Alias of `getType()`. |
| `typeId` | The ID of the block type that the block belongs to. |

### Methods

| Method | Description |
|----------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `getAncestors(distance)` | Returns an `ElementQuery` prepped to return the block's ancestors. You can limit it to only return ancestors that are up to a certain distance away by passing the distance as an argument. |
| `getChildren()` | Returns an `ElementQuery` prepped to return the block's children. (This is an alias for `getDescendants(1)`) |
| `getDescendants(distance)` | Returns an `ElementQuery` prepped to return the block's descendants. You can limit it to only return descendants that are up to a certain distance away by passing the distance as an argument. |
| `getField()` | Returns a `Field` object representing the block's field. |
| `getNext(params)` | Returns the next block that should show up in a list based on the parameters entered. This function accepts either an `ElementQuery` object, or a parameter array. |
| `getNextSibling()` | Returns the block's next sibling (regardless if it's disabled), if there is one. |
| `getOwner()` | Returns an `Element` object representing the block's owner. This could be an entry, category, or some other element type. |
| `getParent()` | Returns the block's parent (regardless if it's disabled), if it's not a top-level block. |
| `getPrev(params)` | Returns the previous block that should show up in a list based on the parameters entered. This function accepts either an `ElementQuery` object, or a parameter array. |
| `getPrevSibling()` | Returns the block's previous sibling (regardless if it's disabled), if there is one. |
| `getSiblings()` | Returns an `ElementQuery` prepped to return the block's siblings. |
| `getType()` | Returns a `BlockType` object representing the block's type. |
| `hasDescendants()` | Returns whether the block has any descendants. |
| `isAncestorOf(block)` | Returns whether the block is an ancestor of another block. |
| `isChildOf(block)` | Returns whether the block is a direct child of another block. |
| `isDescendantOf(block)` | Returns whether the block is a descendant of another block. |
| `isNextSiblingOf(block)` | Returns whether the block is the next sibling of another block. |
| `isParentOf(block)` | Returns whether the block is a direct parent of another block. |
| `isPrevSiblingOf(block)` | Returns whether the block is the previous sibling of another block. |
| `isSiblingOf(block)` | Returns whether the block is a sibling of another block. |

--

## Neo Block Type

### Properties

| Property | Description |
|----------|-------------------------------|
| `handle` | The handle of the block type. |
| `id` | The ID of the block type. |
| `name` | The name of the block type. |
36 changes: 36 additions & 0 deletions docs/creating-neo-fields.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Creating Neo Fields

<img src="docs/assets/creating-field.png" width="790">

#### 1. Field layout tab
Design the field layout for each block type using the familiar field layout designer. One small thing to look out for is asset fields that use `{property}` tags in their directory settings. [Read more about it here.](faq.md#why-do-asset-fields-with-slug-as-an-upload-location-break-on-neo-blocks)

--

#### 2. Max blocks of type setting
Use this field to limit the number of blocks of a certain type in a field. Note that the max blocks setting applies regardless of whether the block is a child of another. You cannot use this setting to restrict the number of child blocks in a block.

--

#### 3. Allowed child block types setting
Here you can define what blocks of certain types can be added as children. If there are any child blocks set, it will add a row of buttons at the bottom of each block. This setting will allow you to nest the same block type recursively.

--

#### 4. Top-level only setting
This setting will determine if blocks of this type will only be allowed as children to another block. If this setting is disabled, then the button for this block type will be hidden on the input – except when it's inside another block.

--

#### 5. Block type group
This is an example of a block type group. All block types down until another group will belong to this group. If you want to simply close a group without creating a new one, you can create a group without a name.

--

#### 6. Parent/child block type example
This is an example of how you might use the child blocks and top level settings – a slideshow. The `Slideshow` block type allows the `Slide` block type as a child. This `Slide` block type has its "top-level only" setting disabled, indicated by the graphical indentation. On the input, the `Slide` block type button will not be seen except for inside a `Slideshow` block.

--

#### 7. Block type and group buttons
The buttons for creating block types and groups.
81 changes: 81 additions & 0 deletions docs/eager-loading.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Eager Loading

As of version 1.4.0, Neo supports [eager-loading](https://docs.craftcms.com/v3/dev/eager-loading-elements.html). However, given the nature of eager-loading, templating an eager-loaded Neo field is quite different to a non-eager-loaded Neo field. This page will attempt to educate you on the differences and provide an example of how to template with it. Keep in mind it expects you have a fairly solid understanding of the Elements system in Craft.

## How it works with Neo

The typical value of a Neo field is something called an [Element Query](https://docs.craftcms.com/v3/dev/element-queries/). At its core, it's simply a wrapper for creating database queries that retrieve elements, or in this case, Neo blocks. You can modify these element queries to more finely select elements &mdash; for example, you can add a level filter to only select Neo blocks from that particular level: `entry.neoField.level(1)`.

An eager-loaded Neo field is no longer an element query. The database query that an element query would make has already been made when eager-loading, with the resulting value of `entry.neoField` being a simple array. This means you can no longer filter your results like above.

## How to deal with this

The answer to this is an unfortunate &ldquo;it depends&rdquo; &mdash; but it mostly depends on whether your Neo field makes use of the child blocks feature. I'll split this into two cases; Neo fields with hierarchy and Neo fields without.

### Without hierarchy

Good news! Chances are you probably don't have to change your code. Though if you are filtering your blocks in some other way, you will have to change your template code a little bit. As an example, you might be filtering your blocks by some block type with the handle `pullQuote`:

```twig
{% for pullQuotes in entry.neoField.type('pullQuote').all() %}
...
{% endfor %}
```

For an eager-loaded Neo field, the above can simply be changed to the following:

```twig
{% for pullQuotes in entry.neoField if pullQuotes.type.handle == 'pullQuote' %}
...
{% endfor %}
```

### With hierarchy

This is where things start to get a little hairy. Using the same approach above to select only the top-level blocks will indeed work:

```twig
{% for block in entry.neoField if block.level == 1 %}
...
{% endfor %}
```

The problem shows up when you output a block's children &mdash; it'll end up creating another database query, which entirely defeats the purpose of eager-loading:

```twig
{% for block in entry.neoField if block.level == 1 %}
{% for child in block.children %}
{# `block.children` is an element query
which will cause an unnecessary database call #}
{% endfor %}
{% endfor %}
```

There is a feature in Neo that will allow you to avoid these database calls, and it works with or without eager loading! At the top of your loop, add the following: `{% do block.useMemoized(entry.neoField) %}`

```twig
{% for block in entry.neoField if block.level == 1 %}
{% do block.useMemoized(entry.neoField) %}
...
{% endfor %}
```

What this does is it forces Neo blocks to use and query against a &ldquo;local database&rdquo; of blocks instead of going to the database. When eager-loading, all blocks of a Neo field are queried for, so the child blocks for any block will already exist in this eager-loaded array. This means instead of creating a database query to get these blocks, this array can just be scanned through.

Be aware though, every block (include all child blocks) should have the `useMemoized` method called in order to completely avoid all unnecessary database calls. If you split rendering your blocks into separate template files or macros, it'll get complicated as you'll have to manually pass around the `entry.neoField` eager loaded array. Therefore, I recommend doing this: iterate over all your blocks and call the `useMemoized` method _first_:

```twig
{# Preparation for the eager-loaded Neo field #}
{% for block in entry.neoField %}
{% do block.useMemoized(entry.neoField) %}
{% endfor %}
{# The real-deal #}
{% for block in entry.neoField if block.level == 1 %}
...
{% endfor %}
```

## Eager loading fields inside Neo blocks

From here on out, eager-loading behaves the same way as the Matrix field type. [Refer to the official Craft documentation](https://docs.craftcms.com/v3/dev/eager-loading-elements.html#eager-loading-elements-related-to-matrix-blocks).
Loading

0 comments on commit 3dfafd8

Please sign in to comment.