{ if ( $ep[0] & EP_ATTACHMENT ) { $rewrite[$sub1 . $regex] = $subquery . $ep[1] . $this->preg_index(2); $rewrite[$sub2 . $regex] = $subquery . $ep[1] . $this->preg_index(2); } } } //now we've finished with endpoints, finish off the $sub1 and $sub2 matches $sub1 .= '?$'; $sub2 .= '?$'; //allow URLs like /2 for /page/2 $match = $match . '(/[0-9]+)?/?$'; $query = $index . '?' . $query . '&page=' . $this->preg_index($num_toks + 1); } else { //not matching a permalink so this is a lot simpler //close the match and finalise the query $match .= '?$'; $query = $index . '?' . $query; } //create the final array for this dir by joining the $rewrite array (which currently //only contains rules/queries for trackback, pages etc) to the main regex/query for //this dir $rewrite = array_merge($rewrite, array($match => $query)); //if we're matching a permalink, add those extras (attachments etc) on if ( $post ) { //add trackback $rewrite = array_merge(array($trackbackmatch => $trackbackquery), $rewrite); //add regexes/queries for attachments, attachment trackbacks and so on if ( ! $page ) //require /attachment/stuff form for pages because of confusion with subpages $rewrite = array_merge($rewrite, array($sub1 => $subquery, $sub1tb => $subtbquery, $sub1feed => $subfeedquery, $sub1feed2 => $subfeedquery, $sub1comment => $subcommentquery)); $rewrite = array_merge(array($sub2 => $subquery, $sub2tb => $subtbquery, $sub2feed => $subfeedquery, $sub2feed2 => $subfeedquery, $sub2comment => $subcommentquery), $rewrite); } } //if($num_toks) //add the rules for this dir to the accumulating $post_rewrite $post_rewrite = array_merge($rewrite, $post_rewrite); } //foreach ($dir) return $post_rewrite; //the finished rules. phew! } /** * Generate Rewrite rules with permalink structure and walking directory only. * * Shorten version of {@link WP_Rewrite::generate_rewrite_rules()} that * allows for shorter list of parameters. See the method for longer * description of what generating rewrite rules does. * * @uses WP_Rewrite::generate_rewrite_rules() See for long description and rest of parameters. * @since 1.5.0 * @access public * * @param string $permalink_structure The permalink structure to generate rules. * @param bool $walk_dirs Optional, default is false. Whether to create list of directories to walk over. * @return array */ function generate_rewrite_rule($permalink_structure, $walk_dirs = false) { return $this->generate_rewrite_rules($permalink_structure, EP_NONE, false, false, false, $walk_dirs); } /** * Construct rewrite matches and queries from permalink structure. * * Runs the action 'generate_rewrite_rules' with the parameter that is an * reference to the current WP_Rewrite instance to further manipulate the * permalink structures and rewrite rules. Runs the 'rewrite_rules_array' * filter on the full rewrite rule array. * * There are two ways to manipulate the rewrite rules, one by hooking into * the 'generate_rewrite_rules' action and gaining full control of the * object or just manipulating the rewrite rule array before it is passed * from the function. * * @since 1.5.0 * @access public * * @return array An associate array of matches and queries. */ function rewrite_rules() { $rewrite = array(); if ( empty($this->permalink_structure) ) return $rewrite; // robots.txt -only if installed at the root $home_path = parse_url( home_url() ); $robots_rewrite = ( empty( $home_path['path'] ) || '/' == $home_path['path'] ) ? array( 'robots\.txt$' => $this->index . '?robots=1' ) : array(); // 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'); // Registration rules $registration_pages = array(); if ( is_multisite() && is_main_site() ) { $registration_pages['.*wp-signup.php$'] = $this->index . '?signup=true'; $registration_pages['.*wp-activate.php$'] = $this->index . '?activate=true'; } // Post $post_rewrite = $this->generate_rewrite_rules($this->permalink_structure, EP_PERMALINK); $post_rewrite = apply_filters('post_rewrite_rules', $post_rewrite); // Date $date_rewrite = $this->generate_rewrite_rules($this->get_date_permastruct(), EP_DATE); $date_rewrite = apply_filters('date_rewrite_rules', $date_rewrite); // Root $root_rewrite = $this->generate_rewrite_rules($this->root . '/', EP_ROOT); $root_rewrite = apply_filters('root_rewrite_rules', $root_rewrite); // Comments $comments_rewrite = $this->generate_rewrite_rules($this->root . $this->comments_base, EP_COMMENTS, 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, EP_SEARCH); $search_rewrite = apply_filters('search_rewrite_rules', $search_rewrite); // Categories $category_rewrite = $this->generate_rewrite_rules($this->get_category_permastruct(), EP_CATEGORIES); $category_rewrite = apply_filters('category_rewrite_rules', $category_rewrite); // Tags $tag_rewrite = $this->generate_rewrite_rules($this->get_tag_permastruct(), EP_TAGS); $tag_rewrite = apply_filters('tag_rewrite_rules', $tag_rewrite); // Authors $author_rewrite = $this->generate_rewrite_rules($this->get_author_permastruct(), EP_AUTHORS); $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); // Extra permastructs foreach ( $this->extra_permastructs as $permastruct ) { if ( is_array($permastruct) ) $this->extra_rules_top = array_merge($this->extra_rules_top, $this->generate_rewrite_rules($permastruct[0], $permastruct[1])); else $this->extra_rules_top = array_merge($this->extra_rules_top, $this->generate_rewrite_rules($permastruct, EP_NONE)); } // Put them together. if ( $this->use_verbose_page_rules ) $this->rules = array_merge($this->extra_rules_top, $robots_rewrite, $default_feeds, $registration_pages, $page_rewrite, $root_rewrite, $comments_rewrite, $search_rewrite, $category_rewrite, $tag_rewrite, $author_rewrite, $date_rewrite, $post_rewrite, $this->extra_rules); else $this->rules = array_merge($this->extra_rules_top, $robots_rewrite, $default_feeds, $registration_pages, $root_rewrite, $comments_rewrite, $search_rewrite, $category_rewrite, $tag_rewrite, $author_rewrite, $date_rewrite, $post_rewrite, $page_rewrite, $this->extra_rules); do_action_ref_array('generate_rewrite_rules', array(&$this)); $this->rules = apply_filters('rewrite_rules_array', $this->rules); return $this->rules; } /** * Retrieve the rewrite rules. * * The difference between this method and {@link * WP_Rewrite::rewrite_rules()} is that this method stores the rewrite rules * in the 'rewrite_rules' option and retrieves it. This prevents having to * process all of the permalinks to get the rewrite rules in the form of * caching. * * @since 1.5.0 * @access public * * @return array Rewrite 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); } return $this->rules; } /** * Retrieve mod_rewrite formatted rewrite rules to write to .htaccess. * * Does not actually write to the .htaccess file, but creates the rules for * the process that will. * * Will add the non_wp_rules property rules to the .htaccess file before * the WordPress rewrite rules one. * * @since 1.5.0 * @access public * * @return string */ function mod_rewrite_rules() { if ( ! $this->using_permalinks() ) return ''; $site_root = parse_url(get_option('siteurl')); if ( isset( $site_root['path'] ) ) $site_root = trailingslashit($site_root['path']); $home_root = parse_url(home_url()); if ( isset( $home_root['path'] ) ) $home_root = trailingslashit($home_root['path']); else $home_root = '/'; $rules = "\n"; $rules .= "RewriteEngine On\n"; $rules .= "RewriteBase $home_root\n"; $rules .= "RewriteRule ^index\.php$ - [L]\n"; // Prevent -f checks on index.php. //add in the rules that don't redirect to WP's index.php (and thus shouldn't be handled by WP at all) foreach ( (array) $this->non_wp_rules 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. //} $rules .= 'RewriteRule ^' . $match . ' ' . $home_root . $query . " [QSA,L]\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 ( (array) $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 ( strpos($query, $this->index) !== false ) $rules .= 'RewriteRule ^' . $match . ' ' . $home_root . $query . " [QSA,L]\n"; else $rules .= 'RewriteRule ^' . $match . ' ' . $site_root . $query . " [QSA,L]\n"; } } else { $rules .= "RewriteCond %{REQUEST_FILENAME} !-f\n" . "RewriteCond %{REQUEST_FILENAME} !-d\n" . "RewriteRule . {$home_root}{$this->index} [L]\n"; } $rules .= "\n"; $rules = apply_filters('mod_rewrite_rules', $rules); $rules = apply_filters('rewrite_rules', $rules); // Deprecated return $rules; } /** * Retrieve IIS7 URL Rewrite formatted rewrite rules to write to web.config file. * * Does not actually write to the web.config file, but creates the rules for * the process that will. * * @since 2.8.0 * @access public * * @return string */ function iis7_url_rewrite_rules( $add_parent_tags = false ) { if ( ! $this->using_permalinks() ) return ''; $rules = ''; if ( $add_parent_tags ) { $rules .= ' '; } if ( !is_multisite() ) { $rules .= ' '; } else { if (is_subdomain_install()) { $rules .= ' '; } else { $rules .= ' '; } } if ( $add_parent_tags ) { $rules .= ' '; } $rules = apply_filters('iis7_url_rewrite_rules', $rules); return $rules; } /** * Add a straight rewrite rule. * * Any value in the $after parameter that isn't 'bottom' will be placed at * the top of the rules. * * @since 2.1.0 * @access public * * @param string $regex Regular expression to match against request. * @param string $redirect URL regex redirects to when regex matches request. * @param string $after Optional, default is bottom. Location to place rule. */ function add_rule($regex, $redirect, $after = 'bottom') { //get everything up to the first ? $index = (strpos($redirect, '?') == false ? strlen($redirect) : strpos($redirect, '?')); $front = substr($redirect, 0, $index); if ( $front != $this->index ) { //it doesn't redirect to WP's index.php $this->add_external_rule($regex, $redirect); } else { if ( 'bottom' == $after) $this->extra_rules = array_merge($this->extra_rules, array($regex => $redirect)); else $this->extra_rules_top = array_merge($this->extra_rules_top, array($regex => $redirect)); //$this->extra_rules[$regex] = $redirect; } } /** * Add a rule that doesn't redirect to index.php. * * Can redirect to any place. * * @since 2.1.0 * @access public * * @param string $regex Regular expression to match against request. * @param string $redirect URL regex redirects to when regex matches request. */ function add_external_rule($regex, $redirect) { $this->non_wp_rules[$regex] = $redirect; } /** * Add an endpoint, like /trackback/. * * To be inserted after certain URL types (specified in $places). * * @since 2.1.0 * @access public * * @param string $name Name of endpoint. * @param array $places URL types that endpoint can be used. */ function add_endpoint($name, $places) { global $wp; $this->endpoints[] = array ( $places, $name ); $wp->add_query_var($name); } /** * Add permalink structure. * * These are added along with the extra rewrite rules that are merged to the * top. * * @since unknown * @access public * * @param string $name Name for permalink structure. * @param string $struct Permalink structure. * @param bool $with_front Prepend front base to permalink structure. */ function add_permastruct($name, $struct, $with_front = true, $ep_mask = EP_NONE) { if ( $with_front ) $struct = $this->front . $struct; $this->extra_permastructs[$name] = array($struct, $ep_mask); } /** * Remove rewrite rules and then recreate rewrite rules. * * Calls {@link WP_Rewrite::wp_rewrite_rules()} after removing the * 'rewrite_rules' option. If the function named 'save_mod_rewrite_rules' * exists, it will be called. * * @since 2.0.1 * @access public * @param $hard bool Whether to update .htaccess (hard flush) or just update rewrite_rules option (soft flush). Default is true (hard). */ function flush_rules($hard = true) { delete_option('rewrite_rules'); $this->wp_rewrite_rules(); if ( $hard && function_exists('save_mod_rewrite_rules') ) save_mod_rewrite_rules(); if ( $hard && function_exists('iis7_save_url_rewrite_rules') ) iis7_save_url_rewrite_rules(); } /** * Sets up the object's properties. * * The 'use_verbose_page_rules' object property will be set to true if the * permalink structure begins with one of the following: '%postname%', '%category%', * '%tag%', or '%author%'. * * @since 1.5.0 * @access public */ function init() { $this->extra_rules = $this->non_wp_rules = $this->endpoints = array(); $this->permalink_structure = get_option('permalink_structure'); $this->front = substr($this->permalink_structure, 0, strpos($this->permalink_structure, '%')); $this->root = ''; if ( $this->using_index_permalinks() ) $this->root = $this->index . '/'; $this->category_base = get_option( 'category_base' ); $this->tag_base = get_option( 'tag_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); $this->use_trailing_slashes = ( '/' == substr($this->permalink_structure, -1, 1) ); // Enable generic rules for pages if permalink structure doesn't begin with a wildcard. if ( preg_match("/^[^%]*%(?:postname|category|tag|author)%/", $this->permalink_structure) ) $this->use_verbose_page_rules = true; else $this->use_verbose_page_rules = false; } /** * Set the main permalink structure for the blog. * * Will update the 'permalink_structure' option, if there is a difference * between the current permalink structure and the parameter value. Calls * {@link WP_Rewrite::init()} after the option is updated. * * Fires the 'permalink_structure_changed' action once the init call has * processed passing the old and new values * * @since 1.5.0 * @access public * * @param string $permalink_structure Permalink structure. */ function set_permalink_structure($permalink_structure) { if ( $permalink_structure != $this->permalink_structure ) { update_option('permalink_structure', $permalink_structure); $this->init(); do_action('permalink_structure_changed', $this->permalink_structure, $permalink_structure); } } /** * Set the category base for the category permalink. * * Will update the 'category_base' option, if there is a difference between * the current category base and the parameter value. Calls * {@link WP_Rewrite::init()} after the option is updated. * * @since 1.5.0 * @access public * * @param string $category_base Category permalink structure base. */ function set_category_base($category_base) { if ( $category_base != $this->category_base ) { update_option('category_base', $category_base); $this->init(); } } /** * Set the tag base for the tag permalink. * * Will update the 'tag_base' option, if there is a difference between the * current tag base and the parameter value. Calls * {@link WP_Rewrite::init()} after the option is updated. * * @since 2.3.0 * @access public * * @param string $tag_base Tag permalink structure base. */ function set_tag_base( $tag_base ) { if ( $tag_base != $this->tag_base ) { update_option( 'tag_base', $tag_base ); $this->init(); } } /** * PHP4 Constructor - Calls init(), which runs setup. * * @since 1.5.0 * @access public * * @return WP_Rewrite */ function WP_Rewrite() { $this->init(); } } ?>