I'm attempting to do a deep clone of a panelized node with a few Fieldable panels panes on it.
Once I worked out how to clone a panels page, I found that the text pane I had inserted on the first page, was only referenced on the clone, instead of properly cloned as I had hoped.

Where do I begin if I want this function?

I'm using Drupal 7.14, Node Clone 7.x-1.0-rc1, Panelizer 7.x-3.0-rc1, Fieldable Panels Panes
7.x-1.2 (and panopoly 7.x-1.0-beta6).

Comments

klim_’s picture

Have you resolved this issue?

lelizondo’s picture

Issue summary:View changes
Status:Active» Fixed

This is whay I did.

First, the problem was that FPP were not being cloned so the same FPP was referenced by the original node and the cloned node. So the solution was actually simple, loop through all the FPP in the original node, then load the FPP entity, create a new one with the same content and assign the new entity to the cloned node.

This is my code:

<?php
function mymodule_clone_node_alter(&$node, $context) {
	$original = $context["original_node"];

	if($original->type == "my_content_type")	{
		if(isset($node->panelizer["page_manager"]->display)) {
                        // The cloned node had the same UUID as the original, so I had to regenerate it
			$node->panelizer["page_manager"]->display->uuid = uuid_generate();

			foreach($node->panelizer["page_manager"]->display->content as $entity) {
                               // The cloned node had the same UUID as the original, so I had to regenerate it
				$entity->uuid = uuid_generate();

				if($entity->type == "fieldable_panels_pane") {
					// clone each fpp and then assign the new fpid in the form of fpid
					list($subtype, $fpid) = explode(":", $entity->subtype);

					if($subtype == "fpid") {
						// Load the entity
						$fpp = fieldable_panels_panes_load($fpid);

						// Create a new entity based on the same entity
						$fpp->fpid = null;
						$fpp->created = null;
						$fpp->timestamp = null;

						$newEntity = fieldable_panels_panes_save($fpp);

						// Assign the new id to the $entity->subtype
						$entity->subtype = "fpid:" . $newEntity->fpid;
					}
				}
			}
		}
	}
}
?>

Status:Fixed» Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

dimitrov.adrian’s picture

Status:Closed (fixed)» Needs review
Issue tags:+cloning
FileSize
6.68 KB
FAILED: [[SimpleTest]]: [MySQL] Unable to apply patch fieldable_panels_panes-cloning-fieldable-panels-panes-1806430-1-7.patch. Unable to apply patch. See the log in the details link for more information. View
942 bytes

Seems it's not fixed yet.

I prepare patch that adds and button (on IPE and menu item on panels) that allow user to clone pane's entity.

Status:Needs review» Needs work
dimitrov.adrian’s picture

FileSize
7.16 KB
FAILED: [[SimpleTest]]: [MySQL] Unable to apply patch fieldable_panels_panes-cloning-fieldable-panels-panes-1806430-6-7.patch. Unable to apply patch. See the log in the details link for more information. View

New patch that should be applicable.

dimitrov.adrian’s picture

Status:Needs work» Needs review

Status:Needs review» Needs work

Status:Needs review» Needs work
valthebald’s picture

Version:7.x-1.2» 7.x-1.x-dev
Status:Needs work» Needs review
FileSize
2.87 KB
FAILED: [[SimpleTest]]: [MySQL] Unable to apply patch 1806430-11.patch. Unable to apply patch. See the log in the details link for more information. View

Another approach is to provide cloning functionality in overridden display renderer.
The idea is to clone the pane, then pass it to edit-pane handler.

Patch follows

valthebald’s picture

FileSize
5.56 KB
FAILED: [[SimpleTest]]: [MySQL] Unable to apply patch 1806430-12.patch. Unable to apply patch. See the log in the details link for more information. View

My bad, missed the function that actually clones a pane

The last submitted patch, 11: 1806430-11.patch, failed testing.

Status:Needs review» Needs work

The last submitted patch, 12: 1806430-12.patch, failed testing.

valthebald’s picture

Status:Needs work» Needs review
FileSize
7.03 KB
FAILED: [[SimpleTest]]: [MySQL] Unable to apply patch 1806430-15.patch. Unable to apply patch. See the log in the details link for more information. View

I guess testbot couldn't apply the patch because of missing image, fixing

Status:Needs review» Needs work

The last submitted patch, 15: 1806430-15.patch, failed testing.

valthebald’s picture

Status:Needs work» Needs review
FileSize
7.02 KB
PASSED: [[SimpleTest]]: [MySQL] 0 pass(es). View

Reverse patch :(

valthebald’s picture

vood002’s picture

I've stumbled into the need for this and have tried the solution in #2 and the patch in #17 with node_clone but have had no luck.

After cleaning up the typo in the Patch in #17---panles in count(fieldable_panles_panes_pane_shares($context['pane']->pid)) (although truth be told I'm not sure where this function is supposed to exist so I just had to comment this out)--I cloned the node, but when I then cloned and changed a pane in the cloned node it updated the same pane in the source node.

I don't completely grasp the overall structure of Panelizer, but my assumption is that node_clone cloned the node but duplicated the same Panels Display, so when I updated the pane in that panels display it updated it in all instances of the display. In this way, #17 may be achieving what it sets out to achieve, but can't be used for my purposes.

I believe the solution in #2, while it looks straight-forward, failed in the same way. The fieldable panels panes were duplicated successfully, but I believe that the cloned node again used the same panels display as the source node, so the source node and cloned node again share the same panels display and when panes are changed on this display they are changed in both instances.

This is a pretty big world to jump into head first but I'm trying to get this code to work. If anyone has any other solutions or thoughts please let me know, otherwise I'm going to continue working in the direction of #2 as it seems to be closest to my end goal.

vood002’s picture

In case anyone stumbles on this conversation I wanted to leave a quick update. #17 does work with a couple of small tweeks mentioned in #19.

The use case of the patch in #17 doesn't apply to me. Essentially I need content authors to have the ability to duplicate an entire panelized page and edit from there. The content authors using the site I'm working on don't have the concept of FPPs as reusable objects as there is no application for that functionality on this project. Thus, the simplest solution for them is to duplicate the node, display, and all of the FPPs on it with a single click.

I make no promises about this below code which I hacked together from #17 and https://www.drupal.org/node/1768746, but it is working for me for this use case, which I have to imagine a lot of people share.

Thanks for the work you put into #17 @valthebald, it looks quite well done to me.

<?php
function mymodule_clone_node($nid){

    // Clone the node.
    $node = node_load($nid);

    $new_node = clone $node;

    // Prepare to save.
    $new_node->nid = NULL;
    $new_node->vid = NULL;
    $new_node->created = NULL;
    $new_node->path = NULL;
    $new_node->files = array();

    // Process the panelizer if there is one attached to this node.
    if ($new_node->panelizer) {

        // Set variables and remove current panelizer, which will give us a new panelizer object.
        $panelizer = $new_node->panelizer;
        $display = $panelizer['page_manager']->display;
        unset($new_node->panelizer);

        // Create a new display to add to the panelizer.
        $code = panels_export_display($display);
        eval($code);

        panels_save_display($display);

        // Save the new node in order to set a new panelizer object.
        entity_save('node', $new_node);

        // Load the new node to get the new panelizer information.
        $new_node = node_load($new_node->nid);

        // Set new values for the new panelizer node.
        $new_node->panelizer['page_manager']->display = $display;
        $new_node->panelizer['page_manager']->new = TRUE;
        $new_node->panelizer['page_manager']->did = $display->did;
        $new_node->panelizer['page_manager']->entity_id = $new_node->nid;
        $new_node->panelizer['page_manager']->entity_type = 'node';

        //Duplicate all of the Fieldable Panels Panes
        foreach($new_node->panelizer['page_manager']->display->content as $pid => &$pane) {

            if($pane->type == "fieldable_panels_pane") {

                // Copy from _fieldable_panels_panes_load_entity().
                list($type, $id) = explode(':', $pane->subtype);
                if ($type == 'uuid' && module_exists('uuid')) {
                    $ids = entity_get_id_by_uuid('fieldable_panels_pane', array($id));
                    if ($content = entity_load('fieldable_panels_pane', $ids)) {
                        $content = reset($content);
                    }
                }

                elseif ($type == 'vid') {
                    $fpid = db_query('SELECT fpid FROM {fieldable_panels_panes_revision} WHERE vid = :vid', array(':vid' => $id))->fetchField();
                    $content = fieldable_panels_panes_load($fpid, $id);
                }

                else {
                    $content = fieldable_panels_panes_load($id);
                }

                if (!$content) {
                    return FALSE;
                }

                // Clone the entity and make sure it will get saved as a new entity.
                $new_pane = clone $content;

                $entity_info = entity_get_info('fieldable_panels_pane');
                $new_pane->{$entity_info['entity keys']['id']} = FALSE;
                if (!empty($entity_info['entity keys']['name'])) {
                    $new_pane->{$entity_info['entity keys']['name']} = FALSE;
                }
                $new_pane->is_new = TRUE;
//                $new_pane->title = '(Clone)' . $new_pane->title;

                // Make sure the status of a cloned exportable is custom.
                if (!empty($entity_info['exportable'])) {
                    $status_key = isset($entity_info['entity keys']['status']) ? $entity_info['entity keys']['status'] : 'status';
                    $new_pane->$status_key = ENTITY_CUSTOM;
                }

                if ($type == 'uuid' && module_exists('uuid')) {
                    $new_pane->vuuid = NULL;
                    $new_pane->uuid = NULL;
                }
                if (!empty($new_pane->vid)) {
                    $new_pane->vid = NULL;
                }

                $new_pane = fieldable_panels_panes_save($new_pane);

                $pane->subtype = $new_pane_subtype = 'fpid:' . $new_pane->fpid;

            }
        }
    }

    // Save the new node.
    entity_save('node', $new_node);
    drupal_set_message("Node " . $node->title . " has been cloned successfully. You are now viewing the cloned node.");
    drupal_goto('node/' . $new_node->nid);

}
?>
DamienMcKenna’s picture

Title:Cloning Fieldable panels panes» Cloning fieldable panels panes via IPE
Category:Support request» Feature request
Status:Needs review» Needs work

Sounds like this needs further work.

roborn’s picture

Status:Needs work» Needs review
FileSize
7.37 KB

Patch on #17 is missing fieldable_panels_panes_pane_shares()
Other than that, is working ok here.

roborn’s picture

FileSize
7.37 KB

I did run into the issue described on #19, where you edit the cloned pane, and it saves to the original pane.
I've set the panels edit cache before calling the ajax_edit_pane(), and it fixes the issue.

DamienMcKenna’s picture

Status:Needs review» Needs work

This needs a little work so that it supports the 'vid:' and 'current:' pane selectors that were added in #1986334: Allow a particular revision of a fieldable panels pane to be placed in a panelized page.

DamienMcKenna’s picture

Also, it might be worth working with #2468263: Copy or clone a fieldable pane so that both approaches use the same logic.