diff --git a/Sources/Theme.php b/Sources/Theme.php index 861fa74388..1b6a696a56 100644 --- a/Sources/Theme.php +++ b/Sources/Theme.php @@ -507,25 +507,34 @@ public static function loadSubTemplates(): void public static function loadSubTemplate(string|array $sub_template_name, bool|string $fatal = false): void { $template_name = \is_array($sub_template_name) ? $sub_template_name[0] : $sub_template_name; + $function_params = \is_array($sub_template_name) ? ($sub_template_name[1] ?? []) : []; // Add the sub-template to the debug context if debugging is enabled. if (DebugUtils::isDebugEnabled()) { DebugUtils::addDebugSource('sub_templates', $template_name); } - // Determine the template function name and any associated parameters. - if (\is_array($sub_template_name)) { - $theme_function = 'template_' . $sub_template_name[0]; - $function_params = $sub_template_name[1] ?? []; - } else { - $theme_function = 'template_' . $sub_template_name; - $function_params = []; + $template_loaded = false; + + if (\is_string($template_name) && \str_contains($template_name, '::')) { + $template_name = \preg_replace_callback( + '/(#?)_(above|below)$/i', + fn($m) => \ucfirst($m[2]) . $m[1], + $template_name + ); + + if ($callable = Utils::getCallable($template_name, true)) { + \call_user_func_array($callable, $function_params); + $template_loaded = true; + } } - // Attempt to call the sub-template function. - if (\is_callable($theme_function)) { - \call_user_func_array($theme_function, $function_params); - } else { + if (!$template_loaded && ($callable = Utils::getCallable('template_' . $template_name, true))) { + \call_user_func_array($callable, $function_params); + $template_loaded = true; + } + + if (!$template_loaded) { // Handle errors based on the $fatal parameter. if ($fatal === false) { ErrorHandler::fatalLang( diff --git a/Sources/Utils.php b/Sources/Utils.php index 32544997ef..27caebcdee 100644 --- a/Sources/Utils.php +++ b/Sources/Utils.php @@ -2477,6 +2477,28 @@ public static function getCallable(string|callable $input, ?bool $ignore_errors return $callable; } + /** + * Universal template callback invoker following the logic of the "first file". + * + * @param string $name Callback name (without prefix) + * @param string $prefix Function name prefix (e.g. 'template_callback_' or 'template_profile_') + * @return mixed Result of the callback execution or null if not found + */ + public static function callTemplateCallback(string $name, string $prefix = 'template_callback_'): mixed + { + if (function_exists($prefix . $name)) { + $name = $prefix . $name; + } + + $callable = Utils::getCallable($name); + + if ($callable) { + return call_user_func($callable); + } + + return null; + } + /************************* * Internal static methods *************************/ diff --git a/Themes/default/Admin.template.php b/Themes/default/Admin.template.php index dd999d74c4..f3b6011d65 100644 --- a/Themes/default/Admin.template.php +++ b/Themes/default/Admin.template.php @@ -872,8 +872,7 @@ function ($v) // Hang about? Are you pulling my leg - a callback?! if (is_array($config_var) && $config_var['type'] == 'callback') { - if (function_exists('template_callback_' . $config_var['name'])) - call_user_func('template_callback_' . $config_var['name']); + Utils::callTemplateCallback($config_var['name']); continue; } diff --git a/Themes/default/Profile.template.php b/Themes/default/Profile.template.php index 6331df2eff..fbb507b4cc 100644 --- a/Themes/default/Profile.template.php +++ b/Themes/default/Profile.template.php @@ -1505,10 +1505,8 @@ function template_edit_options() elseif ($field['type'] == 'callback') { - if (isset($field['callback_func']) && function_exists('template_profile_' . $field['callback_func'])) - { - $callback_func = 'template_profile_' . $field['callback_func']; - $callback_func(); + if (!empty($field['callback_func'])) { + Utils::callTemplateCallback($field['callback_func'], 'template_profile_'); } } else diff --git a/Themes/default/Register.template.php b/Themes/default/Register.template.php index ede834d014..f274475f7b 100644 --- a/Themes/default/Register.template.php +++ b/Themes/default/Register.template.php @@ -198,10 +198,8 @@ function verifyAgree() { if ($field['type'] == 'callback') { - if (isset($field['callback_func']) && function_exists('template_profile_' . $field['callback_func'])) - { - $callback_func = 'template_profile_' . $field['callback_func']; - $callback_func(); + if (!empty($field['callback_func'])) { + Utils::callTemplateCallback($field['callback_func'], 'template_profile_'); } } else