Index: css/style.css
===================================================================
--- css/style.css	(revision 633)
+++ css/style.css	(working copy)
@@ -538,4 +538,11 @@
 }
 span.or-cancel {
 	font-size: 0.85em;
+}
+table.form-table th {
+	text-align: left;
+	vertical-align: text-top;
+}
+table.form-table th, table.form-table td {
+	padding: 10px 0 0 0;
 }
\ No newline at end of file
Index: gp-templates/profile.php
===================================================================
--- gp-templates/profile.php	(revision 0)
+++ gp-templates/profile.php	(revision 0)
@@ -0,0 +1,50 @@
+<?php 
+gp_title( __('Profile &lt; GlotPress') );
+gp_breadcrumb( array( __('Profile') ) );
+gp_tmpl_header();
+
+$per_page = GP::$user->get_meta('per_page');
+if ( 0 == $per_page )
+	$per_page = 15;
+	
+$default_sort = GP::$user->get_meta('default_sort');
+if ( ! is_array($default_sort) ) {
+	$default_sort = array(
+		'by' => 'priority',
+		'how' => 'DESC'
+	);
+}
+?>
+<h2><?php _e( "Profile" ); ?></h2>
+<form method="post">
+	<table class="form-table">
+		<tr>
+			<th><label for="per_page"><?php _e( "Number of items per page:" ); ?></label></th>
+			<td><input type="number" id="per_page" name="per_page" value="<?php echo $per_page ?>"/></td>
+		</tr>
+		<tr>
+			<th><label for="default_sort[by]"><?php _e("Default Sort By:") ?></label></th>
+			<td><?php echo gp_radio_buttons('default_sort[by]',
+		array(
+			'original_date_added' => __('Date added (original)'),
+			'translation_date_added' => __('Date added (translation)'),
+			'original' => __('Original string'),
+			'translation' => __('Translation'),
+			'priority' => __('Priority'),
+			'references' => __('Filename in source'),
+			'random' => __('Random'),
+		), gp_array_get( $default_sort, 'by', 'priority' ) ); ?></td>
+		</tr>
+		<tr>
+			<th><label for="default_sort[how]"><?php _e("Default Sort Order:") ?></label></th>
+			<td><?php echo gp_radio_buttons('default_sort[how]',
+				array(
+					'asc' => __('Ascending'),
+					'desc' => __('Descending'),
+				), gp_array_get( $default_sort, 'how', 'desc' ) );
+			?></td>
+		</tr>
+	</table>
+	<br>
+	<input type="submit" name="submit" value="<?php _e("Change Settings"); ?>">
+</form>
\ No newline at end of file
Index: gp-templates/translations.php
===================================================================
--- gp-templates/translations.php	(revision 633)
+++ gp-templates/translations.php	(working copy)
@@ -93,7 +93,16 @@
 	<dl class="filters-expanded sort hidden clearfix">
 		<dt><?php _e('By:'); ?></dt>
 		<dd>
-		<?php echo gp_radio_buttons('sort[by]',
+		<?php 
+		$default_sort = GP::$user->get_meta('default_sort');
+		if ( ! is_array($default_sort) ) {
+			$default_sort = array(
+				'by' => 'priority',
+				'how' => 'desc'
+			);
+		} 
+		
+		echo gp_radio_buttons('sort[by]',
 			array(
 				'original_date_added' => __('Date added (original)'),
 				'translation_date_added' => __('Date added (translation)'),
@@ -102,16 +111,16 @@
 				'priority' => __('Priority'),
 				'references' => __('Filename in source'),
 				'random' => __('Random'),
-			), gp_array_get( $sort, 'by', 'priority' ) );
+			), gp_array_get( $sort, 'by', $default_sort['by'] ) );
 		?>
 		</dd>
-		<dt><?php _e('How:'); ?></dt>
+		<dt><?php _e('Order:'); ?></dt>
 		<dd>
 		<?php echo gp_radio_buttons('sort[how]',
 			array(
 				'asc' => __('Ascending'),
 				'desc' => __('Descending'),
-			), gp_array_get( $sort, 'how', 'desc' ) );
+			), gp_array_get( $sort, 'how', $default_sort['how'] ) );
 		?>
 		</dd>
 		<dd><input type="submit" value="<?php echo esc_attr(__('Sort')); ?>" name="sorts" /></dd>
Index: gp-templates/header.php
===================================================================
--- gp-templates/header.php	(revision 633)
+++ gp-templates/header.php	(working copy)
@@ -22,7 +22,7 @@
 			if (GP::$user->logged_in()):
 				$user = GP::$user->current();
 				
-				printf( __('Hi, %s.'), $user->user_login );
+				printf( __('Hi, %s.'), '<a href="'.gp_url( '/profile' ).'">'.$user->user_login.'</a>' );
 				?>
 				<a href="<?php echo gp_url('/logout')?>"><?php _e('Log out'); ?></a>
 			<?php else: ?>
Index: gp-includes/routes/translation.php
===================================================================
--- gp-includes/routes/translation.php	(revision 633)
+++ gp-includes/routes/translation.php	(working copy)
@@ -67,9 +67,16 @@
 		if ( 'random' == gp_array_get( $sort, 'by') ) {
 			add_filter( 'gp_pagination', create_function( '$html', 'return "";' ) );
 		}
+
+		$per_page = GP::$user->get_meta('per_page');
+		if ( 0 == $per_page )
+			$per_page = GP::$translation->per_page;
+		else
+			GP::$translation->per_page = $per_page;
+
 		$translations = GP::$translation->for_translation( $project, $translation_set, $page, $filters, $sort );
 		$total_translations_count = GP::$translation->found_rows;
-		$per_page = GP::$translation->per_page;
+		
 		$can_edit = GP::$user->logged_in();
 		$can_write = $this->can( 'write', 'project', $project->id );
 		$can_approve = $this->can( 'approve', 'translation-set', $translation_set->id );
Index: gp-includes/routes/profile.php
===================================================================
--- gp-includes/routes/profile.php	(revision 0)
+++ gp-includes/routes/profile.php	(revision 0)
@@ -0,0 +1,23 @@
+<?php
+class GP_Route_Profile extends GP_Route_Main {
+	function profile_get() {
+		if ( !GP::$user->logged_in() ) {
+			$this->redirect( gp_url( '/login?redirect_to=' ).urlencode( gp_url( '/profile') ) );
+			return;
+		}
+
+		gp_tmpl_load( 'profile', array() );
+	}
+
+	function profile_post() {
+		if ( isset( $_POST['submit'] ) ) {
+			$per_page = (int) $_POST['per_page'];
+			GP::$user->set_meta( 'per_page', $per_page );
+
+			$default_sort = $_POST['default_sort'];
+			GP::$user->set_meta( 'default_sort', $default_sort );
+		}
+		
+		$this->redirect( gp_url( '/profile' ) );
+	}
+}
Index: gp-includes/things/translation.php
===================================================================
--- gp-includes/things/translation.php	(revision 633)
+++ gp-includes/things/translation.php	(working copy)
@@ -71,9 +71,18 @@
 		$sort_bys = array('original' => 'o.singular %s', 'translation' => 't.translation_0 %s', 'priority' => 'o.priority %s, o.date_added DESC',
 			'random' => 'o.priority DESC, RAND()', 'translation_date_added' => 't.date_added %s', 'original_date_added' => 'o.date_added %s',
 			'references' => 'o.references' );
-		$sort_by = gp_array_get( $sort_bys, gp_array_get( $sort, 'by' ), 'o.priority %1$s, o.date_added %1$s' );
+
+		$default_sort = GP::$user->get_meta('default_sort');
+		if ( ! is_array($default_sort) ) {
+			$default_sort = array(
+				'by' => 'priority',
+				'how' => 'desc'
+			);
+		} 
+		
+		$sort_by = gp_array_get( $sort_bys, gp_array_get( $sort, 'by' ),  gp_array_get( $sort_bys, $default_sort['by'] ) );
 		$sort_hows = array('asc' => 'ASC', 'desc' => 'DESC', );
-		$sort_how = gp_array_get( $sort_hows, gp_array_get( $sort, 'how' ), 'DESC' );
+		$sort_how = gp_array_get( $sort_hows, gp_array_get( $sort, 'how' ), gp_array_get( $sort_hows, $default_sort['how'] ) );
 
 		$where = array();
 		if ( gp_array_get( $filters, 'term' ) ) {
@@ -148,14 +157,15 @@
 			$where = 'AND '.$where;
 		}
 		
-		
 		$join_where = implode( ' AND ', $join_where );
 		if ( $join_where ) {
 			$join_where = 'AND '.$join_where;
 		}
 
 		$sql_sort = sprintf( $sort_by, $sort_how );
-		$limit = $this->sql_limit_for_paging( $page );
+
+		$limit = $this->sql_limit_for_paging( $page, $this->per_page );
+		
 		$rows = $this->many_no_map( "
 		    SELECT SQL_CALC_FOUND_ROWS t.*, o.*, t.id as id, o.id as original_id, t.status as translation_status, o.status as original_status, t.date_added as translation_added, o.date_added as original_added
 		    FROM $gpdb->originals as o
Index: gp-includes/things/user.php
===================================================================
--- gp-includes/things/user.php	(revision 633)
+++ gp-includes/things/user.php	(working copy)
@@ -112,10 +112,7 @@
 	}
 	
 	function get_meta( $key ) {
-		global $wp_users_object;
-		if ( !$user = $wp_users_object->get_user( $this->id ) ) {
-			return;
-		}
+		$user = $this->current();
 
 		$key = gp_sanitize_meta_key( $key );
 		if ( !isset( $user->$key ) ) {
@@ -125,11 +122,13 @@
 	}
 	
 	function set_meta( $key, $value ) {
-		return gp_update_meta( $this->id, $key, $value, 'user' );
+		$user = $this->current();
+		return gp_update_meta( $user->id, $key, $value, 'user' );
 	}
 	
 	function delete_meta( $key ) {
-		return gp_delete_meta( $this->id, $key, '', 'user' );
+		$user = $this->current();
+		return gp_delete_meta( $user->id, $key, '', 'user' );
 	}
 	
 	
Index: gp-includes/thing.php
===================================================================
--- gp-includes/thing.php	(revision 633)
+++ gp-includes/thing.php	(working copy)
@@ -383,7 +383,7 @@
 		$per_page = is_null( $per_page )? $this->per_page : $per_page;
 		if ( 'no-limit' == $per_page || 'no-limit' == $page ) return '';
 		$page = intval( $page )? intval( $page ) : 1;
-		return sprintf( "LIMIT %d OFFSET %d", $this->per_page, ($page-1)*$this->per_page );
+		return sprintf( "LIMIT %d OFFSET %d", $per_page, ($page-1)*$per_page );
 	}
 	
 	function found_rows() {
Index: gp-includes/router.php
===================================================================
--- gp-includes/router.php	(revision 633)
+++ gp-includes/router.php	(working copy)
@@ -44,6 +44,9 @@
 			'get:/login' => array('GP_Route_Login', 'login_get'),
 			'post:/login' => array('GP_Route_Login', 'login_post'),
 			'get:/logout' => array('GP_Route_Login', 'logout'),
+			
+			'get:/profile' => array('GP_Route_Profile', 'profile_get'),
+			'post:/profile' => array('GP_Route_Profile', 'profile_post'),
 
 			"get:/$project/import-originals" => array('GP_Route_Project', 'import_originals_get'),
 			"post:/$project/import-originals" => array('GP_Route_Project', 'import_originals_post'),
Index: gp-includes/meta.php
===================================================================
--- gp-includes/meta.php	(revision 633)
+++ gp-includes/meta.php	(working copy)
@@ -17,7 +17,8 @@
  */
 function gp_update_meta( $object_id = 0, $meta_key, $meta_value, $type, $global = false ) {
 	global $gpdb;
-	if ( !is_numeric( $object_id ) || empty( $object_id ) && !$global ) {
+
+	if ( !is_numeric( $object_id ) || empty( $object_id ) ) {
 		return false;
 	}
 	$cache_object_id = $object_id = (int) $object_id;

