<?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;
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) {
global $wp_rewrite;
$this->query_vars = array();
+ $taxonomy_query_vars = array();
if ( is_array($extra_query_vars) )
$this->extra_query_vars = & $extra_query_vars;
$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
// Look for matches.
$request_match = $request;
foreach ($rewrite as $match => $query) {
+ // Don't try to match against AtomPub calls
+ if ( $req_uri == 'wp-app.php' )
+ break;
+
// If the requesting file is the anchor of the match, prepend it
// to the path info.
if ((! empty($req_uri)) && (strpos($match, $req_uri) === 0) && ($req_uri != $request)) {
$query = preg_replace("!^.+\?!", '', $query);
// Substitute the substring matches into the query.
- eval("\$query = \"$query\";");
+ eval("\$query = \"" . addslashes($query) . "\";");
$this->matched_query = $query;
// Parse the query.
$this->public_query_vars = apply_filters('query_vars', $this->public_query_vars);
+ foreach ( $GLOBALS['wp_taxonomies'] as $taxonomy => $t )
+ if ( isset($t->query_var) )
+ $taxonomy_query_vars[$t->query_var] = $taxonomy;
+
for ($i=0; $i<count($this->public_query_vars); $i += 1) {
$wpvar = $this->public_query_vars[$i];
if (isset($this->extra_query_vars[$wpvar]))
elseif (!empty($perma_query_vars[$wpvar]))
$this->query_vars[$wpvar] = $perma_query_vars[$wpvar];
- if ( !empty( $this->query_vars[$wpvar] ) )
+ if ( !empty( $this->query_vars[$wpvar] ) ) {
$this->query_vars[$wpvar] = (string) $this->query_vars[$wpvar];
+ if ( in_array( $wpvar, $taxonomy_query_vars ) ) {
+ $this->query_vars['taxonomy'] = $taxonomy_query_vars[$wpvar];
+ $this->query_vars['term'] = $this->query_vars[$wpvar];
+ }
+ }
}
foreach ($this->private_query_vars as $var) {
@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'])
)
)
)
$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;
}
// 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);
}
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);
- }
+ $num_elements = sizeof( $children_elements );
+ for ( $i = 0; $i < $num_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 );
+ $num_elements--;
+ $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 = '';
- // 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);
+ 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];
+ $num_elements = sizeof($children_elements);
+ for ( $i = 0; $i < $num_elements; $i++ ) {
+
+ $child = $children_elements[$i];
+ if ($root->$parent_field == $child->$parent_field ) {
+ $top_level_elements[] = $child;
+ array_splice( $children_elements, $i, 1 );
+ $num_elements--;
+ $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;
}
}
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>';
$output .= " " . mysql2date($date_format, $time);
}
-
- return $output;
}
- function end_el($output, $page, $depth) {
+ function end_el(&$output, $page, $depth) {
$output .= "</li>\n";
-
- return $output;
}
}
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(' ', $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(' ', $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";
}
}
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);
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 ) . '"';
$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;
}
}
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(' ', $depth * 3);
$cat_name = apply_filters('list_cats', $category->name, $category);
$output .= ' ' . gmdate($format, $category->last_update_timestamp);
}
$output .= "</option>\n";
-
- return $output;
}
}
$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;
}
$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>";