Index: wp-includes/plugin.php
===================================================================
--- wp-includes/plugin.php	(revision 17624)
+++ wp-includes/plugin.php	(working copy)
@@ -72,6 +72,31 @@
 }
 
 /**
+ * Hooks a function or method to a specific filter action, specifying a required context for application.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @global array $wp_filter Stores all of the filters added in the form of
+ *	wp_filter['tag']['array of priorities']['array of functions serialized']['array of ['array (functions, accepted_args)']']
+ * @global array $merged_filters Tracks the tags that need to be merged for later. If the hook is added, it doesn't need to run through that process.
+ *
+ * @param string $tag The name of the filter to hook the $function_to_add to.
+ * @param callback $function_to_add The name of the function to be called when the filter is applied.
+ * @param int $priority optional. Used to specify the order in which the functions associated with a particular action are executed (default: 10). Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action.
+ * @param int $accepted_args optional. The number of arguments the function accept (default 1).
+ * @param string $context optional. Context to require for filter application (default '').  Nullstring means filter is applied for all query contexts. 
+ * @return boolean true
+ */
+function add_query_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1, $context = '') {
+	global $wp_filter, $merged_filters;
+
+	$idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority);
+	$wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args, 'context' => $context);
+	unset( $merged_filters[ $tag ] );
+	return true;
+}
+
+/**
  * Check if any filter has been registered for a hook.
  *
  * @package WordPress
@@ -173,7 +198,72 @@
 	return $value;
 }
 
+
 /**
+ * Call the functions added to a query filter hook, applying return value validation and context check.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @global array $wp_filter Stores all of the filters
+ * @global array $merged_filters Merges the filter hooks using this function.
+ * @global array $wp_current_filter stores the list of current filters with the current one last
+ *
+ * @param string $tag The name of the filter hook.
+ * @param mixed $value The value on which the filters hooked to <tt>$tag</tt> are applied on.
+ * @param object $query_obj Query object which triggered filter application.
+ * @return mixed The filtered value after all hooked functions are applied to it.
+ */
+function apply_query_filters($tag, $value, $query_obj) {
+	global $wp_filter, $merged_filters, $wp_current_filter;
+
+	$wp_current_filter[] = $tag;
+
+	// Do 'all' actions first
+	if ( isset($wp_filter['all']) ) {
+		_wp_call_all_hook( func_get_args() );
+	}
+
+	if ( !isset($wp_filter[$tag]) ) {
+		array_pop($wp_current_filter);
+		return $value;
+	}
+
+	// Sort
+	if ( !isset( $merged_filters[ $tag ] ) ) {
+		ksort($wp_filter[$tag]);
+		$merged_filters[ $tag ] = true;
+	}
+
+	reset( $wp_filter[ $tag ] );
+
+	$context = $query_obj->query_vars['query_context'];
+
+	do {
+		foreach( (array) current($wp_filter[$tag]) as $the_ ) {
+			// Each valid filter hooked to this tag is applied if it was not added for a specific context or if the current context matches
+			if ( !is_null($the_['function']) && ( empty($the_['context']) || ( $context == $the_['context'] ) ) ) {
+				if ( (int) $the_['accepted_args'] > 1 )
+					$_value = call_user_func($the_['function'], $value, $query_obj);
+				else
+					$_value = call_user_func($the_['function'], $value);
+
+				if ( is_null($_value) ) {
+					if ( WP_DEBUG ) {
+						trigger_error( sprintf( __('Query filter returned null value for %s hook.'), $tag ), E_USER_WARNING );
+					}
+				} else
+					$value = $_value;
+			}
+		}
+
+	} while ( next($wp_filter[$tag]) !== false );
+
+	array_pop( $wp_current_filter );
+
+	return $value;
+}
+
+/**
  * Execute functions hooked on a specific filter hook, specifying arguments in an array.
  *
  * @see apply_filters() This function is identical, but the arguments passed to the
Index: wp-includes/query.php
===================================================================
--- wp-includes/query.php	(revision 17624)
+++ wp-includes/query.php	(working copy)
@@ -1369,6 +1369,7 @@
 			, 's'
 			, 'sentence'
 			, 'fields'
+			, 'query_context'
 		);
 
 		foreach ( $keys as $key ) {
@@ -2167,7 +2168,7 @@
 		}
 
 		// Allow plugins to contextually add/remove/modify the search section of the database query
-		$search = apply_filters_ref_array('posts_search', array( $search, &$this ) );
+		$search = apply_query_filters('posts_search', $search, $this);
 
 		// Taxonomies
 		if ( !$this->is_singular ) {
@@ -2483,8 +2484,8 @@
 		// Apply filters on where and join prior to paging so that any
 		// manipulations to them are reflected in the paging by day queries.
 		if ( !$q['suppress_filters'] ) {
-			$where = apply_filters_ref_array('posts_where', array( $where, &$this ) );
-			$join = apply_filters_ref_array('posts_join', array( $join, &$this ) );
+			$where = apply_query_filters('posts_where', $where, $this);
+			$join = apply_query_filters('posts_join', $join, $this);
 		}
 
 		// Paging
@@ -2517,11 +2518,11 @@
 			}
 
 			if ( !$q['suppress_filters'] ) {
-				$cjoin = apply_filters_ref_array('comment_feed_join', array( $cjoin, &$this ) );
-				$cwhere = apply_filters_ref_array('comment_feed_where', array( $cwhere, &$this ) );
-				$cgroupby = apply_filters_ref_array('comment_feed_groupby', array( $cgroupby, &$this ) );
-				$corderby = apply_filters_ref_array('comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );
-				$climits = apply_filters_ref_array('comment_feed_limits', array( 'LIMIT ' . get_option('posts_per_rss'), &$this ) );
+				$cjoin = apply_query_filters('comment_feed_join', $cjoin, $this);
+				$cwhere = apply_query_filters('comment_feed_where', $cwhere, $this);
+				$cgroupby = apply_query_filters('comment_feed_groupby', $cgroupby, $this);
+				$corderby = apply_query_filters('comment_feed_orderby', 'comment_date_gmt DESC', $this);
+				$climits = apply_query_filters('comment_feed_limits', 'LIMIT ' . get_option('posts_per_rss'), $this);
 			}
 			$cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';
 			$corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';
@@ -2549,16 +2550,16 @@
 		// Apply post-paging filters on where and join.  Only plugins that
 		// manipulate paging queries should use these hooks.
 		if ( !$q['suppress_filters'] ) {
-			$where		= apply_filters_ref_array( 'posts_where_paged',	array( $where, &$this ) );
-			$groupby	= apply_filters_ref_array( 'posts_groupby',		array( $groupby, &$this ) );
-			$join		= apply_filters_ref_array( 'posts_join_paged',	array( $join, &$this ) );
-			$orderby	= apply_filters_ref_array( 'posts_orderby',		array( $orderby, &$this ) );
-			$distinct	= apply_filters_ref_array( 'posts_distinct',	array( $distinct, &$this ) );
-			$limits		= apply_filters_ref_array( 'post_limits',		array( $limits, &$this ) );
-			$fields		= apply_filters_ref_array( 'posts_fields',		array( $fields, &$this ) );
+			$where		= apply_query_filters( 'posts_where_paged',	 $where, $this );
+			$groupby	= apply_query_filters( 'posts_groupby',		 $groupby, $this );
+			$join		= apply_query_filters( 'posts_join_paged',	 $join, $this );
+			$orderby	= apply_query_filters( 'posts_orderby',		 $orderby, $this );
+			$distinct	= apply_query_filters( 'posts_distinct',	 $distinct, $this );
+			$limits		= apply_query_filters( 'post_limits',		 $limits, $this );
+			$fields		= apply_query_filters( 'posts_fields',		 $fields, $this );
 
 			// Filter all clauses at once, for convenience
-			$clauses = (array) apply_filters_ref_array( 'posts_clauses', array( compact( $pieces ), &$this ) );
+			$clauses = (array) apply_query_filters( 'posts_clauses', compact( $pieces ), $this );
 			foreach ( $pieces as $piece )
 				$$piece = isset( $clauses[ $piece ] ) ? $clauses[ $piece ] : '';
 		}
@@ -2568,16 +2569,16 @@
 
 		// Filter again for the benefit of caching plugins.  Regular plugins should use the hooks above.
 		if ( !$q['suppress_filters'] ) {
-			$where		= apply_filters_ref_array( 'posts_where_request',		array( $where, &$this ) );
-			$groupby	= apply_filters_ref_array( 'posts_groupby_request',		array( $groupby, &$this ) );
-			$join		= apply_filters_ref_array( 'posts_join_request',		array( $join, &$this ) );
-			$orderby	= apply_filters_ref_array( 'posts_orderby_request',		array( $orderby, &$this ) );
-			$distinct	= apply_filters_ref_array( 'posts_distinct_request',	array( $distinct, &$this ) );
-			$fields		= apply_filters_ref_array( 'posts_fields_request',		array( $fields, &$this ) );
-			$limits		= apply_filters_ref_array( 'post_limits_request',		array( $limits, &$this ) );
+			$where		= apply_query_filters( 'posts_where_request',		$where, $this );
+			$groupby	= apply_query_filters( 'posts_groupby_request',		$groupby, $this );
+			$join		= apply_query_filters( 'posts_join_request',		$join, $this );
+			$orderby	= apply_query_filters( 'posts_orderby_request',		$orderby, $this );
+			$distinct	= apply_query_filters( 'posts_distinct_request',	$distinct, $this );
+			$fields		= apply_query_filters( 'posts_fields_request',		$fields, $this );
+			$limits		= apply_query_filters( 'post_limits_request',		$limits, $this );
 
 			// Filter all clauses at once, for convenience
-			$clauses = (array) apply_filters_ref_array( 'posts_clauses_request', array( compact( $pieces ), &$this ) );
+			$clauses = (array) apply_query_filters( 'posts_clauses_request', compact( $pieces ), $this );
 			foreach ( $pieces as $piece )
 				$$piece = isset( $clauses[ $piece ] ) ? $clauses[ $piece ] : '';
 		}
@@ -2593,7 +2594,7 @@
 
 		$this->request = " SELECT $found_rows $distinct $fields FROM $wpdb->posts $join WHERE 1=1 $where $groupby $orderby $limits";
 		if ( !$q['suppress_filters'] )
-			$this->request = apply_filters_ref_array('posts_request', array( $this->request, &$this ) );
+			$this->request = apply_query_filters('posts_request', $this->request, $this);
 
 		if ( 'ids' == $q['fields'] ) {
 			$this->posts = $wpdb->get_col($this->request);
@@ -2615,25 +2616,25 @@
 
 		// Raw results filter.  Prior to status checks.
 		if ( !$q['suppress_filters'] )
-			$this->posts = apply_filters_ref_array('posts_results', array( $this->posts, &$this ) );
+			$this->posts = apply_query_filters('posts_results', $this->posts, $this);
 
 		if ( !empty($this->posts) && $this->is_comment_feed && $this->is_singular ) {
-			$cjoin = apply_filters_ref_array('comment_feed_join', array( '', &$this ) );
-			$cwhere = apply_filters_ref_array('comment_feed_where', array( "WHERE comment_post_ID = '{$this->posts[0]->ID}' AND comment_approved = '1'", &$this ) );
-			$cgroupby = apply_filters_ref_array('comment_feed_groupby', array( '', &$this ) );
+			$cjoin = apply_query_filters('comment_feed_join', '', $this);
+			$cwhere = apply_query_filters('comment_feed_where', "WHERE comment_post_ID = '{$this->posts[0]->ID}' AND comment_approved = '1'", $this);
+			$cgroupby = apply_query_filters('comment_feed_groupby', '', $this);
 			$cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';
-			$corderby = apply_filters_ref_array('comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );
+			$corderby = apply_query_filters('comment_feed_orderby', 'comment_date_gmt DESC', $this);
 			$corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';
-			$climits = apply_filters_ref_array('comment_feed_limits', array( 'LIMIT ' . get_option('posts_per_rss'), &$this ) );
+			$climits = apply_query_filters('comment_feed_limits', 'LIMIT ' . get_option('posts_per_rss'), $this);
 			$comments_request = "SELECT $wpdb->comments.* FROM $wpdb->comments $cjoin $cwhere $cgroupby $corderby $climits";
 			$this->comments = $wpdb->get_results($comments_request);
 			$this->comment_count = count($this->comments);
 		}
 
 		if ( !$q['no_found_rows'] && !empty($limits) ) {
-			$found_posts_query = apply_filters_ref_array( 'found_posts_query', array( 'SELECT FOUND_ROWS()', &$this ) );
+			$found_posts_query = apply_query_filters( 'found_posts_query', 'SELECT FOUND_ROWS()', $this);
 			$this->found_posts = $wpdb->get_var( $found_posts_query );
-			$this->found_posts = apply_filters_ref_array( 'found_posts', array( $this->found_posts, &$this ) );
+			$this->found_posts = apply_query_filters( 'found_posts', $this->found_posts, $this);
 			$this->max_num_pages = ceil($this->found_posts / $q['posts_per_page']);
 		}
 
@@ -2666,7 +2667,7 @@
 			}
 
 			if ( $this->is_preview && current_user_can( $edit_cap, $this->posts[0]->ID ) )
-				$this->posts[0] = apply_filters_ref_array('the_preview', array( $this->posts[0], &$this ));
+				$this->posts[0] = apply_query_filters('the_preview', $this->posts[0], $this);
 		}
 
 		// Put sticky posts at the top of the posts array
@@ -2720,7 +2721,7 @@
 		}
 
 		if ( !$q['suppress_filters'] )
-			$this->posts = apply_filters_ref_array('the_posts', array( $this->posts, &$this ) );
+			$this->posts = apply_query_filters('the_posts', $this->posts, $this);
 
 		$this->post_count = count($this->posts);
 
