diff -rupN SemanticMediaWiki-30829/includes/SMW_QueryProcessor.php SemanticMediaWiki-30829-multsort/includes/SMW_QueryProcessor.php
--- SemanticMediaWiki-30829/includes/SMW_QueryProcessor.php	2008-02-11 14:05:18.000000000 +0300
+++ SemanticMediaWiki-30829-multsort/includes/SMW_QueryProcessor.php	2008-02-11 15:13:28.000000000 +0300
@@ -92,14 +92,24 @@ class SMWQueryProcessor {
 				$query->setLimit($smwgQDefaultLimit);
 			}
 		}
-		if (array_key_exists('sort', $params)) {
+		// next one works, sortkeys and ascendings are properly filled with data:
+		if ( array_key_exists('sort', $params) ) {
 			$query->sort = true;
-			$query->sortkey = smwfNormalTitleDBKey($params['sort']);
+			$query->sortkeys = Array();
+			foreach ( explode( ',', trim($params['sort']) ) as $sort ) {
+				$query->sortkeys[] = smwfNormalTitleDBKey( trim($sort) );
+			}
 		}
-		if (array_key_exists('order', $params)) {
-			$order = strtolower(trim($params['order']));
-			if (('descending'==$order)||('reverse'==$order)||('desc'==$order)) {
-				$query->ascending = false;
+		if ( array_key_exists('order', $params) ) {
+			$query->ascendings = Array();
+			foreach ( explode( ',', trim($params['order']) ) as $order ) {
+				$order = strtolower(trim($order));
+				$query->ascendings[] = ('descending'!=$order) && ('reverse'!=$order) && ('desc'!=$order);
+			}
+			// make sure all the ascendings filled with values, even if these aren't actually presented in query
+			foreach ( $query->sortkeys as $key => $val ) {
+				if ( !array_key_exists( $key, $query->ascendings ) )
+					$query->ascendings[$key] = true;
 			}
 		}
 		return $query;
diff -rupN SemanticMediaWiki-30829/includes/storage/SMW_Query.php SemanticMediaWiki-30829-multsort/includes/storage/SMW_Query.php
--- SemanticMediaWiki-30829/includes/storage/SMW_Query.php	2008-02-11 14:05:16.000000000 +0300
+++ SemanticMediaWiki-30829-multsort/includes/storage/SMW_Query.php	2008-02-11 14:28:10.000000000 +0300
@@ -26,8 +26,8 @@ class SMWQuery {
 	const MODE_NONE = 4;  // do nothing with the query
 
 	public $sort = false;
-	public $ascending = true;
-	public $sortkey = false;
+	public $ascendings = Array(true);
+	public $sortkeys = false;
 	public $querymode = SMWQuery::MODE_INSTANCES;
 
 	protected $m_limit;
diff -rupN SemanticMediaWiki-30829/includes/storage/SMW_SQLStore.php SemanticMediaWiki-30829-multsort/includes/storage/SMW_SQLStore.php
--- SemanticMediaWiki-30829/includes/storage/SMW_SQLStore.php	2008-02-11 14:05:16.000000000 +0300
+++ SemanticMediaWiki-30829-multsort/includes/storage/SMW_SQLStore.php	2008-02-11 15:14:54.000000000 +0300
@@ -16,18 +16,18 @@ require_once( "$smwgIP/includes/SMW_Data
 class SMWSQLStore extends SMWStore {
 
 	/**
-	 * The (normalised) name of the property by which results during query
+	 * The array of (normalised) names of the properties by which results during query
 	 * processing should be ordered, if any. False otherwise (default from
 	 * SMWQuery). Needed during query processing (where this key is searched
 	 * while building the query conditions).
 	 */
-	protected $m_sortkey;
+	protected $m_sortkeys;
 	/**
-	 * The database field name by which results during query processing should
+	 * The database field names by which results during query processing should
 	 * be ordered, if any. False if no $m_sortkey was specified or if the key
 	 * did not match any condition.
 	 */
-	protected $m_sortfield;
+	protected $m_sortfields;
 	/**
 	 * Global counter to prevent clashes between table aliases.
 	 */
@@ -782,8 +782,8 @@ class SMWSQLStore extends SMWStore {
 
 		// Build main query
 		$this->m_usedtables = array();
-		$this->m_sortkey = $query->sortkey;
-		$this->m_sortfield = false;
+		$this->m_sortkeys = $query->sortkeys;
+		$this->m_sortfields = false;
 
 		$pagetable = $db->tableName('page');
 		$from = $pagetable;
@@ -796,22 +796,41 @@ class SMWSQLStore extends SMWStore {
 		$sql_options['LIMIT'] = $query->getLimit() + 1;
 		$sql_options['OFFSET'] = $query->getOffset();
 		if ( $smwgQSortingSupport ) {
-			$order = $query->ascending ? 'ASC' : 'DESC';
-			if ( ($this->m_sortfield == false) && ($this->m_sortkey == false) ) {
+			$order = $query->ascendings[0] ? 'ASC' : 'DESC';
+			if ( ($this->m_sortfields === false) && ($this->m_sortkeys === false) ) {
 				$sql_options['ORDER BY'] = "$pagetable.page_title $order "; // default
 			} else {
-				if ($this->m_sortfield == false) { // also query for sort property
+				if ( is_array( $this->m_sortkeys ) ) {
+					reset( $this->m_sortkeys );
+					$m_sortkey = current( $this->m_sortkeys );
 					$extrawhere = '';
-					$this->createSQLQuery(new SMWSomeProperty(Title::newFromText($this->m_sortkey, SMW_NS_PROPERTY), new SMWThingDescription()), $from, $extrawhere, $db, $curtables);
+					$this->createSQLQuery(new SMWSomeProperty(Title::newFromText($m_sortkey, SMW_NS_PROPERTY), new SMWThingDescription()), $from, $extrawhere, $db, $curtables);
 					if ($extrawhere != '') {
 						if ($where != '') {
 							$where = "($where) AND ";
 						}
 						$where .= "($extrawhere)";
 					}
-				}
-				if ($this->m_sortfield != false) { // should always be the case, but who knows ...
-					$sql_options['ORDER BY'] = $this->m_sortfield . " $order ";
+					for ( $m_sortkey=next($this->m_sortkeys); $m_sortkey !== false; $m_sortkey=next($this->m_sortkeys) ) {
+						$this->setSQLSortOption(new SMWSomeProperty(Title::newFromText($m_sortkey, SMW_NS_PROPERTY), new SMWThingDescription()), key($this->m_sortkeys), $from, $extrawhere, $db, $curtables );
+						if ($extrawhere != '') {
+							if ($where != '') {
+								$where = "($where) AND ";
+							}
+							$where .= "($extrawhere)";
+						}
+					}
+					if ($this->m_sortfields !== false) { // should always be the case, but who knows ...
+  					$first_order = true;
+					  foreach ( $this->m_sortfields as $m_key => $m_sortfield ) {
+							$order = $query->ascendings[$m_key] ? 'ASC' : 'DESC';
+							if ( $first_order )
+								$first_order=false;
+							else
+								$sql_options['ORDER BY'] .= ", ";
+  						$sql_options['ORDER BY'] .= $m_sortfield . " $order ";
+					  }
+					}
 				}
 			}
 		}
@@ -1766,7 +1785,7 @@ class SMWSQLStore extends SMWStore {
 					$tablename = 'RELS';
 					$pcolumn = 'relation_title';
 					$sub = true;
-					if ($this->m_sortkey == $description->getProperty()->getDBkey()) {
+					if ($this->m_sortkeys[0] == $description->getProperty()->getDBkey()) {
 						$sort = 'object_title';
 					}
 				break;
@@ -1784,7 +1803,7 @@ class SMWSQLStore extends SMWStore {
 					$tablename = 'ATTS';
 					$pcolumn = 'attribute_title';
 					$sub = true;
-					if ($this->m_sortkey == $description->getProperty()->getDBkey()) {
+					if ($this->m_sortkeys[0] == $description->getProperty()->getDBkey()) {
 						if (SMWDataValueFactory::newTypeIDValue($id)->isNumeric()) {
 							$sort = 'value_num';
 						} else {
@@ -1807,7 +1826,7 @@ class SMWSQLStore extends SMWStore {
 					$nexttables['p' . $tablename] = $table; // keep only current table for reference
 					$this->createSQLQuery($description->getDescription(), $from, $subwhere, $db, $nexttables, $nary_pos);
 					if ($sort) {
-						$this->m_sortfield = "$table.$sort";
+						$this->m_sortfields[0] = "$table.$sort";
 					}
 					if ( $subwhere != '') {
 						$where .= ' AND (' . $subwhere . ')';
@@ -1819,6 +1838,71 @@ class SMWSQLStore extends SMWStore {
 	}
 
 	/**
+	 * Add orering option to an SQL query for a given property.
+	 *
+   */
+	protected function setSQLSortOption( SMWSomeProperty $property, $sortidx, &$from, &$where, &$db, &$curtables, $nary_pos = ''  ) {
+		$id = SMWDataValueFactory::getPropertyObjectTypeID($property->getProperty());
+		$sort = false;
+		switch ($id) {
+			case '_wpg':
+				$tablename = 'RELS';
+				$pcolumn = 'relation_title';
+				$sub = true;
+				if ($this->m_sortkeys[$sortidx] == $property->getProperty()->getDBkey()) {
+					$sort = 'object_title';
+				}
+			break;
+			case '_txt':
+				$tablename = 'TEXT';
+				$pcolumn = 'attribute_title';
+				$sub = false; //no recursion: we do not support further conditions on text-type values
+			break;
+			case '__nry':
+				$tablename = 'NARY';
+				$pcolumn = 'attribute_title';
+				$sub = true;
+			break;
+			default:
+				$tablename = 'ATTS';
+				$pcolumn = 'attribute_title';
+				$sub = true;
+				if ($this->m_sortkeys[$sortidx] == $property->getProperty()->getDBkey()) {
+					if (SMWDataValueFactory::newTypeIDValue($id)->isNumeric()) {
+						$sort = 'value_num';
+					} else {
+						$sort = 'value_xsd';
+					}
+				}
+		}
+		$pt = $this->getPropertyTable($property->getProperty()->getDBkey(), $db);
+		// in case don't unset, it would be all the same property, makes no sence here
+		unset($curtables[$tablename]);
+		if ($table = $this->addJoin($tablename, $from, $db, $curtables, $nary_pos)) {
+			global $smwgQSubpropertyDepth;
+			if ($smwgQSubpropertyDepth > 0) {
+				$pt = $this->getPropertyTable($property->getProperty()->getDBkey(), $db);
+				$from = '`' . $pt . '`, ' . $from;
+				$where = "$pt.title=" . $table . '.' . $pcolumn;
+			} else {
+				$where .= $table . '.' . $pcolumn . '=' .
+									$db->addQuotes($property->getProperty()->getDBkey());
+			}
+			if ($sub) {
+				$nexttables = array();
+				$nexttables['p' . $tablename] = $table; // keep only current table for reference
+				if ($sort) {
+					$this->m_sortfields[$sortidx] = "$table.$sort";
+				}
+				if ( $subwhere != '') {
+					$where .= ' AND (' . $subwhere . ')';
+				}
+			}
+		}
+	}
+
+
+	/**
 	 * Make sure the table of the given name has the given fields, provided
 	 * as an array with entries fieldname => typeparams. typeparams should be
 	 * in a normalised form and order to match to existing values.
