panels_node.module

Tracking 5.x-2.x branch
  1. drupal
    1. 5 contributions/panels/panels_node/panels_node.module
    2. 6 contributions/panels/panels_node/panels_node.module
    3. 7 contributions/panels/panels_node/panels_node.module

panels_node.module

This module provides the "panel" node type. Panel nodes are useful to add additional content to the content area on a per-node base.

Functions & methods

NameDescription
panels_node_accessImplementation of hook_access().
panels_node_add
panels_node_adminPage callback for the very short admin page.
panels_node_context_editEdit contexts of a panel node.
panels_node_context_formThe form to edit the context settings of a panel node.
panels_node_context_form_submitProcess submission of the panel node edit form.
panels_node_deleteImplementation of hook_delete().
panels_node_edit_contentPass through to the panels content editor.
panels_node_edit_layoutPass through to the panels layout editor.
panels_node_edit_layout_settingsPass through to the panels layout settings editor.
panels_node_formImplementation of hook_form().
panels_node_insertImplementation of hook_insert().
panels_node_loadImplementation of hook_load().
panels_node_menuImplementation of hook_menu().
panels_node_node_infoImplementation of hook_node_info().
panels_node_permImplementation of hook_perm().
panels_node_saveSave a panel node.
panels_node_settingsSettings for panel nodes.
panels_node_updateImplementation of hook_update().
panels_node_validateImplementation of hook_validate().
panels_node_viewImplementation of hook_view().

File

View source
  1. <?php
  2. /**
  3. * @file panels_node.module
  4. *
  5. * This module provides the "panel" node type.
  6. * Panel nodes are useful to add additional content to the content area
  7. * on a per-node base.
  8. */
  9. // ---------------------------------------------------------------------------
  10. // General Drupal hooks
  11. /**
  12. * Implementation of hook_perm().
  13. */
  14. function panels_node_perm() {
  15. return array('create panel-nodes', 'edit own panel-nodes', 'administer panel-nodes');
  16. }
  17. /**
  18. * Implementation of hook_menu().
  19. */
  20. function panels_node_menu($may_cache) {
  21. if ($may_cache) {
  22. $items[] = array(
  23. 'path' => 'node/add/panel',
  24. 'title' => t('Panel'),
  25. 'access' => user_access('create panel-nodes'),
  26. 'type' => MENU_NORMAL_ITEM,
  27. );
  28. $items[] = array(
  29. 'path' => 'admin/panels/panel-nodes',
  30. 'title' => t('Panel nodes'),
  31. 'access' => user_access('create panel-nodes') && user_access('access administration pages'),
  32. 'type' => MENU_NORMAL_ITEM,
  33. 'callback' => 'panels_node_admin',
  34. 'description' => t('Information about panel nodes.'),
  35. );
  36. $items[] = array(
  37. 'path' => 'admin/panels/panel-nodes/information',
  38. 'title' => t('Information'),
  39. 'access' => user_access('create panel-nodes') && user_access('access administration pages'),
  40. 'type' => MENU_DEFAULT_LOCAL_TASK,
  41. );
  42. $items[] = array(
  43. 'path' => 'admin/panels/panel-nodes/settings',
  44. 'title' => t('Settings'),
  45. 'description' => t('Configure panel node content availability.'),
  46. 'access' => user_access('administer panel-nodes'),
  47. 'callback' => 'panels_node_settings',
  48. 'type' => MENU_LOCAL_TASK,
  49. );
  50. }
  51. else {
  52. if (arg(0) == 'node' && is_numeric(arg(1))) {
  53. $node = node_load(arg(1));
  54. if ($node && $node->type == 'panel' && node_access('update', $node)) {
  55. $base = 'node/' . arg(1) . '/panel_';
  56. $items[] = array(
  57. 'path' => $base . 'layout',
  58. 'title' => t('Panel layout'),
  59. 'access' => TRUE,
  60. 'callback' => 'panels_node_edit_layout',
  61. 'callback arguments' => array($node),
  62. 'weight' => 2,
  63. 'type' => MENU_LOCAL_TASK,
  64. );
  65. $items[] = array(
  66. 'path' => $base . 'settings',
  67. 'title' => t('Panel layout settings'),
  68. 'access' => TRUE,
  69. 'callback' => 'panels_node_edit_layout_settings',
  70. 'callback arguments' => array($node),
  71. 'weight' => 2,
  72. 'type' => MENU_LOCAL_TASK,
  73. );
  74. $items[] = array(
  75. 'path' => $base . 'content',
  76. 'title' => t('Panel content'),
  77. 'access' => TRUE,
  78. 'callback' => 'panels_node_edit_content',
  79. 'callback arguments' => array($node),
  80. 'weight' => 3,
  81. 'type' => MENU_LOCAL_TASK,
  82. );
  83. $items[] = array(
  84. 'path' => $base . 'context',
  85. 'title' => t('Context'),
  86. 'access' => TRUE,
  87. 'callback' => 'panels_node_context_edit',
  88. 'callback arguments' => array($node),
  89. 'weight' => 4,
  90. 'type' => MENU_LOCAL_TASK,
  91. );
  92. }
  93. }
  94. // Hard override of node/add
  95. if (arg(0) == 'node' && arg(1) == 'add' && arg(2) == 'panel' && arg(3) == NULL) {
  96. $items[] = array(
  97. 'path' => 'node/add/panel',
  98. 'title' => t('Panel'),
  99. 'access' => user_access('create panel-nodes'),
  100. 'callback' => 'panels_node_add',
  101. 'type' => MENU_NORMAL_ITEM,
  102. );
  103. }
  104. }
  105. return $items;
  106. }
  107. /**
  108. * Page callback for the very short admin page.
  109. */
  110. function panels_node_admin() {
  111. $output = '<p>';
  112. $output .= t('Panel nodes do not have a normal administrative UI, such as panels pages or mini panels. With this module, a new node type is created: a "panel" node. These are nodes that have panel layouts, but do not have the breadth of features that panel pages do; these features are sacrificed so that you gain all the capabilities of nodes.');
  113. $output .= '</p><p>';
  114. $output .= t('You may create a !panel_node using the normal !create_content menu, and you can administer your panel nodes under the normal !administer_nodes menu (administrative permission required).', array(
  115. '!panel_node' => l(t('panel node'), 'node/add/panel'),
  116. '!create_content' => l(t('create content'), 'node/add'),
  117. '!administer_nodes' => l(t('administer nodes'), 'admin/content/node'),
  118. ));
  119. $output .= '</p><p>';
  120. $output .= t('On the !settings page, you may control which panes may be added to panel nodes; this can be very valuable to limit what content is available if your users who can create panel nodes are not administrators.', array(
  121. '!settings' => l(t('settings'), 'admin/panels/panel-nodes/settings'),
  122. ));
  123. $output .= '</p>';
  124. return $output;
  125. }
  126. // ---------------------------------------------------------------------------
  127. // Node hooks
  128. /**
  129. * Implementation of hook_node_info().
  130. */
  131. function panels_node_node_info() {
  132. return array(
  133. 'panel' => array(
  134. 'name' => t('Panel'),
  135. 'module' => 'panels_node',
  136. 'body_label' => t('Teaser'),
  137. 'description' => t("A panel a page layout broken up into rows and columns."),
  138. ),
  139. );
  140. }
  141. /**
  142. * Implementation of hook_access().
  143. */
  144. function panels_node_access($op, $node = NULL) {
  145. if (user_access('administer panel-nodes')) {
  146. return TRUE;
  147. }
  148. if ($op == 'create' && user_access('create panel-nodes')) {
  149. return TRUE;
  150. }
  151. if ($op == 'update' && $node->uid == $user->uid && user_access('edit own panel-nodes')) {
  152. return TRUE;
  153. }
  154. }
  155. function panels_node_add() {
  156. $output = '';
  157. panels_load_include('plugins');
  158. // If no layout selected, present a list of choices.
  159. foreach (panels_get_layouts() as $id => $layout) {
  160. $output .= panels_print_layout_link($id, $layout, $_GET['q'] . '/' . $id);
  161. }
  162. return $output;
  163. }
  164. /**
  165. * Implementation of hook_form().
  166. */
  167. function panels_node_form(&$node, &$param) {
  168. $form['panels_node']['#tree'] = TRUE;
  169. if (!$node->nid) {
  170. // Grab our selected layout from the $node, If it doesn't exist, try arg(3)
  171. // and if that doesn't work present them with a list to pick from.
  172. $panel_layout = $node->panel_layout ? $node->panel_layout : arg(3);
  173. panels_load_include('plugins');
  174. $layout = panels_get_layout($panel_layout);
  175. if (empty($layout)) {
  176. return drupal_not_found();
  177. }
  178. $form['panels_node']['layout'] = array(
  179. '#type' => 'value',
  180. '#value' => $panel_layout,
  181. );
  182. }
  183. $type = node_get_types('type', $node);
  184. $form['title'] = array(
  185. '#type' => 'textfield',
  186. '#title' => check_plain($type->title_label),
  187. '#required' => TRUE,
  188. '#default_value' => $node->title,
  189. );
  190. if (!empty($type->body_label)) {
  191. $form['body'] = array(
  192. '#type' => 'textarea',
  193. '#title' => check_plain($type->body_label),
  194. '#rows' => 10,
  195. '#required' => TRUE,
  196. '#description' => t('The teaser is a piece of text to describe when the panel is listed (such as when promoted to front page); the actual content will only be displayed on the full node view.'),
  197. '#default_value' => $node->body,
  198. );
  199. }
  200. // drupal_set_message('<pre>' . check_plain(var_export($node, true)) . '</pre>');
  201. $css_id = '';
  202. if (!empty($node->panels_node['css_id'])) {
  203. $css_id = $node->panels_node['css_id'];
  204. }
  205. $form['panels_node']['css_id'] = array(
  206. '#type' => 'textfield',
  207. '#title' => t('CSS ID'),
  208. '#size' => 30,
  209. '#description' => t('An ID that can be used by CSS to style the panel.'),
  210. '#default_value' => $css_id,
  211. );
  212. return $form;
  213. }
  214. /**
  215. * Implementation of hook_validate().
  216. */
  217. function panels_node_validate($node) {
  218. if (!$node->nid && empty($node->panels_node['layout'])) {
  219. form_set_error('', t('Please select a layout.'));
  220. }
  221. }
  222. /**
  223. * Implementation of hook_load().
  224. *
  225. * Panels does not use revisions for nodes because that would open us up
  226. * to have completely separate displays, and we'd have to copy them,
  227. * and that's going to be a LOT of data.
  228. */
  229. function panels_node_load($node) {
  230. // We shortcut this because only in some really drastic corruption circumstance will this
  231. // not work.
  232. $additions['panels_node'] = db_fetch_array(db_query("SELECT * FROM {panels_node} WHERE nid = %d", $node->nid));
  233. $additions['panels_node']['contexts'] = (!empty($additions['panels_node']['contexts'])) ? unserialize($additions['panels_node']['contexts']) : array();
  234. $additions['panels_node']['relationships'] = (!empty($additions['panels_node']['relationships'])) ? unserialize($additions['panels_node']['relationships']) : array();
  235. return $additions;
  236. }
  237. /**
  238. * Implementation of hook_insert().
  239. */
  240. function panels_node_insert(&$node) {
  241. // Create a new display and record that.
  242. $display = panels_new_display();
  243. $display->layout = $node->panels_node['layout'];
  244. panels_save_display($display);
  245. $css_id = $node->panels_node['css_id'];
  246. db_query("INSERT INTO {panels_node} (nid, did, css_id) VALUES (%d, %d, '%s')", $node->nid, $display->did, $node->panels_node['css_id']);
  247. $node->panels_node['did'] = $display->did;
  248. }
  249. /**
  250. * Implementation of hook_delete().
  251. */
  252. function panels_node_delete(&$node) {
  253. db_query("DELETE FROM {panels_node} WHERE nid = %d", $node->nid);
  254. if (!empty($node->panels_node['did'])) {
  255. panels_delete_display($node->panels_node['did']);
  256. }
  257. }
  258. /**
  259. * Implementation of hook_update().
  260. */
  261. function panels_node_update($node) {
  262. db_query("UPDATE {panels_node} SET css_id = '%s' WHERE nid = %d", $node->panels_node['css_id'], $node->nid);
  263. }
  264. /**
  265. * Implementation of hook_view().
  266. */
  267. function panels_node_view($node, $teaser = FALSE, $page = FALSE) {
  268. panels_load_include('plugins');
  269. if ($teaser) {
  270. // Do the standard view for teaser.
  271. $node = node_prepare($node, $teaser);
  272. }
  273. else {
  274. $display = panels_load_display($node->panels_node['did']);
  275. $display->css_id = $node->panels_node['css_id'];
  276. // TODO: Find a way to make sure this can't node_view.
  277. $display->context = array('panel-node' => panels_context_create('node', $node));
  278. // Load additional contexts.
  279. $panel_node = (object)$node->panels_node;
  280. $display->context += panels_context_load_contexts($panel_node);
  281. $node->content['body'] = array(
  282. '#value' => panels_render_display($display),
  283. '#weight' => 0,
  284. );
  285. }
  286. return $node;
  287. }
  288. /**
  289. * Save a panel node.
  290. *
  291. * While panels_node_update() is run when a panel node is edited, this function
  292. * must be run to update the enhanced panel node configuration, f.e. contexts,
  293. * which are not edited on the regular node edit page.
  294. *
  295. * @see panels_node_update(), panels_node_context_form_submit()
  296. */
  297. function panels_node_save($panel_node) {
  298. db_query("UPDATE {panels_node} SET contexts = '%s', relationships = '%s' WHERE nid = %d", serialize($panel_node->contexts), serialize($panel_node->relationships), $panel_node->nid);
  299. }
  300. // ---------------------------------------------------------------------------
  301. // Administrative pages
  302. /**
  303. * Settings for panel nodes.
  304. */
  305. function panels_node_settings() {
  306. panels_load_include('common');
  307. return drupal_get_form('panels_common_settings', 'panels_node');
  308. }
  309. // ---------------------------------------------------------------------------
  310. // Meat of the Panels API; almost completely passing through to panels.module
  311. /**
  312. * Pass through to the panels layout editor.
  313. */
  314. function panels_node_edit_layout($node) {
  315. panels_load_include('plugins');
  316. $display = panels_load_display($node->panels_node['did']);
  317. $display->context = array('panel-node' => panels_context_create('node', $node));
  318. return panels_edit_layout($display, t('Save'), "node/$node->nid/panel_layout");
  319. }
  320. /**
  321. * Pass through to the panels layout settings editor.
  322. */
  323. function panels_node_edit_layout_settings($node) {
  324. panels_load_include('plugins');
  325. $display = panels_load_display($node->panels_node['did']);
  326. return panels_edit_layout_settings($display, t('Save'), "node/$node->nid/panel_settings");
  327. }
  328. /**
  329. * Pass through to the panels content editor.
  330. */
  331. function panels_node_edit_content($node) {
  332. panels_load_include('plugins');
  333. $display = panels_load_display($node->panels_node['did']);
  334. $display->context = array('panel-node' => panels_context_create('node', $node));
  335. $display->context['panel-node']->identifier = $node->title;
  336. // Load additional contexts.
  337. $panel_node = (object)$node->panels_node;
  338. $display->context += panels_context_load_contexts($panel_node);
  339. panels_load_include('common');
  340. $content_types = panels_common_get_allowed_types('panels_node', $display->context);
  341. // Print this with theme('page') so that blocks are disabled while editing a display.
  342. // This is important because negative margins in common block layouts (i.e, Garland)
  343. // messes up the drag & drop.
  344. print theme('page', panels_edit($display, "node/$node->nid/panel_content", $content_types), FALSE);
  345. }
  346. /**
  347. * Edit contexts of a panel node.
  348. *
  349. * FIXME: panels_node_edit_context() already defined in arguments/node_edit.inc.
  350. */
  351. function panels_node_context_edit($node) {
  352. panels_load_include('plugins');
  353. $panel_node = (object)$node->panels_node;
  354. $panel_node->nid = $node->nid;
  355. $cache = panels_common_cache_get('panel_object:panel_node', $panel_node->did);
  356. if (!$cache) {
  357. panels_common_cache_set('panel_object:panel_node', $panel_node->did, $panel_node);
  358. }
  359. else {
  360. $panel_node = $cache;
  361. }
  362. drupal_set_title(check_plain($node->title));
  363. return drupal_get_form('panels_node_context_form', $panel_node);
  364. }
  365. /**
  366. * The form to edit the context settings of a panel node.
  367. */
  368. function panels_node_context_form($panel_node) {
  369. drupal_add_css(panels_get_path('css/panels_admin.css'));
  370. $form['panel_node'] = array(
  371. '#type' => 'value',
  372. '#value' => $panel_node,
  373. );
  374. $form['right'] = array(
  375. '#prefix' => '<div class="right-container">',
  376. '#suffix' => '</div>',
  377. );
  378. $form['left'] = array(
  379. '#prefix' => '<div class="left-container">',
  380. '#suffix' => '</div>',
  381. );
  382. panels_load_include('common');
  383. // FIXME: Common panels forms are based on $object->name instead of did.
  384. $panel_node->name = $panel_node->did;
  385. $settings = panels_common_add_context_form('panel_node', $form, $form['right']['contexts_table'], $panel_node);
  386. $settings += panels_common_add_relationship_form('panel_node', $form, $form['left']['relationships_table'], $panel_node);
  387. panels_common_add_context_js($settings);
  388. $label = t('Save');
  389. $form['submit'] = array(
  390. '#type' => 'submit',
  391. '#value' => $label,
  392. );
  393. return $form;
  394. }
  395. /**
  396. * Process submission of the panel node edit form.
  397. */
  398. function panels_node_context_form_submit($form_id, $form_values) {
  399. $panel_node = $form_values['panel_node'];
  400. // Organize these from the common form.
  401. panels_common_save_context('context', $panel_node->contexts, $form_values);
  402. panels_common_save_context('relationship', $panel_node->relationships, $form_values);
  403. drupal_set_message(t('Your changes have been saved.'));
  404. panels_node_save($panel_node);
  405. panels_common_cache_clear('panel_object:panel_node', $panel_node->did);
  406. }