]> scripts.mit.edu Git - autoinstalls/wordpress.git/blobdiff - wp-includes/classes.php
Wordpress 2.5.1
[autoinstalls/wordpress.git] / wp-includes / classes.php
index 6e55c45fef0ee5eb6067d41248d4c88fec225d19..0d866faac973491279bd707331e5e63481ff5466 100644 (file)
@@ -1,9 +1,9 @@
 <?php
 
 class WP {
-       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');
+       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');
 
-       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');
+       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');
        var $extra_query_vars = array();
 
        var $query_vars;
@@ -14,7 +14,8 @@ class WP {
        var $did_permalink = false;
 
        function add_query_var($qv) {
-               $this->public_query_vars[] = $qv;
+               if ( !in_array($qv, $this->public_query_vars) )
+                       $this->public_query_vars[] = $qv;
        }
 
        function set_query_var($key, $value) {
@@ -71,7 +72,6 @@ class WP {
                        $pathinfo = trim($pathinfo, '/');
                        $self = trim($self, '/');
                        $self = preg_replace("|^$home_path|", '', $self);
-                       $self = str_replace($home_path, '', $self);
                        $self = trim($self, '/');
 
                        // The requested permalink is in $pathinfo for path info requests and
@@ -185,14 +185,14 @@ class WP {
                        @header('Content-Type: ' . get_option('html_type') . '; charset=' . get_option('blog_charset'));
                } else {
                        // We're showing a feed, so WP is indeed the only thing that last changed
-                       if ( $this->query_vars['withcomments']
-                               || ( !$this->query_vars['withoutcomments']
-                                       && ( $this->query_vars['p']
-                                               || $this->query_vars['name']
-                                               || $this->query_vars['page_id']
-                                               || $this->query_vars['pagename']
-                                               || $this->query_vars['attachment']
-                                               || $this->query_vars['attachment_id']
+                       if ( !empty($this->query_vars['withcomments'])
+                               || ( empty($this->query_vars['withoutcomments'])
+                                       && ( !empty($this->query_vars['p'])
+                                               || !empty($this->query_vars['name'])
+                                               || !empty($this->query_vars['page_id'])
+                                               || !empty($this->query_vars['pagename'])
+                                               || !empty($this->query_vars['attachment'])
+                                               || !empty($this->query_vars['attachment_id'])
                                        )
                                )
                        )
@@ -208,7 +208,7 @@ class WP {
                                $client_etag = stripslashes(stripslashes($_SERVER['HTTP_IF_NONE_MATCH']));
                        else $client_etag = false;
 
-                       $client_last_modified = trim( $_SERVER['HTTP_IF_MODIFIED_SINCE']);
+                       $client_last_modified = empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? '' : trim($_SERVER['HTTP_IF_MODIFIED_SINCE']);
                        // If string is empty, return 0. If not, attempt to parse into a timestamp
                        $client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;
 
@@ -238,8 +238,7 @@ class WP {
                }
 
                // query_string filter deprecated.  Use request filter instead.
-               global $wp_filter;
-               if ( isset($wp_filter['query_string']) ) {  // Don't bother filtering and parsing if no plugins are hooked in.
+               if ( has_filter('query_string') ) {  // Don't bother filtering and parsing if no plugins are hooked in.
                        $this->query_string = apply_filters('query_string', $this->query_string);
                        parse_str($this->query_string, $this->query_vars);
                }
@@ -387,107 +386,142 @@ function is_wp_error($thing) {
        return false;
 }
 
-
-// A class for displaying various tree-like structures. Extend the Walker class to use it, see examples at the bottom
-
+/*
+ * A class for displaying various tree-like structures.
+ * Extend the Walker class to use it, see examples at the bottom
+ */
 class Walker {
        var $tree_type;
        var $db_fields;
 
        //abstract callbacks
-       function start_lvl($output) { return $output; }
-       function end_lvl($output)   { return $output; }
-       function start_el($output)  { return $output; }
-       function end_el($output)    { return $output; }
-
-       function walk($elements, $to_depth) {
-               $args = array_slice(func_get_args(), 2); $parents = array(); $depth = 1; $previous_element = ''; $output = '';
-
-               //padding at the end
-               $last_element->post_parent = 0;
-               $last_element->post_id = 0;
-               $elements[] = $last_element;
+       function start_lvl(&$output) {}
+       function end_lvl(&$output)   {}
+       function start_el(&$output)  {}
+       function end_el(&$output)    {}
+
+       /*
+        * display one element if the element doesn't have any children
+        * otherwise, display the element and its children
+        */
+       function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
+
+               if ( !$element )
+                       return;
 
                $id_field = $this->db_fields['id'];
                $parent_field = $this->db_fields['parent'];
 
-               $flat = ($to_depth == -1) ? true : false;
+               //display this element
+               $cb_args = array_merge( array(&$output, $element, $depth), $args);
+               call_user_func_array(array(&$this, 'start_el'), $cb_args);
 
-               foreach ( $elements as $element ) {
-                       // If flat, start and end the element and skip the level checks.
-                       if ( $flat) {
-                               // Start the element.
-                               if ( isset($element->$id_field) && $element->$id_field != 0 ) {
-                                       $cb_args = array_merge( array($output, $element, $depth - 1), $args);
-                                       $output = call_user_func_array(array(&$this, 'start_el'), $cb_args);
-                               }
+               if ( $max_depth == 0 ||
+                    ($max_depth != 0 &&  $max_depth > $depth+1 )) { //whether to descend
 
-                               // End the element.
-                               if ( isset($element->$id_field) && $element->$id_field != 0 ) {
-                                       $cb_args = array_merge( array($output, $element, $depth - 1), $args);
-                                       $output = call_user_func_array(array(&$this, 'end_el'), $cb_args);
-                               }
+                       for ( $i = 0; $i < sizeof( $children_elements ); $i++ ) {
 
-                               continue;
-                       }
+                               $child = $children_elements[$i];
+                               if ( $child->$parent_field == $element->$id_field ) {
 
-                       // Walk the tree.
-                       if ( !empty($previous_element) && ($element->$parent_field == $previous_element->$id_field) ) {
-                               // Previous element is my parent. Descend a level.
-                               array_unshift($parents, $previous_element);
-                               if ( !$to_depth || ($depth < $to_depth) ) { //only descend if we're below $to_depth
-                                       $cb_args = array_merge( array($output, $depth), $args);
-                                       $output = call_user_func_array(array(&$this, 'start_lvl'), $cb_args);
-                               } else if ( $to_depth && $depth == $to_depth  ) {  // If we've reached depth, end the previous element.
-                                       $cb_args = array_merge( array($output, $previous_element, $depth), $args);
-                                       $output = call_user_func_array(array(&$this, 'end_el'), $cb_args);
-                               }
-                               $depth++; //always do this so when we start the element further down, we know where we are
-                       } else if ( $element->$parent_field == $previous_element->$parent_field) {
-                               // On the same level as previous element.
-                               if ( !$to_depth || ($depth <= $to_depth) ) {
-                                       $cb_args = array_merge( array($output, $previous_element, $depth - 1), $args);
-                                       $output = call_user_func_array(array(&$this, 'end_el'), $cb_args);
-                               }
-                       } else if ( $depth > 1 ) {
-                               // Ascend one or more levels.
-                               if ( !$to_depth || ($depth <= $to_depth) ) {
-                                       $cb_args = array_merge( array($output, $previous_element, $depth - 1), $args);
-                                       $output = call_user_func_array(array(&$this, 'end_el'), $cb_args);
-                               }
-
-                               while ( $parent = array_shift($parents) ) {
-                                       $depth--;
-                                       if ( !$to_depth || ($depth < $to_depth) ) {
-                                               $cb_args = array_merge( array($output, $depth), $args);
-                                               $output = call_user_func_array(array(&$this, 'end_lvl'), $cb_args);
-                                               $cb_args = array_merge( array($output, $parent, $depth - 1), $args);
-                                               $output = call_user_func_array(array(&$this, 'end_el'), $cb_args);
-                                       }
-                                       if ( $element->$parent_field == $parents[0]->$id_field ) {
-                                               break;
+                                       if ( !isset($newlevel) ) {
+                                               $newlevel = true;
+                                               //start the child delimiter
+                                               $cb_args = array_merge( array(&$output, $depth), $args);
+                                               call_user_func_array(array(&$this, 'start_lvl'), $cb_args);
                                        }
-                               }
-                       } else if ( !empty($previous_element) ) {
-                               // Close off previous element.
-                               if ( !$to_depth || ($depth <= $to_depth) ) {
-                                       $cb_args = array_merge( array($output, $previous_element, $depth - 1), $args);
-                                       $output = call_user_func_array(array(&$this, 'end_el'), $cb_args);
+
+                                       array_splice( $children_elements, $i, 1 );
+                                       $this->display_element( $child, $children_elements, $max_depth, $depth + 1, $args, $output );
+                                       $i = -1;
                                }
                        }
+               }
+
+               if ( isset($newlevel) && $newlevel ){
+                       //end the child delimiter
+                       $cb_args = array_merge( array(&$output, $depth), $args);
+                       call_user_func_array(array(&$this, 'end_lvl'), $cb_args);
+               }
+
+               //end this element
+               $cb_args = array_merge( array(&$output, $element, $depth), $args);
+               call_user_func_array(array(&$this, 'end_el'), $cb_args);
+       }
+
+       /*
+       * displays array of elements hierarchically
+       * it is a generic function which does not assume any existing order of elements
+       * max_depth = -1 means flatly display every element
+       * max_depth = 0  means display all levels
+       * max_depth > 0  specifies the number of display levels.
+       */
+       function walk( $elements, $max_depth) {
+
+               $args = array_slice(func_get_args(), 2);
+               $output = '';
+
+               if ($max_depth < -1) //invalid parameter
+                       return $output;
+
+               if (empty($elements)) //nothing to walk
+                       return $output;
+
+               $id_field = $this->db_fields['id'];
+               $parent_field = $this->db_fields['parent'];
+
+               // flat display
+               if ( -1 == $max_depth ) {
+                       $empty_array = array();
+                       foreach ( $elements as $e )
+                               $this->display_element( $e, $empty_array, 1, 0, $args, $output );
+                       return $output;
+               }
+
+               /*
+                * need to display in hierarchical order
+                * splice elements into two buckets: those without parent and those with parent
+                */
+               $top_level_elements = array();
+               $children_elements  = array();
+               foreach ( $elements as $e) {
+                       if ( 0 == $e->$parent_field )
+                               $top_level_elements[] = $e;
+                       else
+                               $children_elements[] = $e;
+               }
+
+               /*
+                * none of the elements is top level
+                * the first one must be root of the sub elements
+                */
+               if ( !$top_level_elements ) {
+
+                       $root = $children_elements[0];
+                       for ( $i = 0; $i < sizeof( $children_elements ); $i++ ) {
 
-                       // Start the element.
-                       if ( !$to_depth || ($depth <= $to_depth) ) {
-                               if ( $element->$id_field != 0 ) {
-                                       $cb_args = array_merge( array($output, $element, $depth - 1), $args);
-                                       $output = call_user_func_array(array(&$this, 'start_el'), $cb_args);
+                               $child = $children_elements[$i];
+                               if ($root->$parent_field == $child->$parent_field ) {
+                                       $top_level_elements[] = $child;
+                                       array_splice( $children_elements, $i, 1 );
+                                       $i--;
                                }
                        }
-
-                       $previous_element = $element;
                }
 
-               return $output;
+               foreach ( $top_level_elements as $e )
+                       $this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
+
+               /*
+               * if we are displaying all levels, and remaining children_elements is not empty,
+               * then we got orphans, which should be displayed regardless
+               */
+               if ( ( $max_depth == 0 ) && sizeof( $children_elements ) > 0 ) {
+                       $empty_array = array();
+                       foreach ( $children_elements as $orphan_e )
+                               $this->display_element( $orphan_e, $empty_array, 1, 0, $args, $output );
+                }
+                return $output;
        }
 }
 
@@ -495,28 +529,33 @@ class Walker_Page extends Walker {
        var $tree_type = 'page';
        var $db_fields = array ('parent' => 'post_parent', 'id' => 'ID'); //TODO: decouple this
 
-       function start_lvl($output, $depth) {
+       function start_lvl(&$output, $depth) {
                $indent = str_repeat("\t", $depth);
                $output .= "\n$indent<ul>\n";
-               return $output;
        }
 
-       function end_lvl($output, $depth) {
+       function end_lvl(&$output, $depth) {
                $indent = str_repeat("\t", $depth);
                $output .= "$indent</ul>\n";
-               return $output;
        }
 
-       function start_el($output, $page, $depth, $current_page, $args) {
+       function start_el(&$output, $page, $depth, $current_page, $args) {
                if ( $depth )
                        $indent = str_repeat("\t", $depth);
+               else
+                       $indent = '';
+
                extract($args, EXTR_SKIP);
                $css_class = 'page_item page-item-'.$page->ID;
-               $_current_page = get_page( $current_page );
-               if ( $page->ID == $current_page )
-                       $css_class .= ' current_page_item ';
-               elseif ( $_current_page && $page->ID == $_current_page->post_parent )
-                       $css_class .= ' current_page_parent';
+               if ( !empty($current_page) ) {
+                       $_current_page = get_page( $current_page );
+                       if ( in_array($page->ID, (array) $_current_page->ancestors) )
+                               $css_class .= ' current_page_ancestor';
+                       if ( $page->ID == $current_page )
+                               $css_class .= ' current_page_item';
+                       elseif ( $_current_page && $page->ID == $_current_page->post_parent )
+                               $css_class .= ' current_page_parent';
+               }
 
                $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>';
 
@@ -528,14 +567,10 @@ class Walker_Page extends Walker {
 
                        $output .= " " . mysql2date($date_format, $time);
                }
-
-               return $output;
        }
 
-       function end_el($output, $page, $depth) {
+       function end_el(&$output, $page, $depth) {
                $output .= "</li>\n";
-
-               return $output;
        }
 
 }
@@ -544,18 +579,16 @@ class Walker_PageDropdown extends Walker {
        var $tree_type = 'page';
        var $db_fields = array ('parent' => 'post_parent', 'id' => 'ID'); //TODO: decouple this
 
-       function start_el($output, $page, $depth, $args) {
-                               $pad = str_repeat('&nbsp;', $depth * 3);
-
-                               $output .= "\t<option value=\"$page->ID\"";
-                               if ( $page->ID == $args['selected'] )
-                                                               $output .= ' selected="selected"';
-                               $output .= '>';
-                               $title = wp_specialchars($page->post_title);
-                               $output .= "$pad$title";
-                               $output .= "</option>\n";
+       function start_el(&$output, $page, $depth, $args) {
+               $pad = str_repeat('&nbsp;', $depth * 3);
 
-                               return $output;
+               $output .= "\t<option value=\"$page->ID\"";
+               if ( $page->ID == $args['selected'] )
+                       $output .= ' selected="selected"';
+               $output .= '>';
+               $title = wp_specialchars($page->post_title);
+               $output .= "$pad$title";
+               $output .= "</option>\n";
        }
 }
 
@@ -563,25 +596,23 @@ class Walker_Category extends Walker {
        var $tree_type = 'category';
        var $db_fields = array ('parent' => 'parent', 'id' => 'term_id'); //TODO: decouple this
 
-       function start_lvl($output, $depth, $args) {
+       function start_lvl(&$output, $depth, $args) {
                if ( 'list' != $args['style'] )
-                       return $output;
+                       return;
 
                $indent = str_repeat("\t", $depth);
                $output .= "$indent<ul class='children'>\n";
-               return $output;
        }
 
-       function end_lvl($output, $depth, $args) {
+       function end_lvl(&$output, $depth, $args) {
                if ( 'list' != $args['style'] )
-                       return $output;
+                       return;
 
                $indent = str_repeat("\t", $depth);
                $output .= "$indent</ul>\n";
-               return $output;
        }
 
-       function start_el($output, $category, $depth, $args) {
+       function start_el(&$output, $category, $depth, $args) {
                extract($args);
 
                $cat_name = attribute_escape( $category->name);
@@ -600,7 +631,7 @@ class Walker_Category extends Walker {
                        if ( empty($feed_image) )
                                $link .= '(';
 
-                       $link .= '<a href="' . get_category_rss_link( 0, $category->term_id, $category->slug ) . '"';
+                       $link .= '<a href="' . get_category_feed_link($category->term_id, $feed_type) . '"';
 
                        if ( empty($feed) )
                                $alt = ' alt="' . sprintf(__( 'Feed for all posts filed under %s' ), $cat_name ) . '"';
@@ -629,31 +660,28 @@ class Walker_Category extends Walker {
                        $link .= ' ' . gmdate('Y-m-d', $category->last_update_timestamp);
                }
 
-               if ( $current_category )
+               if ( isset($current_category) && $current_category )
                        $_current_category = get_category( $current_category );
 
                if ( 'list' == $args['style'] ) {
                        $output .= "\t<li";
                        $class = 'cat-item cat-item-'.$category->term_id;
-                       if ( $current_category && ($category->term_id == $current_category) )
+                       if ( isset($current_category) && $current_category && ($category->term_id == $current_category) )
                                $class .=  ' current-cat';
-                       elseif ( $_current_category && ($category->term_id == $_current_category->parent) )
+                       elseif ( isset($_current_category) && $_current_category && ($category->term_id == $_current_category->parent) )
                                $class .=  ' current-cat-parent';
                        $output .=  ' class="'.$class.'"';
                        $output .= ">$link\n";
                } else {
                        $output .= "\t$link<br />\n";
                }
-
-               return $output;
        }
 
-       function end_el($output, $page, $depth, $args) {
+       function end_el(&$output, $page, $depth, $args) {
                if ( 'list' != $args['style'] )
-                       return $output;
+                       return;
 
                $output .= "</li>\n";
-               return $output;
        }
 
 }
@@ -662,7 +690,7 @@ class Walker_CategoryDropdown extends Walker {
        var $tree_type = 'category';
        var $db_fields = array ('parent' => 'parent', 'id' => 'term_id'); //TODO: decouple this
 
-       function start_el($output, $category, $depth, $args) {
+       function start_el(&$output, $category, $depth, $args) {
                $pad = str_repeat('&nbsp;', $depth * 3);
 
                $cat_name = apply_filters('list_cats', $category->name, $category);
@@ -678,8 +706,6 @@ class Walker_CategoryDropdown extends Walker {
                        $output .= '&nbsp;&nbsp;' . gmdate($format, $category->last_update_timestamp);
                }
                $output .= "</option>\n";
-
-               return $output;
        }
 }
 
@@ -696,11 +722,13 @@ class WP_Ajax_Response {
                $defaults = array(
                        'what' => 'object', 'action' => false,
                        'id' => '0', 'old_id' => false,
+                       'position' => 1, // -1 = top, 1 = bottom, html ID = after, -html ID = before
                        'data' => '', 'supplemental' => array()
                );
 
                $r = wp_parse_args( $args, $defaults );
                extract( $r, EXTR_SKIP );
+               $position = preg_replace( '/[^a-z0-9:_-]/i', '', $position );
 
                if ( is_wp_error($id) ) {
                        $data = $id;
@@ -708,23 +736,45 @@ class WP_Ajax_Response {
                }
 
                $response = '';
-               if ( is_wp_error($data) )
-                       foreach ( $data->get_error_codes() as $code )
+               if ( is_wp_error($data) ) {
+                       foreach ( $data->get_error_codes() as $code ) {
                                $response .= "<wp_error code='$code'><![CDATA[" . $data->get_error_message($code) . "]]></wp_error>";
-               else
+                               if ( !$error_data = $data->get_error_data($code) )
+                                       continue;
+                               $class = '';
+                               if ( is_object($error_data) ) {
+                                       $class = ' class="' . get_class($error_data) . '"';
+                                       $error_data = get_object_vars($error_data);
+                               }
+
+                               $response .= "<wp_error_data code='$code'$class>";
+
+                               if ( is_scalar($error_data) ) {
+                                       $response .= "<![CDATA[$error_data]]>";
+                               } elseif ( is_array($error_data) ) {
+                                       foreach ( $error_data as $k => $v )
+                                               $response .= "<$k><![CDATA[$v]]></$k>";
+                               }
+
+                               $response .= "</wp_error_data>";
+                       }
+               } else {
                        $response = "<response_data><![CDATA[$data]]></response_data>";
+               }
 
                $s = '';
-               if ( (array) $supplemental )
+               if ( (array) $supplemental ) {
                        foreach ( $supplemental as $k => $v )
                                $s .= "<$k><![CDATA[$v]]></$k>";
+                       $s = "<supplemental>$s</supplemental>";
+               }
 
                if ( false === $action )
                        $action = $_POST['action'];
 
                $x = '';
                $x .= "<response action='{$action}_$id'>"; // The action attribute in the xml output is formatted like a nonce action
-               $x .=   "<$what id='$id'" . ( false !== $old_id ? "old_id='$old_id'>" : '>' );
+               $x .=   "<$what id='$id' " . ( false === $old_id ? '' : "old_id='$old_id' " ) . "position='$position'>";
                $x .=           $response;
                $x .=           $s;
                $x .=   "</$what>";