home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Blogs / wordpress2.6.exe / wordpress2.6 / wp-includes / classes.php < prev    next >
Encoding:
PHP Script  |  2008-07-30  |  24.3 KB  |  816 lines

  1. <?php
  2.  
  3. class WP {
  4.     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');
  5.  
  6.     var $private_query_vars = array('offset', 'posts_per_page', 'posts_per_archive_page', 'what_to_show', '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');
  7.     var $extra_query_vars = array();
  8.  
  9.     var $query_vars;
  10.     var $query_string;
  11.     var $request;
  12.     var $matched_rule;
  13.     var $matched_query;
  14.     var $did_permalink = false;
  15.  
  16.     function add_query_var($qv) {
  17.         if ( !in_array($qv, $this->public_query_vars) )
  18.             $this->public_query_vars[] = $qv;
  19.     }
  20.  
  21.     function set_query_var($key, $value) {
  22.         $this->query_vars[$key] = $value;
  23.     }
  24.  
  25.     function parse_request($extra_query_vars = '') {
  26.         global $wp_rewrite;
  27.  
  28.         $this->query_vars = array();
  29.         $taxonomy_query_vars = array();
  30.  
  31.         if ( is_array($extra_query_vars) )
  32.             $this->extra_query_vars = & $extra_query_vars;
  33.         else if (! empty($extra_query_vars))
  34.             parse_str($extra_query_vars, $this->extra_query_vars);
  35.  
  36.         // Process PATH_INFO, REQUEST_URI, and 404 for permalinks.
  37.  
  38.         // Fetch the rewrite rules.
  39.         $rewrite = $wp_rewrite->wp_rewrite_rules();
  40.  
  41.         if (! empty($rewrite)) {
  42.             // If we match a rewrite rule, this will be cleared.
  43.             $error = '404';
  44.             $this->did_permalink = true;
  45.  
  46.             if ( isset($_SERVER['PATH_INFO']) )
  47.                 $pathinfo = $_SERVER['PATH_INFO'];
  48.             else
  49.                 $pathinfo = '';
  50.             $pathinfo_array = explode('?', $pathinfo);
  51.             $pathinfo = str_replace("%", "%25", $pathinfo_array[0]);
  52.             $req_uri = $_SERVER['REQUEST_URI'];
  53.             $req_uri_array = explode('?', $req_uri);
  54.             $req_uri = $req_uri_array[0];
  55.             $self = $_SERVER['PHP_SELF'];
  56.             $home_path = parse_url(get_option('home'));
  57.             if ( isset($home_path['path']) )
  58.                 $home_path = $home_path['path'];
  59.             else
  60.                 $home_path = '';
  61.             $home_path = trim($home_path, '/');
  62.  
  63.             // Trim path info from the end and the leading home path from the
  64.             // front.  For path info requests, this leaves us with the requesting
  65.             // filename, if any.  For 404 requests, this leaves us with the
  66.             // requested permalink.
  67.             $req_uri = str_replace($pathinfo, '', rawurldecode($req_uri));
  68.             $req_uri = trim($req_uri, '/');
  69.             $req_uri = preg_replace("|^$home_path|", '', $req_uri);
  70.             $req_uri = trim($req_uri, '/');
  71.             $pathinfo = trim($pathinfo, '/');
  72.             $pathinfo = preg_replace("|^$home_path|", '', $pathinfo);
  73.             $pathinfo = trim($pathinfo, '/');
  74.             $self = trim($self, '/');
  75.             $self = preg_replace("|^$home_path|", '', $self);
  76.             $self = trim($self, '/');
  77.  
  78.             // The requested permalink is in $pathinfo for path info requests and
  79.             //  $req_uri for other requests.
  80.             if ( ! empty($pathinfo) && !preg_match('|^.*' . $wp_rewrite->index . '$|', $pathinfo) ) {
  81.                 $request = $pathinfo;
  82.             } else {
  83.                 // If the request uri is the index, blank it out so that we don't try to match it against a rule.
  84.                 if ( $req_uri == $wp_rewrite->index )
  85.                     $req_uri = '';
  86.                 $request = $req_uri;
  87.             }
  88.  
  89.             $this->request = $request;
  90.  
  91.             // Look for matches.
  92.             $request_match = $request;
  93.             foreach ($rewrite as $match => $query) {
  94.                 // Don't try to match against AtomPub calls
  95.                 if ( $req_uri == 'wp-app.php' )
  96.                     break;
  97.  
  98.                 // If the requesting file is the anchor of the match, prepend it
  99.                 // to the path info.
  100.                 if ((! empty($req_uri)) && (strpos($match, $req_uri) === 0) && ($req_uri != $request)) {
  101.                     $request_match = $req_uri . '/' . $request;
  102.                 }
  103.  
  104.                 if (preg_match("!^$match!", $request_match, $matches) ||
  105.                     preg_match("!^$match!", urldecode($request_match), $matches)) {
  106.                     // Got a match.
  107.                     $this->matched_rule = $match;
  108.  
  109.                     // Trim the query of everything up to the '?'.
  110.                     $query = preg_replace("!^.+\?!", '', $query);
  111.  
  112.                     // Substitute the substring matches into the query.
  113.                     eval("\$query = \"" . addslashes($query) . "\";");
  114.                     $this->matched_query = $query;
  115.  
  116.                     // Parse the query.
  117.                     parse_str($query, $perma_query_vars);
  118.  
  119.                     // If we're processing a 404 request, clear the error var
  120.                     // since we found something.
  121.                     if (isset($_GET['error']))
  122.                         unset($_GET['error']);
  123.  
  124.                     if (isset($error))
  125.                         unset($error);
  126.  
  127.                     break;
  128.                 }
  129.             }
  130.  
  131.             // If req_uri is empty or if it is a request for ourself, unset error.
  132.             if (empty($request) || $req_uri == $self || strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false) {
  133.                 if (isset($_GET['error']))
  134.                     unset($_GET['error']);
  135.  
  136.                 if (isset($error))
  137.                     unset($error);
  138.  
  139.                 if (isset($perma_query_vars) && strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false)
  140.                     unset($perma_query_vars);
  141.  
  142.                 $this->did_permalink = false;
  143.             }
  144.         }
  145.  
  146.         $this->public_query_vars = apply_filters('query_vars', $this->public_query_vars);
  147.  
  148.         foreach ( $GLOBALS['wp_taxonomies'] as $taxonomy => $t )
  149.             if ( isset($t->query_var) )
  150.                 $taxonomy_query_vars[$t->query_var] = $taxonomy;
  151.  
  152.         for ($i=0; $i<count($this->public_query_vars); $i += 1) {
  153.             $wpvar = $this->public_query_vars[$i];
  154.             if (isset($this->extra_query_vars[$wpvar]))
  155.                 $this->query_vars[$wpvar] = $this->extra_query_vars[$wpvar];
  156.             elseif (isset($GLOBALS[$wpvar]))
  157.                 $this->query_vars[$wpvar] = $GLOBALS[$wpvar];
  158.             elseif (!empty($_POST[$wpvar]))
  159.                 $this->query_vars[$wpvar] = $_POST[$wpvar];
  160.             elseif (!empty($_GET[$wpvar]))
  161.                 $this->query_vars[$wpvar] = $_GET[$wpvar];
  162.             elseif (!empty($perma_query_vars[$wpvar]))
  163.                 $this->query_vars[$wpvar] = $perma_query_vars[$wpvar];
  164.  
  165.             if ( !empty( $this->query_vars[$wpvar] ) ) {
  166.                 $this->query_vars[$wpvar] = (string) $this->query_vars[$wpvar];
  167.                 if ( in_array( $wpvar, $taxonomy_query_vars ) ) {
  168.                     $this->query_vars['taxonomy'] = $taxonomy_query_vars[$wpvar];
  169.                     $this->query_vars['term'] = $this->query_vars[$wpvar];
  170.                 }
  171.             }
  172.         }
  173.  
  174.         foreach ($this->private_query_vars as $var) {
  175.             if (isset($this->extra_query_vars[$var]))
  176.                 $this->query_vars[$var] = $this->extra_query_vars[$var];
  177.             elseif (isset($GLOBALS[$var]) && '' != $GLOBALS[$var])
  178.                 $this->query_vars[$var] = $GLOBALS[$var];
  179.         }
  180.  
  181.         if ( isset($error) )
  182.             $this->query_vars['error'] = $error;
  183.  
  184.         $this->query_vars = apply_filters('request', $this->query_vars);
  185.  
  186.         do_action_ref_array('parse_request', array(&$this));
  187.     }
  188.  
  189.     function send_headers() {
  190.         @header('X-Pingback: '. get_bloginfo('pingback_url'));
  191.         if ( is_user_logged_in() )
  192.             nocache_headers();
  193.         if ( !empty($this->query_vars['error']) && '404' == $this->query_vars['error'] ) {
  194.             status_header( 404 );
  195.             if ( !is_user_logged_in() )
  196.                 nocache_headers();
  197.             @header('Content-Type: ' . get_option('html_type') . '; charset=' . get_option('blog_charset'));
  198.         } else if ( empty($this->query_vars['feed']) ) {
  199.             @header('Content-Type: ' . get_option('html_type') . '; charset=' . get_option('blog_charset'));
  200.         } else {
  201.             // We're showing a feed, so WP is indeed the only thing that last changed
  202.             if ( !empty($this->query_vars['withcomments'])
  203.                 || ( empty($this->query_vars['withoutcomments'])
  204.                     && ( !empty($this->query_vars['p'])
  205.                         || !empty($this->query_vars['name'])
  206.                         || !empty($this->query_vars['page_id'])
  207.                         || !empty($this->query_vars['pagename'])
  208.                         || !empty($this->query_vars['attachment'])
  209.                         || !empty($this->query_vars['attachment_id'])
  210.                     )
  211.                 )
  212.             )
  213.                 $wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastcommentmodified('GMT'), 0).' GMT';
  214.             else
  215.                 $wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastpostmodified('GMT'), 0).' GMT';
  216.             $wp_etag = '"' . md5($wp_last_modified) . '"';
  217.             @header("Last-Modified: $wp_last_modified");
  218.             @header("ETag: $wp_etag");
  219.  
  220.             // Support for Conditional GET
  221.             if (isset($_SERVER['HTTP_IF_NONE_MATCH']))
  222.                 $client_etag = stripslashes(stripslashes($_SERVER['HTTP_IF_NONE_MATCH']));
  223.             else $client_etag = false;
  224.  
  225.             $client_last_modified = empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? '' : trim($_SERVER['HTTP_IF_MODIFIED_SINCE']);
  226.             // If string is empty, return 0. If not, attempt to parse into a timestamp
  227.             $client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;
  228.  
  229.             // Make a timestamp for our most recent modification...
  230.             $wp_modified_timestamp = strtotime($wp_last_modified);
  231.  
  232.             if ( ($client_last_modified && $client_etag) ?
  233.                      (($client_modified_timestamp >= $wp_modified_timestamp) && ($client_etag == $wp_etag)) :
  234.                      (($client_modified_timestamp >= $wp_modified_timestamp) || ($client_etag == $wp_etag)) ) {
  235.                 status_header( 304 );
  236.                 exit;
  237.             }
  238.         }
  239.  
  240.         do_action_ref_array('send_headers', array(&$this));
  241.     }
  242.  
  243.     function build_query_string() {
  244.         $this->query_string = '';
  245.         foreach (array_keys($this->query_vars) as $wpvar) {
  246.             if ( '' != $this->query_vars[$wpvar] ) {
  247.                 $this->query_string .= (strlen($this->query_string) < 1) ? '' : '&';
  248.                 if ( !is_scalar($this->query_vars[$wpvar]) ) // Discard non-scalars.
  249.                     continue;
  250.                 $this->query_string .= $wpvar . '=' . rawurlencode($this->query_vars[$wpvar]);
  251.             }
  252.         }
  253.  
  254.         // query_string filter deprecated.  Use request filter instead.
  255.         if ( has_filter('query_string') ) {  // Don't bother filtering and parsing if no plugins are hooked in.
  256.             $this->query_string = apply_filters('query_string', $this->query_string);
  257.             parse_str($this->query_string, $this->query_vars);
  258.         }
  259.     }
  260.  
  261.     function register_globals() {
  262.         global $wp_query;
  263.         // Extract updated query vars back into global namespace.
  264.         foreach ($wp_query->query_vars as $key => $value) {
  265.             $GLOBALS[$key] = $value;
  266.         }
  267.  
  268.         $GLOBALS['query_string'] = & $this->query_string;
  269.         $GLOBALS['posts'] = & $wp_query->posts;
  270.         $GLOBALS['post'] = & $wp_query->post;
  271.         $GLOBALS['request'] = & $wp_query->request;
  272.  
  273.         if ( is_single() || is_page() ) {
  274.             $GLOBALS['more'] = 1;
  275.             $GLOBALS['single'] = 1;
  276.         }
  277.     }
  278.  
  279.     function init() {
  280.         wp_get_current_user();
  281.     }
  282.  
  283.     function query_posts() {
  284.         global $wp_the_query;
  285.         $this->build_query_string();
  286.         $wp_the_query->query($this->query_vars);
  287.      }
  288.  
  289.     function handle_404() {
  290.         global $wp_query;
  291.         // Issue a 404 if a permalink request doesn't match any posts.  Don't
  292.         // issue a 404 if one was already issued, if the request was a search,
  293.         // or if the request was a regular query string request rather than a
  294.         // permalink request.
  295.         if ( (0 == count($wp_query->posts)) && !is_404() && !is_search() && ( $this->did_permalink || (!empty($_SERVER['QUERY_STRING']) && (false === strpos($_SERVER['REQUEST_URI'], '?'))) ) ) {
  296.             $wp_query->set_404();
  297.             status_header( 404 );
  298.             nocache_headers();
  299.         }    elseif( is_404() != true ) {
  300.             status_header( 200 );
  301.         }
  302.     }
  303.  
  304.     function main($query_args = '') {
  305.         $this->init();
  306.         $this->parse_request($query_args);
  307.         $this->send_headers();
  308.         $this->query_posts();
  309.         $this->handle_404();
  310.         $this->register_globals();
  311.         do_action_ref_array('wp', array(&$this));
  312.     }
  313.  
  314.     function WP() {
  315.         // Empty.
  316.     }
  317. }
  318.  
  319. class WP_Error {
  320.     var $errors = array();
  321.     var $error_data = array();
  322.  
  323.     function WP_Error($code = '', $message = '', $data = '') {
  324.         if ( empty($code) )
  325.             return;
  326.  
  327.         $this->errors[$code][] = $message;
  328.  
  329.         if ( ! empty($data) )
  330.             $this->error_data[$code] = $data;
  331.     }
  332.  
  333.     function get_error_codes() {
  334.         if ( empty($this->errors) )
  335.             return array();
  336.  
  337.         return array_keys($this->errors);
  338.     }
  339.  
  340.     function get_error_code() {
  341.         $codes = $this->get_error_codes();
  342.  
  343.         if ( empty($codes) )
  344.             return '';
  345.  
  346.         return $codes[0];
  347.     }
  348.  
  349.     function get_error_messages($code = '') {
  350.         // Return all messages if no code specified.
  351.         if ( empty($code) ) {
  352.             $all_messages = array();
  353.             foreach ( $this->errors as $code => $messages )
  354.                 $all_messages = array_merge($all_messages, $messages);
  355.  
  356.             return $all_messages;
  357.         }
  358.  
  359.         if ( isset($this->errors[$code]) )
  360.             return $this->errors[$code];
  361.         else
  362.             return array();
  363.     }
  364.  
  365.     function get_error_message($code = '') {
  366.         if ( empty($code) )
  367.             $code = $this->get_error_code();
  368.         $messages = $this->get_error_messages($code);
  369.         if ( empty($messages) )
  370.             return '';
  371.         return $messages[0];
  372.     }
  373.  
  374.     function get_error_data($code = '') {
  375.         if ( empty($code) )
  376.             $code = $this->get_error_code();
  377.  
  378.         if ( isset($this->error_data[$code]) )
  379.             return $this->error_data[$code];
  380.         return null;
  381.     }
  382.  
  383.     function add($code, $message, $data = '') {
  384.         $this->errors[$code][] = $message;
  385.         if ( ! empty($data) )
  386.             $this->error_data[$code] = $data;
  387.     }
  388.  
  389.     function add_data($data, $code = '') {
  390.         if ( empty($code) )
  391.             $code = $this->get_error_code();
  392.  
  393.         $this->error_data[$code] = $data;
  394.     }
  395. }
  396.  
  397. function is_wp_error($thing) {
  398.     if ( is_object($thing) && is_a($thing, 'WP_Error') )
  399.         return true;
  400.     return false;
  401. }
  402.  
  403. /*
  404.  * A class for displaying various tree-like structures.
  405.  * Extend the Walker class to use it, see examples at the bottom
  406.  */
  407. class Walker {
  408.     var $tree_type;
  409.     var $db_fields;
  410.  
  411.     //abstract callbacks
  412.     function start_lvl(&$output) {}
  413.     function end_lvl(&$output)   {}
  414.     function start_el(&$output)  {}
  415.     function end_el(&$output)    {}
  416.  
  417.     /*
  418.       * display one element if the element doesn't have any children
  419.       * otherwise, display the element and its children
  420.       */
  421.     function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
  422.  
  423.         if ( !$element )
  424.             return;
  425.  
  426.         $id_field = $this->db_fields['id'];
  427.         $parent_field = $this->db_fields['parent'];
  428.  
  429.         //display this element
  430.         $cb_args = array_merge( array(&$output, $element, $depth), $args);
  431.         call_user_func_array(array(&$this, 'start_el'), $cb_args);
  432.  
  433.         if ( $max_depth == 0 ||
  434.              ($max_depth != 0 &&  $max_depth > $depth+1 )) { //whether to descend
  435.  
  436.             $num_elements = sizeof( $children_elements );
  437.             for ( $i = 0; $i < $num_elements; $i++ ) {
  438.  
  439.                 $child = $children_elements[$i];
  440.                 if ( $child->$parent_field == $element->$id_field ) {
  441.  
  442.                     if ( !isset($newlevel) ) {
  443.                         $newlevel = true;
  444.                         //start the child delimiter
  445.                         $cb_args = array_merge( array(&$output, $depth), $args);
  446.                         call_user_func_array(array(&$this, 'start_lvl'), $cb_args);
  447.                     }
  448.  
  449.                     array_splice( $children_elements, $i, 1 );
  450.                     $num_elements--;
  451.                     $this->display_element( $child, $children_elements, $max_depth, $depth + 1, $args, $output );
  452.                     $i = -1;
  453.                 }
  454.             }
  455.         }
  456.  
  457.         if ( isset($newlevel) && $newlevel ){
  458.             //end the child delimiter
  459.             $cb_args = array_merge( array(&$output, $depth), $args);
  460.             call_user_func_array(array(&$this, 'end_lvl'), $cb_args);
  461.         }
  462.  
  463.         //end this element
  464.         $cb_args = array_merge( array(&$output, $element, $depth), $args);
  465.         call_user_func_array(array(&$this, 'end_el'), $cb_args);
  466.     }
  467.  
  468.     /*
  469.      * displays array of elements hierarchically
  470.      * it is a generic function which does not assume any existing order of elements
  471.      * max_depth = -1 means flatly display every element
  472.      * max_depth = 0  means display all levels
  473.      * max_depth > 0  specifies the number of display levels.
  474.      */
  475.     function walk( $elements, $max_depth) {
  476.  
  477.         $args = array_slice(func_get_args(), 2);
  478.         $output = '';
  479.  
  480.         if ($max_depth < -1) //invalid parameter
  481.             return $output;
  482.  
  483.         if (empty($elements)) //nothing to walk
  484.             return $output;
  485.  
  486.         $id_field = $this->db_fields['id'];
  487.         $parent_field = $this->db_fields['parent'];
  488.  
  489.         // flat display
  490.         if ( -1 == $max_depth ) {
  491.             $empty_array = array();
  492.             foreach ( $elements as $e )
  493.                 $this->display_element( $e, $empty_array, 1, 0, $args, $output );
  494.             return $output;
  495.         }
  496.  
  497.         /*
  498.          * need to display in hierarchical order
  499.          * splice elements into two buckets: those without parent and those with parent
  500.          */
  501.         $top_level_elements = array();
  502.         $children_elements  = array();
  503.         foreach ( $elements as $e) {
  504.             if ( 0 == $e->$parent_field )
  505.                 $top_level_elements[] = $e;
  506.             else
  507.                 $children_elements[] = $e;
  508.         }
  509.  
  510.         /*
  511.          * none of the elements is top level
  512.          * the first one must be root of the sub elements
  513.          */
  514.         if ( !$top_level_elements ) {
  515.  
  516.             $root = $children_elements[0];
  517.             $num_elements = sizeof($children_elements);
  518.             for ( $i = 0; $i < $num_elements; $i++ ) {
  519.  
  520.                 $child = $children_elements[$i];
  521.                 if ($root->$parent_field == $child->$parent_field ) {
  522.                     $top_level_elements[] = $child;
  523.                     array_splice( $children_elements, $i, 1 );
  524.                     $num_elements--;
  525.                     $i--;
  526.                 }
  527.             }
  528.         }
  529.  
  530.         foreach ( $top_level_elements as $e )
  531.             $this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
  532.  
  533.         /*
  534.         * if we are displaying all levels, and remaining children_elements is not empty,
  535.         * then we got orphans, which should be displayed regardless
  536.          */
  537.         if ( ( $max_depth == 0 ) && sizeof( $children_elements ) > 0 ) {
  538.             $empty_array = array();
  539.             foreach ( $children_elements as $orphan_e )
  540.                 $this->display_element( $orphan_e, $empty_array, 1, 0, $args, $output );
  541.          }
  542.          return $output;
  543.     }
  544. }
  545.  
  546. class Walker_Page extends Walker {
  547.     var $tree_type = 'page';
  548.     var $db_fields = array ('parent' => 'post_parent', 'id' => 'ID'); //TODO: decouple this
  549.  
  550.     function start_lvl(&$output, $depth) {
  551.         $indent = str_repeat("\t", $depth);
  552.         $output .= "\n$indent<ul>\n";
  553.     }
  554.  
  555.     function end_lvl(&$output, $depth) {
  556.         $indent = str_repeat("\t", $depth);
  557.         $output .= "$indent</ul>\n";
  558.     }
  559.  
  560.     function start_el(&$output, $page, $depth, $current_page, $args) {
  561.         if ( $depth )
  562.             $indent = str_repeat("\t", $depth);
  563.         else
  564.             $indent = '';
  565.  
  566.         extract($args, EXTR_SKIP);
  567.         $css_class = 'page_item page-item-'.$page->ID;
  568.         if ( !empty($current_page) ) {
  569.             $_current_page = get_page( $current_page );
  570.             if ( in_array($page->ID, (array) $_current_page->ancestors) )
  571.                 $css_class .= ' current_page_ancestor';
  572.             if ( $page->ID == $current_page )
  573.                 $css_class .= ' current_page_item';
  574.             elseif ( $_current_page && $page->ID == $_current_page->post_parent )
  575.                 $css_class .= ' current_page_parent';
  576.         }
  577.  
  578.         $output .= $indent . '<li class="' . $css_class . '"><a href="' . get_page_link($page->ID) . '" title="' . attribute_escape(apply_filters('the_title', $page->post_title)) . '">' . apply_filters('the_title', $page->post_title) . '</a>';
  579.  
  580.         if ( !empty($show_date) ) {
  581.             if ( 'modified' == $show_date )
  582.                 $time = $page->post_modified;
  583.             else
  584.                 $time = $page->post_date;
  585.  
  586.             $output .= " " . mysql2date($date_format, $time);
  587.         }
  588.     }
  589.  
  590.     function end_el(&$output, $page, $depth) {
  591.         $output .= "</li>\n";
  592.     }
  593.  
  594. }
  595.  
  596. class Walker_PageDropdown extends Walker {
  597.     var $tree_type = 'page';
  598.     var $db_fields = array ('parent' => 'post_parent', 'id' => 'ID'); //TODO: decouple this
  599.  
  600.     function start_el(&$output, $page, $depth, $args) {
  601.         $pad = str_repeat(' ', $depth * 3);
  602.  
  603.         $output .= "\t<option value=\"$page->ID\"";
  604.         if ( $page->ID == $args['selected'] )
  605.             $output .= ' selected="selected"';
  606.         $output .= '>';
  607.         $title = wp_specialchars($page->post_title);
  608.         $output .= "$pad$title";
  609.         $output .= "</option>\n";
  610.     }
  611. }
  612.  
  613. class Walker_Category extends Walker {
  614.     var $tree_type = 'category';
  615.     var $db_fields = array ('parent' => 'parent', 'id' => 'term_id'); //TODO: decouple this
  616.  
  617.     function start_lvl(&$output, $depth, $args) {
  618.         if ( 'list' != $args['style'] )
  619.             return;
  620.  
  621.         $indent = str_repeat("\t", $depth);
  622.         $output .= "$indent<ul class='children'>\n";
  623.     }
  624.  
  625.     function end_lvl(&$output, $depth, $args) {
  626.         if ( 'list' != $args['style'] )
  627.             return;
  628.  
  629.         $indent = str_repeat("\t", $depth);
  630.         $output .= "$indent</ul>\n";
  631.     }
  632.  
  633.     function start_el(&$output, $category, $depth, $args) {
  634.         extract($args);
  635.  
  636.         $cat_name = attribute_escape( $category->name);
  637.         $cat_name = apply_filters( 'list_cats', $cat_name, $category );
  638.         $link = '<a href="' . get_category_link( $category->term_id ) . '" ';
  639.         if ( $use_desc_for_title == 0 || empty($category->description) )
  640.             $link .= 'title="' . sprintf(__( 'View all posts filed under %s' ), $cat_name) . '"';
  641.         else
  642.             $link .= 'title="' . attribute_escape( apply_filters( 'category_description', $category->description, $category )) . '"';
  643.         $link .= '>';
  644.         $link .= $cat_name . '</a>';
  645.  
  646.         if ( (! empty($feed_image)) || (! empty($feed)) ) {
  647.             $link .= ' ';
  648.  
  649.             if ( empty($feed_image) )
  650.                 $link .= '(';
  651.  
  652.             $link .= '<a href="' . get_category_feed_link($category->term_id, $feed_type) . '"';
  653.  
  654.             if ( empty($feed) )
  655.                 $alt = ' alt="' . sprintf(__( 'Feed for all posts filed under %s' ), $cat_name ) . '"';
  656.             else {
  657.                 $title = ' title="' . $feed . '"';
  658.                 $alt = ' alt="' . $feed . '"';
  659.                 $name = $feed;
  660.                 $link .= $title;
  661.             }
  662.  
  663.             $link .= '>';
  664.  
  665.             if ( empty($feed_image) )
  666.                 $link .= $name;
  667.             else
  668.                 $link .= "<img src='$feed_image'$alt$title" . ' />';
  669.             $link .= '</a>';
  670.             if ( empty($feed_image) )
  671.                 $link .= ')';
  672.         }
  673.  
  674.         if ( isset($show_count) && $show_count )
  675.             $link .= ' (' . intval($category->count) . ')';
  676.  
  677.         if ( isset($show_date) && $show_date ) {
  678.             $link .= ' ' . gmdate('Y-m-d', $category->last_update_timestamp);
  679.         }
  680.  
  681.         if ( isset($current_category) && $current_category )
  682.             $_current_category = get_category( $current_category );
  683.  
  684.         if ( 'list' == $args['style'] ) {
  685.             $output .= "\t<li";
  686.             $class = 'cat-item cat-item-'.$category->term_id;
  687.             if ( isset($current_category) && $current_category && ($category->term_id == $current_category) )
  688.                 $class .=  ' current-cat';
  689.             elseif ( isset($_current_category) && $_current_category && ($category->term_id == $_current_category->parent) )
  690.                 $class .=  ' current-cat-parent';
  691.             $output .=  ' class="'.$class.'"';
  692.             $output .= ">$link\n";
  693.         } else {
  694.             $output .= "\t$link<br />\n";
  695.         }
  696.     }
  697.  
  698.     function end_el(&$output, $page, $depth, $args) {
  699.         if ( 'list' != $args['style'] )
  700.             return;
  701.  
  702.         $output .= "</li>\n";
  703.     }
  704.  
  705. }
  706.  
  707. class Walker_CategoryDropdown extends Walker {
  708.     var $tree_type = 'category';
  709.     var $db_fields = array ('parent' => 'parent', 'id' => 'term_id'); //TODO: decouple this
  710.  
  711.     function start_el(&$output, $category, $depth, $args) {
  712.         $pad = str_repeat(' ', $depth * 3);
  713.  
  714.         $cat_name = apply_filters('list_cats', $category->name, $category);
  715.         $output .= "\t<option value=\"".$category->term_id."\"";
  716.         if ( $category->term_id == $args['selected'] )
  717.             $output .= ' selected="selected"';
  718.         $output .= '>';
  719.         $output .= $pad.$cat_name;
  720.         if ( $args['show_count'] )
  721.             $output .= '  ('. $category->count .')';
  722.         if ( $args['show_last_update'] ) {
  723.             $format = 'Y-m-d';
  724.             $output .= '  ' . gmdate($format, $category->last_update_timestamp);
  725.         }
  726.         $output .= "</option>\n";
  727.     }
  728. }
  729.  
  730. class WP_Ajax_Response {
  731.     var $responses = array();
  732.  
  733.     function WP_Ajax_Response( $args = '' ) {
  734.         if ( !empty($args) )
  735.             $this->add($args);
  736.     }
  737.  
  738.     // a WP_Error object can be passed in 'id' or 'data'
  739.     function add( $args = '' ) {
  740.         $defaults = array(
  741.             'what' => 'object', 'action' => false,
  742.             'id' => '0', 'old_id' => false,
  743.             'position' => 1, // -1 = top, 1 = bottom, html ID = after, -html ID = before
  744.             'data' => '', 'supplemental' => array()
  745.         );
  746.  
  747.         $r = wp_parse_args( $args, $defaults );
  748.         extract( $r, EXTR_SKIP );
  749.         $position = preg_replace( '/[^a-z0-9:_-]/i', '', $position );
  750.  
  751.         if ( is_wp_error($id) ) {
  752.             $data = $id;
  753.             $id = 0;
  754.         }
  755.  
  756.         $response = '';
  757.         if ( is_wp_error($data) ) {
  758.             foreach ( $data->get_error_codes() as $code ) {
  759.                 $response .= "<wp_error code='$code'><![CDATA[" . $data->get_error_message($code) . "]]></wp_error>";
  760.                 if ( !$error_data = $data->get_error_data($code) )
  761.                     continue;
  762.                 $class = '';
  763.                 if ( is_object($error_data) ) {
  764.                     $class = ' class="' . get_class($error_data) . '"';
  765.                     $error_data = get_object_vars($error_data);
  766.                 }
  767.  
  768.                 $response .= "<wp_error_data code='$code'$class>";
  769.  
  770.                 if ( is_scalar($error_data) ) {
  771.                     $response .= "<![CDATA[$error_data]]>";
  772.                 } elseif ( is_array($error_data) ) {
  773.                     foreach ( $error_data as $k => $v )
  774.                         $response .= "<$k><![CDATA[$v]]></$k>";
  775.                 }
  776.  
  777.                 $response .= "</wp_error_data>";
  778.             }
  779.         } else {
  780.             $response = "<response_data><![CDATA[$data]]></response_data>";
  781.         }
  782.  
  783.         $s = '';
  784.         if ( (array) $supplemental ) {
  785.             foreach ( $supplemental as $k => $v )
  786.                 $s .= "<$k><![CDATA[$v]]></$k>";
  787.             $s = "<supplemental>$s</supplemental>";
  788.         }
  789.  
  790.         if ( false === $action )
  791.             $action = $_POST['action'];
  792.  
  793.         $x = '';
  794.         $x .= "<response action='{$action}_$id'>"; // The action attribute in the xml output is formatted like a nonce action
  795.         $x .=    "<$what id='$id' " . ( false === $old_id ? '' : "old_id='$old_id' " ) . "position='$position'>";
  796.         $x .=        $response;
  797.         $x .=        $s;
  798.         $x .=    "</$what>";
  799.         $x .= "</response>";
  800.  
  801.         $this->responses[] = $x;
  802.         return $x;
  803.     }
  804.  
  805.     function send() {
  806.         header('Content-Type: text/xml');
  807.         echo "<?xml version='1.0' standalone='yes'?><wp_ajax>";
  808.         foreach ( $this->responses as $response )
  809.             echo $response;
  810.         echo '</wp_ajax>';
  811.         die();
  812.     }
  813. }
  814.  
  815. ?>
  816.