[ Index ]

PHP Cross Reference of Wordpress 2.9.1

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


Generated: Fri Jan 8 00:19:48 2010 Cross-referenced by PHPXref 0.7