diff --git a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2020-06-25.sql b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2020-06-25.sql new file mode 100644 index 0000000000000..2c2ca01fe72f9 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2020-06-25.sql @@ -0,0 +1,2 @@ +ALTER TABLE `#__template_styles` ADD COLUMN `inheritable` tinyint(1) NOT NULL DEFAULT 0; +ALTER TABLE `#__template_styles` ADD COLUMN `parent` varchar(50) DEFAULT ''; diff --git a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2020-06-25.sql b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2020-06-25.sql new file mode 100644 index 0000000000000..f56fffe8e83dd --- /dev/null +++ b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2020-06-25.sql @@ -0,0 +1,2 @@ +ALTER TABLE "#__template_styles" ADD COLUMN "inheritable" smallint NOT NULL DEFAULT 0; +ALTER TABLE "#__template_styles" ADD COLUMN "parent" varchar(50) DEFAULT ""; diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql index c3f69d898295a..df444d5e6c412 100644 --- a/installation/sql/mysql/base.sql +++ b/installation/sql/mysql/base.sql @@ -782,6 +782,8 @@ CREATE TABLE IF NOT EXISTS `#__template_styles` ( `client_id` tinyint(1) unsigned NOT NULL DEFAULT 0, `home` char(7) NOT NULL DEFAULT '0', `title` varchar(255) NOT NULL DEFAULT '', + `inheritable` tinyint(1) NOT NULL DEFAULT 0, + `parent` varchar(50) DEFAULT '', `params` text NOT NULL, PRIMARY KEY (`id`), KEY `idx_template` (`template`), @@ -793,9 +795,9 @@ CREATE TABLE IF NOT EXISTS `#__template_styles` ( -- Dumping data for table `#__template_styles` -- -INSERT INTO `#__template_styles` (`id`, `template`, `client_id`, `home`, `title`, `params`) VALUES -(10, 'atum', 1, '1', 'atum - Default', ''), -(11, 'cassiopeia', 0, '1', 'cassiopeia - Default', '{"logoFile":"","fluidContainer":"0","sidebarLeftWidth":"3","sidebarRightWidth":"3"}'); +INSERT INTO `#__template_styles` (`id`, `template`, `client_id`, `home`, `title`, `inheritable`, `parent`, `params`) VALUES +(10, 'atum', 1, '1', 'atum - Default', 0, '', ''), +(11, 'cassiopeia', 0, '1', 'cassiopeia - Default', 0, '', '{"logoFile":"","fluidContainer":"0","sidebarLeftWidth":"3","sidebarRightWidth":"3"}'); -- -------------------------------------------------------- diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index aaf8ee57f0507..c936e8e1fd247 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -798,6 +798,8 @@ CREATE TABLE IF NOT EXISTS "#__template_styles" ( "client_id" smallint DEFAULT 0 NOT NULL, "home" varchar(7) DEFAULT '0' NOT NULL, "title" varchar(255) DEFAULT '' NOT NULL, + `inheritable` smallint DEFAULT 0 NOT NULL, + `parent` varchar(50) DEFAULT '', "params" text NOT NULL, PRIMARY KEY ("id") ); @@ -808,10 +810,9 @@ CREATE INDEX "#__template_styles_idx_client_id_home" ON "#__template_styles" ("c -- -- Dumping data for table `#__template_styles` -- - -INSERT INTO "#__template_styles" ("id", "template", "client_id", "home", "title", "params") VALUES -(10, 'atum', 1, '1', 'atum - Default', ''), -(11, 'cassiopeia', 0, '1', 'cassiopeia - Default', '{"logoFile":"","fluidContainer":"0","sidebarLeftWidth":"3","sidebarRightWidth":"3"}'); +INSERT INTO "#__template_styles" ("id", "template", "client_id", "home", "title", "inheritable", "parent", "params") VALUES +(10, 'atum', 1, '1', 'atum - Default', 0, '', ''), +(11, 'cassiopeia', 0, '1', 'cassiopeia - Default', 0, '', '{"logoFile":"","fluidContainer":"0","sidebarLeftWidth":"3","sidebarRightWidth":"3"}'); SELECT setval('#__template_styles_id_seq', 12, false); diff --git a/installation/src/Application/InstallationApplication.php b/installation/src/Application/InstallationApplication.php index 71f8b746fbe13..bc50f4461b500 100644 --- a/installation/src/Application/InstallationApplication.php +++ b/installation/src/Application/InstallationApplication.php @@ -405,6 +405,8 @@ public function getTemplate($params = false) $template = new \stdClass; $template->template = 'template'; $template->params = new Registry; + $template->inheritable = 0; + $template->parent = null; return $template; } @@ -544,10 +546,11 @@ public function render() $file = $this->input->getCmd('tmpl', 'index'); $options = [ - 'template' => 'template', - 'file' => $file . '.php', - 'directory' => JPATH_THEMES, - 'params' => '{}', + 'template' => 'template', + 'file' => $file . '.php', + 'directory' => JPATH_THEMES, + 'params' => '{}', + "templateInherits" => '' ]; } diff --git a/libraries/src/Application/AdministratorApplication.php b/libraries/src/Application/AdministratorApplication.php index 3758813d64f1e..b12d3cc970da6 100644 --- a/libraries/src/Application/AdministratorApplication.php +++ b/libraries/src/Application/AdministratorApplication.php @@ -108,6 +108,7 @@ public function dispatch($component = null) case 'html': // Get the template $template = $this->getTemplate(true); + $clientId = $this->getClientId(); // Store the template and its params to the config $this->set('theme', $template->template); @@ -121,7 +122,12 @@ public function dispatch($component = null) $wr->addExtensionRegistryFile($component); } - $wr->addTemplateRegistryFile($template->template, $this->getClientId()); + if (!empty($template->parent)) + { + $wr->addTemplateRegistryFile($template->parent, $clientId); + } + + $wr->addTemplateRegistryFile($template->template, $clientId); break; @@ -223,8 +229,9 @@ public function getTemplate($params = false) // Load the template name from the database $db = Factory::getDbo(); + $query = $db->getQuery(true) - ->select($db->quoteName(['s.template', 's.params'])) + ->select($db->quoteName(['s.template', 's.params', 's.inheritable', 's.parent'])) ->from($db->quoteName('#__template_styles', 's')) ->join( 'LEFT', @@ -260,20 +267,26 @@ public function getTemplate($params = false) $template->template = InputFilter::getInstance()->clean($template->template, 'cmd'); $template->params = new Registry($template->params); - if (!file_exists(JPATH_THEMES . '/' . $template->template . '/index.php')) + // Fallback template + if (!file_exists(JPATH_THEMES . '/' . $template->template . '/index.php') + && !file_exists(JPATH_THEMES . '/' . $template->parent . '/index.php')) { $this->enqueueMessage(Text::_('JERROR_ALERTNOTEMPLATE'), 'error'); $template->params = new Registry; $template->template = 'atum'; + + // Check, the data were found and if template really exists + if (!file_exists(JPATH_THEMES . '/' . $template->template . '/index.php')) + { + throw new \InvalidArgumentException(Text::sprintf('JERROR_COULD_NOT_FIND_TEMPLATE', $template->template)); + } } // Cache the result $this->template = $template; - if (!file_exists(JPATH_THEMES . '/' . $template->template . '/index.php')) - { - throw new \InvalidArgumentException(Text::sprintf('JERROR_COULD_NOT_FIND_TEMPLATE', $template->template)); - } + // Pass the parent template to the state + $this->set('themeInherits', $template->parent); if ($params) { diff --git a/libraries/src/Application/CMSApplication.php b/libraries/src/Application/CMSApplication.php index 10e99a94a15db..759da7cccae8a 100644 --- a/libraries/src/Application/CMSApplication.php +++ b/libraries/src/Application/CMSApplication.php @@ -561,17 +561,19 @@ public static function getRouter($name = null, array $options = array()) */ public function getTemplate($params = false) { - $template = new \stdClass; - - $template->template = 'system'; - $template->params = new Registry; - if ($params) { + $template = new \stdClass; + + $template->template = 'system'; + $template->params = new Registry; + $template->inheritable = 0; + $template->parent = ''; + return $template; } - return $template->template; + return 'system'; } /** @@ -939,10 +941,11 @@ public function redirect($url, $status = 303) protected function render() { // Setup the document options. - $this->docOptions['template'] = $this->get('theme'); - $this->docOptions['file'] = $this->get('themeFile', 'index.php'); - $this->docOptions['params'] = $this->get('themeParams'); - $this->docOptions['csp_nonce'] = $this->get('csp_nonce'); + $this->docOptions['template'] = $this->get('theme'); + $this->docOptions['file'] = $this->get('themeFile', 'index.php'); + $this->docOptions['params'] = $this->get('themeParams'); + $this->docOptions['csp_nonce'] = $this->get('csp_nonce'); + $this->docOptions['templateInherits'] = $this->get('themeInherits'); if ($this->get('themes.base')) { diff --git a/libraries/src/Application/SiteApplication.php b/libraries/src/Application/SiteApplication.php index 8d66274455b6e..856ebde2df96e 100644 --- a/libraries/src/Application/SiteApplication.php +++ b/libraries/src/Application/SiteApplication.php @@ -176,6 +176,11 @@ public function dispatch($component = null) $wr->addExtensionRegistryFile($component); } + if ($template->parent) + { + $wr->addTemplateRegistryFile($template->parent, $this->getClientId()); + } + $wr->addTemplateRegistryFile($template->template, $this->getClientId()); break; @@ -394,7 +399,17 @@ public function getTemplate($params = false) { if (\is_object($this->template)) { - if (!file_exists(JPATH_THEMES . '/' . $this->template->template . '/index.php')) + if ($this->template->parent) + { + if (!file_exists(JPATH_THEMES . '/' . $this->template->template . '/index.php')) + { + if (!file_exists(JPATH_THEMES . '/' . $this->template->parent . '/index.php')) + { + throw new \InvalidArgumentException(Text::sprintf('JERROR_COULD_NOT_FIND_TEMPLATE', $this->template->template)); + } + } + } + elseif (!file_exists(JPATH_THEMES . '/' . $this->template->template . '/index.php')) { throw new \InvalidArgumentException(Text::sprintf('JERROR_COULD_NOT_FIND_TEMPLATE', $this->template->template)); } @@ -453,8 +468,9 @@ public function getTemplate($params = false) { // Load styles $db = Factory::getDbo(); + $query = $db->getQuery(true) - ->select($db->quoteName(['id', 'home', 'template', 's.params'])) + ->select($db->quoteName(['id', 'home', 'template', 's.params', 'inheritable', 'parent'])) ->from($db->quoteName('#__template_styles', 's')) ->where( [ @@ -529,7 +545,35 @@ public function getTemplate($params = false) $template->template = InputFilter::getInstance()->clean($template->template, 'cmd'); // Fallback template - if (!file_exists(JPATH_THEMES . '/' . $template->template . '/index.php')) + if (!empty($template->parent)) + { + if (!file_exists(JPATH_THEMES . '/' . $template->template . '/index.php')) + { + if (!file_exists(JPATH_THEMES . '/' . $template->parent . '/index.php')) + { + $this->enqueueMessage(Text::_('JERROR_ALERTNOTEMPLATE'), 'error'); + + // Try to find data for 'cassiopeia' template + $original_tmpl = $template->template; + + foreach ($templates as $tmpl) + { + if ($tmpl->template === 'cassiopeia') + { + $template = $tmpl; + break; + } + } + + // Check, the data were found and if template really exists + if (!file_exists(JPATH_THEMES . '/' . $template->template . '/index.php')) + { + throw new \InvalidArgumentException(Text::sprintf('JERROR_COULD_NOT_FIND_TEMPLATE', $original_tmpl)); + } + } + } + } + elseif (!file_exists(JPATH_THEMES . '/' . $template->template . '/index.php')) { $this->enqueueMessage(Text::_('JERROR_ALERTNOTEMPLATE'), 'error'); @@ -751,6 +795,9 @@ protected function render() $this->set('themeFile', $file . '.php'); } + // Pass the parent template to the state + $this->set('themeInherits', $template->parent); + break; } diff --git a/libraries/src/Document/HtmlDocument.php b/libraries/src/Document/HtmlDocument.php index 6777db65a0a47..5e50d092cb825 100644 --- a/libraries/src/Document/HtmlDocument.php +++ b/libraries/src/Document/HtmlDocument.php @@ -806,13 +806,23 @@ protected function _fetchTemplate($params = array()) $filter = InputFilter::getInstance(); $template = $filter->clean($params['template'], 'cmd'); $file = $filter->clean($params['file'], 'cmd'); + $inherits = $params['templateInherits']; + $baseDir = $directory . '/' . $template; - if (!file_exists($directory . '/' . $template . '/' . $file)) + if (!empty($inherits) + && !file_exists($directory . '/' . $template . '/' . $file) + && file_exists($directory . '/' . $inherits . '/' . $file) + ) + { + $baseDir = $directory . '/' . $inherits; + } + + if (!file_exists($baseDir . '/' . $file)) { $template = 'system'; } - if (!file_exists($directory . '/' . $template . '/' . $file)) + if (!file_exists($baseDir . '/' . $file)) { $file = 'index.php'; } @@ -822,15 +832,16 @@ protected function _fetchTemplate($params = array()) // 1.5 or core then 1.6 $lang->load('tpl_' . $template, JPATH_BASE) + || $lang->load('tpl_' . $inherits, $directory . '/' . $inherits) || $lang->load('tpl_' . $template, $directory . '/' . $template); // Assign the variables - $this->template = $template; $this->baseurl = Uri::base(true); $this->params = $params['params'] ?? new Registry; + $this->template = $template; // Load - $this->_template = $this->_loadTemplate($directory . '/' . $template, $file); + $this->_template = $this->_loadTemplate($baseDir, $file); return $this; } diff --git a/libraries/src/HTML/HTMLHelper.php b/libraries/src/HTML/HTMLHelper.php index 9c27a370a7cea..497d61759d827 100644 --- a/libraries/src/HTML/HTMLHelper.php +++ b/libraries/src/HTML/HTMLHelper.php @@ -436,8 +436,15 @@ protected static function includeRelativeFiles($folder, $file, $relative, $detec // If relative search in template directory or media directory if ($relative) { - // Get the template - $template = Factory::getApplication()->getTemplate(); + $app = Factory::getApplication(); + $template = $app->getTemplate(true); + $templaPath = JPATH_THEMES; + + if ($template->inheritable || !empty($template->parent)) + { + $client = $app->isClient('administrator') === true ? 'administrator' : 'site'; + $templaPath = JPATH_ROOT . "/media/templates/$client"; + } // For each potential files foreach ($potential as $strip) @@ -452,7 +459,19 @@ protected static function includeRelativeFiles($folder, $file, $relative, $detec */ foreach ($files as $file) { - $found = static::addFileToBuffer(JPATH_THEMES . "/$template/$folder/$file", $ext, $debugMode); + if (!empty($template->parent)) + { + $found = static::addFileToBuffer("$templaPath/$template->template/$folder/$file", $ext, $debugMode); + + if (empty($found)) + { + $found = static::addFileToBuffer("$templaPath/$template->parent/$folder/$file", $ext, $debugMode); + } + } + else + { + $found = static::addFileToBuffer("$templaPath/$template->template/$folder/$file", $ext, $debugMode); + } if (!empty($found)) { @@ -495,23 +514,37 @@ protected static function includeRelativeFiles($folder, $file, $relative, $detec } // Try to deal with system files in the template folder - $found = static::addFileToBuffer(JPATH_THEMES . "/$template/$folder/system/$element/$file", $ext, $debugMode); - - if (!empty($found)) + if (!empty($template->parent)) { - $includes[] = $found; + $found = static::addFileToBuffer("$templaPath/$template->template/$folder/system/$element/$file", $ext, $debugMode); - break; - } + if (!empty($found)) + { + $includes[] = $found; - // Try to deal with system files in the media folder - $found = static::addFileToBuffer(JPATH_ROOT . "/media/system/$folder/$element/$file", $ext, $debugMode); + break; + } - if (!empty($found)) + $found = static::addFileToBuffer("$templaPath/$template->parent/$folder/system/$element/$file", $ext, $debugMode); + + if (!empty($found)) + { + $includes[] = $found; + + break; + } + } + else { - $includes[] = $found; + // Try to deal with system files in the media folder + $found = static::addFileToBuffer(JPATH_ROOT . "/media/system/$folder/$element/$file", $ext, $debugMode); - break; + if (!empty($found)) + { + $includes[] = $found; + + break; + } } } else @@ -527,13 +560,37 @@ protected static function includeRelativeFiles($folder, $file, $relative, $detec } // Try to deal with system files in the template folder - $found = static::addFileToBuffer(JPATH_THEMES . "/$template/$folder/system/$file", $ext, $debugMode); + if (!empty($template->parent)) + { + $found = static::addFileToBuffer("$templaPath/$template->templete/$folder/system/$file", $ext, $debugMode); - if (!empty($found)) + if (!empty($found)) + { + $includes[] = $found; + + break; + } + + $found = static::addFileToBuffer("$templaPath/$template->parent/$folder/system/$file", $ext, $debugMode); + + if (!empty($found)) + { + $includes[] = $found; + + break; + } + } + else { - $includes[] = $found; + // Try to deal with system files in the template folder + $found = static::addFileToBuffer("$templaPath/$template->templete/$folder/system/$file", $ext, $debugMode); - break; + if (!empty($found)) + { + $includes[] = $found; + + break; + } } // Try to deal with system files in the media folder diff --git a/libraries/src/Helper/ModuleHelper.php b/libraries/src/Helper/ModuleHelper.php index b18672a574a71..579ad4257e5b7 100644 --- a/libraries/src/Helper/ModuleHelper.php +++ b/libraries/src/Helper/ModuleHelper.php @@ -320,8 +320,9 @@ public static function renderRawModule($module, Registry $params, $attribs = arr */ public static function getLayoutPath($module, $layout = 'default') { - $template = Factory::getApplication()->getTemplate(); + $templateObj = Factory::getApplication()->getTemplate(true); $defaultLayout = $layout; + $template = $templateObj->template; if (strpos($layout, ':') !== false) { @@ -334,6 +335,7 @@ public static function getLayoutPath($module, $layout = 'default') // Build the template and base path for the layout $tPath = JPATH_THEMES . '/' . $template . '/html/' . $module . '/' . $layout . '.php'; + $iPath = JPATH_THEMES . '/' . $templateObj->parent . '/html/' . $module . '/' . $layout . '.php'; $bPath = JPATH_BASE . '/modules/' . $module . '/tmpl/' . $defaultLayout . '.php'; $dPath = JPATH_BASE . '/modules/' . $module . '/tmpl/default.php'; @@ -343,6 +345,11 @@ public static function getLayoutPath($module, $layout = 'default') return $tPath; } + if (!empty($templateObj->parent) && file_exists($iPath)) + { + return $iPath; + } + if (file_exists($bPath)) { return $bPath; diff --git a/libraries/src/Installer/Adapter/TemplateAdapter.php b/libraries/src/Installer/Adapter/TemplateAdapter.php index 2d5e23456ff2f..0c2e22389073e 100644 --- a/libraries/src/Installer/Adapter/TemplateAdapter.php +++ b/libraries/src/Installer/Adapter/TemplateAdapter.php @@ -323,6 +323,8 @@ protected function parseQueries() $db->quoteName('home'), $db->quoteName('title'), $db->quoteName('params'), + $db->quoteName('parent'), + $db->quoteName('inherits'), ]; $values = $query->bindArray( @@ -332,6 +334,8 @@ protected function parseQueries() '0', Text::sprintf('JLIB_INSTALLER_DEFAULT_STYLE', Text::_($this->extension->name)), $this->extension->params, + (int) $this->manifest->inheritable, + $this->manifest->parent ?: '', ], [ ParameterType::STRING, @@ -339,6 +343,8 @@ protected function parseQueries() ParameterType::STRING, ParameterType::STRING, ParameterType::STRING, + ParameterType::INTEGER, + ParameterType::STRING, ] ); diff --git a/libraries/src/Layout/FileLayout.php b/libraries/src/Layout/FileLayout.php index ee76f95b14d43..9632a1c3cac2c 100644 --- a/libraries/src/Layout/FileLayout.php +++ b/libraries/src/Layout/FileLayout.php @@ -535,6 +535,9 @@ public function setLayoutId($layoutId) */ public function getDefaultIncludePaths() { + // Get the template + $template = Factory::getApplication()->getTemplate(true); + // Reset includePaths $paths = array(); @@ -550,7 +553,13 @@ public function getDefaultIncludePaths() if (!empty($component)) { // (2) Component template overrides path - $paths[] = JPATH_THEMES . '/' . Factory::getApplication()->getTemplate() . '/html/layouts/' . $component; + $paths[] = JPATH_THEMES . '/' . $template->template . '/html/layouts/' . $component; + + if (!empty($template->parent)) + { + // (2.a) Component template overrides path for an inherited template using the parent + $paths[] = JPATH_THEMES . '/' . $template->parent . '/html/layouts/' . $component; + } // (3) Component path if ($this->options->get('client') == 0) @@ -564,7 +573,13 @@ public function getDefaultIncludePaths() } // (4) Standard Joomla! layouts overridden - $paths[] = JPATH_THEMES . '/' . Factory::getApplication()->getTemplate() . '/html/layouts'; + $paths[] = JPATH_THEMES . '/' . $template->template . '/html/layouts'; + + if (!empty($template->parent)) + { + // (4.a) Component template overrides path for an inherited template using the parent + $paths[] = JPATH_THEMES . '/' . $template->parent . '/html/layouts'; + } // (5 - lower priority) Frontend base layouts $paths[] = JPATH_ROOT . '/layouts'; diff --git a/libraries/src/MVC/View/HtmlView.php b/libraries/src/MVC/View/HtmlView.php index 9f4d6a8fd7e2d..bb9005d25b138 100644 --- a/libraries/src/MVC/View/HtmlView.php +++ b/libraries/src/MVC/View/HtmlView.php @@ -372,7 +372,7 @@ public function loadTemplate($tpl = null) // Clear prior output $this->_output = null; - $template = Factory::getApplication()->getTemplate(); + $template = Factory::getApplication()->getTemplate(true); $layout = $this->getLayout(); $layoutTemplate = $this->getLayoutTemplate(); @@ -385,14 +385,15 @@ public function loadTemplate($tpl = null) // Load the language file for the template $lang = Factory::getLanguage(); - $lang->load('tpl_' . $template, JPATH_BASE) - || $lang->load('tpl_' . $template, JPATH_THEMES . "/$template"); + $lang->load('tpl_' . $template->template, JPATH_BASE) + || $lang->load('tpl_' . $template->parent, JPATH_THEMES . '/' . $template->parent) + || $lang->load('tpl_' . $template->template, JPATH_THEMES . '/' . $template->template); // Change the template folder if alternative layout is in different template - if (isset($layoutTemplate) && $layoutTemplate !== '_' && $layoutTemplate != $template) + if (isset($layoutTemplate) && $layoutTemplate !== '_' && $layoutTemplate != $template->template) { $this->_path['template'] = str_replace( - JPATH_THEMES . DIRECTORY_SEPARATOR . $template, + JPATH_THEMES . DIRECTORY_SEPARATOR . $template->template, JPATH_THEMES . DIRECTORY_SEPARATOR . $layoutTemplate, $this->_path['template'] ); @@ -491,6 +492,9 @@ protected function _setPath($type, $path) // Actually add the user-specified directories $this->_addPath($type, $path); + // Get the active template object + $template = $app->getTemplate(true); + // Always add the fallback directories as last resort switch (strtolower($type)) { @@ -499,8 +503,20 @@ protected function _setPath($type, $path) if (isset($app)) { $component = preg_replace('/[^A-Z0-9_\.-]/i', '', $component); - $fallback = JPATH_THEMES . '/' . $app->getTemplate() . '/html/' . $component . '/' . $this->getName(); - $this->_addPath('template', $fallback); + $name = $this->getName(); + + if (!empty($template->parent)) + { + // Parent template's overrides + $this->_addPath('template', JPATH_THEMES . '/' . $template->parent . '/html/' . $component . '/' . $name); + + // Child template's overrides + $this->_addPath('template', JPATH_THEMES . '/' . $template->template . '/html/' . $component . '/' . $name); + + break; + } + + $this->_addPath('template', JPATH_THEMES . '/' . $template->template . '/html/' . $component . '/' . $name); } break; } diff --git a/libraries/src/Plugin/PluginHelper.php b/libraries/src/Plugin/PluginHelper.php index f1cb426ded6e2..44b28a388ebaf 100644 --- a/libraries/src/Plugin/PluginHelper.php +++ b/libraries/src/Plugin/PluginHelper.php @@ -43,20 +43,22 @@ abstract class PluginHelper */ public static function getLayoutPath($type, $name, $layout = 'default') { - $template = Factory::getApplication()->getTemplate(); + $templateObj = Factory::getApplication()->getTemplate(true); $defaultLayout = $layout; + $template = $templateObj->template; if (strpos($layout, ':') !== false) { // Get the template and file name from the string $temp = explode(':', $layout); - $template = $temp[0] === '_' ? $template : $temp[0]; + $template = $temp[0] === '_' ? $templateObj->template : $temp[0]; $layout = $temp[1]; $defaultLayout = $temp[1] ?: 'default'; } // Build the template and base path for the layout $tPath = JPATH_THEMES . '/' . $template . '/html/plg_' . $type . '_' . $name . '/' . $layout . '.php'; + $iPath = JPATH_THEMES . '/' . $templateObj->parent . '/html/plg_' . $type . '_' . $name . '/' . $layout . '.php'; $bPath = JPATH_PLUGINS . '/' . $type . '/' . $name . '/tmpl/' . $defaultLayout . '.php'; $dPath = JPATH_PLUGINS . '/' . $type . '/' . $name . '/tmpl/default.php'; @@ -65,6 +67,10 @@ public static function getLayoutPath($type, $name, $layout = 'default') { return $tPath; } + elseif (!empty($templateObj->parent) && file_exists($iPath)) + { + return $iPath; + } elseif (file_exists($bPath)) { return $bPath;