* Rewrite API: WP_Rewrite class
* Core class used to implement a rewrite component API.
* The WordPress Rewrite class writes the rewrite module rules to the .htaccess
* file. It also handles parsing the request to get the correct setup for the
* The Rewrite along with WP class function as a front controller for WordPress.
* You can add rules to trigger your page view and processing using this
* component. The full functionality of a front controller does not exist,
* meaning you can't define how the template files load based on the rewrite
* Permalink structure for posts.
public $permalink_structure;
* Whether to add trailing slashes.
public $use_trailing_slashes;
* Base for the author permalink structure (example.com/$author_base/authorname).
public $author_base = 'author';
* Permalink structure for author archives.
public $author_structure;
* Permalink structure for date archives.
* Permalink structure for pages.
* Base of the search permalink structure (example.com/$search_base/query).
public $search_base = 'search';
* Permalink structure for searches.
public $search_structure;
* Comments permalink base.
public $comments_base = 'comments';
* Pagination permalink base.
public $pagination_base = 'page';
* Comments pagination permalink base.
public $comments_pagination_base = 'comment-page';
public $feed_base = 'feed';
* Comments feed permalink structure.
public $comment_feed_structure;
* Feed request permalink structure.
* The static portion of the post permalink structure.
* If the permalink structure is "/archive/%post_id%" then the front
* is "/archive/". If the permalink structure is "/%year%/%postname%/"
* @see WP_Rewrite::init()
* The prefix for all permalink structures.
* If PATHINFO/index permalinks are in use then the root is the value of
* `WP_Rewrite::$index` with a trailing slash appended. Otherwise the root
* @see WP_Rewrite::init()
* @see WP_Rewrite::using_index_permalinks()
* The name of the index file which is the entry point to all requests.
public $index = 'index.php';
* Variable name to use for regex matches in the rewritten query.
* Rewrite rules to match against the request to find the redirect or query.
* Additional rules added external to the rewrite class.
* Those not generated by the class, see add_rewrite_rule().
public $extra_rules = array();
* Additional rules that belong at the beginning to match first.
* Those not generated by the class, see add_rewrite_rule().
public $extra_rules_top = array();
* Rules that don't redirect to WordPress' index.php.
* These rules are written to the mod_rewrite portion of the .htaccess,
* and are added by add_external_rule().
public $non_wp_rules = array();
* Extra permalink structures, e.g. categories, added by add_permastruct().
public $extra_permastructs = array();
* Endpoints (like /trackback/) added by add_rewrite_endpoint().
* Whether to write every mod_rewrite rule for WordPress into the .htaccess file.
* This is off by default, turning it on might print a lot of rewrite rules
* @see WP_Rewrite::mod_rewrite_rules()
public $use_verbose_rules = false;
* Could post permalinks be confused with those of pages?
* If the first rewrite tag in the post permalink structure is one that could
* also match a page name (e.g. %postname% or %author%) then this flag is
* set to true. Prior to WordPress 3.3 this flag indicated that every page
* would have a set of rules added to the top of the rewrite rules array.
* Now it tells WP::parse_request() to check if a URL matching the page
* permastruct is actually a page before accepting it.
* @see WP_Rewrite::init()
public $use_verbose_page_rules = true;
* Rewrite tags that can be used in permalink structures.
* These are translated into the regular expressions stored in
* `WP_Rewrite::$rewritereplace` and are rewritten to the query
* variables listed in WP_Rewrite::$queryreplace.
* Additional tags can be added with add_rewrite_tag().
public $rewritecode = array(
* Regular expressions to be substituted into rewrite rules in place
* of rewrite tags, see WP_Rewrite::$rewritecode.
public $rewritereplace = array(
* Query variables that rewrite tags map to, see WP_Rewrite::$rewritecode.
public $queryreplace = array(
* Supported default feeds.
public $feeds = array( 'feed', 'rdf', 'rss', 'rss2', 'atom' );
* Determines whether permalinks are being used.
* This can be either rewrite module or permalink in the HTTP query string.
* @return bool True, if permalinks are enabled.
public function using_permalinks() {
return ! empty( $this->permalink_structure );
* Determines whether permalinks are being used and rewrite module is not enabled.
* Means that permalink links are enabled and index.php is in the URL.
* @return bool Whether permalink links are enabled and index.php is in the URL.
public function using_index_permalinks() {
if ( empty( $this->permalink_structure ) ) {
// If the index is not in the permalink, we're using mod_rewrite.
return preg_match( '#^/*' . $this->index . '#', $this->permalink_structure );
* Determines whether permalinks are being used and rewrite module is enabled.
* Using permalinks and index.php is not in the URL.
* @return bool Whether permalink links are enabled and index.php is NOT in the URL.
public function using_mod_rewrite_permalinks() {
return $this->using_permalinks() && ! $this->using_index_permalinks();
* Indexes for matches for usage in preg_*() functions.
* The format of the string is, with empty matches property value, '$NUM'.
* The 'NUM' will be replaced with the value in the $number parameter. With
* the matches property not empty, the value of the returned string will
* contain that value of the matches property. The format then will be
* '$MATCHES[NUM]', with MATCHES as the value in the property and NUM the
* value of the $number parameter.
* @param int $number Index number.
public function preg_index( $number ) {
if ( ! empty( $this->matches ) ) {
$match_prefix = '$' . $this->matches . '[';
return "$match_prefix$number$match_suffix";
* Retrieves all page and attachments for pages URIs.
* The attachments are for those that have pages as parents and will be
* @global wpdb $wpdb WordPress database abstraction object.
* @return array Array of page URIs as first element and attachment URIs as second element.
public function page_uri_index() {
// Get pages in order of hierarchy, i.e. children after parents.
$pages = $wpdb->get_results( "SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE post_type = 'page' AND post_status != 'auto-draft'" );
$posts = get_page_hierarchy( $pages );
// If we have no pages get out quick.
return array( array(), array() );
// Now reverse it, because we need parents after children for rewrite rules to work properly.
$posts = array_reverse( $posts, true );
$page_attachment_uris = array();
foreach ( $posts as $id => $post ) {
$uri = get_page_uri( $id );
$attachments = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE post_type = 'attachment' AND post_parent = %d", $id ) );
if ( ! empty( $attachments ) ) {
foreach ( $attachments as $attachment ) {
$attach_uri = get_page_uri( $attachment->ID );
$page_attachment_uris[ $attach_uri ] = $attachment->ID;
$page_uris[ $uri ] = $id;
return array( $page_uris, $page_attachment_uris );
* Retrieves all of the rewrite rules for pages.
* @return string[] Page rewrite rules.
public function page_rewrite_rules() {
// The extra .? at the beginning prevents clashes with other regular expressions in the rules array.
$this->add_rewrite_tag( '%pagename%', '(.?.+?)', 'pagename=' );
return $this->generate_rewrite_rules( $this->get_page_permastruct(), EP_PAGES, true, true, false, false );
* Retrieves date permalink structure, with year, month, and day.
* The permalink structure for the date, if not set already depends on the
* permalink structure. It can be one of three formats. The first is year,
* month, day; the second is day, month, year; and the last format is month,
* day, year. These are matched against the permalink structure for which
* one is used. If none matches, then the default will be used, which is
* Prevents post ID and date permalinks from overlapping. In the case of
* post_id, the date permalink will be prepended with front permalink with
* 'date/' before the actual permalink to form the complete date permalink
* @return string|false Date permalink structure on success, false on failure.
public function get_date_permastruct() {
if ( isset( $this->date_structure ) ) {
return $this->date_structure;
if ( empty( $this->permalink_structure ) ) {
$this->date_structure = '';