Issue #1478590 by rv0: add new permission to access the administration page.
[project/og_menu.git] / og_menu.module
1 <?php
2
3 /**
4 * @file
5 * Integrates Menu with Organic Groups.
6 * Lots of menu forms duplication in OG context.
7 */
8
9 /**
10 * Implements hook_permission().
11 */
12 function og_menu_permission() {
13 return array(
14 'administer og menu configuration' => array(
15 'title' => t('Administer OG Menu configuration'),
16 'description' => t('Grant access to the global OG Menu configuration.'),
17 ),
18 'administer og menu' => array(
19 'title' => t('Administer OG menus'),
20 'description' => t('Administer custom menus for all groups.'),
21 ),
22 );
23 }
24
25 /**
26 * Implements hook_og_permission().
27 */
28 function og_menu_og_permission() {
29 return array(
30 'administer og menu' => array(
31 'title' => t('Administer OG menus'),
32 'description' => t('Administer custom menus in the group context'),
33 ),
34 );
35 }
36
37 /**
38 * Implements hook_og_ui_get_group_admin().
39 * */
40 function og_menu_og_ui_get_group_admin($group_type, $gid) {
41 $items = array();
42
43 if (og_user_access($group_type, $gid, 'administer og menu')) {
44 $items['menus'] = array(
45 'title' => t('Menus'),
46 'description' => t('Manage group menus.'),
47 'href' => 'admin/menus',
48 );
49 }
50
51 return $items;
52 }
53
54 /**
55 * Implements hook_help().
56 */
57 function og_menu_help($path, $arg) {
58 switch ($path) {
59 case 'admin/structure/og_menu':
60 return '<p>' . t('Add new menus on the <a href="@menu">Menu administration page</a>.', array('@menu' => url('admin/structure/menu'))) . '</p>';
61 break;
62 }
63 if ($path == 'group/%/%/admin/menus' && module_exists('block')) {
64 if (!variable_get('og_menu_show_blocks', FALSE)) {
65 return '<p>' . t('With the current setting, OG Menus will not be
66 exposed as blocks on the blocks administration page. Use the OG Menu
67 supplied menu blocks on the <a href="@blocks">Blocks administration
68 page</a>.', array('@blocks' => url('admin/structure/block'))) . '</p>';
69 }
70 else {
71 return '<p>' . t('Each menu has a corresponding block that is managed on
72 the <a href="@blocks">Blocks administration page</a>.',
73 array('@blocks' => url('admin/structure/block'))) . '</p>';
74 }
75 }
76 }
77
78 /**
79 * Implements hook_menu().
80 *
81 * @todo Add MENU_LOCAL_ACTION for adding an OG Menu? Meanwhile fix it in hook_help().
82 */
83 function og_menu_menu() {
84 $items = array();
85 $items['group/%/%/admin/menus'] = array(
86 'title' => 'Menus',
87 'page callback' => 'og_menu_overview_page',
88 'page arguments' => array(1, 2),
89 'access callback' => 'og_menu_access',
90 'access arguments' => array(1, 2),
91 'weight' => 10,
92 'file' => 'og_menu.pages.inc',
93 );
94 $items['group/%/%/admin/menus/list'] = array(
95 'title' => 'List menus',
96 'weight' => -10,
97 'type' => MENU_DEFAULT_LOCAL_TASK,
98 );
99 $items['group/%/%/admin/menus/add'] = array(
100 'title' => 'Add menu',
101 'page callback' => 'drupal_get_form',
102 'page arguments' => array('og_menu_edit_menu_form', 'add', 1, 2),
103 'access callback' => 'og_menu_access',
104 'access arguments' => array(1, 2, 'new-menu'),
105 'type' => MENU_LOCAL_ACTION,
106 'weight' => 1,
107 'file' => 'og_menu.pages.inc',
108 );
109 $items['group/%/%/admin/menus/%menu'] = array(
110 'title' => 'Customize menu',
111 'page callback' => 'drupal_get_form',
112 'page arguments' => array('og_menu_overview_form', 1, 2, 5),
113 'access callback' => 'og_menu_access',
114 'access arguments' => array(1, 2),
115 'type' => MENU_CALLBACK,
116 'weight' => 1,
117 'file' => 'og_menu.pages.inc',
118 );
119 $items['group/%/%/admin/menus/%menu/list'] = array(
120 'title' => 'List items',
121 'weight' => -10,
122 'type' => MENU_DEFAULT_LOCAL_TASK,
123 );
124 $items['group/%/%/admin/menus/%menu/add'] = array(
125 'title' => 'Add item',
126 'page callback' => 'drupal_get_form',
127 'page arguments' => array('og_menu_edit_item_form', 'add', 1, 2, 5),
128 'access callback' => 'og_menu_access',
129 'access arguments' => array(1, 2),
130 'type' => MENU_LOCAL_TASK,
131 'weight' => 1,
132 'file' => 'og_menu.pages.inc',
133 );
134 $items['group/%/%/admin/menus/%menu/edit'] = array(
135 'title' => 'Edit menu',
136 'page callback' => 'drupal_get_form',
137 'page arguments' => array('og_menu_edit_menu_form', 'edit', 1, 2, 5),
138 'access callback' => 'og_menu_access',
139 'access arguments' => array(1, 2),
140 'type' => MENU_LOCAL_TASK,
141 'weight' => 1,
142 'file' => 'og_menu.pages.inc',
143 );
144 $items['group/%/%/admin/menus/%menu/delete'] = array(
145 'title' => 'Delete menu',
146 'page callback' => 'drupal_get_form',
147 'page arguments' => array('og_menu_delete_menu_confirm', 5, 1, 2),
148 'access callback' => 'og_menu_access',
149 'access arguments' => array(1, 2),
150 'type' => MENU_CALLBACK,
151 'weight' => 1,
152 'file' => 'og_menu.pages.inc',
153 );
154 $items['group/%/%/admin/menus/%menu/item/%menu_link/edit'] = array(
155 'title' => 'Edit menu item',
156 'page callback' => 'drupal_get_form',
157 'page arguments' => array('og_menu_edit_item_form', 'edit', 1, 2, 5, 7),
158 'access callback' => 'og_menu_access',
159 'access arguments' => array(1, 2),
160 'type' => MENU_LOCAL_TASK,
161 'weight' => 1,
162 'file' => 'og_menu.pages.inc',
163 );
164 $items['group/%/%/admin/menus/%menu/item/%menu_link/delete'] = array(
165 'title' => 'Delete menu item',
166 'page callback' => 'drupal_get_form',
167 'page arguments' => array('og_menu_delete_item_form', 7, 1, 2, 5),
168 'access callback' => 'og_menu_access',
169 'access arguments' => array(1, 2),
170 'type' => MENU_CALLBACK,
171 'weight' => 1,
172 'file' => 'og_menu.pages.inc',
173 );
174 $items['admin/config/group/og_menu'] = array(
175 'title' => 'OG menu settings',
176 'description' => 'Configuration for Organic groups menu',
177 'page callback' => 'drupal_get_form',
178 'page arguments' => array('og_menu_config_form'),
179 'access arguments' => array('administer og menu configuration'),
180 'type' => MENU_NORMAL_ITEM,
181 'file' => 'og_menu.pages.inc',
182 );
183 $items['admin/structure/og_menu'] = array(
184 'title' => 'Organic groups menus',
185 'description' => 'Add new organic groups menus to your site, edit existing ones, and rename and reorganize menu links.',
186 'page callback' => 'drupal_get_form',
187 'page arguments' => array('og_admin_menu_overview_form'),
188 'access callback' => 'user_access',
189 'access arguments' => array('administer menu'),
190 'type' => MENU_NORMAL_ITEM,
191 'file' => 'og_menu.pages.inc',
192 );
193 $items['og_menu/autocomplete'] = array(
194 'page callback' => '_og_menu_autocomplete',
195 'access arguments' => array('og_menu_access'),
196 'type' => MENU_CALLBACK,
197 );
198 return $items;
199 }
200
201 /**
202 * Implements hook_theme_registry_alter().
203 */
204 function og_menu_theme_registry_alter(&$theme_registry) {
205 $theme_registry['block']['theme paths'][] = drupal_get_path('module', 'og_menu');
206 }
207
208 /**
209 * Implements hook_block_info().
210 */
211 function og_menu_block_info() {
212 $blocks = array(
213 'og_single_menu_block' => array('info' => t('OG Menu : single'), 'cache' => DRUPAL_NO_CACHE),
214 'og_multi_menu_block' => array('info' => t('OG Menu : multiple'), 'cache' => DRUPAL_NO_CACHE),
215 );
216 return $blocks;
217 }
218
219 /**
220 * Implements hook_block_view().
221 */
222 function og_menu_block_view($delta = '') {
223 $block = array();
224 $context = og_context();
225 if ($delta == 'og_single_menu_block' && $context) {
226 $menus = og_menu_get_group_menus(array(
227 $context['group_type'] => array($context['gid'])
228 ));
229 $menu = array_shift($menus);
230
231 if ($menu) {
232 if (variable_get('og_menu_block_links', FALSE)) {
233 $block['subject'] = l($menu['title'], $menu['group_type'] . '/' . $menu['gid']);
234 }
235 else {
236 $block['subject'] = check_plain($menu['title']);
237 }
238 $block['content'] = menu_tree($menu['menu_name']);
239 }
240 }
241 if ($delta == 'og_multi_menu_block' && $context) { // @todo Test this!!
242 drupal_add_css(drupal_get_path('module', 'og_menu') . '/og_menu.css');
243 drupal_add_css(drupal_get_path('module', 'og_menu') . '/og_menu.css');
244 $menus = og_menu_get_group_menus(array(
245 $context['group_type'] => array($context['gid'])
246 ));
247 $plural = count($menus) > 1 ? TRUE : FALSE;
248 foreach ($menus as $menu) {
249 $title = ''; $content = '';
250 if (variable_get('og_menu_block_links', FALSE)) {
251 $title = l($menu['title'], $menu['group_type'] . '/' . $menu['gid']);
252 }
253 else {
254 $title = check_plain($menu['title']);
255 }
256 if ($plural) {
257 $content = "<div class='block-og-menu-inset'><h2>{$title}</h2>" . render(menu_tree($menu['menu_name'])) . "</div>";
258 }
259 else {
260 $block['subject'] = $title;
261 $content = render(menu_tree($menu['menu_name']));
262 }
263 $block['content'] = isset($block['content']) ? $block['content'] . $content : $content;
264 if ($plural) {
265 $block['subject'] = '';
266 }
267 }
268 }
269 return $block;
270 }
271
272 /**
273 * Implements hook_field_extra_fields().
274 */
275 function og_menu_field_extra_fields() {
276 $extra = array();
277 foreach (node_type_get_types() as $type) {
278 if (og_is_group_type('node', $type->type)) { // We only need to enable OG Menu on group types.
279 $extra['node'][$type->type] = array(
280 'form' => array(
281 'og_menu' => array(
282 'label' => t('OG Menu'),
283 'description' => t('Enable OG Menu'),
284 'weight' => 0,
285 )
286 )
287 );
288 }
289 }
290 return $extra;
291 }
292
293 /**
294 * Returns the current group context's nid.
295 */
296 function og_menu_get_context() {
297 $context = og_context();
298 return (isset($context['gid']) ? $context['gid'] : 0);
299 }
300
301 /**
302 * Implements hook_form_FORMID_alter().
303 *
304 * Alter the node form's menu form.
305 * We modify the forms for group content and group content types.
306 */
307 function og_menu_form_node_form_alter(&$form, &$form_state) {
308 $type = $form['#node']->type;
309 // Group type.
310 if (og_is_group_type('node', $type)) {
311 $og_menu_default_value = isset($form['nid']['#value']) ? !empty($form['#node']->og_menu) : variable_get('og_menu_create_by_default', FALSE);
312 $form['og_menu'] = array(
313 '#type' => 'checkbox',
314 '#title' => t('Enable menu for this group'),
315 '#default_value' => $og_menu_default_value,
316 '#description' => t('Check to create a menu for this group. Uncheck to delete all menus associated with this group.'),
317 );
318 // @todo If we're going to delete all of the groups menus,
319 // we should ask the user for confirmation
320 //$form['#submit'][] = 'og_menu_group_form_validate';
321 }
322 if (og_is_group_content_type('node', $type)
323 && variable_get('og_menu_enable_' . $type, FALSE)) {
324 // If there is context and the user doesn't have permission on the group,
325 // they shouldn't be allowed to change the menu at all.
326 $context = og_context();
327 if ($context && !og_user_access($context['group_type'], $context['gid'], 'administer og menu') && !user_access('administer menu') && !user_access('administer og menu')) {
328 return;
329 }
330 // Available menus were discovered in og_menu_node_prepare().
331 $menus = $form['#node']->storage['og_menu'];
332 $list = array();
333 $settings['admin'] = user_access('administer menu');
334 if (!empty($menus)) {
335 foreach ($menus as $menu) {
336 $list[$menu['menu_name']] = $menu['title'];
337 $settings['menus'][$menu['menu_name']] = $menu['gid'];
338 }
339 // If user has administer menu permission, also show other menu options.
340 if (user_access('administer menu')) {
341 // Gets menus available to this content type.
342 $type_menus = variable_get('menu_options_' . $type, array('main-menu' => 'main-menu'));
343 $available_menus = array();
344 // Get all existing menus with their name.
345 $result = db_query("SELECT menu_name, title FROM {menu_custom} ORDER BY title");
346 while ($menu = $result->fetchObject()) {
347 if (in_array($menu->menu_name, $type_menus)) {
348 $available_menus[$menu->menu_name] = $menu->title;
349 }
350 }
351 // We want to merge the menus the user has available anyway and the OG ones
352 $merged_list = array_merge($available_menus, $list);
353 }
354 else {
355 $merged_list = $list;
356 }
357
358 $link = $form['#node']->menu;
359
360 // Menu parent options will format the list in a way Drupal expects and give children, etc
361 $options = menu_parent_options($merged_list, array('mlid' => 0));
362
363 // If user does not have administer menu, this fieldset wont be created.
364 if (!isset($form['menu'])) {
365 if (empty($options)) {
366 return;
367 }
368 _og_menu_add_menufieldset($form, $options);
369 }
370
371 if ($nid = $form['nid']['#value']) {
372 $form['menu']['link']['parent']['#default_value'] = $link['menu_name'] . ':' . $link['plid'];
373 }
374 $form['menu']['#access'] = !empty($options);
375 $form['menu']['#attached']['js'][] = drupal_get_path('module', 'og_menu') . '/og_menu.js';
376 $form['menu']['#attached']['js'][] = array(
377 'data' => array('og_menu' => $settings),
378 'type' => 'setting',
379 );
380 $form['menu']['#settings'] = $merged_list;
381 $form['menu']['link']['parent']['#options'] = $options;
382 if (!user_access('administer menu')) {
383 $form['#validate'][] = 'og_menu_node_form_validate';
384 }
385 }
386 }
387 }
388
389
390 /**
391 * Implements hook_menu_insert().
392 *
393 * This is used to automatically add links a series of
394 * predefined links to a new OG Menu.
395 */
396 function og_menu_menu_insert($menu) {
397 // Check to see if this is the many og_menu
398 if (preg_match('/^menu-og-(\d+)$/', $menu['menu_name'], $matches)) {
399
400 // Get Default Menu Items from variable
401 $node = node_load($matches[1]);
402 $default_links = explode("\n", variable_get('og_menu_default_links_' . strtolower($node->type), ''));
403
404 foreach ($default_links as $default_link) {
405 $link_parts = explode("|", $default_link);
406 $link_parts[0] = token_replace($link_parts[0], array('node' => node_load($matches[1])));
407 // Create link
408 $link = array(
409 'link_path' => $link_parts[0],
410 'link_title' => (isset($link_parts[1])) ? $link_parts[1]: $link_parts[0],
411 'menu_name' => $menu['menu_name'],
412 'router_path' => 'faculty/%',
413 );
414 $mlid = menu_link_save($link);
415 }
416 }
417 }
418
419 /**
420 * Implements hook_form_FORMID_alter().
421 */
422 function og_menu_form_menu_edit_menu_alter(&$form, &$form_state) {
423 $types = node_type_get_types();
424 $gtypes = array();
425 foreach ($types as $type) {
426 if (og_is_group_type('node', $type->type))
427 $gtypes[] = $type->type;
428 }
429
430 $types = $gtypes;
431
432 if (count($types) > 0) {
433 $options = array('' => '--');
434 $values = array();
435 // Populate gids
436 if (user_access('administer group')) {
437 $result = db_query("SELECT distinct ogm.gid, n.title FROM {og_membership} ogm LEFT JOIN {node} n ON n.nid = ogm.gid WHERE entity_type='node'");
438 foreach ($result as $group) {
439 $options[$group->gid] = $group->title;
440 }
441 }
442 else {
443 global $user;
444
445 $gids = og_menu_get_node_groups('user', $user);
446 $groups = node_load_multiple($gids);
447 if (!empty($groups)) {
448 foreach ($groups as $gid => $group) {
449 $options[$gid] = $group->title;
450 }
451 }
452 }
453
454 $ogm = db_select('og_menu', 'gid')
455 ->fields('gid')
456 ->condition('menu_name', $form['menu_name']['#default_value'], '=')
457 ->execute()
458 ->fetchAssoc();
459 $gid = $ogm['gid'];
460
461 $og = $gid ? entity_load_single('node', $gid) : NULL;
462 // Add menu og assignment to the form
463 switch (variable_get('og_menu_assignment', 'autocomplete')) {
464 case 'autocomplete':
465 $form['og_menu_gid'] = array(
466 '#title' => t('Enable this menu for the following group'),
467 '#type' => 'textfield',
468 '#default_value' => !is_null($gid) ? $og->title . ' [gid:' . $gid . ']' : '',
469 '#autocomplete_path' => 'og_menu/autocomplete',
470 );
471 break;
472
473 case 'select':
474 $form['og_menu_gid'] = array(
475 '#title' => t('Enable this menu for the following group'),
476 '#type' => 'select',
477 '#options' => $options,
478 '#default_value' => !is_null($gid) ? $gid : '',
479 '#weight' => 1,
480 );
481 break;
482 default;
483 }
484 if (!user_access('administer menu')) {
485 $form['og_menu_gid']['#required'] = TRUE;
486 }
487 if (!isset($form['submit']['#weight'])) {
488 $form['submit']['#weight'] = 2;
489 }
490 $form['#submit'][] = 'og_menu_edit_menu_form_submit';
491 }
492 }
493
494 /**
495 * Implements hook_form_FORMID_alter().
496 *
497 * Integration with menu module for node type admin page.
498 * Hides OG Menus from available menu settings.
499 */
500 function og_menu_form_node_type_form_alter(&$form, &$form_state) {
501 if (!variable_get('og_menu_show_nodetype', FALSE)) {
502 // Remove OG Menus from the list by default.
503 $result = db_query("SELECT mc.menu_name FROM {menu_custom} mc, {og_menu} ogm WHERE ogm.menu_name = mc.menu_name")->fetchCol();
504 foreach ($result as $ogblock) {
505 unset($form['menu']['menu_options']['#options'][$ogblock]);
506 }
507 }
508 // Provide a setting to enable OG Menus on this content type.
509 $form['menu']['og_menu_enable'] = array(
510 '#type' => 'checkbox',
511 '#title' => t("Enable for OG Menus"),
512 '#default_value' => variable_get('og_menu_enable_' . $form['#node_type']->type, FALSE),
513 '#description' => t("Allow nodes of this content type to be added to OG Menus."),
514 );
515 if (!og_is_group_content_type('node', $form['#node_type']->type)) {
516 $form['menu']['og_menu_enable']['#description'] .= ' <strong>';
517 $form['menu']['og_menu_enable']['#description'] .= t("This setting will not
518 have any effect until you enable this type as Group Content");
519 $form['menu']['og_menu_enable']['#description'] .= '</strong>';
520 }
521 }
522
523 /**
524 * Implements hook_form_FORMID_alter().
525 *
526 * Integration with Menu Position module for menu_position config page.
527 * Hides OG Menus from available parent options settings.
528 */
529 function og_menu_form_alter(&$form, &$form_state, $form_id) {
530 if ($form_id == 'menu_position_add_rule_form' || $form_id == 'menu_position_edit_rule_form') {
531 if (!variable_get('og_menu_show_menuposition', FALSE)) {
532 $mlid = !empty($form_state['#menu-position-rule']['mlid']) ? $form_state['#menu-position-rule']['mlid'] : NULL;
533 $menus = menu_get_menus();
534 // @todo convert to new database api functions
535 $result = db_query("SELECT mc.menu_name FROM {menu_custom} mc, {og_menu} ogm WHERE ogm.menu_name = mc.menu_name")->fetchCol();
536 foreach ($result as $ogblock) {
537 unset($menus[$ogblock]);
538 }
539 // Parent menu item.
540 if ($mlid) {
541 $options = menu_parent_options($menus, menu_link_load($mlid));
542 }
543 else {
544 $options = menu_parent_options($menus, array('mlid' => 0));
545 }
546 $form['plid']['#options'] = $options;
547 }
548 }
549 }
550
551 /**
552 * Implements hook_form_FORMID_alter().
553 */
554 function og_menu_form_block_admin_display_form_alter(&$form, &$form_state) {
555 // Only show og menu blocks on the block admin page if the user wants it.
556 if (!variable_get('og_menu_show_blocks', FALSE)) {
557 // @todo convert to new database api functions
558 $result = db_query("SELECT mc.menu_name FROM {menu_custom} mc, {og_menu} ogm WHERE ogm.menu_name = mc.menu_name")->fetchCol();
559 foreach ($result as $ogblock) {
560 unset($form['blocks']['menu_' . $ogblock]);
561 }
562 }
563 }
564
565 /**
566 * Implements hook_form_FORMID_alter().
567 */
568 function og_menu_form_menu_delete_menu_confirm_alter(&$form, &$form_state) {
569 $form['#submit'][] = 'og_menu_delete_menu_confirm_submit';
570 }
571
572 /**
573 * Implements hook_form_FORMID_alter().
574 *
575 * Integration with homebox module.
576 * Hides OG Menus from Homebox config page.
577 */
578 function og_menu_form_homebox_admin_display_form_alter(&$form, &$form_state) {
579 if (!variable_get('og_menu_show_homebox', FALSE)) {
580 // @todo convert to new database api functions
581 $result = db_query("SELECT mc.menu_name FROM {menu_custom} mc, {og_menu} ogm WHERE ogm.menu_name = mc.menu_name")->fetchCol();
582 foreach ($result as $ogblock) {
583 unset($form['menu_' . $ogblock]);
584 }
585 }
586 }
587
588 /**
589 * Implements hook_node_prepare().
590 */
591 function og_menu_node_prepare($node) {
592 $type = $node->type;
593 // $node is a group type.
594 if (og_is_group_type('node', $type)) {
595 if (!empty($node->nid)) {
596 $node->og_menu = og_menu_get_group_menus(array(
597 'node' => array($node->nid)
598 ));
599 }
600 }
601 if (og_is_group_content_type('node', $type)) {
602 // If there is context and the user doesn't have permission on the group,
603 // they shouldn't be allowed to change the menu at all.
604 $context = og_context();
605 if ($context && !og_user_access($context['group_type'], $context['gid'], 'administer og menu') && !user_access('administer menu') && !user_access('administer og menu')) {
606 return;
607 }
608 $groups = array();
609 $og_fields = og_get_group_audience_fields('node', $type);
610 foreach ($og_fields as $field_name => $label) {
611 $field = field_info_field($field_name);
612 $target_type = $field['settings']['target_type'];
613 // The handler delivers all available targets for each content type, skip
614 // the ids if we already have that type's results.
615 if (empty($groups[$target_type])) {
616 $instance = field_info_instance('node', $field_name, $type);
617 $instance['field_mode'] = 'default';
618 // Using the handler allows us to get user options from OG without
619 // running through all the user's groups.
620 $ids = entityreference_get_selection_handler($field, $instance)->getReferencableEntities();
621 if (!empty($ids)) {
622 $field_gids = array();
623 foreach ($ids as $key => $values) {
624 $field_gids += $values;
625 }
626 // Create an array similar to what og_get_entity_groups() returns.
627 $groups[$target_type] = array_keys($field_gids);
628 }
629 }
630 }
631 $menus = og_menu_get_group_menus($groups);
632 // Store the menus for later use in form_alter and form_validate
633 $node->storage['og_menu'] = $menus;
634 // $node is not a new node and menu link is not set
635 if (!empty($node->nid) && empty($node->menu['link_title']) && !empty($menus)) {
636 $menu_names = array();
637 foreach ($menus as $menu) {
638 $menu_names[] = $menu['menu_name'];
639 }
640 // This query comes from menu.modules node_prepare, and is how it does it.
641 $mlid = db_query_range("SELECT mlid FROM {menu_links} WHERE link_path = :path AND module = 'menu' AND menu_name IN (:type_menus) ORDER BY mlid ASC", 0, 1, array(
642 ':path' => 'node/' . $node->nid,
643 ':type_menus' => $menu_names,
644 ))
645 ->fetchField();
646 if ($mlid) {
647 // We've found something, so load the item and set that in the node form
648 $item = menu_link_load($mlid);
649 $options = menu_parent_options(array($item['menu_name']), $item);
650 if (!empty($options)) {
651 $node->menu = $item;
652 // Find the depth limit for the parent select.
653 if (!isset($node->menu['parent_depth_limit'])) {
654 $node->menu['parent_depth_limit'] = _menu_parent_depth_limit($node->menu);
655 }
656 }
657 }
658 }
659 }
660 }
661
662 /**
663 * Implements hook_node_insert().
664 */
665 function og_menu_node_insert($node) {
666 if (og_is_group_type('node', $node->type)) {
667 if ($node->og_menu) {
668 menu_save(array(
669 'menu_name' => 'menu-og-' . $node->nid,
670 'title' => $node->title,
671 'description' => t('OG Menu for') . ' ' . check_plain($node->title),
672 ));
673 og_menu_update_menu('menu-og-' . $node->nid, $node->nid, 'node');
674 }
675 }
676 }
677
678 /**
679 * Implements hook_node_update().
680 */
681 function og_menu_node_update($node) {
682 if (og_is_group_type('node', $node->type)) {
683 if (isset($node->og_menu)) {
684 if ($node->og_menu) {
685 $menu = og_menu_get_group_menus(array('node' => array($node->nid)));
686 if (empty($menu)) {
687 menu_save(array(
688 'menu_name' => 'menu-og-' . $node->nid,
689 'title' => $node->title,
690 'description' => t('OG Menu for') . ' ' . check_plain($node->title),
691 ));
692 og_menu_update_menu('menu-og-' . $node->nid, $node->nid, 'node');
693 }
694 }
695 else {
696 // Delete the associated menus.
697 // We can't assume that the menu name is 'menu-og-[gid]'
698 // we need to look up menus associated with this group
699 $result = db_select('og_menu', 'm')
700 ->fields('m', array('menu_name'))
701 ->condition('gid', $node->nid, '=')
702 ->condition('group_type', 'node', '=')
703 ->execute();
704
705 while ($record = $result->fetchAssoc()) {
706 $menu = menu_load($record['menu_name']);
707 menu_delete($menu);
708 og_menu_delete_menu($record['menu_name']);
709 }
710 }
711 }
712 // else = programmatic node save, do nothing.
713 }
714 }
715
716 /**
717 * Implements hook_node_delete().
718 */
719 function og_menu_node_delete($node) {
720 if (og_is_group_type('node', $node->type)) {
721 /* We need to be careful here. As users can create menu of whatever name,
722 * we can't just delete from menu_custom looking for 'menu-og-' . [gid]
723 * we need the gid of the group being deleted, see if its an og assosiated
724 * menu from og_menu and then from that menu name, delete it.
725 */
726 $result = db_select('og_menu', 'm')
727 ->fields('m', array('menu_name'))
728 ->condition('gid', $node->nid, '=')
729 ->condition('group_type', 'node', '=')
730 ->execute();
731
732 while ($record = $result->fetchAssoc()) {
733 $menu = menu_load($record['menu_name']);
734 menu_delete($menu);
735 og_menu_delete_menu($record['menu_name']);
736 }
737 }
738 }
739
740 /**
741 * Validation handler for OG group node forms.
742 * We will only end up here if we have confirmed that the node is a group type content
743 */
744 function og_menu_node_form_validate($form, &$form_state) {
745 // If the user didn't ask for a menu, we have nothing to do.
746 if (!isset($form_state['values']['menu']['enabled']) || $form_state['values']['menu']['enabled'] !== 1) {
747 return;
748 }
749
750 // Available menus were discovered in og_menu_node_prepare().
751 $menus = $form['#node']->storage['og_menu'];
752 $parents = explode(':', $form_state['values']['menu']['parent']);
753 $parent = $parents[0];
754 $gids = array();
755 $has_menu_access = FALSE;
756
757 $group_is_set = FALSE;
758
759 foreach (og_get_group_audience_fields('node', $form_state['values']['type']) as $field_name => $label) {
760 if (isset($form_state['values'][$field_name][LANGUAGE_NONE])) {
761 $group_is_set = TRUE;
762 foreach ($form_state['values'][$field_name][LANGUAGE_NONE] as $item => $gid) {
763 $gids[] = $gid['target_id'];
764 }
765 }
766 }
767
768 if (!$group_is_set) {
769 // It's possible that the user doesn't have permission to change
770 // the group audience once a piece of content has been created.
771 // In this case, we need to look it up.
772 $gids = og_get_entity_groups('node', $form_state['node']);
773 }
774 foreach ($menus as $menu) {
775 if ($menu['menu_name'] == $parent) {
776 // Check if user has access to the chosen menu parent
777 $has_menu_access = TRUE;
778 // Check if menu belongs to one of the selected groups
779 if (!in_array($menu['gid'], $gids)) {
780 form_set_error('og_groups', t('The menu you chose does not belong to the selected groups.'));
781 }
782 }
783 }
784 if (!$has_menu_access) {
785 form_set_error('menu][parent', t('You cannot add menu items to this menu. Choose another parent menu.'));
786 }
787 }
788
789 /**
790 * Updates internal record of group's menu id
791 */
792 function og_menu_update_menu($menu_name, $gid, $group_type) {
793 db_merge('og_menu')
794 ->key(array('menu_name' => $menu_name))
795 ->fields(array(
796 'gid' => $gid,
797 'group_type' => $group_type,
798 ))
799 ->execute();
800 }
801
802 /**
803 * Deletes menus for og menu table.
804 */
805 function og_menu_delete_menu($menu_name) {
806 db_delete('og_menu')
807 ->condition('menu_name', $menu_name)
808 ->execute();
809 }
810
811 /**
812 * Returns acessible menus for a given user or gids in a structured array.
813 *
814 * @param gids
815 * An optional array of groups as returned by og_get_entity_groups().
816 * @param user
817 * An optional array of the user object.
818 * @return
819 * A structured array with menus list.
820 */
821 function og_menu_get_group_menus($groups = NULL, $user = NULL) {
822 if (!$groups) {
823 $groups = og_get_entity_groups('user', $user);
824 }
825 $menus = array();
826 foreach ($groups as $group_type => $gids) {
827 foreach ($gids as $gid) {
828 $query = db_select('og_menu', 'om');
829 $query
830 ->join('menu_custom', 'm', 'om.menu_name = m.menu_name');
831 $query
832 ->fields('om', array('gid', 'group_type', 'menu_name'))
833 ->fields('m', array('title'))
834 ->condition('om.gid', $gid, '=')
835 ->condition('om.group_type', $group_type, '=');
836 $result = $query->execute();
837 while ($record = $result->fetchAssoc()) {
838 $menus[] = $record;
839 }
840 }
841 }
842 return $menus;
843 }
844
845 /**
846 * Access function.
847 *
848 * @param node
849 * The group node for which the menu is edited.
850 * @param menu
851 * The edited menu.
852 */
853 function og_menu_access($group_type, $gid, $op = NULL) {
854 if (!og_is_group($group_type, $gid)) {
855 return FALSE;
856 }
857 elseif (user_access('administer menu')) {
858 return TRUE;
859 }
860 elseif (user_access('administer og menu') || og_user_access_entity('administer og menu', $group_type, $gid)) {
861 if ($op == 'new-menu') {
862 $query = db_select('og_menu', 'ogm');
863 $query->condition('ogm.gid', $gid, '=');
864 $count = $query->countQuery()->execute()->fetchField();
865 $max = variable_get('og_menu_max_menus_per_group', 1);
866 if ($max > 0 && $count >= $max) {
867 return FALSE;
868 }
869 else {
870 return TRUE;
871 }
872 }
873 else {
874 // return true for all other cases edit menu, add/edit links
875 return TRUE;
876 }
877 }
878 return FALSE;
879 }
880
881 /**
882 * Generic redirect function.
883 *
884 * @param form
885 * The form array.
886 * @param form_state
887 * The form_state array.
888 */
889 function og_menu_redirect($form, &$form_state) {
890 $group_type = $form['og_menu_group_type']['#value'];
891 $gid = $form['og_menu_gid']['#value'];
892 $menu_name = $form['og_menu_name']['#value'];
893 $form_state['redirect'] = 'group/' . $group_type . '/' . $gid . '/admin/menus/' . $menu_name;
894 }
895
896 /**
897 * Submit handler used on various forms.
898 */
899 function og_menu_edit_menu_form_submit($form, &$form_state) {
900 $menu_name = $form_state['values']['menu_name'];
901 $gid = $form_state['values']['og_menu_gid'];
902 if (!empty($gid)) {
903 // If this is a new menu.
904 if ($form['#insert']) {
905 $menu_name = 'menu-' . $menu_name;
906 }
907 if (is_numeric($gid)) {
908 og_menu_update_menu($menu_name, $gid, 'node');
909 }
910 else {
911 preg_match('/^(?:\s*|(.*) )?\[\s*gid\s*:\s*(\d+)\s*\]$/', $gid, $matches);
912 if (!empty($matches)) {
913 $gid = $matches[count($matches) - 1];
914 if (is_numeric($gid)) {
915 og_menu_update_menu($menu_name, $gid, 'node');
916 }
917 }
918 else {
919 drupal_set_message(t('Cannot assign menu to invalid group, please retry'), 'error');
920 }
921 }
922 }
923 }
924
925 /**
926 * Submit handler used on various forms.
927 */
928 function og_menu_delete_menu_confirm_submit($form, &$form_state) {
929 $menu = $form['#menu'];
930 og_menu_delete_menu($menu['menu_name']);
931 }
932
933 /**
934 * Submit handler used on various forms.
935 */
936 function og_menu_delete_menu_confirm_submit_redirect($form, &$form_state) {
937 $group_type = $form['og_menu_group_type']['#value'];
938 $gid = $form['og_menu_gid']['#value'];
939 $form_state['redirect'] = 'group/' . $group_type . '/' . $gid . '/admin/menus';
940 }
941
942 /**
943 * Implements hook_menu_delete().
944 *
945 * Looks like og_menu didn't used to catch the case where a menu item was deleted
946 * in the admin area, and forgot to delete it's own db_record
947 */
948 function og_menu_menu_delete($menu) {
949 db_delete('og_menu')->condition('menu_name', $menu['menu_name'])->execute();
950 }
951
952 /**
953 * Override menu.module's menu_overview_page().
954 *
955 * We do this so that we can filter out og_menu created menus from the listing
956 * so that we don't flood the admin pages.
957 *
958 * @todo get this into og_menu_pages.inc
959 *
960 */
961 function og_admin_standard_menu_overview_page() {
962 $result = db_query("SELECT *
963 FROM {menu_custom} mc
964 WHERE NOT EXISTS (SELECT om.menu_name
965 FROM {og_menu} om
966 WHERE om.menu_name = mc.menu_name)
967 ORDER BY title;", array(), array('fetch' => PDO::FETCH_ASSOC));
968 $header = array(t('Title'), array(
969 'data' => t('Operations'),
970 'colspan' => '3',
971 ));
972 $rows = array();
973 foreach ($result as $menu) {
974 $row = array(theme('menu_admin_overview', array('title' => $menu['title'], 'name' => $menu['menu_name'], 'description' => $menu['description'])));
975 $row[] = array('data' => l(t('list links'), 'admin/structure/menu/manage/' . $menu['menu_name']));
976 $row[] = array('data' => l(t('edit menu'), 'admin/structure/menu/manage/' . $menu['menu_name'] . '/edit'));
977 $row[] = array('data' => l(t('add link'), 'admin/structure/menu/manage/' . $menu['menu_name'] . '/add'));
978 $rows[] = $row;
979 }
980
981 return theme('table', array('header' => $header, 'rows' => $rows));
982 }
983
984 /**
985 * Implements hook_menu_alter().
986 *
987 * We use this to override the /admin/structure/menu callback and replace it with
988 * our own og_admin_menu_overview_page().
989 */
990 function og_menu_menu_alter(&$items) {
991 $items['admin/structure/menu']['page callback'] = 'og_admin_standard_menu_overview_page';
992 $items['admin/structure/menu']['file'] = 'og_menu.module';
993 $items['admin/structure/menu']['module'] = 'og_menu';
994 }
995
996 /**
997 * Retrieve autocomplete suggestions for organic groups
998 */
999 function _og_menu_autocomplete($string) {
1000 $matches = array();
1001 $query = db_select('node', 'n');
1002 $query->distinct();
1003 $query->join('og_membership', 'og', 'n.nid = og.gid');
1004 $query->fields('og', array('gid'));
1005 $query->fields('n', array('title'));
1006 $query->condition('n.title', '%' . db_like($string) . '%', 'LIKE');
1007 $query->range(0, 10);
1008 $return = $query->execute();
1009 foreach ($return as $row) {
1010 $matches[$row->title . " [gid:$row->gid]"] = '<div class="og-autocomplete">' . $row->title . '</div>';
1011 }
1012 // return for JS
1013 drupal_json_output($matches);
1014 }
1015
1016 /**
1017 * Return a list of node groups corresponding to nodes
1018 *
1019 * @see og_get_entity_groups()
1020 * @param string $group_type the entity type .eg node, user
1021 * @param object the object in question .eg node user
1022 * @return array the gids corresponding to the criteria or empty
1023 */
1024 function og_menu_get_node_groups($group_type, $object) {
1025 $groups = og_get_entity_groups($group_type, $object);
1026
1027 if (!empty($groups['node'])) {
1028 $gids = $groups['node'];
1029 }
1030 else {
1031 $gids = array();
1032 }
1033
1034 return $gids;
1035 }
1036
1037 /**
1038 * Adds a standard menu fieldset to a form, mainly copied from menu.module.
1039 *
1040 * @param type $form the form we will add a menu fieldset to
1041 * @param type $optione
1042 */
1043 function _og_menu_add_menufieldset(&$form, $options) {
1044 $link = $form['#node']->menu;
1045
1046 $form['menu'] = array(
1047 '#type' => 'fieldset',
1048 '#title' => t('Menu settings'),
1049 '#collapsible' => TRUE,
1050 '#collapsed' => !$link['link_title'],
1051 '#group' => 'additional_settings',
1052 '#attached' => array(
1053 'js' => array(drupal_get_path('module', 'menu') . '/menu.js'),
1054 ),
1055 '#tree' => TRUE,
1056 '#weight' => -2,
1057 '#attributes' => array('class' => array('menu-link-form')),
1058 );
1059 $form['menu']['enabled'] = array(
1060 '#type' => 'checkbox',
1061 '#title' => t('Provide a menu link'),
1062 '#default_value' => (int) (bool) $link['mlid'],
1063 );
1064 $form['menu']['link'] = array(
1065 '#type' => 'container',
1066 '#parents' => array('menu'),
1067 '#states' => array(
1068 'invisible' => array(
1069 'input[name="menu[enabled]"]' => array('checked' => FALSE),
1070 ),
1071 ),
1072 );
1073
1074 // Populate the element with the link data.
1075 foreach (array('mlid', 'module', 'hidden', 'has_children', 'customized', 'options', 'expanded', 'hidden', 'parent_depth_limit') as $key) {
1076 $form['menu']['link'][$key] = array('#type' => 'value', '#value' => $link[$key]);
1077 }
1078
1079 $form['menu']['link']['link_title'] = array(
1080 '#type' => 'textfield',
1081 '#title' => t('Menu link title'),
1082 '#default_value' => $link['link_title'],
1083 );
1084
1085 $form['menu']['link']['description'] = array(
1086 '#type' => 'textarea',
1087 '#title' => t('Description'),
1088 '#default_value' => isset($link['options']['attributes']['title']) ? $link['options']['attributes']['title'] : '',
1089 '#rows' => 1,
1090 '#description' => t('Shown when hovering over the menu link.'),
1091 );
1092
1093 $default = ($link['mlid'] ? $link['menu_name'] . ':' . $link['plid'] : NULL);
1094 if (!isset($options[$default])) {
1095 $array = array_keys($options);
1096 $default = reset($array);
1097 }
1098 $form['menu']['link']['parent'] = array(
1099 '#type' => 'select',
1100 '#title' => t('Parent item'),
1101 '#default_value' => $default,
1102 '#options' => $options,
1103 '#attributes' => array('class' => array('menu-parent-select')),
1104 );
1105 $form['menu']['link']['weight'] = array(
1106 '#type' => 'weight',
1107 '#title' => t('Weight'),
1108 '#delta' => 50,
1109 '#default_value' => $link['weight'],
1110 '#description' => t('Menu links with smaller weights are displayed before links with larger weights.'),
1111 );
1112 }