Possibility to copy (child) nodes from another node
With NodeTemplates version 1.2 I've created the possibility to create template sites where you can add content elements to have a fast quick start (e.g. for blog posts).
For this, I've created following mixin
'Base.Templates:Mixin.CreationDialog':
ui:
creationDialog:
elements:
templateNodeIdentifier:
type: reference
ui:
label: Template
editorOptions:
nodeTypes: ['Base.Templates:Mixin.Template']
options:
template:
childNodes:
mainContentCollection:
when: '${data.templateNodeIdentifier}'
name: main
options:
childNodesToCopy: "${q(node).find('#' + data.templateNodeIdentifier).children('main').children().get()}"
And following Package.php
<?php
namespace Base\Templates;
use Base\Templates\Service\ChildNodeCopyService;
use Flowpack\NodeTemplates\Template;
use Neos\Flow\Core\Bootstrap;
use Neos\Flow\Package\Package as BasePackage;
/**
* The Node Templates Magic Package
*/
class Package extends BasePackage
{
/**
* @param Bootstrap $bootstrap The current bootstrap
* @return void
*/
public function boot(Bootstrap $bootstrap)
{
$dispatcher = $bootstrap->getSignalSlotDispatcher();
$dispatcher->connect(
Template::class,
"nodeTemplateApplied",
ChildNodeCopyService::class,
"copyChildNodesAfterTemplateApplication"
);
}
}
The ChildNodeCopyService.php looks like that
<?php
namespace Base\Templates\Service;
use Flowpack\NodeTemplates\Service\EelEvaluationService;
use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\Eel\Package as EelPackage;
use Neos\Flow\Annotations as Flow;
use Neos\Neos\Service\NodeOperations;
/**
*/
class ChildNodeCopyService
{
/**
* @var EelEvaluationService
* @Flow\Inject
*/
protected $eelEvaluationService;
/**
* @var NodeOperations
* @Flow\Inject
*/
protected $nodeOperations;
/**
* @param NodeInterface $node
* @param array $context
* @param array $options
* @return void
*/
public function copyChildNodesAfterTemplateApplication(
NodeInterface $node,
array $context,
array $options
): void {
// Copy child nodes from template
if (
isset($options["childNodesToCopy"]) &&
preg_match(
EelPackage::EelExpressionRecognizer,
$options["childNodesToCopy"]
)
) {
$childNodes = $this->eelEvaluationService->evaluateEelExpression(
$options["childNodesToCopy"],
$context
);
/** @var NodeInterface $childNode */
foreach ($childNodes as $childNode) {
$this->nodeOperations->copy($childNode, $node, "into");
}
}
}
}
With the new version, it is not possible to create this helpful feature. Should we create an API for that, to make this possible?
Funnily we just discussed this but dindt think of this perfectly legit and cool usecase - thanks for reminding us. https://github.com/Flowpack/Flowpack.NodeTemplates/issues/50
Our options to solve this usecase are:
1 - use a custom NodeCreationHandler yourself -> but i dislike this, as the api will change with 9.0 (one could extract it into an own package then) 2 - introduce this as a feature with support for neos8 and neos9
Yes that's the use case I was mentioning in #50 - I introduced the signal exactly for that (cool that you are using it :)). It will be more complex to solve this for neos9, but I think it should be possible - and I agree, it should be part of the NodeTemplates package.
We are using it too for every customer. We have a template section nodetype where the editor is able to create template sections in a hidden part of the document tree. When creating sections on any page the creation dialogue will ask if a template should be used and if so the childnodes will be copied. This is a killer feature imho.
This uses the mentioned logic with a custom datasource for making the created templates selectable.
So +1 for reimplementing this :)
For our use-case (which also involves copying), I was able to migrate to the nodeCreationHandlersApplied Signal (from Neos\Neos\Ui\Domain\Model\Changes\AbstractCreate).
(Which also gets triggered after the NodeTemplates are fully applied.)
If somebody is looking for an alternative/ in between solution.
@MiauzGenau Could you provide an example, so we can add it to the readme?
This is the current example from the readme: https://github.com/mindscreen/neos-nodetemplates-demo/blob/master/Classes/Service/ChildNodeCopyService.php
What we do, is hook into Neos\Neos\Ui\Domain\Model\Changes\AbstractCreate -> nodeCreationHandlersApplied(). With this function and some custom code:
public function nodeCreationHandlersAppliedHandler(NodeInterface $node): void
{
if (!$node->getNodeType()->isOfType('Paessler.Demo:Content.Section')) {
return;
}
// do some flowqueries
$q = new FlowQuery([$node]);
$childNodesToCopy = $q->children()->get();
$documentNode = $q->closest('[instanceof Neos.Neos:Document]')->get(0);
[...]
// do some copy operation
$this->nodeOperations->copy($childNode, $page, 'into');
}
This is not suited for the readme I would assume. I'm unsure what you expect/ want.
But how can you get the selection option from the creation dialog? With the parameter $node it seems not possible. The power of this signal was that you are able to react on the options given in the creation dialog
Hi btw the long term plan is definitely to allow this requested feature in the core. A year ago i made a draft of how that could look like: https://github.com/Flowpack/Flowpack.NodeTemplates/pull/80/files#diff-4026ac608fda12fc5dc44d704d88e08fde47e4bb910e3d4f298aca5f399cab08 but i currently hadn't had capacities to follow up on that.
Why is it not possible to solve this with a second handler that is applied after the TemplateNodeCreationHandler?
The second handler gets the same information and could do something else with it?