| 1 |
<?php
|
| 2 |
// $Id: taxonomynode.module,v 1.1.2.6 2008/11/06 18:38:11 hanoii Exp $
|
| 3 |
|
| 4 |
define ('TAXONOMYNODE_SETTINGS_NODE_OPERATIONS', variable_get('taxonomynode_node_operations', FALSE));
|
| 5 |
|
| 6 |
/**
|
| 7 |
* Toggle the state of a global variable that's used in hook_taxonomy and hook_nodeapi
|
| 8 |
*
|
| 9 |
* @param boolean $state
|
| 10 |
*/
|
| 11 |
function _taxonomynode_toggle($state = null) {
|
| 12 |
global $taxonomynode;
|
| 13 |
if (!is_null($state)) {
|
| 14 |
$taxonomynode = $state;
|
| 15 |
}
|
| 16 |
else {
|
| 17 |
$taxonomynode = $taxonomynode ? FALSE : TRUE;
|
| 18 |
}
|
| 19 |
}
|
| 20 |
|
| 21 |
/**
|
| 22 |
* Query the database and obtain the nid associated to a tid.
|
| 23 |
*
|
| 24 |
* @param integer $tid
|
| 25 |
* term id
|
| 26 |
* @return integer
|
| 27 |
* node id
|
| 28 |
*/
|
| 29 |
function _taxonomynode_get_nid_from_tid($tid) {
|
| 30 |
$nid = db_result(db_query("SELECT nid FROM {taxonomynode} tn WHERE tn.tid = %d", $tid));
|
| 31 |
return $nid;
|
| 32 |
}
|
| 33 |
|
| 34 |
/**
|
| 35 |
* Query the database and obtain the tid associated to a nid.
|
| 36 |
*
|
| 37 |
* @param integer $nid
|
| 38 |
* node id
|
| 39 |
* @return integer
|
| 40 |
* term id
|
| 41 |
*/
|
| 42 |
function _taxonomynode_get_tid_from_nid($nid) {
|
| 43 |
$tid = db_result(db_query("SELECT tid FROM {taxonomynode} tn WHERE tn.nid = %d", $nid));
|
| 44 |
return $tid;
|
| 45 |
}
|
| 46 |
|
| 47 |
/**
|
| 48 |
* From a node object, find out if there are vocabularies associated to that
|
| 49 |
* speicfic content type
|
| 50 |
*
|
| 51 |
* @param object $node
|
| 52 |
* @return array
|
| 53 |
* Array of vocabularies ID, empty array if none
|
| 54 |
*/
|
| 55 |
function _taxonomynode_node_get_vids($node) {
|
| 56 |
$vocabs = array();
|
| 57 |
|
| 58 |
// find if node is mapped to some vocabulary
|
| 59 |
$vocabularies = taxonomy_get_vocabularies();
|
| 60 |
foreach ($vocabularies as $vocab) {
|
| 61 |
$taxonomynode_settings = variable_get("taxonomynode_{$vocab->vid}", array());
|
| 62 |
if ($taxonomynode_settings['content_type'] == $node->type) {
|
| 63 |
$vocabs[] = $vocab->vid;
|
| 64 |
}
|
| 65 |
}
|
| 66 |
|
| 67 |
return $vocabs;
|
| 68 |
}
|
| 69 |
|
| 70 |
function _taxonomynode_create_term($node) {
|
| 71 |
$terms = array();
|
| 72 |
// find if node is mapped to some vocabulary
|
| 73 |
foreach (_taxonomynode_node_get_vids($node) as $vid) {
|
| 74 |
$taxonomynode_settings = variable_get("taxonomynode_{$vid}", array());
|
| 75 |
if ($taxonomynode_settings['content_type'] == $node->type) {
|
| 76 |
$term['vid'] = $vid;
|
| 77 |
$term['name'] = $node->title;
|
| 78 |
// parents
|
| 79 |
$parents = array_keys(taxonomy_node_get_terms_by_vocabulary($node->nid, $vid));
|
| 80 |
$term['parent'] = $parents;
|
| 81 |
taxonomy_save_term($term);
|
| 82 |
$terms[] = $term;
|
| 83 |
|
| 84 |
db_query("INSERT INTO {taxonomynode} (tid, vid, nid) VALUES (%d, %d, %d)", $term['tid'], $vid, $node->nid);
|
| 85 |
}
|
| 86 |
}
|
| 87 |
|
| 88 |
return $terms;
|
| 89 |
}
|
| 90 |
|
| 91 |
function _taxonomynode_create_node($tid, $vid, $term_name, $parents) {
|
| 92 |
$taxonomynode_settings = variable_get("taxonomynode_{$vid}", array());
|
| 93 |
if ($taxonomynode_settings['content_type']) {
|
| 94 |
$nid = _taxonomynode_get_nid_from_tid($tid);
|
| 95 |
if ($nid) {
|
| 96 |
$node = node_load($nid);
|
| 97 |
}
|
| 98 |
else {
|
| 99 |
$node = new stdClass();
|
| 100 |
$node->type = $taxonomynode_settings['content_type'];
|
| 101 |
node_object_prepare($node);
|
| 102 |
$node_options = variable_get('node_options_'. $node->type, array('status', 'promote'));
|
| 103 |
foreach (array('status', 'promote', 'sticky') as $key) {
|
| 104 |
$node->$key = in_array($key, $node_options);
|
| 105 |
}
|
| 106 |
global $user;
|
| 107 |
$node->uid = $user->uid;
|
| 108 |
// Always use the default revision setting.
|
| 109 |
$node->revision = in_array('revision', $node_options);
|
| 110 |
}
|
| 111 |
$node->title = $term_name;
|
| 112 |
$node->taxonomy = array();
|
| 113 |
if (is_numeric($parents)) {
|
| 114 |
$parents = array($parents);
|
| 115 |
}
|
| 116 |
foreach ($parents as $pid) {
|
| 117 |
$node->taxonomy[] = $pid;
|
| 118 |
}
|
| 119 |
node_save($node);
|
| 120 |
|
| 121 |
if (!$nid) {
|
| 122 |
db_query("INSERT INTO {taxonomynode} (tid, vid, nid) VALUES (%d, %d, %d)", $tid, $vid, $node->nid);
|
| 123 |
}
|
| 124 |
}
|
| 125 |
|
| 126 |
return $node;
|
| 127 |
}
|
| 128 |
|
| 129 |
/**
|
| 130 |
* Drupal hooks
|
| 131 |
*/
|
| 132 |
/**
|
| 133 |
* Implementation of hook_menu
|
| 134 |
*
|
| 135 |
* @param unknown_type $may_cache
|
| 136 |
*/
|
| 137 |
function taxonomynode_menu($may_cache) {
|
| 138 |
$items = array();
|
| 139 |
|
| 140 |
if ($may_cache) {
|
| 141 |
$items[]= array (
|
| 142 |
'path' => 'admin/settings/taxonomynode',
|
| 143 |
'title' => 'Taxonomy Node',
|
| 144 |
'callback' => 'drupal_get_form',
|
| 145 |
'callback arguments' => array('taxonomynode_settings'),
|
| 146 |
'access' => user_access('administer taxonomy'),
|
| 147 |
);
|
| 148 |
}
|
| 149 |
else {
|
| 150 |
if (arg(0) == 'admin' && arg(1) == 'content' && arg(2) == 'taxonomy' && arg(3) == 'edit' && arg(4) == 'term') {
|
| 151 |
$items[]= array(
|
| 152 |
'path' => 'admin/content/taxonomy/edit/term/'. arg(5) .'/taxonomynode/create',
|
| 153 |
'callback' => 'taxonomynode_create',
|
| 154 |
'callback arguments' => array(arg(5)),
|
| 155 |
'type' => MENU_CALLBACK,
|
| 156 |
);
|
| 157 |
}
|
| 158 |
}
|
| 159 |
|
| 160 |
return $items;
|
| 161 |
}
|
| 162 |
|
| 163 |
/**
|
| 164 |
* Implementation of hook_form_alter
|
| 165 |
*
|
| 166 |
* @param unknown_type $form_id
|
| 167 |
* @param unknown_type $form
|
| 168 |
*/
|
| 169 |
function taxonomynode_form_alter($form_id, &$form) {
|
| 170 |
if ($form_id == 'taxonomy_form_vocabulary') {
|
| 171 |
$form['taxonomynode'] = array(
|
| 172 |
'#type' => 'fieldset',
|
| 173 |
'#title' => t('Taxonomy Node'),
|
| 174 |
'#weight' => 0,
|
| 175 |
);
|
| 176 |
$options = array();
|
| 177 |
$options[''] = t('None');
|
| 178 |
$types = content_types();
|
| 179 |
foreach ($types as $type) {
|
| 180 |
$options[$type['type']] = $type['name'];
|
| 181 |
}
|
| 182 |
|
| 183 |
$vid = $form['vid']['#value'];
|
| 184 |
if ($vid) {
|
| 185 |
$taxonomynode_settings = variable_get("taxonomynode_{$vid}", array());
|
| 186 |
}
|
| 187 |
$form['taxonomynode']['taxonomynode_content_type'] = array(
|
| 188 |
'#type' => 'select',
|
| 189 |
'#title' => t('Content type'),
|
| 190 |
'#options' => $options,
|
| 191 |
'#default_value' => $taxonomynode_settings['content_type'],
|
| 192 |
'#description' => t('Choose the content type that will be created when adding new terms. <b>Important note:</b> If you change your content type selection once nodes have been created, you will have to manually remove the already created nodes for each of the terms of this vocabulary as well as unset the old content type from the <i>Types</i> associated to this vocabulary.')
|
| 193 |
);
|
| 194 |
$form['taxonomynode']['taxonomynode_batch'] = array(
|
| 195 |
'#type' => 'checkbox',
|
| 196 |
'#title' => t('Batch create'),
|
| 197 |
'#description' => t('Select this checkbox if you want to create content types of the current terms inside this vocabulary. <b>There is a limit of 50 nodes to prevent the script from timeout. If you have more than 50 terms you will have to edit and check this box until you get a "0" nodes created message.</b>'),
|
| 198 |
);
|
| 199 |
}
|
| 200 |
|
| 201 |
if ($form_id == 'taxonomy_form_term') {
|
| 202 |
$tid = $form['tid']['#value'];
|
| 203 |
$vid = $form['vid']['#value'];
|
| 204 |
|
| 205 |
$taxonomynode_settings = variable_get("taxonomynode_{$vid}", array());
|
| 206 |
if ($taxonomynode_settings['content_type'] && $tid) {
|
| 207 |
$nid = db_result(db_query("SELECT nid FROM {taxonomynode} tn WHERE tn.tid = %d", $tid));
|
| 208 |
|
| 209 |
$form['taxonomynode'] = array(
|
| 210 |
'#type' => 'fieldset',
|
| 211 |
'#title' => t('Taxonomy Node'),
|
| 212 |
'#weight' => -20,
|
| 213 |
);
|
| 214 |
if ($nid) {
|
| 215 |
$form['taxonomynode']['taxonomynode_node'] = array(
|
| 216 |
'#type' => 'markup',
|
| 217 |
'#value' => t('You can edit the associated node !node as well.', array('!node' => l($form['name']['#default_value'], 'node/'. $nid .'/edit'))),
|
| 218 |
);
|
| 219 |
}
|
| 220 |
else {
|
| 221 |
$form['taxonomynode']['taxonomynode_node'] = array(
|
| 222 |
'#type' => 'markup',
|
| 223 |
'#value' => t('There is no associated node available for this term. !link.', array('!link' => l(t('Create it'), 'admin/content/taxonomy/edit/term/'. $tid .'/taxonomynode/create'))),
|
| 224 |
);
|
| 225 |
}
|
| 226 |
}
|
| 227 |
}
|
| 228 |
|
| 229 |
if (substr($form_id, -10) == '_node_form') {
|
| 230 |
$nid = $form['nid']['#value'];
|
| 231 |
// find vid in module table
|
| 232 |
if ($nid) {
|
| 233 |
$row = db_fetch_object(db_query("SELECT * FROM {taxonomynode} tn WHERE tn.nid = %d", $nid));
|
| 234 |
$vid = $row->vid;
|
| 235 |
if ($vid) {
|
| 236 |
$vocab = taxonomy_get_vocabulary($vid);
|
| 237 |
$form['taxonomy'][$vid .'_disabled'] = $form['taxonomy'][$vid];
|
| 238 |
$form['taxonomy'][$vid .'_disabled']['#multiple'] = ($vocab->hierarchy == 2);
|
| 239 |
$form['taxonomy'][$vid .'_disabled']['#disabled'] = TRUE;
|
| 240 |
$form['taxonomy'][$vid .'_disabled']['#tree'] = FALSE;
|
| 241 |
$form['taxonomy'][$vid .'_disabled']['#required'] = FALSE;
|
| 242 |
$form['taxonomy'][$vid] = array(
|
| 243 |
'#type' => 'value',
|
| 244 |
'#value' => $form['taxonomy'][$vid]['#default_value'],
|
| 245 |
);
|
| 246 |
$form['title']['#disabled'] = TRUE;
|
| 247 |
unset($form['delete']);
|
| 248 |
|
| 249 |
$term = taxonomy_get_term($row->tid);
|
| 250 |
if (!$form['#post']) {
|
| 251 |
drupal_set_message(t('Taxonomy Node: Disabled form elements should be only changed on the associated term !term. To delete this node, just delete the term.', array('!term' => l($term->name, 'admin/content/taxonomy/edit/term/'. $row->tid))));
|
| 252 |
}
|
| 253 |
}
|
| 254 |
}
|
| 255 |
}
|
| 256 |
}
|
| 257 |
|
| 258 |
/**
|
| 259 |
* Implementation of hook_taxonomy().
|
| 260 |
*
|
| 261 |
* @param unknown_type $op
|
| 262 |
* @param unknown_type $type
|
| 263 |
* @param unknown_type $array
|
| 264 |
*/
|
| 265 |
function taxonomynode_taxonomy($op, $type, $array = NULL) {
|
| 266 |
global $taxonomynode;
|
| 267 |
|
| 268 |
// As this module can trigger taxonomy and node operations, check if the
|
| 269 |
// operation was triggered from this module, and, if that's the case,
|
| 270 |
// do nothing
|
| 271 |
if ($taxonomynode) {
|
| 272 |
return;
|
| 273 |
}
|
| 274 |
|
| 275 |
if ($type == 'vocabulary') {
|
| 276 |
$vid = $array['vid'];
|
| 277 |
$content_type = $array['taxonomynode_content_type'];
|
| 278 |
if ($op == 'insert' || $op == 'update') {
|
| 279 |
// store settings
|
| 280 |
$taxonomynode_settings_old = variable_get("taxonomynode_{$vid}", array());
|
| 281 |
if ($taxonomynode_settings_old['content_type'] && $taxonomynode_settings_old['content_type'] != $content_type) {
|
| 282 |
db_query("DELETE FROM {taxonomynode} WHERE vid = %d", $vid);
|
| 283 |
drupal_set_message(t('Taxonomy Node: You have changed your content type selection. If nodes have been created with the old content type, you will have to manually remove the already created nodes for each of the terms of this vocabulary as well as unset the old content type from the <i>Types</i> associated to this vocabulary.'));
|
| 284 |
}
|
| 285 |
$taxonomynode_settings['content_type'] = $content_type;
|
| 286 |
variable_set("taxonomynode_{$vid}", $taxonomynode_settings);
|
| 287 |
// force vocabulary to have the assigned content as Type
|
| 288 |
if ($content_type) {
|
| 289 |
db_query("DELETE FROM {vocabulary_node_types} WHERE vid = %d AND type = '%s'", $vid, $content_type);
|
| 290 |
db_query("INSERT INTO {vocabulary_node_types} (vid, type) VALUES (%d, '%s')", $vid, $content_type);
|
| 291 |
drupal_set_message(t('Taxonomy Node: Information set.'));
|
| 292 |
|
| 293 |
if ($array['taxonomynode_batch']) {
|
| 294 |
$result = db_query_range("SELECT t.* FROM {term_data} t LEFT JOIN {taxonomynode} tn ON t.tid = tn.tid WHERE t.vid = %d AND isnull(tn.tid)", $vid, 0, 50);
|
| 295 |
|
| 296 |
$cnt = 0;
|
| 297 |
while ($row = db_fetch_object($result)) {
|
| 298 |
$term = taxonomy_get_term($row->tid);
|
| 299 |
$parents = taxonomy_get_parents($row->tid);
|
| 300 |
_taxonomynode_toggle();
|
| 301 |
_taxonomynode_create_node($row->tid, $vid, $term->name, array_keys($parents));
|
| 302 |
_taxonomynode_toggle();
|
| 303 |
$cnt++;
|
| 304 |
}
|
| 305 |
|
| 306 |
drupal_set_message(t('Taxonomy Node: Batch operation, %cnt nodes created.', array('%cnt' => $cnt)));
|
| 307 |
}
|
| 308 |
}
|
| 309 |
}
|
| 310 |
|
| 311 |
if ($op == 'delete') {
|
| 312 |
variable_del("taxonomynode_{$vid}");
|
| 313 |
}
|
| 314 |
}
|
| 315 |
|
| 316 |
if ($type == 'term') {
|
| 317 |
$vid = $array['vid'];
|
| 318 |
$tid = $array['tid'];
|
| 319 |
$taxonomynode_settings = variable_get("taxonomynode_{$vid}", array());
|
| 320 |
if ($taxonomynode_settings['content_type']) {
|
| 321 |
if ($op == 'insert' || $op == 'update') {
|
| 322 |
_taxonomynode_toggle();
|
| 323 |
$node = _taxonomynode_create_node($tid, $vid, $array['name'], $array['parent']);
|
| 324 |
_taxonomynode_toggle();
|
| 325 |
|
| 326 |
drupal_set_message(t('Taxonomy Node: Node !node created/updated.', array('!node' => l($node->title, 'node/'. $node->nid))));
|
| 327 |
}
|
| 328 |
}
|
| 329 |
|
| 330 |
if ($op == 'delete') {
|
| 331 |
$nid = _taxonomynode_get_nid_from_tid($tid);
|
| 332 |
if ($nid) {
|
| 333 |
_taxonomynode_toggle();
|
| 334 |
node_delete($nid);
|
| 335 |
_taxonomynode_toggle();
|
| 336 |
db_query("DELETE FROM {taxonomynode} WHERE nid = %d", $nid);
|
| 337 |
}
|
| 338 |
}
|
| 339 |
}
|
| 340 |
}
|
| 341 |
|
| 342 |
/**
|
| 343 |
* Implementation of hook_nodeapi().
|
| 344 |
*/
|
| 345 |
function taxonomynode_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
|
| 346 |
global $taxonomynode;
|
| 347 |
|
| 348 |
// As this module can trigger taxonomy and node operations, check if the
|
| 349 |
// operation was triggered from this module, and, if that's the case,
|
| 350 |
// do nothing
|
| 351 |
if ($taxonomynode) {
|
| 352 |
return;
|
| 353 |
}
|
| 354 |
|
| 355 |
// If no vids is associated to the content type of this node, do nothing
|
| 356 |
$vids = _taxonomynode_node_get_vids($node);
|
| 357 |
if (empty($vids)) {
|
| 358 |
return;
|
| 359 |
}
|
| 360 |
|
| 361 |
switch ($op) {
|
| 362 |
case 'insert':
|
| 363 |
case 'update':
|
| 364 |
$tid = _taxonomynode_get_tid_from_nid($node->nid);
|
| 365 |
if (TAXONOMYNODE_SETTINGS_NODE_OPERATIONS) {
|
| 366 |
// if unpublished and exists, delete node and delete term info from database
|
| 367 |
if ($tid && $node->status == 0) {
|
| 368 |
db_query("DELETE FROM {taxonomynode} WHERE tid = %d", $tid);
|
| 369 |
_taxonomynode_toggle();
|
| 370 |
taxonomy_del_term($tid);
|
| 371 |
_taxonomynode_toggle();
|
| 372 |
drupal_set_message(t('Taxonomy Node: Term %term deleted.', array('%term' => $node->title)));
|
| 373 |
}
|
| 374 |
// if published and term does not exist, create term
|
| 375 |
if (!$tid && $node->status == 1) {
|
| 376 |
_taxonomynode_toggle();
|
| 377 |
$terms = _taxonomynode_create_term($node);
|
| 378 |
_taxonomynode_toggle();
|
| 379 |
foreach ($terms as $term) {
|
| 380 |
$term_links[] = l($term['name'], 'admin/content/taxonomy/edit/term/'.$term['tid']);
|
| 381 |
}
|
| 382 |
drupal_set_message(t('Taxonomy Node: Terms !terms created.', array('!terms' => implode(', ', $term_links))));
|
| 383 |
}
|
| 384 |
|
| 385 |
}
|
| 386 |
break;
|
| 387 |
|
| 388 |
case 'delete':
|
| 389 |
$tid = _taxonomynode_get_tid_from_nid($node->nid);
|
| 390 |
if (TAXONOMYNODE_SETTINGS_NODE_OPERATIONS) {
|
| 391 |
_taxonomynode_toggle();
|
| 392 |
taxonomy_del_term($tid);
|
| 393 |
_taxonomynode_toggle();
|
| 394 |
drupal_set_message(t('Taxonomy Node: Term %term deleted.', array('%term' => $node->title)));
|
| 395 |
}
|
| 396 |
// In case the node is deleted from the admin content screen, remove
|
| 397 |
// the association from the database.
|
| 398 |
db_query("DELETE FROM {taxonomynode} WHERE nid = %d", $node->nid);
|
| 399 |
break;
|
| 400 |
}
|
| 401 |
}
|
| 402 |
|
| 403 |
/**
|
| 404 |
* Callbacks
|
| 405 |
*/
|
| 406 |
|
| 407 |
/**
|
| 408 |
* Create a node out of
|
| 409 |
*
|
| 410 |
* @param unknown_type $tid
|
| 411 |
*/
|
| 412 |
function taxonomynode_create($tid) {
|
| 413 |
$term = taxonomy_get_term($tid);
|
| 414 |
$parents = taxonomy_get_parents($tid);
|
| 415 |
_taxonomynode_create_node($tid, $term->vid, $term->name, array_keys($parents));
|
| 416 |
drupal_set_message(t('Taxonomy Node: Node created.'));
|
| 417 |
drupal_goto('admin/content/taxonomy/edit/term/'. $tid);
|
| 418 |
}
|
| 419 |
|
| 420 |
/**
|
| 421 |
* Implementation of hook_settings().
|
| 422 |
*/
|
| 423 |
function taxonomynode_settings() {
|
| 424 |
$form['taxonomynode_node_operations'] = array(
|
| 425 |
'#type' => 'checkbox',
|
| 426 |
'#title' => t('Map Node Operations'),
|
| 427 |
'#default_value' => TAXONOMYNODE_SETTINGS_NODE_OPERATIONS,
|
| 428 |
'#description' => t('Select this checkbox if you want to map node operations to term operations. Creating a content type associated to vocabularies will create terms on those vocabularies. Deleting or unpublishing a node will delete the associated term, publishing it back will recreate it. Updating the name and hierarchy is still only possible on by editing the actual term.'),
|
| 429 |
);
|
| 430 |
|
| 431 |
return system_settings_form($form);
|
| 432 |
}
|