You are here

site_map.module in Site map 7

site_map.module

Original author: Nic Ivy Now maintained by Fredrik Jonsson fredrik at combonet dot se.

File

site_map.module
View source
<?php

/**
 * @file
 * site_map.module
 *
 * Original author: Nic Ivy
 * Now maintained by Fredrik Jonsson fredrik at combonet dot se.
 */

/**
 * Implements hook_help().
 */
function site_map_help($path, $arg) {
  switch ($path) {
    case 'admin/help#site_map':
      $output = '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('Site Map provides a site map that gives visitors an overview of your site. It can also display the RSS feeds for all blogs and terms. Drupal generates the RSS feeds automatically but few seems to be aware that they exist.') . '</p>';
      $output .= '<p>' . t('The site map can display the following items:') . '</p>';
      $output .= '<ul>';
      $output .= '<li>' . t('A message to be displayed above the site map') . '</li>';
      $output .= '<li>' . t('The front page.') . '</li>';
      $output .= '<li>' . t('The latest blogs.') . '</li>';
      $output .= '<li>' . t('Any books that optionally will be displayed fully expanded.') . '</li>';
      $output .= '<li>' . t('Any menus that will be displayed fully expanded.') . '</li>';
      $output .= '<li>' . t('Any vocabulary with all the terms expanded. Optionally with node counts and RSS feeds.') . '</li>';
      $output .= '<li>' . t('Display comment RSS links if the Comment RSS module is installed.') . '</li>';
      $output .= '<li>' . t('A syndication block, the "more" link goes to the site map.') . '</li>';
      $output .= '</ul>';
      $output .= '<h3>' . t('Usage') . '</h3>';
      $output .= '<ol>';
      $output .= '<li>' . t('Have a look at the different settings in Administer » Site configuration » Site map') . '</li>';
      $output .= '<li>' . t('Visit <a href="@url_site_map">@url_site_map</a>', array(
        '@url_site_map' => url('admin/config/search/sitemap'),
      )) . '</li>';
      $output .= '</ol>';
      $output .= '<p>' . t('If you have many books/menus/vocabularies the Checkall module is recommended. It will implement "Check all / Uncheck all" for checkboxes on the site map settings page. http://drupal.org/project/checkall') . '</p>';
      $output .= '<h3>' . t('Site map term path (and Pathauto)') . '</h3>';
      $output .= '<p>' . t('There is a "depth" setting on the Site map settings page where you can adjust how site map constructs the term links.') . '</p>';
      $output .= '<p>' . t('For making Site map build the same path that Pathauto per default generates alias for you should set this to "-1" I believe.') . '</p>';
      return $output;
  }
}

/**
 * Implements hook_permission().
 */
function site_map_permission() {
  return array(
    'access site map' => array(
      'title' => t('View published site map'),
    ),
    'administer site map' => array(
      'title' => t('Administer site map'),
    ),
  );
}

/**
 * Implements hook_theme().
 */
function site_map_theme() {
  return array(
    'site_map' => array(
      'variables' => array(
        'message' => NULL,
        'rss_legend' => NULL,
        'front_page' => NULL,
        'blogs' => NULL,
        'books' => NULL,
        'menus' => NULL,
        'faq' => NULL,
        'taxonomys' => NULL,
        'additional' => NULL,
      ),
      'template' => 'site-map',
      'file' => 'includes/site_map.theme.inc',
    ),
    'site_map_box' => array(
      'variables' => array(
        'title' => NULL,
        'content' => NULL,
        'attributes' => array(),
      ),
      'file' => 'includes/site_map.theme.inc',
    ),
    'site_map_feed_icon' => array(
      'variables' => array(
        'url' => NULL,
        'name' => NULL,
        'type' => 'node',
      ),
      'file' => 'includes/site_map.theme.inc',
    ),
    'site_map_menu_link' => array(
      'render element' => 'element',
      'file' => 'includes/site_map.theme.inc',
    ),
    'site_map_menu_tree' => array(
      'render element' => 'tree',
      'file' => 'includes/site_map.theme.inc',
    ),
    'site_map_rss_legend' => array(
      'variables' => array(),
      'file' => 'includes/site_map.theme.inc',
    ),
    'site_map_order' => array(
      'render element' => 'element',
      'file' => 'includes/site_map.theme.inc',
    ),
  );
}

/**
 * Implements hook_menu().
 */
function site_map_menu() {
  $items['admin/config/search/sitemap'] = array(
    'title' => 'Site map',
    'description' => 'Control what should be displayed on the site map.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'site_map_admin_settings_form',
    ),
    'access arguments' => array(
      'administer site map',
    ),
    'file' => 'includes/site_map.admin.inc',
  );
  $items[variable_get('site_map_path', 'sitemap')] = array(
    'title callback' => '_site_map_title',
    'description' => 'Display a site map with RSS feeds.',
    'page callback' => 'site_map_page',
    'access arguments' => array(
      'access site map',
    ),
    'type' => MENU_SUGGESTED_ITEM,
  );
  return $items;
}

/**
 * Title callback for the sitemap page.
 *
 * @param string $default
 *   The default title that hook_menu provides.
 *
 * @return string
 *   The actual title of the page (customized or not).
 */
function _site_map_title($default = NULL) {

  // If there's a variable set, overriding the translatable title, use it.
  // Otherwise, use the built-in one or one of its translations.
  $var = variable_get('site_map_page_title', '');

  // @codingStandardsIgnoreLine
  return strlen($var) ? t($var) : t('Site map');
}

/**
 * Implements hook_block_info().
 */
function site_map_block_info() {
  $block['syndicate']['info'] = t('Syndicate (site map)');

  // Do no caching because $feedurl is different for blogs.
  // @codingStandardsIgnoreLine
  $blocks['syndicate']['cache'] = DRUPAL_NO_CACHE;
  $block['site_map']['info'] = t('Site map');
  return $block;
}

/**
 * Implements hook_block_view().
 */
function site_map_block_view($delta = '') {
  if (user_access('access content')) {
    switch ($delta) {
      case 'syndicate':
        $block['subject'] = t('Syndicate');
        if (arg(0) == 'blog') {
          $uid = arg(1);
          $feedurl = is_numeric($uid) ? "blog/{$uid}/feed" : 'blog/feed';
        }
        else {
          $feedurl = variable_get('site_map_rss_front', 'rss.xml');
        }
        $block['content'] = theme('feed_icon', array(
          'url' => $feedurl,
          'title' => t('Syndicate'),
        ));
        $block['content'] .= theme('more_link', array(
          'url' => 'sitemap',
          'title' => t('View the site map to see more RSS feeds.'),
        ));
        break;
      case 'site_map':
        $block['subject'] = _site_map_title();
        $block['content'] = site_map_content();
        break;
    }
    return $block;
  }
}

/**
 * Menu callback for the site map.
 */
function site_map_page() {
  drupal_set_title(_site_map_title());
  return site_map_content();
}

/**
 * The content of the site map page.
 */
function site_map_content() {
  if (variable_get('site_map_css', 0) != 1) {
    drupal_add_css(drupal_get_path('module', 'site_map') . '/styles/site_map.theme.css');
  }
  return theme('site_map');
}

/**
 * Menu callback for the site map front page.
 *
 * @return string
 *   Returns HTML string for front page site map.
 */
function _site_map_front_page() {
  $output = '';
  $class = array();
  $options = array();
  $title = t('Front page');
  $output = l(t('Front page of %sn', array(
    '%sn' => variable_get('site_name', 'Drupal'),
  )), '<front>', array(
    'html' => TRUE,
  ));
  if (variable_get('site_map_show_rss_links', 1) != 0) {
    $rss_link = theme('site_map_feed_icon', array(
      'url' => variable_get('site_map_rss_front', 'rss.xml'),
      'name' => 'front page',
    ));
    if (module_exists('commentrss') && variable_get('commentrss_site', COMMENTRSS_SITE_FRONT_PAGE)) {
      $rss_link .= ' ' . theme('site_map_feed_icon', array(
        'url' => 'crss',
        'name' => 'front page comments',
        'type' => 'comment',
      ));
    }
    if (variable_get('site_map_show_rss_links', 1) == 1) {
      $output .= ' ' . $rss_link;
    }
    else {
      $class[] = 'site-map-rss-left';
      $output = $rss_link . ' ' . $output;
    }
  }
  _site_map_set_option($options, 'site_map_show_titles', 1, 1, 'show_titles', TRUE);
  $class[] = 'site-map-box-front';
  $attributes = array(
    'class' => $class,
  );
  return theme('site_map_box', array(
    'title' => $title,
    'content' => $output,
    'attributes' => $attributes,
    'options' => $options,
  ));
}

/**
 * Render the latest blogs.
 *
 * @return string
 *   Returns HTML string of site map for blogs.
 */
function _site_map_blogs() {
  $output = '';
  $class = array();
  $options = array();
  if (module_exists('blog')) {
    $title = t('Blogs');
    $output = '<div class="description">' . t('Community blog and recent blog authors at %sn.', array(
      '%sn' => variable_get('site_name', 'Drupal'),
    )) . '</div>';
    $blog_link = l(t('All blogs'), 'blog');
    if (variable_get('site_map_show_rss_links', 1) != 0) {
      $rss_link = theme('site_map_feed_icon', array(
        'url' => 'blog/feed',
        'name' => 'all blogs',
      ));
      if (variable_get('site_map_show_rss_links', 1) == 1) {
        $blog_link .= ' ' . $rss_link;
      }
      else {
        $class[] = 'site-map-rss-left';
        $blog_link = $rss_link . ' ' . $blog_link;
      }
    }
    _site_map_set_option($options, 'site_map_show_titles', 1, 1, 'show_titles', TRUE);
    $blogs = array();
    $blogs[] = $blog_link;
    $query = db_select('node', 'n');
    $query
      ->join('users', 'u', 'u.uid = n.uid');
    $query
      ->fields('u', array(
      'uid',
      'name',
    ));
    $query
      ->addExpression('COUNT(u.uid)', 'numitems');
    $query
      ->condition('n.type', 'blog')
      ->condition('n.status', 1)
      ->groupBy('u.uid')
      ->groupBy('u.name')
      ->orderBy('numitems', 'DESC')
      ->orderBy('u.name', 'ASC')
      ->range(0, 10);
    $query
      ->addTag('node_access');
    $query
      ->distinct();
    $result = $query
      ->execute();
    foreach ($result as $blog) {
      if ($blog->uid == 0) {
        $blog->name = t('Anonymous');
      }
      $blog_item = t('<a href="@url">@name\'s blog</a> (@num_items)', array(
        '@url' => "blog/{$blog->uid}",
        '@name' => $blog->name,
        '@num_items' => $blog->numitems,
      ));
      if (variable_get('site_map_show_rss_links', 1) != 0) {
        $rss_link = theme('site_map_feed_icon', array(
          'url' => "blog/{$blog->uid}/feed",
          'name' => $blog->name . '\'s blog',
        ));
        if (variable_get('site_map_show_rss_links', 1) == 1) {
          $blog_item .= ' ' . $rss_link;
        }
        else {
          $blog_item = $rss_link . ' ' . $blog_item;
        }
      }
      $blogs[] = $blog_item;
    }
    $class[] = 'site-map-box-blog';
    $attributes = array(
      'class' => $class,
    );
    $output .= theme('item_list', array(
      'items' => $blogs,
    ));
    $output = theme('site_map_box', array(
      'title' => $title,
      'content' => $output,
      'attributes' => $attributes,
      'options' => $options,
    ));
  }
  return $output;
}

/**
 * Render the latest maps for audio.
 *
 * @return string
 *   Returns HTML string of site map for audio.
 */
function _site_map_audio() {
  $output = '';
  $class = array();
  $options = array();
  if (module_exists('audio')) {
    $title = t('Audio');
    $output = l(t('Audio content'), 'audio');
    if (variable_get('site_map_show_rss_links', 1) != 0) {
      $rss_link = theme('site_map_feed_icon', array(
        'url' => 'audio/feed',
        'name' => 'audio content',
      ));
      if (variable_get('site_map_show_rss_links', 1) == 1) {
        $output .= ' ' . $rss_link;
      }
      else {
        $class[] = 'site-map-rss-left';
        $output = $rss_link . ' ' . $output;
      }
    }
    _site_map_set_option($options, 'site_map_show_titles', 1, 1, 'show_titles', TRUE);
    $class[] = 'site-map-box-audio';
    $attributes = array(
      'class' => $class,
    );
    $output = theme('site_map_box', array(
      'title' => $title,
      'content' => $output,
      'attributes' => $attributes,
      'options' => $options,
    ));
  }
  return $output;
}

/**
 * Render the latest maps for video.
 *
 * @return string
 *   Returns HTML string of site map for video.
 */
function _site_map_video() {
  $output = '';
  $class = array();
  $options = array();
  if (module_exists('video')) {
    $title = t('Video');
    $output = l(t('Video content'), 'video');
    if (variable_get('site_map_show_rss_links', 1) != 0) {
      $rss_link = theme('site_map_feed_icon', array(
        'url' => 'video/feed',
        'name' => 'video content',
      ));
      if (variable_get('site_map_show_rss_links', 1) == 1) {
        $output .= ' ' . $rss_link;
      }
      else {
        $class[] = 'site-map-rss-left';
        $output = $rss_link . '  ' . $output;
      }
    }
    _site_map_set_option($options, 'site_map_show_titles', 1, 1, 'show_titles', TRUE);
    $class[] = 'site-map-box-video';
    $attributes = array(
      'class' => $class,
    );
    $output = theme('site_map_box', array(
      'title' => $title,
      'content' => $output,
      'attributes' => $attributes,
      'options' => $options,
    ));
  }
  return $output;
}

/**
 * Render the latest maps for books.
 *
 * @return string
 *   Returns HTML string of site map for video.
 */
function _site_map_books() {
  $output = '';
  $options = array();
  $book_titles = array();
  $mlid = array_filter(variable_get('site_map_show_books', array()));
  if (module_exists('book') && !empty($mlid)) {
    $books_expanded = variable_get('site_map_books_expanded', 1);
    $title = t('Books');
    $description = '<div class="description">' . t('Books at %sn.', array(
      '%sn' => variable_get('site_name', 'Drupal'),
    )) . '</div>';
    foreach (book_get_books() as $book) {
      if (in_array($book['mlid'], $mlid)) {

        // Use menu_tree_all_data to retrieve the expanded tree.
        $tree = menu_tree_all_data($book['menu_name']);
        if (module_exists('i18n_menu')) {
          $tree = i18n_menu_localize_tree($tree, $GLOBALS['language']->language);
        }

        // Add an alter hook so other modules can manipulate the book tree prior
        // to rendering.
        drupal_alter('site_map_book_tree', $tree);
        if ($books_expanded) {
          $tree_output = _site_map_menu_tree_output($tree);
          $output .= drupal_render($tree_output);
        }
        else {
          $data = array_shift($tree);
          $book_titles[] = theme('book_title_link', array(
            'link' => $data['link'],
          ));
        }
      }
    }
    _site_map_set_option($options, 'site_map_show_titles', 1, 1, 'show_titles', TRUE);
    if (!$books_expanded && !empty($book_titles)) {
      $output .= theme('item_list', array(
        'items' => $book_titles,
      ));
    }
    if (!empty($output)) {
      $attributes = array(
        'class' => array(
          'site-map-box-book',
        ),
      );
      $output = theme('site_map_box', array(
        'title' => $title,
        'content' => $description . $output,
        'attributes' => $attributes,
        'options' => $options,
      ));
    }
  }
  return $output;
}

/**
 * Render the latest maps for all the menus.
 *
 * @return string
 *   Returns HTML string of site map for menus.
 */
function _site_map_menus($mid) {
  $output = '';
  $class = array();
  $options = array();
  if (!empty($mid)) {
    $menu = menu_load($mid);

    // Use menu_tree_all_data to retrieve the expanded tree.
    $tree = menu_tree_all_data($mid);
    if (module_exists('i18n_menu')) {
      $tree = i18n_menu_localize_tree($tree, $GLOBALS['language']->language);
    }

    // Add an alter hook so that other modules can manipulate the
    // menu tree prior to rendering.
    $alter_mid = preg_replace('/[^a-z0-9_]+/', '_', $mid);
    drupal_alter(array(
      'site_map_menu_tree',
      'site_map_menu_tree_' . $alter_mid,
    ), $tree, $menu);
    $menu_display = _site_map_menu_tree_output($tree);
    $menu_html = drupal_render($menu_display);
    if (!empty($menu_html)) {

      // @codingStandardsIgnoreLine
      $title = t($menu['title']);
      if (module_exists('i18n_string')) {
        $m_array = array(
          'menu',
          'menu',
          $menu['menu_name'],
          'title',
        );
        $title = i18n_string_plain($m_array, $title);
      }
      _site_map_set_option($options, 'site_map_show_titles', 1, 1, 'show_titles', TRUE);
      $class[] = 'site-map-box-menu';
      $class[] = 'site-map-box-menu-' . $mid;
      $attributes = array(
        'class' => $class,
      );
      $output .= theme('site_map_box', array(
        'title' => $title,
        'content' => $menu_html,
        'attributes' => $attributes,
        'options' => $options,
      ));
    }
  }
  return $output;
}

/**
 * Render the latest maps for faq.
 *
 * @return string
 *   Returns HTML string of site map for faq.
 */
function _site_map_faq() {
  $output = '';
  $options = array();
  if (module_exists('faq')) {
    $title = variable_get('faq_title', t('Frequently Asked Questions'));
    $attributes = array(
      'class' => array(
        'site-map-box-faq',
      ),
    );
    $output = faq_get_faq_list();
    _site_map_set_option($options, 'site_map_show_titles', 1, 1, 'show_titles', TRUE);
    $output = theme('site_map_box', array(
      'title' => $title,
      'content' => $output,
      'attributes' => $attributes,
      'options' => $options,
    ));
  }
  return $output;
}

/**
 * Render the latest maps for the taxonomy tree.
 *
 * @return string
 *   Returns HTML string of site map for taxonomies.
 */
function _site_map_taxonomys($voc) {
  $output = '';
  $options = array();
  if (module_exists('taxonomy') && !empty($voc)) {
    if (module_exists('i18n_taxonomy')) {
      $voc->name = i18n_taxonomy_vocabulary_name($voc, $GLOBALS['language']->language);
    }
    $output .= _site_map_taxonomy_tree($voc->vid, $voc->name, $voc->description);
    _site_map_set_option($options, 'site_map_show_titles', 1, 1, 'show_titles', TRUE);
  }
  return $output;
}

/**
 * Render the taxonomy tree.
 *
 * @param string $vid
 *   The results of taxonomy_get_tree() with optional 'count' fields.
 * @param string $name
 *   An optional name for the tree. (Default: NULL)
 * @param string $description
 *   $description An optional description of the tree. (Default: NULL)
 *
 * @return string
 *   A string representing a rendered tree.
 */
function _site_map_taxonomy_tree($vid, $name = NULL, $description = NULL) {
  $output = '';
  $options = array();
  $class = array();
  if ($vid == variable_get('forum_nav_vocabulary', '')) {
    $title = l($name, 'forum');
    $threshold = variable_get('site_map_forum_threshold', -1);
    $forum_link = TRUE;
  }
  else {

    // @codingStandardsIgnoreLine
    $title = $name ? check_plain(t($name)) : '';
    $threshold = variable_get('site_map_term_threshold', 0);
    $forum_link = FALSE;
  }
  $title .= module_exists('commentrss') && variable_get('commentrss_term', FALSE) ? ' ' . theme('site_map_feed_icon', array(
    'url' => "crss/vocab/{$vid}",
    'name' => check_plain($name),
    'type' => 'comment',
  )) : '';
  $last_depth = -1;
  $output .= !empty($description) && variable_get('site_map_show_description', 1) ? '<div class="description">' . filter_xss_admin($description) . "</div>\n" : '';

  // Get the depth.
  $site_map_categories_depth = variable_get('site_map_categories_depth') ? variable_get('site_map_categories_depth') : NULL;
  if ($site_map_categories_depth == 'all') {
    $site_map_categories_depth = NULL;
  }
  $link_empty = variable_get('site_map_link_empty', FALSE);

  // Get the tree in a form that respects access control and translations.
  if (module_exists('i18n_taxonomy')) {

    // Taxonomy Translation.
    $tree = i18n_taxonomy_get_tree($vid, $GLOBALS['language']->language, 0, $site_map_categories_depth);
  }
  elseif (module_exists('entity_translation')) {

    // Entity Translation.
    // Setting the last parameter has performance implications, but adds
    // proper translation support: https://www.drupal.org/node/2418629.
    $tree = taxonomy_get_tree($vid, 0, $site_map_categories_depth, TRUE);
  }
  else {

    // If we don't care about translation, there's no need to lose performance.
    $tree = taxonomy_get_tree($vid, 0, $site_map_categories_depth);
  }
  foreach ($tree as $term) {
    $term->count = site_map_taxonomy_term_count_nodes($term->tid);
    if ($term->count <= $threshold) {
      continue;
    }
    if (module_exists('i18n_taxonomy')) {
      $term->name = i18n_taxonomy_term_name($term, $GLOBALS['language']->language);
    }

    // Adjust the depth of the <ul> based on the change
    // in $term->depth since the $last_depth.
    if ($term->depth > $last_depth) {
      for ($i = 0; $i < $term->depth - $last_depth; $i++) {
        $output .= "\n<ul>";
      }
    }
    elseif ($term->depth == $last_depth) {
      $output .= '</li>';
    }
    elseif ($term->depth < $last_depth) {
      for ($i = 0; $i < $last_depth - $term->depth; $i++) {
        $output .= "</li>\n</ul>\n</li>";
      }
    }

    // Display the $term.
    $output .= "\n<li>";
    $term_item = '';
    if ($forum_link) {
      $term_item .= l($term->name, 'forum/' . $term->tid, array(
        'attributes' => array(
          'title' => $term->description,
        ),
      ));
    }
    elseif ($link_empty || $term->count) {
      $term_item .= l($term->name, 'taxonomy/term/' . $term->tid, array(
        'attributes' => array(
          'title' => $term->description,
        ),
      ));
    }
    else {
      $term_item .= check_plain($term->name);
    }
    if (variable_get('site_map_show_count', 1)) {
      $term_item .= " <span title=\"" . format_plural($term->count, '1 item has this tag', '@count items have this tag') . "\">(" . $term->count . ")</span>";
    }
    if (variable_get('site_map_show_rss_links', 1) != 0) {
      $rss_link = theme('site_map_feed_icon', array(
        'url' => 'taxonomy/term/' . $term->tid . '/feed',
        'name' => $term->name,
      ));
      if (module_exists('commentrss') && variable_get('commentrss_term', FALSE)) {
        $rss_link .= ' ' . theme('site_map_feed_icon', array(
          'url' => "crss/term/{$term->tid}",
          'type' => 'comment',
          'name' => $term->name . ' comments',
        ));
      }
      if (variable_get('site_map_show_rss_links', 1) == 1) {
        $term_item .= ' ' . $rss_link;
      }
      else {
        $class[] = 'site-map-rss-left';
        $term_item = $rss_link . ' ' . $term_item;
      }
    }

    // Add an alter hook for modules to manipulate the taxonomy term output.
    drupal_alter(array(
      'site_map_taxonomy_term',
      'site_map_taxonomy_term_' . $term->tid,
    ), $term_item, $term);
    $output .= $term_item;

    // Reset $last_depth in preparation for the next $term.
    $last_depth = $term->depth;
  }

  // Bring the depth back to where it began, -1.
  if ($last_depth > -1) {
    for ($i = 0; $i < $last_depth + 1; $i++) {
      $output .= "</li>\n</ul>\n";
    }
  }
  _site_map_set_option($options, 'site_map_show_titles', 1, 1, 'show_titles', TRUE);
  $class[] = 'site-map-box-terms';
  $class[] = 'site-map-box-terms-' . $vid;
  $attributes = array(
    'class' => $class,
  );
  $output = theme('site_map_box', array(
    'title' => $title,
    'content' => $output,
    'attributes' => $attributes,
    'options' => $options,
  ));
  return $output;
}

/**
 * Count the number of published nodes classified by a term.
 *
 * This is a re-implementation of taxonomy_term_count_nodes() that has been
 * removed from D7 core.
 *
 * Implementation note: the normal way to count field instances is through
 * field_attach_query(), but taxonomy.module has a special denormalized
 * table taxonomy_index which we can use for more speed. THX to taxonews.
 *
 * @param string $tid
 *   The term's ID.
 *
 * @return string
 *   An integer representing a number of nodes. Results are statically cached.
 */
function site_map_taxonomy_term_count_nodes($tid) {
  $query = db_select('taxonomy_index', 'ti');
  $query
    ->addExpression('COUNT(ti.nid)');
  $count = $query
    ->condition('ti.tid', $tid)
    ->execute()
    ->fetchCol();
  return $count[0];
}

/**
 * Returns a rendered menu tree.
 *
 * This is a clone of the core menu_tree_output() function with the exception
 * of theme('site_map_menu_tree') for theming override reasons.
 *
 * The menu item's LI element is given one of the following classes:
 * - expanded: The menu item is showing its submenu.
 * - collapsed: The menu item has a submenu which is not shown.
 * - leaf: The menu item has no submenu.
 *
 * @param array $tree
 *   A data structure representing the tree as returned from menu_tree_data.
 *
 * @return array
 *   A structured array to be rendered by drupal_render().
 *
 * @codingStandardsIgnoreStart
 */
function _site_map_menu_tree_output($tree) {

  // @codingStandardsIgnoreEnd
  $build = array();
  $items = array();

  // Pull out just the menu links we are going to render so that we
  // get an accurate count for the first/last classes.
  // Thanks for fix by zhuber at https://drupal.org/node/1331104#comment-5200266
  foreach ($tree as $data) {
    if ($data['link']['access'] && (!$data['link']['hidden'] || variable_get('site_map_show_menus_hidden', 0))) {
      $items[] = $data;
    }
  }
  $router_item = menu_get_item();
  $num_items = count($items);
  foreach ($items as $i => $data) {
    $class = array();
    if ($i == 0) {
      $class[] = 'first';
    }
    if ($i == $num_items - 1) {
      $class[] = 'last';
    }

    // Set a class for the <li>-tag. Since $data['below'] may contain local
    // tasks, only set 'expanded' class if the link also has children within
    // the current menu.
    if ($data['link']['has_children'] && $data['below']) {
      $class[] = 'expanded';
    }
    elseif ($data['link']['has_children']) {
      $class[] = 'collapsed';
    }
    else {
      $class[] = 'leaf';
    }

    // Set a class if the link is in the active trail.
    if ($data['link']['in_active_trail']) {
      $class[] = 'active-trail';
      $data['link']['localized_options']['attributes']['class'][] = 'active-trail';
    }

    // Normally, l() compares the href of every link with $_GET['q'] and sets
    // the active class accordingly. But local tasks do not appear in menu
    // trees, so if the current path is a local task, and this link is its
    // tab root, then we have to set the class manually.
    if ($data['link']['href'] == $router_item['tab_root_href'] && $data['link']['href'] != $_GET['q']) {
      $data['link']['localized_options']['attributes']['class'][] = 'active';
    }

    // Allow menu-specific theme overrides.
    $element['#theme'] = 'site_map_menu_link__' . strtr($data['link']['menu_name'], '-', '_');
    $element['#attributes']['class'] = $class;
    $element['#title'] = $data['link']['title'];
    $element['#href'] = $data['link']['href'];
    $element['#title'] = $data['link']['title'];
    if (variable_get('site_map_show_node_titles', 1) == 1) {
      if (strpos($element['#href'], 'node/') !== FALSE) {
        $url = $element['#href'];
        $nid = basename($url);
        $node = node_load($nid);
        if (isset($node->title)) {
          $element['#title'] = $node->title;
        }
      }
    }
    $element['#localized_options'] = !empty($data['link']['localized_options']) ? $data['link']['localized_options'] : array();
    $element['#below'] = $data['below'] ? _site_map_menu_tree_output($data['below']) : $data['below'];
    $element['#original_link'] = $data['link'];

    // Index using the link's unique mlid.
    $build[$data['link']['mlid']] = $element;
  }
  if ($build) {

    // Make sure drupal_render() does not re-order the links.
    $build['#sorted'] = TRUE;

    // Add the theme wrapper for outer markup.
    // Allow menu-specific theme overrides.
    $build['#theme_wrappers'][] = 'site_map_menu_tree__' . strtr($data['link']['menu_name'], '-', '_');
  }
  return $build;
}

/**
 * Sets options based on admin input parameters for redering.
 *
 * @param array $options
 *   The array of options to the site map theme.
 * @param string $option_string
 *   The string index given from the admin form to match.
 * @param int $get_param
 *   Parameter number.
 * @param int $equal_param
 *   Result of param test, 0 or 1.
 * @param string $set_string
 *   Index of option to set, or the option name.
 * @param bool $set_value
 *   The option, on or off, or strings or ints for other options.
 *
 * @codingStandardsIgnoreStart
 */
function _site_map_set_option(&$options, $option_string, $get_param, $equal_param, $set_string, $set_value) {

  // @codingStandardsIgnoreEnd
  if (variable_get($option_string, $get_param) == $equal_param) {
    $options[$set_string] = $set_value;
  }
}

Functions

Namesort descending Description
site_map_block_info Implements hook_block_info().
site_map_block_view Implements hook_block_view().
site_map_content The content of the site map page.
site_map_help Implements hook_help().
site_map_menu Implements hook_menu().
site_map_page Menu callback for the site map.
site_map_permission Implements hook_permission().
site_map_taxonomy_term_count_nodes Count the number of published nodes classified by a term.
site_map_theme Implements hook_theme().
_site_map_audio Render the latest maps for audio.
_site_map_blogs Render the latest blogs.
_site_map_books Render the latest maps for books.
_site_map_faq Render the latest maps for faq.
_site_map_front_page Menu callback for the site map front page.
_site_map_menus Render the latest maps for all the menus.
_site_map_menu_tree_output Returns a rendered menu tree.
_site_map_set_option Sets options based on admin input parameters for redering.
_site_map_taxonomys Render the latest maps for the taxonomy tree.
_site_map_taxonomy_tree Render the taxonomy tree.
_site_map_title Title callback for the sitemap page.
_site_map_video Render the latest maps for video.