Projet

Général

Profil

Paste
Télécharger (14,2 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / panels / panels_node / panels_node.module @ 64156087

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
// ---------------------------------------------------------------------------
11
// General Drupal hooks.
12
/**
13
 * Implementation of hook_permission().
14
 */
15
function panels_node_permission() {
16
  return array(
17
    'administer panel-nodes' => array(
18
      'title' => t('Administer panel nodes'),
19
      'description' => t('Full administrative access to panel nodes including create, update and delete all'),
20
    ),
21
  );
22
}
23

    
24
/**
25
 * Implementation of hook_ctools_plugin_directory().
26
 */
27
function panels_node_ctools_plugin_directory($module, $plugin) {
28
  if ($module == 'panels' && $plugin == 'panels_storage') {
29
    return 'plugins/' . $plugin;
30
  }
31
}
32

    
33
/**
34
 * Implementation of hook_menu().
35
 */
36
function panels_node_menu() {
37
  // Safety: go away if CTools is not at an appropriate version.
38
  if (!defined('PANELS_REQUIRED_CTOOLS_API') || !module_invoke('ctools', 'api_version', PANELS_REQUIRED_CTOOLS_API)) {
39
    return array();
40
  }
41

    
42
  $items['admin/structure/panels/settings/panel-node'] = array(
43
    'title' => 'Panel nodes',
44
    'description' => 'Configure which content is available to add to panel node displays.',
45
    'access arguments' => array('administer panel-nodes'),
46
    'page callback' => 'panels_node_settings',
47
    'type' => MENU_LOCAL_TASK,
48
  );
49

    
50
  // Avoid some repetition on these:
51
  $base = array(
52
    'access callback' => 'panels_node_edit_node',
53
    'access arguments' => array(1),
54
    'page arguments' => array(1),
55
    'type' => MENU_LOCAL_TASK,
56
  );
57

    
58
  $items['node/%node/panel_layout'] = array(
59
    'title' => 'Panel layout',
60
    'page callback' => 'panels_node_edit_layout',
61
    'weight' => 2,
62
  ) + $base;
63

    
64
  $items['node/%node/panel_content'] = array(
65
    'title' => 'Panel content',
66
    'page callback' => 'panels_node_edit_content',
67
    'weight' => 3,
68
  ) + $base;
69

    
70
  $items['node/add/panel/choose-layout'] = array(
71
    'title' => 'Choose layout',
72
    'access callback' => 'panels_add_panel_access_callback',
73
    'page callback' => 'panels_node_add',
74
    'type' => MENU_CALLBACK,
75
  );
76

    
77
  return $items;
78
}
79

    
80
/**
81
 * Access callback to determine if a user has edit access.
82
 */
83
function panels_node_edit_node($node) {
84
  if (!isset($node->panels_node)) {
85
    return FALSE;
86
  }
87

    
88
  return node_access('update', $node);
89
}
90

    
91
/**
92
 * Access callback to determine if user has access to add panel nodes.
93
 */
94
function panels_add_panel_access_callback() {
95
  return user_access('create panel content') || user_access('administer panel-nodes');
96
}
97

    
98
/**
99
 * Override of node add page to force layout selection prior
100
 * to actually editing a node.
101
 */
102
function panels_node_add() {
103
  $output = '';
104

    
105
  ctools_include('plugins', 'panels');
106
  ctools_include('common', 'panels');
107

    
108
  $layouts = panels_common_get_allowed_layouts('panels_node');
109
  return panels_common_print_layout_links($layouts, 'node/add/panel', array('query' => drupal_get_query_parameters()));
110
}
111

    
112
// ---------------------------------------------------------------------------
113
// Node hooks.
114
/**
115
 * Implementation of hook_node_info().
116
 */
117
function panels_node_node_info() {
118
  // Safety: go away if CTools is not at an appropriate version.
119
  if (!defined('PANELS_REQUIRED_CTOOLS_API') || !module_invoke('ctools', 'api_version', PANELS_REQUIRED_CTOOLS_API)) {
120
    return array();
121
  }
122

    
123
  return array(
124
    'panel' => array(
125
      'name' => t('Panel'),
126
      // We use panels_node_hook so that panels_node private
127
      // callbacks do not get confused with panels versions of
128
      // nodeapi callbacks.
129
      'base' => 'panels_node_hook',
130
      'body_label' => t('Teaser'),
131
      'description' => t("A panel layout broken up into rows and columns."),
132
    ),
133
  );
134
}
135

    
136
/**
137
 * Implementation of hook_access().
138
 */
139
function panels_node_node_access($node, $op, $account) {
140
  if ($op == 'create' && $node != 'panel') {
141
    return NODE_ACCESS_IGNORE;
142
  }
143

    
144
  if (is_object($node) && $node->type != 'panel') {
145
    return NODE_ACCESS_IGNORE;
146
  }
147

    
148
  if (user_access('administer panel-nodes', $account)) {
149
    return NODE_ACCESS_ALLOW;
150
  }
151
}
152

    
153
/**
154
 * Implementation of hook_form().
155
 */
156
function panels_node_hook_form(&$node, &$form_state) {
157
  ctools_include('plugins', 'panels');
158

    
159
  $form['panels_node']['#tree'] = TRUE;
160
  if (empty($node->nid) && arg(0) == 'node' && arg(1) == 'add') {
161
    // Grab our selected layout from the $node, If it doesn't exist, try arg(3)
162
    // and if that doesn't work present them with a list to pick from.
163
    $panel_layout = isset($node->panel_layout) ? $node->panel_layout : arg(3);
164
    if (empty($panel_layout)) {
165
      drupal_goto('node/add/panel/choose-layout', array('query' => drupal_get_query_parameters()));
166
    }
167

    
168
    $layout = panels_get_layout($panel_layout);
169
    if (empty($layout)) {
170
      return MENU_NOT_FOUND;
171
    }
172
    $form['panels_node']['layout'] = array(
173
      '#type' => 'value',
174
      '#value' => $panel_layout,
175
    );
176
  }
177

    
178
  $type = node_type_get_type($node);
179

    
180
  $form['title'] = array(
181
    '#type' => 'textfield',
182
    '#title' => check_plain($type->title_label),
183
    '#required' => TRUE,
184
    '#default_value' => $node->title,
185
  );
186

    
187
  $css_id = '';
188
  if (!empty($node->panels_node['css_id'])) {
189
    $css_id = $node->panels_node['css_id'];
190
  }
191

    
192
  $form['panels_node']['css_id'] = array(
193
    '#type' => 'textfield',
194
    '#title' => t('CSS ID'),
195
    '#size' => 30,
196
    '#description' => t('An ID that can be used by CSS to style the panel.'),
197
    '#default_value' => $css_id,
198
  );
199

    
200
  // Support for different rendering pipelines
201
  // Mostly borrowed from panel_context.inc.
202
  $pipelines = panels_get_renderer_pipelines();
203

    
204
  $options = array();
205
  foreach ($pipelines as $name => $pipeline) {
206
    $options[$name] = check_plain($pipeline->admin_title) . '<div class="description">' . check_plain($pipeline->admin_description) . '</div>';
207
  }
208

    
209
  $form['panels_node']['pipeline'] = array(
210
    '#type' => 'radios',
211
    '#options' => $options,
212
    '#title' => t('Renderer'),
213
    '#default_value' => isset($node->panels_node['pipeline']) ? $node->panels_node['pipeline'] : variable_get('panels_renderer_default', 'standard'),
214
  );
215

    
216
  return $form;
217
}
218

    
219
/**
220
 * Implementation of hook_validate().
221
 */
222
function panels_node_hook_validate($node, $form, &$form_state) {
223
  if (!$node->nid && empty($node->panels_node['layout'])) {
224
    form_error($form['panels_node']['layout'], t('Please select a layout.'));
225
  }
226
}
227

    
228
/**
229
 * Implementation of hook_load().
230
 *
231
 * Panels does not use revisions for nodes because that would open us up
232
 * to have completely separate displays, and we'd have to copy them,
233
 * and that's going to be a LOT of data.
234
 */
235
function panels_node_hook_load($nodes) {
236
  // We shortcut this because only in some really drastic corruption circumstance will this
237
  // not work.
238
  $result = db_query("SELECT * FROM {panels_node} WHERE nid IN (:nids)", array(':nids' => array_keys($nodes)));
239
  foreach ($result as $record) {
240
    $nodes[$record->nid]->panels_node = (array) $record;
241
  }
242
}
243

    
244
/**
245
 * Implementation of hook_insert().
246
 */
247
function panels_node_hook_insert(&$node) {
248
  // Create a new display and record that.
249
  $display = panels_new_display();
250
  $display->layout = $node->panels_node['layout'];
251
  $display->storage_type = 'panels_node';
252
  $display->storage_id = $node->nid;
253

    
254
  // Special handling for nodes being imported from an export.module data dump.
255
  if (!empty($node->export_display)) {
256
    // This works by overriding the $display set above.
257
    eval($node->export_display);
258
    unset($node->export_display);
259
  }
260

    
261
  panels_save_display($display);
262
  $node->panels_node['did'] = $display->did;
263

    
264
  db_insert('panels_node')
265
    ->fields(array(
266
      'nid' => $node->nid,
267
      'did' => $display->did,
268
      'css_id' => $node->panels_node['css_id'],
269
      'pipeline' => $node->panels_node['pipeline'],
270
    ))
271
    ->execute();
272
}
273

    
274
/**
275
 * Implementation of hook_delete().
276
 */
277
function panels_node_hook_delete(&$node) {
278
  db_delete('panels_node')->condition('nid', $node->nid)->execute();
279
  if (!empty($node->panels_node['did'])) {
280
    panels_delete_display($node->panels_node['did']);
281
  }
282
}
283

    
284
/**
285
 * Implementation of hook_update().
286
 */
287
function panels_node_hook_update($node) {
288
  db_update('panels_node')
289
    ->condition('nid', $node->nid)
290
    ->fields(array(
291
      'css_id' => $node->panels_node['css_id'],
292
      'pipeline' => $node->panels_node['pipeline'],
293
    ))
294
    ->execute();
295
}
296

    
297
/**
298
 * Implementation of hook_view().
299
 */
300
function panels_node_hook_view($node, $view_mode) {
301
  static $rendering = array();
302

    
303
  // Prevent loops if someone foolishly puts the node inside itself:
304
  if (!empty($rendering[$node->nid])) {
305
    return $node;
306
  }
307

    
308
  $rendering[$node->nid] = TRUE;
309
  ctools_include('plugins', 'panels');
310
  if ($view_mode == 'teaser') {
311
    // Because our teasier is never the same as our content, *always* provide
312
    // the read more flag.
313
    $node->readmore = TRUE;
314
  }
315
  else {
316
    if (!empty($node->panels_node['did'])) {
317
      $display = panels_load_display($node->panels_node['did']);
318
      $display->css_id = $node->panels_node['css_id'];
319
      // TODO: Find a way to make sure this can't node_view.
320
      $display->context = panels_node_get_context($node);
321
      $display->cache_key = 'panels_node:' . $node->nid;
322
      $renderer = panels_get_renderer($node->panels_node['pipeline'], $display);
323
      $node->content['body'] = array(
324
        '#markup' => panels_render_display($display, $renderer),
325
        '#weight' => 0,
326
      );
327
    }
328
  }
329

    
330
  unset($rendering[$node->nid]);
331
  return $node;
332
}
333

    
334
// ---------------------------------------------------------------------------
335
// Administrative pages.
336
/**
337
 * Settings for panel nodes.
338
 */
339
function panels_node_settings() {
340
  ctools_include('common', 'panels');
341
  return drupal_get_form('panels_common_settings', 'panels_node');
342
}
343

    
344
// ---------------------------------------------------------------------------
345
// Meat of the Panels API; almost completely passing through to panels.module.
346
/**
347
 * Pass through to the panels layout editor.
348
 */
349
function panels_node_edit_layout($node) {
350
//  ctools_include('plugins', 'panels');
351
  ctools_include('context');
352
  $display = panels_load_display($node->panels_node['did']);
353
  $display->context = panels_node_get_context($node);
354
  return panels_edit_layout($display, t('Save'), "node/$node->nid/panel_layout", 'panels_node');
355
}
356

    
357
/**
358
 * Pass through to the panels content editor.
359
 */
360
function panels_node_edit_content($node) {
361
  ctools_include('context');
362
  $display = panels_load_display($node->panels_node['did']);
363
  $display->context = panels_node_get_context($node);
364
  ctools_include('common', 'panels');
365
  $content_types = panels_common_get_allowed_types('panels_node', $display->context);
366

    
367
  return panels_edit($display, "node/$node->nid/panel_content", $content_types);
368
}
369

    
370
/**
371
 * Build the context to use for a panel node.
372
 */
373
function panels_node_get_context(&$node) {
374
  ctools_include('context');
375
  $context = ctools_context_create('node', $node);
376
  $context->identifier = t('This node');
377
  $context->keyword = 'node';
378
  return array('panel-node' => $context);
379
}
380

    
381
/**
382
 * Implementation of hook_export_node_alter().
383
 *
384
 * Integrate with export.module for saving panel_nodes into code.
385
 */
386
function panels_node_export_node_alter(&$node, $original_node, $method) {
387
  if ($method == 'export') {
388
    $node_export_omitted = variable_get('node_export_omitted', array());
389
    if (variable_get('node_export_method', '') != 'save-edit' && (array_key_exists('panel', $node_export_omitted) && !$node_export_omitted['panel'])) {
390
      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."));
391
    }
392
    $display = panels_load_display($node->panels_node['did']);
393
    $export = panels_export_display($display);
394
    $node->export_display = $export;
395
  }
396
}
397

    
398
/**
399
 * Implementation of hook_panels_dashboard_blocks().
400
 *
401
 * Adds panel nodes information to the Panels dashboard.
402
 */
403
function panels_node_panels_dashboard_blocks(&$vars) {
404
  $vars['links']['panels_node'] = array(
405
    'title' => l(t('Panel node'), 'node/add/panel'),
406
    'description' => t('Panel nodes are node content and appear in your searches, but are more limited than panel pages.'),
407
    'weight' => -1,
408
  );
409
}
410

    
411
/**
412
 * Implements hook_panels_ipe_access().
413
 */
414
function panels_node_panels_ipe_access($display) {
415
  // We only care about Panels displays from panels_node.
416
  if (isset($display->context['panel-node'])) {
417
    // Only allow access to use the IPE if the user has 'update' access to
418
    // the underlying node.
419
    $node = $display->context['panel-node']->data;
420
    return node_access('update', $node);
421
  }
422
}
423

    
424
// ---------------------------------------------------------------------------
425
// Callbacks for panel caching.
426
/**
427
 * Get display edit cache for a panel node being edited.
428
 *
429
 * The key is the second half of the key in this form:
430
 * panels_node:NID;
431
 */
432
function panels_node_panels_cache_get($nid) {
433
  ctools_include('object-cache');
434
  $cache = ctools_object_cache_get('panels_node_display_cache', $nid);
435
  if (empty($cache)) {
436
    $cache = new stdClass();
437
    $node = node_load($nid);
438
    if (empty($node)) {
439
      return;
440
    }
441

    
442
    ctools_include('common', 'panels');
443
    $cache->display = panels_load_display($node->panels_node['did']);
444
    $cache->display->css_id = $node->panels_node['css_id'];
445
    $cache->display->context = panels_node_get_context($node);
446
    $cache->display->cache_key = 'panels_node:' . $node->nid;
447
    $cache->content_types = panels_common_get_allowed_types('panels_node', $cache->display->context);
448
    $cache->allwed_layouts = panels_common_get_allowed_layouts('panels_node');
449
  }
450

    
451
  return $cache;
452
}
453

    
454
/**
455
 * Store a display edit in progress in the panels cache.
456
 */
457
function panels_node_panels_cache_set($nid, $cache) {
458
  ctools_include('object-cache');
459
  ctools_object_cache_set('panels_node_display_cache', $nid, $cache);
460
}
461

    
462
/**
463
 * Clear all changes made to a display using the panels cache.
464
 */
465
function panels_node_panels_cache_clear($nid, $cache) {
466
  ctools_include('object-cache');
467
  ctools_object_cache_clear('panels_node_display_cache', $nid);
468
}
469

    
470
/**
471
 * React to a cache save and save the display and clear cache.
472
 */
473
function panels_node_panels_cache_save($nid, $cache) {
474
  panels_save_display($cache->display);
475
  ctools_include('object-cache');
476
  ctools_object_cache_clear('panels_node_display_cache', $nid);
477
}