| 1 |
<?php
|
| 2 |
|
| 3 |
// $Id: nodetemplate.module,v 1.3.2.3 2007/06/26 08:20:18 motou Exp $
|
| 4 |
|
| 5 |
/**
|
| 6 |
* Implementation of hook_help().
|
| 7 |
*/
|
| 8 |
function nodetemplate_help($section) {
|
| 9 |
switch ($section) {
|
| 10 |
case 'admin/help#nodetemplate':
|
| 11 |
$output = '<p>'. t('The node template module allows users to make any existing node and use it as a template. The authorship is set to the current user, the menu and url aliases are reset, and the words "Clone of" are inserted into the title to remind you that you are not editing the original node.') .'</p>';
|
| 12 |
$output .= '<p>'. t('Users with the "node template" permission can utilize this functionality. A tab named "set template" will appear on every editable pages. Once you click this tab you have <em>already</em> created a new node that is a copy of the node you were viewing, and you will be redirected to an edit screen for that new node.') .'</p>';
|
| 13 |
return $output;
|
| 14 |
case 'admin/modules#description':
|
| 15 |
return t('Allows users to duplicate an existing node and set it as a template.');
|
| 16 |
}
|
| 17 |
}
|
| 18 |
|
| 19 |
/**
|
| 20 |
* Implementation of hook_perm().
|
| 21 |
*/
|
| 22 |
function nodetemplate_perm() {
|
| 23 |
return array('access node template');
|
| 24 |
}
|
| 25 |
|
| 26 |
/**
|
| 27 |
* Implementation of hook_menu().
|
| 28 |
*/
|
| 29 |
function nodetemplate_menu($may_cache) {
|
| 30 |
$items = array();
|
| 31 |
|
| 32 |
if (!$may_cache) {
|
| 33 |
if (arg(0) == 'node' && is_numeric(arg(1))){
|
| 34 |
$node=node_load(arg(1));
|
| 35 |
if ($node->nid) {
|
| 36 |
$access = (user_access('access node template') && filter_access($node->format) && node_access('create',$node->type));
|
| 37 |
$items[] = array('path' => 'node/'. $node->nid.'/template',
|
| 38 |
'title' => t('set template'),
|
| 39 |
'callback' => 'nodetemplate_confirm',
|
| 40 |
'access' => $access,
|
| 41 |
'type' => MENU_LOCAL_TASK,
|
| 42 |
'weight' => 5);
|
| 43 |
}
|
| 44 |
}
|
| 45 |
}
|
| 46 |
|
| 47 |
if ($may_cache) {
|
| 48 |
$access = user_access('access node template');
|
| 49 |
|
| 50 |
$items[] = array(
|
| 51 |
'path' => 'nodetemplate',
|
| 52 |
'title' => t('my node templates'),
|
| 53 |
'callback' => 'nodetemplate_admin',
|
| 54 |
'access' => $access);
|
| 55 |
|
| 56 |
$items[] = array(
|
| 57 |
'path' => 'nodetemplate/list',
|
| 58 |
'title' => t('list'),
|
| 59 |
'type' => MENU_DEFAULT_LOCAL_TASK,
|
| 60 |
'weight' => -10);
|
| 61 |
|
| 62 |
$items[] = array(
|
| 63 |
'path' => 'nodetemplate/configure',
|
| 64 |
'title' => t('configure'),
|
| 65 |
'callback' => 'nodetemplate_configure',
|
| 66 |
'access' => user_access('access node template'),
|
| 67 |
'type' => MENU_LOCAL_TASK);
|
| 68 |
|
| 69 |
$items[] = array(
|
| 70 |
'path' => 'nodetemplate/delete',
|
| 71 |
'title' => t('delete'),
|
| 72 |
'callback' => 'nodetemplate_delete',
|
| 73 |
'type' => MENU_CALLBACK);
|
| 74 |
|
| 75 |
}
|
| 76 |
return $items;
|
| 77 |
}
|
| 78 |
|
| 79 |
/**
|
| 80 |
* Implementation of hook_settings().
|
| 81 |
*/
|
| 82 |
function nodetemplate_settings() {
|
| 83 |
|
| 84 |
$form['heading'] = array(
|
| 85 |
'#value' => '<b>'.t('Configuration options for the node template module:').'</b>',
|
| 86 |
);
|
| 87 |
|
| 88 |
$form['node_template_without_confirm'] = array(
|
| 89 |
'#type' => 'checkbox',
|
| 90 |
'#title' => t('Set template needs no confirmation'),
|
| 91 |
'#default_value' => variable_get('node_template_without_confirm', FALSE),
|
| 92 |
'#description' => t('If this is set, a new node will be created immediately after clicking the "set template" tab when viewing a node.'),
|
| 93 |
);
|
| 94 |
|
| 95 |
$form['node_template_without_clone'] = array(
|
| 96 |
'#type' => 'checkbox',
|
| 97 |
'#title' => t('Set template but without duplicating the node'),
|
| 98 |
'#default_value' => variable_get('node_template_without_clone', TRUE),
|
| 99 |
'#description' => t('If this is set, a new node will be created immediately after clicking the "set template" tab when viewing a node.'),
|
| 100 |
);
|
| 101 |
|
| 102 |
$form['node_template_with_child'] = array(
|
| 103 |
'#type' => 'checkbox',
|
| 104 |
'#title' => t('Book pages should be duplicated with all the children'),
|
| 105 |
'#default_value' => variable_get('node_template_with_child', FALSE),
|
| 106 |
'#description' => t('If this is set, a new book page with all the children will be created after clicking the "set template" tab when viewing a node.'),
|
| 107 |
);
|
| 108 |
|
| 109 |
$form['publishing'] = array(
|
| 110 |
'#type' => 'fieldset',
|
| 111 |
'#title' => '<b>'.t('Should the publishing options ( e.g. published, promoted, etc) be reset to the defaults?').'</b>',
|
| 112 |
);
|
| 113 |
|
| 114 |
foreach (node_get_types() as $type => $name) {
|
| 115 |
$form['publishing']['clone_reset_'. $type] = array(
|
| 116 |
'#type' => 'checkbox',
|
| 117 |
'#title' => t('%s: reset publishing options when cloned', array('%s' => $name)),
|
| 118 |
'#default_value' => variable_get('clone_reset_'. $type, FALSE),
|
| 119 |
);
|
| 120 |
}
|
| 121 |
|
| 122 |
return $form;
|
| 123 |
}
|
| 124 |
|
| 125 |
/**
|
| 126 |
* Menu callback: prompt the user to confirm the operation
|
| 127 |
*/
|
| 128 |
function nodetemplate_confirm() {
|
| 129 |
|
| 130 |
if (variable_get('node_template_without_confirm', FALSE)) {
|
| 131 |
if (variable_get('node_template_without_clone', TRUE)) {
|
| 132 |
$nid = $form_values['nid'];
|
| 133 |
$existed_node = db_num_rows(db_query('SELECT * FROM {node_template} WHERE nid = %d', $nid));
|
| 134 |
if ($existed_node > 0) {
|
| 135 |
db_query('UPDATE {node_template} SET is_template = 1 WHERE nid = %d', $nid);
|
| 136 |
}
|
| 137 |
else {
|
| 138 |
db_query("INSERT INTO {node_template} (nid, is_template) VALUES (%d, %d)", $nid, 1);
|
| 139 |
}
|
| 140 |
drupal_goto('node/'.$nid);
|
| 141 |
}
|
| 142 |
else {
|
| 143 |
duplicate_node($form_values['nid']);
|
| 144 |
}
|
| 145 |
}
|
| 146 |
else {
|
| 147 |
$node = node_load(arg(1));
|
| 148 |
$description = (variable_get('node_template_without_clone', TRUE))?
|
| 149 |
t('This action will set the current node as template without duplicating it now, and then you can duplicate the node later.'):
|
| 150 |
t('This action will create a new node or a set of book pages, and then you will be redirected to editing the new node.');
|
| 151 |
$form['nid'] = array('#type' => 'value', '#value' => $node->nid);
|
| 152 |
$output = confirm_form('nodetemplate_confirm', $form,
|
| 153 |
t('Do you really want to set %title as a template?', array('%title' => theme('placeholder', $node->title))),
|
| 154 |
'node/'. $node->nid,'<p>'.$description. '</p>',
|
| 155 |
t('Next'), t('Cancel'));
|
| 156 |
|
| 157 |
return $output;
|
| 158 |
}
|
| 159 |
}
|
| 160 |
|
| 161 |
/**
|
| 162 |
* Handle confirm form submission
|
| 163 |
*/
|
| 164 |
function nodetemplate_confirm_submit($form_id, $form_values) {
|
| 165 |
if ($form_values['confirm']) {
|
| 166 |
if (variable_get('node_template_without_clone', TRUE)) {
|
| 167 |
$nid = $form_values['nid'];
|
| 168 |
$existed_node = db_num_rows(db_query('SELECT * FROM {node_template} WHERE nid = %d', $nid));
|
| 169 |
if ($existed_node > 0) {
|
| 170 |
db_query('UPDATE {node_template} SET is_template = 1 WHERE nid = %d', $nid);
|
| 171 |
}
|
| 172 |
else {
|
| 173 |
db_query("INSERT INTO {node_template} (nid, is_template) VALUES (%d, %d)", $nid, 1);
|
| 174 |
}
|
| 175 |
drupal_goto('node/'.$nid);
|
| 176 |
}
|
| 177 |
else {
|
| 178 |
duplicate_node($form_values['nid']);
|
| 179 |
}
|
| 180 |
}
|
| 181 |
return '';
|
| 182 |
}
|
| 183 |
|
| 184 |
/**
|
| 185 |
* Clones a node
|
| 186 |
*/
|
| 187 |
function duplicate_node($nid) {
|
| 188 |
if (is_numeric($nid)) {
|
| 189 |
global $user;
|
| 190 |
|
| 191 |
$existed_node = db_num_rows(db_query('SELECT * FROM {node_template} WHERE nid = %d', $nid));
|
| 192 |
if ($existed_node > 0) {
|
| 193 |
db_query('UPDATE {node_template} SET is_template = 1 WHERE nid = %d', $nid);
|
| 194 |
} else {
|
| 195 |
db_query("INSERT INTO {node_template} (nid, is_template) VALUES (%d, %d)", $nid, 1);
|
| 196 |
}
|
| 197 |
|
| 198 |
$parents = array();
|
| 199 |
$oldnode = node_load($nid);
|
| 200 |
|
| 201 |
if ($oldnode->type == "book") {
|
| 202 |
$pages = array();
|
| 203 |
$pages = book_tree_travel($nid,$pages,true);
|
| 204 |
//print_r($pages);
|
| 205 |
$first_time = true;
|
| 206 |
if (count($pages)>0 && variable_get('node_template_with_child', TRUE)) {
|
| 207 |
foreach ($pages as $ori_node){
|
| 208 |
$node = node_load($ori_node->nid,NULL,TRUE);
|
| 209 |
//watchdog('content', t('node_duplicate: duplicating %subject.', array('%subject' => theme('placeholder', $ori_node->nid))), WATCHDOG_WARNING);
|
| 210 |
if (isset($node->nid)) {
|
| 211 |
|
| 212 |
$node->nid = NULL;
|
| 213 |
$node->uid = $user->uid;
|
| 214 |
$node->created = 0;
|
| 215 |
$node->menu = NULL;
|
| 216 |
$node->path = NULL;
|
| 217 |
|
| 218 |
if ($first_time) {
|
| 219 |
$node->title = t('Clone of %title', array('%title' => $node->title));
|
| 220 |
$first_time = false;
|
| 221 |
}
|
| 222 |
|
| 223 |
if (variable_get('clone_reset_'. $node->type, FALSE)) {
|
| 224 |
$node_options = variable_get('node_options_'. $node->type, array('status', 'promote'));
|
| 225 |
// fill in the default values
|
| 226 |
foreach (array('status', 'moderate', 'promote', 'sticky', 'revision') as $key) {
|
| 227 |
$node->$key = in_array($key, $node_options);
|
| 228 |
}
|
| 229 |
}
|
| 230 |
node_save($node);
|
| 231 |
$parents[$ori_node->nid] = $node->nid;
|
| 232 |
}
|
| 233 |
}
|
| 234 |
reset($parents);
|
| 235 |
foreach ($parents as $old_node_id => $node_id){
|
| 236 |
//watchdog('content', t('node_duplicate: updating %subject.', array('%subject' => theme('placeholder', $node_id))), WATCHDOG_WARNING);
|
| 237 |
$newnode = node_load($node_id,NULL,TRUE);
|
| 238 |
if (array_key_exists($newnode->parent, $parents)){
|
| 239 |
$newnode->parent = $parents[$newnode->parent];
|
| 240 |
book_update($newnode);
|
| 241 |
}
|
| 242 |
}
|
| 243 |
}
|
| 244 |
|
| 245 |
reset($parents);
|
| 246 |
drupal_goto('node/'. current($parents).'/edit');
|
| 247 |
|
| 248 |
}
|
| 249 |
else {
|
| 250 |
|
| 251 |
if (isset($oldnode->nid)) {
|
| 252 |
$oldnode->nid = NULL;
|
| 253 |
$oldnode->uid = $user->uid;
|
| 254 |
$oldnode->created = 0;
|
| 255 |
$oldnode->menu = NULL;
|
| 256 |
$oldnode->path = NULL;
|
| 257 |
$oldnode->title = t('Clone of %title', array('%title' => $oldnode->title));
|
| 258 |
|
| 259 |
if (variable_get('clone_reset_'. $oldnode->type, FALSE)) {
|
| 260 |
$node_options = variable_get('node_options_'. $oldnode->type, array('status', 'promote'));
|
| 261 |
// fill in the default values
|
| 262 |
foreach (array('status', 'moderate', 'promote', 'sticky', 'revision') as $key) {
|
| 263 |
$oldnode->$key = in_array($key, $node_options);
|
| 264 |
}
|
| 265 |
}
|
| 266 |
node_save($oldnode);
|
| 267 |
drupal_goto('node/'. $oldnode->nid.'/edit');
|
| 268 |
}
|
| 269 |
}
|
| 270 |
}
|
| 271 |
}
|
| 272 |
|
| 273 |
/**
|
| 274 |
* find all the children of a book node
|
| 275 |
*/
|
| 276 |
function book_tree_travel($nid, $pages = array(), $include_father = false) {
|
| 277 |
if ($include_father) {
|
| 278 |
$result = db_query(db_rewrite_sql('SELECT n.nid FROM {node} n WHERE n.nid = %d AND n.moderate = 0'), $nid);
|
| 279 |
while ($page = db_fetch_object($result)) {
|
| 280 |
$pages[] = $page;
|
| 281 |
}
|
| 282 |
}
|
| 283 |
|
| 284 |
$children = db_query(db_rewrite_sql('SELECT n.nid FROM {node} n INNER JOIN {book} b ON n.vid = b.vid WHERE n.status = 1 AND b.parent = %d AND n.moderate = 0'), $nid);
|
| 285 |
while ($childpage = db_fetch_object($children)) {
|
| 286 |
$pages[] = $childpage;
|
| 287 |
$pages = book_tree_travel($childpage->nid, $pages);
|
| 288 |
}
|
| 289 |
|
| 290 |
return $pages;
|
| 291 |
}
|
| 292 |
|
| 293 |
/********************************************************************
|
| 294 |
* Module Functions :: Controllers
|
| 295 |
********************************************************************/
|
| 296 |
|
| 297 |
function nodetemplate_admin() {
|
| 298 |
global $user;
|
| 299 |
|
| 300 |
$title = t('Node template') . ' : ' . $user->name;
|
| 301 |
drupal_set_title($title);
|
| 302 |
$output = nodetemplate_list();
|
| 303 |
return $output;
|
| 304 |
}
|
| 305 |
|
| 306 |
/**
|
| 307 |
* The configuration page.
|
| 308 |
*/
|
| 309 |
function nodetemplate_configure() {
|
| 310 |
global $user;
|
| 311 |
$form = array();
|
| 312 |
$form['maxnodes'] = array(
|
| 313 |
'#type' => 'textfield',
|
| 314 |
'#title' => t('Number of items'),
|
| 315 |
'#description' => t('Maximum number of items to display.'),
|
| 316 |
'#default_value' => $user->nodetemplate ? $user->nodetemplate['default']['maxnodes'] : 50,
|
| 317 |
'#size' => 4
|
| 318 |
);
|
| 319 |
|
| 320 |
$form['submit'] = array(
|
| 321 |
'#type' => 'submit',
|
| 322 |
'#value' => t('Save configuration')
|
| 323 |
);
|
| 324 |
$output = drupal_get_form('nodetemplate_configure', $form);
|
| 325 |
drupal_set_title(t('Node template : %username', array('%username' => $user->name)));
|
| 326 |
return $output;
|
| 327 |
}
|
| 328 |
|
| 329 |
function nodetemplate_configure_validate($form_id, $edit) {
|
| 330 |
if (!is_numeric($edit['maxnodes'])) {
|
| 331 |
form_set_error('maxnodes', t('Please enter a numeric value.'));
|
| 332 |
}
|
| 333 |
}
|
| 334 |
|
| 335 |
function nodetemplate_configure_submit($form_id, $edit) {
|
| 336 |
global $user;
|
| 337 |
if (!isset($user->nodetemplate)) {
|
| 338 |
$user->nodetemplate = array();
|
| 339 |
}
|
| 340 |
$user->nodetemplate['default']['maxnodes'] = $edit['maxnodes'];
|
| 341 |
|
| 342 |
user_save($user, array('nodetemplate' => $user->nodetemplate));
|
| 343 |
drupal_set_message(t('The node template configuration has been saved.'));
|
| 344 |
return 'nodetemplate';
|
| 345 |
}
|
| 346 |
|
| 347 |
/********************************************************************
|
| 348 |
* Module Functions :: Views
|
| 349 |
********************************************************************/
|
| 350 |
|
| 351 |
/**
|
| 352 |
* The default admin interface is a list of content.
|
| 353 |
*/
|
| 354 |
function nodetemplate_list() {
|
| 355 |
global $user;
|
| 356 |
$maxnodes = isset($user->nodetemplate) ? $user->nodetemplate['default']['maxnodes'] : 50;
|
| 357 |
|
| 358 |
if (!is_numeric($maxnodes)) {$maxnodes = 50;}
|
| 359 |
|
| 360 |
|
| 361 |
$node_select = array('n.nid', 'n.uid', 'n.type', '0 AS cid', 'n.title', 'n.status', 'n.changed', '1 AS node');
|
| 362 |
$node_from = array('{node} n');
|
| 363 |
$node_join = array('INNER JOIN {node_template} s ON n.nid = s.nid');
|
| 364 |
$node_where = array('s.is_template = 1');
|
| 365 |
|
| 366 |
$sql = 'SELECT '. implode(', ', $node_select) .' FROM '. implode(', ', $node_from) .' '. implode(' ', $node_join) .' WHERE '. implode(' ', $node_where);
|
| 367 |
$count_sql = 'SELECT COUNT(n.nid) FROM '. implode(', ', $node_from) .' '. implode(' ', $node_join) .' WHERE '. implode(' ', $node_where);
|
| 368 |
|
| 369 |
// build the combined template listing
|
| 370 |
$header = array(
|
| 371 |
array('data' => t('Type'), 'field' => 'type'),
|
| 372 |
array('data' => t('Title'), 'field' => 'title'),
|
| 373 |
array('data' => t('Owner'), 'field' => 'uid'),
|
| 374 |
array('data' => t('Published'), 'field' => 'status'),
|
| 375 |
array('data' => t('Modified'), 'field' => 'changed', 'sort' => 'desc'),
|
| 376 |
array('data' => t('Operations'), 'colspan' => 2)
|
| 377 |
);
|
| 378 |
|
| 379 |
$result = pager_query($sql . tablesort_sql($header), $maxnodes, 0, $count_sql);
|
| 380 |
$yes = t('yes');
|
| 381 |
$no = t('no');
|
| 382 |
|
| 383 |
while ($row = db_fetch_object($result)) {
|
| 384 |
// it's a node
|
| 385 |
if ($row->node == 1) {
|
| 386 |
// Duplicate permissions are set by the nodetype's access hook.
|
| 387 |
// This approach is part of Drupal's core design.
|
| 388 |
$can_duplicate = FALSE;
|
| 389 |
|
| 390 |
//Check the nodetype's access hook.
|
| 391 |
$function = $row->type. '_access';
|
| 392 |
if ($flexinode_enabled && strstr($function, 'flexinode-')) {
|
| 393 |
$function = 'flexinode_access';
|
| 394 |
}
|
| 395 |
elseif ($cck_enabled && strstr($function, 'content_')) {
|
| 396 |
$function = 'content_access';
|
| 397 |
}
|
| 398 |
|
| 399 |
if (function_exists($function)) {
|
| 400 |
$can_duplicate = $function('update', $row) ? TRUE : FALSE;
|
| 401 |
}
|
| 402 |
|
| 403 |
// the name of the owner of this node
|
| 404 |
$name = ($user->uid == $row->uid) ? $user->name : db_result(db_query('SELECT name FROM {users} WHERE uid = %d', $row->uid));
|
| 405 |
$rows[] = array(
|
| 406 |
node_get_name($row->type),
|
| 407 |
l($row->title, "node/$row->nid"),
|
| 408 |
$name,
|
| 409 |
$row->status ? $yes : $no,
|
| 410 |
format_date($row->changed, 'small'),
|
| 411 |
$can_duplicate ? l(t('duplicate'), "node/$row->nid/template") : '',
|
| 412 |
l(t('delete'), "nodetemplate/delete/$row->nid")
|
| 413 |
);
|
| 414 |
}
|
| 415 |
}
|
| 416 |
|
| 417 |
if ($rows) {
|
| 418 |
$pager = theme('pager', NULL, $maxnodes, 0);
|
| 419 |
if (!empty($pager)) {
|
| 420 |
$rows[] = array(array('data' => $pager, 'colspan' => 8));
|
| 421 |
}
|
| 422 |
$output .= theme('table', $header, $rows);
|
| 423 |
}
|
| 424 |
else {
|
| 425 |
$output .= t('You have no node template yet.');
|
| 426 |
}
|
| 427 |
|
| 428 |
return $output;
|
| 429 |
}
|
| 430 |
|
| 431 |
/**
|
| 432 |
* The deletion menu callback
|
| 433 |
*/
|
| 434 |
function nodetemplate_delete() {
|
| 435 |
$nid = intval(arg(2));
|
| 436 |
if (is_numeric($nid)) {
|
| 437 |
db_query('DELETE FROM {node_template} WHERE nid = %d', $nid);
|
| 438 |
}
|
| 439 |
drupal_goto('nodetemplate');
|
| 440 |
}
|