Cloning/Duplicating Nodes in Drupal is easy, just get some module that does that for you and you are ready but the problem is when you are using Drupal 8 and there is no stable module or they are still not ported to Drupal 8. I had this problem, so I had to find some kind of solution. You can check my short answer on stackoverflow or continue reading this.

At the time of this writing, there is still no stable modules for cloning.

TL;DR: Code for this can be found here.


What if we add Paragraphs module? Great solution for page builder in Drupal, be sure to check it out. I will explain how to create clones of your Nodes with or without Paragraphs.

We will create a custom module that will add an option to our content listing for cloning.

Custom Module

So we will create a custom module with name 'clone_nodes' in the modules directory.

clone_nodes.info.yml
name: Clone Nodes
description: 'Creates clone of node.'
type: module
core: 8.x
package: Custom
clone_nodes.routing.yml
clone_nodes:
    path: '/cnodes/node/{id}/clone'
    defaults:
        _controller: '\Drupal\clone_nodes\Controller\CloneController::clone'
    requirements:
        _permission: 'access content'
clone_nodes.module
<?php

function clone_nodes_pages_entity_operation(\Drupal\Core\Entity\EntityInterface $entity)
{

    $operations = [];

    if ($entity instanceof \Drupal\node\Entity\Node) {
        $operations['clone'] = [
          'title' => t('Clone'),
          'url' => \Drupal\Core\Url::fromRoute('clone_nodes',['id' => $entity->id()]),
          'weight' => 150,
        ];
    }

    return $operations;
}

Now we only need the Controller and that will be different if you are using paragraphs or not.

Controller without Paragraphs

After searching for this solution I found that Drupal 8 Entity API has createDuplicate method so I used that.

CloneController.php
<?php
namespace Drupal\clone_nodes\Controller;

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Drupal\node\Entity\Node;

class CloneController extends ControllerBase
{

    public function clone($id)
    {
        $node = Node::load($id);
        if ($node === null) {
            drupal_set_message(t('Node with id @id does not exist.', ['@id' => $id]), 'error');
        } else {

            $nodeDuplicate = $node->createDuplicate();
            //edit title or something so you can find cloned
            $nodeDuplicate->save();

            drupal_set_message(
            	t("Node has been created. <a href='/node/@id/edit' target='_blank'>Edit now</a>", [
                  '@id' => $nodeDuplicate->id(),
                  '@title' => $nodeDuplicate->getTitle()]
            	 ), 'status');
        }

        return new RedirectResponse('/admin/content');
    }
}

When you create duplicate of node you can edit title or something so you can distinguish original from cloned, but the only difference that I saw was that cloned Node doesn’t have alias url becuase that stays bound to original.

Controller with Paragraphs

The only difference is that you have to duplicate every paragraphs field that is connected to node, so we will just add this part of code :

foreach ($nodeDuplicate->field_paragraphs as $field) {
    $field->entity = $field->entity->createDuplicate();
}

field_paragraphs is machine name I used for my paragraphs field in Content Type, be sure to changed it to match yours.

So our Controller now looks like :

CloneController.php
<?php
namespace Drupal\clone_nodes\Controller;

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Drupal\node\Entity\Node;

class CloneController extends ControllerBase
{

    public function clone($id)
    {
        $node = Node::load($id);
        if ($node === null) {
            drupal_set_message(t('Node with id @id does not exist.', ['@id' => $id]), 'error');
        } else {

            $nodeDuplicate = $node->createDuplicate();

            foreach ($nodeDuplicate->field_paragraphs as $field) {
                $field->entity = $field->entity->createDuplicate();
            }

            //edit title or something so you can find cloned
            $nodeDuplicate->save();

            drupal_set_message(
            	t("Node has been created. <a href='/node/@id/edit' target='_blank'>Edit now</a>", [
                  '@id' => $nodeDuplicate->id(),
                  '@title' => $nodeDuplicate->getTitle()]
            	 ), 'status');
        }

        return new RedirectResponse('/admin/content');
    }
}

I hope this helps someone with this problem and until some old clone module is ported to Drupal 8 I guess this will have to do it.