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