diff --git a/system/src/Grav/Common/Page/Page.php b/system/src/Grav/Common/Page/Page.php index e844a75b7..48eae0c52 100644 --- a/system/src/Grav/Common/Page/Page.php +++ b/system/src/Grav/Common/Page/Page.php @@ -2282,6 +2282,74 @@ class Page } } + /** + * Helper method to return an ancestor page. + * + * @param string $url The url of the page + * @param bool $lookup Name of the parent folder + * + * @return \Grav\Common\Page\Page page you were looking for if it exists + */ + public function ancestor($lookup = null) + { + /** @var Pages $pages */ + $pages = Grav::instance()['pages']; + + return $pages->ancestor($this->route, $lookup); + } + + /** + * Helper method to return an ancestor page to inherit from. The current + * page object is returned. + * + * @param string $field Name of the parent folder + * + * @return Page + */ + public function inherited($field) + { + list($inherited, $currentParams) = $this->getInheritedParams($field); + + $this->modifyHeader($field, $currentParams); + + return $inherited; + } + /** + * Helper method to return an ancestor field only to inherit from. The + * first occurrence of an ancestor field will be returned if at all. + * + * @param string $field Name of the parent folder + * + * @return array + */ + public function inheritedField($field) + { + list($inherited, $currentParams) = $this->getInheritedParams($field); + + return $currentParams; + } + + /** + * Method that contains shared logic for inherited() and inheritedField() + * + * @param string $field Name of the parent folder + * + * @return array + */ + protected function getInheritedParams($field) + { + $pages = Grav::instance()['pages']; + + /** @var Pages $pages */ + $inherited = $pages->inherited($this->route, $field); + $inheritedParams = (array) $inherited->value('header.' . $field); + $currentParams = (array) $this->value('header.' . $field); + if($inheritedParams && is_array($inheritedParams)) { + $currentParams = array_replace_recursive($inheritedParams, $currentParams); + } + return [$inherited, $currentParams]; + } + /** * Helper method to return a page. * diff --git a/system/src/Grav/Common/Page/Pages.php b/system/src/Grav/Common/Page/Pages.php index 4e8614aec..9d5fd0ec1 100644 --- a/system/src/Grav/Common/Page/Pages.php +++ b/system/src/Grav/Common/Page/Pages.php @@ -291,37 +291,82 @@ class Pages return new Collection($children, [], $this); } + /** + * Get a page ancestor. + * + * @param string $route The relative URL of the page + * @param string $path The relative path of the ancestor folder + * + * @return Page|null + */ + public function ancestor($route, $path = null) + { + if (!is_null($path)) { + + $page = $this->getPage($route); + + if ($page->path() == $path) { + return $page; + } elseif (!$page->parent()->root()) { + return $this->ancestor($page->parent()->route(), $path); + } + } + + return null; + } + + /** + * Get a page ancestor trait. + * + * @param string $route The relative route of the page + * @param string $field The field name of the ancestor to query for + * + * @return Page|null + */ + public function inherited($route, $field = null) + { + if (!is_null($field)) { + + $page = $this->getPage($route); + + $ancestorField = $page->parent()->value('header.' . $field); + + if ($ancestorField != null) { + return $page->parent(); + } elseif (!$page->parent()->root()) { + return $this->inherited($page->parent()->route(), $field); + } + } + + return null; + } + /** * alias method to return find a page. * - * @param string $url The relative URL of the page + * @param string $route The relative URL of the page * @param bool $all * * @return Page|null */ - public function find($url, $all = false) + public function find($route, $all = false) { - return $this->dispatch($url, $all, false); + return $this->dispatch($route, $all, false); } /** * Dispatch URI to a page. * - * @param string $url The relative URL of the page + * @param string $route The relative URL of the page * @param bool $all * * @param bool $redirect * @return Page|null * @throws \Exception */ - public function dispatch($url, $all = false, $redirect = true) + public function dispatch($route, $all = false, $redirect = true) { - // Fetch page if there's a defined route to it. - $page = isset($this->routes[$url]) ? $this->get($this->routes[$url]) : null; - // Try without trailing slash - if (!$page && Utils::endsWith($url, '/')) { - $page = isset($this->routes[rtrim($url, '/')]) ? $this->get($this->routes[rtrim($url, '/')]) : null; - } + $page = $this->getPage($route); // Are we in the admin? this is important! $not_admin = !isset($this->grav['admin']); @@ -340,13 +385,13 @@ class Pages $config = $this->grav['config']; // See if route matches one in the site configuration - $route = $config->get("site.routes.{$url}"); + $route = $config->get("site.routes.{$route}"); if ($route) { $page = $this->dispatch($route, $all); } else { // Try Regex style redirects $uri = $this->grav['uri']; - $source_url = $url; + $source_url = $route; $extension = $uri->extension(); if (isset($extension) && !Utils::endsWith($uri->url(), $extension)) { $source_url.= '.' . $extension; @@ -389,6 +434,22 @@ class Pages return $page; } + /** + * Retrieve page instance based on the route + * + * @return Page + */ + protected function getPage($route) { + // Fetch page if there's a defined route to it. + $page = isset($this->routes[$route]) ? $this->get($this->routes[$route]) : null; + // Try without trailing slash + if (!$page && Utils::endsWith($route, '/')) { + $page = isset($this->routes[rtrim($route, '/')]) ? $this->get($this->routes[rtrim($route, '/')]) : null; + } + + return $page; + } + /** * Get root page. *