Index: .
===================================================================
--- .	(revision 20434)
+++ .	(working copy)

Property changes on: .
___________________________________________________________________
Added: svn:ignore
## -0,0 +1 ##
+wp-content/plugins/
Index: wp-comments-post.php
===================================================================
--- wp-comments-post.php	(revision 20434)
+++ wp-comments-post.php	(working copy)
@@ -37,7 +37,7 @@
 } elseif ( 'trash' == $status ) {
 	do_action('comment_on_trash', $comment_post_ID);
 	exit;
-} elseif ( !$status_obj->public && !$status_obj->private ) {
+} elseif ( empty($status_obj->public) && empty($status_obj->private) ) {
 	do_action('comment_on_draft', $comment_post_ID);
 	exit;
 } elseif ( post_password_required($comment_post_ID) ) {
Index: wp-includes/post-template.php
===================================================================
--- wp-includes/post-template.php	(revision 20434)
+++ wp-includes/post-template.php	(working copy)
@@ -107,12 +107,22 @@
 	$id = isset($post->ID) ? $post->ID : (int) $id;
 
 	if ( !is_admin() ) {
-		if ( !empty($post->post_password) ) {
-			$protected_title_format = apply_filters('protected_title_format', __('Protected: %s'));
+		if ( ! empty($post->post_password) ) {
+			$protected_title_format = apply_filters( 'protected_title_format', __( 'Protected: %s' ) );
 			$title = sprintf($protected_title_format, $title);
-		} else if ( isset($post->post_status) && 'private' == $post->post_status ) {
-			$private_title_format = apply_filters('private_title_format', __('Private: %s'));
-			$title = sprintf($private_title_format, $title);
+		} elseif ( isset($post->post_status) ) {
+			$post_status_obj = get_post_status_object( $post->post_status );
+			if ( $post_status_obj && $post_status_obj->private ) {
+				if ( 'private' == $post->post_status ) {
+					$format_string = __( 'Private: %s' );  // preserve existing translation string
+					$private_title_format = apply_filters( 'private_title_format', $format_string );
+					$title = sprintf( $private_title_format, $title );
+				} else {
+					$format_string = _x( '%1$s: %2$s', 'post status: title' );	
+					$private_title_format = apply_filters( 'post_title_format', $format_string, $_status );
+					$title = sprintf( $private_title_format, $post_status_obj->labels->name, $title );
+				}
+			}
 		}
 	}
 	return apply_filters( 'the_title', $title, $id );
@@ -700,7 +710,7 @@
 	if ( 1 == $i ) {
 		$url = get_permalink();
 	} else {
-		if ( '' == get_option('permalink_structure') || in_array($post->post_status, array('draft', 'pending')) )
+		if ( '' == get_option('permalink_structure') || in_array( $post->post_status, array('draft', 'auto-draft', 'pending') ) || ! empty( $GLOBALS['wp_post_statuses'][$post->post_status]->moderation )  )
 			$url = add_query_arg( 'page', $i, get_permalink() );
 		elseif ( 'page' == get_option('show_on_front') && get_option('page_on_front') == $post->ID )
 			$url = trailingslashit(get_permalink()) . user_trailingslashit("$wp_rewrite->pagination_base/" . $i, 'single_paged');
Index: wp-includes/taxonomy.php
===================================================================
--- wp-includes/taxonomy.php	(revision 20434)
+++ wp-includes/taxonomy.php	(working copy)
@@ -132,6 +132,9 @@
 
 	$field = ('names' == $output) ? 'name' : false;
 
+	if ( isset( $args['object_type'] ) )
+		$args['object_type'] = (array) $args['object_type'];
+
 	return wp_filter_object_list($wp_taxonomies, $args, $operator, $field);
 }
 
@@ -2839,7 +2842,11 @@
 	// Get the object and term ids and stick them in a lookup table
 	$tax_obj = get_taxonomy($taxonomy);
 	$object_types = esc_sql($tax_obj->object_type);
-	$results = $wpdb->get_results("SELECT object_id, term_taxonomy_id FROM $wpdb->term_relationships INNER JOIN $wpdb->posts ON object_id = ID WHERE term_taxonomy_id IN (" . implode(',', array_keys($term_ids)) . ") AND post_type IN ('" . implode("', '", $object_types) . "') AND post_status = 'publish'");
+	
+	$public_stati = apply_filters( 'term_count_stati', get_post_stati( array( 'public' => true, 'object_type' => $tax_obj->object_type ) ) );
+	$public_csv = implode( "', '", $public_stati );
+
+	$results = $wpdb->get_results("SELECT object_id, term_taxonomy_id FROM $wpdb->term_relationships INNER JOIN $wpdb->posts ON object_id = ID WHERE term_taxonomy_id IN (" . implode(',', array_keys($term_ids)) . ") AND post_type IN ('" . implode("', '", $object_types) . "') AND post_status IN ('$public_csv')");
 	foreach ( $results as $row ) {
 		$id = $term_ids[$row->term_taxonomy_id];
 		$term_items[$id][$row->object_id] = isset($term_items[$id][$row->object_id]) ? ++$term_items[$id][$row->object_id] : 1;
@@ -2900,15 +2907,19 @@
 	if ( $object_types )
 		$object_types = esc_sql( array_filter( $object_types, 'post_type_exists' ) );
 
+	$public_stati = apply_filters( 'term_count_stati', get_post_stati( array( 'public' => true, 'object_type' => $taxonomy->object_type ) ) );
+	$public_csv = implode( "', '", $public_stati );
+	
 	foreach ( (array) $terms as $term ) {
+
 		$count = 0;
 
 		// Attachments can be 'inherit' status, we need to base count off the parent's status if so
 		if ( $check_attachments )
-			$count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts p1 WHERE p1.ID = $wpdb->term_relationships.object_id AND ( post_status = 'publish' OR ( post_status = 'inherit' AND post_parent > 0 AND ( SELECT post_status FROM $wpdb->posts WHERE ID = p1.post_parent ) = 'publish' ) ) AND post_type = 'attachment' AND term_taxonomy_id = %d", $term ) );
+			$count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts p1 WHERE p1.ID = $wpdb->term_relationships.object_id AND ( post_status IN ('$public_csv') OR ( post_status = 'inherit' AND post_parent > 0 AND ( SELECT post_status FROM $wpdb->posts WHERE ID = p1.post_parent ) IN ('$public_csv') ) ) AND post_type = 'attachment' AND term_taxonomy_id = %d", $term ) );
 
 		if ( $object_types )
-			$count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts WHERE $wpdb->posts.ID = $wpdb->term_relationships.object_id AND post_status = 'publish' AND post_type IN ('" . implode("', '", $object_types ) . "') AND term_taxonomy_id = %d", $term ) );
+			$count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts WHERE $wpdb->posts.ID = $wpdb->term_relationships.object_id AND post_status IN ('$public_csv') AND post_type IN ('" . implode("', '", $object_types ) . "') AND term_taxonomy_id = %d", $term ) );
 
 		do_action( 'edit_term_taxonomy', $term, $taxonomy );
 		$wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) );
Index: wp-includes/default-widgets.php
===================================================================
--- wp-includes/default-widgets.php	(revision 20434)
+++ wp-includes/default-widgets.php	(working copy)
@@ -562,6 +562,9 @@
 		if ( empty( $instance['number'] ) || ! $number = absint( $instance['number'] ) )
  			$number = 10;
 
+		$public_stati = apply_filters( 'recent_posts_stati', get_post_stati( array( 'public' => true ) ) );
+		$status_arg = implode( ',', $public_stati );
+
 		$r = new WP_Query( apply_filters( 'widget_posts_args', array( 'posts_per_page' => $number, 'no_found_rows' => true, 'post_status' => 'publish', 'ignore_sticky_posts' => true ) ) );
 		if ($r->have_posts()) :
 ?>
Index: wp-includes/link-template.php
===================================================================
--- wp-includes/link-template.php	(revision 20434)
+++ wp-includes/link-template.php	(working copy)
@@ -114,7 +114,7 @@
 
 	$permalink = apply_filters('pre_post_link', $permalink, $post, $leavename);
 
-	if ( '' != $permalink && !in_array($post->post_status, array('draft', 'pending', 'auto-draft')) ) {
+	if ( '' != $permalink && ! in_array( $post->post_status, array('draft', 'auto-draft', 'pending') ) && empty( $GLOBALS['wp_post_statuses'][$post->post_status]->moderation ) ) {
 		$unixtime = strtotime($post->post_date);
 
 		$category = '';
@@ -185,7 +185,7 @@
 
 	$slug = $post->post_name;
 
-	$draft_or_pending = isset($post->post_status) && in_array( $post->post_status, array( 'draft', 'pending', 'auto-draft' ) );
+	$draft_or_pending = isset($post->post_status) && in_array( $post->post_status, array( 'draft', 'pending', 'auto-draft' ) ) || ! empty( $GLOBALS['wp_post_statuses'][$post->post_status]->moderation );
 
 	$post_type = get_post_type_object($post->post_type);
 
@@ -275,7 +275,7 @@
 
 	$link = $wp_rewrite->get_page_permastruct();
 
-	if ( !empty($link) && ( ( isset($post->post_status) && !$draft_or_pending ) || $sample ) ) {
+	if ( !empty($link) && ( ( isset($post->post_status) && !$draft_or_pending ) && empty( $GLOBALS['wp_post_statuses'][$post->post_status]->moderation ) ) || $sample ) {
 		if ( ! $leavename ) {
 			$link = str_replace('%pagename%', get_page_uri($id), $link);
 		}
Index: wp-includes/nav-menu.php
===================================================================
--- wp-includes/nav-menu.php	(revision 20434)
+++ wp-includes/nav-menu.php	(working copy)
@@ -482,8 +482,11 @@
 	if ( empty( $items ) )
 		return $items;
 
+	$public_stati = apply_filters( 'nav_menu_stati', get_post_stati( array( 'public' => true ) ), $menu );
+	$public_csv = implode( ',', $public_stati );
+
 	$defaults = array( 'order' => 'ASC', 'orderby' => 'menu_order', 'post_type' => 'nav_menu_item',
-		'post_status' => 'publish', 'output' => ARRAY_A, 'output_key' => 'menu_order', 'nopaging' => true,
+		'post_status' => $public_csv, 'output' => ARRAY_A, 'output_key' => 'menu_order', 'nopaging' => true,
 		'update_post_term_cache' => false );
 	$args = wp_parse_args( $args, $defaults );
 	if ( count( $items ) > 1 )
Index: wp-includes/post.php
===================================================================
--- wp-includes/post.php	(revision 20434)
+++ wp-includes/post.php	(working copy)
@@ -95,56 +95,82 @@
 	) );
 
 	register_post_status( 'publish', array(
-		'label'       => _x( 'Published', 'post' ),
+		'labels'	  => array( 
+			'name' 	  => _x( 'Published', 'post' ),
+			'publish' => esc_attr__('Publish'),
+			'count' => _n_noop( 'Published <span class="count">(%s)</span>', 'Published <span class="count">(%s)</span>' ),
+		),
 		'public'      => true,
 		'_builtin'    => true, /* internal use only. */
-		'label_count' => _n_noop( 'Published <span class="count">(%s)</span>', 'Published <span class="count">(%s)</span>' ),
 	) );
 
 	register_post_status( 'future', array(
-		'label'       => _x( 'Scheduled', 'post' ),
+		'labels'	  => array( 
+			'name' 	  => _x( 'Scheduled', 'post' ),
+			'publish' => esc_attr__('Schedule'),
+			'count' => _n_noop('Scheduled <span class="count">(%s)</span>', 'Scheduled <span class="count">(%s)</span>' ),
+		),
 		'protected'   => true,
 		'_builtin'    => true, /* internal use only. */
-		'label_count' => _n_noop('Scheduled <span class="count">(%s)</span>', 'Scheduled <span class="count">(%s)</span>' ),
 	) );
 
 	register_post_status( 'draft', array(
-		'label'       => _x( 'Draft', 'post' ),
+		'labels'	  => array( 
+			'name' 	  => _x( 'Draft', 'post' ),
+			'save_as' => esc_attr__('Save Draft'), 
+			'count' => _n_noop( 'Draft <span class="count">(%s)</span>', 'Drafts <span class="count">(%s)</span>' ),
+		),
 		'protected'   => true,
 		'_builtin'    => true, /* internal use only. */
-		'label_count' => _n_noop( 'Draft <span class="count">(%s)</span>', 'Drafts <span class="count">(%s)</span>' ),
 	) );
 
 	register_post_status( 'pending', array(
-		'label'       => _x( 'Pending', 'post' ),
+		'labels'	  => array( 
+			'name' 	  => _x( 'Pending', 'post' ),
+			'caption' => __( 'Pending Review' ),
+			'publish' => esc_attr__('Submit for Review'),
+			'count' => _n_noop( 'Pending <span class="count">(%s)</span>', 'Pending <span class="count">(%s)</span>' ),
+		),
 		'protected'   => true,
 		'_builtin'    => true, /* internal use only. */
-		'label_count' => _n_noop( 'Pending <span class="count">(%s)</span>', 'Pending <span class="count">(%s)</span>' ),
+		'moderation'  => true,
 	) );
 
 	register_post_status( 'private', array(
-		'label'       => _x( 'Private', 'post' ),
+		'labels'	  => array( 
+			'name'   => _x( 'Private', 'post' ),
+			'caption' => __( 'Privately Published' ),
+			'count' => _n_noop( 'Private <span class="count">(%s)</span>', 'Private <span class="count">(%s)</span>' ),
+		),
 		'private'     => true,
 		'_builtin'    => true, /* internal use only. */
-		'label_count' => _n_noop( 'Private <span class="count">(%s)</span>', 'Private <span class="count">(%s)</span>' ),
 	) );
 
 	register_post_status( 'trash', array(
-		'label'       => _x( 'Trash', 'post' ),
+		'labels'	  => array( 
+			'name'   => _x( 'Trash', 'post' ),
+			'count' => _n_noop( 'Trash <span class="count">(%s)</span>', 'Trash <span class="count">(%s)</span>' ),
+		),
 		'internal'    => true,
 		'_builtin'    => true, /* internal use only. */
-		'label_count' => _n_noop( 'Trash <span class="count">(%s)</span>', 'Trash <span class="count">(%s)</span>' ),
 		'show_in_admin_status_list' => true,
 	) );
 
 	register_post_status( 'auto-draft', array(
-		'label'    => 'auto-draft',
+		'labels'	  => array( 
+			'name'    => 'auto-draft',
+			'caption' => __( 'Draft' ),
+		),
 		'internal' => true,
 		'_builtin' => true, /* internal use only. */
+		'show_in_admin_all_list' => false,
+		'show_in_admin_status_list' => false,
 	) );
 
 	register_post_status( 'inherit', array(
-		'label'    => 'inherit',
+		'labels'	  => array( 
+			'name'   => 'inherit',
+		),
 		'internal' => true,
 		'_builtin' => true, /* internal use only. */
 		'exclude_from_search' => false,
@@ -632,6 +658,32 @@
 }
 
 /**
+ * Add an already registered post status to an object type.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 3.1.0
+ * @uses $wp_post_statuses Modifies post_type object
+ *
+ * @param string $post_status Name of post_status object
+ * @param array|string $object_type Name of the object type
+ * @return bool True if successful, false if not
+ */
+function register_status_for_object_type( $post_status, $object_type) {
+	global $wp_post_statuses;
+
+	if ( ! isset( $wp_post_statuses[$post_status] ) )
+		return false;
+
+	if ( ! get_post_type_object($object_type) )
+		return false;
+
+	$wp_post_statuses[$post_status]->object_type[] = $object_type;
+
+	return true;
+}
+
+/**
  * Register a post type. Do not use before init.
  *
  * A simple function for creating or modifying a post status based on the
@@ -665,13 +717,20 @@
 		$wp_post_statuses = array();
 
 	// Args prefixed with an underscore are reserved for internal use.
-	$defaults = array('label' => false, 'label_count' => false, 'exclude_from_search' => null, '_builtin' => false, '_edit_link' => 'post.php?post=%d', 'capability_type' => 'post', 'hierarchical' => false, 'public' => null, 'internal' => null, 'protected' => null, 'private' => null, 'show_in_admin_all' => null, 'publicly_queryable' => null, 'show_in_admin_status_list' => null, 'show_in_admin_all_list' => null, 'single_view_cap' => null);
+	$defaults = array( 'object_type' => null, 'labels' => array(), 'label_count' => false, 'exclude_from_search' => null, '_builtin' => false, '_edit_link' => 'post.php?post=%d', 'capability_type' => 'post', 'hierarchical' => false, 'public' => null, 'internal' => null, 'protected' => null, 'private' => null, 'moderation' => null, 'publicly_queryable' => null, 'show_in_admin_status_list' => null, 'show_in_admin_all_list' => null, 'single_view_cap' => null);
+	
 	$args = wp_parse_args($args, $defaults);
 	$args = (object) $args;
 
 	$post_status = sanitize_key($post_status);
 	$args->name = $post_status;
 
+	if ( null == $args->object_type ) {
+		$args->object_type = array_values( get_post_types( array( 'public' => true, 'show_ui' => true ) ) );
+	} else {
+		$args->object_type = (array) $args->object_type;
+	}
+	
 	if ( null === $args->public && null === $args->internal && null === $args->protected && null === $args->private )
 		$args->internal = true;
 
@@ -681,6 +740,9 @@
 	if ( null === $args->private  )
 		$args->private = false;
 
+	if ( null === $args->moderation  )
+		$args->moderation = false;
+		
 	if ( null === $args->protected  )
 		$args->protected = false;
 
@@ -702,12 +764,38 @@
 	if ( null === $args->single_view_cap )
 		$args->single_view_cap = $args->public ? '' : 'edit';
 
-	if ( false === $args->label )
-		$args->label = $post_status;
+	$args->labels = (object) $args->labels;
 
-	if ( false === $args->label_count )
-		$args->label_count = array( $args->label, $args->label );
+	if ( empty( $args->labels->name ) )
+		$args->labels->name = ( ! empty( $args->label ) ) ? $args->label : $post_status;
+	
+	if ( empty( $args->label ) )
+		$args->label = $args->labels->name;
+		
+	if ( empty( $args->labels->caption ) )
+		$args->labels->caption = $args->label;
 
+	if ( empty( $args->labels->count ) )
+		$args->labels->count = ( ! empty( $args->label_count ) ) ? $args->label_count : array( $args->label, $args->label );
+
+	if ( empty( $args->label_count ) )	// TODO: need to support this for external API?
+		$args->label_count = $args->labels->count;
+
+	if ( empty( $args->labels->publish ) )
+		$args->labels->publish = esc_attr( sprintf( __( 'Set %s' ), $args->label ) );
+
+	if ( empty( $args->labels->save_as ) )
+		$args->labels->save_as = esc_attr( sprintf( __( 'Save as %s' ), $args->label ) );
+
+	if ( empty( $args->labels->visibility ) ) {
+		if ( 'publish' == $post_status )
+			$args->labels->visibility =__( 'Public' );
+		elseif ( $args->public )
+			$args->labels->visibility = esc_attr( sprintf( __( 'Public (%s)' ), $args->label ) );
+		elseif ( $args->private )
+			$args->labels->visibility = $args->label;
+	}
+
 	$wp_post_statuses[$post_status] = $args;
 
 	return $args;
@@ -753,13 +841,60 @@
  */
 function get_post_stati( $args = array(), $output = 'names', $operator = 'and' ) {
 	global $wp_post_statuses;
+	
+	$post_statuses = $wp_post_statuses;
 
 	$field = ('names' == $output) ? 'name' : false;
+	
+	//wp_filter_object_list doesn't like nested arrays, 
+	//so grab a subset of post stati that match the query, and THEN run through wp_list_filter
+	if ( ! empty( $args['object_type'] ) ) {
+		$post_statuses = get_object_stati( $args['object_type'], 'objects' );
+		unset( $args['object_type'] );
+	}
 
-	return wp_filter_object_list($wp_post_statuses, $args, $operator, $field);
+	return wp_filter_object_list( $post_statuses, $args, $operator, $field );
 }
 
 /**
+ * Return all of the post_statuses that are of $object_type.
+ * *
+ * <code><?php $taxonomies = get_object_stati('post'); ?></code> Should
+ * result in <code>Array('publish', 'future', 'pending', etc. )</code>
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 3.5
+ *
+ * @uses $wp_post_statuses
+ *
+ * @param array|string|object $object Name of the type of post_status object, or an object (row from posts)
+ * @param string $output The type of output to return, either status 'names' or 'objects'. 'names' is the default.
+ * @return array The names of all statuses of $object_type.
+ */
+
+function get_object_stati($object, $output = 'names') {
+	global $wp_post_statuses;
+
+	if ( is_object($object) )
+		$object = $object->post_type;
+
+	$object = (array) $object;
+
+	$stati = array();
+	foreach ( (array) $wp_post_statuses as $status_name => $status_obj ) {
+		if ( array_intersect($object, (array) $status_obj->object_type) ) {
+			if ( 'names' == $output )
+				$stati[] = $status_name;
+			else
+				$stati[ $status_name ] = $status_obj;
+		}
+	}
+
+	return $stati;
+}
+
+/**
  * Whether the post type is hierarchical.
  *
  * A false return value might also mean that the post type does not exist.
@@ -928,7 +1063,7 @@
 		'_builtin' => false, '_edit_link' => 'post.php?post=%d', 'hierarchical' => false,
 		'public' => false, 'rewrite' => true, 'has_archive' => false, 'query_var' => true,
 		'supports' => array(), 'register_meta_box_cb' => null,
-		'taxonomies' => array(), 'show_ui' => null, 'menu_position' => null, 'menu_icon' => null,
+		'taxonomies' => array(), 'statuses' => array(), 'show_ui' => null, 'menu_position' => null, 'menu_icon' => null,
 		'can_export' => true,
 		'show_in_nav_menus' => null, 'show_in_menu' => null, 'show_in_admin_bar' => null,
 	);
@@ -1049,6 +1184,10 @@
 	foreach ( $args->taxonomies as $taxonomy ) {
 		register_taxonomy_for_object_type( $taxonomy, $post_type );
 	}
+	
+	foreach ( $args->statuses as $post_status ) {
+		register_status_for_object_type( $post_status, $post_type );
+	}
 
 	do_action( 'registered_post_type', $post_type, $args );
 
@@ -1823,13 +1962,17 @@
 	$query = "SELECT post_status, COUNT( * ) AS num_posts FROM {$wpdb->posts} WHERE post_type = %s";
 	if ( 'readable' == $perm && is_user_logged_in() ) {
 		$post_type_object = get_post_type_object($type);
-		if ( !current_user_can( $post_type_object->cap->read_private_posts ) ) {
-			$cache_key .= '_' . $perm . '_' . $user->ID;
-			$query .= " AND (post_status != 'private' OR ( post_author = '$user->ID' AND post_status = 'private' ))";
+		foreach( get_post_stati( array( 'private' => true, 'object_type' => $type ) ) as $_status ) {
+			$cap_name = "read_{$_status}_posts";
+			if ( ! empty($post_type_object->cap->$cap_name) && ! current_user_can( $post_type_object->cap->$cap_name ) ) {
+				$suffix = ( 'private' == $_status ) ? '' : $_status;
+				$cache_key .= '_' . $perm . $suffix . '_' . $user->ID;
+				$query .= " AND (post_status != '$_status' OR ( post_author = '$user->ID' AND post_status = '$_status' ))";
+			}
 		}
 	}
 	$query .= ' GROUP BY post_status';
-
+	
 	$count = wp_cache_get($cache_key, 'counts');
 	if ( false !== $count )
 		return $count;
@@ -1837,7 +1980,7 @@
 	$count = $wpdb->get_results( $wpdb->prepare( $query, $type ), ARRAY_A );
 
 	$stats = array();
-	foreach ( get_post_stati() as $state )
+	foreach ( get_post_stati( array( 'object_type' => $type ) ) as $state )
 		$stats[$state] = 0;
 
 	foreach ( (array) $count as $row )
@@ -2320,13 +2463,16 @@
 		$args = array( 'numberposts' => absint( $args ) );
 	}
 
+	$status_names = get_post_stati( array( 'public' => true, 'object_type' => 'post' ) );
+	$status_names_csv = "'" . implode( "', '", $status_names ) . "'";
+
 	// Set default arguments
 	$defaults = array(
 		'numberposts' => 10, 'offset' => 0,
 		'category' => 0, 'orderby' => 'post_date',
 		'order' => 'DESC', 'include' => '',
 		'exclude' => '', 'meta_key' => '',
-		'meta_value' =>'', 'post_type' => 'post', 'post_status' => 'draft, publish, future, pending, private',
+		'meta_value' =>'', 'post_type' => 'post', 'post_status' => $status_names_csv,
 		'suppress_filters' => true
 	);
 
@@ -2493,13 +2639,16 @@
 	}
 
 	// Don't allow contributors to set the post slug for pending review posts
-	if ( 'pending' == $post_status && !current_user_can( 'publish_posts' ) )
+	$post_status_obj = get_post_status_object( $post_status );
+	$draft_or_pending = in_array( $post_status, array( 'draft', 'auto-draft' ) ) || ! empty( $post_status_obj->moderation );
+
+	if ( ! empty( $post_status_obj->moderation ) && ! current_user_can( 'publish_posts' ) )
 		$post_name = '';
 
 	// Create a valid post name. Drafts and pending posts are allowed to have an empty
 	// post name.
 	if ( empty($post_name) ) {
-		if ( !in_array( $post_status, array( 'draft', 'pending', 'auto-draft' ) ) )
+		if ( ! $draft_or_pending )
 			$post_name = sanitize_title($post_title);
 		else
 			$post_name = '';
@@ -2517,7 +2666,7 @@
 		$post_date = current_time('mysql');
 
 	if ( empty($post_date_gmt) || '0000-00-00 00:00:00' == $post_date_gmt ) {
-		if ( !in_array( $post_status, array( 'draft', 'pending', 'auto-draft' ) ) )
+		if ( ! $draft_or_pending )
 			$post_date_gmt = get_gmt_from_date($post_date);
 		else
 			$post_date_gmt = '0000-00-00 00:00:00';
@@ -2531,7 +2680,9 @@
 		$post_modified_gmt = $post_date_gmt;
 	}
 
-	if ( 'publish' == $post_status ) {
+	$set_status = $post_status;
+	
+	if ( $post_status_obj->public || $post_status_obj->private ) {
 		$now = gmdate('Y-m-d H:i:59');
 		if ( mysql2date('U', $post_date_gmt, false) > mysql2date('U', $now, false) )
 			$post_status = 'future';
@@ -2541,6 +2692,11 @@
 			$post_status = 'publish';
 	}
 
+	if ( ( 'future' == $post_status ) && ( 'publish' != $set_status ) ) {
+		update_post_meta( $post_ID, '_scheduled_status', $set_status );
+	} else
+		delete_post_meta( $post_ID, '_scheduled_status' );
+
 	if ( empty($comment_status) ) {
 		if ( $update )
 			$comment_status = 'closed';
@@ -2571,7 +2727,7 @@
 	else
 		$menu_order = 0;
 
-	if ( !isset($post_password) || 'private' == $post_status )
+	if ( ! isset($post_password) || $post_status_obj->private )
 		$post_password = '';
 
 	$post_name = wp_unique_post_slug($post_name, $post_ID, $post_status, $post_type, $post_parent);
@@ -2612,7 +2768,10 @@
 		$where = array( 'ID' => $post_ID );
 	}
 
-	if ( empty($data['post_name']) && !in_array( $data['post_status'], array( 'draft', 'pending', 'auto-draft' ) ) ) {
+	$post_status_obj = get_post_status_object( $data['post_status'] );
+	$draft_or_pending = in_array( $data['post_status'], array('draft', 'auto-draft') ) || ! empty($post_status_obj->moderation);
+	
+	if ( empty($data['post_name']) && ! $draft_or_pending ) {
 		$data['post_name'] = sanitize_title($data['post_title'], $post_ID);
 		$wpdb->update( $wpdb->posts, array( 'post_name' => $data['post_name'] ), $where );
 	}
@@ -2702,10 +2861,11 @@
 		$post_cats = $post['post_category'];
 
 	// Drafts shouldn't be assigned a date unless explicitly done so by the user
-	if ( isset( $post['post_status'] ) && in_array($post['post_status'], array('draft', 'pending', 'auto-draft')) && empty($postarr['edit_date']) &&
-			 ('0000-00-00 00:00:00' == $post['post_date_gmt']) )
-		$clear_date = true;
-	else
+	if ( isset( $post['post_status'] ) && empty($postarr['edit_date']) && ('0000-00-00 00:00:00' == $post['post_date_gmt']) ) {
+		$post_status_obj = get_post_status_object( $post['post_status'] );
+
+		$clear_date = in_array( $post['post_status'], array('draft', 'auto-draft') ) || ! empty($post_status_obj->moderation);
+	} else
 		$clear_date = false;
 
 	// Merge old and new fields with new fields overwriting old ones.
@@ -2743,8 +2903,14 @@
 	if ( 'publish' == $post->post_status )
 		return;
 
-	$wpdb->update( $wpdb->posts, array( 'post_status' => 'publish' ), array( 'ID' => $post_id ) );
+	if ( 'future' == $post->post_status ) {
+		if ( ! $post_status = get_post_meta( $post_id, '_scheduled_status', true ) )
+			$post_status = 'publish';	
+	} else
+		$post_status = 'publish';
 
+	$wpdb->update( $wpdb->posts, array( 'post_status' => $post_status ), array( 'ID' => $post_id ) );
+
 	$old_status = $post->post_status;
 	$post->post_status = 'publish';
 	wp_transition_post_status('publish', $old_status, $post);
@@ -2801,7 +2967,9 @@
  * @return string unique slug for the post, based on $post_name (with a -1, -2, etc. suffix)
  */
 function wp_unique_post_slug( $slug, $post_ID, $post_status, $post_type, $post_parent ) {
-	if ( in_array( $post_status, array( 'draft', 'pending', 'auto-draft' ) ) )
+	$post_status_obj = get_post_status_object( $post_status );
+
+	if ( in_array( $post_status, array('draft', 'auto-draft') ) || ! empty($post_status_obj->moderation) )
 		return $slug;
 
 	global $wpdb, $wp_rewrite;
@@ -3365,7 +3533,8 @@
 	// Make sure we have a valid post status
 	if ( !is_array( $post_status ) )
 		$post_status = explode( ',', $post_status );
-	if ( array_diff( $post_status, get_post_stati() ) )
+	if ( array_diff( $post_status, get_post_stati( array( 'object_type' => $post_type ) ) ) )
+
 		return false;
 
 	$cache = array();
Index: wp-includes/query.php
===================================================================
--- wp-includes/query.php	(revision 20434)
+++ wp-includes/query.php	(working copy)
@@ -2402,16 +2402,18 @@
 			$post_type_object = get_post_type_object ( 'post' );
 		}
 
+		$_post_type = ( $post_type ) ? $post_type : 'post';  // corresponds to hardcoded default for POST_TYPE clause
+		$type_arg = ( 'any' == $_post_type ) ? array() : array( 'object_type' => $_post_type );
+
 		if ( ! empty( $post_type_object ) ) {
+			$post_type_cap = $post_type_object->capability_type;
 			$edit_cap = $post_type_object->cap->edit_post;
 			$read_cap = $post_type_object->cap->read_post;
 			$edit_others_cap = $post_type_object->cap->edit_others_posts;
-			$read_private_cap = $post_type_object->cap->read_private_posts;
 		} else {
 			$edit_cap = 'edit_' . $post_type_cap;
 			$read_cap = 'read_' . $post_type_cap;
 			$edit_others_cap = 'edit_others_' . $post_type_cap . 's';
-			$read_private_cap = 'read_private_' . $post_type_cap . 's';
 		}
 
 		if ( ! empty( $q['post_status'] ) ) {
@@ -2421,24 +2423,36 @@
 				$q_status = explode(',', $q_status);
 			$r_status = array();
 			$p_status = array();
+			$p_status_owner = array();
 			$e_status = array();
 			if ( in_array('any', $q_status) ) {
 				foreach ( get_post_stati( array('exclude_from_search' => true) ) as $status )
 					$e_status[] = "$wpdb->posts.post_status <> '$status'";
 			} else {
-				foreach ( get_post_stati() as $status ) {
+				$_args = array_merge( array(), $type_arg ); 
+				foreach ( get_post_stati( $_args, 'object' ) as $status => $status_obj ) {
 					if ( in_array( $status, $q_status ) ) {
-						if ( 'private' == $status )
-							$p_status[] = "$wpdb->posts.post_status = '$status'";
-						else
+						if ( $status_obj->private ) {
+							if ( ! empty($post_type_object) ) {
+								$check_cap = "read_{$status}_posts";
+								$read_private_cap = ( ! empty( $post_type_object->cap->$check_cap ) ) ? $post_type_object->cap->$check_cap : $post_type_object->cap->read_private_posts;
+							} else
+								$read_private_cap = 'read_private_' . $post_type_cap . 's';
+							
+							if ( ! empty($q['perm'] ) && 'readable' == $q['perm'] && ! current_user_can( $read_private_cap ) )
+								$p_status_owner[] = "$wpdb->posts.post_status = '$status'";
+							else
+								$p_status[] = "$wpdb->posts.post_status = '$status'";
+						} else
 							$r_status[] = "$wpdb->posts.post_status = '$status'";
 					}
 				}
 			}
 
 			if ( empty($q['perm'] ) || 'readable' != $q['perm'] ) {
-				$r_status = array_merge($r_status, $p_status);
+				$r_status = array_merge($r_status, $p_status, $p_status_owner);
 				unset($p_status);
+				unset($p_status_owner);
 			}
 
 			if ( !empty($e_status) ) {
@@ -2450,24 +2464,30 @@
 				else
 					$statuswheres[] = "(" . join( ' OR ', $r_status ) . ")";
 			}
-			if ( !empty($p_status) ) {
+
+			if ( ! empty( $p_status ) ) {
 				if ( !empty($q['perm'] ) && 'readable' == $q['perm'] && !current_user_can($read_private_cap) )
 					$statuswheres[] = "($wpdb->posts.post_author = $user_ID " . "AND (" . join( ' OR ', $p_status ) . "))";
 				else
 					$statuswheres[] = "(" . join( ' OR ', $p_status ) . ")";
 			}
+			if ( ! empty( $p_status ) ) {			
+				$statuswheres[] = "(" . join( ' OR ', $p_status ) . ")";
+			}
 			if ( $post_status_join ) {
 				$join .= " LEFT JOIN $wpdb->posts AS p2 ON ($wpdb->posts.post_parent = p2.ID) ";
 				foreach ( $statuswheres as $index => $statuswhere )
 					$statuswheres[$index] = "($statuswhere OR ($wpdb->posts.post_status = 'inherit' AND " . str_replace($wpdb->posts, 'p2', $statuswhere) . "))";
 			}
 			foreach ( $statuswheres as $statuswhere )
-				$where .= " AND $statuswhere";
+				$where .= " AND $statuswhere";	
+
 		} elseif ( !$this->is_singular ) {
 			$where .= " AND ($wpdb->posts.post_status = 'publish'";
 
 			// Add public states.
-			$public_states = get_post_stati( array('public' => true) );
+			$_args = array_merge( array( 'public' => true ), $type_arg );
+			$public_states = apply_filters_ref_array( 'posts_public_stati', array( get_post_stati( $_args ), &$this ) );
 			foreach ( (array) $public_states as $state ) {
 				if ( 'publish' == $state ) // Publish is hard-coded above.
 					continue;
@@ -2476,16 +2496,25 @@
 
 			if ( $this->is_admin ) {
 				// Add protected states that should show in the admin all list.
-				$admin_all_states = get_post_stati( array('protected' => true, 'show_in_admin_all_list' => true) );
+				$_args = array_merge( array( 'protected' => true, 'show_in_admin_all_list' => true ), $type_arg );
+				$admin_all_states = get_post_stati( $_args );
 				foreach ( (array) $admin_all_states as $state )
 					$where .= " OR $wpdb->posts.post_status = '$state'";
 			}
 
 			if ( is_user_logged_in() ) {
 				// Add private states that are limited to viewing by the author of a post or someone who has caps to read private states.
-				$private_states = get_post_stati( array('private' => true) );
-				foreach ( (array) $private_states as $state )
+				$_args = array_merge( array( 'private' => true ), $type_arg );
+				$private_states = apply_filters_ref_array( 'posts_private_stati', array( get_post_stati( $_args ), &$this ) );
+				foreach ( (array) $private_states as $state ) {
+					if ( ! empty($post_type_object) ) {
+						$check_cap = "read_{$state}_posts";
+						$read_private_cap = ( ! empty( $post_type_object->cap->$check_cap ) ) ? $post_type_object->cap->$check_cap : $post_type_object->cap->read_private_posts;
+					} else
+						$read_private_cap = 'read_private_' . $post_type_cap . 's';
+
 					$where .= current_user_can( $read_private_cap ) ? " OR $wpdb->posts.post_status = '$state'" : " OR $wpdb->posts.post_author = $user_ID AND $wpdb->posts.post_status = '$state'";
+				}
 			}
 
 			$where .= ')';
@@ -2526,8 +2555,11 @@
 				$cwhere = "WHERE comment_approved = '1' $where";
 				$cgroupby = "$wpdb->comments.comment_id";
 			} else { // Other non singular e.g. front
+				$public_stati = apply_filters( 'comment_feed_stati', get_post_stati( array( 'public' => true ) ) );
+				$public_csv = implode( "', '", $public_stati );
+
 				$cjoin = "JOIN $wpdb->posts ON ( $wpdb->comments.comment_post_ID = $wpdb->posts.ID )";
-				$cwhere = "WHERE post_status = 'publish' AND comment_approved = '1'";
+				$cwhere = "WHERE post_status IN ( '$public_csv' ) AND comment_approved = '1'";
 				$cgroupby = '';
 			}
 
@@ -2738,11 +2770,13 @@
 					$stickies_where = "AND $wpdb->posts.post_type IN ('" . $post_types . "')";
 				}
 
+				$public_stati = apply_filters_ref_array( 'posts_sticky_stati', array( get_post_stati( array( 'public' => true ) ), &$this ) );
 				$stickies = $wpdb->get_results( "SELECT * FROM $wpdb->posts WHERE $wpdb->posts.ID IN ($stickies__in) $stickies_where" );
 				foreach ( $stickies as $sticky_post ) {
 					// Ignore sticky posts the current user cannot read or are not published.
-					if ( 'publish' != $sticky_post->post_status )
+					if ( ! in_array( $sticky_post->post_status, $public_stati ) )
 						continue;
+
 					array_splice($this->posts, $sticky_offset, 0, array($sticky_post));
 					$sticky_offset++;
 				}
Index: wp-includes/general-template.php
===================================================================
--- wp-includes/general-template.php	(revision 20434)
+++ wp-includes/general-template.php	(working copy)
@@ -915,9 +915,12 @@
 	}
 
 	//filters
-	$where = apply_filters( 'getarchives_where', "WHERE post_type = 'post' AND post_status = 'publish'", $r );
-	$join = apply_filters( 'getarchives_join', '', $r );
+	$public_stati = apply_filters( 'getarchives_stati', get_post_stati( array( 'public' => true ) ) );
+	$public_csv = implode( "', '", $public_stati );
 
+	$where = apply_filters('getarchives_where', "WHERE post_type = 'post' AND post_status IN ('" . $public_csv . "')", $r );
+	$join = apply_filters('getarchives_join', "", $r);
+
 	$output = '';
 
 	if ( 'monthly' == $type ) {
Index: wp-includes/script-loader.php
===================================================================
--- wp-includes/script-loader.php	(revision 20434)
+++ wp-includes/script-loader.php	(working copy)
@@ -332,7 +332,7 @@
 		$scripts->add( 'postbox', "/wp-admin/js/postbox$suffix.js", array('jquery-ui-sortable'), false, 1 );
 
 		$scripts->add( 'post', "/wp-admin/js/post$suffix.js", array('suggest', 'wp-lists', 'postbox'), false, 1 );
-		$scripts->localize( 'post', 'postL10n', array(
+		$arr = array(
 			'ok' => __('OK'),
 			'cancel' => __('Cancel'),
 			'publishOn' => __('Publish on:'),
@@ -352,9 +352,25 @@
 			'privatelyPublished' => __('Privately Published'),
 			'published' => __('Published'),
 			'comma' => _x( ',', 'tag delimiter' ),
-		) );
+		);
+		
+		$custom = array();
+		foreach( get_post_stati( array( 'public' => true, 'private' => true ), 'object', 'or' ) as $_status => $_status_obj ) {
+			if ( 'publish' == $_status )
+				continue;
 
+			$custom[ $_status ] = $_status_obj->labels->visibility;
+
+			if ( $_status_obj->public )
+				$custom[ $_status . 'Sticky' ] = sprintf( __('%s, Sticky'), $_status_obj->label );
+		}
+
+		$arr = array_merge( $custom, $arr );  // note: 'publish' has existing value of 'Publish', cannot be used to reference status name 
+
+		$scripts->localize( 'post', 'postL10n', $arr );
+
 		$scripts->add( 'link', "/wp-admin/js/link$suffix.js", array('wp-lists', 'postbox'), false, 1 );
+		$scripts->add_data( 'link', 'group', 1 );
 
 		$scripts->add( 'comment', "/wp-admin/js/comment$suffix.js", array('jquery') );
 		$scripts->add_data( 'comment', 'group', 1 );
Index: wp-content
===================================================================
--- wp-content	(revision 20434)
+++ wp-content	(working copy)

Property changes on: wp-content
___________________________________________________________________
Added: svn:ignore
## -0,0 +1 ##
+.
Index: wp-content/plugins
===================================================================
--- wp-content/plugins	(revision 20434)
+++ wp-content/plugins	(working copy)

Property changes on: wp-content/plugins
___________________________________________________________________
Added: svn:ignore
## -0,0 +1 ##
+.
Index: wp-admin/includes/post.php
===================================================================
--- wp-admin/includes/post.php	(revision 20434)
+++ wp-admin/includes/post.php	(working copy)
@@ -71,7 +71,7 @@
 	// What to do based on which button they pressed
 	if ( isset($post_data['saveasdraft']) && '' != $post_data['saveasdraft'] )
 		$post_data['post_status'] = 'draft';
-	if ( isset($post_data['saveasprivate']) && '' != $post_data['saveasprivate'] )
+	if ( isset($post_data['saveasprivate']) && '' != $post_data['saveasprivate'] ) // TODO: is this set anywhere?
 		$post_data['post_status'] = 'private';
 	if ( isset($post_data['publish']) && ( '' != $post_data['publish'] ) && ( !isset($post_data['post_status']) || $post_data['post_status'] != 'private' ) )
 		$post_data['post_status'] = 'publish';
@@ -88,10 +88,20 @@
 
 	// Posts 'submitted for approval' present are submitted to $_POST the same as if they were being published.
 	// Change status from 'publish' to 'pending' if user lacks permissions to publish or to resave published posts.
-	if ( isset($post_data['post_status']) && ('publish' == $post_data['post_status'] && !current_user_can( $ptype->cap->publish_posts )) )
-		if ( $previous_status != 'publish' || !current_user_can( 'edit_post', $post_id ) )
-			$post_data['post_status'] = 'pending';
+	if ( isset($post_data['post_status']) && ('publish' == $post_data['post_status'] && !current_user_can( $ptype->cap->publish_posts )) ) {
+		if ( $previous_status != 'publish' || !current_user_can( 'edit_post', $post_id ) ) {
+			$moderation_status = apply_filters( 'post_moderation_status', 'pending', $post->ID );
 
+			$_status_obj = get_post_status_object( $moderation_status );
+			$cap_name = "set_{$moderation_status}_posts";
+
+			if ( empty($_status_obj) || ! $_status_obj->moderation || ( ! empty($ptype->cap->$cap_name) && ! current_user_can($ptype->cap->$cap_name) ) )
+				$moderation_status = 'pending';
+
+			$post_data['post_status'] = $moderation_status;
+		}
+	}
+
 	if ( ! isset($post_data['post_status']) )
 		$post_data['post_status'] = $previous_status;
 
@@ -182,11 +192,17 @@
 			case 'password' :
 				unset( $post_data['sticky'] );
 				break;
-			case 'private' :
-				$post_data['post_status'] = 'private';
-				$post_data['post_password'] = '';
-				unset( $post_data['sticky'] );
-				break;
+			default:
+				$status_obj = get_post_status_object( $post_data['visibility'] );
+	
+				if ( ! empty( $status_obj->private ) || ! empty( $status_obj->public ) ) {
+					$post_data['post_status'] = $status_obj->name;
+					$post_data['post_password'] = '';
+				}
+
+				if ( ! empty( $status_obj->private ) ) {
+					unset( $post_data['sticky'] );
+				}
 		}
 	}
 
@@ -568,11 +584,13 @@
 			case 'password' :
 				unset( $_POST['sticky'] );
 				break;
-			case 'private' :
-				$_POST['post_status'] = 'private';
-				$_POST['post_password'] = '';
-				unset( $_POST['sticky'] );
-				break;
+			default:
+				$status_obj = get_post_status_object( $_POST['visibility'] );	
+				if ( ! empty( $status_obj->private ) ) {
+					$_POST['post_status'] = $status_obj->name;
+					$_POST['post_password'] = '';
+					unset( $_POST['sticky'] );
+				}
 		}
 	}
 
@@ -862,7 +880,7 @@
 
 	if ( isset($q['orderby']) )
 		$orderby = $q['orderby'];
-	elseif ( isset($q['post_status']) && in_array($q['post_status'], array('pending', 'draft')) )
+	elseif ( isset($q['post_status']) && ( in_array($q['post_status'], array('pending', 'draft')) || ! empty( $GLOBALS['wp_post_statuses'][$q['post_status']]->moderation ) ) )
 		$orderby = 'modified';
 
 	if ( isset($q['order']) )
@@ -1024,9 +1042,11 @@
 	$original_date = $post->post_date;
 	$original_name = $post->post_name;
 
+	$post_status_obj = get_post_status_object( $post->post_status );
+	
 	// Hack: get_permalink would return ugly permalink for
 	// drafts, so we will fake, that our post is published
-	if ( in_array($post->post_status, array('draft', 'pending')) ) {
+	if ( in_array($post->post_status, array('draft', 'pending')) || ! empty($post_status_obj->moderation) ) {
 		$post->post_status = 'publish';
 		$post->post_name = sanitize_title($post->post_name ? $post->post_name : $post->post_title, $post->ID);
 	}
@@ -1084,7 +1104,8 @@
 
 	list($permalink, $post_name) = get_sample_permalink($post->ID, $new_title, $new_slug);
 
-	if ( 'publish' == $post->post_status ) {
+	$public_stati = get_post_stati( array( 'public' => true ) );
+	if ( in_array( $post->post_status, $public_stati ) ) {
 		$ptype = get_post_type_object($post->post_type);
 		$view_post = $ptype->labels->view_item;
 		$title = __('Click to edit this part of the permalink');
Index: wp-admin/includes/template.php
===================================================================
--- wp-admin/includes/template.php	(revision 20434)
+++ wp-admin/includes/template.php	(working copy)
@@ -254,7 +254,16 @@
 	<div class="post_author">' . $post->post_author . '</div>
 	<div class="comment_status">' . esc_html( $post->comment_status ) . '</div>
 	<div class="ping_status">' . esc_html( $post->ping_status ) . '</div>
-	<div class="_status">' . esc_html( $post->post_status ) . '</div>
+	<div class="_status">' . esc_html( $post->post_status ) . '</div>';
+
+	if ( 'future' == $post->post_status ) {
+		if ( ! $scheduled_status = get_post_meta( $post->ID, '_scheduled_status', true ) )
+			$scheduled_status = 'publish';	
+	echo '
+	<div class="scheduled_status">' . esc_html( $scheduled_status  ). '</div>';
+	}
+
+	echo '
 	<div class="jj">' . mysql2date( 'd', $post->post_date, false ) . '</div>
 	<div class="mm">' . mysql2date( 'm', $post->post_date, false ) . '</div>
 	<div class="aa">' . mysql2date( 'Y', $post->post_date, false ) . '</div>
@@ -575,9 +584,11 @@
 function touch_time( $edit = 1, $for_post = 1, $tab_index = 0, $multi = 0 ) {
 	global $wp_locale, $post, $comment;
 
-	if ( $for_post )
-		$edit = ! ( in_array($post->post_status, array('draft', 'pending') ) && (!$post->post_date_gmt || '0000-00-00 00:00:00' == $post->post_date_gmt ) );
-
+	if ( $for_post ) {
+		$post_status_obj = get_post_status_object($post->post_status);
+		$edit = ( ( 'draft' != $post->post_status ) && empty($post_status_obj->moderation) ) || ( $post->post_date_gmt && '0000-00-00 00:00:00' != $post->post_date_gmt );
+	}
+			
 	$tab_index_attribute = '';
 	if ( (int) $tab_index > 0 )
 		$tab_index_attribute = " tabindex=\"$tab_index\"";
@@ -1467,18 +1478,26 @@
 	else
 		$post_status = '';
 
+	$post_status_obj = get_post_status_object($post->post_status);
+	
 	if ( !empty($post->post_password) )
 		$post_states['protected'] = __('Password protected');
-	if ( 'private' == $post->post_status && 'private' != $post_status )
-		$post_states['private'] = __('Private');
-	if ( 'draft' == $post->post_status && 'draft' != $post_status )
-		$post_states['draft'] = __('Draft');
-	if ( 'pending' == $post->post_status && 'pending' != $post_status )
-		/* translators: post state */
-		$post_states['pending'] = _x('Pending', 'post state');
-	if ( is_sticky($post->ID) )
-		$post_states['sticky'] = __('Sticky');
+	
+	if ( $post_status_obj && ( 'publish' != $post->post_status ) ) {
+		if ( $post->post_status != $post_status ) {
+			$post_states[] = $post_status_obj->label;
 
+			if ( 'future' == $post->post_status ) {
+				if ( $scheduled_status = get_post_meta( $post->ID, '_scheduled_status', true ) ) {
+					if ( 'publish' != $scheduled_status ) {
+						if ( $_scheduled_status_obj = get_post_status_object( $scheduled_status ) )
+							$post_states[] = $_scheduled_status_obj->label;
+					}
+				}
+			}
+		}
+	}
+
 	$post_states = apply_filters( 'display_post_states', $post_states );
 
 	if ( ! empty($post_states) ) {
Index: wp-admin/includes/ajax-actions.php
===================================================================
--- wp-admin/includes/ajax-actions.php	(revision 20434)
+++ wp-admin/includes/ajax-actions.php	(working copy)
@@ -735,10 +735,11 @@
 		wp_die( -1 );
 
 	$status = $wpdb->get_var( $wpdb->prepare("SELECT post_status FROM $wpdb->posts WHERE ID = %d", $comment_post_ID) );
+    $post_status_obj = get_post_status_object($status); 
 
-	if ( empty($status) )
+	if ( empty($post_status_obj) ) 
 		wp_die( 1 );
-	elseif ( in_array($status, array('draft', 'pending', 'trash') ) )
+	elseif ( ! $post_status_obj->public && ! $post_status_obj->private )
 		wp_die( __('ERROR: you are replying to a comment on a draft post.') );
 
 	$user = wp_get_current_user();
@@ -1354,10 +1355,26 @@
 	if ( isset($data['post_parent']) )
 		$data['parent_id'] = $data['post_parent'];
 
+	$post_type_object = get_post_type_object( $post['post_type'] ); 
+
 	// status
-	if ( isset($data['keep_private']) && 'private' == $data['keep_private'] )
-		$data['post_status'] = 'private';
-	else
+	foreach( get_post_stati( array( 'internal' => false, 'object_type' => $post['post_type'] ), 'object' ) as $_status => $_status_obj ) {
+		if ( ( 'publish' == $_status ) || ( ! $_status_obj->private && ! $_status_obj->public ) ) // private and custom public stati only here
+			continue;
+
+		if ( isset($data["keep_{$_status}"]) ) {
+			$set_status_cap = "set_{$_status}_posts";
+			$check_cap = ( ! empty( $post_type_object->cap->$set_status_cap ) ) ? $post_type_object->cap->$set_status_cap : $post_type_object->cap->publish_posts;
+
+			if ( current_user_can( $check_cap ) ) {
+				$data['post_status'] = $_status;
+				$keeping_private = true;
+				break;
+			}	
+		}
+	}
+
+	if ( empty($keeping_private) ) // private or custom public status selected and granted
 		$data['post_status'] = $data['_status'];
 
 	if ( empty($data['comment_status']) )
@@ -1445,30 +1462,30 @@
 	if ( count($search_terms) > 1 && $search_terms[0] != $s )
 		$search .= " OR ($wpdb->posts.post_title LIKE '%{$term}%') OR ($wpdb->posts.post_content LIKE '%{$term}%')";
 
-	$posts = $wpdb->get_results( "SELECT ID, post_title, post_status, post_date FROM $wpdb->posts WHERE post_type = '$what' AND post_status IN ('draft', 'publish') AND ($search) ORDER BY post_date_gmt DESC LIMIT 50" );
+	$public_stati = apply_filters( 'find_posts_stati', get_post_stati( array( 'public' => true ) ) );
+	$public_csv = implode( "', '", $public_stati ); 
+	 
+	$posts = $wpdb->get_results( "SELECT ID, post_title, post_status, post_date FROM $wpdb->posts WHERE post_type = '$what' AND post_status IN ('draft', $public_csv) AND ($search) ORDER BY post_date_gmt DESC LIMIT 50" );
 
 	if ( ! $posts ) {
 		$posttype = get_post_type_object($what);
 		wp_die( $posttype->labels->not_found );
 	}
+	
+	$stat = array();
 
 	$html = '<table class="widefat" cellspacing="0"><thead><tr><th class="found-radio"><br /></th><th>'.__('Title').'</th><th>'.__('Date').'</th><th>'.__('Status').'</th></tr></thead><tbody>';
 	foreach ( $posts as $post ) {
 
-		switch ( $post->post_status ) {
-			case 'publish' :
-			case 'private' :
-				$stat = __('Published');
-				break;
-			case 'future' :
-				$stat = __('Scheduled');
-				break;
-			case 'pending' :
-				$stat = __('Pending Review');
-				break;
-			case 'draft' :
-				$stat = __('Draft');
-				break;
+		if ( ! isset( $stat[$post->post_status] ) ) {
+			$_status_obj = get_post_status_object( $post->post_status );
+			
+			if ( ! $_status_obj )
+				$_status_obj = get_post_status_object( 'draft' );
+			elseif ( ( $_status_obj->public || $_status_obj->private ) &&  ( 'publish' != $post->post_status ) )
+				$_status_obj = get_post_status_object( 'publish' );
+
+			$stat[$post->post_status] = $_status_obj->labels->caption;
 		}
 
 		if ( '0000-00-00 00:00:00' == $post->post_date ) {
@@ -1479,7 +1496,7 @@
 		}
 
 		$html .= '<tr class="found-posts"><td class="found-radio"><input type="radio" id="found-'.$post->ID.'" name="found_post_id" value="' . esc_attr($post->ID) . '"></td>';
-		$html .= '<td><label for="found-'.$post->ID.'">'.esc_html( $post->post_title ).'</label></td><td>'.esc_html( $time ).'</td><td>'.esc_html( $stat ).'</td></tr>'."\n\n";
+		$html .= '<td><label for="found-'.$post->ID.'">'.esc_html( $post->post_title ).'</label></td><td>'.esc_html( $time ).'</td><td>'.esc_html( $stat[$post->post_status] ).'</td></tr>'."\n\n";
 	}
 	$html .= '</tbody></table>';
 
Index: wp-admin/includes/meta-boxes.php
===================================================================
--- wp-admin/includes/meta-boxes.php	(revision 20434)
+++ wp-admin/includes/meta-boxes.php	(working copy)
@@ -11,10 +11,22 @@
  */
 function post_submit_meta_box($post) {
 	global $action;
+	
+	$post_type = $post->post_type;
+	$post_type_obj = get_post_type_object($post_type);
+	$can_publish = current_user_can($post_type_obj->cap->publish_posts);
+	$post_status = $post->post_status;
+	
+	if ( ! $post_status_obj = get_post_status_object($post_status) )
+		$post_status_obj = get_post_status_object( 'draft' );
+	
+	$moderation_stati = get_post_stati( array( 'moderation' => true, 'internal' => false, 'object_type' => $post_type ), 'object' );
 
-	$post_type = $post->post_type;
-	$post_type_object = get_post_type_object($post_type);
-	$can_publish = current_user_can($post_type_object->cap->publish_posts);
+	foreach( array_keys($moderation_stati) as $_status ) { 
+		$set_cap = "set_{$_status}_posts";
+		if ( ( $_status != $post_status ) && ( ! empty( $post_type_obj->cap->$set_cap ) && ! current_user_can( $post_type_obj->cap->$set_cap ) ) )
+			unset( $moderation_stati[$_status] );
+	}
 ?>
 <div class="submitbox" id="submitpost">
 
@@ -27,17 +39,25 @@
 
 <div id="minor-publishing-actions">
 <div id="save-action">
-<?php if ( 'publish' != $post->post_status && 'future' != $post->post_status && 'pending' != $post->post_status ) { ?>
-<input <?php if ( 'private' == $post->post_status ) { ?>style="display:none"<?php } ?> type="submit" name="save" id="save-post" value="<?php esc_attr_e('Save Draft'); ?>" tabindex="4" class="button button-highlighted" />
-<?php } elseif ( 'pending' == $post->post_status && $can_publish ) { ?>
-<input type="submit" name="save" id="save-post" value="<?php esc_attr_e('Save as Pending'); ?>" tabindex="4" class="button button-highlighted" />
+<?php 
+//if ( 'publish' != $post_status && 'future' != $post_status && 'pending' != $post_status )  { 
+if ( ! $post_status_obj->public && ! $post_status_obj->private && ! $post_status_obj->moderation && ( 'future' != $post_status ) ) {  
+// TODO: confirm we don't need a hidden save button when current status is private
+	$draft_status_obj = get_post_status_object( 'draft' );
+?>
+<input type="submit" name="save" id="save-post" value="<?php echo $draft_status_obj->labels->save_as ?>" tabindex="4" class="button button-highlighted" />
+<?php
+} elseif ( $post_status_obj->moderation && $can_publish ) { 			
+?>
+<input type="submit" name="save" id="save-post" value="<?php echo $post_status_obj->labels->save_as ?>" tabindex="4" class="button button-highlighted" />
+
 <?php } ?>
 <img src="<?php echo esc_url( admin_url( 'images/wpspin_light.gif' ) ); ?>" class="ajax-loading" id="draft-ajax-loading" alt="" />
 </div>
 
 <div id="preview-action">
 <?php
-if ( 'publish' == $post->post_status ) {
+if ( $post_status_obj->public ) {
 	$preview_link = esc_url( get_permalink( $post->ID ) );
 	$preview_button = __( 'Preview Changes' );
 } else {
@@ -59,46 +79,33 @@
 
 <div class="misc-pub-section"><label for="post_status"><?php _e('Status:') ?></label>
 <span id="post-status-display">
-<?php
-switch ( $post->post_status ) {
-	case 'private':
-		_e('Privately Published');
-		break;
-	case 'publish':
-		_e('Published');
-		break;
-	case 'future':
-		_e('Scheduled');
-		break;
-	case 'pending':
-		_e('Pending Review');
-		break;
-	case 'draft':
-	case 'auto-draft':
-		_e('Draft');
-		break;
-}
-?>
+<?php echo $post_status_obj->labels->caption; ?>
 </span>
-<?php if ( 'publish' == $post->post_status || 'private' == $post->post_status || $can_publish ) { ?>
-<a href="#post_status" <?php if ( 'private' == $post->post_status ) { ?>style="display:none;" <?php } ?>class="edit-post-status hide-if-no-js" tabindex='4'><?php _e('Edit') ?></a>
+<?php 
+$select_moderation = ( count($moderation_stati) > 1 || ( $post_status != key($moderation_stati) ) );  // multiple moderation stati are selectable or a single non-current moderation stati is selectable
 
+if ( $post_status_obj->public || $post_status_obj->private || $can_publish || $select_moderation ) { ?>
+<a href="#post_status" <?php if ( $post_status_obj->private || ( $post_status_obj->public && 'publish' != $post_status ) ) { ?>style="display:none;" <?php } ?>class="edit-post-status hide-if-no-js" tabindex='4'><?php _e('Edit') ?></a>
+
 <div id="post-status-select" class="hide-if-js">
-<input type="hidden" name="hidden_post_status" id="hidden_post_status" value="<?php echo esc_attr( ('auto-draft' == $post->post_status ) ? 'draft' : $post->post_status); ?>" />
+<input type="hidden" name="hidden_post_status" id="hidden_post_status" value="<?php echo esc_attr( ('auto-draft' == $post_status ) ? 'draft' : $post_status); ?>" />
 <select name='post_status' id='post_status' tabindex='4'>
-<?php if ( 'publish' == $post->post_status ) : ?>
-<option<?php selected( $post->post_status, 'publish' ); ?> value='publish'><?php _e('Published') ?></option>
-<?php elseif ( 'private' == $post->post_status ) : ?>
-<option<?php selected( $post->post_status, 'private' ); ?> value='publish'><?php _e('Privately Published') ?></option>
-<?php elseif ( 'future' == $post->post_status ) : ?>
-<option<?php selected( $post->post_status, 'future' ); ?> value='future'><?php _e('Scheduled') ?></option>
+
+<?php if ( $post_status_obj->public || $post_status_obj->private || ( 'future' == $post_status ) ) : ?>
+<option<?php selected( $post_status, $post_status ); ?> value='publish'><?php echo $post_status_obj->labels->caption ?></option>
 <?php endif; ?>
-<option<?php selected( $post->post_status, 'pending' ); ?> value='pending'><?php _e('Pending Review') ?></option>
-<?php if ( 'auto-draft' == $post->post_status ) : ?>
-<option<?php selected( $post->post_status, 'auto-draft' ); ?> value='draft'><?php _e('Draft') ?></option>
-<?php else : ?>
-<option<?php selected( $post->post_status, 'draft' ); ?> value='draft'><?php _e('Draft') ?></option>
-<?php endif; ?>
+
+<?php 
+foreach( $moderation_stati as $_status => $_status_obj ) : ?>
+<option<?php selected( $post_status, $_status ); ?> value='<?php echo $_status ?>'><?php echo $_status_obj->labels->caption ?></option>
+<?php endforeach ?>
+
+<?php 
+$draft_status_obj = get_post_status_object( 'draft' );
+$compare_status = ( 'auto-draft' == $post_status ) ? 'auto-draft' : 'draft';
+?>
+<option<?php selected( $post_status, $compare_status ); ?> value='draft'><?php echo $draft_status_obj->label ?></option>
+
 </select>
  <a href="#post_status" class="save-post-status hide-if-no-js button"><?php _e('OK'); ?></a>
  <a href="#post_status" class="cancel-post-status hide-if-no-js"><?php _e('Cancel'); ?></a>
@@ -110,10 +117,37 @@
 <div class="misc-pub-section" id="visibility">
 <?php _e('Visibility:'); ?> <span id="post-visibility-display"><?php
 
-if ( 'private' == $post->post_status ) {
+if ( 'future' == $post_status ) {	// indicate eventual visibility of scheduled post
+	if ( ! $vis_status = get_post_meta( $post->ID, '_scheduled_status', true ) )
+		$vis_status = 'publish';	
+
+	$vis_status_obj = get_post_status_object( $vis_status );
+} else {
+	$vis_status = $post_status;
+	$vis_status_obj = $post_status_obj;
+}
+	
+if ( 'publish' == $vis_status ) {
 	$post->post_password = '';
-	$visibility = 'private';
-	$visibility_trans = __('Private');
+	$visibility = 'public';
+
+	if ( post_type_supports( $post->post_type, 'sticky' ) && is_sticky( $post->ID ) ) {
+		$visibility_trans = __('Public, Sticky');
+	} else {
+	    $visibility_trans = __('Public');
+	}
+} elseif ( $vis_status_obj->public  ) {
+	$post->post_password = '';
+	$visibility = $vis_status;
+
+	if ( post_type_supports( $post->post_type, 'sticky' ) && is_sticky( $post->ID ) ) {
+		$visibility_trans = sprintf( __('%s, Sticky'), $vis_status_obj->label );
+    } else {
+	    $visibility_trans = $vis_status_obj->labels->visibility;
+	}
+} elseif ( $vis_status_obj->private ) {
+	$post->post_password = '';
+	$visibility_trans = $vis_status_obj->labels->visibility;
 } elseif ( !empty( $post->post_password ) ) {
 	$visibility = 'password';
 	$visibility_trans = __('Password protected');
@@ -135,14 +169,38 @@
 <input type="checkbox" style="display:none" name="hidden_post_sticky" id="hidden-post-sticky" value="sticky" <?php checked(is_sticky($post->ID)); ?> />
 <?php endif; ?>
 <input type="hidden" name="hidden_post_visibility" id="hidden-post-visibility" value="<?php echo esc_attr( $visibility ); ?>" />
+
 <input type="radio" name="visibility" id="visibility-radio-public" value="public" <?php checked( $visibility, 'public' ); ?> /> <label for="visibility-radio-public" class="selectit"><?php _e('Public'); ?></label><br />
+
+<?php
+foreach( get_post_stati( array( 'public' => true, 'object_type' => $post_type ), 'object' ) as $_status => $_status_obj ) :
+	if ( 'publish' == $_status )
+		continue;
+
+	$post_cap = "set_{$_status}_posts";
+	if ( empty( $post_type_obj->cap->$post_cap ) || current_user_can( $post_type_obj->cap->$post_cap ) ) {
+?>
+<input type="radio" name="visibility" id="visibility-radio-<?php echo $_status ?>" value="<?php echo $_status ?>" <?php checked( $visibility, $_status ); ?> /> <label for="visibility-radio-<?php echo $_status ?>" class="selectit"><?php echo $_status_obj->labels->visibility ?></label><br />	
+<?php 
+	} // end if this user can set status
+endforeach ?>
+
 <?php if ( $post_type == 'post' && current_user_can( 'edit_others_posts' ) ) : ?>
 <span id="sticky-span"><input id="sticky" name="sticky" type="checkbox" value="sticky" <?php checked( is_sticky( $post->ID ) ); ?> tabindex="4" /> <label for="sticky" class="selectit"><?php _e( 'Stick this post to the front page' ); ?></label><br /></span>
 <?php endif; ?>
+
 <input type="radio" name="visibility" id="visibility-radio-password" value="password" <?php checked( $visibility, 'password' ); ?> /> <label for="visibility-radio-password" class="selectit"><?php _e('Password protected'); ?></label><br />
 <span id="password-span"><label for="post_password"><?php _e('Password:'); ?></label> <input type="text" name="post_password" id="post_password" value="<?php echo esc_attr($post->post_password); ?>" /><br /></span>
-<input type="radio" name="visibility" id="visibility-radio-private" value="private" <?php checked( $visibility, 'private' ); ?> /> <label for="visibility-radio-private" class="selectit"><?php _e('Private'); ?></label><br />
 
+<?php
+foreach( get_post_stati( array( 'private' => true, 'object_type' => $post_type ), 'object' ) as $_status => $_status_obj ) :
+	$post_cap = "set_{$_status}_posts";
+	if ( empty( $post_type_obj->cap->$post_cap ) || current_user_can( $post_type_obj->cap->$post_cap ) ) {
+?>
+<input type="radio" name="visibility" id="visibility-radio-<?php echo $_status ?>" value="<?php echo $_status ?>" <?php checked( $visibility, $_status ); ?> /> <label for="visibility-radio-<?php echo $_status ?>" class="selectit"><?php echo $_status_obj->label ?></label><br />	
+<?php 
+	} // end if this user can set status
+endforeach ?>
 <p>
  <a href="#visibility" class="save-post-visibility hide-if-no-js button"><?php _e('OK'); ?></a>
  <a href="#visibility" class="cancel-post-visibility hide-if-no-js"><?php _e('Cancel'); ?></a>
@@ -155,10 +213,13 @@
 <?php
 // translators: Publish box date format, see http://php.net/date
 $datef = __( 'M j, Y @ G:i' );
+
+$published_stati = get_post_stati( array( 'public' => true, 'private' => true ), 'names', 'or' );
+
 if ( 0 != $post->ID ) {
-	if ( 'future' == $post->post_status ) { // scheduled for publishing at a future date
+	if ( 'future' == $post_status ) { // scheduled for publishing at a future date
 		$stamp = __('Scheduled for: <b>%1$s</b>');
-	} else if ( 'publish' == $post->post_status || 'private' == $post->post_status ) { // already published
+	} else if ( in_array( $post_status, $published_stati ) ) { // already published
 		$stamp = __('Published on: <b>%1$s</b>');
 	} else if ( '0000-00-00 00:00:00' == $post->post_date_gmt ) { // draft, 1 or more saves, no date specified
 		$stamp = __('Publish <b>immediately</b>');
@@ -204,18 +265,32 @@
 <div id="publishing-action">
 <img src="<?php echo esc_url( admin_url( 'images/wpspin_light.gif' ) ); ?>" class="ajax-loading" id="ajax-loading" alt="" />
 <?php
-if ( !in_array( $post->post_status, array('publish', 'future', 'private') ) || 0 == $post->ID ) {
+if ( ( ! $post_status_obj->public && ! $post_status_obj->private && ( 'future' != $post_status ) ) ) {
 	if ( $can_publish ) :
-		if ( !empty($post->post_date_gmt) && time() < strtotime( $post->post_date_gmt . ' +0000' ) ) : ?>
-		<input name="original_publish" type="hidden" id="original_publish" value="<?php esc_attr_e('Schedule') ?>" />
-		<?php submit_button( __( 'Schedule' ), 'primary', 'publish', false, array( 'tabindex' => '5', 'accesskey' => 'p' ) ); ?>
-<?php	else : ?>
-		<input name="original_publish" type="hidden" id="original_publish" value="<?php esc_attr_e('Publish') ?>" />
-		<?php submit_button( __( 'Publish' ), 'primary', 'publish', false, array( 'tabindex' => '5', 'accesskey' => 'p' ) ); ?>
+
+		if ( !empty($post->post_date_gmt) && time() < strtotime( $post->post_date_gmt . ' +0000' ) ) : 
+		$future_status_obj = get_post_status_object( 'future' );
+		?>
+		<input name="original_publish" type="hidden" id="original_publish" value="<?php echo $future_status_obj->labels->publish ?>" />
+		<?php submit_button( $future_status_obj->labels->publish, 'primary', 'publish', false, array( 'tabindex' => '5', 'accesskey' => 'p' ) ); ?>
+<?php	else : 
+		$publish_status_obj = get_post_status_object( 'publish' );
+		?>
+		<input name="original_publish" type="hidden" id="original_publish" value="<?php echo $publish_status_obj->labels->publish ?>" />
+		<?php submit_button( $publish_status_obj->labels->publish, 'primary', 'publish', false, array( 'tabindex' => '5', 'accesskey' => 'p' ) ); ?>
 <?php	endif;
 	else : ?>
-		<input name="original_publish" type="hidden" id="original_publish" value="<?php esc_attr_e('Submit for Review') ?>" />
-		<?php submit_button( __( 'Submit for Review' ), 'primary', 'publish', false, array( 'tabindex' => '5', 'accesskey' => 'p' ) ); ?>
+		<?php
+		$moderation_button_status = apply_filters( 'post_moderation_status', 'pending', $post->ID );
+
+		$status_obj = get_post_status_object( $moderation_button_status );
+		$cap_name = "set_{$moderation_button_status}_posts";
+
+		if ( ! $status_obj || ( ! empty($post_type_obj->cap->$cap_name) && ! current_user_can($post_type_obj->cap->$cap_name) ) )
+			$status_obj = get_post_status_object( 'pending' );
+		?>
+		<input name="original_publish" type="hidden" id="original_publish" value="<?php echo $status_obj->labels->publish ?>" />
+		<?php submit_button( $status_obj->labels->publish, 'primary', 'publish', false, array( 'tabindex' => '5', 'accesskey' => 'p' ) ); ?>
 <?php
 	endif;
 } else { ?>
Index: wp-admin/includes/nav-menu.php
===================================================================
--- wp-admin/includes/nav-menu.php	(revision 20434)
+++ wp-admin/includes/nav-menu.php	(working copy)
@@ -1039,17 +1039,19 @@
  */
 function _wp_nav_menu_meta_box_object( $object = null ) {
 	if ( isset( $object->name ) ) {
+		$public_stati = apply_filters( 'nav_menu_metabox_stati', get_post_stati( array( 'public' => true, 'object_type' => $object->name ) ), $object );
+		$public_csv = implode( ',', $public_stati );
 
 		if ( 'page' == $object->name ) {
 			$object->_default_query = array(
 				'orderby' => 'menu_order title',
-				'post_status' => 'publish',
+				'post_status' => $public_csv,
 			);
 
-		// posts should show only published items
+		// posts should show only public items
 		} elseif ( 'post' == $object->name ) {
 			$object->_default_query = array(
-				'post_status' => 'publish',
+				'post_status' => $public_csv,
 			);
 
 		// cats should be in reverse chronological order
@@ -1059,10 +1061,10 @@
 				'order' => 'DESC',
 			);
 
-		// custom post types should show only published items
+		// custom post types should show only public items
 		} else {
 			$object->_default_query = array(
-				'post_status' => 'publish',
+				'post_status' => $public_csv,
 			);
 		}
 	}
Index: wp-admin/js/post.dev.js
===================================================================
--- wp-admin/js/post.dev.js	(revision 20434)
+++ wp-admin/js/post.dev.js	(working copy)
@@ -380,8 +380,8 @@
 		}
 
 		function updateText() {
-			var attemptedDate, originalDate, currentDate, publishOn, postStatus = $('#post_status'),
-				optPublish = $('option[value="publish"]', postStatus), aa = $('#aa').val(),
+			var attemptedDate, originalDate, currentDate, publishOn,
+				postStatus = $('#post_status'),	optPublish = $('option[value=publish]', postStatus), aa = $('#aa').val(),
 				mm = $('#mm').val(), jj = $('#jj').val(), hh = $('#hh').val(), mn = $('#mn').val();
 
 			attemptedDate = new Date( aa, mm - 1, jj, hh, mn );
@@ -405,6 +405,7 @@
 				publishOn = postL10n.publishOnPast;
 				$('#publish').val( postL10n.update );
 			}
+
 			if ( originalDate.toUTCString() == attemptedDate.toUTCString() ) { //hack
 				$('#timestamp').html(stamp);
 			} else {
@@ -419,13 +420,16 @@
 			}
 
 			if ( $('input:radio:checked', '#post-visibility-select').val() == 'private' ) {
+
 				$('#publish').val( postL10n.update );
 				if ( optPublish.length == 0 ) {
 					postStatus.append('<option value="publish">' + postL10n.privatelyPublished + '</option>');
 				} else {
 					optPublish.html( postL10n.privatelyPublished );
 				}
+
 				$('option[value="publish"]', postStatus).prop('selected', true);
+
 				$('.edit-post-status', '#misc-publishing-actions').hide();
 			} else {
 				if ( $('#original_post_status').val() == 'future' || $('#original_post_status').val() == 'draft' ) {
@@ -439,17 +443,7 @@
 				if ( postStatus.is(':hidden') )
 					$('.edit-post-status', '#misc-publishing-actions').show();
 			}
-			$('#post-status-display').html($('option:selected', postStatus).text());
-			if ( $('option:selected', postStatus).val() == 'private' || $('option:selected', postStatus).val() == 'publish' ) {
-				$('#save-post').hide();
-			} else {
-				$('#save-post').show();
-				if ( $('option:selected', postStatus).val() == 'pending' ) {
-					$('#save-post').show().val( postL10n.savePending );
-				} else {
-					$('#save-post').show().val( postL10n.saveDraft );
-				}
-			}
+
 			return true;
 		}
 
@@ -461,7 +455,7 @@
 			}
 			return false;
 		});
-
+		
 		$('.cancel-post-visibility', '#post-visibility-select').click(function () {
 			$('#post-visibility-select').slideUp('fast');
 			$('#visibility-radio-' + $('#hidden-post-visibility').val()).prop('checked', true);
@@ -469,17 +463,16 @@
 			$('#sticky').prop('checked', $('#hidden-post-sticky').prop('checked'));
 			$('#post-visibility-display').html(visibility);
 			$('.edit-visibility', '#visibility').show();
-			updateText();
 			return false;
 		});
-
+		
 		$('.save-post-visibility', '#post-visibility-select').click(function () { // crazyhorse - multiple ok cancels
 			var pvSelect = $('#post-visibility-select');
 
 			pvSelect.slideUp('fast');
 			$('.edit-visibility', '#visibility').show();
-			updateText();
 
+
 			if ( $('input:radio:checked', pvSelect).val() != 'public' ) {
 				$('#sticky').prop('checked', false);
 			} // WEAPON LOCKED
@@ -489,11 +482,11 @@
 			} else {
 				sticky = '';
 			}
-
+	
 			$('#post-visibility-display').html(	postL10n[$('input:radio:checked', pvSelect).val() + sticky]	);
 			return false;
 		});
-
+		
 		$('input:radio', '#post-visibility-select').change(function() {
 			updateVisibility();
 		});
Index: wp-admin/js/inline-edit-post.dev.js
===================================================================
--- wp-admin/js/inline-edit-post.dev.js	(revision 20434)
+++ wp-admin/js/inline-edit-post.dev.js	(working copy)
@@ -78,6 +78,12 @@
 			t.revert();
 			$('select[name^="action"]').val('-1');
 		});
+		
+		$('.keep-private, .keep-private input').click(function() {
+			if ( $(this).attr('checked') ) {
+				$('.keep-private input').filter("[name!='" + $(this).attr('name') + "']").removeAttr('checked');
+			}
+		});
 	},
 
 	toggle : function(el){
@@ -129,7 +135,8 @@
 		if ( typeof(id) == 'object' )
 			id = t.getId(id);
 
-		fields = ['post_title', 'post_name', 'post_author', '_status', 'jj', 'mm', 'aa', 'hh', 'mn', 'ss', 'post_password', 'post_format', 'menu_order'];
+		fields = ['post_title', 'post_name', 'post_author', '_status', 'scheduled_status', 'jj', 'mm', 'aa', 'hh', 'mn', 'ss', 'post_password', 'post_format', 'menu_order'];
+
 		if ( t.type == 'page' )
 			fields.push('post_parent', 'page_template');
 
@@ -198,12 +205,16 @@
 
 		// handle the post status
 		status = $('._status', rowData).text();
-		if ( 'future' != status )
+
+		if ( 'future' == status ) {
+			status = $('.scheduled_status', rowData).text();
+		} else {
 			$('select[name="_status"] option[value="future"]', editRow).remove();
+		}
 
-		if ( 'private' == status ) {
-			$('input[name="keep_private"]', editRow).prop("checked", true);
-			$('input.inline-edit-password-input').val('').prop('disabled', true);
+		if ( $('[name=keep_' + status + ']').length > 0) {
+			$('input[name="keep_' + status + '"]', editRow).prop("checked", "checked");
+			$('input.inline-edit-password-input').val('').prop('disabled', 'disabled');
 		}
 
 		// remove the current page and children from the parent dropdown
Index: wp-admin/post.php
===================================================================
--- wp-admin/post.php	(revision 20434)
+++ wp-admin/post.php	(working copy)
@@ -51,7 +51,11 @@
 					$message = 9;
 					break;
 				default:
-					$message = 6;
+					$status_obj = get_post_status_object( $status );
+					if ( ! empty($status_obj->moderation) )
+						$message = 11;
+					else
+						$message = 6;
 			}
 		} else {
 				$message = 'draft' == $status ? 10 : 1;
Index: wp-admin/edit-form-advanced.php
===================================================================
--- wp-admin/edit-form-advanced.php	(revision 20434)
+++ wp-admin/edit-form-advanced.php	(working copy)
@@ -45,6 +45,7 @@
 		// translators: Publish box date format, see http://php.net/date
 		date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_ID) ) ),
 	10 => sprintf( __('Post draft updated. <a target="_blank" href="%s">Preview post</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
+	11 => sprintf( __('Post moderated. <a target="_blank" href="%s">Preview post</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
 );
 $messages['page'] = array(
 	 0 => '', // Unused. Messages start at index 1.
@@ -58,6 +59,7 @@
 	 8 => sprintf( __('Page submitted. <a target="_blank" href="%s">Preview page</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
 	 9 => sprintf( __('Page scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview page</a>'), date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_ID) ) ),
 	10 => sprintf( __('Page draft updated. <a target="_blank" href="%s">Preview page</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
+	11 => sprintf( __('Page moderated. <a target="_blank" href="%s">Preview page</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
 );
 
 $messages = apply_filters( 'post_updated_messages', $messages );
@@ -140,10 +142,13 @@
 if ( post_type_supports($post_type, 'comments') )
 	add_meta_box('commentstatusdiv', __('Discussion'), 'post_comment_status_meta_box', null, 'normal', 'core');
 
-if ( ('publish' == $post->post_status || 'private' == $post->post_status) && post_type_supports($post_type, 'comments') )
+if ( ! $post_status_object = get_post_status_object( $post->post_status ) )
+	$post_status_object = get_post_status_object( 'draft' );
+
+if ( ( $post_status_object->public || $post_status_object->private ) && post_type_supports($post_type, 'comments') )
 	add_meta_box('commentsdiv', __('Comments'), 'post_comment_meta_box', null, 'normal', 'core');
 
-if ( !( 'pending' == $post->post_status && !current_user_can( $post_type_object->cap->publish_posts ) ) )
+if ( ! ( $post_status_object->moderation && ! current_user_can( $post_type_object->cap->publish_posts ) ) )
 	add_meta_box('slugdiv', __('Slug'), 'post_slug_meta_box', null, 'normal', 'core');
 
 if ( post_type_supports($post_type, 'author') ) {
@@ -292,7 +297,7 @@
 if ( !empty($shortlink) )
     $sample_permalink_html .= '<input id="shortlink" type="hidden" value="' . esc_attr($shortlink) . '" /><a href="#" class="button" onclick="prompt(&#39;URL:&#39;, jQuery(\'#shortlink\').val()); return false;">' . __('Get Shortlink') . '</a>';
 
-if ( $post_type_object->public && ! ( 'pending' == $post->post_status && !current_user_can( $post_type_object->cap->publish_posts ) ) ) { ?>
+if ( $post_type_object->public && ! ( $post_status_object->moderation && ! current_user_can( $post_type_object->cap->publish_posts ) ) ) { ?>
 	<div id="edit-slug-box">
 	<?php
 		if ( ! empty($post->ID) && ! empty($sample_permalink_html) && 'auto-draft' != $post->post_status )
@@ -385,3 +390,119 @@
 try{document.post.title.focus();}catch(e){}
 </script>
 <?php endif; ?>
+
+
+<?php
+add_action( 'admin_print_footer_scripts', create_function('', "_edit_form_advanced_scripts('$post_type');") );
+
+function _edit_form_advanced_scripts( $post_type ) {
+?>
+	
+<script type="text/javascript">
+//<![CDATA[
+jQuery(document).ready( function($) {
+	function updateStatusCaptions() {
+		postStatus = $('#post_status');
+
+		$('#post-status-display').html($('option:selected', postStatus).text());
+
+		switch( $('option:selected', postStatus).val() ) {
+
+<?php foreach( get_post_stati( array( 'public' => true, 'private' => true ), 'object', 'or' ) as $_status => $_status_obj ): ?>
+			case '<?php echo $_status ?>':
+				$('#save-post').hide();
+				break;
+<?php endforeach; ?>
+
+<?php foreach( get_post_stati( array( 'moderation' => true, 'internal' => false, 'object_type' => $post_type ), 'object' ) as $_status => $_status_obj ): ?>
+			case '<?php echo $_status ?>':
+				$('#save-post').show().val( '<?php echo $_status_obj->labels->save_as ?>' );
+				break;
+<?php endforeach; ?>
+
+			default :
+				<?php $draft_status_obj = get_post_status_object( 'draft' ); ?>			
+		 		$('#save-post').show().val( '<?php echo $draft_status_obj->labels->save_as ?>' );
+	 	}
+	}
+
+	$('input:radio', '#post-visibility-select').change(function() {
+		switch ( $('input:radio:checked', '#post-visibility-select').val() ) {
+			case 'public':
+				$('#sticky-span').show();
+				break;
+
+<?php foreach( get_post_stati( array( 'public' => true, 'object_type' => $post_type ) ) as $_status ) : ?>
+			case '<?php echo $_status ?>':
+				$('#sticky-span').show();
+				break;
+<?php endforeach; ?>
+
+			default :
+				$('#sticky').attr('checked', false);
+				$('#sticky-span').hide();
+		}
+	});
+	
+	function updateVisibilityCaptions() {
+		var postStatus = $('#post_status'), optPublish = $('option[value=publish]', postStatus);
+
+		switch( $('input:radio:checked', '#post-visibility-select').val() ) {
+
+<?php foreach( get_post_stati( array( 'internal' => false, 'object_type' => $post_type ), 'object' ) as $_status => $_status_obj ) : 
+		if ( ( 'publish' == $_status ) || ( ! $_status_obj->private && ! $_status_obj->public ) )
+			continue;
+?>
+			case '<?php echo $_status ?>':
+				$('#publish').val( postL10n.update );
+
+				if ( optPublish.length == 0 ) {
+					postStatus.append('<option value="publish">' + '<?php echo $_status_obj->labels->caption ?>' + '</option>');
+				} else {
+					optPublish.html( '<?php echo $_status_obj->labels->caption ?>' );
+				}
+
+				$('option[value=publish]', postStatus).attr('selected', true);
+				$('.edit-post-status', '#misc-publishing-actions').hide();
+
+				break;
+<?php endforeach; ?>
+
+			default:
+				if ( $('#original_post_status').val() == 'future' || $('#original_post_status').val() == 'draft' ) {
+					if ( optPublish.length ) {
+						optPublish.remove();
+						postStatus.val($('#hidden_post_status').val());
+					}
+				} else {
+					optPublish.html( postL10n.published );
+				}
+				if ( postStatus.is(':hidden') )
+					$('.edit-post-status', '#misc-publishing-actions').show();
+		}
+
+		return true;
+	}
+	
+	$('.save-post-status', '#post-status-select').click(function() {
+		updateStatusCaptions();
+		return false;
+	});
+	
+	$('.cancel-post-visibility', '#post-visibility-select').click(function () {
+		updateVisibilityCaptions();
+		return false;
+	});
+
+	$('.save-post-visibility', '#post-visibility-select').click(function () { // crazyhorse - multiple ok cancels
+		updateVisibilityCaptions();
+		updateStatusCaptions();
+		return false;
+	});
+});
+//]]>
+</script>
+
+<?php
+} // end function edit_form_advanced_scripts
+?>
\ No newline at end of file
