-
+ 9648F5A79BD461B244937AEE2060ED42F7018EF6AC204ACAEA6CF7678B0AAF839B3553DF38C68653A6C63272832DDC297E69B7D2DE1B8CDAFFEDF02BF0214741
mp-wp/wp-includes/rewrite.php
(0 . 0)(1 . 1904)
147768 <?php
147769 /**
147770 * WordPress Rewrite API
147771 *
147772 * @package WordPress
147773 * @subpackage Rewrite
147774 */
147775
147776 /**
147777 * Add a straight rewrite rule.
147778 *
147779 * @see WP_Rewrite::add_rule() for long description.
147780 * @since 2.1.0
147781 *
147782 * @param string $regex Regular Expression to match request against.
147783 * @param string $redirect Page to redirect to.
147784 * @param string $after Optional, default is 'bottom'. Where to add rule, can also be 'top'.
147785 */
147786 function add_rewrite_rule($regex, $redirect, $after = 'bottom') {
147787 global $wp_rewrite;
147788 $wp_rewrite->add_rule($regex, $redirect, $after);
147789 }
147790
147791 /**
147792 * Add a new tag (like %postname%).
147793 *
147794 * Warning: you must call this on init or earlier, otherwise the query var
147795 * addition stuff won't work.
147796 *
147797 * @since 2.1.0
147798 *
147799 * @param string $tagname
147800 * @param string $regex
147801 */
147802 function add_rewrite_tag($tagname, $regex) {
147803 //validation
147804 if (strlen($tagname) < 3 || $tagname{0} != '%' || $tagname{strlen($tagname)-1} != '%') {
147805 return;
147806 }
147807
147808 $qv = trim($tagname, '%');
147809
147810 global $wp_rewrite, $wp;
147811 $wp->add_query_var($qv);
147812 $wp_rewrite->add_rewrite_tag($tagname, $regex, $qv . '=');
147813 }
147814
147815 /**
147816 * Add a new feed type like /atom1/.
147817 *
147818 * @since 2.1.0
147819 *
147820 * @param string $feedname
147821 * @param callback $function Callback to run on feed display.
147822 * @return string Feed action name.
147823 */
147824 function add_feed($feedname, $function) {
147825 global $wp_rewrite;
147826 if (!in_array($feedname, $wp_rewrite->feeds)) { //override the file if it is
147827 $wp_rewrite->feeds[] = $feedname;
147828 }
147829 $hook = 'do_feed_' . $feedname;
147830 // Remove default function hook
147831 remove_action($hook, $hook, 10, 1);
147832 add_action($hook, $function, 10, 1);
147833 return $hook;
147834 }
147835
147836 /**
147837 * Endpoint Mask for Permalink.
147838 *
147839 * @since 2.1.0
147840 */
147841 define('EP_PERMALINK', 1);
147842
147843 /**
147844 * Endpoint Mask for Attachment.
147845 *
147846 * @since 2.1.0
147847 */
147848 define('EP_ATTACHMENT', 2);
147849
147850 /**
147851 * Endpoint Mask for date.
147852 *
147853 * @since 2.1.0
147854 */
147855 define('EP_DATE', 4);
147856
147857 /**
147858 * Endpoint Mask for year
147859 *
147860 * @since 2.1.0
147861 */
147862 define('EP_YEAR', 8);
147863
147864 /**
147865 * Endpoint Mask for month.
147866 *
147867 * @since 2.1.0
147868 */
147869 define('EP_MONTH', 16);
147870
147871 /**
147872 * Endpoint Mask for day.
147873 *
147874 * @since 2.1.0
147875 */
147876 define('EP_DAY', 32);
147877
147878 /**
147879 * Endpoint Mask for root.
147880 *
147881 * @since 2.1.0
147882 */
147883 define('EP_ROOT', 64);
147884
147885 /**
147886 * Endpoint Mask for comments.
147887 *
147888 * @since 2.1.0
147889 */
147890 define('EP_COMMENTS', 128);
147891
147892 /**
147893 * Endpoint Mask for searches.
147894 *
147895 * @since 2.1.0
147896 */
147897 define('EP_SEARCH', 256);
147898
147899 /**
147900 * Endpoint Mask for categories.
147901 *
147902 * @since 2.1.0
147903 */
147904 define('EP_CATEGORIES', 512);
147905
147906 /**
147907 * Endpoint Mask for tags.
147908 *
147909 * @since 2.3.0
147910 */
147911 define('EP_TAGS', 1024);
147912
147913 /**
147914 * Endpoint Mask for authors.
147915 *
147916 * @since 2.1.0
147917 */
147918 define('EP_AUTHORS', 2048);
147919
147920 /**
147921 * Endpoint Mask for pages.
147922 *
147923 * @since 2.1.0
147924 */
147925 define('EP_PAGES', 4096);
147926
147927 //pseudo-places
147928 /**
147929 * Endpoint Mask for default, which is nothing.
147930 *
147931 * @since 2.1.0
147932 */
147933 define('EP_NONE', 0);
147934
147935 /**
147936 * Endpoint Mask for everything.
147937 *
147938 * @since 2.1.0
147939 */
147940 define('EP_ALL', 8191);
147941
147942 /**
147943 * Add an endpoint, like /trackback/.
147944 *
147945 * The endpoints are added to the end of the request. So a request matching
147946 * "/2008/10/14/my_post/myep/", the endpoint will be "/myep/".
147947 *
147948 * @since 2.1.0
147949 * @see WP_Rewrite::add_endpoint() Parameters and more description.
147950 * @uses $wp_rewrite
147951 *
147952 * @param unknown_type $name
147953 * @param unknown_type $places
147954 */
147955 function add_rewrite_endpoint($name, $places) {
147956 global $wp_rewrite;
147957 $wp_rewrite->add_endpoint($name, $places);
147958 }
147959
147960 /**
147961 * Filter the URL base for taxonomies.
147962 *
147963 * To remove any manually prepended /index.php/.
147964 *
147965 * @access private
147966 * @since 2.6.0
147967 * @author Mark Jaquith
147968 *
147969 * @param string $base The taxonomy base that we're going to filter
147970 * @return string
147971 */
147972 function _wp_filter_taxonomy_base( $base ) {
147973 if ( !empty( $base ) ) {
147974 $base = preg_replace( '|^/index\.php/|', '', $base );
147975 $base = trim( $base, '/' );
147976 }
147977 return $base;
147978 }
147979
147980 /**
147981 * Examine a url and try to determine the post ID it represents.
147982 *
147983 * Checks are supposedly from the hosted site blog.
147984 *
147985 * @since 1.0.0
147986 *
147987 * @param string $url Permalink to check.
147988 * @return int Post ID, or 0 on failure.
147989 */
147990 function url_to_postid($url) {
147991 global $wp_rewrite;
147992
147993 $url = apply_filters('url_to_postid', $url);
147994
147995 // First, check to see if there is a 'p=N' or 'page_id=N' to match against
147996 if ( preg_match('#[?&](p|page_id|attachment_id)=(\d+)#', $url, $values) ) {
147997 $id = absint($values[2]);
147998 if ($id)
147999 return $id;
148000 }
148001
148002 // Check to see if we are using rewrite rules
148003 $rewrite = $wp_rewrite->wp_rewrite_rules();
148004
148005 // Not using rewrite rules, and 'p=N' and 'page_id=N' methods failed, so we're out of options
148006 if ( empty($rewrite) )
148007 return 0;
148008
148009 // $url cleanup by Mark Jaquith
148010 // This fixes things like #anchors, ?query=strings, missing 'www.',
148011 // added 'www.', or added 'index.php/' that will mess up our WP_Query
148012 // and return a false negative
148013
148014 // Get rid of the #anchor
148015 $url_split = explode('#', $url);
148016 $url = $url_split[0];
148017
148018 // Get rid of URL ?query=string
148019 $url_split = explode('?', $url);
148020 $url = $url_split[0];
148021
148022 // Add 'www.' if it is absent and should be there
148023 if ( false !== strpos(get_option('home'), '://www.') && false === strpos($url, '://www.') )
148024 $url = str_replace('://', '://www.', $url);
148025
148026 // Strip 'www.' if it is present and shouldn't be
148027 if ( false === strpos(get_option('home'), '://www.') )
148028 $url = str_replace('://www.', '://', $url);
148029
148030 // Strip 'index.php/' if we're not using path info permalinks
148031 if ( !$wp_rewrite->using_index_permalinks() )
148032 $url = str_replace('index.php/', '', $url);
148033
148034 if ( false !== strpos($url, get_option('home')) ) {
148035 // Chop off http://domain.com
148036 $url = str_replace(get_option('home'), '', $url);
148037 } else {
148038 // Chop off /path/to/blog
148039 $home_path = parse_url(get_option('home'));
148040 $home_path = $home_path['path'];
148041 $url = str_replace($home_path, '', $url);
148042 }
148043
148044 // Trim leading and lagging slashes
148045 $url = trim($url, '/');
148046
148047 $request = $url;
148048
148049 // Done with cleanup
148050
148051 // Look for matches.
148052 $request_match = $request;
148053 foreach ($rewrite as $match => $query) {
148054 // If the requesting file is the anchor of the match, prepend it
148055 // to the path info.
148056 if ( (! empty($url)) && (strpos($match, $url) === 0) && ($url != $request)) {
148057 $request_match = $url . '/' . $request;
148058 }
148059
148060 if ( preg_match("!^$match!", $request_match, $matches) ) {
148061 // Got a match.
148062 // Trim the query of everything up to the '?'.
148063 $query = preg_replace("!^.+\?!", '', $query);
148064
148065 // Substitute the substring matches into the query.
148066 eval("\$query = \"" . addslashes($query) . "\";");
148067 // Filter out non-public query vars
148068 global $wp;
148069 parse_str($query, $query_vars);
148070 $query = array();
148071 foreach ( (array) $query_vars as $key => $value ) {
148072 if ( in_array($key, $wp->public_query_vars) )
148073 $query[$key] = $value;
148074 }
148075 // Do the query
148076 $query = new WP_Query($query);
148077 if ( $query->is_single || $query->is_page )
148078 return $query->post->ID;
148079 else
148080 return 0;
148081 }
148082 }
148083 return 0;
148084 }
148085
148086 /**
148087 * WordPress Rewrite Component.
148088 *
148089 * The WordPress Rewrite class writes the rewrite module rules to the .htaccess
148090 * file. It also handles parsing the request to get the correct setup for the
148091 * WordPress Query class.
148092 *
148093 * The Rewrite along with WP class function as a front controller for WordPress.
148094 * You can add rules to trigger your page view and processing using this
148095 * component. The full functionality of a front controller does not exist,
148096 * meaning you can't define how the template files load based on the rewrite
148097 * rules.
148098 *
148099 * @since 1.5.0
148100 */
148101 class WP_Rewrite {
148102 /**
148103 * Default permalink structure for WordPress.
148104 *
148105 * @since 1.5.0
148106 * @access private
148107 * @var string
148108 */
148109 var $permalink_structure;
148110
148111 /**
148112 * Whether to add trailing slashes.
148113 *
148114 * @since 2.2.0
148115 * @access private
148116 * @var bool
148117 */
148118 var $use_trailing_slashes;
148119
148120 /**
148121 * Customized or default category permalink base ( example.com/xx/tagname ).
148122 *
148123 * @since 1.5.0
148124 * @access private
148125 * @var string
148126 */
148127 var $category_base;
148128
148129 /**
148130 * Customized or default tag permalink base ( example.com/xx/tagname ).
148131 *
148132 * @since 2.3.0
148133 * @access private
148134 * @var string
148135 */
148136 var $tag_base;
148137
148138 /**
148139 * Permalink request structure for categories.
148140 *
148141 * @since 1.5.0
148142 * @access private
148143 * @var string
148144 */
148145 var $category_structure;
148146
148147 /**
148148 * Permalink request structure for tags.
148149 *
148150 * @since 2.3.0
148151 * @access private
148152 * @var string
148153 */
148154 var $tag_structure;
148155
148156 /**
148157 * Permalink author request base ( example.com/author/authorname ).
148158 *
148159 * @since 1.5.0
148160 * @access private
148161 * @var string
148162 */
148163 var $author_base = 'author';
148164
148165 /**
148166 * Permalink request structure for author pages.
148167 *
148168 * @since 1.5.0
148169 * @access private
148170 * @var string
148171 */
148172 var $author_structure;
148173
148174 /**
148175 * Permalink request structure for dates.
148176 *
148177 * @since 1.5.0
148178 * @access private
148179 * @var string
148180 */
148181 var $date_structure;
148182
148183 /**
148184 * Permalink request structure for pages.
148185 *
148186 * @since 1.5.0
148187 * @access private
148188 * @var string
148189 */
148190 var $page_structure;
148191
148192 /**
148193 * Search permalink base ( example.com/search/query ).
148194 *
148195 * @since 1.5.0
148196 * @access private
148197 * @var string
148198 */
148199 var $search_base = 'search';
148200
148201 /**
148202 * Permalink request structure for searches.
148203 *
148204 * @since 1.5.0
148205 * @access private
148206 * @var string
148207 */
148208 var $search_structure;
148209
148210 /**
148211 * Comments permalink base.
148212 *
148213 * @since 1.5.0
148214 * @access private
148215 * @var string
148216 */
148217 var $comments_base = 'comments';
148218
148219 /**
148220 * Feed permalink base.
148221 *
148222 * @since 1.5.0
148223 * @access private
148224 * @var string
148225 */
148226 var $feed_base = 'feed';
148227
148228 /**
148229 * Comments feed request structure permalink.
148230 *
148231 * @since 1.5.0
148232 * @access private
148233 * @var string
148234 */
148235 var $comments_feed_structure;
148236
148237 /**
148238 * Feed request structure permalink.
148239 *
148240 * @since 1.5.0
148241 * @access private
148242 * @var string
148243 */
148244 var $feed_structure;
148245
148246 /**
148247 * Front URL path.
148248 *
148249 * The difference between the root property is that WordPress might be
148250 * located at example/WordPress/index.php, if permalinks are turned off. The
148251 * WordPress/index.php will be the front portion. If permalinks are turned
148252 * on, this will most likely be empty or not set.
148253 *
148254 * @since 1.5.0
148255 * @access private
148256 * @var string
148257 */
148258 var $front;
148259
148260 /**
148261 * Root URL path to WordPress (without domain).
148262 *
148263 * The difference between front property is that WordPress might be located
148264 * at example.com/WordPress/. The root is the 'WordPress/' portion.
148265 *
148266 * @since 1.5.0
148267 * @access private
148268 * @var string
148269 */
148270 var $root = '';
148271
148272 /**
148273 * Permalink to the home page.
148274 *
148275 * @since 1.5.0
148276 * @access public
148277 * @var string
148278 */
148279 var $index = 'index.php';
148280
148281 /**
148282 * Request match string.
148283 *
148284 * @since 1.5.0
148285 * @access private
148286 * @var string
148287 */
148288 var $matches = '';
148289
148290 /**
148291 * Rewrite rules to match against the request to find the redirect or query.
148292 *
148293 * @since 1.5.0
148294 * @access private
148295 * @var array
148296 */
148297 var $rules;
148298
148299 /**
148300 * Additional rules added external to the rewrite class.
148301 *
148302 * Those not generated by the class, see add_rewrite_rule().
148303 *
148304 * @since 2.1.0
148305 * @access private
148306 * @var array
148307 */
148308 var $extra_rules = array(); //
148309
148310 /**
148311 * Additional rules that belong at the beginning to match first.
148312 *
148313 * Those not generated by the class, see add_rewrite_rule().
148314 *
148315 * @since 2.3.0
148316 * @access private
148317 * @var array
148318 */
148319 var $extra_rules_top = array(); //
148320
148321 /**
148322 * Rules that don't redirect to WP's index.php.
148323 *
148324 * These rules are written to the mod_rewrite portion of the .htaccess.
148325 *
148326 * @since 2.1.0
148327 * @access private
148328 * @var array
148329 */
148330 var $non_wp_rules = array(); //
148331
148332 /**
148333 * Extra permalink structures.
148334 *
148335 * @since 2.1.0
148336 * @access private
148337 * @var array
148338 */
148339 var $extra_permastructs = array();
148340
148341 /**
148342 * Endpoints permalinks
148343 *
148344 * @since unknown
148345 * @access private
148346 * @var array
148347 */
148348 var $endpoints;
148349
148350 /**
148351 * Whether to write every mod_rewrite rule for WordPress.
148352 *
148353 * This is off by default, turning it on might print a lot of rewrite rules
148354 * to the .htaccess file.
148355 *
148356 * @since 2.0.0
148357 * @access public
148358 * @var bool
148359 */
148360 var $use_verbose_rules = false;
148361
148362 /**
148363 * Whether to write every mod_rewrite rule for WordPress pages.
148364 *
148365 * @since 2.5.0
148366 * @access public
148367 * @var bool
148368 */
148369 var $use_verbose_page_rules = true;
148370
148371 /**
148372 * Permalink structure search for preg_replace.
148373 *
148374 * @since 1.5.0
148375 * @access private
148376 * @var array
148377 */
148378 var $rewritecode =
148379 array(
148380 '%year%',
148381 '%monthnum%',
148382 '%day%',
148383 '%hour%',
148384 '%minute%',
148385 '%second%',
148386 '%postname%',
148387 '%post_id%',
148388 '%category%',
148389 '%tag%',
148390 '%author%',
148391 '%pagename%',
148392 '%search%'
148393 );
148394
148395 /**
148396 * Preg_replace values for the search, see {@link WP_Rewrite::$rewritecode}.
148397 *
148398 * @since 1.5.0
148399 * @access private
148400 * @var array
148401 */
148402 var $rewritereplace =
148403 array(
148404 '([0-9]{4})',
148405 '([0-9]{1,2})',
148406 '([0-9]{1,2})',
148407 '([0-9]{1,2})',
148408 '([0-9]{1,2})',
148409 '([0-9]{1,2})',
148410 '([^/]+)',
148411 '([0-9]+)',
148412 '(.+?)',
148413 '(.+?)',
148414 '([^/]+)',
148415 '([^/]+?)',
148416 '(.+)'
148417 );
148418
148419 /**
148420 * Search for the query to look for replacing.
148421 *
148422 * @since 1.5.0
148423 * @access private
148424 * @var array
148425 */
148426 var $queryreplace =
148427 array (
148428 'year=',
148429 'monthnum=',
148430 'day=',
148431 'hour=',
148432 'minute=',
148433 'second=',
148434 'name=',
148435 'p=',
148436 'category_name=',
148437 'tag=',
148438 'author_name=',
148439 'pagename=',
148440 's='
148441 );
148442
148443 /**
148444 * Supported default feeds.
148445 *
148446 * @since 1.5.0
148447 * @access private
148448 * @var array
148449 */
148450 var $feeds = array ( 'feed', 'rdf', 'rss', 'rss2', 'atom' );
148451
148452 /**
148453 * Whether permalinks are being used.
148454 *
148455 * This can be either rewrite module or permalink in the HTTP query string.
148456 *
148457 * @since 1.5.0
148458 * @access public
148459 *
148460 * @return bool True, if permalinks are enabled.
148461 */
148462 function using_permalinks() {
148463 if (empty($this->permalink_structure))
148464 return false;
148465 else
148466 return true;
148467 }
148468
148469 /**
148470 * Whether permalinks are being used and rewrite module is not enabled.
148471 *
148472 * Means that permalink links are enabled and index.php is in the URL.
148473 *
148474 * @since 1.5.0
148475 * @access public
148476 *
148477 * @return bool
148478 */
148479 function using_index_permalinks() {
148480 if (empty($this->permalink_structure)) {
148481 return false;
148482 }
148483
148484 // If the index is not in the permalink, we're using mod_rewrite.
148485 if (preg_match('#^/*' . $this->index . '#', $this->permalink_structure)) {
148486 return true;
148487 }
148488
148489 return false;
148490 }
148491
148492 /**
148493 * Whether permalinks are being used and rewrite module is enabled.
148494 *
148495 * Using permalinks and index.php is not in the URL.
148496 *
148497 * @since 1.5.0
148498 * @access public
148499 *
148500 * @return bool
148501 */
148502 function using_mod_rewrite_permalinks() {
148503 if ( $this->using_permalinks() && ! $this->using_index_permalinks())
148504 return true;
148505 else
148506 return false;
148507 }
148508
148509 /**
148510 * Index for matches for usage in preg_*() functions.
148511 *
148512 * The format of the string is, with empty matches property value, '$NUM'.
148513 * The 'NUM' will be replaced with the value in the $number parameter. With
148514 * the matches property not empty, the value of the returned string will
148515 * contain that value of the matches property. The format then will be
148516 * '$MATCHES[NUM]', with MATCHES as the value in the property and NUM the
148517 * value of the $number parameter.
148518 *
148519 * @since 1.5.0
148520 * @access public
148521 *
148522 * @param int $number Index number.
148523 * @return string
148524 */
148525 function preg_index($number) {
148526 $match_prefix = '$';
148527 $match_suffix = '';
148528
148529 if ( ! empty($this->matches) ) {
148530 $match_prefix = '$' . $this->matches . '[';
148531 $match_suffix = ']';
148532 }
148533
148534 return "$match_prefix$number$match_suffix";
148535 }
148536
148537 /**
148538 * Retrieve all page and attachments for pages URIs.
148539 *
148540 * The attachments are for those that have pages as parents and will be
148541 * retrieved.
148542 *
148543 * @since 2.5.0
148544 * @access public
148545 *
148546 * @return array Array of page URIs as first element and attachment URIs as second element.
148547 */
148548 function page_uri_index() {
148549 global $wpdb;
148550
148551 //get pages in order of hierarchy, i.e. children after parents
148552 $posts = get_page_hierarchy($wpdb->get_results("SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE post_type = 'page'"));
148553 //now reverse it, because we need parents after children for rewrite rules to work properly
148554 $posts = array_reverse($posts, true);
148555
148556 $page_uris = array();
148557 $page_attachment_uris = array();
148558
148559 if ( !$posts )
148560 return array( array(), array() );
148561
148562 foreach ($posts as $id => $post) {
148563 // URL => page name
148564 $uri = get_page_uri($id);
148565 $attachments = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE post_type = 'attachment' AND post_parent = %d", $id ));
148566 if ( $attachments ) {
148567 foreach ( $attachments as $attachment ) {
148568 $attach_uri = get_page_uri($attachment->ID);
148569 $page_attachment_uris[$attach_uri] = $attachment->ID;
148570 }
148571 }
148572
148573 $page_uris[$uri] = $id;
148574 }
148575
148576 return array( $page_uris, $page_attachment_uris );
148577 }
148578
148579 /**
148580 * Retrieve all of the rewrite rules for pages.
148581 *
148582 * If the 'use_verbose_page_rules' property is false, then there will only
148583 * be a single rewrite rule for pages for those matching '%pagename%'. With
148584 * the property set to true, the attachments and the pages will be added for
148585 * each individual attachment URI and page URI, respectively.
148586 *
148587 * @since 1.5.0
148588 * @access public
148589 *
148590 * @return array
148591 */
148592 function page_rewrite_rules() {
148593 $rewrite_rules = array();
148594 $page_structure = $this->get_page_permastruct();
148595
148596 if ( ! $this->use_verbose_page_rules ) {
148597 $this->add_rewrite_tag('%pagename%', "(.+?)", 'pagename=');
148598 $rewrite_rules = array_merge($rewrite_rules, $this->generate_rewrite_rules($page_structure, EP_PAGES));
148599 return $rewrite_rules;
148600 }
148601
148602 $page_uris = $this->page_uri_index();
148603 $uris = $page_uris[0];
148604 $attachment_uris = $page_uris[1];
148605
148606 if( is_array( $attachment_uris ) ) {
148607 foreach ($attachment_uris as $uri => $pagename) {
148608 $this->add_rewrite_tag('%pagename%', "($uri)", 'attachment=');
148609 $rewrite_rules = array_merge($rewrite_rules, $this->generate_rewrite_rules($page_structure, EP_PAGES));
148610 }
148611 }
148612 if( is_array( $uris ) ) {
148613 foreach ($uris as $uri => $pagename) {
148614 $this->add_rewrite_tag('%pagename%', "($uri)", 'pagename=');
148615 $rewrite_rules = array_merge($rewrite_rules, $this->generate_rewrite_rules($page_structure, EP_PAGES));
148616 }
148617 }
148618
148619 return $rewrite_rules;
148620 }
148621
148622 /**
148623 * Retrieve date permalink structure, with year, month, and day.
148624 *
148625 * The permalink structure for the date, if not set already depends on the
148626 * permalink structure. It can be one of three formats. The first is year,
148627 * month, day; the second is day, month, year; and the last format is month,
148628 * day, year. These are matched against the permalink structure for which
148629 * one is used. If none matches, then the default will be used, which is
148630 * year, month, day.
148631 *
148632 * Prevents post ID and date permalinks from overlapping. In the case of
148633 * post_id, the date permalink will be prepended with front permalink with
148634 * 'date/' before the actual permalink to form the complete date permalink
148635 * structure.
148636 *
148637 * @since 1.5.0
148638 * @access public
148639 *
148640 * @return bool|string False on no permalink structure. Date permalink structure.
148641 */
148642 function get_date_permastruct() {
148643 if (isset($this->date_structure)) {
148644 return $this->date_structure;
148645 }
148646
148647 if (empty($this->permalink_structure)) {
148648 $this->date_structure = '';
148649 return false;
148650 }
148651
148652 // The date permalink must have year, month, and day separated by slashes.
148653 $endians = array('%year%/%monthnum%/%day%', '%day%/%monthnum%/%year%', '%monthnum%/%day%/%year%');
148654
148655 $this->date_structure = '';
148656 $date_endian = '';
148657
148658 foreach ($endians as $endian) {
148659 if (false !== strpos($this->permalink_structure, $endian)) {
148660 $date_endian= $endian;
148661 break;
148662 }
148663 }
148664
148665 if ( empty($date_endian) )
148666 $date_endian = '%year%/%monthnum%/%day%';
148667
148668 // Do not allow the date tags and %post_id% to overlap in the permalink
148669 // structure. If they do, move the date tags to $front/date/.
148670 $front = $this->front;
148671 preg_match_all('/%.+?%/', $this->permalink_structure, $tokens);
148672 $tok_index = 1;
148673 foreach ( (array) $tokens[0] as $token) {
148674 if ( ($token == '%post_id%') && ($tok_index <= 3) ) {
148675 $front = $front . 'date/';
148676 break;
148677 }
148678 $tok_index++;
148679 }
148680
148681 $this->date_structure = $front . $date_endian;
148682
148683 return $this->date_structure;
148684 }
148685
148686 /**
148687 * Retrieve the year permalink structure without month and day.
148688 *
148689 * Gets the date permalink structure and strips out the month and day
148690 * permalink structures.
148691 *
148692 * @since 1.5.0
148693 * @access public
148694 *
148695 * @return bool|string False on failure. Year structure on success.
148696 */
148697 function get_year_permastruct() {
148698 $structure = $this->get_date_permastruct($this->permalink_structure);
148699
148700 if (empty($structure)) {
148701 return false;
148702 }
148703
148704 $structure = str_replace('%monthnum%', '', $structure);
148705 $structure = str_replace('%day%', '', $structure);
148706
148707 $structure = preg_replace('#/+#', '/', $structure);
148708
148709 return $structure;
148710 }
148711
148712 /**
148713 * Retrieve the month permalink structure without day and with year.
148714 *
148715 * Gets the date permalink structure and strips out the day permalink
148716 * structures. Keeps the year permalink structure.
148717 *
148718 * @since 1.5.0
148719 * @access public
148720 *
148721 * @return bool|string False on failure. Year/Month structure on success.
148722 */
148723 function get_month_permastruct() {
148724 $structure = $this->get_date_permastruct($this->permalink_structure);
148725
148726 if (empty($structure)) {
148727 return false;
148728 }
148729
148730 $structure = str_replace('%day%', '', $structure);
148731
148732 $structure = preg_replace('#/+#', '/', $structure);
148733
148734 return $structure;
148735 }
148736
148737 /**
148738 * Retrieve the day permalink structure with month and year.
148739 *
148740 * Keeps date permalink structure with all year, month, and day.
148741 *
148742 * @since 1.5.0
148743 * @access public
148744 *
148745 * @return bool|string False on failure. Year/Month/Day structure on success.
148746 */
148747 function get_day_permastruct() {
148748 return $this->get_date_permastruct($this->permalink_structure);
148749 }
148750
148751 /**
148752 * Retrieve the permalink structure for categories.
148753 *
148754 * If the category_base property has no value, then the category structure
148755 * will have the front property value, followed by 'category', and finally
148756 * '%category%'. If it does, then the root property will be used, along with
148757 * the category_base property value.
148758 *
148759 * @since 1.5.0
148760 * @access public
148761 *
148762 * @return bool|string False on failure. Category permalink structure.
148763 */
148764 function get_category_permastruct() {
148765 if (isset($this->category_structure)) {
148766 return $this->category_structure;
148767 }
148768
148769 if (empty($this->permalink_structure)) {
148770 $this->category_structure = '';
148771 return false;
148772 }
148773
148774 if (empty($this->category_base))
148775 $this->category_structure = trailingslashit( $this->front . 'category' );
148776 else
148777 $this->category_structure = trailingslashit( '/' . $this->root . $this->category_base );
148778
148779 $this->category_structure .= '%category%';
148780
148781 return $this->category_structure;
148782 }
148783
148784 /**
148785 * Retrieve the permalink structure for tags.
148786 *
148787 * If the tag_base property has no value, then the tag structure will have
148788 * the front property value, followed by 'tag', and finally '%tag%'. If it
148789 * does, then the root property will be used, along with the tag_base
148790 * property value.
148791 *
148792 * @since 2.3.0
148793 * @access public
148794 *
148795 * @return bool|string False on failure. Tag permalink structure.
148796 */
148797 function get_tag_permastruct() {
148798 if (isset($this->tag_structure)) {
148799 return $this->tag_structure;
148800 }
148801
148802 if (empty($this->permalink_structure)) {
148803 $this->tag_structure = '';
148804 return false;
148805 }
148806
148807 if (empty($this->tag_base))
148808 $this->tag_structure = trailingslashit( $this->front . 'tag' );
148809 else
148810 $this->tag_structure = trailingslashit( '/' . $this->root . $this->tag_base );
148811
148812 $this->tag_structure .= '%tag%';
148813
148814 return $this->tag_structure;
148815 }
148816
148817 /**
148818 * Retrieve extra permalink structure by name.
148819 *
148820 * @since unknown
148821 * @access public
148822 *
148823 * @param string $name Permalink structure name.
148824 * @return string|bool False if not found. Permalink structure string.
148825 */
148826 function get_extra_permastruct($name) {
148827 if ( isset($this->extra_permastructs[$name]) )
148828 return $this->extra_permastructs[$name];
148829 return false;
148830 }
148831
148832 /**
148833 * Retrieve the author permalink structure.
148834 *
148835 * The permalink structure is front property, author base, and finally
148836 * '/%author%'. Will set the author_structure property and then return it
148837 * without attempting to set the value again.
148838 *
148839 * @since 1.5.0
148840 * @access public
148841 *
148842 * @return string|bool False if not found. Permalink structure string.
148843 */
148844 function get_author_permastruct() {
148845 if (isset($this->author_structure)) {
148846 return $this->author_structure;
148847 }
148848
148849 if (empty($this->permalink_structure)) {
148850 $this->author_structure = '';
148851 return false;
148852 }
148853
148854 $this->author_structure = $this->front . $this->author_base . '/%author%';
148855
148856 return $this->author_structure;
148857 }
148858
148859 /**
148860 * Retrieve the search permalink structure.
148861 *
148862 * The permalink structure is root property, search base, and finally
148863 * '/%search%'. Will set the search_structure property and then return it
148864 * without attempting to set the value again.
148865 *
148866 * @since 1.5.0
148867 * @access public
148868 *
148869 * @return string|bool False if not found. Permalink structure string.
148870 */
148871 function get_search_permastruct() {
148872 if (isset($this->search_structure)) {
148873 return $this->search_structure;
148874 }
148875
148876 if (empty($this->permalink_structure)) {
148877 $this->search_structure = '';
148878 return false;
148879 }
148880
148881 $this->search_structure = $this->root . $this->search_base . '/%search%';
148882
148883 return $this->search_structure;
148884 }
148885
148886 /**
148887 * Retrieve the page permalink structure.
148888 *
148889 * The permalink structure is root property, and '%pagename%'. Will set the
148890 * page_structure property and then return it without attempting to set the
148891 * value again.
148892 *
148893 * @since 1.5.0
148894 * @access public
148895 *
148896 * @return string|bool False if not found. Permalink structure string.
148897 */
148898 function get_page_permastruct() {
148899 if (isset($this->page_structure)) {
148900 return $this->page_structure;
148901 }
148902
148903 if (empty($this->permalink_structure)) {
148904 $this->page_structure = '';
148905 return false;
148906 }
148907
148908 $this->page_structure = $this->root . '%pagename%';
148909
148910 return $this->page_structure;
148911 }
148912
148913 /**
148914 * Retrieve the feed permalink structure.
148915 *
148916 * The permalink structure is root property, feed base, and finally
148917 * '/%feed%'. Will set the feed_structure property and then return it
148918 * without attempting to set the value again.
148919 *
148920 * @since 1.5.0
148921 * @access public
148922 *
148923 * @return string|bool False if not found. Permalink structure string.
148924 */
148925 function get_feed_permastruct() {
148926 if (isset($this->feed_structure)) {
148927 return $this->feed_structure;
148928 }
148929
148930 if (empty($this->permalink_structure)) {
148931 $this->feed_structure = '';
148932 return false;
148933 }
148934
148935 $this->feed_structure = $this->root . $this->feed_base . '/%feed%';
148936
148937 return $this->feed_structure;
148938 }
148939
148940 /**
148941 * Retrieve the comment feed permalink structure.
148942 *
148943 * The permalink structure is root property, comment base property, feed
148944 * base and finally '/%feed%'. Will set the comment_feed_structure property
148945 * and then return it without attempting to set the value again.
148946 *
148947 * @since 1.5.0
148948 * @access public
148949 *
148950 * @return string|bool False if not found. Permalink structure string.
148951 */
148952 function get_comment_feed_permastruct() {
148953 if (isset($this->comment_feed_structure)) {
148954 return $this->comment_feed_structure;
148955 }
148956
148957 if (empty($this->permalink_structure)) {
148958 $this->comment_feed_structure = '';
148959 return false;
148960 }
148961
148962 $this->comment_feed_structure = $this->root . $this->comments_base . '/' . $this->feed_base . '/%feed%';
148963
148964 return $this->comment_feed_structure;
148965 }
148966
148967 /**
148968 * Append or update tag, pattern, and query for replacement.
148969 *
148970 * If the tag already exists, replace the existing pattern and query for
148971 * that tag, otherwise add the new tag, pattern, and query to the end of the
148972 * arrays.
148973 *
148974 * @internal What is the purpose of this function again? Need to finish long
148975 * description.
148976 *
148977 * @since 1.5.0
148978 * @access public
148979 *
148980 * @param string $tag Append tag to rewritecode property array.
148981 * @param string $pattern Append pattern to rewritereplace property array.
148982 * @param string $query Append query to queryreplace property array.
148983 */
148984 function add_rewrite_tag($tag, $pattern, $query) {
148985 $position = array_search($tag, $this->rewritecode);
148986 if ( false !== $position && null !== $position ) {
148987 $this->rewritereplace[$position] = $pattern;
148988 $this->queryreplace[$position] = $query;
148989 } else {
148990 $this->rewritecode[] = $tag;
148991 $this->rewritereplace[] = $pattern;
148992 $this->queryreplace[] = $query;
148993 }
148994 }
148995
148996 /**
148997 * Generate the rules from permalink structure.
148998 *
148999 * The main WP_Rewrite function for building the rewrite rule list. The
149000 * contents of the function is a mix of black magic and regular expressions,
149001 * so best just ignore the contents and move to the parameters.
149002 *
149003 * @since 1.5.0
149004 * @access public
149005 *
149006 * @param string $permalink_structure The permalink structure.
149007 * @param int $ep_mask Optional, default is EP_NONE. Endpoint constant, see EP_* constants.
149008 * @param bool $paged Optional, default is true. Whether permalink request is paged.
149009 * @param bool $feed Optional, default is true. Whether for feed.
149010 * @param bool $forcomments Optional, default is false. Whether for comments.
149011 * @param bool $walk_dirs Optional, default is true. Whether to create list of directories to walk over.
149012 * @param bool $endpoints Optional, default is true. Whether endpoints are enabled.
149013 * @return array Rewrite rule list.
149014 */
149015 function generate_rewrite_rules($permalink_structure, $ep_mask = EP_NONE, $paged = true, $feed = true, $forcomments = false, $walk_dirs = true, $endpoints = true) {
149016 //build a regex to match the feed section of URLs, something like (feed|atom|rss|rss2)/?
149017 $feedregex2 = '';
149018 foreach ( (array) $this->feeds as $feed_name) {
149019 $feedregex2 .= $feed_name . '|';
149020 }
149021 $feedregex2 = '(' . trim($feedregex2, '|') . ')/?$';
149022 //$feedregex is identical but with /feed/ added on as well, so URLs like <permalink>/feed/atom
149023 //and <permalink>/atom are both possible
149024 $feedregex = $this->feed_base . '/' . $feedregex2;
149025
149026 //build a regex to match the trackback and page/xx parts of URLs
149027 $trackbackregex = 'trackback/?$';
149028 $pageregex = 'page/?([0-9]{1,})/?$';
149029 $commentregex = 'comment-page-([0-9]{1,})/?$';
149030
149031 //build up an array of endpoint regexes to append => queries to append
149032 if ($endpoints) {
149033 $ep_query_append = array ();
149034 foreach ( (array) $this->endpoints as $endpoint) {
149035 //match everything after the endpoint name, but allow for nothing to appear there
149036 $epmatch = $endpoint[1] . '(/(.*))?/?$';
149037 //this will be appended on to the rest of the query for each dir
149038 $epquery = '&' . $endpoint[1] . '=';
149039 $ep_query_append[$epmatch] = array ( $endpoint[0], $epquery );
149040 }
149041 }
149042
149043 //get everything up to the first rewrite tag
149044 $front = substr($permalink_structure, 0, strpos($permalink_structure, '%'));
149045 //build an array of the tags (note that said array ends up being in $tokens[0])
149046 preg_match_all('/%.+?%/', $permalink_structure, $tokens);
149047
149048 $num_tokens = count($tokens[0]);
149049
149050 $index = $this->index; //probably 'index.php'
149051 $feedindex = $index;
149052 $trackbackindex = $index;
149053 //build a list from the rewritecode and queryreplace arrays, that will look something like
149054 //tagname=$matches[i] where i is the current $i
149055 for ($i = 0; $i < $num_tokens; ++$i) {
149056 if (0 < $i) {
149057 $queries[$i] = $queries[$i - 1] . '&';
149058 } else {
149059 $queries[$i] = '';
149060 }
149061
149062 $query_token = str_replace($this->rewritecode, $this->queryreplace, $tokens[0][$i]) . $this->preg_index($i+1);
149063 $queries[$i] .= $query_token;
149064 }
149065
149066 //get the structure, minus any cruft (stuff that isn't tags) at the front
149067 $structure = $permalink_structure;
149068 if ($front != '/') {
149069 $structure = str_replace($front, '', $structure);
149070 }
149071 //create a list of dirs to walk over, making rewrite rules for each level
149072 //so for example, a $structure of /%year%/%month%/%postname% would create
149073 //rewrite rules for /%year%/, /%year%/%month%/ and /%year%/%month%/%postname%
149074 $structure = trim($structure, '/');
149075 if ($walk_dirs) {
149076 $dirs = explode('/', $structure);
149077 } else {
149078 $dirs[] = $structure;
149079 }
149080 $num_dirs = count($dirs);
149081
149082 //strip slashes from the front of $front
149083 $front = preg_replace('|^/+|', '', $front);
149084
149085 //the main workhorse loop
149086 $post_rewrite = array();
149087 $struct = $front;
149088 for ($j = 0; $j < $num_dirs; ++$j) {
149089 //get the struct for this dir, and trim slashes off the front
149090 $struct .= $dirs[$j] . '/'; //accumulate. see comment near explode('/', $structure) above
149091 $struct = ltrim($struct, '/');
149092 //replace tags with regexes
149093 $match = str_replace($this->rewritecode, $this->rewritereplace, $struct);
149094 //make a list of tags, and store how many there are in $num_toks
149095 $num_toks = preg_match_all('/%.+?%/', $struct, $toks);
149096 //get the 'tagname=$matches[i]'
149097 $query = ( isset($queries) && is_array($queries) ) ? $queries[$num_toks - 1] : '';
149098
149099 //set up $ep_mask_specific which is used to match more specific URL types
149100 switch ($dirs[$j]) {
149101 case '%year%': $ep_mask_specific = EP_YEAR; break;
149102 case '%monthnum%': $ep_mask_specific = EP_MONTH; break;
149103 case '%day%': $ep_mask_specific = EP_DAY; break;
149104 }
149105
149106 //create query for /page/xx
149107 $pagematch = $match . $pageregex;
149108 $pagequery = $index . '?' . $query . '&paged=' . $this->preg_index($num_toks + 1);
149109
149110 //create query for /comment-page-xx
149111 $commentmatch = $match . $commentregex;
149112 $commentquery = $index . '?' . $query . '&cpage=' . $this->preg_index($num_toks + 1);
149113
149114 //create query for /feed/(feed|atom|rss|rss2|rdf)
149115 $feedmatch = $match . $feedregex;
149116 $feedquery = $feedindex . '?' . $query . '&feed=' . $this->preg_index($num_toks + 1);
149117
149118 //create query for /(feed|atom|rss|rss2|rdf) (see comment near creation of $feedregex)
149119 $feedmatch2 = $match . $feedregex2;
149120 $feedquery2 = $feedindex . '?' . $query . '&feed=' . $this->preg_index($num_toks + 1);
149121
149122 //if asked to, turn the feed queries into comment feed ones
149123 if ($forcomments) {
149124 $feedquery .= '&withcomments=1';
149125 $feedquery2 .= '&withcomments=1';
149126 }
149127
149128 //start creating the array of rewrites for this dir
149129 $rewrite = array();
149130 if ($feed) //...adding on /feed/ regexes => queries
149131 $rewrite = array($feedmatch => $feedquery, $feedmatch2 => $feedquery2);
149132 if ($paged) //...and /page/xx ones
149133 $rewrite = array_merge($rewrite, array($pagematch => $pagequery));
149134
149135 //only on pages with comments add ../comment-page-xx/
149136 if ( EP_PAGES & $ep_mask || EP_PERMALINK & $ep_mask || EP_NONE & $ep_mask )
149137 $rewrite = array_merge($rewrite, array($commentmatch => $commentquery));
149138
149139 //do endpoints
149140 if ($endpoints) {
149141 foreach ( (array) $ep_query_append as $regex => $ep) {
149142 //add the endpoints on if the mask fits
149143 if ($ep[0] & $ep_mask || $ep[0] & $ep_mask_specific) {
149144 $rewrite[$match . $regex] = $index . '?' . $query . $ep[1] . $this->preg_index($num_toks + 2);
149145 }
149146 }
149147 }
149148
149149 //if we've got some tags in this dir
149150 if ($num_toks) {
149151 $post = false;
149152 $page = false;
149153
149154 //check to see if this dir is permalink-level: i.e. the structure specifies an
149155 //individual post. Do this by checking it contains at least one of 1) post name,
149156 //2) post ID, 3) page name, 4) timestamp (year, month, day, hour, second and
149157 //minute all present). Set these flags now as we need them for the endpoints.
149158 if (strpos($struct, '%postname%') !== false || strpos($struct, '%post_id%') !== false
149159 || strpos($struct, '%pagename%') !== false
149160 || (strpos($struct, '%year%') !== false && strpos($struct, '%monthnum%') !== false && strpos($struct, '%day%') !== false && strpos($struct, '%hour%') !== false && strpos($struct, '%minute%') !== false && strpos($struct, '%second%') !== false)) {
149161 $post = true;
149162 if (strpos($struct, '%pagename%') !== false)
149163 $page = true;
149164 }
149165
149166 //if we're creating rules for a permalink, do all the endpoints like attachments etc
149167 if ($post) {
149168 $post = true;
149169 //create query and regex for trackback
149170 $trackbackmatch = $match . $trackbackregex;
149171 $trackbackquery = $trackbackindex . '?' . $query . '&tb=1';
149172 //trim slashes from the end of the regex for this dir
149173 $match = rtrim($match, '/');
149174 //get rid of brackets
149175 $submatchbase = str_replace(array('(',')'),'',$match);
149176
149177 //add a rule for at attachments, which take the form of <permalink>/some-text
149178 $sub1 = $submatchbase . '/([^/]+)/';
149179 $sub1tb = $sub1 . $trackbackregex; //add trackback regex <permalink>/trackback/...
149180 $sub1feed = $sub1 . $feedregex; //and <permalink>/feed/(atom|...)
149181 $sub1feed2 = $sub1 . $feedregex2; //and <permalink>/(feed|atom...)
149182 $sub1comment = $sub1 . $commentregex; //and <permalink>/comment-page-xx
149183 //add an ? as we don't have to match that last slash, and finally a $ so we
149184 //match to the end of the URL
149185
149186 //add another rule to match attachments in the explicit form:
149187 //<permalink>/attachment/some-text
149188 $sub2 = $submatchbase . '/attachment/([^/]+)/';
149189 $sub2tb = $sub2 . $trackbackregex; //and add trackbacks <permalink>/attachment/trackback
149190 $sub2feed = $sub2 . $feedregex; //feeds, <permalink>/attachment/feed/(atom|...)
149191 $sub2feed2 = $sub2 . $feedregex2; //and feeds again on to this <permalink>/attachment/(feed|atom...)
149192 $sub2comment = $sub2 . $commentregex; //and <permalink>/comment-page-xx
149193
149194 //create queries for these extra tag-ons we've just dealt with
149195 $subquery = $index . '?attachment=' . $this->preg_index(1);
149196 $subtbquery = $subquery . '&tb=1';
149197 $subfeedquery = $subquery . '&feed=' . $this->preg_index(2);
149198 $subcommentquery = $subquery . '&cpage=' . $this->preg_index(2);
149199
149200 //do endpoints for attachments
149201 if ( !empty($endpoint) ) { foreach ( (array) $ep_query_append as $regex => $ep ) {
149202 if ($ep[0] & EP_ATTACHMENT) {
149203 $rewrite[$sub1 . $regex] = $subquery . '?' . $ep[1] . $this->preg_index(2);
149204 $rewrite[$sub2 . $regex] = $subquery . '?' . $ep[1] . $this->preg_index(2);
149205 }
149206 } }
149207
149208 //now we've finished with endpoints, finish off the $sub1 and $sub2 matches
149209 $sub1 .= '?$';
149210 $sub2 .= '?$';
149211
149212 //allow URLs like <permalink>/2 for <permalink>/page/2
149213 $match = $match . '(/[0-9]+)?/?$';
149214 $query = $index . '?' . $query . '&page=' . $this->preg_index($num_toks + 1);
149215 } else { //not matching a permalink so this is a lot simpler
149216 //close the match and finalise the query
149217 $match .= '?$';
149218 $query = $index . '?' . $query;
149219 }
149220
149221 //create the final array for this dir by joining the $rewrite array (which currently
149222 //only contains rules/queries for trackback, pages etc) to the main regex/query for
149223 //this dir
149224 $rewrite = array_merge($rewrite, array($match => $query));
149225
149226 //if we're matching a permalink, add those extras (attachments etc) on
149227 if ($post) {
149228 //add trackback
149229 $rewrite = array_merge(array($trackbackmatch => $trackbackquery), $rewrite);
149230
149231 //add regexes/queries for attachments, attachment trackbacks and so on
149232 if ( ! $page ) //require <permalink>/attachment/stuff form for pages because of confusion with subpages
149233 $rewrite = array_merge($rewrite, array($sub1 => $subquery, $sub1tb => $subtbquery, $sub1feed => $subfeedquery, $sub1feed2 => $subfeedquery, $sub1comment => $subcommentquery));
149234 $rewrite = array_merge(array($sub2 => $subquery, $sub2tb => $subtbquery, $sub2feed => $subfeedquery, $sub2feed2 => $subfeedquery, $sub2comment => $subcommentquery), $rewrite);
149235 }
149236 } //if($num_toks)
149237 //add the rules for this dir to the accumulating $post_rewrite
149238 $post_rewrite = array_merge($rewrite, $post_rewrite);
149239 } //foreach ($dir)
149240 return $post_rewrite; //the finished rules. phew!
149241 }
149242
149243 /**
149244 * Generate Rewrite rules with permalink structure and walking directory only.
149245 *
149246 * Shorten version of {@link WP_Rewrite::generate_rewrite_rules()} that
149247 * allows for shorter list of parameters. See the method for longer
149248 * description of what generating rewrite rules does.
149249 *
149250 * @uses WP_Rewrite::generate_rewrite_rules() See for long description and rest of parameters.
149251 * @since 1.5.0
149252 * @access public
149253 *
149254 * @param string $permalink_structure The permalink structure to generate rules.
149255 * @param bool $walk_dirs Optional, default is false. Whether to create list of directories to walk over.
149256 * @return array
149257 */
149258 function generate_rewrite_rule($permalink_structure, $walk_dirs = false) {
149259 return $this->generate_rewrite_rules($permalink_structure, EP_NONE, false, false, false, $walk_dirs);
149260 }
149261
149262 /**
149263 * Construct rewrite matches and queries from permalink structure.
149264 *
149265 * Runs the action 'generate_rewrite_rules' with the parameter that is an
149266 * reference to the current WP_Rewrite instance to further manipulate the
149267 * permalink structures and rewrite rules. Runs the 'rewrite_rules_array'
149268 * filter on the full rewrite rule array.
149269 *
149270 * There are two ways to manipulate the rewrite rules, one by hooking into
149271 * the 'generate_rewrite_rules' action and gaining full control of the
149272 * object or just manipulating the rewrite rule array before it is passed
149273 * from the function.
149274 *
149275 * @since 1.5.0
149276 * @access public
149277 *
149278 * @return array An associate array of matches and queries.
149279 */
149280 function rewrite_rules() {
149281 $rewrite = array();
149282
149283 if (empty($this->permalink_structure)) {
149284 return $rewrite;
149285 }
149286
149287 // robots.txt
149288 $robots_rewrite = array('robots\.txt$' => $this->index . '?robots=1');
149289
149290 //Default Feed rules - These are require to allow for the direct access files to work with permalink structure starting with %category%
149291 $default_feeds = array( '.*wp-atom.php$' => $this->index .'?feed=atom',
149292 '.*wp-rdf.php$' => $this->index .'?feed=rdf',
149293 '.*wp-rss.php$' => $this->index .'?feed=rss',
149294 '.*wp-rss2.php$' => $this->index .'?feed=rss2',
149295 '.*wp-feed.php$' => $this->index .'?feed=feed',
149296 '.*wp-commentsrss2.php$' => $this->index . '?feed=rss2&withcomments=1');
149297
149298 // Post
149299 $post_rewrite = $this->generate_rewrite_rules($this->permalink_structure, EP_PERMALINK);
149300 $post_rewrite = apply_filters('post_rewrite_rules', $post_rewrite);
149301
149302 // Date
149303 $date_rewrite = $this->generate_rewrite_rules($this->get_date_permastruct(), EP_DATE);
149304 $date_rewrite = apply_filters('date_rewrite_rules', $date_rewrite);
149305
149306 // Root
149307 $root_rewrite = $this->generate_rewrite_rules($this->root . '/', EP_ROOT);
149308 $root_rewrite = apply_filters('root_rewrite_rules', $root_rewrite);
149309
149310 // Comments
149311 $comments_rewrite = $this->generate_rewrite_rules($this->root . $this->comments_base, EP_COMMENTS, true, true, true, false);
149312 $comments_rewrite = apply_filters('comments_rewrite_rules', $comments_rewrite);
149313
149314 // Search
149315 $search_structure = $this->get_search_permastruct();
149316 $search_rewrite = $this->generate_rewrite_rules($search_structure, EP_SEARCH);
149317 $search_rewrite = apply_filters('search_rewrite_rules', $search_rewrite);
149318
149319 // Categories
149320 $category_rewrite = $this->generate_rewrite_rules($this->get_category_permastruct(), EP_CATEGORIES);
149321 $category_rewrite = apply_filters('category_rewrite_rules', $category_rewrite);
149322
149323 // Tags
149324 $tag_rewrite = $this->generate_rewrite_rules($this->get_tag_permastruct(), EP_TAGS);
149325 $tag_rewrite = apply_filters('tag_rewrite_rules', $tag_rewrite);
149326
149327 // Authors
149328 $author_rewrite = $this->generate_rewrite_rules($this->get_author_permastruct(), EP_AUTHORS);
149329 $author_rewrite = apply_filters('author_rewrite_rules', $author_rewrite);
149330
149331 // Pages
149332 $page_rewrite = $this->page_rewrite_rules();
149333 $page_rewrite = apply_filters('page_rewrite_rules', $page_rewrite);
149334
149335 // Extra permastructs
149336 foreach ( $this->extra_permastructs as $permastruct )
149337 $this->extra_rules_top = array_merge($this->extra_rules_top, $this->generate_rewrite_rules($permastruct, EP_NONE));
149338
149339 // Put them together.
149340 if ( $this->use_verbose_page_rules )
149341 $this->rules = array_merge($this->extra_rules_top, $robots_rewrite, $default_feeds, $page_rewrite, $root_rewrite, $comments_rewrite, $search_rewrite, $category_rewrite, $tag_rewrite, $author_rewrite, $date_rewrite, $post_rewrite, $this->extra_rules);
149342 else
149343 $this->rules = array_merge($this->extra_rules_top, $robots_rewrite, $default_feeds, $root_rewrite, $comments_rewrite, $search_rewrite, $category_rewrite, $tag_rewrite, $author_rewrite, $date_rewrite, $post_rewrite, $page_rewrite, $this->extra_rules);
149344
149345 do_action_ref_array('generate_rewrite_rules', array(&$this));
149346 $this->rules = apply_filters('rewrite_rules_array', $this->rules);
149347
149348 return $this->rules;
149349 }
149350
149351 /**
149352 * Retrieve the rewrite rules.
149353 *
149354 * The difference between this method and {@link
149355 * WP_Rewrite::rewrite_rules()} is that this method stores the rewrite rules
149356 * in the 'rewrite_rules' option and retrieves it. This prevents having to
149357 * process all of the permalinks to get the rewrite rules in the form of
149358 * caching.
149359 *
149360 * @since 1.5.0
149361 * @access public
149362 *
149363 * @return array Rewrite rules.
149364 */
149365 function wp_rewrite_rules() {
149366 $this->rules = get_option('rewrite_rules');
149367 if ( empty($this->rules) ) {
149368 $this->matches = 'matches';
149369 $this->rewrite_rules();
149370 update_option('rewrite_rules', $this->rules);
149371 }
149372
149373 return $this->rules;
149374 }
149375
149376 /**
149377 * Retrieve mod_rewrite formatted rewrite rules to write to .htaccess.
149378 *
149379 * Does not actually write to the .htaccess file, but creates the rules for
149380 * the process that will.
149381 *
149382 * Will add the non_wp_rules property rules to the .htaccess file before
149383 * the WordPress rewrite rules one.
149384 *
149385 * @since 1.5.0
149386 * @access public
149387 *
149388 * @return string
149389 */
149390 function mod_rewrite_rules() {
149391 if ( ! $this->using_permalinks()) {
149392 return '';
149393 }
149394
149395 $site_root = parse_url(get_option('siteurl'));
149396 if ( isset( $site_root['path'] ) ) {
149397 $site_root = trailingslashit($site_root['path']);
149398 }
149399
149400 $home_root = parse_url(get_option('home'));
149401 if ( isset( $home_root['path'] ) ) {
149402 $home_root = trailingslashit($home_root['path']);
149403 } else {
149404 $home_root = '/';
149405 }
149406
149407 $rules = "<IfModule mod_rewrite.c>\n";
149408 $rules .= "RewriteEngine On\n";
149409 $rules .= "RewriteBase $home_root\n";
149410
149411 //add in the rules that don't redirect to WP's index.php (and thus shouldn't be handled by WP at all)
149412 foreach ( (array) $this->non_wp_rules as $match => $query) {
149413 // Apache 1.3 does not support the reluctant (non-greedy) modifier.
149414 $match = str_replace('.+?', '.+', $match);
149415
149416 // If the match is unanchored and greedy, prepend rewrite conditions
149417 // to avoid infinite redirects and eclipsing of real files.
149418 if ($match == '(.+)/?$' || $match == '([^/]+)/?$' ) {
149419 //nada.
149420 }
149421
149422 $rules .= 'RewriteRule ^' . $match . ' ' . $home_root . $query . " [QSA,L]\n";
149423 }
149424
149425 if ($this->use_verbose_rules) {
149426 $this->matches = '';
149427 $rewrite = $this->rewrite_rules();
149428 $num_rules = count($rewrite);
149429 $rules .= "RewriteCond %{REQUEST_FILENAME} -f [OR]\n" .
149430 "RewriteCond %{REQUEST_FILENAME} -d\n" .
149431 "RewriteRule ^.*$ - [S=$num_rules]\n";
149432
149433 foreach ( (array) $rewrite as $match => $query) {
149434 // Apache 1.3 does not support the reluctant (non-greedy) modifier.
149435 $match = str_replace('.+?', '.+', $match);
149436
149437 // If the match is unanchored and greedy, prepend rewrite conditions
149438 // to avoid infinite redirects and eclipsing of real files.
149439 if ($match == '(.+)/?$' || $match == '([^/]+)/?$' ) {
149440 //nada.
149441 }
149442
149443 if (strpos($query, $this->index) !== false) {
149444 $rules .= 'RewriteRule ^' . $match . ' ' . $home_root . $query . " [QSA,L]\n";
149445 } else {
149446 $rules .= 'RewriteRule ^' . $match . ' ' . $site_root . $query . " [QSA,L]\n";
149447 }
149448 }
149449 } else {
149450 $rules .= "RewriteCond %{REQUEST_FILENAME} !-f\n" .
149451 "RewriteCond %{REQUEST_FILENAME} !-d\n" .
149452 "RewriteRule . {$home_root}{$this->index} [L]\n";
149453 }
149454
149455 $rules .= "</IfModule>\n";
149456
149457 $rules = apply_filters('mod_rewrite_rules', $rules);
149458 $rules = apply_filters('rewrite_rules', $rules); // Deprecated
149459
149460 return $rules;
149461 }
149462
149463 /**
149464 * Add a straight rewrite rule.
149465 *
149466 * Any value in the $after parameter that isn't 'bottom' will be placed at
149467 * the top of the rules.
149468 *
149469 * @since 2.1.0
149470 * @access public
149471 *
149472 * @param string $regex Regular expression to match against request.
149473 * @param string $redirect URL regex redirects to when regex matches request.
149474 * @param string $after Optional, default is bottom. Location to place rule.
149475 */
149476 function add_rule($regex, $redirect, $after = 'bottom') {
149477 //get everything up to the first ?
149478 $index = (strpos($redirect, '?') == false ? strlen($redirect) : strpos($redirect, '?'));
149479 $front = substr($redirect, 0, $index);
149480 if ($front != $this->index) { //it doesn't redirect to WP's index.php
149481 $this->add_external_rule($regex, $redirect);
149482 } else {
149483 if ( 'bottom' == $after)
149484 $this->extra_rules = array_merge($this->extra_rules, array($regex => $redirect));
149485 else
149486 $this->extra_rules_top = array_merge($this->extra_rules_top, array($regex => $redirect));
149487 //$this->extra_rules[$regex] = $redirect;
149488 }
149489 }
149490
149491 /**
149492 * Add a rule that doesn't redirect to index.php.
149493 *
149494 * Can redirect to any place.
149495 *
149496 * @since 2.1.0
149497 * @access public
149498 *
149499 * @param string $regex Regular expression to match against request.
149500 * @param string $redirect URL regex redirects to when regex matches request.
149501 */
149502 function add_external_rule($regex, $redirect) {
149503 $this->non_wp_rules[$regex] = $redirect;
149504 }
149505
149506 /**
149507 * Add an endpoint, like /trackback/.
149508 *
149509 * To be inserted after certain URL types (specified in $places).
149510 *
149511 * @since 2.1.0
149512 * @access public
149513 *
149514 * @param string $name Name of endpoint.
149515 * @param array $places URL types that endpoint can be used.
149516 */
149517 function add_endpoint($name, $places) {
149518 global $wp;
149519 $this->endpoints[] = array ( $places, $name );
149520 $wp->add_query_var($name);
149521 }
149522
149523 /**
149524 * Add permalink structure.
149525 *
149526 * These are added along with the extra rewrite rules that are merged to the
149527 * top.
149528 *
149529 * @since unknown
149530 * @access public
149531 *
149532 * @param string $name Name for permalink structure.
149533 * @param string $struct Permalink structure.
149534 * @param bool $with_front Prepend front base to permalink structure.
149535 */
149536 function add_permastruct($name, $struct, $with_front = true) {
149537 if ( $with_front )
149538 $struct = $this->front . $struct;
149539 $this->extra_permastructs[$name] = $struct;
149540 }
149541
149542 /**
149543 * Remove rewrite rules and then recreate rewrite rules.
149544 *
149545 * Calls {@link WP_Rewrite::wp_rewrite_rules()} after removing the
149546 * 'rewrite_rules' option. If the function named 'save_mod_rewrite_rules'
149547 * exists, it will be called.
149548 *
149549 * @since 2.0.1
149550 * @access public
149551 */
149552 function flush_rules() {
149553 delete_option('rewrite_rules');
149554 $this->wp_rewrite_rules();
149555 if ( function_exists('save_mod_rewrite_rules') )
149556 save_mod_rewrite_rules();
149557 }
149558
149559 /**
149560 * Sets up the object's properties.
149561 *
149562 * The 'use_verbose_page_rules' object property will be turned on, if the
149563 * permalink structure includes the following: '%postname%', '%category%',
149564 * '%tag%', or '%author%'.
149565 *
149566 * @since 1.5.0
149567 * @access public
149568 */
149569 function init() {
149570 $this->extra_rules = $this->non_wp_rules = $this->endpoints = array();
149571 $this->permalink_structure = get_option('permalink_structure');
149572 $this->front = substr($this->permalink_structure, 0, strpos($this->permalink_structure, '%'));
149573 $this->root = '';
149574 if ($this->using_index_permalinks()) {
149575 $this->root = $this->index . '/';
149576 }
149577 $this->category_base = get_option( 'category_base' );
149578 $this->tag_base = get_option( 'tag_base' );
149579 unset($this->category_structure);
149580 unset($this->author_structure);
149581 unset($this->date_structure);
149582 unset($this->page_structure);
149583 unset($this->search_structure);
149584 unset($this->feed_structure);
149585 unset($this->comment_feed_structure);
149586 $this->use_trailing_slashes = ( substr($this->permalink_structure, -1, 1) == '/' ) ? true : false;
149587
149588 // Enable generic rules for pages if permalink structure doesn't begin with a wildcard.
149589 $structure = ltrim($this->permalink_structure, '/');
149590 if ( $this->using_index_permalinks() )
149591 $structure = ltrim($this->permalink_structure, $this->index . '/');
149592 if ( 0 === strpos($structure, '%postname%') ||
149593 0 === strpos($structure, '%category%') ||
149594 0 === strpos($structure, '%tag%') ||
149595 0 === strpos($structure, '%author%') )
149596 $this->use_verbose_page_rules = true;
149597 else
149598 $this->use_verbose_page_rules = false;
149599 }
149600
149601 /**
149602 * Set the main permalink structure for the blog.
149603 *
149604 * Will update the 'permalink_structure' option, if there is a difference
149605 * between the current permalink structure and the parameter value. Calls
149606 * {@link WP_Rewrite::init()} after the option is updated.
149607 *
149608 * @since 1.5.0
149609 * @access public
149610 *
149611 * @param string $permalink_structure Permalink structure.
149612 */
149613 function set_permalink_structure($permalink_structure) {
149614 if ($permalink_structure != $this->permalink_structure) {
149615 update_option('permalink_structure', $permalink_structure);
149616 $this->init();
149617 }
149618 }
149619
149620 /**
149621 * Set the category base for the category permalink.
149622 *
149623 * Will update the 'category_base' option, if there is a difference between
149624 * the current category base and the parameter value. Calls
149625 * {@link WP_Rewrite::init()} after the option is updated.
149626 *
149627 * @since 1.5.0
149628 * @access public
149629 *
149630 * @param string $category_base Category permalink structure base.
149631 */
149632 function set_category_base($category_base) {
149633 if ($category_base != $this->category_base) {
149634 update_option('category_base', $category_base);
149635 $this->init();
149636 }
149637 }
149638
149639 /**
149640 * Set the tag base for the tag permalink.
149641 *
149642 * Will update the 'tag_base' option, if there is a difference between the
149643 * current tag base and the parameter value. Calls
149644 * {@link WP_Rewrite::init()} after the option is updated.
149645 *
149646 * @since 2.3.0
149647 * @access public
149648 *
149649 * @param string $tag_base Tag permalink structure base.
149650 */
149651 function set_tag_base( $tag_base ) {
149652 if ( $tag_base != $this->tag_base ) {
149653 update_option( 'tag_base', $tag_base );
149654 $this->init();
149655 }
149656 }
149657
149658 /**
149659 * PHP4 Constructor - Calls init(), which runs setup.
149660 *
149661 * @since 1.5.0
149662 * @access public
149663 *
149664 * @return WP_Rewrite
149665 */
149666 function WP_Rewrite() {
149667 $this->init();
149668 }
149669 }
149670
149671 ?>