how to best change node type
knugar - May 23, 2006 - 14:47
I've some book nodes that would prefer to convertet to ordinary story nodes. It's important that the nid does not change so I cannot just create a new node with the same content.
I found this by searching the forums:
Of these, the altertype module looks nice. Do any of you have any experiences with this and is there anything more (besides to back up before i play around) I should think about.
After a quick look at the altertype module it seems to leave "dead" rows in the book table when converting a book node to a story node. Is this a problem?

orphaned rows
Once the node type has been changed the orphaned rows in the book table probably won't hurt anything because the node relationship no longer exists. Ideally these should be cleaned up (deleted) though.
list of child pages still exists
I tested the altertype module. After changing node type from book to story the list of child nodes is still rendered at the bottom of the page. After I manually delete all related rows in the book table it goes away.
I have no idea why this is the case. A little strange that the list is output even if node.type == 'story'. The test to produce the list or not seems to look in the book table for related rows independent of the node.type.
I will try to add some book table clean-up to the altertype module.
an attempt to improve the altertype module
After playing around with the altertype module I decided to add support for:
I simply delete or insert a row into the book table when necessary. I'm not a regular PHP or Drupal coder, so feel free to comment/improve.
<?php
// $Id: altertype.module,v 1.2 2005/04/20 15:49:51 kevin Exp $
function altertype_help($section) {
switch ($section) {
case 'admin/modules#description':
return t("Allows editors to change a node's type.");
}
}
function _altertype_get_node_type($node) {
if ($node->nid) {
// The node already exist in the data base.
$sql = "SELECT type from node WHERE nid=$node->nid";
$result = db_query($sql);
$obj = db_fetch_object($result);
return $obj->type;
} else {
// A new node is born.
return $node->type;
}
}
function altertype_nodeapi(&$node, $op, $arg) {
switch ($op) {
case 'form post':
// The node form was just displayed. This hook can be used to
// add fields at the bottom of the form.
if (user_access('administer nodes')) {
$options = array();
foreach (node_list() as $type) {
$n = new StdClass();
$n->type = $type;
$options[$type] = node_invoke($n, 'node_name');
}
$output = form_select(t('Node type'), 'altertype', $node->type,
$options, t("<p>Since different node types have different properties, it is not"
. " usually a good idea to change the type of a published node.</p>",
NULL, FALSE, FALSE));
}
break;
case 'validate':
// The user has just finished editing the node and is trying to
// preview or submit it. This hook can be used to check or even
// modify the node. Errors should be set with form_set_error().
if ($node->altertype != NULL
&& $node->altertype != $node->type
&& user_access('administer nodes')) {
// Added by Karl
$old_type = _altertype_get_node_type($node);
$msg = "<B>WARNING:</b> By submitting, you change the node type from "
. "<b>$old_type</b> to <b>$node->altertype</b>.<br/>";
if ($old_type == 'book' and $node->altertype !='book'){
$msg .= "<br/>Some information about relations bewteen book pages etc may be lost."
. " Procede at your own risk.";
}
$node->type = $node->altertype; // Orignal node type change by kevin
}
break;
case 'fields':
// Added by Karl
// The node is being saved to the database. This hook can be used
// to declare that additional fields of information should be
// saved to the node table.
// Simply changing the $node->type does not suffice if the
// previous node type was book. After changing node type from book
// to for example story, the list of child nodes is still rendered
// at the bottom of the page. After deleting the related
// rows in the book table it goes away.
// See discussion at <a href="http://drupal.org/node/65118
" title="http://drupal.org/node/65118
" rel="nofollow">http://drupal.org/node/65118
</a> $old_type = _altertype_get_node_type($node);
if ($old_type == 'book' and $node->type !='book'){
// Must clean up the book table
$msg = "The node type is beeing changed from a book page to a $node->type<br/><br/>";
book_delete($node);
$msg .= db_affected_rows() . " row(s) deleted from the book table.<br/>";
} else if ($old_type != 'book' and $node->type == 'book') {
// Must create a book entry.
$msg = "The node type is beeing changed from a $node->type to a book page<br/><br/>";
book_insert($node);
$msg .= db_affected_rows() . " row(s) insertet into the book table.<br/>";
$msg .= "<br/><br/><b>NOTE:</b> this is a simple attempt to "upgrade\" to a book page."
. " You have to re-edit the node to set parent and weight.";
}
break;
}
drupal_set_message($msg); // Added by Karl
return $output;
}
?>
graceful node conversion
Without commenting on your code changes specifically, your notion of graceful node conversion is a good one. Addressing the most common node types is a good place to start.
for D5 and D6 users
For anyone using newer Drupal version, who stumbles upon this thread, there's a module Nodetype:
http://drupal.org/project/nodetype
Just keep in mind, it only changes the type so if the new type has different structure or lacks some field etc., there may be consequences...