wp/wp-includes/class-wp-rewrite.php
changeset 21 48c4eec2b7e6
parent 19 3d72ae0968f4
child 22 8c2e4d02f4ef
--- a/wp/wp-includes/class-wp-rewrite.php	Thu Sep 29 08:06:27 2022 +0200
+++ b/wp/wp-includes/class-wp-rewrite.php	Fri Sep 05 18:40:08 2025 +0200
@@ -22,6 +22,7 @@
  *
  * @since 1.5.0
  */
+#[AllowDynamicProperties]
 class WP_Rewrite {
 	/**
 	 * Permalink structure for posts.
@@ -184,7 +185,7 @@
 	 * Rewrite rules to match against the request to find the redirect or query.
 	 *
 	 * @since 1.5.0
-	 * @var array
+	 * @var string[]
 	 */
 	public $rules;
 
@@ -194,7 +195,7 @@
 	 * Those not generated by the class, see add_rewrite_rule().
 	 *
 	 * @since 2.1.0
-	 * @var array
+	 * @var string[]
 	 */
 	public $extra_rules = array();
 
@@ -204,7 +205,7 @@
 	 * Those not generated by the class, see add_rewrite_rule().
 	 *
 	 * @since 2.3.0
-	 * @var array
+	 * @var string[]
 	 */
 	public $extra_rules_top = array();
 
@@ -215,7 +216,7 @@
 	 * and are added by add_external_rule().
 	 *
 	 * @since 2.1.0
-	 * @var array
+	 * @var string[]
 	 */
 	public $non_wp_rules = array();
 
@@ -223,7 +224,7 @@
 	 * Extra permalink structures, e.g. categories, added by add_permastruct().
 	 *
 	 * @since 2.1.0
-	 * @var array
+	 * @var array[]
 	 */
 	public $extra_permastructs = array();
 
@@ -231,7 +232,7 @@
 	 * Endpoints (like /trackback/) added by add_rewrite_endpoint().
 	 *
 	 * @since 2.1.0
-	 * @var array
+	 * @var array[]
 	 */
 	public $endpoints;
 
@@ -412,7 +413,7 @@
 	}
 
 	/**
-	 * Retrieves all page and attachments for pages URIs.
+	 * Retrieves all pages and attachments for pages URIs.
 	 *
 	 * The attachments are for those that have pages as parents and will be
 	 * retrieved.
@@ -508,7 +509,7 @@
 		$date_endian          = '';
 
 		foreach ( $endians as $endian ) {
-			if ( false !== strpos( $this->permalink_structure, $endian ) ) {
+			if ( str_contains( $this->permalink_structure, $endian ) ) {
 				$date_endian = $endian;
 				break;
 			}
@@ -530,7 +531,7 @@
 				$front = $front . 'date/';
 				break;
 			}
-			$tok_index++;
+			++$tok_index;
 		}
 
 		$this->date_structure = $front . $date_endian;
@@ -615,7 +616,7 @@
 	}
 
 	/**
-	 * Retrieve the permalink structure for tags.
+	 * Retrieves the permalink structure for tags.
 	 *
 	 * If the tag_base property has no value, then the tag structure will have
 	 * the front property value, followed by 'tag', and finally '%tag%'. If it
@@ -860,7 +861,7 @@
 	 *                                    Default `EP_NONE`.
 	 * @param bool   $paged               Optional. Whether archive pagination rules should be added for the structure.
 	 *                                    Default true.
-	 * @param bool   $feed                Optional Whether feed rewrite rules should be added for the structure.
+	 * @param bool   $feed                Optional. Whether feed rewrite rules should be added for the structure.
 	 *                                    Default true.
 	 * @param bool   $forcomments         Optional. Whether the feed rules should be a query for a comments feed.
 	 *                                    Default false.
@@ -1059,13 +1060,18 @@
 				 * 2) post ID, 3) page name, 4) timestamp (year, month, day, hour, second and
 				 * minute all present). Set these flags now as we need them for the endpoints.
 				 */
-				if ( strpos( $struct, '%postname%' ) !== false
-						|| strpos( $struct, '%post_id%' ) !== false
-						|| strpos( $struct, '%pagename%' ) !== false
-						|| ( strpos( $struct, '%year%' ) !== false && strpos( $struct, '%monthnum%' ) !== false && strpos( $struct, '%day%' ) !== false && strpos( $struct, '%hour%' ) !== false && strpos( $struct, '%minute%' ) !== false && strpos( $struct, '%second%' ) !== false )
-						) {
+				if ( str_contains( $struct, '%postname%' )
+					|| str_contains( $struct, '%post_id%' )
+					|| str_contains( $struct, '%pagename%' )
+					|| ( str_contains( $struct, '%year%' )
+						&& str_contains( $struct, '%monthnum%' )
+						&& str_contains( $struct, '%day%' )
+						&& str_contains( $struct, '%hour%' )
+						&& str_contains( $struct, '%minute%' )
+						&& str_contains( $struct, '%second%' ) )
+				) {
 					$post = true;
-					if ( strpos( $struct, '%pagename%' ) !== false ) {
+					if ( str_contains( $struct, '%pagename%' ) ) {
 						$page = true;
 					}
 				}
@@ -1073,7 +1079,7 @@
 				if ( ! $post ) {
 					// For custom post types, we need to add on endpoints as well.
 					foreach ( get_post_types( array( '_builtin' => false ) ) as $ptype ) {
-						if ( strpos( $struct, "%$ptype%" ) !== false ) {
+						if ( str_contains( $struct, "%$ptype%" ) ) {
 							$post = true;
 
 							// This is for page style attachment URLs.
@@ -1244,7 +1250,7 @@
 	 * @param string $permalink_structure The permalink structure to generate rules.
 	 * @param bool   $walk_dirs           Optional. Whether to create list of directories to walk over.
 	 *                                    Default false.
-	 * @return array
+	 * @return array An array of rewrite rules keyed by their regex pattern.
 	 */
 	public function generate_rewrite_rule( $permalink_structure, $walk_dirs = false ) {
 		return $this->generate_rewrite_rules( $permalink_structure, EP_NONE, false, false, false, $walk_dirs );
@@ -1398,7 +1404,7 @@
 		// Extra permastructs.
 		foreach ( $this->extra_permastructs as $permastructname => $struct ) {
 			if ( is_array( $struct ) ) {
-				if ( count( $struct ) == 2 ) {
+				if ( count( $struct ) === 2 ) {
 					$rules = $this->generate_rewrite_rules( $struct[0], $struct[1] );
 				} else {
 					$rules = $this->generate_rewrite_rules( $struct['struct'], $struct['ep_mask'], $struct['paged'], $struct['feed'], $struct['forcomments'], $struct['walk_dirs'], $struct['endpoints'] );
@@ -1484,19 +1490,36 @@
 	public function wp_rewrite_rules() {
 		$this->rules = get_option( 'rewrite_rules' );
 		if ( empty( $this->rules ) ) {
-			$this->matches = 'matches';
-			$this->rewrite_rules();
-			if ( ! did_action( 'wp_loaded' ) ) {
-				add_action( 'wp_loaded', array( $this, 'flush_rules' ) );
-				return $this->rules;
-			}
-			update_option( 'rewrite_rules', $this->rules );
+			$this->refresh_rewrite_rules();
 		}
 
 		return $this->rules;
 	}
 
 	/**
+	 * Refreshes the rewrite rules, saving the fresh value to the database.
+	 * If the `wp_loaded` action has not occurred yet, will postpone saving to the database.
+	 *
+	 * @since 6.4.0
+	 */
+	private function refresh_rewrite_rules() {
+		$this->rules   = '';
+		$this->matches = 'matches';
+
+		$this->rewrite_rules();
+
+		if ( ! did_action( 'wp_loaded' ) ) {
+			/*
+			 * Is not safe to save the results right now, as the rules may be partial.
+			 * Need to give all rules the chance to register.
+			 */
+			add_action( 'wp_loaded', array( $this, 'flush_rules' ) );
+		} else {
+			update_option( 'rewrite_rules', $this->rules );
+		}
+	}
+
+	/**
 	 * Retrieves mod_rewrite-formatted rewrite rules to write to .htaccess.
 	 *
 	 * Does not actually write to the .htaccess file, but creates the rules for
@@ -1554,7 +1577,7 @@
 				// Apache 1.3 does not support the reluctant (non-greedy) modifier.
 				$match = str_replace( '.+?', '.+', $match );
 
-				if ( strpos( $query, $this->index ) !== false ) {
+				if ( str_contains( $query, $this->index ) ) {
 					$rules .= 'RewriteRule ^' . $match . ' ' . $home_root . $query . " [QSA,L]\n";
 				} else {
 					$rules .= 'RewriteRule ^' . $match . ' ' . $site_root . $query . " [QSA,L]\n";
@@ -1659,10 +1682,10 @@
 			$external = false;
 			$query    = add_query_arg( $query, 'index.php' );
 		} else {
-			$index = false === strpos( $query, '?' ) ? strlen( $query ) : strpos( $query, '?' );
+			$index = ! str_contains( $query, '?' ) ? strlen( $query ) : strpos( $query, '?' );
 			$front = substr( $query, 0, $index );
 
-			$external = $front != $this->index;
+			$external = $front !== $this->index;
 		}
 
 		// "external" = it doesn't correspond to index.php.
@@ -1793,7 +1816,8 @@
 		if ( ! is_array( $args ) ) {
 			$args = array( 'with_front' => $args );
 		}
-		if ( func_num_args() == 4 ) {
+
+		if ( func_num_args() === 4 ) {
 			$args['ep_mask'] = func_get_arg( 3 );
 		}
 
@@ -1806,14 +1830,16 @@
 			'walk_dirs'   => true,
 			'endpoints'   => true,
 		);
-		$args     = array_intersect_key( $args, $defaults );
-		$args     = wp_parse_args( $args, $defaults );
+
+		$args = array_intersect_key( $args, $defaults );
+		$args = wp_parse_args( $args, $defaults );
 
 		if ( $args['with_front'] ) {
 			$struct = $this->front . $struct;
 		} else {
 			$struct = $this->root . $struct;
 		}
+
 		$args['struct'] = $struct;
 
 		$this->extra_permastructs[ $name ] = $args;
@@ -1855,8 +1881,7 @@
 			unset( $do_hard_later );
 		}
 
-		update_option( 'rewrite_rules', '' );
-		$this->wp_rewrite_rules();
+		$this->refresh_rewrite_rules();
 
 		/**
 		 * Filters whether a "hard" rewrite rule flush should be performed when requested.
@@ -1906,7 +1931,7 @@
 		unset( $this->feed_structure );
 		unset( $this->comment_feed_structure );
 
-		$this->use_trailing_slashes = ( '/' === substr( $this->permalink_structure, -1, 1 ) );
+		$this->use_trailing_slashes = str_ends_with( $this->permalink_structure, '/' );
 
 		// Enable generic rules for pages if permalink structure doesn't begin with a wildcard.
 		if ( preg_match( '/^[^%]*%(?:postname|category|tag|author)%/', $this->permalink_structure ) ) {
@@ -1931,7 +1956,7 @@
 	 * @param string $permalink_structure Permalink structure.
 	 */
 	public function set_permalink_structure( $permalink_structure ) {
-		if ( $permalink_structure != $this->permalink_structure ) {
+		if ( $this->permalink_structure !== $permalink_structure ) {
 			$old_permalink_structure = $this->permalink_structure;
 			update_option( 'permalink_structure', $permalink_structure );