first commit
[step2_drupal.git] / og / modules / og_panels / og_panels.module
blob14a51cb92ad4ae25c8512c7686ada1c54230d153
1 <?php
2 // $Id: og_panels.module,v 1.41 2008/10/31 12:14:04 weitzman Exp $
4 function og_panels_help($section) {
5   switch ($section) {
6     case 'admin/help#og_panels':
7       return t('After enabling this module, visit the new "Pages" tab on any group. There, group admins may create as many pages as desired for their group. The pages may contain any layout that the site offers and admins may arrange many different types of content as desired. Site admins can restrict the types of content that may be added on the <a href="!settings">og_panels settings</a> page. You might want to make some Views available using <a href="!apv">admin/panels/views</a>. Group admins may designate one page as their group home page.', array('!settings' => url('admin/og/og_panels'), '!apv' => url('admin/panels/views')));
8       case (arg(0) == 'node' && arg(2) == 'og_panels' && !arg(3)):
9         return '<p>'. t('Create custom pages for your group. Use custom pages to organize your content in a pretty and informative manner. Your group can group to be a whole website within a web site. Each custom page becomes a tab when viewing your group. One of your custom pages should be designated as your <em>group home page</em>. That page will then display when visitors first arrive at your group.') .'</p><p>'. t('Start by clicking the <a href="!url">Add new page</a> tab. Then you will choose a custom layout for your page. Then you will want to <em>edit content</em> for your custom page.', array('!url' => url('node/'. arg(1). '/og_panels/form'))) .'</p>';
10   }
13 function og_panels_menu($may_cache) {
14   if ($may_cache) {
15     $items[] = array(
16       'path' => 'admin/og/og_panels',
17       'title' => 'Organic groups panels',
18       'description' => 'Configure the content that is available to group admins when creating group pages.',
19       'callback' => 'og_panels_admin_content',
20       'access' => user_access('administer organic groups'),
21     );
22   }
23   else {
24     if (arg(0) == 'node' && is_numeric(arg(1))) {
25       $node = node_load(arg(1));
26       if (og_is_group_type($node->type) && node_access('view', $node)) {
27         $nid = arg(1);
28         $items[] = array(
29           'path' => "node/$nid/og_panels",
30           'title' => 'Pages',
31           'callback' => 'og_panels_overview',
32           'callback arguments' => array($node),
33           'access' => og_is_group_admin($node) && user_access('manage OG panels pages'),
34           'type' => MENU_LOCAL_TASK,
35           'weight' => 8,
36         );
37         
38         $items[] = array(
39           'path' => "node/$nid/og_panels/list",
40           'title' => 'List',
41           'type' => MENU_DEFAULT_LOCAL_TASK,
42           'weight' => -10,
43         );
44         
45         $items[] = array(
46           'path' => "node/$nid/og_panels/form",
47           'callback' => 'drupal_get_form',
48           'callback arguments' => array('og_panels_form', $node),
49           'title' => arg(4) ? 'Edit page' : 'Add new page',
50           'type' => MENU_LOCAL_TASK,
51           'weight' => 0, 
52         );
53         
54         $displays = og_panels_get_all($node->nid);
55         foreach ($displays as $display) {
56           if ($display->default_page && $display->published && arg(2) != 'feed') {
57             // Hijack the menu handler for this node.
58             $items[] = array(
59               'path' => "node/$nid",
60               'title' => $node->title, // doesn't work
61               'callback' => 'og_panels_page',
62               'callback arguments' => array($display->did, $node, $node->title),
63             );
64             
65             /*
66              * Optional. Horrible hack since the tab title is not changeable in D5. Add the following code 
67              * to your theme's template.php in the _phptemplate_variables('page') section.
68              *   if (isset($GLOBALS['og_panels_view_tab_fix'])) {
69              *     $variables['tabs'] = str_replace('>View<', '>'. $GLOBALS['og_panels_view_tab_fix']. '<', $variables['tabs']);
70              *   }
71              */
72             $GLOBALS['og_panels_view_tab_fix'] = check_plain($display->page_title);
73           }
74           else {
75             $items[] = array(
76               'path' => "node/$nid/$display->path",
77               'title' => $display->page_title,
78               'callback' => 'og_panels_page',
79               // have to pass all these args so the args are known in panels_page()
80               'callback arguments' => array($display->did, $node, $display->page_title),
81               'type' => MENU_LOCAL_TASK,
82               'access' => $display->published || (og_is_group_admin($node) && user_access('manage OG panels pages')),
83               'weight' => $display->weight,
84             );
85           }
86         }
87         
88         $items[] = array(
89           'path' => "node/$nid/og_panels/". arg(3). '/view',
90           'callback' => 'og_panels_page',
91           'callback arguments' => array(arg(3), $node),
92           'type' => MENU_CALLBACK,
93         );
94         
95         if (is_numeric(arg(3))) {   
96           $items[] = array(
97             'path' => "node/$nid/og_panels/". arg(3). '/panel_layout',
98             'callback' => 'og_panels_edit_layout',
99             'callback arguments' => array(arg(3), $node),
100             'type' => MENU_CALLBACK,
101           );
103           $items[] = array(
104             'path' => "node/$nid/og_panels/". arg(3). '/panel_settings',
105             'callback' => 'og_panels_edit_layout_settings',
106             'callback arguments' => array(arg(3), $node),
107             'type' => MENU_CALLBACK,
108           );
110           $items[] = array(
111             'path' => "node/$nid/og_panels/". arg(3). '/panel_content',
112             'callback' => 'og_panels_edit_content',
113             'callback arguments' => array(arg(3), $node),
114             'type' => MENU_CALLBACK,
115           );
116           
117           $items[] = array(
118             'path' => "node/$nid/og_panels/". arg(3). '/delete',
119             'title' => 'Delete',
120             'callback' => 'drupal_get_form',
121             'callback arguments' => array('og_panels_delete_confirm', arg(3), $node),
122             'type' => MENU_CALLBACK,
123           ); 
124         }
125       }
126     }
127   }
128   return $items;
131 function og_panels_perm() {
132   return array('manage OG panels pages');
135 function og_panels_delete_confirm($did, $group_node) {
136   $form['did'] = array('#type' => 'value', '#value' => $did);
137   $form['nid'] = array('#type' => 'value', '#value' => $group_node->nid);
138   $sql = "SELECT page_title FROM {og_panels} WHERE did = %d";
139   $page_title = db_result(db_query($sql, $did));
140   $form['page_title'] = array('#type' => 'value', '#value' => $page_title);
141   
142   return confirm_form($form,
143     t('Are you sure you want to delete %title?', array('%title' => $page_title)),
144     isset($_GET['destination']) ? $_GET['destination'] : 'node/'. $node->nid. 'og_panels',
145     t('This action cannot be undone.'),
146     t('Delete'), t('Cancel')
147   );
150 function og_panels_delete_confirm_submit($form_id, $form_values) {
151   og_panels_delete($form_values['did']);
152   drupal_set_message(t('%title has been deleted', array('%title' => $form_values['page_title'])));
155 function og_panels_delete($did) {
156   $sql = "DELETE FROM {og_panels} WHERE did = %d";
157   db_query($sql, $did);
158   panels_delete_display($did);
162  * Menu callback. List the pages for this specified group. Provide helpful operations links.
163  * 
164  * @return string
165  **/
166 function og_panels_overview($group_node) {
167   drupal_set_title(check_plain($group_node->title));
168   $displays = og_panels_get_all($group_node->nid);
169   $output = drupal_get_form('og_panels_table', $displays, $group_node);
170   return $output;
174  * A form for setting the group homepage. Includes a helpful table of Pages and their operations links.
175  * 
176  * @return $form array
177  **/
178 function og_panels_table($displays, $group_node) {
179   $nid = $group_node->nid;
180   $form['#tree'] = TRUE; // #tree must be true in order to separate out the entries in the weight field
181   foreach ($displays as $display) {
182     $item['page_title'] = array('#value' => l($display->page_title, "node/$nid/$display->path"));
183     $item['weight'] = array('#type' => 'weight', '#default_value' => $display->weight);
184     $item['edit content'] = array('#value' => l(t('Edit content'), "node/$nid/og_panels/$display->did/panel_content", array('query' => drupal_get_destination())));
185     $item['change layout'] = array('#value' => l(t('Change layout'), "node/$nid/og_panels/$display->did/panel_layout"));
186     $item['edit layout settings'] = array('#value' => l(t('Edit layout settings'), "node/$nid/og_panels/$display->did/panel_settings"));
187     $item['edit page'] = array('#value' => l(t('Edit page'), "node/$nid/og_panels/form/$display->did", array('query' => drupal_get_destination())));
188     $item['delete page'] =  array('#value' => l(t('Delete page'), "node/$nid/og_panels/$display->did/delete", array('query' => drupal_get_destination())));
189      
190     $form['displays'][$display->did] = $item;
191      
192     // Store the default_page for later.
193     if ($display->default_page == 1) {
194       $default_page = $display->did;
195     }
196     // Prepare the options for the radios.
197     $options[$display->did] = '';
198   }
199    
200   $form['default_page'] = array(
201     '#type' => 'radios', 
202     '#options' => $options, 
203     '#default_value' => $default_page,
204   );
205   $form['submit'] = array(
206     '#type' => 'submit', 
207     '#value' => t('Save settings'),
208   );
210   $form['group_node'] = array('#type' => 'value', '#value' => $group_node);
211   return $form;
215  * Wrangle the $form into a tabular listing of pages.
217  * @ingroup Themeable functions
218  * 
219  * @return void
220  **/
221 function theme_og_panels_table($form) {
222   foreach (element_children($form['displays']) as $did) {
223     if (is_numeric($did)) {
224       $rows[] = array(
225         drupal_render($form['default_page'][$did]),
226         drupal_render($form['displays'][$did]['page_title']), 
227         drupal_render($form['displays'][$did]['weight']),
228         drupal_render($form['displays'][$did]['edit content']),
229         drupal_render($form['displays'][$did]['change layout']), 
230         drupal_render($form['displays'][$did]['edit layout settings']), 
231         drupal_render($form['displays'][$did]['edit page']),
232         drupal_render($form['displays'][$did]['delete page']),
233       );
234     }
235   }
236   
237   $output = drupal_render($form);
238   $header = array(t('Home page'), t('Title'), t('Weight'), array('align' => 'center', 'colspan' => 5, 'data' => t('Operations')));
239   return theme('table', $header, $rows). $output;
242 function og_panels_table_submit($form_id, $form_values) {
243   db_query("UPDATE {og_panels} SET default_page = 0 WHERE nid = %d", $form_values['group_node']->nid);
244   foreach ($form_values['displays'] as $did => $settings) {
245     $default = $did == $form_values['default_page'] ? TRUE : FALSE;
246     $sql = "UPDATE {og_panels} SET weight = %d, default_page = %d WHERE did = %d";
247     db_query($sql, $settings['weight'], $default, $did);
248   }
249   drupal_set_message(t('Updated panels configuration.'));
253  * A menu callback. Renders an og_panel based upon its display ID.
254  * 
255  * @return void
256  **/
257 function og_panels_page($did, $group_node, $title = NULL) {
258   $og_panel = og_panels_get_one_by_display($did);
259   // Set breadcrumb and title on non group nodes
260   if ($title) {
261     drupal_set_title(check_plain($title));
262   }
263   if (!$og_panel->default_page) {
264     $bc[] = l(t('Home'), "");
265     $bc[] = l($group_node->title, "node/$group_node->nid");
266     // I tried MSL but it let me down. again.
267     // menu_set_location($bc);
268     drupal_set_breadcrumb($bc);
269   }
270   // Mark node as read and show feed icon for any group panel page (how to do this better?)
271   drupal_add_feed(url("node/$group_node->nid/feed"), t('@name at @site', array('@name' => $group_node->title, '@site' => variable_get('site_name', 'drupal'))));
272   node_tag_new($group_node->nid);
273   
274   
275   $allargs = func_get_args();
276   $args = array_slice($allargs, 3);
277   $display = og_panels_load_display($did, $group_node);
278   $display->args = $args;
279   $output = panels_render_display($display);
280   // We print instead of return in order to allow blocks to be suppressed.
281   print theme('page', $output, $og_panel->show_blocks);
285  * Add/edit an og_panel.
286  * 
287  * @return void
288  **/
289 function og_panels_form($group_node, $did = NULL) {
290   drupal_set_title(check_plain($group_node->title));
291   if (!is_null($did)) {
292     $display = og_panels_get_one_by_display($did);
293   }
294   else {
295     $display = new stdClass;
296   }
297   
298   $form['page_title'] = array(
299     '#title' => t('Page title'),
300     '#type' => 'textfield',
301     '#required' => $display->default_page ? FALSE : TRUE,
302     '#default_value' => $display->page_title,
303     '#description' => t('This is the title of the page and of the tab.'),
304     '#size' => 32,
305   );
306   global $base_url;
307   $field_prefix = "$base_url/node/$group_node->nid/";
308   $form[$display->default_page ? 'path_placeholder' : 'path'] = array(
309     '#title' => t('Path'),
310     '#type' => 'textfield',
311     '#default_value' => $display->default_page ? '' : $display->path,
312     '#field_prefix' =>  $field_prefix,
313     '#required' => $display->default_page ? FALSE : TRUE,
314     '#description' => $display->default_page ? t('This page is currently your default group home page and has no configurable path.') : '',
315     '#disabled' => $display->default_page,
316     '#size' => 32,
317   );
318   if ($display->default_page) {
319     $form['path'] = array(
320       '#type' => 'hidden',
321       '#value' => $display->path,
322     );
323   }
324   $form['show_blocks'] = array(
325     '#title' => t('Show blocks'),
326     '#type' => 'checkbox',
327     '#default_value' => isset($display->show_blocks) ? $display->show_blocks : TRUE,
328     '#description' => t('If unchecked, the standard group blocks will not be shown unless you place them into your page content. This gives admin more control over page presentation.'),
329   );
330   $form['published'] = array(
331     '#type' => 'checkbox',
332     '#title' => t('Published'),
333     '#default_value' => $display->published,
334     '#description' => t('If unchecked, this page is only accessible by group or site administrators. Thats useful while you are configuring the page.'),
335   );
336   
337   $form['submit'] = array(
338     '#type' => 'submit', 
339     '#value' => $did ? t('Update page') : t('Create page'),
340   );
341   $form['did'] = array('#type' => 'value', '#value' => $did);
342   $form['nid'] = array('#type' => 'value', '#value' => $group_node->nid);
343   return $form;
347  * Return an array of all og_panels attached to the given nid.
349  * @param int $nid
350  * @return array $rows
351  *   An associative array keyed by the $did of the og_panel
352  */
353 function og_panels_get_all($nid) {  
354   $sql = "SELECT * FROM {og_panels} WHERE nid = %d ORDER BY default_page DESC, weight ASC";
355   $result = db_query($sql, $nid);
356   while ($row = db_fetch_object($result)) {
357     $rows[$row->did] = $row;
358   }
359   if (isset($rows)) {
360     return $rows;
361   }
362   return array();
366  * Load an og_panels object.
368  * @param int $did
369  * @return object $og_panel
370  */
371 function og_panels_get_one_by_display($did) {
372   $sql = "SELECT * FROM {og_panels} WHERE did = %d";
373   $result = db_query($sql, $did);
374   return db_fetch_object($result);
378  * Load the default og_panels object, if any, for the given nid.
380  * @param int $nid
381  * @return mixed $og_panel
382  *   Either returns the og_panel object, or FALSE if no default panel was found for the nid
383  */
384 function og_panels_get_one_by_nid_default($nid) {
385   $sql = "SELECT * FROM {og_panels} WHERE nid = %d AND default_page = 1";
386   $result = db_query($sql, $nid);
387   $og_panel = db_fetch_object($result);
388   return is_object($og_panel) ? $og_panel : FALSE;
392  * Load an og_panel's display information.
393  * 
394  * Loads a panels display object with various parameters, depending on the information passed into the load function. 
395  * 
396  * @param int $did
397  *   The did of the panels display.
398  * @param object $group_node = NULL
399  *   The node object for the group to which the panel is attached.
400  * @param bool $ct = FALSE
401  *   If TRUE, content_types are also loaded into the $display object 
402  * 
403  * @return mixed
404  *   Either returns a display object, or FALSE if no display was found with the parameters provided.
405  */
406 function og_panels_load_display($did, $group_node = NULL, $ct = FALSE) {
407   panels_load_include('plugins');
408   $display = panels_load_display($did);
409   if (is_object($group_node)) {
410     $display->context = array('og_panels' => panels_context_create('group', $group_node));
411     if ($ct) {
412       panels_load_include('common');
413       $display->content_types = panels_common_get_allowed_types('og_panels', $display->context);
414     }
415   }
416   return is_object($display) ? $display : FALSE;
419 function og_panels_form_validate($form_id, $form_values, $form) {
420   $pathblacklist = array('view', 'edit', 'delete', 'outline', 'load', 'render', 'clone');
421   if (in_array($form_values['path'], $pathblacklist)) {
422     form_error($form['path'], t('%path is a reserved system path, and cannot be used for a group page. Please enter another path.', array('%path' => $form_values['path']))); 
423   }
424   else if (preg_match("/[^A-Za-z0-9-]/", $form_values['path'])) {
425     form_error($form['path'], t('Panel paths may only contain alphanumeric characters and dashes.'));
426   }
427   else if (db_result(db_query("SELECT path FROM {og_panels} WHERE path = '%s' AND did <> %d AND nid = %d", $form_values['path'], $form_values['did'], $form_values['nid']))) {
428     form_error($form['path'], t("That path is currently in use by another one of your group's pages. Please enter another path."));
429   }
433  * INSERT or UPDATE a new og_panel. If insert, redirect to layout form.
434  * 
435  * @return void
436  **/
437 function og_panels_form_submit($form_id, $form_values) {
438   if ($form_values['did']) {
439     $sql = "UPDATE {og_panels} SET page_title='%s', path='%s', published=%d, show_blocks=%d WHERE did = %d";
440     db_query($sql, $form_values['page_title'], $form_values['path'], $form_values['published'], $form_values['show_blocks'], $form_values['did']);
441     drupal_set_message(t('Group page updated.'));
442   }
443   else {
444     // Create a new display and record that.
445     $display = panels_new_display();
446     panels_save_display($display);
447     $sql = "INSERT INTO {og_panels} (did, nid, page_title, path, published, show_blocks) VALUES (%d, %d, '%s', '%s', %d, %d)";
448     db_query($sql, $display->did, $form_values['nid'], $form_values['page_title'], $form_values['path'], $form_values['published'], $form_values['show_blocks']);
449     drupal_set_message(t('Group page created.'));
450     return 'node/'. $form_values['nid']. "/og_panels/$display->did/panel_layout";
451   }
454 function og_panels_set_breadcrumb($section, $group_node = NULL) {
455   switch ($section) {
456     case 'panel_edit':
457       $bc[] = l(t('Home'), '');
458       $bc[] = l($group_node->title, "node/$group_node->nid");
459       $bc[] = l(t('Pages'), "node/$group_node->nid/og_panels");
460   }
461   drupal_set_breadcrumb($bc);
464 function og_panels_nodeapi($node, $op) {
465   switch ($op) {
466     case 'delete':
467       if ($og_panels = og_panels_get_all($node->nid)) {
468         foreach ($og_panels as $og_panel) {
469           panels_delete_display($og_panel->did);
470         }
471         $sql = "DELETE FROM {og_panels} WHERE nid = %d";
472         db_query($sql, $node->nid);
473         drupal_set_message(t('Organic groups panel pages deleted.'));
474       }
475       break;
476   }
479 // ---------------------------------------------------------------------------
480 // Meat of the Panels API; almost completely passing through to panels.module
483  * Pass through to the panels layout editor.
484  * 
485  * @param int $did
486  *  the $did of the og_panel to be edited. 
487  * 
488  * @param object $group_node
489  *  the node object to which the og_panel is attached.
490  */
491 function og_panels_edit_layout($did, $group_node) {
492   og_panels_set_breadcrumb('panel_edit', $group_node);
493   $display = og_panels_load_display($did, $group_node); // TODO I don't believe that having the context present is necessary for editing the layout.
494   return panels_edit_layout($display, t('Save'), "node/$group_node->nid/og_panels");
498  * Pass through to the panels layout settings editor.
499  * 
500  * @param int $did
501  *  the $did of the og_panel to be edited. 
502  * 
503  * @param object $group_node
504  *  the node object to which the og_panel is attached.
505  */
506 function og_panels_edit_layout_settings($did, $group_node) {
507   og_panels_set_breadcrumb('panel_edit', $group_node);
508   $display = og_panels_load_display($did);
509   return panels_edit_layout_settings($display, t('Save'), "node/$group_node->nid/og_panels");
513  * Pass through to the panels content editor.
514  * 
515  * @param int $did
516  *  the $did of the og_panel to be edited. 
517  * 
518  * @param object $group_node
519  *  the node object to which the og_panel is attached.
520  */
521 function og_panels_edit_content($did, $group_node) {
522   og_panels_set_breadcrumb('panel_edit', $group_node);
523   $display = og_panels_load_display($did, $group_node, TRUE);
524   // Print this with theme('page') so that blocks are disabled while editing a display.
525   // This is important because negative margins in common block layouts (i.e, Garland)
526   // messes up the drag & drop.
527   print theme('page', panels_edit($display, "node/$group_node->nid/og_panels", $display->content_types), FALSE);
530 function og_panels_admin_content() {
531   panels_load_include('common');
532   return drupal_get_form('panels_common_settings', 'og_panels');
536  * Implementation of hook_panels_contexts()
537  * 
538  */
539 function og_panels_panels_contexts() {
540   include_once './'. drupal_get_path('module', 'og_panels') .'/includes/groupcontext.inc';
541   $args['group'] = array(
542     'title' => t('Group'),
543     'description' => t('A node object that is flagged as an OG group type.'),
544     'context' => 'og_panels_context_create_group',
545     'settings form' => 'og_panels_context_group_settings_form',
546     'settings form validate' => 'og_panels_context_group_settings_form_validate',
547     'keyword' => 'group',
548     'context name' => 'group',
549   );
550   return $args;
554  * Implementation of hook_panels_content_types()
555  */
556 function og_panels_panels_content_types() {
557   include_once './'. drupal_get_path('module', 'og_panels') .'/includes/groupcontent.inc';
558   $items['og_mission'] = array(
559     'title' => t('OG mission'),
560     'content_types' => 'og_panels_ct_list_mission',
561     'single' => TRUE, // only provides a single content type
562     'render callback' => 'og_panels_ct_render_callback_mission',
563 //      'add callback' => 'og_panels_content_types_add_callback',
564 //      'edit callback' => 'og_panels_content_types_edit_callback',
565     'title callback' => 'og_panels_ct_title_callback_mission',
566 //    'add submit callback' => 'panels_admin_submit_group',
567 //    'edit submit callback' => 'panels_admin_submit_group',
568 //    'validate callback' => 'panels_admin_validate_group',
569   );
570   $items['og_description'] = array(
571     'title' => t('OG description'),
572     'content_types' => 'og_panels_ct_list_description',
573     'single' => TRUE, // only provides a single content type
574     'render callback' => 'og_panels_ct_render_callback_description',
575     'title callback' => 'og_panels_ct_title_callback_description',
576   );
577   
578     $items['og_subscribers'] = array(
579       'title' => t('OG members'),
580       'content_types' => 'og_panels_ct_list_subscribers',
581       'single' => TRUE, // only provides a single content type
582       'render callback' => 'og_panels_ct_render_callback_subscribers',
583       'add callback' => 'og_panels_content_types_addedit_callback_subscribers',
584       'edit callback' => 'og_panels_content_types_addedit_callback_subscribers',
585       'title callback' => 'og_panels_ct_title_callback_subscribers',
586       'add validate callback' => 'og_panels_content_types_validate_callback_subscribers',
587       'edit validate callback' => 'og_panels_content_types_validate_callback_subscribers',
588     );
589     
590     if (module_exists('search')) {
591       $items['og_search'] = array(
592         'title' => t('Group search'),
593         'content_types' => 'og_panels_ct_list_search',
594         'single' => TRUE, // only provides a single content type
595         'render callback' => 'og_panels_ct_render_callback_search',
596         'title callback' => 'og_panels_ct_title_callback_search',
597       );
598     }
599     
600     if (og_is_picture()) {
601       $items['og_faces'] = array(
602         'title' => t('OG faces'),
603         'content_types' => 'og_panels_ct_list_faces',
604         'single' => TRUE, // only provides a single content type
605         'render callback' => 'og_panels_ct_render_callback_faces',
606         'add callback' => 'og_panels_content_types_addedit_callback_faces',
607         'edit callback' => 'og_panels_content_types_addedit_callback_faces',
608         'title callback' => 'og_panels_ct_title_callback_faces',
609         'add validate callback' => 'og_panels_content_types_validate_callback_faces',
610         'edit validate callback' => 'og_panels_content_types_validate_callback_faces',
611       );
612       
613     }    
614   return $items;
617 // An implementation of hook_panels_relationships.
618 function og_panels_panels_relationships() {
619   include_once './'. drupal_get_path('module', 'og_panels') .'/includes/grouprelationships.inc';
620   $args['group_from_node'] = array(
621     'title' => t('Group from node'),
622     'keyword' => 'group',
623     'description' => t('Adds a group from a node context; if multiple groups are associated with a node, this will get the "first" group only.'),
624     'required context' => new panels_required_context(t('Node'), 'node'),
625     'context' => 'panels_group_from_node_context',
626   );
627   return $args;
630 // An implementation of hook_panels_block_info. We have to prefix with 'og' and not 'og_panels'.
631 function og_panels_block_info($module, $delta, &$info) {
632   switch ($delta) {
633     case 2:
634       // Provide alternate versions as content items
635       unset($info);
636       break;
637     default:
638       $info['icon'] = 'images/user-multiple.png';
639       $info['required context'] = new panels_required_context(t('Group'), 'group');
640       $info['path'] = drupal_get_path('module', 'og_panels'). '/';
641       $info['category'] = t('Organic groups');
642       break;
643   }
644   
645   // These blocks do not need group context.
646   if ($delta == 3 || $delta == 6) {
647     unset($info['required context']);
648   }