123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484 |
- <?php
- /**
- * @file 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.
- */
- // ---------------------------------------------------------------------------
- // General Drupal hooks
- /**
- * Implementation of hook_permission().
- */
- function panels_node_permission() {
- return array(
- 'administer panel-nodes' => array(
- 'title' => t('Administer panel nodes'),
- 'description' => t('Full administrative access to panel nodes including create, update and delete all'),
- ),
- );
- }
- /**
- * Implementation of hook_ctools_plugin_directory().
- */
- function panels_node_ctools_plugin_directory($module, $plugin) {
- if ($module == 'panels' && $plugin == 'panels_storage') {
- return 'plugins/' . $plugin;
- }
- }
- /**
- * Implementation of hook_menu().
- */
- function panels_node_menu() {
- // Safety: go away if CTools is not at an appropriate version.
- if (!defined('PANELS_REQUIRED_CTOOLS_API') || !module_invoke('ctools', 'api_version', PANELS_REQUIRED_CTOOLS_API)) {
- return array();
- }
- $items['admin/structure/panels/settings/panel-node'] = array(
- 'title' => 'Panel nodes',
- 'description' => 'Configure which content is available to add to panel node displays.',
- 'access arguments' => array('administer panel-nodes'),
- 'page callback' => 'panels_node_settings',
- 'type' => MENU_LOCAL_TASK,
- );
- // Avoid some repetition on these:
- $base = array(
- 'access callback' => 'panels_node_edit_node',
- 'access arguments' => array(1),
- 'page arguments' => array(1),
- 'type' => MENU_LOCAL_TASK,
- );
- $items['node/%node/panel_layout'] = array(
- 'title' => 'Panel layout',
- 'page callback' => 'panels_node_edit_layout',
- 'weight' => 2,
- ) + $base;
- $items['node/%node/panel_content'] = array(
- 'title' => 'Panel content',
- 'page callback' => 'panels_node_edit_content',
- 'weight' => 3,
- ) + $base;
- $items['node/add/panel/choose-layout'] = array(
- 'title' => 'Choose layout',
- 'access callback' => 'panels_add_panel_access_callback',
- 'page callback' => 'panels_node_add',
- 'type' => MENU_CALLBACK,
- );
- return $items;
- }
- /**
- * Access callback to determine if a user has edit access
- */
- function panels_node_edit_node($node) {
- if (!isset($node->panels_node)) {
- return FALSE;
- }
- return node_access('update', $node);
- }
- /**
- * Access callback to determine if user has access to add panel nodes.
- */
- function panels_add_panel_access_callback() {
- return user_access('create panel content') || user_access('administer panel-nodes');
- }
- /**
- * Override of node add page to force layout selection prior
- * to actually editing a node.
- */
- function panels_node_add() {
- $output = '';
- ctools_include('plugins', 'panels');
- ctools_include('common', 'panels');
- $layouts = panels_common_get_allowed_layouts('panels_node');
- return panels_common_print_layout_links($layouts, 'node/add/panel', array('query' => drupal_get_query_parameters()));
- }
- // ---------------------------------------------------------------------------
- // Node hooks
- /**
- * Implementation of hook_node_info().
- */
- function panels_node_node_info() {
- // Safety: go away if CTools is not at an appropriate version.
- if (!defined('PANELS_REQUIRED_CTOOLS_API') || !module_invoke('ctools', 'api_version', PANELS_REQUIRED_CTOOLS_API)) {
- return array();
- }
- return array(
- 'panel' => array(
- 'name' => t('Panel'),
- // We use panels_node_hook so that panels_node private
- // callbacks do not get confused with panels versions of
- // nodeapi callbacks.
- 'base' => 'panels_node_hook',
- 'body_label' => t('Teaser'),
- 'description' => t("A panel layout broken up into rows and columns."),
- ),
- );
- }
- /**
- * Implementation of hook_access().
- */
- function panels_node_node_access($node, $op, $account) {
- if ($op == 'create' && $node != 'panel') {
- return NODE_ACCESS_IGNORE;
- }
- if (is_object($node) && $node->type != 'panel') {
- return NODE_ACCESS_IGNORE;
- }
- if (user_access('administer panel-nodes', $account)) {
- return NODE_ACCESS_ALLOW;
- }
- }
- /**
- * Implementation of hook_form().
- */
- function panels_node_hook_form(&$node, &$form_state) {
- ctools_include('plugins', 'panels');
- $form['panels_node']['#tree'] = TRUE;
- if (empty($node->nid) && arg(0) == 'node' && arg(1) == 'add') {
- // Grab our selected layout from the $node, If it doesn't exist, try arg(3)
- // and if that doesn't work present them with a list to pick from.
- $panel_layout = isset($node->panel_layout) ? $node->panel_layout : arg(3);
- if (empty($panel_layout)) {
- drupal_goto('node/add/panel/choose-layout', array('query' => drupal_get_query_parameters()));
- }
- $layout = panels_get_layout($panel_layout);
- if (empty($layout)) {
- return MENU_NOT_FOUND;
- }
- $form['panels_node']['layout'] = array(
- '#type' => 'value',
- '#value' => $panel_layout,
- );
- }
- $type = node_type_get_type($node);
- $form['title'] = array(
- '#type' => 'textfield',
- '#title' => check_plain($type->title_label),
- '#required' => TRUE,
- '#default_value' => $node->title,
- );
- $css_id = '';
- if (!empty($node->panels_node['css_id'])) {
- $css_id = $node->panels_node['css_id'];
- }
- $form['panels_node']['css_id'] = array(
- '#type' => 'textfield',
- '#title' => t('CSS ID'),
- '#size' => 30,
- '#description' => t('An ID that can be used by CSS to style the panel.'),
- '#default_value' => $css_id,
- );
- // Support for different rendering pipelines
- // Mostly borrowed from panel_context.inc
- $pipelines = panels_get_renderer_pipelines();
- $options = array();
- foreach ($pipelines as $name => $pipeline) {
- $options[$name] = check_plain($pipeline->admin_title) . '<div class="description">' . check_plain($pipeline->admin_description) . '</div>';
- }
- $form['panels_node']['pipeline'] = array(
- '#type' => 'radios',
- '#options' => $options,
- '#title' => t('Renderer'),
- '#default_value' => isset($node->panels_node['pipeline']) ? $node->panels_node['pipeline'] : variable_get('panels_renderer_default', 'standard'),
- );
- return $form;
- }
- /**
- * Implementation of hook_validate().
- */
- function panels_node_hook_validate($node, $form, &$form_state) {
- if (!$node->nid && empty($node->panels_node['layout'])) {
- form_error($form['panels_node']['layout'], t('Please select a layout.'));
- }
- }
- /**
- * Implementation of hook_load().
- *
- * Panels does not use revisions for nodes because that would open us up
- * to have completely separate displays, and we'd have to copy them,
- * and that's going to be a LOT of data.
- */
- function panels_node_hook_load($nodes) {
- // We shortcut this because only in some really drastic corruption circumstance will this
- // not work.
- $result = db_query("SELECT * FROM {panels_node} WHERE nid IN (:nids)", array(':nids' => array_keys($nodes)));
- foreach ($result as $record) {
- $nodes[$record->nid]->panels_node = (array) $record;
- }
- }
- /**
- * Implementation of hook_insert().
- */
- function panels_node_hook_insert(&$node) {
- // Create a new display and record that.
- $display = panels_new_display();
- $display->layout = $node->panels_node['layout'];
- $display->storage_type = 'panels_node';
- $display->storage_id = $node->nid;
- // Special handling for nodes being imported from an export.module data dump.
- if (!empty($node->export_display)) {
- // This works by overriding the $display set above
- eval($node->export_display);
- unset($node->export_display);
- }
- panels_save_display($display);
- $node->panels_node['did'] = $display->did;
- db_insert('panels_node')
- ->fields(array(
- 'nid' => $node->nid,
- 'did' => $display->did,
- 'css_id' => $node->panels_node['css_id'],
- 'pipeline' => $node->panels_node['pipeline'],
- ))
- ->execute();
- }
- /**
- * Implementation of hook_delete().
- */
- function panels_node_hook_delete(&$node) {
- db_delete('panels_node')->condition('nid', $node->nid)->execute();
- if (!empty($node->panels_node['did'])) {
- panels_delete_display($node->panels_node['did']);
- }
- }
- /**
- * Implementation of hook_update().
- */
- function panels_node_hook_update($node) {
- db_update('panels_node')
- ->condition('nid', $node->nid)
- ->fields(array(
- 'css_id' => $node->panels_node['css_id'],
- 'pipeline' => $node->panels_node['pipeline'],
- ))
- ->execute();
- }
- /**
- * Implementation of hook_view().
- */
- function panels_node_hook_view($node, $view_mode) {
- static $rendering = array();
- // Prevent loops if someone foolishly puts the node inside itself:
- if (!empty($rendering[$node->nid])) {
- return $node;
- }
- $rendering[$node->nid] = TRUE;
- ctools_include('plugins', 'panels');
- if ($view_mode == 'teaser') {
- // Because our teasier is never the same as our content, *always* provide
- // the read more flag.
- $node->readmore = TRUE;
- }
- else {
- if (!empty($node->panels_node['did'])) {
- $display = panels_load_display($node->panels_node['did']);
- $display->css_id = $node->panels_node['css_id'];
- // TODO: Find a way to make sure this can't node_view.
- $display->context = panels_node_get_context($node);
- $display->cache_key = 'panels_node:' . $node->nid;
- $renderer = panels_get_renderer($node->panels_node['pipeline'], $display);
- $node->content['body'] = array(
- '#markup' => panels_render_display($display, $renderer),
- '#weight' => 0,
- );
- }
- }
- unset($rendering[$node->nid]);
- return $node;
- }
- // ---------------------------------------------------------------------------
- // Administrative pages
- /**
- * Settings for panel nodes.
- */
- function panels_node_settings() {
- ctools_include('common', 'panels');
- return drupal_get_form('panels_common_settings', 'panels_node');
- }
- // ---------------------------------------------------------------------------
- // Meat of the Panels API; almost completely passing through to panels.module
- /**
- * Pass through to the panels layout editor.
- */
- function panels_node_edit_layout($node) {
- // ctools_include('plugins', 'panels');
- ctools_include('context');
- $display = panels_load_display($node->panels_node['did']);
- $display->context = panels_node_get_context($node);
- return panels_edit_layout($display, t('Save'), "node/$node->nid/panel_layout", 'panels_node');
- }
- /**
- * Pass through to the panels content editor.
- */
- function panels_node_edit_content($node) {
- ctools_include('context');
- $display = panels_load_display($node->panels_node['did']);
- $display->context = panels_node_get_context($node);
- ctools_include('common', 'panels');
- $content_types = panels_common_get_allowed_types('panels_node', $display->context);
- return panels_edit($display, "node/$node->nid/panel_content", $content_types);
- }
- /**
- * Build the context to use for a panel node.
- */
- function panels_node_get_context(&$node) {
- ctools_include('context');
- $context = ctools_context_create('node', $node);
- $context->identifier = t('This node');
- $context->keyword = 'node';
- return array('panel-node' => $context);
- }
- /**
- * Implementation of hook_export_node_alter()
- *
- * Integrate with export.module for saving panel_nodes into code.
- */
- function panels_node_export_node_alter(&$node, $original_node, $method) {
- if ($method == 'export') {
- $node_export_omitted = variable_get('node_export_omitted', array());
- if (variable_get('node_export_method', '') != 'save-edit' && (array_key_exists('panel', $node_export_omitted) && !$node_export_omitted['panel'])) {
- drupal_set_message(t("NOTE: in order to import panel_nodes you must first set the export.module settings to \"Save as a new node then edit\", otherwise it won't work."));
- }
- $display = panels_load_display($node->panels_node['did']);
- $export = panels_export_display($display);
- $node->export_display = $export;
- }
- }
- /**
- * Implementation of hook_panels_dashboard_blocks().
- *
- * Adds panel nodes information to the Panels dashboard.
- */
- function panels_node_panels_dashboard_blocks(&$vars) {
- $vars['links']['panels_node'] = array(
- 'title' => l(t('Panel node'), 'node/add/panel'),
- 'description' => t('Panel nodes are node content and appear in your searches, but are more limited than panel pages.'),
- 'weight' => -1,
- );
- }
- /**
- * Implements hook_panels_ipe_access().
- */
- function panels_node_panels_ipe_access($display) {
- // We only care about Panels displays from panels_node.
- if (isset($display->context['panel-node'])) {
- // Only allow access to use the IPE if the user has 'update' access to
- // the underlying node.
- $node = $display->context['panel-node']->data;
- return node_access('update', $node);
- }
- }
- // ---------------------------------------------------------------------------
- // Callbacks for panel caching.
- /**
- * Get display edit cache for a panel node being edited.
- *
- * The key is the second half of the key in this form:
- * panels_node:NID;
- */
- function panels_node_panels_cache_get($nid) {
- ctools_include('object-cache');
- $cache = ctools_object_cache_get('panels_node_display_cache', $nid);
- if (empty($cache)) {
- $cache = new stdClass();
- $node = node_load($nid);
- if (empty($node)) {
- return;
- }
- ctools_include('common', 'panels');
- $cache->display = panels_load_display($node->panels_node['did']);
- $cache->display->css_id = $node->panels_node['css_id'];
- $cache->display->context = panels_node_get_context($node);
- $cache->display->cache_key = 'panels_node:' . $node->nid;
- $cache->content_types = panels_common_get_allowed_types('panels_node', $cache->display->context);
- $cache->allwed_layouts = panels_common_get_allowed_layouts('panels_node');
- }
- return $cache;
- }
- /**
- * Store a display edit in progress in the panels cache.
- */
- function panels_node_panels_cache_set($nid, $cache) {
- ctools_include('object-cache');
- ctools_object_cache_set('panels_node_display_cache', $nid, $cache);
- }
- /**
- * Clear all changes made to a display using the panels cache.
- */
- function panels_node_panels_cache_clear($nid, $cache) {
- ctools_include('object-cache');
- ctools_object_cache_clear('panels_node_display_cache', $nid);
- }
- /**
- * React to a cache save and save the display and clear cache.
- */
- function panels_node_panels_cache_save($nid, $cache) {
- panels_save_display($cache->display);
- ctools_include('object-cache');
- ctools_object_cache_clear('panels_node_display_cache', $nid);
- }
|