Make WordPress Core


Ignore:
Timestamp:
10/28/2010 04:27:18 PM (14 years ago)
Author:
scribu
Message:

Move WP_Object_Query to it's own file. See #15032

File:
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/wp-includes/class.wp-object-query.php

    r16048 r16051  
    1010 * @package WordPress
    1111 */
    12 
    13 /**
    14  * WordPress environment setup class.
    15  *
    16  * @package WordPress
    17  * @since 2.0.0
    18  */
    19 class WP {
    20     /**
    21      * Public query variables.
    22      *
    23      * Long list of public query variables.
    24      *
    25      * @since 2.0.0
    26      * @access public
    27      * @var array
    28      */
    29     var $public_query_vars = array('m', 'p', 'posts', 'w', 'cat', 'withcomments', 'withoutcomments', 's', 'search', 'exact', 'sentence', 'debug', 'calendar', 'page', 'paged', 'more', 'tb', 'pb', 'author', 'order', 'orderby', 'year', 'monthnum', 'day', 'hour', 'minute', 'second', 'name', 'category_name', 'tag', 'feed', 'author_name', 'static', 'pagename', 'page_id', 'error', 'comments_popup', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'taxonomy', 'term', 'cpage', 'post_type');
    30 
    31     /**
    32      * Private query variables.
    33      *
    34      * Long list of private query variables.
    35      *
    36      * @since 2.0.0
    37      * @var array
    38      */
    39     var $private_query_vars = array('offset', 'posts_per_page', 'posts_per_archive_page', 'showposts', 'nopaging', 'post_type', 'post_status', 'category__in', 'category__not_in', 'category__and', 'tag__in', 'tag__not_in', 'tag__and', 'tag_slug__in', 'tag_slug__and', 'tag_id', 'post_mime_type', 'perm', 'comments_per_page', 'post__in', 'post__not_in');
    40 
    41     /**
    42      * Extra query variables set by the user.
    43      *
    44      * @since 2.1.0
    45      * @var array
    46      */
    47     var $extra_query_vars = array();
    48 
    49     /**
    50      * Query variables for setting up the WordPress Query Loop.
    51      *
    52      * @since 2.0.0
    53      * @var array
    54      */
    55     var $query_vars;
    56 
    57     /**
    58      * String parsed to set the query variables.
    59      *
    60      * @since 2.0.0
    61      * @var string
    62      */
    63     var $query_string;
    64 
    65     /**
    66      * Permalink or requested URI.
    67      *
    68      * @since 2.0.0
    69      * @var string
    70      */
    71     var $request;
    72 
    73     /**
    74      * Rewrite rule the request matched.
    75      *
    76      * @since 2.0.0
    77      * @var string
    78      */
    79     var $matched_rule;
    80 
    81     /**
    82      * Rewrite query the request matched.
    83      *
    84      * @since 2.0.0
    85      * @var string
    86      */
    87     var $matched_query;
    88 
    89     /**
    90      * Whether already did the permalink.
    91      *
    92      * @since 2.0.0
    93      * @var bool
    94      */
    95     var $did_permalink = false;
    96 
    97     /**
    98      * Add name to list of public query variables.
    99      *
    100      * @since 2.1.0
    101      *
    102      * @param string $qv Query variable name.
    103      */
    104     function add_query_var($qv) {
    105         if ( !in_array($qv, $this->public_query_vars) )
    106             $this->public_query_vars[] = $qv;
    107     }
    108 
    109     /**
    110      * Set the value of a query variable.
    111      *
    112      * @since 2.3.0
    113      *
    114      * @param string $key Query variable name.
    115      * @param mixed $value Query variable value.
    116      */
    117     function set_query_var($key, $value) {
    118         $this->query_vars[$key] = $value;
    119     }
    120 
    121     /**
    122      * Parse request to find correct WordPress query.
    123      *
    124      * Sets up the query variables based on the request. There are also many
    125      * filters and actions that can be used to further manipulate the result.
    126      *
    127      * @since 2.0.0
    128      *
    129      * @param array|string $extra_query_vars Set the extra query variables.
    130      */
    131     function parse_request($extra_query_vars = '') {
    132         global $wp_rewrite;
    133 
    134         $this->query_vars = array();
    135         $post_type_query_vars = array();
    136 
    137         if ( is_array($extra_query_vars) )
    138             $this->extra_query_vars = & $extra_query_vars;
    139         else if (! empty($extra_query_vars))
    140             parse_str($extra_query_vars, $this->extra_query_vars);
    141 
    142         // Process PATH_INFO, REQUEST_URI, and 404 for permalinks.
    143 
    144         // Fetch the rewrite rules.
    145         $rewrite = $wp_rewrite->wp_rewrite_rules();
    146 
    147         if ( ! empty($rewrite) ) {
    148             // If we match a rewrite rule, this will be cleared.
    149             $error = '404';
    150             $this->did_permalink = true;
    151 
    152             if ( isset($_SERVER['PATH_INFO']) )
    153                 $pathinfo = $_SERVER['PATH_INFO'];
    154             else
    155                 $pathinfo = '';
    156             $pathinfo_array = explode('?', $pathinfo);
    157             $pathinfo = str_replace("%", "%25", $pathinfo_array[0]);
    158             $req_uri = $_SERVER['REQUEST_URI'];
    159             $req_uri_array = explode('?', $req_uri);
    160             $req_uri = $req_uri_array[0];
    161             $self = $_SERVER['PHP_SELF'];
    162             $home_path = parse_url(home_url());
    163             if ( isset($home_path['path']) )
    164                 $home_path = $home_path['path'];
    165             else
    166                 $home_path = '';
    167             $home_path = trim($home_path, '/');
    168 
    169             // Trim path info from the end and the leading home path from the
    170             // front.  For path info requests, this leaves us with the requesting
    171             // filename, if any.  For 404 requests, this leaves us with the
    172             // requested permalink.
    173             $req_uri = str_replace($pathinfo, '', $req_uri);
    174             $req_uri = trim($req_uri, '/');
    175             $req_uri = preg_replace("|^$home_path|", '', $req_uri);
    176             $req_uri = trim($req_uri, '/');
    177             $pathinfo = trim($pathinfo, '/');
    178             $pathinfo = preg_replace("|^$home_path|", '', $pathinfo);
    179             $pathinfo = trim($pathinfo, '/');
    180             $self = trim($self, '/');
    181             $self = preg_replace("|^$home_path|", '', $self);
    182             $self = trim($self, '/');
    183 
    184             // The requested permalink is in $pathinfo for path info requests and
    185             //  $req_uri for other requests.
    186             if ( ! empty($pathinfo) && !preg_match('|^.*' . $wp_rewrite->index . '$|', $pathinfo) ) {
    187                 $request = $pathinfo;
    188             } else {
    189                 // If the request uri is the index, blank it out so that we don't try to match it against a rule.
    190                 if ( $req_uri == $wp_rewrite->index )
    191                     $req_uri = '';
    192                 $request = $req_uri;
    193             }
    194 
    195             $this->request = $request;
    196 
    197             // Look for matches.
    198             $request_match = $request;
    199             foreach ( (array) $rewrite as $match => $query) {
    200                 // Don't try to match against AtomPub calls
    201                 if ( $req_uri == 'wp-app.php' )
    202                     break;
    203 
    204                 // If the requesting file is the anchor of the match, prepend it
    205                 // to the path info.
    206                 if ( (! empty($req_uri)) && (strpos($match, $req_uri) === 0) && ($req_uri != $request) )
    207                     $request_match = $req_uri . '/' . $request;
    208 
    209                 if ( preg_match("#^$match#", $request_match, $matches) ||
    210                     preg_match("#^$match#", urldecode($request_match), $matches) ) {
    211                     // Got a match.
    212                     $this->matched_rule = $match;
    213 
    214                     // Trim the query of everything up to the '?'.
    215                     $query = preg_replace("!^.+\?!", '', $query);
    216 
    217                     // Substitute the substring matches into the query.
    218                     $query = addslashes(WP_MatchesMapRegex::apply($query, $matches));
    219 
    220                     $this->matched_query = $query;
    221 
    222                     // Parse the query.
    223                     parse_str($query, $perma_query_vars);
    224 
    225                     // If we're processing a 404 request, clear the error var
    226                     // since we found something.
    227                     if ( isset($_GET['error']) )
    228                         unset($_GET['error']);
    229 
    230                     if ( isset($error) )
    231                         unset($error);
    232 
    233                     break;
    234                 }
    235             }
    236 
    237             // If req_uri is empty or if it is a request for ourself, unset error.
    238             if ( empty($request) || $req_uri == $self || strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) {
    239                 if ( isset($_GET['error']) )
    240                     unset($_GET['error']);
    241 
    242                 if ( isset($error) )
    243                     unset($error);
    244 
    245                 if ( isset($perma_query_vars) && strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false )
    246                     unset($perma_query_vars);
    247 
    248                 $this->did_permalink = false;
    249             }
    250         }
    251 
    252         $this->public_query_vars = apply_filters('query_vars', $this->public_query_vars);
    253 
    254         foreach ( $GLOBALS['wp_post_types'] as $post_type => $t )
    255             if ( $t->query_var )
    256                 $post_type_query_vars[$t->query_var] = $post_type;
    257 
    258         foreach ( $this->public_query_vars as $wpvar ) {
    259             if ( isset( $this->extra_query_vars[$wpvar] ) )
    260                 $this->query_vars[$wpvar] = $this->extra_query_vars[$wpvar];
    261             elseif ( isset( $_POST[$wpvar] ) )
    262                 $this->query_vars[$wpvar] = $_POST[$wpvar];
    263             elseif ( isset( $_GET[$wpvar] ) )
    264                 $this->query_vars[$wpvar] = $_GET[$wpvar];
    265             elseif ( isset( $perma_query_vars[$wpvar] ) )
    266                 $this->query_vars[$wpvar] = $perma_query_vars[$wpvar];
    267 
    268             if ( !empty( $this->query_vars[$wpvar] ) ) {
    269                 if ( ! is_array( $this->query_vars[$wpvar] ) ) {
    270                     $this->query_vars[$wpvar] = (string) $this->query_vars[$wpvar];
    271                 } else {
    272                     foreach ( $this->query_vars[$wpvar] as $vkey => $v ) {
    273                         if ( !is_object( $v ) ) {
    274                             $this->query_vars[$wpvar][$vkey] = (string) $v;
    275                         }
    276                     }
    277                 }
    278 
    279                 if ( isset($post_type_query_vars[$wpvar] ) ) {
    280                     $this->query_vars['post_type'] = $post_type_query_vars[$wpvar];
    281                     $this->query_vars['name'] = $this->query_vars[$wpvar];
    282                 }
    283             }
    284         }
    285 
    286         // Limit publicly queried post_types to those that are publicly_queryable
    287         if ( isset( $this->query_vars['post_type']) ) {
    288             $queryable_post_types = get_post_types( array('publicly_queryable' => true) );
    289             if ( ! is_array( $this->query_vars['post_type'] ) ) {
    290                 if ( ! in_array( $this->query_vars['post_type'], $queryable_post_types ) )
    291                     unset( $this->query_vars['post_type'] );
    292             } else {
    293                 $this->query_vars['post_type'] = array_intersect( $this->query_vars['post_type'], $queryable_post_types );
    294             }
    295         }
    296 
    297         foreach ( (array) $this->private_query_vars as $var) {
    298             if ( isset($this->extra_query_vars[$var]) )
    299                 $this->query_vars[$var] = $this->extra_query_vars[$var];
    300         }
    301 
    302         if ( isset($error) )
    303             $this->query_vars['error'] = $error;
    304 
    305         $this->query_vars = apply_filters('request', $this->query_vars);
    306 
    307         do_action_ref_array('parse_request', array(&$this));
    308     }
    309 
    310     /**
    311      * Send additional HTTP headers for caching, content type, etc.
    312      *
    313      * Sets the X-Pingback header, 404 status (if 404), Content-type. If showing
    314      * a feed, it will also send last-modified, etag, and 304 status if needed.
    315      *
    316      * @since 2.0.0
    317      */
    318     function send_headers() {
    319         $headers = array('X-Pingback' => get_bloginfo('pingback_url'));
    320         $status = null;
    321         $exit_required = false;
    322 
    323         if ( is_user_logged_in() )
    324             $headers = array_merge($headers, wp_get_nocache_headers());
    325         if ( !empty($this->query_vars['error']) && '404' == $this->query_vars['error'] ) {
    326             $status = 404;
    327             if ( !is_user_logged_in() )
    328                 $headers = array_merge($headers, wp_get_nocache_headers());
    329             $headers['Content-Type'] = get_option('html_type') . '; charset=' . get_option('blog_charset');
    330         } else if ( empty($this->query_vars['feed']) ) {
    331             $headers['Content-Type'] = get_option('html_type') . '; charset=' . get_option('blog_charset');
    332         } else {
    333             // We're showing a feed, so WP is indeed the only thing that last changed
    334             if ( !empty($this->query_vars['withcomments'])
    335                 || ( empty($this->query_vars['withoutcomments'])
    336                     && ( !empty($this->query_vars['p'])
    337                         || !empty($this->query_vars['name'])
    338                         || !empty($this->query_vars['page_id'])
    339                         || !empty($this->query_vars['pagename'])
    340                         || !empty($this->query_vars['attachment'])
    341                         || !empty($this->query_vars['attachment_id'])
    342                     )
    343                 )
    344             )
    345                 $wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastcommentmodified('GMT'), 0).' GMT';
    346             else
    347                 $wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastpostmodified('GMT'), 0).' GMT';
    348             $wp_etag = '"' . md5($wp_last_modified) . '"';
    349             $headers['Last-Modified'] = $wp_last_modified;
    350             $headers['ETag'] = $wp_etag;
    351 
    352             // Support for Conditional GET
    353             if (isset($_SERVER['HTTP_IF_NONE_MATCH']))
    354                 $client_etag = stripslashes(stripslashes($_SERVER['HTTP_IF_NONE_MATCH']));
    355             else $client_etag = false;
    356 
    357             $client_last_modified = empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? '' : trim($_SERVER['HTTP_IF_MODIFIED_SINCE']);
    358             // If string is empty, return 0. If not, attempt to parse into a timestamp
    359             $client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;
    360 
    361             // Make a timestamp for our most recent modification...
    362             $wp_modified_timestamp = strtotime($wp_last_modified);
    363 
    364             if ( ($client_last_modified && $client_etag) ?
    365                      (($client_modified_timestamp >= $wp_modified_timestamp) && ($client_etag == $wp_etag)) :
    366                      (($client_modified_timestamp >= $wp_modified_timestamp) || ($client_etag == $wp_etag)) ) {
    367                 $status = 304;
    368                 $exit_required = true;
    369             }
    370         }
    371 
    372         $headers = apply_filters('wp_headers', $headers, $this);
    373 
    374         if ( ! empty( $status ) )
    375             status_header( $status );
    376         foreach( (array) $headers as $name => $field_value )
    377             @header("{$name}: {$field_value}");
    378 
    379         if ( $exit_required )
    380             exit();
    381 
    382         do_action_ref_array('send_headers', array(&$this));
    383     }
    384 
    385     /**
    386      * Sets the query string property based off of the query variable property.
    387      *
    388      * The 'query_string' filter is deprecated, but still works. Plugins should
    389      * use the 'request' filter instead.
    390      *
    391      * @since 2.0.0
    392      */
    393     function build_query_string() {
    394         $this->query_string = '';
    395         foreach ( (array) array_keys($this->query_vars) as $wpvar) {
    396             if ( '' != $this->query_vars[$wpvar] ) {
    397                 $this->query_string .= (strlen($this->query_string) < 1) ? '' : '&';
    398                 if ( !is_scalar($this->query_vars[$wpvar]) ) // Discard non-scalars.
    399                     continue;
    400                 $this->query_string .= $wpvar . '=' . rawurlencode($this->query_vars[$wpvar]);
    401             }
    402         }
    403 
    404         // query_string filter deprecated.  Use request filter instead.
    405         if ( has_filter('query_string') ) {  // Don't bother filtering and parsing if no plugins are hooked in.
    406             $this->query_string = apply_filters('query_string', $this->query_string);
    407             parse_str($this->query_string, $this->query_vars);
    408         }
    409     }
    410 
    411     /**
    412      * Set up the WordPress Globals.
    413      *
    414      * The query_vars property will be extracted to the GLOBALS. So care should
    415      * be taken when naming global variables that might interfere with the
    416      * WordPress environment.
    417      *
    418      * @global string $query_string Query string for the loop.
    419      * @global int $more Only set, if single page or post.
    420      * @global int $single If single page or post. Only set, if single page or post.
    421      *
    422      * @since 2.0.0
    423      */
    424     function register_globals() {
    425         global $wp_query;
    426         // Extract updated query vars back into global namespace.
    427         foreach ( (array) $wp_query->query_vars as $key => $value) {
    428             $GLOBALS[$key] = $value;
    429         }
    430 
    431         $GLOBALS['query_string'] = $this->query_string;
    432         $GLOBALS['posts'] = & $wp_query->posts;
    433         $GLOBALS['post'] = (isset($wp_query->post)) ? $wp_query->post : null;
    434         $GLOBALS['request'] = $wp_query->request;
    435 
    436         if ( is_single() || is_page() ) {
    437             $GLOBALS['more'] = 1;
    438             $GLOBALS['single'] = 1;
    439         }
    440     }
    441 
    442     /**
    443      * Set up the current user.
    444      *
    445      * @since 2.0.0
    446      */
    447     function init() {
    448         wp_get_current_user();
    449     }
    450 
    451     /**
    452      * Set up the Loop based on the query variables.
    453      *
    454      * @uses WP::$query_vars
    455      * @since 2.0.0
    456      */
    457     function query_posts() {
    458         global $wp_the_query;
    459         $this->build_query_string();
    460         $wp_the_query->query($this->query_vars);
    461     }
    462 
    463     /**
    464      * Set the Headers for 404, if nothing is found for requested URL.
    465      *
    466      * Issue a 404 if a request doesn't match any posts and doesn't match
    467      * any object (e.g. an existing-but-empty category, tag, author) and a 404 was not already
    468      * issued, and if the request was not a search or the homepage.
    469      *
    470      * Otherwise, issue a 200.
    471      *
    472      * @since 2.0.0
    473      */
    474     function handle_404() {
    475         global $wp_query;
    476 
    477         if ( !is_admin() && ( 0 == count( $wp_query->posts ) ) && !is_404() && !is_robots() && !is_search() && !is_home() ) {
    478             // Don't 404 for these queries if they matched an object.
    479             if ( ( is_tag() || is_category() || is_tax() || is_author() ) && $wp_query->get_queried_object() && !is_paged() ) {
    480                 if ( !is_404() )
    481                     status_header( 200 );
    482                 return;
    483             }
    484             $wp_query->set_404();
    485             status_header( 404 );
    486             nocache_headers();
    487         } elseif ( !is_404() ) {
    488             status_header( 200 );
    489         }
    490     }
    491 
    492     /**
    493      * Sets up all of the variables required by the WordPress environment.
    494      *
    495      * The action 'wp' has one parameter that references the WP object. It
    496      * allows for accessing the properties and methods to further manipulate the
    497      * object.
    498      *
    499      * @since 2.0.0
    500      *
    501      * @param string|array $query_args Passed to {@link parse_request()}
    502      */
    503     function main($query_args = '') {
    504         $this->init();
    505         $this->parse_request($query_args);
    506         $this->send_headers();
    507         $this->query_posts();
    508         $this->handle_404();
    509         $this->register_globals();
    510         do_action_ref_array('wp', array(&$this));
    511     }
    512 
    513     /**
    514      * PHP4 Constructor - Does nothing.
    515      *
    516      * Call main() method when ready to run setup.
    517      *
    518      * @since 2.0.0
    519      *
    520      * @return WP
    521      */
    522     function WP() {
    523         // Empty.
    524     }
    525 }
    52612
    52713/**
     
    761247}
    762248
    763 /**
    764  * WordPress Error class.
    765  *
    766  * Container for checking for WordPress errors and error messages. Return
    767  * WP_Error and use {@link is_wp_error()} to check if this class is returned.
    768  * Many core WordPress functions pass this class in the event of an error and
    769  * if not handled properly will result in code errors.
    770  *
    771  * @package WordPress
    772  * @since 2.1.0
    773  */
    774 class WP_Error {
    775     /**
    776      * Stores the list of errors.
    777      *
    778      * @since 2.1.0
    779      * @var array
    780      * @access private
    781      */
    782     var $errors = array();
    783 
    784     /**
    785      * Stores the list of data for error codes.
    786      *
    787      * @since 2.1.0
    788      * @var array
    789      * @access private
    790      */
    791     var $error_data = array();
    792 
    793     /**
    794      * PHP4 Constructor - Sets up error message.
    795      *
    796      * If code parameter is empty then nothing will be done. It is possible to
    797      * add multiple messages to the same code, but with other methods in the
    798      * class.
    799      *
    800      * All parameters are optional, but if the code parameter is set, then the
    801      * data parameter is optional.
    802      *
    803      * @since 2.1.0
    804      *
    805      * @param string|int $code Error code
    806      * @param string $message Error message
    807      * @param mixed $data Optional. Error data.
    808      * @return WP_Error
    809      */
    810     function WP_Error($code = '', $message = '', $data = '') {
    811         if ( empty($code) )
    812             return;
    813 
    814         $this->errors[$code][] = $message;
    815 
    816         if ( ! empty($data) )
    817             $this->error_data[$code] = $data;
    818     }
    819 
    820     /**
    821      * Retrieve all error codes.
    822      *
    823      * @since 2.1.0
    824      * @access public
    825      *
    826      * @return array List of error codes, if avaiable.
    827      */
    828     function get_error_codes() {
    829         if ( empty($this->errors) )
    830             return array();
    831 
    832         return array_keys($this->errors);
    833     }
    834 
    835     /**
    836      * Retrieve first error code available.
    837      *
    838      * @since 2.1.0
    839      * @access public
    840      *
    841      * @return string|int Empty string, if no error codes.
    842      */
    843     function get_error_code() {
    844         $codes = $this->get_error_codes();
    845 
    846         if ( empty($codes) )
    847             return '';
    848 
    849         return $codes[0];
    850     }
    851 
    852     /**
    853      * Retrieve all error messages or error messages matching code.
    854      *
    855      * @since 2.1.0
    856      *
    857      * @param string|int $code Optional. Retrieve messages matching code, if exists.
    858      * @return array Error strings on success, or empty array on failure (if using codee parameter).
    859      */
    860     function get_error_messages($code = '') {
    861         // Return all messages if no code specified.
    862         if ( empty($code) ) {
    863             $all_messages = array();
    864             foreach ( (array) $this->errors as $code => $messages )
    865                 $all_messages = array_merge($all_messages, $messages);
    866 
    867             return $all_messages;
    868         }
    869 
    870         if ( isset($this->errors[$code]) )
    871             return $this->errors[$code];
    872         else
    873             return array();
    874     }
    875 
    876     /**
    877      * Get single error message.
    878      *
    879      * This will get the first message available for the code. If no code is
    880      * given then the first code available will be used.
    881      *
    882      * @since 2.1.0
    883      *
    884      * @param string|int $code Optional. Error code to retrieve message.
    885      * @return string
    886      */
    887     function get_error_message($code = '') {
    888         if ( empty($code) )
    889             $code = $this->get_error_code();
    890         $messages = $this->get_error_messages($code);
    891         if ( empty($messages) )
    892             return '';
    893         return $messages[0];
    894     }
    895 
    896     /**
    897      * Retrieve error data for error code.
    898      *
    899      * @since 2.1.0
    900      *
    901      * @param string|int $code Optional. Error code.
    902      * @return mixed Null, if no errors.
    903      */
    904     function get_error_data($code = '') {
    905         if ( empty($code) )
    906             $code = $this->get_error_code();
    907 
    908         if ( isset($this->error_data[$code]) )
    909             return $this->error_data[$code];
    910         return null;
    911     }
    912 
    913     /**
    914      * Append more error messages to list of error messages.
    915      *
    916      * @since 2.1.0
    917      * @access public
    918      *
    919      * @param string|int $code Error code.
    920      * @param string $message Error message.
    921      * @param mixed $data Optional. Error data.
    922      */
    923     function add($code, $message, $data = '') {
    924         $this->errors[$code][] = $message;
    925         if ( ! empty($data) )
    926             $this->error_data[$code] = $data;
    927     }
    928 
    929     /**
    930      * Add data for error code.
    931      *
    932      * The error code can only contain one error data.
    933      *
    934      * @since 2.1.0
    935      *
    936      * @param mixed $data Error data.
    937      * @param string|int $code Error code.
    938      */
    939     function add_data($data, $code = '') {
    940         if ( empty($code) )
    941             $code = $this->get_error_code();
    942 
    943         $this->error_data[$code] = $data;
    944     }
    945 }
    946 
    947 /**
    948  * Check whether variable is a WordPress Error.
    949  *
    950  * Looks at the object and if a WP_Error class. Does not check to see if the
    951  * parent is also WP_Error, so can't inherit WP_Error and still use this
    952  * function.
    953  *
    954  * @since 2.1.0
    955  *
    956  * @param mixed $thing Check if unknown variable is WordPress Error object.
    957  * @return bool True, if WP_Error. False, if not WP_Error.
    958  */
    959 function is_wp_error($thing) {
    960     if ( is_object($thing) && is_a($thing, 'WP_Error') )
    961         return true;
    962     return false;
    963 }
    964 
    965 /**
    966  * A class for displaying various tree-like structures.
    967  *
    968  * Extend the Walker class to use it, see examples at the below. Child classes
    969  * do not need to implement all of the abstract methods in the class. The child
    970  * only needs to implement the methods that are needed. Also, the methods are
    971  * not strictly abstract in that the parameter definition needs to be followed.
    972  * The child classes can have additional parameters.
    973  *
    974  * @package WordPress
    975  * @since 2.1.0
    976  * @abstract
    977  */
    978 class Walker {
    979     /**
    980      * What the class handles.
    981      *
    982      * @since 2.1.0
    983      * @var string
    984      * @access public
    985      */
    986     var $tree_type;
    987 
    988     /**
    989      * DB fields to use.
    990      *
    991      * @since 2.1.0
    992      * @var array
    993      * @access protected
    994      */
    995     var $db_fields;
    996 
    997     /**
    998      * Max number of pages walked by the paged walker
    999      *
    1000      * @since 2.7.0
    1001      * @var int
    1002      * @access protected
    1003      */
    1004     var $max_pages = 1;
    1005 
    1006     /**
    1007      * Starts the list before the elements are added.
    1008      *
    1009      * Additional parameters are used in child classes. The args parameter holds
    1010      * additional values that may be used with the child class methods. This
    1011      * method is called at the start of the output list.
    1012      *
    1013      * @since 2.1.0
    1014      * @abstract
    1015      *
    1016      * @param string $output Passed by reference. Used to append additional content.
    1017      */
    1018     function start_lvl(&$output) {}
    1019 
    1020     /**
    1021      * Ends the list of after the elements are added.
    1022      *
    1023      * Additional parameters are used in child classes. The args parameter holds
    1024      * additional values that may be used with the child class methods. This
    1025      * method finishes the list at the end of output of the elements.
    1026      *
    1027      * @since 2.1.0
    1028      * @abstract
    1029      *
    1030      * @param string $output Passed by reference. Used to append additional content.
    1031      */
    1032     function end_lvl(&$output)   {}
    1033 
    1034     /**
    1035      * Start the element output.
    1036      *
    1037      * Additional parameters are used in child classes. The args parameter holds
    1038      * additional values that may be used with the child class methods. Includes
    1039      * the element output also.
    1040      *
    1041      * @since 2.1.0
    1042      * @abstract
    1043      *
    1044      * @param string $output Passed by reference. Used to append additional content.
    1045      */
    1046     function start_el(&$output)  {}
    1047 
    1048     /**
    1049      * Ends the element output, if needed.
    1050      *
    1051      * Additional parameters are used in child classes. The args parameter holds
    1052      * additional values that may be used with the child class methods.
    1053      *
    1054      * @since 2.1.0
    1055      * @abstract
    1056      *
    1057      * @param string $output Passed by reference. Used to append additional content.
    1058      */
    1059     function end_el(&$output)    {}
    1060 
    1061     /**
    1062      * Traverse elements to create list from elements.
    1063      *
    1064      * Display one element if the element doesn't have any children otherwise,
    1065      * display the element and its children. Will only traverse up to the max
    1066      * depth and no ignore elements under that depth. It is possible to set the
    1067      * max depth to include all depths, see walk() method.
    1068      *
    1069      * This method shouldn't be called directly, use the walk() method instead.
    1070      *
    1071      * @since 2.5.0
    1072      *
    1073      * @param object $element Data object
    1074      * @param array $children_elements List of elements to continue traversing.
    1075      * @param int $max_depth Max depth to traverse.
    1076      * @param int $depth Depth of current element.
    1077      * @param array $args
    1078      * @param string $output Passed by reference. Used to append additional content.
    1079      * @return null Null on failure with no changes to parameters.
    1080      */
    1081     function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
    1082 
    1083         if ( !$element )
    1084             return;
    1085 
    1086         $id_field = $this->db_fields['id'];
    1087 
    1088         //display this element
    1089         if ( is_array( $args[0] ) )
    1090             $args[0]['has_children'] = ! empty( $children_elements[$element->$id_field] );
    1091         $cb_args = array_merge( array(&$output, $element, $depth), $args);
    1092         call_user_func_array(array(&$this, 'start_el'), $cb_args);
    1093 
    1094         $id = $element->$id_field;
    1095 
    1096         // descend only when the depth is right and there are childrens for this element
    1097         if ( ($max_depth == 0 || $max_depth > $depth+1 ) && isset( $children_elements[$id]) ) {
    1098 
    1099             foreach( $children_elements[ $id ] as $child ){
    1100 
    1101                 if ( !isset($newlevel) ) {
    1102                     $newlevel = true;
    1103                     //start the child delimiter
    1104                     $cb_args = array_merge( array(&$output, $depth), $args);
    1105                     call_user_func_array(array(&$this, 'start_lvl'), $cb_args);
    1106                 }
    1107                 $this->display_element( $child, $children_elements, $max_depth, $depth + 1, $args, $output );
    1108             }
    1109             unset( $children_elements[ $id ] );
    1110         }
    1111 
    1112         if ( isset($newlevel) && $newlevel ){
    1113             //end the child delimiter
    1114             $cb_args = array_merge( array(&$output, $depth), $args);
    1115             call_user_func_array(array(&$this, 'end_lvl'), $cb_args);
    1116         }
    1117 
    1118         //end this element
    1119         $cb_args = array_merge( array(&$output, $element, $depth), $args);
    1120         call_user_func_array(array(&$this, 'end_el'), $cb_args);
    1121     }
    1122 
    1123     /**
    1124      * Display array of elements hierarchically.
    1125      *
    1126      * It is a generic function which does not assume any existing order of
    1127      * elements. max_depth = -1 means flatly display every element. max_depth =
    1128      * 0 means display all levels. max_depth > 0  specifies the number of
    1129      * display levels.
    1130      *
    1131      * @since 2.1.0
    1132      *
    1133      * @param array $elements
    1134      * @param int $max_depth
    1135      * @return string
    1136      */
    1137     function walk( $elements, $max_depth) {
    1138 
    1139         $args = array_slice(func_get_args(), 2);
    1140         $output = '';
    1141 
    1142         if ($max_depth < -1) //invalid parameter
    1143             return $output;
    1144 
    1145         if (empty($elements)) //nothing to walk
    1146             return $output;
    1147 
    1148         $id_field = $this->db_fields['id'];
    1149         $parent_field = $this->db_fields['parent'];
    1150 
    1151         // flat display
    1152         if ( -1 == $max_depth ) {
    1153             $empty_array = array();
    1154             foreach ( $elements as $e )
    1155                 $this->display_element( $e, $empty_array, 1, 0, $args, $output );
    1156             return $output;
    1157         }
    1158 
    1159         /*
    1160          * need to display in hierarchical order
    1161          * separate elements into two buckets: top level and children elements
    1162          * children_elements is two dimensional array, eg.
    1163          * children_elements[10][] contains all sub-elements whose parent is 10.
    1164          */
    1165         $top_level_elements = array();
    1166         $children_elements  = array();
    1167         foreach ( $elements as $e) {
    1168             if ( 0 == $e->$parent_field )
    1169                 $top_level_elements[] = $e;
    1170             else
    1171                 $children_elements[ $e->$parent_field ][] = $e;
    1172         }
    1173 
    1174         /*
    1175          * when none of the elements is top level
    1176          * assume the first one must be root of the sub elements
    1177          */
    1178         if ( empty($top_level_elements) ) {
    1179 
    1180             $first = array_slice( $elements, 0, 1 );
    1181             $root = $first[0];
    1182 
    1183             $top_level_elements = array();
    1184             $children_elements  = array();
    1185             foreach ( $elements as $e) {
    1186                 if ( $root->$parent_field == $e->$parent_field )
    1187                     $top_level_elements[] = $e;
    1188                 else
    1189                     $children_elements[ $e->$parent_field ][] = $e;
    1190             }
    1191         }
    1192 
    1193         foreach ( $top_level_elements as $e )
    1194             $this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
    1195 
    1196         /*
    1197          * if we are displaying all levels, and remaining children_elements is not empty,
    1198          * then we got orphans, which should be displayed regardless
    1199          */
    1200         if ( ( $max_depth == 0 ) && count( $children_elements ) > 0 ) {
    1201             $empty_array = array();
    1202             foreach ( $children_elements as $orphans )
    1203                 foreach( $orphans as $op )
    1204                     $this->display_element( $op, $empty_array, 1, 0, $args, $output );
    1205          }
    1206 
    1207          return $output;
    1208     }
    1209 
    1210     /**
    1211      * paged_walk() - produce a page of nested elements
    1212      *
    1213      * Given an array of hierarchical elements, the maximum depth, a specific page number,
    1214      * and number of elements per page, this function first determines all top level root elements
    1215      * belonging to that page, then lists them and all of their children in hierarchical order.
    1216      *
    1217      * @package WordPress
    1218      * @since 2.7
    1219      * @param int $max_depth = 0 means display all levels; $max_depth > 0 specifies the number of display levels.
    1220      * @param int $page_num the specific page number, beginning with 1.
    1221      * @return XHTML of the specified page of elements
    1222      */
    1223     function paged_walk( $elements, $max_depth, $page_num, $per_page ) {
    1224 
    1225         /* sanity check */
    1226         if ( empty($elements) || $max_depth < -1 )
    1227             return '';
    1228 
    1229         $args = array_slice( func_get_args(), 4 );
    1230         $output = '';
    1231 
    1232         $id_field = $this->db_fields['id'];
    1233         $parent_field = $this->db_fields['parent'];
    1234 
    1235         $count = -1;
    1236         if ( -1 == $max_depth )
    1237             $total_top = count( $elements );
    1238         if ( $page_num < 1 || $per_page < 0  ) {
    1239             // No paging
    1240             $paging = false;
    1241             $start = 0;
    1242             if ( -1 == $max_depth )
    1243                 $end = $total_top;
    1244             $this->max_pages = 1;
    1245         } else {
    1246             $paging = true;
    1247             $start = ( (int)$page_num - 1 ) * (int)$per_page;
    1248             $end   = $start + $per_page;
    1249             if ( -1 == $max_depth )
    1250                 $this->max_pages = ceil($total_top / $per_page);
    1251         }
    1252 
    1253         // flat display
    1254         if ( -1 == $max_depth ) {
    1255             if ( !empty($args[0]['reverse_top_level']) ) {
    1256                 $elements = array_reverse( $elements );
    1257                 $oldstart = $start;
    1258                 $start = $total_top - $end;
    1259                 $end = $total_top - $oldstart;
    1260             }
    1261 
    1262             $empty_array = array();
    1263             foreach ( $elements as $e ) {
    1264                 $count++;
    1265                 if ( $count < $start )
    1266                     continue;
    1267                 if ( $count >= $end )
    1268                     break;
    1269                 $this->display_element( $e, $empty_array, 1, 0, $args, $output );
    1270             }
    1271             return $output;
    1272         }
    1273 
    1274         /*
    1275          * separate elements into two buckets: top level and children elements
    1276          * children_elements is two dimensional array, eg.
    1277          * children_elements[10][] contains all sub-elements whose parent is 10.
    1278          */
    1279         $top_level_elements = array();
    1280         $children_elements  = array();
    1281         foreach ( $elements as $e) {
    1282             if ( 0 == $e->$parent_field )
    1283                 $top_level_elements[] = $e;
    1284             else
    1285                 $children_elements[ $e->$parent_field ][] = $e;
    1286         }
    1287 
    1288         $total_top = count( $top_level_elements );
    1289         if ( $paging )
    1290             $this->max_pages = ceil($total_top / $per_page);
    1291         else
    1292             $end = $total_top;
    1293 
    1294         if ( !empty($args[0]['reverse_top_level']) ) {
    1295             $top_level_elements = array_reverse( $top_level_elements );
    1296             $oldstart = $start;
    1297             $start = $total_top - $end;
    1298             $end = $total_top - $oldstart;
    1299         }
    1300         if ( !empty($args[0]['reverse_children']) ) {
    1301             foreach ( $children_elements as $parent => $children )
    1302                 $children_elements[$parent] = array_reverse( $children );
    1303         }
    1304 
    1305         foreach ( $top_level_elements as $e ) {
    1306             $count++;
    1307 
    1308             //for the last page, need to unset earlier children in order to keep track of orphans
    1309             if ( $end >= $total_top && $count < $start )
    1310                     $this->unset_children( $e, $children_elements );
    1311 
    1312             if ( $count < $start )
    1313                 continue;
    1314 
    1315             if ( $count >= $end )
    1316                 break;
    1317 
    1318             $this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
    1319         }
    1320 
    1321         if ( $end >= $total_top && count( $children_elements ) > 0 ) {
    1322             $empty_array = array();
    1323             foreach ( $children_elements as $orphans )
    1324                 foreach( $orphans as $op )
    1325                     $this->display_element( $op, $empty_array, 1, 0, $args, $output );
    1326         }
    1327 
    1328         return $output;
    1329     }
    1330 
    1331     function get_number_of_root_elements( $elements ){
    1332 
    1333         $num = 0;
    1334         $parent_field = $this->db_fields['parent'];
    1335 
    1336         foreach ( $elements as $e) {
    1337             if ( 0 == $e->$parent_field )
    1338                 $num++;
    1339         }
    1340         return $num;
    1341     }
    1342 
    1343     // unset all the children for a given top level element
    1344     function unset_children( $e, &$children_elements ){
    1345 
    1346         if ( !$e || !$children_elements )
    1347             return;
    1348 
    1349         $id_field = $this->db_fields['id'];
    1350         $id = $e->$id_field;
    1351 
    1352         if ( !empty($children_elements[$id]) && is_array($children_elements[$id]) )
    1353             foreach ( (array) $children_elements[$id] as $child )
    1354                 $this->unset_children( $child, $children_elements );
    1355 
    1356         if ( isset($children_elements[$id]) )
    1357             unset( $children_elements[$id] );
    1358 
    1359     }
    1360 }
    1361 
    1362 /**
    1363  * Create HTML list of pages.
    1364  *
    1365  * @package WordPress
    1366  * @since 2.1.0
    1367  * @uses Walker
    1368  */
    1369 class Walker_Page extends Walker {
    1370     /**
    1371      * @see Walker::$tree_type
    1372      * @since 2.1.0
    1373      * @var string
    1374      */
    1375     var $tree_type = 'page';
    1376 
    1377     /**
    1378      * @see Walker::$db_fields
    1379      * @since 2.1.0
    1380      * @todo Decouple this.
    1381      * @var array
    1382      */
    1383     var $db_fields = array ('parent' => 'post_parent', 'id' => 'ID');
    1384 
    1385     /**
    1386      * @see Walker::start_lvl()
    1387      * @since 2.1.0
    1388      *
    1389      * @param string $output Passed by reference. Used to append additional content.
    1390      * @param int $depth Depth of page. Used for padding.
    1391      */
    1392     function start_lvl(&$output, $depth) {
    1393         $indent = str_repeat("\t", $depth);
    1394         $output .= "\n$indent<ul class='children'>\n";
    1395     }
    1396 
    1397     /**
    1398      * @see Walker::end_lvl()
    1399      * @since 2.1.0
    1400      *
    1401      * @param string $output Passed by reference. Used to append additional content.
    1402      * @param int $depth Depth of page. Used for padding.
    1403      */
    1404     function end_lvl(&$output, $depth) {
    1405         $indent = str_repeat("\t", $depth);
    1406         $output .= "$indent</ul>\n";
    1407     }
    1408 
    1409     /**
    1410      * @see Walker::start_el()
    1411      * @since 2.1.0
    1412      *
    1413      * @param string $output Passed by reference. Used to append additional content.
    1414      * @param object $page Page data object.
    1415      * @param int $depth Depth of page. Used for padding.
    1416      * @param int $current_page Page ID.
    1417      * @param array $args
    1418      */
    1419     function start_el(&$output, $page, $depth, $args, $current_page) {
    1420         if ( $depth )
    1421             $indent = str_repeat("\t", $depth);
    1422         else
    1423             $indent = '';
    1424 
    1425         extract($args, EXTR_SKIP);
    1426         $css_class = array('page_item', 'page-item-'.$page->ID);
    1427         if ( !empty($current_page) ) {
    1428             $_current_page = get_page( $current_page );
    1429             if ( isset($_current_page->ancestors) && in_array($page->ID, (array) $_current_page->ancestors) )
    1430                 $css_class[] = 'current_page_ancestor';
    1431             if ( $page->ID == $current_page )
    1432                 $css_class[] = 'current_page_item';
    1433             elseif ( $_current_page && $page->ID == $_current_page->post_parent )
    1434                 $css_class[] = 'current_page_parent';
    1435         } elseif ( $page->ID == get_option('page_for_posts') ) {
    1436             $css_class[] = 'current_page_parent';
    1437         }
    1438 
    1439         $css_class = implode(' ', apply_filters('page_css_class', $css_class, $page));
    1440 
    1441         $output .= $indent . '<li class="' . $css_class . '"><a href="' . get_permalink($page->ID) . '" title="' . esc_attr( wp_strip_all_tags( apply_filters( 'the_title', $page->post_title, $page->ID ) ) ) . '">' . $link_before . apply_filters( 'the_title', $page->post_title, $page->ID ) . $link_after . '</a>';
    1442 
    1443         if ( !empty($show_date) ) {
    1444             if ( 'modified' == $show_date )
    1445                 $time = $page->post_modified;
    1446             else
    1447                 $time = $page->post_date;
    1448 
    1449             $output .= " " . mysql2date($date_format, $time);
    1450         }
    1451     }
    1452 
    1453     /**
    1454      * @see Walker::end_el()
    1455      * @since 2.1.0
    1456      *
    1457      * @param string $output Passed by reference. Used to append additional content.
    1458      * @param object $page Page data object. Not used.
    1459      * @param int $depth Depth of page. Not Used.
    1460      */
    1461     function end_el(&$output, $page, $depth) {
    1462         $output .= "</li>\n";
    1463     }
    1464 
    1465 }
    1466 
    1467 /**
    1468  * Create HTML dropdown list of pages.
    1469  *
    1470  * @package WordPress
    1471  * @since 2.1.0
    1472  * @uses Walker
    1473  */
    1474 class Walker_PageDropdown extends Walker {
    1475     /**
    1476      * @see Walker::$tree_type
    1477      * @since 2.1.0
    1478      * @var string
    1479      */
    1480     var $tree_type = 'page';
    1481 
    1482     /**
    1483      * @see Walker::$db_fields
    1484      * @since 2.1.0
    1485      * @todo Decouple this
    1486      * @var array
    1487      */
    1488     var $db_fields = array ('parent' => 'post_parent', 'id' => 'ID');
    1489 
    1490     /**
    1491      * @see Walker::start_el()
    1492      * @since 2.1.0
    1493      *
    1494      * @param string $output Passed by reference. Used to append additional content.
    1495      * @param object $page Page data object.
    1496      * @param int $depth Depth of page in reference to parent pages. Used for padding.
    1497      * @param array $args Uses 'selected' argument for selected page to set selected HTML attribute for option element.
    1498      */
    1499     function start_el(&$output, $page, $depth, $args) {
    1500         $pad = str_repeat('&nbsp;', $depth * 3);
    1501 
    1502         $output .= "\t<option class=\"level-$depth\" value=\"$page->ID\"";
    1503         if ( $page->ID == $args['selected'] )
    1504             $output .= ' selected="selected"';
    1505         $output .= '>';
    1506         $title = esc_html($page->post_title);
    1507         $output .= "$pad$title";
    1508         $output .= "</option>\n";
    1509     }
    1510 }
    1511 
    1512 /**
    1513  * Create HTML list of categories.
    1514  *
    1515  * @package WordPress
    1516  * @since 2.1.0
    1517  * @uses Walker
    1518  */
    1519 class Walker_Category extends Walker {
    1520     /**
    1521      * @see Walker::$tree_type
    1522      * @since 2.1.0
    1523      * @var string
    1524      */
    1525     var $tree_type = 'category';
    1526 
    1527     /**
    1528      * @see Walker::$db_fields
    1529      * @since 2.1.0
    1530      * @todo Decouple this
    1531      * @var array
    1532      */
    1533     var $db_fields = array ('parent' => 'parent', 'id' => 'term_id');
    1534 
    1535     /**
    1536      * @see Walker::start_lvl()
    1537      * @since 2.1.0
    1538      *
    1539      * @param string $output Passed by reference. Used to append additional content.
    1540      * @param int $depth Depth of category. Used for tab indentation.
    1541      * @param array $args Will only append content if style argument value is 'list'.
    1542      */
    1543     function start_lvl(&$output, $depth, $args) {
    1544         if ( 'list' != $args['style'] )
    1545             return;
    1546 
    1547         $indent = str_repeat("\t", $depth);
    1548         $output .= "$indent<ul class='children'>\n";
    1549     }
    1550 
    1551     /**
    1552      * @see Walker::end_lvl()
    1553      * @since 2.1.0
    1554      *
    1555      * @param string $output Passed by reference. Used to append additional content.
    1556      * @param int $depth Depth of category. Used for tab indentation.
    1557      * @param array $args Will only append content if style argument value is 'list'.
    1558      */
    1559     function end_lvl(&$output, $depth, $args) {
    1560         if ( 'list' != $args['style'] )
    1561             return;
    1562 
    1563         $indent = str_repeat("\t", $depth);
    1564         $output .= "$indent</ul>\n";
    1565     }
    1566 
    1567     /**
    1568      * @see Walker::start_el()
    1569      * @since 2.1.0
    1570      *
    1571      * @param string $output Passed by reference. Used to append additional content.
    1572      * @param object $category Category data object.
    1573      * @param int $depth Depth of category in reference to parents.
    1574      * @param array $args
    1575      */
    1576     function start_el(&$output, $category, $depth, $args) {
    1577         extract($args);
    1578 
    1579         $cat_name = esc_attr( $category->name );
    1580         $cat_name = apply_filters( 'list_cats', $cat_name, $category );
    1581         $link = '<a href="' . esc_attr( get_term_link($category) ) . '" ';
    1582         if ( $use_desc_for_title == 0 || empty($category->description) )
    1583             $link .= 'title="' . sprintf(__( 'View all posts filed under %s' ), $cat_name) . '"';
    1584         else
    1585             $link .= 'title="' . esc_attr( strip_tags( apply_filters( 'category_description', $category->description, $category ) ) ) . '"';
    1586         $link .= '>';
    1587         $link .= $cat_name . '</a>';
    1588 
    1589         if ( !empty($feed_image) || !empty($feed) ) {
    1590             $link .= ' ';
    1591 
    1592             if ( empty($feed_image) )
    1593                 $link .= '(';
    1594 
    1595             $link .= '<a href="' . get_term_feed_link( $category->term_id, $category->taxonomy, $feed_type ) . '"';
    1596 
    1597             if ( empty($feed) ) {
    1598                 $alt = ' alt="' . sprintf(__( 'Feed for all posts filed under %s' ), $cat_name ) . '"';
    1599             } else {
    1600                 $title = ' title="' . $feed . '"';
    1601                 $alt = ' alt="' . $feed . '"';
    1602                 $name = $feed;
    1603                 $link .= $title;
    1604             }
    1605 
    1606             $link .= '>';
    1607 
    1608             if ( empty($feed_image) )
    1609                 $link .= $name;
    1610             else
    1611                 $link .= "<img src='$feed_image'$alt$title" . ' />';
    1612 
    1613             $link .= '</a>';
    1614 
    1615             if ( empty($feed_image) )
    1616                 $link .= ')';
    1617         }
    1618 
    1619         if ( !empty($show_count) )
    1620             $link .= ' (' . intval($category->count) . ')';
    1621 
    1622         if ( !empty($show_date) )
    1623             $link .= ' ' . gmdate('Y-m-d', $category->last_update_timestamp);
    1624 
    1625         if ( 'list' == $args['style'] ) {
    1626             $output .= "\t<li";
    1627             $class = 'cat-item cat-item-' . $category->term_id;
    1628             if ( !empty($current_category) ) {
    1629                 $_current_category = get_term( $current_category, $category->taxonomy );
    1630                 if ( $category->term_id == $current_category )
    1631                     $class .=  ' current-cat';
    1632                 elseif ( $category->term_id == $_current_category->parent )
    1633                     $class .=  ' current-cat-parent';
    1634             }
    1635             $output .=  ' class="' . $class . '"';
    1636             $output .= ">$link\n";
    1637         } else {
    1638             $output .= "\t$link<br />\n";
    1639         }
    1640     }
    1641 
    1642     /**
    1643      * @see Walker::end_el()
    1644      * @since 2.1.0
    1645      *
    1646      * @param string $output Passed by reference. Used to append additional content.
    1647      * @param object $page Not used.
    1648      * @param int $depth Depth of category. Not used.
    1649      * @param array $args Only uses 'list' for whether should append to output.
    1650      */
    1651     function end_el(&$output, $page, $depth, $args) {
    1652         if ( 'list' != $args['style'] )
    1653             return;
    1654 
    1655         $output .= "</li>\n";
    1656     }
    1657 
    1658 }
    1659 
    1660 /**
    1661  * Create HTML dropdown list of Categories.
    1662  *
    1663  * @package WordPress
    1664  * @since 2.1.0
    1665  * @uses Walker
    1666  */
    1667 class Walker_CategoryDropdown extends Walker {
    1668     /**
    1669      * @see Walker::$tree_type
    1670      * @since 2.1.0
    1671      * @var string
    1672      */
    1673     var $tree_type = 'category';
    1674 
    1675     /**
    1676      * @see Walker::$db_fields
    1677      * @since 2.1.0
    1678      * @todo Decouple this
    1679      * @var array
    1680      */
    1681     var $db_fields = array ('parent' => 'parent', 'id' => 'term_id');
    1682 
    1683     /**
    1684      * @see Walker::start_el()
    1685      * @since 2.1.0
    1686      *
    1687      * @param string $output Passed by reference. Used to append additional content.
    1688      * @param object $category Category data object.
    1689      * @param int $depth Depth of category. Used for padding.
    1690      * @param array $args Uses 'selected', 'show_count', and 'show_last_update' keys, if they exist.
    1691      */
    1692     function start_el(&$output, $category, $depth, $args) {
    1693         $pad = str_repeat('&nbsp;', $depth * 3);
    1694 
    1695         $cat_name = apply_filters('list_cats', $category->name, $category);
    1696         $output .= "\t<option class=\"level-$depth\" value=\"".$category->term_id."\"";
    1697         if ( $category->term_id == $args['selected'] )
    1698             $output .= ' selected="selected"';
    1699         $output .= '>';
    1700         $output .= $pad.$cat_name;
    1701         if ( $args['show_count'] )
    1702             $output .= '&nbsp;&nbsp;('. $category->count .')';
    1703         if ( $args['show_last_update'] ) {
    1704             $format = 'Y-m-d';
    1705             $output .= '&nbsp;&nbsp;' . gmdate($format, $category->last_update_timestamp);
    1706         }
    1707         $output .= "</option>\n";
    1708     }
    1709 }
    1710 
    1711 /**
    1712  * Send XML response back to AJAX request.
    1713  *
    1714  * @package WordPress
    1715  * @since 2.1.0
    1716  */
    1717 class WP_Ajax_Response {
    1718     /**
    1719      * Store XML responses to send.
    1720      *
    1721      * @since 2.1.0
    1722      * @var array
    1723      * @access private
    1724      */
    1725     var $responses = array();
    1726 
    1727     /**
    1728      * PHP4 Constructor - Passes args to {@link WP_Ajax_Response::add()}.
    1729      *
    1730      * @since 2.1.0
    1731      * @see WP_Ajax_Response::add()
    1732      *
    1733      * @param string|array $args Optional. Will be passed to add() method.
    1734      * @return WP_Ajax_Response
    1735      */
    1736     function WP_Ajax_Response( $args = '' ) {
    1737         if ( !empty($args) )
    1738             $this->add($args);
    1739     }
    1740 
    1741     /**
    1742      * Append to XML response based on given arguments.
    1743      *
    1744      * The arguments that can be passed in the $args parameter are below. It is
    1745      * also possible to pass a WP_Error object in either the 'id' or 'data'
    1746      * argument. The parameter isn't actually optional, content should be given
    1747      * in order to send the correct response.
    1748      *
    1749      * 'what' argument is a string that is the XMLRPC response type.
    1750      * 'action' argument is a boolean or string that acts like a nonce.
    1751      * 'id' argument can be WP_Error or an integer.
    1752      * 'old_id' argument is false by default or an integer of the previous ID.
    1753      * 'position' argument is an integer or a string with -1 = top, 1 = bottom,
    1754      * html ID = after, -html ID = before.
    1755      * 'data' argument is a string with the content or message.
    1756      * 'supplemental' argument is an array of strings that will be children of
    1757      * the supplemental element.
    1758      *
    1759      * @since 2.1.0
    1760      *
    1761      * @param string|array $args Override defaults.
    1762      * @return string XML response.
    1763      */
    1764     function add( $args = '' ) {
    1765         $defaults = array(
    1766             'what' => 'object', 'action' => false,
    1767             'id' => '0', 'old_id' => false,
    1768             'position' => 1,
    1769             'data' => '', 'supplemental' => array()
    1770         );
    1771 
    1772         $r = wp_parse_args( $args, $defaults );
    1773         extract( $r, EXTR_SKIP );
    1774         $position = preg_replace( '/[^a-z0-9:_-]/i', '', $position );
    1775 
    1776         if ( is_wp_error($id) ) {
    1777             $data = $id;
    1778             $id = 0;
    1779         }
    1780 
    1781         $response = '';
    1782         if ( is_wp_error($data) ) {
    1783             foreach ( (array) $data->get_error_codes() as $code ) {
    1784                 $response .= "<wp_error code='$code'><![CDATA[" . $data->get_error_message($code) . "]]></wp_error>";
    1785                 if ( !$error_data = $data->get_error_data($code) )
    1786                     continue;
    1787                 $class = '';
    1788                 if ( is_object($error_data) ) {
    1789                     $class = ' class="' . get_class($error_data) . '"';
    1790                     $error_data = get_object_vars($error_data);
    1791                 }
    1792 
    1793                 $response .= "<wp_error_data code='$code'$class>";
    1794 
    1795                 if ( is_scalar($error_data) ) {
    1796                     $response .= "<![CDATA[$error_data]]>";
    1797                 } elseif ( is_array($error_data) ) {
    1798                     foreach ( $error_data as $k => $v )
    1799                         $response .= "<$k><![CDATA[$v]]></$k>";
    1800                 }
    1801 
    1802                 $response .= "</wp_error_data>";
    1803             }
    1804         } else {
    1805             $response = "<response_data><![CDATA[$data]]></response_data>";
    1806         }
    1807 
    1808         $s = '';
    1809         if ( is_array($supplemental) ) {
    1810             foreach ( $supplemental as $k => $v )
    1811                 $s .= "<$k><![CDATA[$v]]></$k>";
    1812             $s = "<supplemental>$s</supplemental>";
    1813         }
    1814 
    1815         if ( false === $action )
    1816             $action = $_POST['action'];
    1817 
    1818         $x = '';
    1819         $x .= "<response action='{$action}_$id'>"; // The action attribute in the xml output is formatted like a nonce action
    1820         $x .=   "<$what id='$id' " . ( false === $old_id ? '' : "old_id='$old_id' " ) . "position='$position'>";
    1821         $x .=       $response;
    1822         $x .=       $s;
    1823         $x .=   "</$what>";
    1824         $x .= "</response>";
    1825 
    1826         $this->responses[] = $x;
    1827         return $x;
    1828     }
    1829 
    1830     /**
    1831      * Display XML formatted responses.
    1832      *
    1833      * Sets the content type header to text/xml.
    1834      *
    1835      * @since 2.1.0
    1836      */
    1837     function send() {
    1838         header('Content-Type: text/xml');
    1839         echo "<?xml version='1.0' standalone='yes'?><wp_ajax>";
    1840         foreach ( (array) $this->responses as $response )
    1841             echo $response;
    1842         echo '</wp_ajax>';
    1843         die();
    1844     }
    1845 }
    1846 
    1847 /**
    1848  * Helper class to remove the need to use eval to replace $matches[] in query strings.
    1849  *
    1850  * @since 2.9.0
    1851  */
    1852 class WP_MatchesMapRegex {
    1853     /**
    1854      * store for matches
    1855      *
    1856      * @access private
    1857      * @var array
    1858      */
    1859     var $_matches;
    1860 
    1861     /**
    1862      * store for mapping result
    1863      *
    1864      * @access public
    1865      * @var string
    1866      */
    1867     var $output;
    1868 
    1869     /**
    1870      * subject to perform mapping on (query string containing $matches[] references
    1871      *
    1872      * @access private
    1873      * @var string
    1874      */
    1875     var $_subject;
    1876 
    1877     /**
    1878      * regexp pattern to match $matches[] references
    1879      *
    1880      * @var string
    1881      */
    1882     var $_pattern = '(\$matches\[[1-9]+[0-9]*\])'; // magic number
    1883 
    1884     /**
    1885      * constructor
    1886      *
    1887      * @param string $subject subject if regex
    1888      * @param array  $matches data to use in map
    1889      * @return self
    1890      */
    1891     function WP_MatchesMapRegex($subject, $matches) {
    1892         $this->_subject = $subject;
    1893         $this->_matches = $matches;
    1894         $this->output = $this->_map();
    1895     }
    1896 
    1897     /**
    1898      * Substitute substring matches in subject.
    1899      *
    1900      * static helper function to ease use
    1901      *
    1902      * @access public
    1903      * @param string $subject subject
    1904      * @param array  $matches data used for subsitution
    1905      * @return string
    1906      */
    1907     function apply($subject, $matches) {
    1908         $oSelf =& new WP_MatchesMapRegex($subject, $matches);
    1909         return $oSelf->output;
    1910     }
    1911 
    1912     /**
    1913      * do the actual mapping
    1914      *
    1915      * @access private
    1916      * @return string
    1917      */
    1918     function _map() {
    1919         $callback = array(&$this, 'callback');
    1920         return preg_replace_callback($this->_pattern, $callback, $this->_subject);
    1921     }
    1922 
    1923     /**
    1924      * preg_replace_callback hook
    1925      *
    1926      * @access public
    1927      * @param  array $matches preg_replace regexp matches
    1928      * @return string
    1929      */
    1930     function callback($matches) {
    1931         $index = intval(substr($matches[0], 9, -1));
    1932         return ( isset( $this->_matches[$index] ) ? urlencode($this->_matches[$index]) : '' );
    1933     }
    1934 
    1935 }
    1936 
    1937249?>
Note: See TracChangeset for help on using the changeset viewer.