Entity view (Content)

Sorting Multigroup Fields

By bfung
Apr. 5, 2012

Drupal 6 CCK3's multigroup interface allows users to re-arrange the display order within multigroup; however, sometimes you might need to sort these data automatically upon adding a new entry. Currently, there is no built-in functionality to do this so you will have to add your own code to handle this. Before we begin, there are some points you need to consider first:

1) You have to identify which field(s) to sort. The more fields used the more complicated and slower the process will become.

2) If you are applying the sort during save you will overwrite the built-in re-order function. You can add a sort button on the form to trigger the sort before form save. I will only cover the sort during save process in this blog. If anyone is interested I can do a part two next time.

3) It might be easier to handle the sorting in view or template. Ask yourself if it is really necessary to sort the data on save. If you only need to display the data sorted then you can simply do it on display level instead. Understand the Data StructureIf you take a look at the multigroup data inside the node you will find that they are being stored separately by default. As a result you will not find all your data within the same multigroup to be under a single array. Each field inside the multigroup is still stored as if they are just a normal field in the form. Unlike a single text field which has just one element in the array, each field will have multiple elements which equals to the number of rows you added to that multigroup. Let's take a look at the following example which has 2 fields (fruit name and date) in the group:

apple, 2009-10
orange, 2010-12-31
banana, 2007-04-05

The data saved inside the node will follow this structure below. I have simplified the actual structure so if you are new to this you will able to understand this easier.

field_1 => array() {
  [0] => array() {
    ['value'] =  'apple';
   //some extra attributes 
  }
  [1] => array() {
    ['value'] =  'orange';
   //some extra attributes 
  }
  [2] => array() {
    ['value'] =  'banana';
   //some extra attributes 
  }
}

field_2 => array() {
  [0] => array() {
    ['date'] =  '2009-10-01';
   //some extra attributes 
  }
  [1] => array() {
    ['date'] =  '2010-12-31';
   //some extra attributes 
  }
  [2] => array() {
    ['date'] =  '2007-04-05';
   //some extra attributes 
  }
}

So basically each field has its own array of rows. Inside each row you will have another array that contains the data as well as other attributes like title, weight etc. Unfortunately, it is not easy to just sort this directly.

How do We Sort?

The final sorting part is actually pretty straight forward. Your goal is to re-arrange both field1 and field2's array order in the node and then save the changes. For example, if you want to sort the data by date in DESC order then your result will this order: 1, 0, 2. If you want to sort the data by fruit name in ASC order then you should re-arrange your data in this order: 0, 2, 1. We will use the 'array_multisort' PHP function to help us. I am not going to details about this function as there are detailed examples on the web. You will need to create a new array for the array_multisort function to perform the sorting. You will also need to add a new column that contains the original row index. For example if you sort by date in DESC order then your original array will change from

[0] => {0, apple, 2009-10-01}
[1] => {1, orange, 2010-12-31}
[2] => {2, banana, 2007-04-05}

to

[0] => {1, orange, 2010-12-31}
[1] => {0, apple, 2009-10-01}
[2] => {2, banana, 2007-04-05}

If you look at the first column ,which is the original row index, you will now get and order 1, 0, 2. This is the exact order you need to re-arrange all the fields in the multigroup to.

Final Touch

Now you know which order to re-arrange the data. The final step is to figure out where to execute the sort. If you want to sort the data after the node is saved then you can do it inside 'hook_node_api' under the op 'presave'. As a result, your node data will get updated and the system will save your node without having you call 'node_save' again. If you wish to do it in the form level you can look into form_alter or the after_build function.

Post Tags: