WordPress.org

Make WordPress Core

Ticket #17093: apply_query_filters.diff

File apply_query_filters.diff, 13.1 KB (added by kevinB, 7 years ago)

new plugin API for query filtering :add_query_filter() and apply_query_filters()

  • wp-includes/plugin.php

     
    7272}
    7373
    7474/**
     75 * Hooks a function or method to a specific filter action, specifying a required context for application.
     76 *
     77 * @package WordPress
     78 * @subpackage Plugin
     79 * @global array $wp_filter Stores all of the filters added in the form of
     80 *      wp_filter['tag']['array of priorities']['array of functions serialized']['array of ['array (functions, accepted_args)']']
     81 * @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.
     82 *
     83 * @param string $tag The name of the filter to hook the $function_to_add to.
     84 * @param callback $function_to_add The name of the function to be called when the filter is applied.
     85 * @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.
     86 * @param int $accepted_args optional. The number of arguments the function accept (default 1).
     87 * @param string $context optional. Context to require for filter application (default '').  Nullstring means filter is applied for all query contexts.
     88 * @return boolean true
     89 */
     90function add_query_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1, $context = '') {
     91        global $wp_filter, $merged_filters;
     92
     93        $idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority);
     94        $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args, 'context' => $context);
     95        unset( $merged_filters[ $tag ] );
     96        return true;
     97}
     98
     99/**
    75100 * Check if any filter has been registered for a hook.
    76101 *
    77102 * @package WordPress
     
    173198        return $value;
    174199}
    175200
     201
    176202/**
     203 * Call the functions added to a query filter hook, applying return value validation and context check.
     204 *
     205 * @package WordPress
     206 * @subpackage Plugin
     207 * @global array $wp_filter Stores all of the filters
     208 * @global array $merged_filters Merges the filter hooks using this function.
     209 * @global array $wp_current_filter stores the list of current filters with the current one last
     210 *
     211 * @param string $tag The name of the filter hook.
     212 * @param mixed $value The value on which the filters hooked to <tt>$tag</tt> are applied on.
     213 * @param object $query_obj Query object which triggered filter application.
     214 * @return mixed The filtered value after all hooked functions are applied to it.
     215 */
     216function apply_query_filters($tag, $value, $query_obj) {
     217        global $wp_filter, $merged_filters, $wp_current_filter;
     218
     219        $wp_current_filter[] = $tag;
     220
     221        // Do 'all' actions first
     222        if ( isset($wp_filter['all']) ) {
     223                _wp_call_all_hook( func_get_args() );
     224        }
     225
     226        if ( !isset($wp_filter[$tag]) ) {
     227                array_pop($wp_current_filter);
     228                return $value;
     229        }
     230
     231        // Sort
     232        if ( !isset( $merged_filters[ $tag ] ) ) {
     233                ksort($wp_filter[$tag]);
     234                $merged_filters[ $tag ] = true;
     235        }
     236
     237        reset( $wp_filter[ $tag ] );
     238
     239        $context = $query_obj->query_vars['query_context'];
     240
     241        do {
     242                foreach( (array) current($wp_filter[$tag]) as $the_ ) {
     243                        // Each valid filter hooked to this tag is applied if it was not added for a specific context or if the current context matches
     244                        if ( !is_null($the_['function']) && ( empty($the_['context']) || ( $context == $the_['context'] ) ) ) {
     245                                if ( (int) $the_['accepted_args'] > 1 )
     246                                        $_value = call_user_func($the_['function'], $value, $query_obj);
     247                                else
     248                                        $_value = call_user_func($the_['function'], $value);
     249
     250                                if ( is_null($_value) ) {
     251                                        if ( WP_DEBUG ) {
     252                                                trigger_error( sprintf( __('Query filter returned null value for %s hook.'), $tag ), E_USER_WARNING );
     253                                        }
     254                                } else
     255                                        $value = $_value;
     256                        }
     257                }
     258
     259        } while ( next($wp_filter[$tag]) !== false );
     260
     261        array_pop( $wp_current_filter );
     262
     263        return $value;
     264}
     265
     266/**
    177267 * Execute functions hooked on a specific filter hook, specifying arguments in an array.
    178268 *
    179269 * @see apply_filters() This function is identical, but the arguments passed to the
  • wp-includes/query.php

     
    13691369                        , 's'
    13701370                        , 'sentence'
    13711371                        , 'fields'
     1372                        , 'query_context'
    13721373                );
    13731374
    13741375                foreach ( $keys as $key ) {
     
    21672168                }
    21682169
    21692170                // Allow plugins to contextually add/remove/modify the search section of the database query
    2170                 $search = apply_filters_ref_array('posts_search', array( $search, &$this ) );
     2171                $search = apply_query_filters('posts_search', $search, $this);
    21712172
    21722173                // Taxonomies
    21732174                if ( !$this->is_singular ) {
     
    24832484                // Apply filters on where and join prior to paging so that any
    24842485                // manipulations to them are reflected in the paging by day queries.
    24852486                if ( !$q['suppress_filters'] ) {
    2486                         $where = apply_filters_ref_array('posts_where', array( $where, &$this ) );
    2487                         $join = apply_filters_ref_array('posts_join', array( $join, &$this ) );
     2487                        $where = apply_query_filters('posts_where', $where, $this);
     2488                        $join = apply_query_filters('posts_join', $join, $this);
    24882489                }
    24892490
    24902491                // Paging
     
    25172518                        }
    25182519
    25192520                        if ( !$q['suppress_filters'] ) {
    2520                                 $cjoin = apply_filters_ref_array('comment_feed_join', array( $cjoin, &$this ) );
    2521                                 $cwhere = apply_filters_ref_array('comment_feed_where', array( $cwhere, &$this ) );
    2522                                 $cgroupby = apply_filters_ref_array('comment_feed_groupby', array( $cgroupby, &$this ) );
    2523                                 $corderby = apply_filters_ref_array('comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );
    2524                                 $climits = apply_filters_ref_array('comment_feed_limits', array( 'LIMIT ' . get_option('posts_per_rss'), &$this ) );
     2521                                $cjoin = apply_query_filters('comment_feed_join', $cjoin, $this);
     2522                                $cwhere = apply_query_filters('comment_feed_where', $cwhere, $this);
     2523                                $cgroupby = apply_query_filters('comment_feed_groupby', $cgroupby, $this);
     2524                                $corderby = apply_query_filters('comment_feed_orderby', 'comment_date_gmt DESC', $this);
     2525                                $climits = apply_query_filters('comment_feed_limits', 'LIMIT ' . get_option('posts_per_rss'), $this);
    25252526                        }
    25262527                        $cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';
    25272528                        $corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';
     
    25492550                // Apply post-paging filters on where and join.  Only plugins that
    25502551                // manipulate paging queries should use these hooks.
    25512552                if ( !$q['suppress_filters'] ) {
    2552                         $where          = apply_filters_ref_array( 'posts_where_paged', array( $where, &$this ) );
    2553                         $groupby        = apply_filters_ref_array( 'posts_groupby',             array( $groupby, &$this ) );
    2554                         $join           = apply_filters_ref_array( 'posts_join_paged',  array( $join, &$this ) );
    2555                         $orderby        = apply_filters_ref_array( 'posts_orderby',             array( $orderby, &$this ) );
    2556                         $distinct       = apply_filters_ref_array( 'posts_distinct',    array( $distinct, &$this ) );
    2557                         $limits         = apply_filters_ref_array( 'post_limits',               array( $limits, &$this ) );
    2558                         $fields         = apply_filters_ref_array( 'posts_fields',              array( $fields, &$this ) );
     2553                        $where          = apply_query_filters( 'posts_where_paged',      $where, $this );
     2554                        $groupby        = apply_query_filters( 'posts_groupby',          $groupby, $this );
     2555                        $join           = apply_query_filters( 'posts_join_paged',       $join, $this );
     2556                        $orderby        = apply_query_filters( 'posts_orderby',          $orderby, $this );
     2557                        $distinct       = apply_query_filters( 'posts_distinct',         $distinct, $this );
     2558                        $limits         = apply_query_filters( 'post_limits',            $limits, $this );
     2559                        $fields         = apply_query_filters( 'posts_fields',           $fields, $this );
    25592560
    25602561                        // Filter all clauses at once, for convenience
    2561                         $clauses = (array) apply_filters_ref_array( 'posts_clauses', array( compact( $pieces ), &$this ) );
     2562                        $clauses = (array) apply_query_filters( 'posts_clauses', compact( $pieces ), $this );
    25622563                        foreach ( $pieces as $piece )
    25632564                                $$piece = isset( $clauses[ $piece ] ) ? $clauses[ $piece ] : '';
    25642565                }
     
    25682569
    25692570                // Filter again for the benefit of caching plugins.  Regular plugins should use the hooks above.
    25702571                if ( !$q['suppress_filters'] ) {
    2571                         $where          = apply_filters_ref_array( 'posts_where_request',               array( $where, &$this ) );
    2572                         $groupby        = apply_filters_ref_array( 'posts_groupby_request',             array( $groupby, &$this ) );
    2573                         $join           = apply_filters_ref_array( 'posts_join_request',                array( $join, &$this ) );
    2574                         $orderby        = apply_filters_ref_array( 'posts_orderby_request',             array( $orderby, &$this ) );
    2575                         $distinct       = apply_filters_ref_array( 'posts_distinct_request',    array( $distinct, &$this ) );
    2576                         $fields         = apply_filters_ref_array( 'posts_fields_request',              array( $fields, &$this ) );
    2577                         $limits         = apply_filters_ref_array( 'post_limits_request',               array( $limits, &$this ) );
     2572                        $where          = apply_query_filters( 'posts_where_request',           $where, $this );
     2573                        $groupby        = apply_query_filters( 'posts_groupby_request',         $groupby, $this );
     2574                        $join           = apply_query_filters( 'posts_join_request',            $join, $this );
     2575                        $orderby        = apply_query_filters( 'posts_orderby_request',         $orderby, $this );
     2576                        $distinct       = apply_query_filters( 'posts_distinct_request',        $distinct, $this );
     2577                        $fields         = apply_query_filters( 'posts_fields_request',          $fields, $this );
     2578                        $limits         = apply_query_filters( 'post_limits_request',           $limits, $this );
    25782579
    25792580                        // Filter all clauses at once, for convenience
    2580                         $clauses = (array) apply_filters_ref_array( 'posts_clauses_request', array( compact( $pieces ), &$this ) );
     2581                        $clauses = (array) apply_query_filters( 'posts_clauses_request', compact( $pieces ), $this );
    25812582                        foreach ( $pieces as $piece )
    25822583                                $$piece = isset( $clauses[ $piece ] ) ? $clauses[ $piece ] : '';
    25832584                }
     
    25932594
    25942595                $this->request = " SELECT $found_rows $distinct $fields FROM $wpdb->posts $join WHERE 1=1 $where $groupby $orderby $limits";
    25952596                if ( !$q['suppress_filters'] )
    2596                         $this->request = apply_filters_ref_array('posts_request', array( $this->request, &$this ) );
     2597                        $this->request = apply_query_filters('posts_request', $this->request, $this);
    25972598
    25982599                if ( 'ids' == $q['fields'] ) {
    25992600                        $this->posts = $wpdb->get_col($this->request);
     
    26152616
    26162617                // Raw results filter.  Prior to status checks.
    26172618                if ( !$q['suppress_filters'] )
    2618                         $this->posts = apply_filters_ref_array('posts_results', array( $this->posts, &$this ) );
     2619                        $this->posts = apply_query_filters('posts_results', $this->posts, $this);
    26192620
    26202621                if ( !empty($this->posts) && $this->is_comment_feed && $this->is_singular ) {
    2621                         $cjoin = apply_filters_ref_array('comment_feed_join', array( '', &$this ) );
    2622                         $cwhere = apply_filters_ref_array('comment_feed_where', array( "WHERE comment_post_ID = '{$this->posts[0]->ID}' AND comment_approved = '1'", &$this ) );
    2623                         $cgroupby = apply_filters_ref_array('comment_feed_groupby', array( '', &$this ) );
     2622                        $cjoin = apply_query_filters('comment_feed_join', '', $this);
     2623                        $cwhere = apply_query_filters('comment_feed_where', "WHERE comment_post_ID = '{$this->posts[0]->ID}' AND comment_approved = '1'", $this);
     2624                        $cgroupby = apply_query_filters('comment_feed_groupby', '', $this);
    26242625                        $cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';
    2625                         $corderby = apply_filters_ref_array('comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );
     2626                        $corderby = apply_query_filters('comment_feed_orderby', 'comment_date_gmt DESC', $this);
    26262627                        $corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';
    2627                         $climits = apply_filters_ref_array('comment_feed_limits', array( 'LIMIT ' . get_option('posts_per_rss'), &$this ) );
     2628                        $climits = apply_query_filters('comment_feed_limits', 'LIMIT ' . get_option('posts_per_rss'), $this);
    26282629                        $comments_request = "SELECT $wpdb->comments.* FROM $wpdb->comments $cjoin $cwhere $cgroupby $corderby $climits";
    26292630                        $this->comments = $wpdb->get_results($comments_request);
    26302631                        $this->comment_count = count($this->comments);
    26312632                }
    26322633
    26332634                if ( !$q['no_found_rows'] && !empty($limits) ) {
    2634                         $found_posts_query = apply_filters_ref_array( 'found_posts_query', array( 'SELECT FOUND_ROWS()', &$this ) );
     2635                        $found_posts_query = apply_query_filters( 'found_posts_query', 'SELECT FOUND_ROWS()', $this);
    26352636                        $this->found_posts = $wpdb->get_var( $found_posts_query );
    2636                         $this->found_posts = apply_filters_ref_array( 'found_posts', array( $this->found_posts, &$this ) );
     2637                        $this->found_posts = apply_query_filters( 'found_posts', $this->found_posts, $this);
    26372638                        $this->max_num_pages = ceil($this->found_posts / $q['posts_per_page']);
    26382639                }
    26392640
     
    26662667                        }
    26672668
    26682669                        if ( $this->is_preview && current_user_can( $edit_cap, $this->posts[0]->ID ) )
    2669                                 $this->posts[0] = apply_filters_ref_array('the_preview', array( $this->posts[0], &$this ));
     2670                                $this->posts[0] = apply_query_filters('the_preview', $this->posts[0], $this);
    26702671                }
    26712672
    26722673                // Put sticky posts at the top of the posts array
     
    27202721                }
    27212722
    27222723                if ( !$q['suppress_filters'] )
    2723                         $this->posts = apply_filters_ref_array('the_posts', array( $this->posts, &$this ) );
     2724                        $this->posts = apply_query_filters('the_posts', $this->posts, $this);
    27242725
    27252726                $this->post_count = count($this->posts);
    27262727