[ XREF Home ] [ Index ]

PHP Cross Reference of WordPress Trunk

Provided by Yoast

title

Body

[close]

/wp-includes/ -> rewrite.php (source)

   1  <?php
   2  /**
   3   * WordPress Rewrite API
   4   *
   5   * @package WordPress
   6   * @subpackage Rewrite
   7   */
   8  
   9  /**
  10   * Add a straight rewrite rule.
  11   *
  12   * @see WP_Rewrite::add_rule() for long description.
  13   * @since 2.1.0
  14   *
  15   * @param string $regex Regular Expression to match request against.
  16   * @param string $redirect Page to redirect to.
  17   * @param string $after Optional, default is 'bottom'. Where to add rule, can also be 'top'.
  18   */
  19  function add_rewrite_rule($regex, $redirect, $after = 'bottom') {
  20      global $wp_rewrite;
  21      $wp_rewrite->add_rule($regex, $redirect, $after);
  22  }
  23  
  24  /**
  25   * Add a new tag (like %postname%).
  26   *
  27   * Warning: you must call this on init or earlier, otherwise the query var
  28   * addition stuff won't work.
  29   *
  30   * @since 2.1.0
  31   *
  32   * @param string $tagname
  33   * @param string $regex
  34   */
  35  function add_rewrite_tag($tagname, $regex) {
  36      //validation
  37      if ( strlen($tagname) < 3 || $tagname[0] != '%' || $tagname[strlen($tagname)-1] != '%' )
  38          return;
  39  
  40      $qv = trim($tagname, '%');
  41  
  42      global $wp_rewrite, $wp;
  43      $wp->add_query_var($qv);
  44      $wp_rewrite->add_rewrite_tag($tagname, $regex, $qv . '=');
  45  }
  46  
  47  /**
  48   * Add permalink structure.
  49   *
  50   * @see WP_Rewrite::add_permastruct()
  51   * @since 3.0.0
  52   *
  53   * @param string $name Name for permalink structure.
  54   * @param string $struct Permalink structure.
  55   * @param bool $with_front Prepend front base to permalink structure.
  56   */
  57  function add_permastruct( $name, $struct, $with_front = true, $ep_mask = EP_NONE ) {
  58      global $wp_rewrite;
  59      return $wp_rewrite->add_permastruct( $name, $struct, $with_front, $ep_mask );
  60  }
  61  
  62  /**
  63   * Add a new feed type like /atom1/.
  64   *
  65   * @since 2.1.0
  66   *
  67   * @param string $feedname
  68   * @param callback $function Callback to run on feed display.
  69   * @return string Feed action name.
  70   */
  71  function add_feed($feedname, $function) {
  72      global $wp_rewrite;
  73      if ( ! in_array($feedname, $wp_rewrite->feeds) ) //override the file if it is
  74          $wp_rewrite->feeds[] = $feedname;
  75      $hook = 'do_feed_' . $feedname;
  76      // Remove default function hook
  77      remove_action($hook, $hook, 10, 1);
  78      add_action($hook, $function, 10, 1);
  79      return $hook;
  80  }
  81  
  82  /**
  83   * Remove rewrite rules and then recreate rewrite rules.
  84   *
  85   * @see WP_Rewrite::flush_rules()
  86   * @since 3.0.0
  87   *
  88   * @param bool $hard Whether to update .htaccess (hard flush) or just update
  89   *     rewrite_rules transient (soft flush). Default is true (hard).
  90   */
  91  function flush_rewrite_rules( $hard = true ) {
  92      global $wp_rewrite;
  93      $wp_rewrite->flush_rules( $hard );
  94  }
  95  
  96  //pseudo-places
  97  /**
  98   * Endpoint Mask for default, which is nothing.
  99   *
 100   * @since 2.1.0
 101   */
 102  define('EP_NONE', 0);
 103  
 104  /**
 105   * Endpoint Mask for Permalink.
 106   *
 107   * @since 2.1.0
 108   */
 109  define('EP_PERMALINK', 1);
 110  
 111  /**
 112   * Endpoint Mask for Attachment.
 113   *
 114   * @since 2.1.0
 115   */
 116  define('EP_ATTACHMENT', 2);
 117  
 118  /**
 119   * Endpoint Mask for date.
 120   *
 121   * @since 2.1.0
 122   */
 123  define('EP_DATE', 4);
 124  
 125  /**
 126   * Endpoint Mask for year
 127   *
 128   * @since 2.1.0
 129   */
 130  define('EP_YEAR', 8);
 131  
 132  /**
 133   * Endpoint Mask for month.
 134   *
 135   * @since 2.1.0
 136   */
 137  define('EP_MONTH', 16);
 138  
 139  /**
 140   * Endpoint Mask for day.
 141   *
 142   * @since 2.1.0
 143   */
 144  define('EP_DAY', 32);
 145  
 146  /**
 147   * Endpoint Mask for root.
 148   *
 149   * @since 2.1.0
 150   */
 151  define('EP_ROOT', 64);
 152  
 153  /**
 154   * Endpoint Mask for comments.
 155   *
 156   * @since 2.1.0
 157   */
 158  define('EP_COMMENTS', 128);
 159  
 160  /**
 161   * Endpoint Mask for searches.
 162   *
 163   * @since 2.1.0
 164   */
 165  define('EP_SEARCH', 256);
 166  
 167  /**
 168   * Endpoint Mask for categories.
 169   *
 170   * @since 2.1.0
 171   */
 172  define('EP_CATEGORIES', 512);
 173  
 174  /**
 175   * Endpoint Mask for tags.
 176   *
 177   * @since 2.3.0
 178   */
 179  define('EP_TAGS', 1024);
 180  
 181  /**
 182   * Endpoint Mask for authors.
 183   *
 184   * @since 2.1.0
 185   */
 186  define('EP_AUTHORS', 2048);
 187  
 188  /**
 189   * Endpoint Mask for pages.
 190   *
 191   * @since 2.1.0
 192   */
 193  define('EP_PAGES', 4096);
 194  
 195  /**
 196   * Endpoint Mask for everything.
 197   *
 198   * @since 2.1.0
 199   */
 200  define('EP_ALL', 8191);
 201  
 202  /**
 203   * Add an endpoint, like /trackback/.
 204   *
 205   * The endpoints are added to the end of the request. So a request matching
 206   * "/2008/10/14/my_post/myep/", the endpoint will be "/myep/".
 207   *
 208   * Be sure to flush the rewrite rules (wp_rewrite->flush_rules()) when your plugin gets
 209   * activated (register_activation_hook()) and deactivated (register_deactivation_hook())
 210   *
 211   * @since 2.1.0
 212   * @see WP_Rewrite::add_endpoint() Parameters and more description.
 213   * @uses $wp_rewrite
 214   *
 215   * @param unknown_type $name
 216   * @param unknown_type $places
 217   */
 218  function add_rewrite_endpoint($name, $places) {
 219      global $wp_rewrite;
 220      $wp_rewrite->add_endpoint($name, $places);
 221  }
 222  
 223  /**
 224   * Filter the URL base for taxonomies.
 225   *
 226   * To remove any manually prepended /index.php/.
 227   *
 228   * @access private
 229   * @since 2.6.0
 230   *
 231   * @param string $base The taxonomy base that we're going to filter
 232   * @return string
 233   */
 234  function _wp_filter_taxonomy_base( $base ) {
 235      if ( !empty( $base ) ) {
 236          $base = preg_replace( '|^/index\.php/|', '', $base );
 237          $base = trim( $base, '/' );
 238      }
 239      return $base;
 240  }
 241  
 242  /**
 243   * Examine a url and try to determine the post ID it represents.
 244   *
 245   * Checks are supposedly from the hosted site blog.
 246   *
 247   * @since 1.0.0
 248   *
 249   * @param string $url Permalink to check.
 250   * @return int Post ID, or 0 on failure.
 251   */
 252  function url_to_postid($url) {
 253      global $wp_rewrite;
 254  
 255      $url = apply_filters('url_to_postid', $url);
 256  
 257      // First, check to see if there is a 'p=N' or 'page_id=N' to match against
 258      if ( preg_match('#[?&](p|page_id|attachment_id)=(\d+)#', $url, $values) )    {
 259          $id = absint($values[2]);
 260          if ( $id )
 261              return $id;
 262      }
 263  
 264      // Check to see if we are using rewrite rules
 265      $rewrite = $wp_rewrite->wp_rewrite_rules();
 266  
 267      // Not using rewrite rules, and 'p=N' and 'page_id=N' methods failed, so we're out of options
 268      if ( empty($rewrite) )
 269          return 0;
 270  
 271      // Get rid of the #anchor
 272      $url_split = explode('#', $url);
 273      $url = $url_split[0];
 274  
 275      // Get rid of URL ?query=string
 276      $url_split = explode('?', $url);
 277      $url = $url_split[0];
 278  
 279      // Add 'www.' if it is absent and should be there
 280      if ( false !== strpos(home_url(), '://www.') && false === strpos($url, '://www.') )
 281          $url = str_replace('://', '://www.', $url);
 282  
 283      // Strip 'www.' if it is present and shouldn't be
 284      if ( false === strpos(home_url(), '://www.') )
 285          $url = str_replace('://www.', '://', $url);
 286  
 287      // Strip 'index.php/' if we're not using path info permalinks
 288      if ( !$wp_rewrite->using_index_permalinks() )
 289          $url = str_replace('index.php/', '', $url);
 290  
 291      if ( false !== strpos($url, home_url()) ) {
 292          // Chop off http://domain.com
 293          $url = str_replace(home_url(), '', $url);
 294      } else {
 295          // Chop off /path/to/blog
 296          $home_path = parse_url(home_url());
 297          $home_path = isset( $home_path['path'] ) ? $home_path['path'] : '' ;
 298          $url = str_replace($home_path, '', $url);
 299      }
 300  
 301      // Trim leading and lagging slashes
 302      $url = trim($url, '/');
 303  
 304      $request = $url;
 305  
 306      // Look for matches.
 307      $request_match = $request;
 308      foreach ( (array)$rewrite as $match => $query) {
 309          // If the requesting file is the anchor of the match, prepend it
 310          // to the path info.
 311          if ( !empty($url) && ($url != $request) && (strpos($match, $url) === 0) )
 312              $request_match = $url . '/' . $request;
 313  
 314          if ( preg_match("!^$match!", $request_match, $matches) ) {
 315              // Got a match.
 316              // Trim the query of everything up to the '?'.
 317              $query = preg_replace("!^.+\?!", '', $query);
 318  
 319              // Substitute the substring matches into the query.
 320              $query = addslashes(WP_MatchesMapRegex::apply($query, $matches));
 321  
 322              // Filter out non-public query vars
 323              global $wp;
 324              parse_str($query, $query_vars);
 325              $query = array();
 326              foreach ( (array) $query_vars as $key => $value ) {
 327                  if ( in_array($key, $wp->public_query_vars) )
 328                      $query[$key] = $value;
 329              }
 330  
 331              // Do the query
 332              $query = new WP_Query($query);
 333              if ( !empty($query->posts) && $query->is_singular )
 334                  return $query->post->ID;
 335              else
 336                  return 0;
 337          }
 338      }
 339      return 0;
 340  }
 341  
 342  /**
 343   * WordPress Rewrite Component.
 344   *
 345   * The WordPress Rewrite class writes the rewrite module rules to the .htaccess
 346   * file. It also handles parsing the request to get the correct setup for the
 347   * WordPress Query class.
 348   *
 349   * The Rewrite along with WP class function as a front controller for WordPress.
 350   * You can add rules to trigger your page view and processing using this
 351   * component. The full functionality of a front controller does not exist,
 352   * meaning you can't define how the template files load based on the rewrite
 353   * rules.
 354   *
 355   * @since 1.5.0
 356   */
 357  class WP_Rewrite {
 358      /**
 359       * Default permalink structure for WordPress.
 360       *
 361       * @since 1.5.0
 362       * @access private
 363       * @var string
 364       */
 365      var $permalink_structure;
 366  
 367      /**
 368       * Whether to add trailing slashes.
 369       *
 370       * @since 2.2.0
 371       * @access private
 372       * @var bool
 373       */
 374      var $use_trailing_slashes;
 375  
 376      /**
 377       * Permalink author request base ( example.com/author/authorname ).
 378       *
 379       * @since 1.5.0
 380       * @access private
 381       * @var string
 382       */
 383      var $author_base = 'author';
 384  
 385      /**
 386       * Permalink request structure for author pages.
 387       *
 388       * @since 1.5.0
 389       * @access private
 390       * @var string
 391       */
 392      var $author_structure;
 393  
 394      /**
 395       * Permalink request structure for dates.
 396       *
 397       * @since 1.5.0
 398       * @access private
 399       * @var string
 400       */
 401      var $date_structure;
 402  
 403      /**
 404       * Permalink request structure for pages.
 405       *
 406       * @since 1.5.0
 407       * @access private
 408       * @var string
 409       */
 410      var $page_structure;
 411  
 412      /**
 413       * Search permalink base ( example.com/search/query ).
 414       *
 415       * @since 1.5.0
 416       * @access private
 417       * @var string
 418       */
 419      var $search_base = 'search';
 420  
 421      /**
 422       * Permalink request structure for searches.
 423       *
 424       * @since 1.5.0
 425       * @access private
 426       * @var string
 427       */
 428      var $search_structure;
 429  
 430      /**
 431       * Comments permalink base.
 432       *
 433       * @since 1.5.0
 434       * @access private
 435       * @var string
 436       */
 437      var $comments_base = 'comments';
 438  
 439      /**
 440       * Pagination permalink base.
 441       *
 442       * @since 3.1.0
 443       * @access private
 444       * @var string
 445       */
 446      var $pagination_base = 'page';
 447  
 448      /**
 449       * Feed permalink base.
 450       *
 451       * @since 1.5.0
 452       * @access private
 453       * @var string
 454       */
 455      var $feed_base = 'feed';
 456  
 457      /**
 458       * Comments feed request structure permalink.
 459       *
 460       * @since 1.5.0
 461       * @access private
 462       * @var string
 463       */
 464      var $comments_feed_structure;
 465  
 466      /**
 467       * Feed request structure permalink.
 468       *
 469       * @since 1.5.0
 470       * @access private
 471       * @var string
 472       */
 473      var $feed_structure;
 474  
 475      /**
 476       * Front URL path.
 477       *
 478       * The difference between the root property is that WordPress might be
 479       * located at example/WordPress/index.php, if permalinks are turned off. The
 480       * WordPress/index.php will be the front portion. If permalinks are turned
 481       * on, this will most likely be empty or not set.
 482       *
 483       * @since 1.5.0
 484       * @access private
 485       * @var string
 486       */
 487      var $front;
 488  
 489      /**
 490       * Root URL path to WordPress (without domain).
 491       *
 492       * The difference between front property is that WordPress might be located
 493       * at example.com/WordPress/. The root is the 'WordPress/' portion.
 494       *
 495       * @since 1.5.0
 496       * @access private
 497       * @var string
 498       */
 499      var $root = '';
 500  
 501      /**
 502       * Permalink to the home page.
 503       *
 504       * @since 1.5.0
 505       * @access public
 506       * @var string
 507       */
 508      var $index = 'index.php';
 509  
 510      /**
 511       * Request match string.
 512       *
 513       * @since 1.5.0
 514       * @access private
 515       * @var string
 516       */
 517      var $matches = '';
 518  
 519      /**
 520       * Rewrite rules to match against the request to find the redirect or query.
 521       *
 522       * @since 1.5.0
 523       * @access private
 524       * @var array
 525       */
 526      var $rules;
 527  
 528      /**
 529       * Additional rules added external to the rewrite class.
 530       *
 531       * Those not generated by the class, see add_rewrite_rule().
 532       *
 533       * @since 2.1.0
 534       * @access private
 535       * @var array
 536       */
 537      var $extra_rules = array(); //
 538  
 539      /**
 540       * Additional rules that belong at the beginning to match first.
 541       *
 542       * Those not generated by the class, see add_rewrite_rule().
 543       *
 544       * @since 2.3.0
 545       * @access private
 546       * @var array
 547       */
 548      var $extra_rules_top = array(); //
 549  
 550      /**
 551       * Rules that don't redirect to WP's index.php.
 552       *
 553       * These rules are written to the mod_rewrite portion of the .htaccess.
 554       *
 555       * @since 2.1.0
 556       * @access private
 557       * @var array
 558       */
 559      var $non_wp_rules = array(); //
 560  
 561      /**
 562       * Extra permalink structures.
 563       *
 564       * @since 2.1.0
 565       * @access private
 566       * @var array
 567       */
 568      var $extra_permastructs = array();
 569  
 570      /**
 571       * Endpoints permalinks
 572       *
 573       * @since 2.1.0
 574       * @access private
 575       * @var array
 576       */
 577      var $endpoints;
 578  
 579      /**
 580       * Whether to write every mod_rewrite rule for WordPress.
 581       *
 582       * This is off by default, turning it on might print a lot of rewrite rules
 583       * to the .htaccess file.
 584       *
 585       * @since 2.0.0
 586       * @access public
 587       * @var bool
 588       */
 589      var $use_verbose_rules = false;
 590  
 591      /**
 592       * Whether to write every mod_rewrite rule for WordPress pages.
 593       *
 594       * @since 2.5.0
 595       * @access public
 596       * @var bool
 597       */
 598      var $use_verbose_page_rules = true;
 599  
 600      /**
 601       * Permalink structure search for preg_replace.
 602       *
 603       * @since 1.5.0
 604       * @access private
 605       * @var array
 606       */
 607      var $rewritecode =
 608          array(
 609                      '%year%',
 610                      '%monthnum%',
 611                      '%day%',
 612                      '%hour%',
 613                      '%minute%',
 614                      '%second%',
 615                      '%postname%',
 616                      '%post_id%',
 617                      '%author%',
 618                      '%pagename%',
 619                      '%search%'
 620                      );
 621  
 622      /**
 623       * Preg_replace values for the search, see {@link WP_Rewrite::$rewritecode}.
 624       *
 625       * @since 1.5.0
 626       * @access private
 627       * @var array
 628       */
 629      var $rewritereplace =
 630          array(
 631                      '([0-9]{4})',
 632                      '([0-9]{1,2})',
 633                      '([0-9]{1,2})',
 634                      '([0-9]{1,2})',
 635                      '([0-9]{1,2})',
 636                      '([0-9]{1,2})',
 637                      '([^/]+)',
 638                      '([0-9]+)',
 639                      '([^/]+)',
 640                      '([^/]+?)',
 641                      '(.+)'
 642                      );
 643  
 644      /**
 645       * Search for the query to look for replacing.
 646       *
 647       * @since 1.5.0
 648       * @access private
 649       * @var array
 650       */
 651      var $queryreplace =
 652          array (
 653                      'year=',
 654                      'monthnum=',
 655                      'day=',
 656                      'hour=',
 657                      'minute=',
 658                      'second=',
 659                      'name=',
 660                      'p=',
 661                      'author_name=',
 662                      'pagename=',
 663                      's='
 664                      );
 665  
 666      /**
 667       * Supported default feeds.
 668       *
 669       * @since 1.5.0
 670       * @access private
 671       * @var array
 672       */
 673      var $feeds = array ( 'feed', 'rdf', 'rss', 'rss2', 'atom' );
 674  
 675      /**
 676       * Whether permalinks are being used.
 677       *
 678       * This can be either rewrite module or permalink in the HTTP query string.
 679       *
 680       * @since 1.5.0
 681       * @access public
 682       *
 683       * @return bool True, if permalinks are enabled.
 684       */
 685  	function using_permalinks() {
 686          return ! empty($this->permalink_structure);
 687      }
 688  
 689      /**
 690       * Whether permalinks are being used and rewrite module is not enabled.
 691       *
 692       * Means that permalink links are enabled and index.php is in the URL.
 693       *
 694       * @since 1.5.0
 695       * @access public
 696       *
 697       * @return bool
 698       */
 699  	function using_index_permalinks() {
 700          if ( empty($this->permalink_structure) )
 701              return false;
 702  
 703          // If the index is not in the permalink, we're using mod_rewrite.
 704          if ( preg_match('#^/*' . $this->index . '#', $this->permalink_structure) )
 705              return true;
 706  
 707          return false;
 708      }
 709  
 710      /**
 711       * Whether permalinks are being used and rewrite module is enabled.
 712       *
 713       * Using permalinks and index.php is not in the URL.
 714       *
 715       * @since 1.5.0
 716       * @access public
 717       *
 718       * @return bool
 719       */
 720  	function using_mod_rewrite_permalinks() {
 721          if ( $this->using_permalinks() && ! $this->using_index_permalinks() )
 722              return true;
 723          else
 724              return false;
 725      }
 726  
 727      /**
 728       * Index for matches for usage in preg_*() functions.
 729       *
 730       * The format of the string is, with empty matches property value, '$NUM'.
 731       * The 'NUM' will be replaced with the value in the $number parameter. With
 732       * the matches property not empty, the value of the returned string will
 733       * contain that value of the matches property. The format then will be
 734       * '$MATCHES[NUM]', with MATCHES as the value in the property and NUM the
 735       * value of the $number parameter.
 736       *
 737       * @since 1.5.0
 738       * @access public
 739       *
 740       * @param int $number Index number.
 741       * @return string
 742       */
 743  	function preg_index($number) {
 744          $match_prefix = '$';
 745          $match_suffix = '';
 746  
 747          if ( ! empty($this->matches) ) {
 748              $match_prefix = '$' . $this->matches . '[';
 749              $match_suffix = ']';
 750          }
 751  
 752          return "$match_prefix$number$match_suffix";
 753      }
 754  
 755      /**
 756       * Retrieve all page and attachments for pages URIs.
 757       *
 758       * The attachments are for those that have pages as parents and will be
 759       * retrieved.
 760       *
 761       * @since 2.5.0
 762       * @access public
 763       *
 764       * @return array Array of page URIs as first element and attachment URIs as second element.
 765       */
 766  	function page_uri_index() {
 767          global $wpdb;
 768  
 769          //get pages in order of hierarchy, i.e. children after parents
 770          $posts = get_page_hierarchy( $wpdb->get_results("SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE post_type = 'page' AND post_status != 'auto-draft'") );
 771  
 772          // If we have no pages get out quick
 773          if ( !$posts )
 774              return array( array(), array() );
 775  
 776          //now reverse it, because we need parents after children for rewrite rules to work properly
 777          $posts = array_reverse($posts, true);
 778  
 779          $page_uris = array();
 780          $page_attachment_uris = array();
 781  
 782          foreach ( $posts as $id => $post ) {
 783              // URL => page name
 784              $uri = get_page_uri($id);
 785              $attachments = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE post_type = 'attachment' AND post_parent = %d", $id ));
 786              if ( !empty($attachments) ) {
 787                  foreach ( $attachments as $attachment ) {
 788                      $attach_uri = get_page_uri($attachment->ID);
 789                      $page_attachment_uris[$attach_uri] = $attachment->ID;
 790                  }
 791              }
 792  
 793              $page_uris[$uri] = $id;
 794          }
 795  
 796          return array( $page_uris, $page_attachment_uris );
 797      }
 798  
 799      /**
 800       * Retrieve all of the rewrite rules for pages.
 801       *
 802       * If the 'use_verbose_page_rules' property is false, then there will only
 803       * be a single rewrite rule for pages for those matching '%pagename%'. With
 804       * the property set to true, the attachments and the pages will be added for
 805       * each individual attachment URI and page URI, respectively.
 806       *
 807       * @since 1.5.0
 808       * @access public
 809       *
 810       * @return array
 811       */
 812  	function page_rewrite_rules() {
 813          $rewrite_rules = array();
 814          $page_structure = $this->get_page_permastruct();
 815  
 816          if ( ! $this->use_verbose_page_rules ) {
 817              $this->add_rewrite_tag('%pagename%', "(.+?)", 'pagename=');
 818              $rewrite_rules = array_merge($rewrite_rules, $this->generate_rewrite_rules($page_structure, EP_PAGES));
 819              return $rewrite_rules;
 820          }
 821  
 822          $page_uris = $this->page_uri_index();
 823          $uris = $page_uris[0];
 824          $attachment_uris = $page_uris[1];
 825  
 826          if ( is_array( $attachment_uris ) ) {
 827              foreach ( $attachment_uris as $uri => $pagename ) {
 828                  $this->add_rewrite_tag('%pagename%', "($uri)", 'attachment=');
 829                  $rewrite_rules = array_merge($rewrite_rules, $this->generate_rewrite_rules($page_structure, EP_PAGES));
 830              }
 831          }
 832          if ( is_array( $uris ) ) {
 833              foreach ( $uris as $uri => $pagename ) {
 834                  $this->add_rewrite_tag('%pagename%', "($uri)", 'pagename=');
 835                  $rewrite_rules = array_merge($rewrite_rules, $this->generate_rewrite_rules($page_structure, EP_PAGES));
 836              }
 837          }
 838  
 839          return $rewrite_rules;
 840      }
 841  
 842      /**
 843       * Retrieve date permalink structure, with year, month, and day.
 844       *
 845       * The permalink structure for the date, if not set already depends on the
 846       * permalink structure. It can be one of three formats. The first is year,
 847       * month, day; the second is day, month, year; and the last format is month,
 848       * day, year. These are matched against the permalink structure for which
 849       * one is used. If none matches, then the default will be used, which is
 850       * year, month, day.
 851       *
 852       * Prevents post ID and date permalinks from overlapping. In the case of
 853       * post_id, the date permalink will be prepended with front permalink with
 854       * 'date/' before the actual permalink to form the complete date permalink
 855       * structure.
 856       *
 857       * @since 1.5.0
 858       * @access public
 859       *
 860       * @return bool|string False on no permalink structure. Date permalink structure.
 861       */
 862  	function get_date_permastruct() {
 863          if ( isset($this->date_structure) )
 864              return $this->date_structure;
 865  
 866          if ( empty($this->permalink_structure) ) {
 867              $this->date_structure = '';
 868              return false;
 869          }
 870  
 871          // The date permalink must have year, month, and day separated by slashes.
 872          $endians = array('%year%/%monthnum%/%day%', '%day%/%monthnum%/%year%', '%monthnum%/%day%/%year%');
 873  
 874          $this->date_structure = '';
 875          $date_endian = '';
 876  
 877          foreach ( $endians as $endian ) {
 878              if ( false !== strpos($this->permalink_structure, $endian) ) {
 879                  $date_endian= $endian;
 880                  break;
 881              }
 882          }
 883  
 884          if ( empty($date_endian) )
 885              $date_endian = '%year%/%monthnum%/%day%';
 886  
 887          // Do not allow the date tags and %post_id% to overlap in the permalink
 888          // structure. If they do, move the date tags to $front/date/.
 889          $front = $this->front;
 890          preg_match_all('/%.+?%/', $this->permalink_structure, $tokens);
 891          $tok_index = 1;
 892          foreach ( (array) $tokens[0] as $token) {
 893              if ( '%post_id%' == $token && ($tok_index <= 3) ) {
 894                  $front = $front . 'date/';
 895                  break;
 896              }
 897              $tok_index++;
 898          }
 899  
 900          $this->date_structure = $front . $date_endian;
 901  
 902          return $this->date_structure;
 903      }
 904  
 905      /**
 906       * Retrieve the year permalink structure without month and day.
 907       *
 908       * Gets the date permalink structure and strips out the month and day
 909       * permalink structures.
 910       *
 911       * @since 1.5.0
 912       * @access public
 913       *
 914       * @return bool|string False on failure. Year structure on success.
 915       */
 916  	function get_year_permastruct() {
 917          $structure = $this->get_date_permastruct($this->permalink_structure);
 918  
 919          if ( empty($structure) )
 920              return false;
 921  
 922          $structure = str_replace('%monthnum%', '', $structure);
 923          $structure = str_replace('%day%', '', $structure);
 924  
 925          $structure = preg_replace('#/+#', '/', $structure);
 926  
 927          return $structure;
 928      }
 929  
 930      /**
 931       * Retrieve the month permalink structure without day and with year.
 932       *
 933       * Gets the date permalink structure and strips out the day permalink
 934       * structures. Keeps the year permalink structure.
 935       *
 936       * @since 1.5.0
 937       * @access public
 938       *
 939       * @return bool|string False on failure. Year/Month structure on success.
 940       */
 941  	function get_month_permastruct() {
 942          $structure = $this->get_date_permastruct($this->permalink_structure);
 943  
 944          if ( empty($structure) )
 945              return false;
 946  
 947          $structure = str_replace('%day%', '', $structure);
 948  
 949          $structure = preg_replace('#/+#', '/', $structure);
 950  
 951          return $structure;
 952      }
 953  
 954      /**
 955       * Retrieve the day permalink structure with month and year.
 956       *
 957       * Keeps date permalink structure with all year, month, and day.
 958       *
 959       * @since 1.5.0
 960       * @access public
 961       *
 962       * @return bool|string False on failure. Year/Month/Day structure on success.
 963       */
 964  	function get_day_permastruct() {
 965          return $this->get_date_permastruct($this->permalink_structure);
 966      }
 967  
 968      /**
 969       * Retrieve the permalink structure for categories.
 970       *
 971       * If the category_base property has no value, then the category structure
 972       * will have the front property value, followed by 'category', and finally
 973       * '%category%'. If it does, then the root property will be used, along with
 974       * the category_base property value.
 975       *
 976       * @since 1.5.0
 977       * @access public
 978       *
 979       * @return bool|string False on failure. Category permalink structure.
 980       */
 981  	function get_category_permastruct() {
 982          return $this->get_extra_permastruct('category');
 983      }
 984  
 985      /**
 986       * Retrieve the permalink structure for tags.
 987       *
 988       * If the tag_base property has no value, then the tag structure will have
 989       * the front property value, followed by 'tag', and finally '%tag%'. If it
 990       * does, then the root property will be used, along with the tag_base
 991       * property value.
 992       *
 993       * @since 2.3.0
 994       * @access public
 995       *
 996       * @return bool|string False on failure. Tag permalink structure.
 997       */
 998  	function get_tag_permastruct() {
 999          return $this->get_extra_permastruct('post_tag');
1000      }
1001  
1002      /**
1003       * Retrieve extra permalink structure by name.
1004       *
1005       * @since 2.5.0
1006       * @access public
1007       *
1008       * @param string $name Permalink structure name.
1009       * @return string|bool False if not found. Permalink structure string.
1010       */
1011  	function get_extra_permastruct($name) {
1012          if ( empty($this->permalink_structure) )
1013              return false;
1014  
1015          if ( isset($this->extra_permastructs[$name]) )
1016              return $this->extra_permastructs[$name][0];
1017  
1018          return false;
1019      }
1020  
1021      /**
1022       * Retrieve the author permalink structure.
1023       *
1024       * The permalink structure is front property, author base, and finally
1025       * '/%author%'. Will set the author_structure property and then return it
1026       * without attempting to set the value again.
1027       *
1028       * @since 1.5.0
1029       * @access public
1030       *
1031       * @return string|bool False if not found. Permalink structure string.
1032       */
1033  	function get_author_permastruct() {
1034          if ( isset($this->author_structure) )
1035              return $this->author_structure;
1036  
1037          if ( empty($this->permalink_structure) ) {
1038              $this->author_structure = '';
1039              return false;
1040          }
1041  
1042          $this->author_structure = $this->front . $this->author_base . '/%author%';
1043  
1044          return $this->author_structure;
1045      }
1046  
1047      /**
1048       * Retrieve the search permalink structure.
1049       *
1050       * The permalink structure is root property, search base, and finally
1051       * '/%search%'. Will set the search_structure property and then return it
1052       * without attempting to set the value again.
1053       *
1054       * @since 1.5.0
1055       * @access public
1056       *
1057       * @return string|bool False if not found. Permalink structure string.
1058       */
1059  	function get_search_permastruct() {
1060          if ( isset($this->search_structure) )
1061              return $this->search_structure;
1062  
1063          if ( empty($this->permalink_structure) ) {
1064              $this->search_structure = '';
1065              return false;
1066          }
1067  
1068          $this->search_structure = $this->root . $this->search_base . '/%search%';
1069  
1070          return $this->search_structure;
1071      }
1072  
1073      /**
1074       * Retrieve the page permalink structure.
1075       *
1076       * The permalink structure is root property, and '%pagename%'. Will set the
1077       * page_structure property and then return it without attempting to set the
1078       * value again.
1079       *
1080       * @since 1.5.0
1081       * @access public
1082       *
1083       * @return string|bool False if not found. Permalink structure string.
1084       */
1085  	function get_page_permastruct() {
1086          if ( isset($this->page_structure) )
1087              return $this->page_structure;
1088  
1089          if (empty($this->permalink_structure)) {
1090              $this->page_structure = '';
1091              return false;
1092          }
1093  
1094          $this->page_structure = $this->root . '%pagename%';
1095  
1096          return $this->page_structure;
1097      }
1098  
1099      /**
1100       * Retrieve the feed permalink structure.
1101       *
1102       * The permalink structure is root property, feed base, and finally
1103       * '/%feed%'. Will set the feed_structure property and then return it
1104       * without attempting to set the value again.
1105       *
1106       * @since 1.5.0
1107       * @access public
1108       *
1109       * @return string|bool False if not found. Permalink structure string.
1110       */
1111  	function get_feed_permastruct() {
1112          if ( isset($this->feed_structure) )
1113              return $this->feed_structure;
1114  
1115          if ( empty($this->permalink_structure) ) {
1116              $this->feed_structure = '';
1117              return false;
1118          }
1119  
1120          $this->feed_structure = $this->root . $this->feed_base . '/%feed%';
1121  
1122          return $this->feed_structure;
1123      }
1124  
1125      /**
1126       * Retrieve the comment feed permalink structure.
1127       *
1128       * The permalink structure is root property, comment base property, feed
1129       * base and finally '/%feed%'. Will set the comment_feed_structure property
1130       * and then return it without attempting to set the value again.
1131       *
1132       * @since 1.5.0
1133       * @access public
1134       *
1135       * @return string|bool False if not found. Permalink structure string.
1136       */
1137  	function get_comment_feed_permastruct() {
1138          if ( isset($this->comment_feed_structure) )
1139              return $this->comment_feed_structure;
1140  
1141          if (empty($this->permalink_structure)) {
1142              $this->comment_feed_structure = '';
1143              return false;
1144          }
1145  
1146          $this->comment_feed_structure = $this->root . $this->comments_base . '/' . $this->feed_base . '/%feed%';
1147  
1148          return $this->comment_feed_structure;
1149      }
1150  
1151      /**
1152       * Append or update tag, pattern, and query for replacement.
1153       *
1154       * If the tag already exists, replace the existing pattern and query for
1155       * that tag, otherwise add the new tag, pattern, and query to the end of the
1156       * arrays.
1157       *
1158       * @internal What is the purpose of this function again? Need to finish long
1159       *           description.
1160       *
1161       * @since 1.5.0
1162       * @access public
1163       *
1164       * @param string $tag Append tag to rewritecode property array.
1165       * @param string $pattern Append pattern to rewritereplace property array.
1166       * @param string $query Append query to queryreplace property array.
1167       */
1168  	function add_rewrite_tag($tag, $pattern, $query) {
1169          $position = array_search($tag, $this->rewritecode);
1170          if ( false !== $position && null !== $position ) {
1171              $this->rewritereplace[$position] = $pattern;
1172              $this->queryreplace[$position] = $query;
1173          } else {
1174              $this->rewritecode[] = $tag;
1175              $this->rewritereplace[] = $pattern;
1176              $this->queryreplace[] = $query;
1177          }
1178      }
1179  
1180      /**
1181       * Generate the rules from permalink structure.
1182       *
1183       * The main WP_Rewrite function for building the rewrite rule list. The
1184       * contents of the function is a mix of black magic and regular expressions,
1185       * so best just ignore the contents and move to the parameters.
1186       *
1187       * @since 1.5.0
1188       * @access public
1189       *
1190       * @param string $permalink_structure The permalink structure.
1191       * @param int $ep_mask Optional, default is EP_NONE. Endpoint constant, see EP_* constants.
1192       * @param bool $paged Optional, default is true. Whether permalink request is paged.
1193       * @param bool $feed Optional, default is true. Whether for feed.
1194       * @param bool $forcomments Optional, default is false. Whether for comments.
1195       * @param bool $walk_dirs Optional, default is true. Whether to create list of directories to walk over.
1196       * @param bool $endpoints Optional, default is true. Whether endpoints are enabled.
1197       * @return array Rewrite rule list.
1198       */
1199  	function generate_rewrite_rules($permalink_structure, $ep_mask = EP_NONE, $paged = true, $feed = true, $forcomments = false, $walk_dirs = true, $endpoints = true) {
1200          //build a regex to match the feed section of URLs, something like (feed|atom|rss|rss2)/?
1201          $feedregex2 = '';
1202          foreach ( (array) $this->feeds as $feed_name)
1203              $feedregex2 .= $feed_name . '|';
1204          $feedregex2 = '(' . trim($feedregex2, '|') .  ')/?$';
1205  
1206          //$feedregex is identical but with /feed/ added on as well, so URLs like <permalink>/feed/atom
1207          //and <permalink>/atom are both possible
1208          $feedregex = $this->feed_base  . '/' . $feedregex2;
1209  
1210          //build a regex to match the trackback and page/xx parts of URLs
1211          $trackbackregex = 'trackback/?$';
1212          $pageregex = $this->pagination_base . '/?([0-9]{1,})/?$';
1213          $commentregex = 'comment-page-([0-9]{1,})/?$';
1214  
1215          //build up an array of endpoint regexes to append => queries to append
1216          if ( $endpoints ) {
1217              $ep_query_append = array ();
1218              foreach ( (array) $this->endpoints as $endpoint) {
1219                  //match everything after the endpoint name, but allow for nothing to appear there
1220                  $epmatch = $endpoint[1] . '(/(.*))?/?$';
1221                  //this will be appended on to the rest of the query for each dir
1222                  $epquery = '&' . $endpoint[1] . '=';
1223                  $ep_query_append[$epmatch] = array ( $endpoint[0], $epquery );
1224              }
1225          }
1226  
1227          //get everything up to the first rewrite tag
1228          $front = substr($permalink_structure, 0, strpos($permalink_structure, '%'));
1229          //build an array of the tags (note that said array ends up being in $tokens[0])
1230          preg_match_all('/%.+?%/', $permalink_structure, $tokens);
1231  
1232          $num_tokens = count($tokens[0]);
1233  
1234          $index = $this->index; //probably 'index.php'
1235          $feedindex = $index;
1236          $trackbackindex = $index;
1237          //build a list from the rewritecode and queryreplace arrays, that will look something like
1238          //tagname=$matches[i] where i is the current $i
1239          for ( $i = 0; $i < $num_tokens; ++$i ) {
1240              if ( 0 < $i )
1241                  $queries[$i] = $queries[$i - 1] . '&';
1242              else
1243                  $queries[$i] = '';
1244  
1245              $query_token = str_replace($this->rewritecode, $this->queryreplace, $tokens[0][$i]) . $this->preg_index($i+1);
1246              $queries[$i] .= $query_token;
1247          }
1248  
1249          //get the structure, minus any cruft (stuff that isn't tags) at the front
1250          $structure = $permalink_structure;
1251          if ( $front != '/' )
1252              $structure = str_replace($front, '', $structure);
1253  
1254          //create a list of dirs to walk over, making rewrite rules for each level
1255          //so for example, a $structure of /%year%/%month%/%postname% would create
1256          //rewrite rules for /%year%/, /%year%/%month%/ and /%year%/%month%/%postname%
1257          $structure = trim($structure, '/');
1258          $dirs = $walk_dirs ? explode('/', $structure) : array( $structure );
1259          $num_dirs = count($dirs);
1260  
1261          //strip slashes from the front of $front
1262          $front = preg_replace('|^/+|', '', $front);
1263  
1264          //the main workhorse loop
1265          $post_rewrite = array();
1266          $struct = $front;
1267          for ( $j = 0; $j < $num_dirs; ++$j ) {
1268              //get the struct for this dir, and trim slashes off the front
1269              $struct .= $dirs[$j] . '/'; //accumulate. see comment near explode('/', $structure) above
1270              $struct = ltrim($struct, '/');
1271  
1272              //replace tags with regexes
1273              $match = str_replace($this->rewritecode, $this->rewritereplace, $struct);
1274  
1275              //make a list of tags, and store how many there are in $num_toks
1276              $num_toks = preg_match_all('/%.+?%/', $struct, $toks);
1277  
1278              //get the 'tagname=$matches[i]'
1279              $query = ( isset($queries) && is_array($queries) ) ? $queries[$num_toks - 1] : '';
1280  
1281              //set up $ep_mask_specific which is used to match more specific URL types
1282              switch ( $dirs[$j] ) {
1283                  case '%year%':
1284                      $ep_mask_specific = EP_YEAR;
1285                      break;
1286                  case '%monthnum%':
1287                      $ep_mask_specific = EP_MONTH;
1288                      break;
1289                  case '%day%':
1290                      $ep_mask_specific = EP_DAY;
1291                      break;
1292                  default:
1293                      $ep_mask_specific = EP_NONE;
1294              }
1295  
1296              //create query for /page/xx
1297              $pagematch = $match . $pageregex;
1298              $pagequery = $index . '?' . $query . '&paged=' . $this->preg_index($num_toks + 1);
1299  
1300              //create query for /comment-page-xx
1301              $commentmatch = $match . $commentregex;
1302              $commentquery = $index . '?' . $query . '&cpage=' . $this->preg_index($num_toks + 1);
1303  
1304              if ( get_option('page_on_front') ) {
1305                  //create query for Root /comment-page-xx
1306                  $rootcommentmatch = $match . $commentregex;
1307                  $rootcommentquery = $index . '?' . $query . '&page_id=' . get_option('page_on_front') . '&cpage=' . $this->preg_index($num_toks + 1);
1308              }
1309  
1310              //create query for /feed/(feed|atom|rss|rss2|rdf)
1311              $feedmatch = $match . $feedregex;
1312              $feedquery = $feedindex . '?' . $query . '&feed=' . $this->preg_index($num_toks + 1);
1313  
1314              //create query for /(feed|atom|rss|rss2|rdf) (see comment near creation of $feedregex)
1315              $feedmatch2 = $match . $feedregex2;
1316              $feedquery2 = $feedindex . '?' . $query . '&feed=' . $this->preg_index($num_toks + 1);
1317  
1318              //if asked to, turn the feed queries into comment feed ones
1319              if ( $forcomments ) {
1320                  $feedquery .= '&withcomments=1';
1321                  $feedquery2 .= '&withcomments=1';
1322              }
1323  
1324              //start creating the array of rewrites for this dir
1325              $rewrite = array();
1326              if ( $feed ) //...adding on /feed/ regexes => queries
1327                  $rewrite = array($feedmatch => $feedquery, $feedmatch2 => $feedquery2);
1328              if ( $paged ) //...and /page/xx ones
1329                  $rewrite = array_merge($rewrite, array($pagematch => $pagequery));
1330  
1331              //only on pages with comments add ../comment-page-xx/
1332              if ( EP_PAGES & $ep_mask || EP_PERMALINK & $ep_mask )
1333                  $rewrite = array_merge($rewrite, array($commentmatch => $commentquery));
1334              else if ( EP_ROOT & $ep_mask && get_option('page_on_front') )
1335                  $rewrite = array_merge($rewrite, array($rootcommentmatch => $rootcommentquery));
1336  
1337              //do endpoints
1338              if ( $endpoints ) {
1339                  foreach ( (array) $ep_query_append as $regex => $ep) {
1340                      //add the endpoints on if the mask fits
1341                      if ( $ep[0] & $ep_mask || $ep[0] & $ep_mask_specific )
1342                          $rewrite[$match . $regex] = $index . '?' . $query . $ep[1] . $this->preg_index($num_toks + 2);
1343                  }
1344              }
1345  
1346              //if we've got some tags in this dir
1347              if ( $num_toks ) {
1348                  $post = false;
1349                  $page = false;
1350  
1351                  //check to see if this dir is permalink-level: i.e. the structure specifies an
1352                  //individual post. Do this by checking it contains at least one of 1) post name,
1353                  //2) post ID, 3) page name, 4) timestamp (year, month, day, hour, second and
1354                  //minute all present). Set these flags now as we need them for the endpoints.
1355                  if ( strpos($struct, '%postname%') !== false
1356                          || strpos($struct, '%post_id%') !== false
1357                          || strpos($struct, '%pagename%') !== false
1358                          || (strpos($struct, '%year%') !== false && strpos($struct, '%monthnum%') !== false && strpos($struct, '%day%') !== false && strpos($struct, '%hour%') !== false && strpos($struct, '%minute%') !== false && strpos($struct, '%second%') !== false)
1359                          ) {
1360                      $post = true;
1361                      if ( strpos($struct, '%pagename%') !== false )
1362                          $page = true;
1363                  }
1364  
1365                  if ( ! $post ) {
1366                      // For custom post types, we need to add on endpoints as well.
1367                      foreach ( get_post_types( array('_builtin' => false ) ) as $ptype ) {
1368                          if ( strpos($struct, "%$ptype%") !== false ) {
1369                              $post = true;
1370                              $page = is_post_type_hierarchical( $ptype ); // This is for page style attachment url's
1371                              break;
1372                          }
1373                      }
1374                  }
1375  
1376                  //if we're creating rules for a permalink, do all the endpoints like attachments etc
1377                  if ( $post ) {
1378                      //create query and regex for trackback
1379                      $trackbackmatch = $match . $trackbackregex;
1380                      $trackbackquery = $trackbackindex . '?' . $query . '&tb=1';
1381                      //trim slashes from the end of the regex for this dir
1382                      $match = rtrim($match, '/');
1383                      //get rid of brackets
1384                      $submatchbase = str_replace( array('(', ')'), '', $match);
1385  
1386                      //add a rule for at attachments, which take the form of <permalink>/some-text
1387                      $sub1 = $submatchbase . '/([^/]+)/';
1388                      $sub1tb = $sub1 . $trackbackregex; //add trackback regex <permalink>/trackback/...
1389                      $sub1feed = $sub1 . $feedregex; //and <permalink>/feed/(atom|...)
1390                      $sub1feed2 = $sub1 . $feedregex2; //and <permalink>/(feed|atom...)
1391                      $sub1comment = $sub1 . $commentregex; //and <permalink>/comment-page-xx
1392                      //add an ? as we don't have to match that last slash, and finally a $ so we
1393                      //match to the end of the URL
1394  
1395                      //add another rule to match attachments in the explicit form:
1396                      //<permalink>/attachment/some-text
1397                      $sub2 = $submatchbase . '/attachment/([^/]+)/';
1398                      $sub2tb = $sub2 . $trackbackregex; //and add trackbacks <permalink>/attachment/trackback
1399                      $sub2feed = $sub2 . $feedregex;    //feeds, <permalink>/attachment/feed/(atom|...)
1400                      $sub2feed2 = $sub2 . $feedregex2;  //and feeds again on to this <permalink>/attachment/(feed|atom...)
1401                      $sub2comment = $sub2 . $commentregex; //and <permalink>/comment-page-xx
1402  
1403                      //create queries for these extra tag-ons we've just dealt with
1404                      $subquery = $index . '?attachment=' . $this->preg_index(1);
1405                      $subtbquery = $subquery . '&tb=1';
1406                      $subfeedquery = $subquery . '&feed=' . $this->preg_index(2);
1407                      $subcommentquery = $subquery . '&cpage=' . $this->preg_index(2);
1408  
1409                      //do endpoints for attachments
1410                      if ( !empty($endpoints) ) {
1411                          foreach ( (array) $ep_query_append as $regex => $ep ) {
1412                              if ( $ep[0] & EP_ATTACHMENT ) {
1413                                  $rewrite[$sub1 . $regex] = $subquery . $ep[1] . $this->preg_index(2);
1414                                  $rewrite[$sub2 . $regex] = $subquery . $ep[1] . $this->preg_index(2);
1415                              }
1416                          }
1417                      }
1418  
1419                      //now we've finished with endpoints, finish off the $sub1 and $sub2 matches
1420                      $sub1 .= '?$';
1421                      $sub2 .= '?$';
1422  
1423                      //allow URLs like <permalink>/2 for <permalink>/page/2
1424                      $match = $match . '(/[0-9]+)?/?$';
1425                      $query = $index . '?' . $query . '&page=' . $this->preg_index($num_toks + 1);
1426                  } else { //not matching a permalink so this is a lot simpler
1427                      //close the match and finalise the query
1428                      $match .= '?$';
1429                      $query = $index . '?' . $query;
1430                  }
1431  
1432                  //create the final array for this dir by joining the $rewrite array (which currently
1433                  //only contains rules/queries for trackback, pages etc) to the main regex/query for
1434                  //this dir
1435                  $rewrite = array_merge($rewrite, array($match => $query));
1436  
1437                  //if we're matching a permalink, add those extras (attachments etc) on
1438                  if ( $post ) {
1439                      //add trackback
1440                      $rewrite = array_merge(array($trackbackmatch => $trackbackquery), $rewrite);
1441  
1442                      //add regexes/queries for attachments, attachment trackbacks and so on
1443                      if ( ! $page ) //require <permalink>/attachment/stuff form for pages because of confusion with subpages
1444                          $rewrite = array_merge($rewrite, array($sub1 => $subquery, $sub1tb => $subtbquery, $sub1feed => $subfeedquery, $sub1feed2 => $subfeedquery, $sub1comment => $subcommentquery));
1445                      $rewrite = array_merge(array($sub2 => $subquery, $sub2tb => $subtbquery, $sub2feed => $subfeedquery, $sub2feed2 => $subfeedquery, $sub2comment => $subcommentquery), $rewrite);
1446                  }
1447              } //if($num_toks)
1448              //add the rules for this dir to the accumulating $post_rewrite
1449              $post_rewrite = array_merge($rewrite, $post_rewrite);
1450          } //foreach ($dir)
1451          return $post_rewrite; //the finished rules. phew!
1452      }
1453  
1454      /**
1455       * Generate Rewrite rules with permalink structure and walking directory only.
1456       *
1457       * Shorten version of {@link WP_Rewrite::generate_rewrite_rules()} that
1458       * allows for shorter list of parameters. See the method for longer
1459       * description of what generating rewrite rules does.
1460       *
1461       * @uses WP_Rewrite::generate_rewrite_rules() See for long description and rest of parameters.
1462       * @since 1.5.0
1463       * @access public
1464       *
1465       * @param string $permalink_structure The permalink structure to generate rules.
1466       * @param bool $walk_dirs Optional, default is false. Whether to create list of directories to walk over.
1467       * @return array
1468       */
1469  	function generate_rewrite_rule($permalink_structure, $walk_dirs = false) {
1470          return $this->generate_rewrite_rules($permalink_structure, EP_NONE, false, false, false, $walk_dirs);
1471      }
1472  
1473      /**
1474       * Construct rewrite matches and queries from permalink structure.
1475       *
1476       * Runs the action 'generate_rewrite_rules' with the parameter that is an
1477       * reference to the current WP_Rewrite instance to further manipulate the
1478       * permalink structures and rewrite rules. Runs the 'rewrite_rules_array'
1479       * filter on the full rewrite rule array.
1480       *
1481       * There are two ways to manipulate the rewrite rules, one by hooking into
1482       * the 'generate_rewrite_rules' action and gaining full control of the
1483       * object or just manipulating the rewrite rule array before it is passed
1484       * from the function.
1485       *
1486       * @since 1.5.0
1487       * @access public
1488       *
1489       * @return array An associate array of matches and queries.
1490       */
1491  	function rewrite_rules() {
1492          $rewrite = array();
1493  
1494          if ( empty($this->permalink_structure) )
1495              return $rewrite;
1496  
1497          // robots.txt -only if installed at the root
1498          $home_path = parse_url( home_url() );
1499          $robots_rewrite = ( empty( $home_path['path'] ) || '/' == $home_path['path'] ) ? array( 'robots\.txt$' => $this->index . '?robots=1' ) : array();
1500  
1501          // Default Feed rules - These are require to allow for the direct access files to work with permalink structure starting with %category%
1502          $default_feeds = array(    '.*wp-atom.php$'    =>    $this->index . '?feed=atom',
1503                                  '.*wp-rdf.php$'        =>    $this->index . '?feed=rdf',
1504                                  '.*wp-rss.php$'        =>    $this->index . '?feed=rss',
1505                                  '.*wp-rss2.php$'    =>    $this->index . '?feed=rss2',
1506                                  '.*wp-feed.php$'    =>    $this->index . '?feed=feed',
1507                                  '.*wp-commentsrss2.php$'    =>    $this->index . '?feed=rss2&withcomments=1');
1508  
1509          // Registration rules
1510          $registration_pages = array();
1511          if ( is_multisite() && is_main_site() ) {
1512              $registration_pages['.*wp-signup.php$'] = $this->index . '?signup=true';
1513              $registration_pages['.*wp-activate.php$'] = $this->index . '?activate=true';
1514          }
1515  
1516          // Post
1517          $post_rewrite = $this->generate_rewrite_rules($this->permalink_structure, EP_PERMALINK);
1518          $post_rewrite = apply_filters('post_rewrite_rules', $post_rewrite);
1519  
1520          // Date
1521          $date_rewrite = $this->generate_rewrite_rules($this->get_date_permastruct(), EP_DATE);
1522          $date_rewrite = apply_filters('date_rewrite_rules', $date_rewrite);
1523  
1524          // Root
1525          $root_rewrite = $this->generate_rewrite_rules($this->root . '/', EP_ROOT);
1526          $root_rewrite = apply_filters('root_rewrite_rules', $root_rewrite);
1527  
1528          // Comments
1529          $comments_rewrite = $this->generate_rewrite_rules($this->root . $this->comments_base, EP_COMMENTS, true, true, true, false);
1530          $comments_rewrite = apply_filters('comments_rewrite_rules', $comments_rewrite);
1531  
1532          // Search
1533          $search_structure = $this->get_search_permastruct();
1534          $search_rewrite = $this->generate_rewrite_rules($search_structure, EP_SEARCH);
1535          $search_rewrite = apply_filters('search_rewrite_rules', $search_rewrite);
1536  
1537          // Authors
1538          $author_rewrite = $this->generate_rewrite_rules($this->get_author_permastruct(), EP_AUTHORS);
1539          $author_rewrite = apply_filters('author_rewrite_rules', $author_rewrite);
1540  
1541          // Pages
1542          $page_rewrite = $this->page_rewrite_rules();
1543          $page_rewrite = apply_filters('page_rewrite_rules', $page_rewrite);
1544  
1545          // Extra permastructs
1546          foreach ( $this->extra_permastructs as $permastructname => $permastruct ) {
1547              if ( is_array($permastruct) )
1548                  $rules = $this->generate_rewrite_rules($permastruct[0], $permastruct[1]);
1549              else
1550                  $rules = $this->generate_rewrite_rules($permastruct, EP_NONE);
1551  
1552              $rules = apply_filters($permastructname . '_rewrite_rules', $rules);
1553              if ( 'post_tag' == $permastructname )
1554                  $rules = apply_filters('tag_rewrite_rules', $rules);
1555  
1556              $this->extra_rules_top = array_merge($this->extra_rules_top, $rules);
1557          }
1558  
1559          // Put them together.
1560          if ( $this->use_verbose_page_rules )
1561              $this->rules = array_merge($this->extra_rules_top, $robots_rewrite, $default_feeds, $registration_pages, $page_rewrite, $root_rewrite, $comments_rewrite, $search_rewrite,  $author_rewrite, $date_rewrite, $post_rewrite, $this->extra_rules);
1562          else
1563              $this->rules = array_merge($this->extra_rules_top, $robots_rewrite, $default_feeds, $registration_pages, $root_rewrite, $comments_rewrite, $search_rewrite,  $author_rewrite, $date_rewrite, $post_rewrite, $page_rewrite, $this->extra_rules);
1564  
1565          do_action_ref_array('generate_rewrite_rules', array(&$this));
1566          $this->rules = apply_filters('rewrite_rules_array', $this->rules);
1567  
1568          return $this->rules;
1569      }
1570  
1571      /**
1572       * Retrieve the rewrite rules.
1573       *
1574       * The difference between this method and {@link
1575       * WP_Rewrite::rewrite_rules()} is that this method stores the rewrite rules
1576       * in the 'rewrite_rules' option and retrieves it. This prevents having to
1577       * process all of the permalinks to get the rewrite rules in the form of
1578       * caching.
1579       *
1580       * @since 1.5.0
1581       * @access public
1582       *
1583       * @return array Rewrite rules.
1584       */
1585  	function wp_rewrite_rules() {
1586          $this->rules = get_option('rewrite_rules');
1587          if ( empty($this->rules) ) {
1588              $this->matches = 'matches';
1589              $this->rewrite_rules();
1590              update_option('rewrite_rules', $this->rules);
1591          }
1592  
1593          return $this->rules;
1594      }
1595  
1596      /**
1597       * Retrieve mod_rewrite formatted rewrite rules to write to .htaccess.
1598       *
1599       * Does not actually write to the .htaccess file, but creates the rules for
1600       * the process that will.
1601       *
1602       * Will add  the non_wp_rules property rules to the .htaccess file before
1603       * the WordPress rewrite rules one.
1604       *
1605       * @since 1.5.0
1606       * @access public
1607       *
1608       * @return string
1609       */
1610  	function mod_rewrite_rules() {
1611          if ( ! $this->using_permalinks() )
1612              return '';
1613  
1614          $site_root = parse_url(get_option('siteurl'));
1615          if ( isset( $site_root['path'] ) )
1616              $site_root = trailingslashit($site_root['path']);
1617  
1618          $home_root = parse_url(home_url());
1619          if ( isset( $home_root['path'] ) )
1620              $home_root = trailingslashit($home_root['path']);
1621          else
1622              $home_root = '/';
1623  
1624          $rules = "<IfModule mod_rewrite.c>\n";
1625          $rules .= "RewriteEngine On\n";
1626          $rules .= "RewriteBase $home_root\n";
1627          $rules .= "RewriteRule ^index\.php$ - [L]\n"; // Prevent -f checks on index.php.
1628  
1629          //add in the rules that don't redirect to WP's index.php (and thus shouldn't be handled by WP at all)
1630          foreach ( (array) $this->non_wp_rules as $match => $query) {
1631              // Apache 1.3 does not support the reluctant (non-greedy) modifier.
1632              $match = str_replace('.+?', '.+', $match);
1633  
1634              // If the match is unanchored and greedy, prepend rewrite conditions
1635              // to avoid infinite redirects and eclipsing of real files.
1636              //if ($match == '(.+)/?$' || $match == '([^/]+)/?$' ) {
1637                  //nada.
1638              //}
1639  
1640              $rules .= 'RewriteRule ^' . $match . ' ' . $home_root . $query . " [QSA,L]\n";
1641          }
1642  
1643          if ( $this->use_verbose_rules ) {
1644              $this->matches = '';
1645              $rewrite = $this->rewrite_rules();
1646              $num_rules = count($rewrite);
1647              $rules .= "RewriteCond %{REQUEST_FILENAME} -f [OR]\n" .
1648                  "RewriteCond %{REQUEST_FILENAME} -d\n" .
1649                  "RewriteRule ^.*$ - [S=$num_rules]\n";
1650  
1651              foreach ( (array) $rewrite as $match => $query) {
1652                  // Apache 1.3 does not support the reluctant (non-greedy) modifier.
1653                  $match = str_replace('.+?', '.+', $match);
1654  
1655                  // If the match is unanchored and greedy, prepend rewrite conditions
1656                  // to avoid infinite redirects and eclipsing of real files.
1657                  //if ($match == '(.+)/?$' || $match == '([^/]+)/?$' ) {
1658                      //nada.
1659                  //}
1660  
1661                  if ( strpos($query, $this->index) !== false )
1662                      $rules .= 'RewriteRule ^' . $match . ' ' . $home_root . $query . " [QSA,L]\n";
1663                  else
1664                      $rules .= 'RewriteRule ^' . $match . ' ' . $site_root . $query . " [QSA,L]\n";
1665              }
1666          } else {
1667              $rules .= "RewriteCond %{REQUEST_FILENAME} !-f\n" .
1668                  "RewriteCond %{REQUEST_FILENAME} !-d\n" .
1669                  "RewriteRule . {$home_root}{$this->index} [L]\n";
1670          }
1671  
1672          $rules .= "</IfModule>\n";
1673  
1674          $rules = apply_filters('mod_rewrite_rules', $rules);
1675          $rules = apply_filters('rewrite_rules', $rules);  // Deprecated
1676  
1677          return $rules;
1678      }
1679  
1680      /**
1681       * Retrieve IIS7 URL Rewrite formatted rewrite rules to write to web.config file.
1682       *
1683       * Does not actually write to the web.config file, but creates the rules for
1684       * the process that will.
1685       *
1686       * @since 2.8.0
1687       * @access public
1688       *
1689       * @return string
1690       */
1691  	function iis7_url_rewrite_rules( $add_parent_tags = false ) {
1692  
1693          if ( ! $this->using_permalinks() )
1694              return '';
1695          $rules = '';
1696          if ( $add_parent_tags ) {
1697              $rules .= '<configuration>
1698      <system.webServer>
1699          <rewrite>
1700              <rules>';
1701          }
1702          if ( !is_multisite() ) {
1703              $rules .= '
1704                  <rule name="wordpress" patternSyntax="Wildcard">
1705                      <match url="*" />
1706                          <conditions>
1707                              <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
1708                              <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
1709                          </conditions>
1710                      <action type="Rewrite" url="index.php" />
1711                  </rule>';
1712          } else {
1713              if (is_subdomain_install()) {
1714                  $rules .= '
1715                  <rule name="wordpress - Rule 1" stopProcessing="true">
1716                      <match url="^index\.php$" ignoreCase="false" />
1717                      <action type="None" />
1718                  </rule>
1719                  <rule name="wordpress - Rule 2" stopProcessing="true">
1720                      <match url="^files/(.+)" ignoreCase="false" />
1721                      <action type="Rewrite" url="wp-includes/ms-files.php?file={R:1}" appendQueryString="false" />
1722                  </rule>
1723                  <rule name="wordpress - Rule 3" stopProcessing="true">
1724                      <match url="^" ignoreCase="false" />
1725                      <conditions logicalGrouping="MatchAny">
1726                          <add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" />
1727                          <add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" />
1728                      </conditions>
1729                      <action type="None" />
1730                  </rule>
1731                  <rule name="wordpress - Rule 4" stopProcessing="true">
1732                      <match url="." ignoreCase="false" />
1733                      <action type="Rewrite" url="index.php" />
1734                  </rule>';
1735              } else {
1736                  $rules .= '
1737                  <rule name="wordpress - Rule 1" stopProcessing="true">
1738                      <match url="^index\.php$" ignoreCase="false" />
1739                      <action type="None" />
1740                  </rule>
1741                  <rule name="wordpress - Rule 2" stopProcessing="true">
1742                      <match url="^([_0-9a-zA-Z-]+/)?files/(.+)" ignoreCase="false" />
1743                      <action type="Rewrite" url="wp-includes/ms-files.php?file={R:2}" appendQueryString="false" />
1744                  </rule>
1745                  <rule name="wordpress - Rule 3" stopProcessing="true">
1746                      <match url="^([_0-9a-zA-Z-]+/)?wp-admin$" ignoreCase="false" />
1747                      <action type="Redirect" url="{R:1}wp-admin/" redirectType="Permanent" />
1748                  </rule>
1749                  <rule name="wordpress - Rule 4" stopProcessing="true">
1750                      <match url="^" ignoreCase="false" />
1751                      <conditions logicalGrouping="MatchAny">
1752                          <add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" />
1753                          <add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" />
1754                      </conditions>
1755                      <action type="None" />
1756                  </rule>
1757                  <rule name="wordpress - Rule 5" stopProcessing="true">
1758                      <match url="^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*)" ignoreCase="false" />
1759                      <action type="Rewrite" url="{R:2}" />
1760                  </rule>
1761                  <rule name="wordpress - Rule 6" stopProcessing="true">
1762                      <match url="^([_0-9a-zA-Z-]+/)?(.*\.php)$" ignoreCase="false" />
1763                      <action type="Rewrite" url="{R:2}" />
1764                  </rule>
1765                  <rule name="wordpress - Rule 7" stopProcessing="true">
1766                      <match url="." ignoreCase="false" />
1767                      <action type="Rewrite" url="index.php" />
1768                  </rule>';
1769              }
1770          }
1771          if ( $add_parent_tags ) {
1772              $rules .= '
1773              </rules>
1774          </rewrite>
1775      </system.webServer>
1776  </configuration>';
1777          }
1778  
1779          $rules = apply_filters('iis7_url_rewrite_rules', $rules);
1780  
1781          return $rules;
1782      }
1783  
1784      /**
1785       * Add a straight rewrite rule.
1786       *
1787       * Any value in the $after parameter that isn't 'bottom' will be placed at
1788       * the top of the rules.
1789       *
1790       * @since 2.1.0
1791       * @access public
1792       *
1793       * @param string $regex Regular expression to match against request.
1794       * @param string $redirect URL regex redirects to when regex matches request.
1795       * @param string $after Optional, default is bottom. Location to place rule.
1796       */
1797  	function add_rule($regex, $redirect, $after = 'bottom') {
1798          //get everything up to the first ?
1799          $index = (strpos($redirect, '?') == false ? strlen($redirect) : strpos($redirect, '?'));
1800          $front = substr($redirect, 0, $index);
1801          if ( $front != $this->index ) { //it doesn't redirect to WP's index.php
1802              $this->add_external_rule($regex, $redirect);
1803          } else {
1804              if ( 'bottom' == $after)
1805                  $this->extra_rules = array_merge($this->extra_rules, array($regex => $redirect));
1806              else
1807                  $this->extra_rules_top = array_merge($this->extra_rules_top, array($regex => $redirect));
1808              //$this->extra_rules[$regex] = $redirect;
1809          }
1810      }
1811  
1812      /**
1813       * Add a rule that doesn't redirect to index.php.
1814       *
1815       * Can redirect to any place.
1816       *
1817       * @since 2.1.0
1818       * @access public
1819       *
1820       * @param string $regex Regular expression to match against request.
1821       * @param string $redirect URL regex redirects to when regex matches request.
1822       */
1823  	function add_external_rule($regex, $redirect) {
1824          $this->non_wp_rules[$regex] = $redirect;
1825      }
1826  
1827      /**
1828       * Add an endpoint, like /trackback/.
1829       *
1830       * To be inserted after certain URL types (specified in $places).
1831       *
1832       * @since 2.1.0
1833       * @access public
1834       *
1835       * @param string $name Name of endpoint.
1836       * @param array $places URL types that endpoint can be used.
1837       */
1838  	function add_endpoint($name, $places) {
1839          global $wp;
1840          $this->endpoints[] = array ( $places, $name );
1841          $wp->add_query_var($name);
1842      }
1843  
1844      /**
1845       * Add permalink structure.
1846       *
1847       * These are added along with the extra rewrite rules that are merged to the
1848       * top.
1849       *
1850       * @since 2.5.0
1851       * @access public
1852       *
1853       * @param string $name Name for permalink structure.
1854       * @param string $struct Permalink structure.
1855       * @param bool $with_front Prepend front base to permalink structure.
1856       */
1857  	function add_permastruct($name, $struct, $with_front = true, $ep_mask = EP_NONE) {
1858          if ( $with_front )
1859              $struct = $this->front . $struct;
1860          else
1861              $struct = $this->root . $struct;
1862          $this->extra_permastructs[$name] = array($struct, $ep_mask);
1863      }
1864  
1865      /**
1866       * Remove rewrite rules and then recreate rewrite rules.
1867       *
1868       * Calls {@link WP_Rewrite::wp_rewrite_rules()} after removing the
1869       * 'rewrite_rules' option. If the function named 'save_mod_rewrite_rules'
1870       * exists, it will be called.
1871       *
1872       * @since 2.0.1
1873       * @access public
1874       * @param bool $hard Whether to update .htaccess (hard flush) or just update rewrite_rules option (soft flush). Default is true (hard).
1875       */
1876  	function flush_rules($hard = true) {
1877          delete_option('rewrite_rules');
1878          $this->wp_rewrite_rules();
1879          if ( $hard && function_exists('save_mod_rewrite_rules') )
1880              save_mod_rewrite_rules();
1881          if ( $hard && function_exists('iis7_save_url_rewrite_rules') )
1882              iis7_save_url_rewrite_rules();
1883      }
1884  
1885      /**
1886       * Sets up the object's properties.
1887       *
1888       * The 'use_verbose_page_rules' object property will be set to true if the
1889       * permalink structure begins with one of the following: '%postname%', '%category%',
1890       * '%tag%', or '%author%'.
1891       *
1892       * @since 1.5.0
1893       * @access public
1894       */
1895  	function init() {
1896          $this->extra_rules = $this->non_wp_rules = $this->endpoints = array();
1897          $this->permalink_structure = get_option('permalink_structure');
1898          $this->front = substr($this->permalink_structure, 0, strpos($this->permalink_structure, '%'));
1899          $this->root = '';
1900          if ( $this->using_index_permalinks() )
1901              $this->root = $this->index . '/';
1902          unset($this->author_structure);
1903          unset($this->date_structure);
1904          unset($this->page_structure);
1905          unset($this->search_structure);
1906          unset($this->feed_structure);
1907          unset($this->comment_feed_structure);
1908          $this->use_trailing_slashes = ( '/' == substr($this->permalink_structure, -1, 1) );
1909  
1910          // Enable generic rules for pages if permalink structure doesn't begin with a wildcard.
1911          if ( preg_match("/^[^%]*%(?:postname|category|tag|author)%/", $this->permalink_structure) )
1912               $this->use_verbose_page_rules = true;
1913          else
1914              $this->use_verbose_page_rules = false;
1915      }
1916  
1917      /**
1918       * Set the main permalink structure for the blog.
1919       *
1920       * Will update the 'permalink_structure' option, if there is a difference
1921       * between the current permalink structure and the parameter value. Calls
1922       * {@link WP_Rewrite::init()} after the option is updated.
1923       *
1924       * Fires the 'permalink_structure_changed' action once the init call has
1925       * processed passing the old and new values
1926       *
1927       * @since 1.5.0
1928       * @access public
1929       *
1930       * @param string $permalink_structure Permalink structure.
1931       */
1932  	function set_permalink_structure($permalink_structure) {
1933          if ( $permalink_structure != $this->permalink_structure ) {
1934              update_option('permalink_structure', $permalink_structure);
1935              $this->init();
1936              do_action('permalink_structure_changed', $this->permalink_structure, $permalink_structure);
1937          }
1938      }
1939  
1940      /**
1941       * Set the category base for the category permalink.
1942       *
1943       * Will update the 'category_base' option, if there is a difference between
1944       * the current category base and the parameter value. Calls
1945       * {@link WP_Rewrite::init()} after the option is updated.
1946       *
1947       * @since 1.5.0
1948       * @access public
1949       *
1950       * @param string $category_base Category permalink structure base.
1951       */
1952  	function set_category_base($category_base) {
1953          if ( $category_base != get_option('category_base') ) {
1954              update_option('category_base', $category_base);
1955              $this->init();
1956          }
1957      }
1958  
1959      /**
1960       * Set the tag base for the tag permalink.
1961       *
1962       * Will update the 'tag_base' option, if there is a difference between the
1963       * current tag base and the parameter value. Calls
1964       * {@link WP_Rewrite::init()} after the option is updated.
1965       *
1966       * @since 2.3.0
1967       * @access public
1968       *
1969       * @param string $tag_base Tag permalink structure base.
1970       */
1971  	function set_tag_base( $tag_base ) {
1972          if ( $tag_base != get_option( 'tag_base') ) {
1973              update_option( 'tag_base', $tag_base );
1974              $this->init();
1975          }
1976      }
1977  
1978      /**
1979       * Constructor - Calls init(), which runs setup.
1980       *
1981       * @since 1.5.0
1982       * @access public
1983       *
1984       * @return WP_Rewrite
1985       */
1986  	function __construct() {
1987          $this->init();
1988      }
1989  }
1990  
1991  ?>


Generated: Wed Jun 1 08:30:02 2011 Cross-referenced by PHPXref 0.7
Provided by Yoast and awesome WordPress Hosting