Exemple #1
0
 /**
  * Twig process that renders the site layout. This is the main twig process that renders the overall
  * page and handles all the layout for the site display.
  *
  * @param string $format Output format (defaults to HTML).
  * @return string the rendered output
  * @throws \RuntimeException
  */
 public function processSite($format = null)
 {
     // set the page now its been processed
     $this->grav->fireEvent('onTwigSiteVariables');
     $pages = $this->grav['pages'];
     $page = $this->grav['page'];
     $twig_vars = $this->twig_vars;
     $twig_vars['pages'] = $pages->root();
     $twig_vars['page'] = $page;
     $twig_vars['header'] = $page->header();
     $twig_vars['content'] = $page->content();
     $ext = '.' . ($format ? $format : 'html') . TWIG_EXT;
     // determine if params are set, if so disable twig cache
     $params = $this->grav['uri']->params(null, true);
     if (!empty($params)) {
         $this->twig->setCache(false);
     }
     // Get Twig template layout
     $template = $this->template($page->template() . $ext);
     try {
         $output = $this->twig->render($template, $twig_vars);
     } catch (\Twig_Error_Loader $e) {
         // If loader error, and not .html.twig, try it as fallback
         if ($ext != '.html' . TWIG_EXT) {
             try {
                 $output = $this->twig->render($page->template() . '.html' . TWIG_EXT, $twig_vars);
             } catch (\Twig_Error_Loader $e) {
                 throw new \RuntimeException($e->getRawMessage(), 404, $e);
             }
         } else {
             throw new \RuntimeException($e->getRawMessage(), 404, $e);
         }
     }
     return $output;
 }
 /**
  * Save the current page in a different language. Automatically switches to that language.
  *
  * @return bool True if the action was performed.
  */
 protected function taskSaveas()
 {
     if (!$this->authorizeTask('save', $this->dataPermissions())) {
         return false;
     }
     $data = (array) $this->data;
     $language = $data['lang'];
     if ($language) {
         $this->grav['session']->admin_lang = $language ?: 'en';
     }
     $uri = $this->grav['uri'];
     $obj = $this->admin->page($uri->route());
     $this->preparePage($obj, false, $language);
     $file = $obj->file();
     if ($file) {
         $filename = $this->determineFilenameIncludingLanguage($obj->name(), $language);
         $path = $obj->path() . DS . $filename;
         $aFile = File::instance($path);
         $aFile->save();
         $aPage = new Page();
         $aPage->init(new \SplFileInfo($path), $language . '.md');
         $aPage->header($obj->header());
         $aPage->rawMarkdown($obj->rawMarkdown());
         $aPage->validate();
         $aPage->filter();
         $aPage->save();
         $this->grav->fireEvent('onAdminAfterSave', new Event(['page' => $obj]));
     }
     $this->admin->setMessage($this->admin->translate('PLUGIN_ADMIN.SUCCESSFULLY_SWITCHED_LANGUAGE'), 'info');
     $this->setRedirect('/' . $language . $uri->route());
     return true;
 }
Exemple #3
0
 public function initTheme()
 {
     /** @var Themes $themes */
     $themes = $this->grav['themes'];
     try {
         $instance = $themes->load();
     } catch (\InvalidArgumentException $e) {
         throw new \RuntimeException($this->current() . ' theme could not be found');
     }
     if ($instance instanceof EventSubscriberInterface) {
         /** @var EventDispatcher $events */
         $events = $this->grav['events'];
         $events->addSubscriber($instance);
     }
     $this->grav['theme'] = $instance;
     $this->grav->fireEvent('onThemeInitialized');
 }
 /**
  * Handle deleting a file from a blueprint
  *
  * @return bool True if the action was performed.
  */
 protected function taskRemoveFileFromBlueprint()
 {
     $uri = $this->grav['uri'];
     $blueprint = base64_decode($uri->param('blueprint'));
     $path = base64_decode($uri->param('path'));
     $proute = base64_decode($uri->param('proute'));
     $type = $uri->param('type');
     $field = $uri->param('field');
     $event = $this->grav->fireEvent('onAdminCanSave', new Event(['controller' => &$this]));
     if (!$event['can_save']) {
         return false;
     }
     $this->taskRemoveMedia();
     if ($type == 'pages') {
         $page = $this->admin->page(true, $proute);
         $keys = explode('.', preg_replace('/^header./', '', $field));
         $header = (array) $page->header();
         $data_path = implode('.', $keys);
         $data = Utils::getDotNotation($header, $data_path);
         if (isset($data[$path])) {
             unset($data[$path]);
             Utils::setDotNotation($header, $data_path, $data);
             $page->header($header);
         }
         $page->save();
     } else {
         $blueprint_prefix = $type == 'config' ? '' : $type . '.';
         $blueprint_name = str_replace('/blueprints', '', str_replace('config/', '', $blueprint));
         $blueprint_field = $blueprint_prefix . $blueprint_name . '.' . $field;
         $files = $this->grav['config']->get($blueprint_field);
         if ($files) {
             foreach ($files as $key => $value) {
                 if ($key == $path) {
                     unset($files[$key]);
                 }
             }
         }
         $this->grav['config']->set($blueprint_field, $files);
         switch ($type) {
             case 'config':
                 $data = $this->grav['config']->get($blueprint_name);
                 $config = $this->admin->data($blueprint, $data);
                 $config->save();
                 break;
             case 'themes':
                 Theme::saveConfig($blueprint_name);
                 break;
             case 'plugins':
                 Plugin::saveConfig($blueprint_name);
                 break;
         }
     }
     $this->admin->json_response = ['status' => 'success', 'message' => $this->admin->translate('PLUGIN_ADMIN.REMOVE_SUCCESSFUL')];
     return true;
 }
Exemple #5
0
 /**
  * Twig process that renders the site layout. This is the main twig process that renders the overall
  * page and handles all the layout for the site display.
  *
  * @param string $format Output format (defaults to HTML).
  * @return string the rendered output
  * @throws \RuntimeException
  */
 public function processSite($format = null)
 {
     // set the page now its been processed
     $this->grav->fireEvent('onTwigSiteVariables');
     $pages = $this->grav['pages'];
     $page = $this->grav['page'];
     $content = $page->content();
     $config = $this->grav['config'];
     $twig_vars = $this->twig_vars;
     $twig_vars['pages'] = $pages->root();
     $twig_vars['page'] = $page;
     $twig_vars['header'] = $page->header();
     $twig_vars['content'] = $content;
     $ext = '.' . ($format ? $format : 'html') . TWIG_EXT;
     // determine if params are set, if so disable twig cache
     $params = $this->grav['uri']->params(null, true);
     if (!empty($params)) {
         $this->twig->setCache(false);
     }
     // Get Twig template layout
     $template = $this->template($page->template() . $ext);
     try {
         $output = $this->twig->render($template, $twig_vars);
     } catch (\Twig_Error_Loader $e) {
         // If loader error, and not .html.twig, try it as fallback
         if (Utils::contains($e->getMessage(), $template)) {
             $inflector = new Inflector();
             $error_msg = 'The template file for this page: "' . $template . '" is not provided by the theme: "' . $inflector->titleize($config->get('system.pages.theme')) . '"';
         } else {
             $error_msg = $e->getMessage();
         }
         // Try html version of this template if initial template was NOT html
         if ($ext != '.html' . TWIG_EXT) {
             try {
                 $output = $this->twig->render($page->template() . '.html' . TWIG_EXT, $twig_vars);
             } catch (\Twig_Error_Loader $e) {
                 throw new \RuntimeException($error_msg, 400, $e);
             }
         } else {
             throw new \RuntimeException($error_msg, 400, $e);
         }
     }
     return $output;
 }
Exemple #6
0
 /**
  * Twig process that renders the site layout. This is the main twig process that renders the overall
  * page and handles all the layout for the site display.
  *
  * @param string $format Output format (defaults to HTML).
  * @return string the rendered output
  * @throws \RuntimeException
  */
 public function processSite($format = null)
 {
     // set the page now its been processed
     $this->grav->fireEvent('onTwigSiteVariables');
     $pages = $this->grav['pages'];
     $page = $this->grav['page'];
     $twig_vars = $this->twig_vars;
     $twig_vars['pages'] = $pages->root();
     $twig_vars['page'] = $page;
     $twig_vars['header'] = $page->header();
     $twig_vars['content'] = $page->content();
     $ext = '.' . ($format ? $format : 'html') . TWIG_EXT;
     // Get Twig template layout
     $template = $this->template($page->template() . $ext);
     try {
         $output = $this->twig->render($template, $twig_vars);
     } catch (\Twig_Error_Loader $e) {
         throw new \RuntimeException($e->getRawMessage(), 404, $e);
     }
     return $output;
 }
Exemple #7
0
 /**
  * Twig process that renders the site layout. This is the main twig process that renders the overall
  * page and handles all the layout for the site display.
  *
  * @param string $format Output format (defaults to HTML).
  * @return string the rendered output
  * @throws \RuntimeException
  */
 public function processSite($format = null)
 {
     // set the page now its been processed
     $this->grav->fireEvent('onTwigSiteVariables');
     $pages = $this->grav['pages'];
     $page = $this->grav['page'];
     $content = $page->content();
     $config = $this->grav['config'];
     $twig_vars = $this->twig_vars;
     $twig_vars['pages'] = $pages->root();
     $twig_vars['page'] = $page;
     $twig_vars['header'] = $page->header();
     $twig_vars['media'] = $page->media();
     $twig_vars['content'] = $content;
     $ext = '.' . ($format ? $format : 'html') . TWIG_EXT;
     // determine if params are set, if so disable twig cache
     $params = $this->grav['uri']->params(null, true);
     if (!empty($params)) {
         $this->twig->setCache(false);
     }
     // Get Twig template layout
     $template = $this->template($page->template() . $ext);
     try {
         $output = $this->twig->render($template, $twig_vars);
     } catch (\Twig_Error_Loader $e) {
         $error_msg = $e->getMessage();
         // Try html version of this template if initial template was NOT html
         if ($ext != '.html' . TWIG_EXT) {
             try {
                 $output = $this->twig->render($page->template() . '.html' . TWIG_EXT, $twig_vars);
             } catch (\Twig_Error_Loader $e) {
                 throw new \RuntimeException($error_msg, 400, $e);
             }
         } else {
             throw new \RuntimeException($error_msg, 400, $e);
         }
     }
     return $output;
 }
Exemple #8
0
 /**
  * Recursive function to load & build page relationships.
  *
  * @param string $directory
  * @param Page|null $parent
  * @return Page
  * @throws \RuntimeException
  * @internal
  */
 protected function recurse($directory, Page &$parent = null)
 {
     $directory = rtrim($directory, DS);
     $iterator = new \DirectoryIterator($directory);
     $page = new Page();
     /** @var Config $config */
     $config = $this->grav['config'];
     $page->path($directory);
     if ($parent) {
         $page->parent($parent);
     }
     $page->orderDir($config->get('system.pages.order.dir'));
     $page->orderBy($config->get('system.pages.order.by'));
     // Add into instances
     if (!isset($this->instances[$page->path()])) {
         $this->instances[$page->path()] = $page;
         if ($parent && $page->path()) {
             $this->children[$parent->path()][$page->path()] = array('slug' => $page->slug());
         }
     } else {
         throw new \RuntimeException('Fatal error when creating page instances.');
     }
     // set current modified of page
     $last_modified = $page->modified();
     // flat for content availability
     $content_exists = false;
     /** @var \DirectoryIterator $file */
     foreach ($iterator as $file) {
         if ($file->isDot()) {
             continue;
         }
         $name = $file->getFilename();
         if ($file->isFile()) {
             // Update the last modified if it's newer than already found
             if ($file->getBasename() !== '.DS_Store' && ($modified = $file->getMTime()) > $last_modified) {
                 $last_modified = $modified;
             }
             if (preg_match('/^[^.].*' . CONTENT_EXT . '$/', $name)) {
                 $page->init($file);
                 $content_exists = true;
                 if ($config->get('system.pages.events.page')) {
                     $this->grav->fireEvent('onPageProcessed', new Event(['page' => $page]));
                 }
             }
         } elseif ($file->isDir()) {
             if (!$page->path()) {
                 $page->path($file->getPath());
             }
             $path = $directory . DS . $name;
             $child = $this->recurse($path, $page);
             if (Utils::startsWith($name, '_')) {
                 $child->routable(false);
             }
             $this->children[$page->path()][$child->path()] = array('slug' => $child->slug());
             if ($config->get('system.pages.events.page')) {
                 $this->grav->fireEvent('onFolderProcessed', new Event(['page' => $page]));
             }
         }
     }
     // Set routability to false if no page found
     if (!$content_exists) {
         $page->routable(false);
     }
     // Override the modified and ID so that it takes the latest change into account
     $page->modified($last_modified);
     $page->id($last_modified . md5($page->filePath()));
     // Sort based on Defaults or Page Overridden sort order
     $this->children[$page->path()] = $this->sort($page);
     return $page;
 }
Exemple #9
0
 /**
  * Recursive function to load & build page relationships.
  *
  * @param string $directory
  * @param Page|null $parent
  * @return Page
  * @throws \RuntimeException
  * @internal
  */
 protected function recurse($directory, Page &$parent = null)
 {
     $directory = rtrim($directory, DS);
     $page = new Page();
     /** @var Config $config */
     $config = $this->grav['config'];
     /** @var Language $language */
     $language = $this->grav['language'];
     // stuff to do at root page
     if ($parent === null) {
         // Fire event for memory and time consuming plugins...
         if ($config->get('system.pages.events.page')) {
             $this->grav->fireEvent('onBuildPagesInitialized');
         }
     }
     $page->path($directory);
     if ($parent) {
         $page->parent($parent);
     }
     $page->orderDir($config->get('system.pages.order.dir'));
     $page->orderBy($config->get('system.pages.order.by'));
     // Add into instances
     if (!isset($this->instances[$page->path()])) {
         $this->instances[$page->path()] = $page;
         if ($parent && $page->path()) {
             $this->children[$parent->path()][$page->path()] = array('slug' => $page->slug());
         }
     } else {
         throw new \RuntimeException('Fatal error when creating page instances.');
     }
     $content_exists = false;
     $pages_found = glob($directory . '/*' . CONTENT_EXT);
     $page_extensions = $language->getFallbackPageExtensions();
     if ($pages_found) {
         foreach ($page_extensions as $extension) {
             foreach ($pages_found as $found) {
                 if (preg_match('/^.*\\/[0-9A-Za-z\\-\\_]+(' . $extension . ')$/', $found)) {
                     $page_found = $found;
                     $page_extension = $extension;
                     break 2;
                 }
             }
         }
     }
     if ($parent && !empty($page_found)) {
         $file = new \SplFileInfo($page_found);
         $page->init($file, $page_extension);
         $content_exists = true;
         if ($config->get('system.pages.events.page')) {
             $this->grav->fireEvent('onPageProcessed', new Event(['page' => $page]));
         }
     }
     // set current modified of page
     $last_modified = $page->modified();
     /** @var \DirectoryIterator $file */
     foreach (new \FilesystemIterator($directory) as $file) {
         $name = $file->getFilename();
         // Ignore all hidden files if set.
         if ($this->ignore_hidden) {
             if ($name && $name[0] == '.') {
                 continue;
             }
         }
         if ($file->isFile()) {
             // Update the last modified if it's newer than already found
             if (!in_array($file->getBasename(), $this->ignore_files) && ($modified = $file->getMTime()) > $last_modified) {
                 $last_modified = $modified;
             }
         } elseif ($file->isDir() && !in_array($file->getFilename(), $this->ignore_folders)) {
             if (!$page->path()) {
                 $page->path($file->getPath());
             }
             $path = $directory . DS . $name;
             $child = $this->recurse($path, $page);
             if (Utils::startsWith($name, '_')) {
                 $child->routable(false);
             }
             $this->children[$page->path()][$child->path()] = array('slug' => $child->slug());
             if ($config->get('system.pages.events.page')) {
                 $this->grav->fireEvent('onFolderProcessed', new Event(['page' => $page]));
             }
         }
     }
     // Set routability to false if no page found
     if (!$content_exists) {
         $page->routable(false);
     }
     // Override the modified and ID so that it takes the latest change into account
     $page->modified($last_modified);
     $page->id($last_modified . md5($page->filePath()));
     // Sort based on Defaults or Page Overridden sort order
     $this->children[$page->path()] = $this->sort($page);
     return $page;
 }
Exemple #10
0
 /**
  * Returns the page creating it if it does not exist.
  *
  * @param $path
  *
  * @return Page
  */
 public function getPage($path)
 {
     /** @var Pages $pages */
     $pages = $this->grav['pages'];
     if ($path && $path[0] != '/') {
         $path = "/{$path}";
     }
     $page = $path ? $pages->dispatch($path, true) : $pages->root();
     if (!$page) {
         $slug = basename($path);
         if ($slug == '') {
             return null;
         }
         $ppath = str_replace('\\', '/', dirname($path));
         // Find or create parent(s).
         $parent = $this->getPage($ppath != '/' ? $ppath : '');
         // Create page.
         $page = new Page();
         $page->parent($parent);
         $page->filePath($parent->path() . '/' . $slug . '/' . $page->name());
         // Add routing information.
         $pages->addPage($page, $path);
         // Set if Modular
         $page->modularTwig($slug[0] == '_');
         // Determine page type.
         if (isset($this->session->{$page->route()})) {
             // Found the type and header from the session.
             $data = $this->session->{$page->route()};
             // Set the key header value
             $header = ['title' => $data['title']];
             if (isset($data['visible'])) {
                 if ($data['visible'] == '' || $data['visible']) {
                     // if auto (ie '')
                     $children = $page->parent()->children();
                     foreach ($children as $child) {
                         if ($child->order()) {
                             // set page order
                             $page->order(1000);
                             break;
                         }
                     }
                 }
                 if ($data['visible'] == 1 && !$page->order()) {
                     $header['visible'] = $data['visible'];
                 }
             }
             if ($data['name'] == 'modular') {
                 $header['body_classes'] = 'modular';
             }
             $name = $page->modular() ? str_replace('modular/', '', $data['name']) : $data['name'];
             $page->name($name . '.md');
             // Fire new event to allow plugins to manipulate page frontmatter
             $this->grav->fireEvent('onAdminCreatePageFrontmatter', new Event(['header' => &$header]));
             $page->header($header);
             $page->frontmatter(Yaml::dump((array) $page->header(), 10, 2, false));
         } else {
             // Find out the type by looking at the parent.
             $type = $parent->childType() ? $parent->childType() : $parent->blueprints()->get('child_type', 'default');
             $page->name($type . CONTENT_EXT);
             $page->header();
         }
         $page->modularTwig($slug[0] == '_');
     }
     return $page;
 }
Exemple #11
0
 /**
  * Handles form and saves the input data if its valid.
  *
  * @return bool True if the action was performed.
  */
 public function taskSave()
 {
     if (!$this->authorizeTask('save', $this->dataPermissions())) {
         return;
     }
     $reorder = false;
     $data = $this->post;
     // Special handler for pages data.
     if ($this->view == 'pages') {
         /** @var Page\Pages $pages */
         $pages = $this->grav['pages'];
         $config = $this->grav['config'];
         // Find new parent page in order to build the path.
         $route = !isset($data['route']) ? dirname($this->admin->route) : $data['route'];
         $obj = $this->admin->page(true);
         //Handle system.home.hide_in_urls
         $hide_home_route = $config->get('system.home.hide_in_urls', false);
         if ($hide_home_route) {
             $home_route = $config->get('system.home.alias');
             $topParent = $obj->topParent();
             if (isset($topParent)) {
                 if ($topParent->route() == $home_route) {
                     $baseRoute = (string) $topParent->route();
                     if ($obj->parent() != $topParent) {
                         $baseRoute .= $obj->parent()->route();
                     }
                     $route = isset($baseRoute) ? $baseRoute : null;
                 }
             }
         }
         $parent = $route && $route != '/' && $route != '.' ? $pages->dispatch($route, true) : $pages->root();
         $original_slug = $obj->slug();
         $original_order = intval(trim($obj->order(), '.'));
         // Change parent if needed and initialize move (might be needed also on ordering/folder change).
         $obj = $obj->move($parent);
         $this->preparePage($obj, false, $obj->language());
         // Reset slug and route. For now we do not support slug twig variable on save.
         $obj->slug($original_slug);
         $obj->validate();
         $obj->filter();
         // rename folder based on visible
         if ($original_order == 1000) {
             // increment order to force reshuffle
             $obj->order($original_order + 1);
         }
         // add or remove numeric prefix based on ordering value
         if (isset($data['ordering'])) {
             if ($data['ordering'] && !$obj->order()) {
                 $obj->order(1001);
             } elseif (!$data['ordering'] && $obj->order()) {
                 $obj->folder($obj->slug());
             }
         }
     } else {
         // Handle standard data types.
         $obj = $this->prepareData();
         $obj = $this->processFiles($obj);
         $obj->validate();
         $obj->filter();
     }
     if ($obj) {
         // Event to manipulate data before saving the object
         $this->grav->fireEvent('onAdminSave', new Event(['object' => &$obj]));
         $obj->save(true);
         $this->admin->setMessage($this->admin->translate('PLUGIN_ADMIN.SUCCESSFULLY_SAVED'), 'info');
     }
     if ($this->view != 'pages') {
         // Force configuration reload.
         /** @var Config $config */
         $config = $this->grav['config'];
         $config->reload();
         if ($this->view === 'users') {
             $this->grav['user']->merge(User::load($this->admin->route)->toArray());
         }
     }
     // Always redirect if a page route was changed, to refresh it
     if ($obj instanceof Page\Page) {
         if (method_exists($obj, 'unsetRouteSlug')) {
             $obj->unsetRouteSlug();
         }
         $multilang = $this->isMultilang();
         if ($multilang) {
             if (!$obj->language()) {
                 $obj->language($this->grav['session']->admin_lang);
             }
         }
         $admin_route = $this->grav['config']->get('plugins.admin.route');
         //Handle system.home.hide_in_urls
         $route = $obj->route();
         $hide_home_route = $config->get('system.home.hide_in_urls', false);
         if ($hide_home_route) {
             $home_route = $config->get('system.home.alias');
             $topParent = $obj->topParent();
             if (isset($topParent)) {
                 if ($topParent->route() == $home_route) {
                     $route = (string) $topParent->route() . $route;
                 }
             }
         }
         $redirect_url = '/' . ($multilang ? $obj->language() : '') . $admin_route . '/' . $this->view . $route;
         $this->setRedirect($redirect_url);
     }
     return true;
 }
Exemple #12
0
 /**
  * Recursive function to load & build page relationships.
  *
  * @param string $directory
  * @param null $parent
  * @return Page
  * @throws \RuntimeException
  * @internal
  */
 protected function recurse($directory = PAGES_DIR, Page &$parent = null)
 {
     $directory = rtrim($directory, DS);
     $iterator = new \DirectoryIterator($directory);
     $page = new Page();
     $config = $this->grav['config'];
     $page->path($directory);
     if ($parent) {
         $page->parent($parent);
     }
     $page->orderDir($config->get('system.pages.order.dir'));
     $page->orderBy($config->get('system.pages.order.by'));
     // Add into instances
     if (!isset($this->instances[$page->path()])) {
         $this->instances[$page->path()] = $page;
         if ($parent && $page->path()) {
             $this->children[$parent->path()][$page->path()] = array('slug' => $page->slug());
         }
     } else {
         throw new \RuntimeException('Fatal error when creating page instances.');
     }
     $last_modified = 0;
     /** @var \DirectoryIterator $file */
     foreach ($iterator as $file) {
         $name = $file->getFilename();
         $date = $file->getMTime();
         if ($date > $last_modified) {
             $last_modified = $date;
         }
         if ($file->isFile() && Utils::endsWith($name, CONTENT_EXT)) {
             $page->init($file);
             if ($config->get('system.pages.events.page')) {
                 $this->grav->fireEvent('onPageProcessed', new Event(['page' => $page]));
             }
         } elseif ($file->isDir() && !$file->isDot()) {
             if (!$page->path()) {
                 $page->path($file->getPath());
             }
             $path = $directory . DS . $name;
             $child = $this->recurse($path, $page);
             if (Utils::startsWith($name, '_')) {
                 $child->routable(false);
             }
             $this->children[$page->path()][$child->path()] = array('slug' => $child->slug());
             // set the modified time if not already set
             if (!$page->date()) {
                 $page->date($file->getMTime());
             }
             // set the last modified time on pages
             $this->lastModified($file->getMTime());
             if ($config->get('system.pages.events.page')) {
                 $this->grav->fireEvent('onFolderProcessed', new Event(['page' => $page]));
             }
         }
     }
     // Override the modified and ID so that it takes the latest change
     // into account
     $page->modified($last_modified);
     $page->id($last_modified . md5($page->filePath()));
     // Sort based on Defaults or Page Overridden sort order
     $this->children[$page->path()] = $this->sort($page);
     return $page;
 }
 /**
  * Handles form and saves the input data if its valid.
  *
  * @return bool True if the action was performed.
  */
 public function taskSave()
 {
     if (!$this->authorizeTask('save', $this->dataPermissions())) {
         return false;
     }
     $reorder = true;
     $data = (array) $this->data;
     $config = $this->grav['config'];
     // Special handler for pages data.
     if ($this->view == 'pages') {
         /** @var Pages $pages */
         $pages = $this->grav['pages'];
         // Find new parent page in order to build the path.
         $route = !isset($data['route']) ? dirname($this->admin->route) : $data['route'];
         /** @var Page $obj */
         $obj = $this->admin->page(true);
         // Ensure route is prefixed with a forward slash.
         $route = '/' . ltrim($route, '/');
         if (isset($data['frontmatter']) && !$this->checkValidFrontmatter($data['frontmatter'])) {
             $this->admin->setMessage($this->admin->translate('PLUGIN_ADMIN.INVALID_FRONTMATTER_COULD_NOT_SAVE'), 'error');
             return false;
         }
         //Handle system.home.hide_in_urls
         $hide_home_route = $config->get('system.home.hide_in_urls', false);
         if ($hide_home_route) {
             $home_route = $config->get('system.home.alias');
             $topParent = $obj->topParent();
             if (isset($topParent)) {
                 if ($topParent->route() == $home_route) {
                     $baseRoute = (string) $topParent->route();
                     if ($obj->parent() != $topParent) {
                         $baseRoute .= $obj->parent()->route();
                     }
                     $route = isset($baseRoute) ? $baseRoute : null;
                 }
             }
         }
         $parent = $route && $route != '/' && $route != '.' ? $pages->dispatch($route, true) : $pages->root();
         $original_slug = $obj->slug();
         $original_order = intval(trim($obj->order(), '.'));
         // Change parent if needed and initialize move (might be needed also on ordering/folder change).
         $obj = $obj->move($parent);
         $this->preparePage($obj, false, $obj->language());
         // Reset slug and route. For now we do not support slug twig variable on save.
         $obj->slug($original_slug);
         try {
             $obj->validate();
         } catch (\Exception $e) {
             $this->admin->setMessage($e->getMessage(), 'error');
             return false;
         }
         $obj->filter();
         // rename folder based on visible
         if ($original_order == 1000) {
             // increment order to force reshuffle
             $obj->order($original_order + 1);
         }
         // add or remove numeric prefix based on ordering value
         if (isset($data['ordering'])) {
             if ($data['ordering'] && !$obj->order()) {
                 $obj->order($this->getNextOrderInFolder($obj->parent()->path()));
                 $reorder = false;
             } elseif (!$data['ordering'] && $obj->order()) {
                 $obj->folder($obj->slug());
             }
         }
     } else {
         // Handle standard data types.
         $obj = $this->prepareData($data);
         try {
             $obj->validate();
         } catch (\Exception $e) {
             $this->admin->setMessage($e->getMessage(), 'error');
             return false;
         }
         $obj->filter();
     }
     // Process previously uploaded files for the current URI
     // and finally store them. Everything else will get discarded
     $queue = $this->admin->session()->getFlashObject('files-upload');
     $queue = $queue[base64_encode($this->uri)];
     if (is_array($queue)) {
         foreach ($queue as $key => $files) {
             foreach ($files as $destination => $file) {
                 if (!rename($file['tmp_name'], $destination)) {
                     throw new \RuntimeException(sprintf($this->admin->translate('PLUGIN_ADMIN.FILEUPLOAD_UNABLE_TO_MOVE', null, true), '"' . $file['tmp_name'] . '"', $destination));
                 }
                 unset($files[$destination]['tmp_name']);
             }
             if ($this->view == 'pages') {
                 $keys = explode('.', preg_replace('/^header./', '', $key));
                 $init_key = array_shift($keys);
                 if (count($keys) > 0) {
                     $new_data = isset($obj->header()->{$init_key}) ? $obj->header()->{$init_key} : [];
                     Utils::setDotNotation($new_data, implode('.', $keys), $files, true);
                 } else {
                     $new_data = $files;
                 }
                 if (isset($data['header'][$init_key])) {
                     $obj->modifyHeader($init_key, array_replace_recursive([], $data['header'][$init_key], $new_data));
                 } else {
                     $obj->modifyHeader($init_key, $new_data);
                 }
             } else {
                 // TODO: [this is JS handled] if it's single file, remove existing and use set, if it's multiple, use join
                 $obj->join($key, $files);
                 // stores
             }
         }
     }
     if ($obj) {
         // Event to manipulate data before saving the object
         $this->grav->fireEvent('onAdminSave', new Event(['object' => &$obj]));
         $obj->save($reorder);
         $this->admin->setMessage($this->admin->translate('PLUGIN_ADMIN.SUCCESSFULLY_SAVED'), 'info');
     }
     if ($this->view != 'pages') {
         // Force configuration reload.
         /** @var Config $config */
         $config = $this->grav['config'];
         $config->reload();
         if ($this->view === 'user') {
             $this->grav['user']->merge(User::load($this->admin->route)->toArray());
         }
     }
     // Always redirect if a page route was changed, to refresh it
     if ($obj instanceof Page) {
         if (method_exists($obj, 'unsetRouteSlug')) {
             $obj->unsetRouteSlug();
         }
         $multilang = $this->isMultilang();
         if ($multilang) {
             if (!$obj->language()) {
                 $obj->language($this->grav['session']->admin_lang);
             }
         }
         $admin_route = $this->admin->base;
         //Handle system.home.hide_in_urls
         $route = $obj->route();
         $hide_home_route = $config->get('system.home.hide_in_urls', false);
         if ($hide_home_route) {
             $home_route = $config->get('system.home.alias');
             $topParent = $obj->topParent();
             if (isset($topParent)) {
                 $top_parent_route = (string) $topParent->route();
                 if ($top_parent_route == $home_route && substr($route, 0, strlen($top_parent_route) + 1) != $top_parent_route . '/') {
                     $route = $top_parent_route . $route;
                 }
             }
         }
         $redirect_url = ($multilang ? '/' . $obj->language() : '') . $admin_route . '/' . $this->view . $route;
         $this->setRedirect($redirect_url);
     }
     return true;
 }