';
-
- return $head . $body . $foot;
- } // End function display_edit_form
-
-}
-
-class WP_Rewrite {
- var $permalink_structure;
- var $category_base;
- var $category_structure;
- var $author_base = 'author';
- var $author_structure;
- var $date_structure;
- var $page_structure;
- var $search_base = 'search';
- var $search_structure;
- var $comments_base = 'comments';
- var $feed_base = 'feed';
- var $comments_feed_structure;
- var $feed_structure;
- var $front;
- var $root = '';
- var $index = 'index.php';
- var $matches = '';
- var $rules;
- var $use_verbose_rules = false;
- var $rewritecode =
- array(
- '%year%',
- '%monthnum%',
- '%day%',
- '%hour%',
- '%minute%',
- '%second%',
- '%postname%',
- '%post_id%',
- '%category%',
- '%author%',
- '%pagename%',
- '%search%'
- );
-
- var $rewritereplace =
- array(
- '([0-9]{4})',
- '([0-9]{1,2})',
- '([0-9]{1,2})',
- '([0-9]{1,2})',
- '([0-9]{1,2})',
- '([0-9]{1,2})',
- '([^/]+)',
- '([0-9]+)',
- '(.+?)',
- '([^/]+)',
- '([^/]+)',
- '(.+)'
- );
-
- var $queryreplace =
- array (
- 'year=',
- 'monthnum=',
- 'day=',
- 'hour=',
- 'minute=',
- 'second=',
- 'name=',
- 'p=',
- 'category_name=',
- 'author_name=',
- 'pagename=',
- 's='
- );
-
- var $feeds = array ('feed', 'rdf', 'rss', 'rss2', 'atom');
-
- function using_permalinks() {
- if (empty($this->permalink_structure))
- return false;
- else
- return true;
- }
-
- function using_index_permalinks() {
- if (empty($this->permalink_structure)) {
- return false;
- }
-
- // If the index is not in the permalink, we're using mod_rewrite.
- if (preg_match('#^/*' . $this->index . '#', $this->permalink_structure)) {
- return true;
- }
-
- return false;
}
- function using_mod_rewrite_permalinks() {
- if ( $this->using_permalinks() && ! $this->using_index_permalinks())
- return true;
- else
- return false;
- }
-
- function preg_index($number) {
- $match_prefix = '$';
- $match_suffix = '';
-
- if (! empty($this->matches)) {
- $match_prefix = '$' . $this->matches . '[';
- $match_suffix = ']';
- }
-
- return "$match_prefix$number$match_suffix";
+ /**
+ * Sets up all of the variables required by the WordPress environment.
+ *
+ * The action 'wp' has one parameter that references the WP object. It
+ * allows for accessing the properties and methods to further manipulate the
+ * object.
+ *
+ * @since 2.0.0
+ *
+ * @param string|array $query_args Passed to {@link parse_request()}
+ */
+ function main($query_args = '') {
+ $this->init();
+ $this->parse_request($query_args);
+ $this->send_headers();
+ $this->query_posts();
+ $this->handle_404();
+ $this->register_globals();
+ do_action_ref_array('wp', array(&$this));
}
- function page_rewrite_rules() {
- $uris = get_settings('page_uris');
- $attachment_uris = get_settings('page_attachment_uris');
-
- $rewrite_rules = array();
- $page_structure = $this->get_page_permastruct();
- if( is_array( $attachment_uris ) ) {
- foreach ($attachment_uris as $uri => $pagename) {
- $this->add_rewrite_tag('%pagename%', "($uri)", 'attachment=');
- $rewrite_rules = array_merge($rewrite_rules, $this->generate_rewrite_rules($page_structure));
- }
- }
- if( is_array( $uris ) ) {
- foreach ($uris as $uri => $pagename) {
- $this->add_rewrite_tag('%pagename%', "($uri)", 'pagename=');
- $rewrite_rules = array_merge($rewrite_rules, $this->generate_rewrite_rules($page_structure));
- }
- }
-
- return $rewrite_rules;
+ /**
+ * PHP4 Constructor - Does nothing.
+ *
+ * Call main() method when ready to run setup.
+ *
+ * @since 2.0.0
+ *
+ * @return WP
+ */
+ function WP() {
+ // Empty.
}
+}
- function get_date_permastruct() {
- if (isset($this->date_structure)) {
- return $this->date_structure;
- }
-
- if (empty($this->permalink_structure)) {
- $this->date_structure = '';
- return false;
- }
-
- // The date permalink must have year, month, and day separated by slashes.
- $endians = array('%year%/%monthnum%/%day%', '%day%/%monthnum%/%year%', '%monthnum%/%day%/%year%');
-
- $this->date_structure = '';
- $date_endian = '';
-
- foreach ($endians as $endian) {
- if (false !== strpos($this->permalink_structure, $endian)) {
- $date_endian= $endian;
- break;
- }
- }
-
- if ( empty($date_endian) )
- $date_endian = '%year%/%monthnum%/%day%';
-
- // Do not allow the date tags and %post_id% to overlap in the permalink
- // structure. If they do, move the date tags to $front/date/.
- $front = $this->front;
- preg_match_all('/%.+?%/', $this->permalink_structure, $tokens);
- $tok_index = 1;
- foreach ($tokens[0] as $token) {
- if ( ($token == '%post_id%') && ($tok_index <= 3) ) {
- $front = $front . 'date/';
- break;
- }
- $tok_index++;
- }
+/**
+ * WordPress Error class.
+ *
+ * Container for checking for WordPress errors and error messages. Return
+ * WP_Error and use {@link is_wp_error()} to check if this class is returned.
+ * Many core WordPress functions pass this class in the event of an error and
+ * if not handled properly will result in code errors.
+ *
+ * @package WordPress
+ * @since 2.1.0
+ */
+class WP_Error {
+ /**
+ * Stores the list of errors.
+ *
+ * @since 2.1.0
+ * @var array
+ * @access private
+ */
+ var $errors = array();
+
+ /**
+ * Stores the list of data for error codes.
+ *
+ * @since 2.1.0
+ * @var array
+ * @access private
+ */
+ var $error_data = array();
+
+ /**
+ * PHP4 Constructor - Sets up error message.
+ *
+ * If code parameter is empty then nothing will be done. It is possible to
+ * add multiple messages to the same code, but with other methods in the
+ * class.
+ *
+ * All parameters are optional, but if the code parameter is set, then the
+ * data parameter is optional.
+ *
+ * @since 2.1.0
+ *
+ * @param string|int $code Error code
+ * @param string $message Error message
+ * @param mixed $data Optional. Error data.
+ * @return WP_Error
+ */
+ function WP_Error($code = '', $message = '', $data = '') {
+ if ( empty($code) )
+ return;
- $this->date_structure = $front . $date_endian;
+ $this->errors[$code][] = $message;
- return $this->date_structure;
+ if ( ! empty($data) )
+ $this->error_data[$code] = $data;
}
- function get_year_permastruct() {
- $structure = $this->get_date_permastruct($this->permalink_structure);
-
- if (empty($structure)) {
- return false;
- }
-
- $structure = str_replace('%monthnum%', '', $structure);
- $structure = str_replace('%day%', '', $structure);
-
- $structure = preg_replace('#/+#', '/', $structure);
+ /**
+ * Retrieve all error codes.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @return array List of error codes, if avaiable.
+ */
+ function get_error_codes() {
+ if ( empty($this->errors) )
+ return array();
- return $structure;
+ return array_keys($this->errors);
}
- function get_month_permastruct() {
- $structure = $this->get_date_permastruct($this->permalink_structure);
-
- if (empty($structure)) {
- return false;
- }
-
- $structure = str_replace('%day%', '', $structure);
-
- $structure = preg_replace('#/+#', '/', $structure);
+ /**
+ * Retrieve first error code available.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @return string|int Empty string, if no error codes.
+ */
+ function get_error_code() {
+ $codes = $this->get_error_codes();
- return $structure;
- }
+ if ( empty($codes) )
+ return '';
- function get_day_permastruct() {
- return $this->get_date_permastruct($this->permalink_structure);
+ return $codes[0];
}
- function get_category_permastruct() {
- if (isset($this->category_structure)) {
- return $this->category_structure;
- }
+ /**
+ * Retrieve all error messages or error messages matching code.
+ *
+ * @since 2.1.0
+ *
+ * @param string|int $code Optional. Retrieve messages matching code, if exists.
+ * @return array Error strings on success, or empty array on failure (if using codee parameter).
+ */
+ function get_error_messages($code = '') {
+ // Return all messages if no code specified.
+ if ( empty($code) ) {
+ $all_messages = array();
+ foreach ( (array) $this->errors as $code => $messages )
+ $all_messages = array_merge($all_messages, $messages);
- if (empty($this->permalink_structure)) {
- $this->category_structure = '';
- return false;
+ return $all_messages;
}
- if (empty($this->category_base))
- $this->category_structure = $this->front . 'category/';
+ if ( isset($this->errors[$code]) )
+ return $this->errors[$code];
else
- $this->category_structure = $this->category_base . '/';
-
- $this->category_structure .= '%category%';
-
- return $this->category_structure;
- }
-
- function get_author_permastruct() {
- if (isset($this->author_structure)) {
- return $this->author_structure;
- }
-
- if (empty($this->permalink_structure)) {
- $this->author_structure = '';
- return false;
- }
-
- $this->author_structure = $this->front . $this->author_base . '/%author%';
-
- return $this->author_structure;
+ return array();
}
- function get_search_permastruct() {
- if (isset($this->search_structure)) {
- return $this->search_structure;
- }
-
- if (empty($this->permalink_structure)) {
- $this->search_structure = '';
- return false;
- }
-
- $this->search_structure = $this->root . $this->search_base . '/%search%';
-
- return $this->search_structure;
+ /**
+ * Get single error message.
+ *
+ * This will get the first message available for the code. If no code is
+ * given then the first code available will be used.
+ *
+ * @since 2.1.0
+ *
+ * @param string|int $code Optional. Error code to retrieve message.
+ * @return string
+ */
+ function get_error_message($code = '') {
+ if ( empty($code) )
+ $code = $this->get_error_code();
+ $messages = $this->get_error_messages($code);
+ if ( empty($messages) )
+ return '';
+ return $messages[0];
}
- function get_page_permastruct() {
- if (isset($this->page_structure)) {
- return $this->page_structure;
- }
-
- if (empty($this->permalink_structure)) {
- $this->page_structure = '';
- return false;
- }
-
- $this->page_structure = $this->root . '%pagename%';
+ /**
+ * Retrieve error data for error code.
+ *
+ * @since 2.1.0
+ *
+ * @param string|int $code Optional. Error code.
+ * @return mixed Null, if no errors.
+ */
+ function get_error_data($code = '') {
+ if ( empty($code) )
+ $code = $this->get_error_code();
- return $this->page_structure;
+ if ( isset($this->error_data[$code]) )
+ return $this->error_data[$code];
+ return null;
}
- function get_feed_permastruct() {
- if (isset($this->feed_structure)) {
- return $this->feed_structure;
- }
-
- if (empty($this->permalink_structure)) {
- $this->feed_structure = '';
- return false;
- }
-
- $this->feed_structure = $this->root . $this->feed_base . '/%feed%';
-
- return $this->feed_structure;
+ /**
+ * Append more error messages to list of error messages.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @param string|int $code Error code.
+ * @param string $message Error message.
+ * @param mixed $data Optional. Error data.
+ */
+ function add($code, $message, $data = '') {
+ $this->errors[$code][] = $message;
+ if ( ! empty($data) )
+ $this->error_data[$code] = $data;
}
- function get_comment_feed_permastruct() {
- if (isset($this->comment_feed_structure)) {
- return $this->comment_feed_structure;
- }
-
- if (empty($this->permalink_structure)) {
- $this->comment_feed_structure = '';
- return false;
- }
-
- $this->comment_feed_structure = $this->root . $this->comments_base . '/' . $this->feed_base . '/%feed%';
-
- return $this->comment_feed_structure;
- }
+ /**
+ * Add data for error code.
+ *
+ * The error code can only contain one error data.
+ *
+ * @since 2.1.0
+ *
+ * @param mixed $data Error data.
+ * @param string|int $code Error code.
+ */
+ function add_data($data, $code = '') {
+ if ( empty($code) )
+ $code = $this->get_error_code();
- function add_rewrite_tag($tag, $pattern, $query) {
- // If the tag already exists, replace the existing pattern and query for
- // that tag, otherwise add the new tag, pattern, and query to the end of
- // the arrays.
- $position = array_search($tag, $this->rewritecode);
- if (FALSE !== $position && NULL !== $position) {
- $this->rewritereplace[$position] = $pattern;
- $this->queryreplace[$position] = $query;
- } else {
- $this->rewritecode[] = $tag;
- $this->rewritereplace[] = $pattern;
- $this->queryreplace[] = $query;
- }
+ $this->error_data[$code] = $data;
}
+}
- function generate_rewrite_rules($permalink_structure, $paged = true, $feed = true, $forcomments = false, $walk_dirs = true) {
- $feedregex2 = '';
- foreach ($this->feeds as $feed_name) {
- $feedregex2 .= $feed_name . '|';
- }
- $feedregex2 = '(' . trim($feedregex2, '|') . ')/?$';
- $feedregex = $this->feed_base . '/' . $feedregex2;
-
- $trackbackregex = 'trackback/?$';
- $pageregex = 'page/?([0-9]{1,})/?$';
-
- $front = substr($permalink_structure, 0, strpos($permalink_structure, '%'));
- preg_match_all('/%.+?%/', $permalink_structure, $tokens);
-
- $num_tokens = count($tokens[0]);
-
- $index = $this->index;
- $feedindex = $index;
- $trackbackindex = $index;
- for ($i = 0; $i < $num_tokens; ++$i) {
- if (0 < $i) {
- $queries[$i] = $queries[$i - 1] . '&';
- }
-
- $query_token = str_replace($this->rewritecode, $this->queryreplace, $tokens[0][$i]) . $this->preg_index($i+1);
- $queries[$i] .= $query_token;
- }
+/**
+ * Check whether variable is a WordPress Error.
+ *
+ * Looks at the object and if a WP_Error class. Does not check to see if the
+ * parent is also WP_Error, so can't inherit WP_Error and still use this
+ * function.
+ *
+ * @since 2.1.0
+ *
+ * @param mixed $thing Check if unknown variable is WordPress Error object.
+ * @return bool True, if WP_Error. False, if not WP_Error.
+ */
+function is_wp_error($thing) {
+ if ( is_object($thing) && is_a($thing, 'WP_Error') )
+ return true;
+ return false;
+}
- $structure = $permalink_structure;
- if ($front != '/') {
- $structure = str_replace($front, '', $structure);
- }
- $structure = trim($structure, '/');
- if ($walk_dirs) {
- $dirs = explode('/', $structure);
- } else {
- $dirs[] = $structure;
- }
- $num_dirs = count($dirs);
+/**
+ * A class for displaying various tree-like structures.
+ *
+ * Extend the Walker class to use it, see examples at the below. Child classes
+ * do not need to implement all of the abstract methods in the class. The child
+ * only needs to implement the methods that are needed. Also, the methods are
+ * not strictly abstract in that the parameter definition needs to be followed.
+ * The child classes can have additional parameters.
+ *
+ * @package WordPress
+ * @since 2.1.0
+ * @abstract
+ */
+class Walker {
+ /**
+ * What the class handles.
+ *
+ * @since 2.1.0
+ * @var string
+ * @access public
+ */
+ var $tree_type;
+
+ /**
+ * DB fields to use.
+ *
+ * @since 2.1.0
+ * @var array
+ * @access protected
+ */
+ var $db_fields;
+
+ /**
+ * Max number of pages walked by the paged walker
+ *
+ * @since 2.7.0
+ * @var int
+ * @access protected
+ */
+ var $max_pages = 1;
+
+ /**
+ * Starts the list before the elements are added.
+ *
+ * Additional parameters are used in child classes. The args parameter holds
+ * additional values that may be used with the child class methods. This
+ * method is called at the start of the output list.
+ *
+ * @since 2.1.0
+ * @abstract
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ */
+ function start_lvl(&$output) {}
+
+ /**
+ * Ends the list of after the elements are added.
+ *
+ * Additional parameters are used in child classes. The args parameter holds
+ * additional values that may be used with the child class methods. This
+ * method finishes the list at the end of output of the elements.
+ *
+ * @since 2.1.0
+ * @abstract
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ */
+ function end_lvl(&$output) {}
+
+ /**
+ * Start the element output.
+ *
+ * Additional parameters are used in child classes. The args parameter holds
+ * additional values that may be used with the child class methods. Includes
+ * the element output also.
+ *
+ * @since 2.1.0
+ * @abstract
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ */
+ function start_el(&$output) {}
+
+ /**
+ * Ends the element output, if needed.
+ *
+ * Additional parameters are used in child classes. The args parameter holds
+ * additional values that may be used with the child class methods.
+ *
+ * @since 2.1.0
+ * @abstract
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ */
+ function end_el(&$output) {}
+
+ /**
+ * Traverse elements to create list from elements.
+ *
+ * Display one element if the element doesn't have any children otherwise,
+ * display the element and its children. Will only traverse up to the max
+ * depth and no ignore elements under that depth. It is possible to set the
+ * max depth to include all depths, see walk() method.
+ *
+ * This method shouldn't be called directly, use the walk() method instead.
+ *
+ * @since 2.5.0
+ *
+ * @param object $element Data object
+ * @param array $children_elements List of elements to continue traversing.
+ * @param int $max_depth Max depth to traverse.
+ * @param int $depth Depth of current element.
+ * @param array $args
+ * @param string $output Passed by reference. Used to append additional content.
+ * @return null Null on failure with no changes to parameters.
+ */
+ function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
- $front = preg_replace('|^/+|', '', $front);
+ if ( !$element )
+ return;
- $post_rewrite = array();
- $struct = $front;
- for ($j = 0; $j < $num_dirs; ++$j) {
- $struct .= $dirs[$j] . '/';
- $struct = ltrim($struct, '/');
- $match = str_replace($this->rewritecode, $this->rewritereplace, $struct);
- $num_toks = preg_match_all('/%.+?%/', $struct, $toks);
- $query = $queries[$num_toks - 1];
+ $id_field = $this->db_fields['id'];
- $pagematch = $match . $pageregex;
- $pagequery = $index . '?' . $query . '&paged=' . $this->preg_index($num_toks + 1);
+ //display this element
+ if ( is_array( $args[0] ) )
+ $args[0]['has_children'] = ! empty( $children_elements[$element->$id_field] );
+ $cb_args = array_merge( array(&$output, $element, $depth), $args);
+ call_user_func_array(array(&$this, 'start_el'), $cb_args);
- $feedmatch = $match . $feedregex;
- $feedquery = $feedindex . '?' . $query . '&feed=' . $this->preg_index($num_toks + 1);
+ $id = $element->$id_field;
- $feedmatch2 = $match . $feedregex2;
- $feedquery2 = $feedindex . '?' . $query . '&feed=' . $this->preg_index($num_toks + 1);
+ // descend only when the depth is right and there are childrens for this element
+ if ( ($max_depth == 0 || $max_depth > $depth+1 ) && isset( $children_elements[$id]) ) {
- if ($forcomments) {
- $feedquery .= '&withcomments=1';
- $feedquery2 .= '&withcomments=1';
- }
+ foreach( $children_elements[ $id ] as $child ){
- $rewrite = array();
- if ($feed)
- $rewrite = array($feedmatch => $feedquery, $feedmatch2 => $feedquery2);
- if ($paged)
- $rewrite = array_merge($rewrite, array($pagematch => $pagequery));
-
- if ($num_toks) {
- $post = false;
- $page = false;
- if (strstr($struct, '%postname%') || strstr($struct, '%post_id%')
- || strstr($struct, '%pagename%')
- || (strstr($struct, '%year%') && strstr($struct, '%monthnum%') && strstr($struct, '%day%') && strstr($struct, '%hour%') && strstr($struct, '%minute') && strstr($struct, '%second%'))) {
- $post = true;
- if ( strstr($struct, '%pagename%') )
- $page = true;
- $trackbackmatch = $match . $trackbackregex;
- $trackbackquery = $trackbackindex . '?' . $query . '&tb=1';
- $match = rtrim($match, '/');
- $submatchbase = str_replace(array('(',')'),'',$match);
- $sub1 = $submatchbase . '/([^/]+)/';
- $sub1tb = $sub1 . $trackbackregex;
- $sub1feed = $sub1 . $feedregex;
- $sub1feed2 = $sub1 . $feedregex2;
- $sub1 .= '?$';
- $sub2 = $submatchbase . '/attachment/([^/]+)/';
- $sub2tb = $sub2 . $trackbackregex;
- $sub2feed = $sub2 . $feedregex;
- $sub2feed2 = $sub2 . $feedregex2;
- $sub2 .= '?$';
- $subquery = $index . '?attachment=' . $this->preg_index(1);
- $subtbquery = $subquery . '&tb=1';
- $subfeedquery = $subquery . '&feed=' . $this->preg_index(2);
- $match = $match . '(/[0-9]+)?/?$';
- $query = $index . '?' . $query . '&page=' . $this->preg_index($num_toks + 1);
- } else {
- $match .= '?$';
- $query = $index . '?' . $query;
- }
-
- $rewrite = array_merge($rewrite, array($match => $query));
-
- if ($post) {
- $rewrite = array_merge(array($trackbackmatch => $trackbackquery), $rewrite);
- if ( ! $page )
- $rewrite = array_merge($rewrite, array($sub1 => $subquery, $sub1tb => $subtbquery, $sub1feed => $subfeedquery, $sub1feed2 => $subfeedquery));
- $rewrite = array_merge($rewrite, array($sub2 => $subquery, $sub2tb => $subtbquery, $sub2feed => $subfeedquery, $sub2feed2 => $subfeedquery));
+ 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);
}
+ $this->display_element( $child, $children_elements, $max_depth, $depth + 1, $args, $output );
}
- $post_rewrite = array_merge($rewrite, $post_rewrite);
+ unset( $children_elements[ $id ] );
}
- return $post_rewrite;
- }
- function generate_rewrite_rule($permalink_structure, $walk_dirs = false) {
- return $this->generate_rewrite_rules($permalink_structure, false, false, false, $walk_dirs);
+ 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);
}
- /* rewrite_rules
- * Construct rewrite matches and queries from permalink structure.
- * Returns an associate array of matches and queries.
+ /**
+ * Display 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.
+ *
+ * @since 2.1.0
+ *
+ * @param array $elements
+ * @param int $max_depth
+ * @return string
*/
- function rewrite_rules() {
- $rewrite = array();
-
- if (empty($this->permalink_structure)) {
- return $rewrite;
+ 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
+ * separate elements into two buckets: top level and children elements
+ * children_elements is two dimensional array, eg.
+ * children_elements[10][] contains all sub-elements whose parent is 10.
+ */
+ $top_level_elements = array();
+ $children_elements = array();
+ foreach ( $elements as $e) {
+ if ( 0 == $e->$parent_field )
+ $top_level_elements[] = $e;
+ else
+ $children_elements[ $e->$parent_field ][] = $e;
}
- //Default Feed rules - These are require to allow for the direct access files to work with permalink structure starting with %category%
- $default_feeds = array( 'wp-atom.php$' => $this->index .'?feed=atom',
- 'wp-rdf.php$' => $this->index .'?feed=rdf',
- 'wp-rss.php$' => $this->index .'?feed=rss',
- 'wp-rss2.php$' => $this->index .'?feed=rss2',
- 'wp-feed.php$' => $this->index .'?feed=feed',
- 'wp-commentsrss2.php$' => $this->index . '?feed=rss2&withcomments=1');
-
-
- // Post
- $post_rewrite = $this->generate_rewrite_rules($this->permalink_structure);
- $post_rewrite = apply_filters('post_rewrite_rules', $post_rewrite);
-
- // Date
- $date_rewrite = $this->generate_rewrite_rules($this->get_date_permastruct());
- $date_rewrite = apply_filters('date_rewrite_rules', $date_rewrite);
-
- // Root
- $root_rewrite = $this->generate_rewrite_rules($this->root . '/');
- $root_rewrite = apply_filters('root_rewrite_rules', $root_rewrite);
-
- // Comments
- $comments_rewrite = $this->generate_rewrite_rules($this->root . $this->comments_base, true, true, true, false);
- $comments_rewrite = apply_filters('comments_rewrite_rules', $comments_rewrite);
-
- // Search
- $search_structure = $this->get_search_permastruct();
- $search_rewrite = $this->generate_rewrite_rules($search_structure);
- $search_rewrite = apply_filters('search_rewrite_rules', $search_rewrite);
-
- // Categories
- $category_rewrite = $this->generate_rewrite_rules($this->get_category_permastruct());
- $category_rewrite = apply_filters('category_rewrite_rules', $category_rewrite);
-
- // Authors
- $author_rewrite = $this->generate_rewrite_rules($this->get_author_permastruct());
- $author_rewrite = apply_filters('author_rewrite_rules', $author_rewrite);
-
- // Pages
- $page_rewrite = $this->page_rewrite_rules();
- $page_rewrite = apply_filters('page_rewrite_rules', $page_rewrite);
-
- // Put them together.
- $this->rules = array_merge($default_feeds, $page_rewrite, $root_rewrite, $comments_rewrite, $search_rewrite, $category_rewrite, $author_rewrite, $date_rewrite, $post_rewrite);
-
- do_action('generate_rewrite_rules', array(&$this));
- $this->rules = apply_filters('rewrite_rules_array', $this->rules);
-
- return $this->rules;
- }
- function wp_rewrite_rules() {
- $this->rules = get_option('rewrite_rules');
- if ( empty($this->rules) ) {
- $this->matches = 'matches';
- $this->rewrite_rules();
- update_option('rewrite_rules', $this->rules);
+ /*
+ * when none of the elements is top level
+ * assume the first one must be root of the sub elements
+ */
+ if ( empty($top_level_elements) ) {
+
+ $first = array_slice( $elements, 0, 1 );
+ $root = $first[0];
+
+ $top_level_elements = array();
+ $children_elements = array();
+ foreach ( $elements as $e) {
+ if ( $root->$parent_field == $e->$parent_field )
+ $top_level_elements[] = $e;
+ else
+ $children_elements[ $e->$parent_field ][] = $e;
+ }
}
- return $this->rules;
+ 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 ) && count( $children_elements ) > 0 ) {
+ $empty_array = array();
+ foreach ( $children_elements as $orphans )
+ foreach( $orphans as $op )
+ $this->display_element( $op, $empty_array, 1, 0, $args, $output );
+ }
+
+ return $output;
}
- function mod_rewrite_rules() {
- if ( ! $this->using_permalinks()) {
+ /**
+ * paged_walk() - produce a page of nested elements
+ *
+ * Given an array of hierarchical elements, the maximum depth, a specific page number,
+ * and number of elements per page, this function first determines all top level root elements
+ * belonging to that page, then lists them and all of their children in hierarchical order.
+ *
+ * @package WordPress
+ * @since 2.7
+ * @param $max_depth = 0 means display all levels; $max_depth > 0 specifies the number of display levels.
+ * @param $page_num the specific page number, beginning with 1.
+ * @return XHTML of the specified page of elements
+ */
+ function paged_walk( $elements, $max_depth, $page_num, $per_page ) {
+
+ /* sanity check */
+ if ( empty($elements) || $max_depth < -1 )
return '';
- }
- $site_root = parse_url(get_settings('siteurl'));
- $site_root = trailingslashit($site_root['path']);
-
- $home_root = parse_url(get_settings('home'));
- $home_root = trailingslashit($home_root['path']);
-
- $rules = "\n";
- $rules .= "RewriteEngine On\n";
- $rules .= "RewriteBase $home_root\n";
-
- if ($this->use_verbose_rules) {
- $this->matches = '';
- $rewrite = $this->rewrite_rules();
- $num_rules = count($rewrite);
- $rules .= "RewriteCond %{REQUEST_FILENAME} -f [OR]\n" .
- "RewriteCond %{REQUEST_FILENAME} -d\n" .
- "RewriteRule ^.*$ - [S=$num_rules]\n";
-
- foreach ($rewrite as $match => $query) {
- // Apache 1.3 does not support the reluctant (non-greedy) modifier.
- $match = str_replace('.+?', '.+', $match);
-
- // If the match is unanchored and greedy, prepend rewrite conditions
- // to avoid infinite redirects and eclipsing of real files.
- if ($match == '(.+)/?$' || $match == '([^/]+)/?$' ) {
- //nada.
- }
-
- if (strstr($query, $this->index)) {
- $rules .= 'RewriteRule ^' . $match . ' ' . $home_root . $query . " [QSA,L]\n";
- } else {
- $rules .= 'RewriteRule ^' . $match . ' ' . $site_root . $query . " [QSA,L]\n";
- }
- }
+ $args = array_slice( func_get_args(), 4 );
+ $output = '';
+
+ $id_field = $this->db_fields['id'];
+ $parent_field = $this->db_fields['parent'];
+
+ $count = -1;
+ if ( -1 == $max_depth )
+ $total_top = count( $elements );
+ if ( $page_num < 1 || $per_page < 0 ) {
+ // No paging
+ $paging = false;
+ $start = 0;
+ if ( -1 == $max_depth )
+ $end = $total_top;
+ $this->max_pages = 1;
} else {
- $rules .= "RewriteCond %{REQUEST_FILENAME} !-f\n" .
- "RewriteCond %{REQUEST_FILENAME} !-d\n" .
- "RewriteRule . {$home_root}{$this->index} [L]\n";
+ $paging = true;
+ $start = ( (int)$page_num - 1 ) * (int)$per_page;
+ $end = $start + $per_page;
+ if ( -1 == $max_depth )
+ $this->max_pages = ceil($total_top / $per_page);
+ }
+
+ // flat display
+ if ( -1 == $max_depth ) {
+ if ( !empty($args[0]['reverse_top_level']) ) {
+ $elements = array_reverse( $elements );
+ $oldstart = $start;
+ $start = $total_top - $end;
+ $end = $total_top - $oldstart;
+ }
+
+ $empty_array = array();
+ foreach ( $elements as $e ) {
+ $count++;
+ if ( $count < $start )
+ continue;
+ if ( $count >= $end )
+ break;
+ $this->display_element( $e, $empty_array, 1, 0, $args, $output );
+ }
+ return $output;
+ }
+
+ /*
+ * separate elements into two buckets: top level and children elements
+ * children_elements is two dimensional array, eg.
+ * children_elements[10][] contains all sub-elements whose parent is 10.
+ */
+ $top_level_elements = array();
+ $children_elements = array();
+ foreach ( $elements as $e) {
+ if ( 0 == $e->$parent_field )
+ $top_level_elements[] = $e;
+ else
+ $children_elements[ $e->$parent_field ][] = $e;
}
- $rules .= "\n";
+ $total_top = count( $top_level_elements );
+ if ( $paging )
+ $this->max_pages = ceil($total_top / $per_page);
+ else
+ $end = $total_top;
- $rules = apply_filters('mod_rewrite_rules', $rules);
- $rules = apply_filters('rewrite_rules', $rules); // Deprecated
+ if ( !empty($args[0]['reverse_top_level']) ) {
+ $top_level_elements = array_reverse( $top_level_elements );
+ $oldstart = $start;
+ $start = $total_top - $end;
+ $end = $total_top - $oldstart;
+ }
+ if ( !empty($args[0]['reverse_children']) ) {
+ foreach ( $children_elements as $parent => $children )
+ $children_elements[$parent] = array_reverse( $children );
+ }
- return $rules;
- }
+ foreach ( $top_level_elements as $e ) {
+ $count++;
- function flush_rules() {
- generate_page_rewrite_rules();
- delete_option('rewrite_rules');
- $this->wp_rewrite_rules();
- if ( function_exists('save_mod_rewrite_rules') )
- save_mod_rewrite_rules();
- }
+ //for the last page, need to unset earlier children in order to keep track of orphans
+ if ( $end >= $total_top && $count < $start )
+ $this->unset_children( $e, $children_elements );
- function init() {
- $this->permalink_structure = get_settings('permalink_structure');
- $this->front = substr($this->permalink_structure, 0, strpos($this->permalink_structure, '%'));
- $this->root = '';
- if ($this->using_index_permalinks()) {
- $this->root = $this->index . '/';
+ if ( $count < $start )
+ continue;
+
+ if ( $count >= $end )
+ break;
+
+ $this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
}
- $this->category_base = get_settings('category_base');
- unset($this->category_structure);
- unset($this->author_structure);
- unset($this->date_structure);
- unset($this->page_structure);
- unset($this->search_structure);
- unset($this->feed_structure);
- unset($this->comment_feed_structure);
- }
- function set_permalink_structure($permalink_structure) {
- if ($permalink_structure != $this->permalink_structure) {
- update_option('permalink_structure', $permalink_structure);
- $this->init();
+ if ( $end >= $total_top && count( $children_elements ) > 0 ) {
+ $empty_array = array();
+ foreach ( $children_elements as $orphans )
+ foreach( $orphans as $op )
+ $this->display_element( $op, $empty_array, 1, 0, $args, $output );
}
+
+ return $output;
}
- function set_category_base($category_base) {
- if ($category_base != $this->category_base) {
- update_option('category_base', $category_base);
- $this->init();
+ function get_number_of_root_elements( $elements ){
+
+ $num = 0;
+ $parent_field = $this->db_fields['parent'];
+
+ foreach ( $elements as $e) {
+ if ( 0 == $e->$parent_field )
+ $num++;
}
+ return $num;
}
- function WP_Rewrite() {
- $this->init();
+ // unset all the children for a given top level element
+ function unset_children( $e, &$children_elements ){
+
+ if ( !$e || !$children_elements )
+ return;
+
+ $id_field = $this->db_fields['id'];
+ $id = $e->$id_field;
+
+ if ( !empty($children_elements[$id]) && is_array($children_elements[$id]) )
+ foreach ( (array) $children_elements[$id] as $child )
+ $this->unset_children( $child, $children_elements );
+
+ if ( isset($children_elements[$id]) )
+ unset( $children_elements[$id] );
+
}
}
-class WP {
- var $public_query_vars = array('m', 'p', 'posts', 'w', 'cat', 'withcomments', 's', 'search', 'exact', 'sentence', 'debug', 'calendar', 'page', 'paged', 'more', 'tb', 'pb', 'author', 'order', 'orderby', 'year', 'monthnum', 'day', 'hour', 'minute', 'second', 'name', 'category_name', 'feed', 'author_name', 'static', 'pagename', 'page_id', 'error', 'comments_popup', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview');
+/**
+ * Create HTML list of pages.
+ *
+ * @package WordPress
+ * @since 2.1.0
+ * @uses Walker
+ */
+class Walker_Page extends Walker {
+ /**
+ * @see Walker::$tree_type
+ * @since 2.1.0
+ * @var string
+ */
+ var $tree_type = 'page';
- var $private_query_vars = array('posts_per_page', 'posts_per_archive_page', 'what_to_show', 'showposts', 'nopaging', 'show_post_type');
+ /**
+ * @see Walker::$db_fields
+ * @since 2.1.0
+ * @todo Decouple this.
+ * @var array
+ */
+ var $db_fields = array ('parent' => 'post_parent', 'id' => 'ID');
+
+ /**
+ * @see Walker::start_lvl()
+ * @since 2.1.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param int $depth Depth of page. Used for padding.
+ */
+ function start_lvl(&$output, $depth) {
+ $indent = str_repeat("\t", $depth);
+ $output .= "\n$indent
\n";
+ }
- var $query_vars;
- var $query_string;
- var $request;
- var $matched_rule;
- var $matched_query;
- var $did_permalink = false;
+ /**
+ * @see Walker::end_lvl()
+ * @since 2.1.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param int $depth Depth of page. Used for padding.
+ */
+ function end_lvl(&$output, $depth) {
+ $indent = str_repeat("\t", $depth);
+ $output .= "$indent
\n";
+ }
- function parse_request($extra_query_vars = '') {
- global $wp_rewrite;
+ /**
+ * @see Walker::start_el()
+ * @since 2.1.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param object $page Page data object.
+ * @param int $depth Depth of page. Used for padding.
+ * @param int $current_page Page ID.
+ * @param array $args
+ */
+ function start_el(&$output, $page, $depth, $args, $current_page) {
+ if ( $depth )
+ $indent = str_repeat("\t", $depth);
+ else
+ $indent = '';
- $this->query_vars = array();
+ extract($args, EXTR_SKIP);
+ $css_class = array('page_item', 'page-item-'.$page->ID);
+ if ( !empty($current_page) ) {
+ $_current_page = get_page( $current_page );
+ if ( isset($_current_page->ancestors) && 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';
+ } elseif ( $page->ID == get_option('page_for_posts') ) {
+ $css_class[] = 'current_page_parent';
+ }
- if (! empty($extra_query_vars))
- parse_str($extra_query_vars, $extra_query_vars);
- else
- $extra_query_vars = array();
+ $css_class = implode(' ', apply_filters('page_css_class', $css_class, $page));
- // Process PATH_INFO, REQUEST_URI, and 404 for permalinks.
+ $output .= $indent . '
' . $link_before . apply_filters( 'the_title', $page->post_title, $page->ID ) . $link_after . '';
- // Fetch the rewrite rules.
- $rewrite = $wp_rewrite->wp_rewrite_rules();
+ if ( !empty($show_date) ) {
+ if ( 'modified' == $show_date )
+ $time = $page->post_modified;
+ else
+ $time = $page->post_date;
- if (! empty($rewrite)) {
- // If we match a rewrite rule, this will be cleared.
- $error = '404';
- $this->did_permalink = true;
+ $output .= " " . mysql2date($date_format, $time);
+ }
+ }
- $pathinfo = $_SERVER['PATH_INFO'];
- $pathinfo_array = explode('?', $pathinfo);
- $pathinfo = str_replace("%", "%25", $pathinfo_array[0]);
- $req_uri = $_SERVER['REQUEST_URI'];
- $req_uri_array = explode('?', $req_uri);
- $req_uri = $req_uri_array[0];
- $self = $_SERVER['PHP_SELF'];
- $home_path = parse_url(get_settings('home'));
- $home_path = $home_path['path'];
- $home_path = trim($home_path, '/');
+ /**
+ * @see Walker::end_el()
+ * @since 2.1.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param object $page Page data object. Not used.
+ * @param int $depth Depth of page. Not Used.
+ */
+ function end_el(&$output, $page, $depth) {
+ $output .= "
\n";
+ }
- // Trim path info from the end and the leading home path from the
- // front. For path info requests, this leaves us with the requesting
- // filename, if any. For 404 requests, this leaves us with the
- // requested permalink.
- $req_uri = str_replace($pathinfo, '', $req_uri);
- $req_uri = trim($req_uri, '/');
- $req_uri = preg_replace("|^$home_path|", '', $req_uri);
- $req_uri = trim($req_uri, '/');
- $pathinfo = trim($pathinfo, '/');
- $pathinfo = preg_replace("|^$home_path|", '', $pathinfo);
- $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
- // $req_uri for other requests.
- if ( ! empty($pathinfo) && !preg_match('|^.*' . $wp_rewrite->index . '$|', $pathinfo) ) {
- $request = $pathinfo;
- } else {
- // If the request uri is the index, blank it out so that we don't try to match it against a rule.
- if ( $req_uri == $wp_rewrite->index )
- $req_uri = '';
- $request = $req_uri;
- }
+/**
+ * Create HTML dropdown list of pages.
+ *
+ * @package WordPress
+ * @since 2.1.0
+ * @uses Walker
+ */
+class Walker_PageDropdown extends Walker {
+ /**
+ * @see Walker::$tree_type
+ * @since 2.1.0
+ * @var string
+ */
+ var $tree_type = 'page';
- $this->request = $request;
+ /**
+ * @see Walker::$db_fields
+ * @since 2.1.0
+ * @todo Decouple this
+ * @var array
+ */
+ var $db_fields = array ('parent' => 'post_parent', 'id' => 'ID');
+
+ /**
+ * @see Walker::start_el()
+ * @since 2.1.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param object $page Page data object.
+ * @param int $depth Depth of page in reference to parent pages. Used for padding.
+ * @param array $args Uses 'selected' argument for selected page to set selected HTML attribute for option element.
+ */
+ function start_el(&$output, $page, $depth, $args) {
+ $pad = str_repeat(' ', $depth * 3);
+
+ $output .= "\t\n";
+ }
+}
- // Look for matches.
- $request_match = $request;
- foreach ($rewrite as $match => $query) {
- // 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)) {
- $request_match = $req_uri . '/' . $request;
- }
+/**
+ * Create HTML list of categories.
+ *
+ * @package WordPress
+ * @since 2.1.0
+ * @uses Walker
+ */
+class Walker_Category extends Walker {
+ /**
+ * @see Walker::$tree_type
+ * @since 2.1.0
+ * @var string
+ */
+ var $tree_type = 'category';
- if (preg_match("!^$match!", $request_match, $matches) ||
- preg_match("!^$match!", urldecode($request_match), $matches)) {
- // Got a match.
- $this->matched_rule = $match;
+ /**
+ * @see Walker::$db_fields
+ * @since 2.1.0
+ * @todo Decouple this
+ * @var array
+ */
+ var $db_fields = array ('parent' => 'parent', 'id' => 'term_id');
+
+ /**
+ * @see Walker::start_lvl()
+ * @since 2.1.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param int $depth Depth of category. Used for tab indentation.
+ * @param array $args Will only append content if style argument value is 'list'.
+ */
+ function start_lvl(&$output, $depth, $args) {
+ if ( 'list' != $args['style'] )
+ return;
- // Trim the query of everything up to the '?'.
- $query = preg_replace("!^.+\?!", '', $query);
+ $indent = str_repeat("\t", $depth);
+ $output .= "$indent
\n";
+ }
- // Substitute the substring matches into the query.
- eval("\$query = \"$query\";");
- $this->matched_query = $query;
+ /**
+ * @see Walker::end_lvl()
+ * @since 2.1.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param int $depth Depth of category. Used for tab indentation.
+ * @param array $args Will only append content if style argument value is 'list'.
+ */
+ function end_lvl(&$output, $depth, $args) {
+ if ( 'list' != $args['style'] )
+ return;
- // Parse the query.
- parse_str($query, $query_vars);
+ $indent = str_repeat("\t", $depth);
+ $output .= "$indent