5

I have a D7 Views view which delivers a number of nodes. I would like them to be sorted based on the weight that their relevant menu items have.

I would like to avoid the fine module DraggableViews or any additional weight field for that matter.

How could this be accomplished?

Relevant pages: https://drupal.org/node/313140

5

1: Referencing a user contributed module: Views menu sort which at #48 has a D7 version. I have not tested this but others report success.

2: Another method you could use is to use a PHP field in your view like in this article on tappetyclick.com. (I have used this method before)

3: Or you can use the module menu node views which requires menu node.

4

A quick and simple solution without the need of extra modules might be to:

  1. alter a view result before rendering using uasort(),
  2. use sort callback YOURMODULE_sort_view_on_menu_link_weight() and
  3. use helper function YOURMODULE_build_menu_by_path() to create an array with menu link data keyed on node paths.

NB: This snippet:

  1. assumes the menu the nodes are referenced from is the main menu (one can change the menu key main-menu),
  2. does not take menu depth or Views pagination into account and
  3. overwrites any sorting done by Views.

/**
 * Implements hook_views_pre_render().
 *
 * - Sort view result based on menu link weights.
 */
function YOURMODULE_views_pre_render(&$view) {
  if ($view->name == 'YOURVIEWID') {
    uasort($view->result, 'YOURMODULE_sort_view_on_menu_link_weight');
  }
}

/**
 * uasort() callback to sort a view result on menu links weights.
 */
function YOURMODULE_sort_view_on_menu_link_weight($a, $b) {
  $menu_by_path = &drupal_static(__FILE__, array());

  // Get $menu_by_path once.
  if (empty($menu_by_path)) {
    YOURMODULE_build_menu_by_path(menu_tree_all_data('main-menu'), $menu_by_path);
  }

  // Get menu item weights by node ID.
  $weight_a = isset($menu_by_path['node/' . $a->nid]) ? (int) $menu_by_path['node/' . $a->nid]['weight'] : 0;
  $weight_b = isset($menu_by_path['node/' . $b->nid]) ? (int) $menu_by_path['node/' . $b->nid]['weight'] : 0;

  // Return sort value.
  return $weight_a == $weight_b ? 0 : ($weight_a < $weight_b ? -1 : 1);
}

/**
 * Helper function to get an array with menu link data, keyed by menu link path.
 */
function YOURMODULE_build_menu_by_path($menu, &$menu_by_path, $depth = 0) {
  // Iterate through menu items.
  foreach ($menu as $key => $menu_item) {
    // If menu item links to a node.
    if (strpos($menu_item['link']['link_path'], 'node/') === 0) {
      // Create $menu_by_path entry, store depth and weight.
      $menu_by_path[$menu_item['link']['link_path']] = array(
        'depth' => $depth,
        'weight' => $menu_item['link']['weight'],
      );
    }

    // If menu item has children.
    if (!empty($menu_item['below'])) {
      // Call this function on the menu item's submenu.
      YOURMODULE_build_menu_by_path($menu_item['below'], $menu_by_path, $depth+1);
    }
  }
}
1

The module Views Menu Node Children Filter can also sort by menu weight since version 7.x-1.0-rc3.

1
  • This is the most straight-forward way to do this. Just install the module and add the sort criteria.
    – Randell
    May 29 '19 at 22:48
0

One possibility is to use the Views PHP module.

A PHP function is required in order to retrieve the relevant menu item weight:

function get_menu_weight($nodeID) {
  $weight = 0;
  $query = "SELECT weight FROM {menu_links} WHERE link_path = :path AND hidden < 1";
  $args = array(':path' => 'node/' . $nodeID);
  $result = db_query($query, $args);
  if ($result->rowCount() > 0)
    $weight = $result->fetch()->weight;
  return $weight;
}

This function can reside in a template.php file or a custom module.

Then in the view under concern:

  • Add a Content: Nid field to the list of fields and exclude it from display
  • Add a Global: PHP field to the list of fields and exclude it from display
  • In the Value code set return get_menu_weight($row->nid); (without php tags)
  • In the Output code set <?php print $value; ?> (with PHP tags)
  • Add a Global: PHP field to the sort fields of the view and specify:

    if ($row1->php < $row2->php) return -1; 
    else return 1;
    

Source: http://tappetyclick.com/blog/2013/01/07/how-order-drupal-view-node-menu-weight#.UyG1St8hGb4

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.