From 0c976c2869a7fb5b29cc7f6377526f22d8bb3669 Mon Sep 17 00:00:00 2001
From: Matthew Reishus <mreishus@users.noreply.github.com>
Date: Thu, 12 Jan 2023 17:50:23 -0600
Subject: [PATCH 1/1] get_routes() caches generated routes

---
 .../rest-api/class-wp-rest-server.php         | 63 +++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/src/wp-includes/rest-api/class-wp-rest-server.php b/src/wp-includes/rest-api/class-wp-rest-server.php
index 00c34cd621..0aeb10c02c 100644
--- a/src/wp-includes/rest-api/class-wp-rest-server.php
+++ b/src/wp-includes/rest-api/class-wp-rest-server.php
@@ -71,6 +71,21 @@ class WP_REST_Server {
 	 */
 	protected $endpoints = array();
 
+	/**
+	 * This variable stores namespaces as keys and route maps as values.
+	 * The route map is an associative array with path regexes as the keys. The
+	 * value is an indexed array with the callback function/method as the first
+	 * item, and a bitmask of HTTP methods as the second item (see the class
+	 * constants).
+	 *
+	 * $endpoints is the raw endpoints.
+	 * $route_map is the parsed, filtered and sanitized map from a regex to an endpoint.
+	 *
+	 * @access protected
+	 * @var array Map of namespaces to route maps.
+	 */
+	protected $route_map_for_namespace = array();
+
 	/**
 	 * Options defined for the routes.
 	 *
@@ -839,6 +854,48 @@ class WP_REST_Server {
 		}
 	}
 
+	/**
+	 * Retrieves the internally stored route map.
+	 *
+	 * @access public
+	 *
+	 * @param string $route_namespace The namespace to store the routes for.
+	 * @return array Route map of the routes.
+	 */
+	public function get_route_map( $route_namespace = '' ) {
+		if ( isset( $this->route_map_for_namespace[ $route_namespace ] ) ) {
+			return $this->route_map_for_namespace[ $route_namespace ];
+		}
+		return array();
+	}
+
+	/**
+	 * Sets the internally stored route map.
+	 *
+	 * @access protected
+	 *
+	 * @param string $route_namespace Store the route map for a specific
+	 * namespace, or empty string for the default namespace containing all
+	 * routes.
+	 * @param array $route_map Route map of the routes.
+	 */
+	protected function set_route_map( $route_namespace, $route_map ) {
+		$this->route_map_for_namespace[ $route_namespace ] = $route_map;
+	}
+
+	/**
+	 * Clears the internally stored route map.
+	 *
+	 * @access protected
+	 *
+	 * @param string $route_namespace Store the route map for a specific
+	 * namespace, or empty string for the default namespace containing all
+	 * routes.
+	 */
+	public function clear_route_map( $route_namespace ) {
+		$this->route_map_for_namespace[ $route_namespace ] = array();
+	}
+
 	/**
 	 * Retrieves the route map.
 	 *
@@ -862,6 +919,11 @@ class WP_REST_Server {
 	 *               `'/path/regex' => array( array( $callback, $bitmask ), ...)`.
 	 */
 	public function get_routes( $route_namespace = '' ) {
+		$cached_routes = $this->get_route_map( $route_namespace );
+		if ( ! empty( $cached_routes ) ) {
+			return $cached_routes;
+		}
+
 		$endpoints = $this->endpoints;
 
 		if ( $route_namespace ) {
@@ -929,6 +991,7 @@ class WP_REST_Server {
 			}
 		}
 
+		$this->set_route_map( $route_namespace, $endpoints );
 		return $endpoints;
 	}
 
-- 
2.39.0

