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