Neos Fusion In Action - Part 2

In our second part of Fusion in Action we'll have a deeper look at FlowQuery and how it can be used to access almost anything in your content repository. These exercises can take a little bit longer, but there will be hints along the way.

Ready for action? If unsure, you should have a look at the first part of Fusion in Action and the Hitchhiker's Guide Part 1 and 2 before solving these exercises.

The demo node structure

For all the examples below, we assume the following nodes in the content repository:

Diagram of nodes in the demo site

The current context

An expression in Fusion has access to the context, which stores values about the current node, the current document node (the page) and the site node. The following variable names are available by default:

  • node The current node, this could be the document node on the outer level or a content node when rendering nodes in a ContentCollection
  • documentNode The current document node is the node that is used to render the current page
  • site The site node is the root of your site

It's a wrap

Using FlowQuery means to wrap a value with the q function. This enables the use of all kinds of operations on the resulting FlowQuery object. Some operations will return another FlowQuery object that wraps a modified list of values and some operations will end up in a string or array value. These are called final operations.

Every non-final operation will return another FlowQuery object. The FlowQuery object always wraps a list of values and all operations work on these values.

${q(node).operation().anotherOperation()}

Getting node properties

Properties of nodes make up the actual content. For a node type all properties are automatically declared as variables for a Fluid template. But it's also useful to access properties explicitly to render different parts of a page.

If a FlowQuery result contains more than one node the property operation will only return the property value of the first node.

Context

Diagram with context for the example

1. Write a FlowQuery expression to render the title property of the current node as the title tag

On the document level the context variables node and documentNode refer to the same node instance. But when rendering content the variable node will change to the current node - like a headline or text element. This is a convention used throughout the Neos rendering to always have a reference to the current node.

Traversing nodes

One of the main benefits of FlowQuery is an easy way to traverse nodes in the content repository. That means navigating and querying through the structure to find content. As the nodes are  arranged in a tree, every node has a parent and zero or more children.

Context

Diagram with context for the example

2. Output the parent node and the current node title property as the title tag

The node name is a way to reference nodes by name. This name might not be stable, as it is editable for document nodes by default. But automatically created child nodes like a ContentCollection are safe to reference by name. Most of the operations accept an optional filter argument that will narrow down the matched results. The children operation is one of these operations and can be used to select only specific child nodes.

In it's simplest form the filter will just take a node name:

${q(node).children('nodeName')}

Context

Diagram with context for the example

3. Get the number of child nodes in the main ContentCollection

Filtering attributes

But it's also possible to filter by the properties of a node. The syntax is based on CSS selectors for attributes and attribute values:

// Filter by property existence
${q(node).children('[title]')}

// Filter by property value
${q(node).children('[title="Hello world!"]')}

Context

Diagram with context for the example

4. Get the text property value of the first child node having a text property in the main ContentCollection

Filtering node types

Besides their structure and properties, nodes also have a type. This is quite natural when thinking about content and in Neos CMS many scenarios can be modeled by using distinct node types.

When rendering content it is often necessary to only select nodes of a certain kind. The FlowQuery filter instanceof will only match nodes that have a particular node type:

${q(node).children('[instanceof My.Package:NodeType]')}

Context

Diagram with context for the example

5. Find the first node of type TYPO3.Neos.NodeTypes:Text in the main ContentCollection and output the text property

As node types can have super types that will be extended to compose new types, the instanceof operation will also match super types of a node. Thus, it is possible to filter nodes that have a specific node type either directly or as the parent type. In Neos the most prominent super types are TYPO3.Neos:Content and TYPO3.Neos:Document that make the distinction between nodes that are merely content elements or nodes that make up documents accessible via a URL.

Context

Diagram with context for the example

6. Get the count of all document child nodes of the current node ("Home")

For the rendering of a content node type it's sometimes necessary to find a parent node (or, more correctly, an ancestor) of a specific type or with a particular property. The closest operation comes in handy to find the closest ancestor that matches a given filter.

Context

Diagram with context for the example

7. Find the closest ContentCollection (TYPO3.Neos:ContentCollection) and output the node path of the current node, which will not be a document

The node path or node name can be accessed through the virtual properties _path or _name. They can be handy to debug the result of a FlowQuery.

Modifying the result

For a teaser or a list of some specific nodes it's often desirable to render each element in some way. In Part 2 of the Hitchhiker's Guide you already learned about the Collection Fusion object. The collection property accepts anything that resembles a list of values, which is true for a FlowQuery result.

Besides just passing the result of a FlowQuery as the collection, it's possible to add specific elements to the result using the add operation.

${q(node).add(q(node).children())}

Context

Diagram with context for the example

8. Render a list of nodes for a breadcrumb using a Collection object, the collection should contain the current node and all parents

Wrap up

Congratulation! If you made it this far and solved all code exercises you'll have a good overview of FlowQuery. It's a key piece to bring your content to life and knowing about the operations and filters will give you a great amount of flexibility.

FlowQuery Fu

FlowQuery Fu

Rewarded for solving code exercises in Fusion that involve FlowQuery. Proves sufficient knowledge to traverse nodes, find nodes of a certain type and access properties of nodes.


Update (March, 2018): Renamed TypoScript 2 to Fusion

comments powered by Disqus