Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Idea: Fluid expression node type for TYPO3 CMS to govern editable behavior

Fluid: editable toggle for each template

This short article aims to describe an idea to automatically make properties rendered in Fluid editable in TYPO3. At the currrent time this exclusively applies to frontend editing (the new EXT:frontend_editing) but there's no technical reason why it should not be possible to do the same in the backend (for example, automatically converting variables rendered in content element previews into an editable field).

This article only deals with the frontend editing perspective.

Concept

The concept is based on two different components working in unison:

  1. An expression node type for Fluid which allows you to declare {editable tt_content} or {editable pages} (or any other arbitrary table as long as it is defined in TCA!)
  2. An addition to the TYPO3 variable provider for Fluid which can be configured to render variables with custom wrapping, act as ad-hoc hook to load required assets (JS, CSS), register the required route, validate access, and so on.

These two components together would mean that a developer can for example specify a template like the following:

{editable tt_content record.uid}
<div id="mytype">
    <h1>{header}</h1>
    {bodytext -> f:format.html()}
</div>

This would then make the TYPO3 variable provider aware that when variables get rendered, their name may be a name matching a TCA column name - and can then wrap the output in HTML to trigger editable status.

For the cases where an editable property is rendered from an object (domain model instance of record) it would in addition be possible to declare which TCA column the property corresponds to, for example via a new expression node type as follows:

{editable tt_content myobject.uid}
<div id="mytype">
    <h1>{differentNameForHeader edits header}</h1>
    <f:format.html>{nameForBodyText edits bodytext}</f:format.html>
</div>

(note about the above case: escaping behavior must be toggled on parent node in order to render the HTML; there are several ways to achieve this via Fluid API)

Universality

The major boon from this concept would be the ability to render arbitrary records rather than just tt_content. To eplain what that means, we can use EXT:news as an example. A news item template could look like:

{editable tx_news_domain_model_news newsItem.uid}
<div class="news-item">
    <h1>{newsItem.title}</h1>
    <f:format.html>{newsItem.body}</f:format.html>
</div>

The internal logic used to enable the rendering is the same for all tables; all use EditDocumentController to achieve the record saving - and thus all would be capable of receiving changes for any registered TCA table.

Recursivity

It may already have occurred to you at this point: the concept described above means enabling editing can happen recursively right from the pages level down an infinite depth. To illustrate, consider this rendering tree:

PAGE (capable of editing properties from page being rendered when those are output in Fluid)
  -> Content "textmedia" (capable of editing content record)
     -> Category A (capable of editing category related to content, for example the name or removing the category)
     -> Category B (same as above)
  -> Plugin: News (list+detail view instance, capable of editing plugin's properties)
     -> Detail view news item C (capable of editing all shown properties in detail rendering)
        -> Related news item A (capable of editing related news items' properties)
        -> Related news item B (same as above)
        -> News media relation A (capable of editing properties from related media record)
     -> Listed news item A (capable of editing one listed news item's displayed properties)
     -> Listed news item B (same as above)
        -> Category A (capable of editing category related to news item B)

  The above would be possible to achieve full editing capabilities for any property shown in the frontend, at any depth, cascading into relations. Any branch of the tree would be optional, for example the page Fluid template would not need to enable editing for the content Fluid template to be editable. Regardless of which branches in the rendering tree supports editing, as soon as a child is rendered which does support editing, it gets enabled.

Automation

It would be possible to go even one step further and automatically detect when:

  • The variable being accessed sits on a domain model
  • The domain model is mapped to TCA

Given just two key pieces of information, the variable provider itself would actually have access to enabling the editable status of all properties rendered by that template.

That means: automatically enabled frontend editing for any arbitrarily rendered variables in any Fluid template without any requirement to declare which object and which property is editable. It would work for listing views to automatically make any rendered property in for example a loop, editable.

It would perhaps even mean there no longer is a need to provide custom FCC templates. And there would be no need for the "content editable" ViewHelper currently added to EXT:core. Editing would simply be enabled on-the-fly, as needed, based on each variable that gets rendered, for any domain model without any action from the developer or integrator.

Sketched solution

  1. Create an Interceptor for Fluid which triggers on ObjectAccessors being intercepted
  2. Create a registry that tracks the properties that are encountered (tracking if they are encountered in VH arguments)
  3. Analyse the ObjectAccessor's property path and exract object down to last segment
  4. Use last segment as property that may or may not be editable
  5. Match the object and property against TCA to determine table and type of field as well as user's access to it
  6. Only process fields that are editable in BE (preferably: render the editing field in FE based on what's in TCA)
  7. Use the intercepted property names to do things like create a new node in the Fluid template that adds a sibling element, or simply store them until the page finishes processing and display the editor then.
  8. Decide if it's reasonable to use a Repository to do the update, if one is detected. If this strategy is used

The above will add the edit capability for Extbase domain models. Use cases not based on model objects will require manual opting-in to editing (see above: can have a template-wide setting for which table to edit).

There are basically two ways of presenting FE editing:

  1. As embedded fields or modals opened when you click to edit something inline.
  2. A collected set of fields that will edit objects used on the page, but does so in a way that's separate from the DOM of each individual field (this is the one I would recommend).

The embedded fields require changing the DOM and are not always safe to do. There is however one use case that would allow this in a compatible way predictably regardless of use case: TagBasedViewHelpers can add arbitrary properties to a tag that gets generated; properties that can then be used to enable editable status on the tag itself through JS.

It is also possible to determine whether it is safe (disregarding any CSS issues) to wrap a property being output inside a TextNode, with a tag that makes just that part editable.

A combination can also be used: trustworthy properties can be editable inline while secondary (for example, the ones passed to a ViewHelper, e.g. a target page UID) can be edited separately. And a toggle can be provided on template-, plugin- or extension level to for example force separated editing for some things only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.