Flowpack.NodeTemplates icon indicating copy to clipboard operation
Flowpack.NodeTemplates copied to clipboard

Possibility to copy (child) nodes from another node

Open jonnitto opened this issue 2 years ago • 9 comments

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?

jonnitto avatar Jun 14 '23 08:06 jonnitto

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

mhsdesign avatar Jun 14 '23 08:06 mhsdesign

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.

theilm avatar Jun 14 '23 12:06 theilm

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 :)

bweinzierl avatar Sep 26 '23 15:09 bweinzierl

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 avatar Feb 19 '25 11:02 MiauzGenau

@MiauzGenau Could you provide an example, so we can add it to the readme?

jonnitto avatar Feb 28 '25 13:02 jonnitto

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.

MiauzGenau avatar Mar 04 '25 11:03 MiauzGenau

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

jonnitto avatar Mar 05 '25 14:03 jonnitto

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.

mhsdesign avatar Mar 05 '25 14:03 mhsdesign

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?

Sebobo avatar Apr 01 '25 20:04 Sebobo