This is my proposal on implementing the ability to switch frontend and backend templates independently.

- This introduces a new option "template_backend" that will be set to indicate the backend template, defaults to 2k11.
- The "Engine: xxx" line in info.txt still works, but only for the frontend
- The frontend fallback chain defaults to the old "default" template to ensure that themes will work that have "old-style" HTML output
- The backend fallback chain only falls back to 2k11 and then "default"
- In the future, we will remove templates/default/admin once the mechanism is proven stable

To test this in all cases you can:

- Copy 2k11/ to 2k11-custom, edit info.txt, give it a distinct name. Edit the admin/index.tpl file to add some code to ensure that you will see that template in the backend if you pick it, or adjust the style.css or whatever.
- Copy idea/ to idea-custom, edit info.txt, add a "Engine: 2k11" line. Now you can test how a template would look like that fallsback on 2k11 instead of "default"

Those permutations can be checked and come to my mind:

- Backend: 2k11, Frontend: 2k11
- Backend: 2k11-custom, Frontend: 2k11
- Backend: 2k11, Frontend: 2k11-custom

- Backend: 2k11, Frontend: idea
- Backend: 2k11, Frontend: idea-custom

- Backend: 2k11-custom, Frontend: idea
- Backend: 2k11-custom, Frontend: idea-custom

They seem to work.

Currently the display of backend and frontend theme in templates.inc.tpl takes up some larger space. Maybe it could be prettified somehow, maybe put frontend and backend template next to each other, not beneath each other? Maybe @yellowled has some suggestions.

@onli and @ophian - please have a look at this, since you both also worked on the fallback chains. Please tell me if you have issues with this. We can easily revert, if you see this approach as not workable. This is more a "proof of concept" draft.
This commit is contained in:
Garvin Hicking 2014-05-14 12:58:06 +02:00
parent a6b20ad398
commit dd83225447
12 changed files with 143 additions and 27 deletions

View File

@ -4,6 +4,18 @@
Version 2.0-beta2 ()
------------------------------------------------------------------------
* Backend and Frontend themes can now be set independently from
each other. New backend themes now need to set:
Backend: Yes
in their info.txt file. If you adapt a custom admin theme,
ensure that it is compatible to the new "2k11" backend to
ensure proper future usage within Serendipity. The bulletproof
backend will now no longer be recognized as a backend theme
option, but can be selected as a new frontend theme, while
using 2k11 (=default) in the backend.
* Include klogger, call it as $serendipity['logger']->debug/error
* Add HTTP_Request2 and dependencies as bundled libraries and

View File

@ -62,7 +62,7 @@ if ($serendipity['GET']['adminAction'] == 'editConfiguration') {
$data["adminAction"] = "editConfiguration";
}
if ($serendipity['GET']['adminAction'] == 'install' ) {
if ($serendipity['GET']['adminAction'] == 'install' || $serendipity['GET']['adminAction'] == 'install-frontend' || $serendipity['GET']['adminAction'] == 'install-backend') {
serendipity_plugin_api::hook_event('backend_templates_fetchtemplate', $serendipity);
$themeInfo = serendipity_fetchTemplateInfo(htmlspecialchars($serendipity['GET']['theme']));
@ -70,25 +70,32 @@ if ($serendipity['GET']['adminAction'] == 'install' ) {
// A separate hook is used post installation, for plugins to possibly perform some actions
serendipity_plugin_api::hook_event('backend_templates_install', $serendipity['GET']['theme'], $themeInfo);
serendipity_set_config_var('template', htmlspecialchars($serendipity['GET']['theme']));
if ($serendipity['GET']['adminAction'] == 'install' || $serendipity['GET']['adminAction'] == 'install-frontend') {
serendipity_set_config_var('template', htmlspecialchars($serendipity['GET']['theme']));
}
// template_engine was set by default to default, which screws up the fallback chain (to the default-template first)
serendipity_set_config_var('template_engine', null);
if ($themeInfo['engine']) {
serendipity_set_config_var('template_engine', $themeInfo['engine']);
if ($serendipity['GET']['adminAction'] == 'install-backend' && $themeInfo['custom_admin_interface'] == YES) {
serendipity_set_config_var('template_backend', htmlspecialchars($serendipity['GET']['theme']));
} else {
// template_engine was set by default to default, which screws up the fallback chain (to the default-template first)
// The "Engine" now only applies to FRONTEND themes. Backend themes will always fall back to our default backend theme only, to ensure proper backend operation.
serendipity_set_config_var('template_engine', null);
if ($themeInfo['engine']) {
serendipity_set_config_var('template_engine', $themeInfo['engine']);
}
}
serendipity_set_config_var('last_template_change', time());
$data["adminAction"] = "install";
$data["install_template"] = htmlspecialchars($serendipity['GET']['theme']);
}
if ( @file_exists($serendipity['serendipityPath'] . $serendipity['templatePath'] . $serendipity['template'] .'/layout.php') ) {
$data["deprecated"] = true;
}
$data["cur_template"] = $serendipity['template'];
$data["cur_template"] = $serendipity['template'];
$data["cur_template_backend"] = $serendipity['template_backend'];
if (file_exists($serendipity['serendipityPath'] . $serendipity['templatePath'] . $serendipity['template'] . '/config.inc.php')) {
serendipity_smarty_init();
@ -201,4 +208,4 @@ foreach ($stack as $theme => $info) {
echo serendipity_smarty_show('admin/templates.inc.tpl', $data);
/* vim: set sts=4 ts=4 expandtab : */
/* vim: set sts=4 ts=4 expandtab : */

View File

@ -260,7 +260,7 @@ function serendipity_fetchTemplateInfo($theme, $abspath = null) {
if ( $theme != 'default' && $theme != 'default-rtl'
&& @is_dir($serendipity['templatePath'] . $theme . '/admin')
&& @is_readable($serendipity['templatePath'] . $theme . '/admin/style.css') ) {
&& strtolower($data['backend']) == 'yes' ) {
$data['custom_admin_interface'] = YES;
} else {

View File

@ -261,16 +261,26 @@ function serendipity_getTemplateFile($file, $key = 'serendipityHTTPPath') {
$directories = array();
$directories[] = isset($serendipity['template']) ? $serendipity['template'] . '/' : '';
if (isset($serendipity['template_engine']) && $serendipity['template_engine'] != null) {
$p = explode(',', $serendipity['template_engine']);
foreach($p AS $te) {
$directories[] = trim($te) . '/';
if (defined('IN_serendipity_admin')) {
// Backend will always use our default backend (=defaultTemplate) as fallback.
$directories[] = isset($serendipity['template_backend']) ? $serendipity['template_backend'] . '/' : '';
$directories[] = $serendipity['defaultTemplate'] .'/';
$directories[] = 'default/';
} else {
$directories[] = isset($serendipity['template']) ? $serendipity['template'] . '/' : '';
if (isset($serendipity['template_engine']) && $serendipity['template_engine'] != null) {
$p = explode(',', $serendipity['template_engine']);
foreach($p AS $te) {
$directories[] = trim($te) . '/';
}
}
}
$directories[] = $serendipity['defaultTemplate'] .'/';
$directories[] = 'default/';
// Frontend templates currently need to fall back to "default" (see "idea"), so that they get the
// output they desire. If templates are based on 2k11, the need to set "Engine: 2k11" in their info.txt
// file.
$directories[] = 'default/';
$directories[] = $serendipity['defaultTemplate'] .'/';
}
foreach ($directories as $directory) {
$templateFile = $serendipity['templatePath'] . $directory . $file;
@ -279,7 +289,7 @@ function serendipity_getTemplateFile($file, $key = 'serendipityHTTPPath') {
}
if (file_exists($serendipity['serendipityPath'] . $templateFile . ".tpl") && $serendipity['template'] . '/' == $directory && IS_installed) {
# catch .js.tpl files served via the template-plugin-api, but only if that template is active as well, so config.inc.php is laoded
# catch .js.tpl files served via the template-plugin-api, but only if that template is active as well, so config.inc.php is loaded
# this won't work in the installer
return $serendipity['baseURL'] . 'index.php?/plugin/' . $file;
}

View File

@ -864,6 +864,12 @@ function serendipity_smarty_init($vars = array()) {
// Beware: Smarty is used in the Admin backend, despite of this.
include_once $template_dir . '/template.inc.php';
} else {
// Backend template overwritten here (NOT earlier due to frontend specific check
if (defined('IN_serendipity_admin')) {
$template_dir = $serendipity['serendipityPath'] . $serendipity['templatePath'] . $serendipity['template_backend'];
}
// Set a session variable if Smarty fails:
$prev_smarty = $_SESSION['no_smarty'];
$_SESSION['no_smarty'] = true;
@ -1014,6 +1020,7 @@ function serendipity_smarty_init($vars = array()) {
'category' => $category,
'category_info' => $category_info,
'template' => $serendipity['template'],
'template_backend' => $serendipity['template_backend'],
'dateRange' => (!empty($serendipity['range']) ? $serendipity['range'] : array())
)
@ -1025,11 +1032,26 @@ function serendipity_smarty_init($vars = array()) {
// For advanced usage, we allow template authors to create a file 'config.inc.php' where they can
// setup custom smarty variables, modifiers etc. to use in their templates.
// If a template engine is defined we need that config.inc.php file as well. The template's actual file is loaded after that to be able to overwrite config.
if (isset($serendipity['template_engine']) && $serendipity['template_engine'] != null) {
$p = explode(',', $serendipity['template_engine']);
foreach($p AS $te) {
$config = $serendipity['serendipityPath'] . $serendipity['templatePath'] . trim($te) . '/config.inc.php';
if (file_exists($config)) {
include_once $config;
}
}
}
$config = $serendipity['smarty']->getConfigDir(0) . '/config.inc.php';
if (file_exists($config)) {
include_once $config;
}
if (is_array($template_loaded_config)) {
$template_vars =& $template_loaded_config;
$serendipity['smarty']->assignByRef('template_option', $template_vars);

View File

@ -18,9 +18,15 @@ if (!defined('serendipity_LANG_LOADED') || serendipity_LANG_LOADED !== true) {
if (defined('S9Y_DATA_PATH')) {
@include_once (S9Y_DATA_PATH . 'templates/' . $serendipity['template'] . '/' . $charset . 'lang_' . $serendipity['lang'] . '.inc.php');
@include_once (S9Y_DATA_PATH . 'templates/' . $serendipity['template'] . '/lang_en.inc.php');
@include_once (S9Y_DATA_PATH . 'templates/' . $serendipity['template_backend'] . '/' . $charset . 'lang_' . $serendipity['lang'] . '.inc.php');
@include_once (S9Y_DATA_PATH . 'templates/' . $serendipity['template_backend'] . '/lang_en.inc.php');
} else {
@include_once (S9Y_INCLUDE_PATH . 'templates/' . $serendipity['template'] . '/' . $charset . 'lang_' . $serendipity['lang'] . '.inc.php');
@include_once (S9Y_INCLUDE_PATH . 'templates/' . $serendipity['template'] . '/lang_en.inc.php');
@include_once (S9Y_INCLUDE_PATH . 'templates/' . $serendipity['template_backend'] . '/' . $charset . 'lang_' . $serendipity['lang'] . '.inc.php');
@include_once (S9Y_INCLUDE_PATH . 'templates/' . $serendipity['template_backend'] . '/lang_en.inc.php');
}
}

View File

@ -4,6 +4,7 @@
// define secure_dir and trusted_dirs for Serendipity_Smarty_Security_Policy class.
@define('S9Y_TEMPLATE_FALLBACK', $serendipity['serendipityPath'] . $serendipity['templatePath'] . 'default');
@define('S9Y_TEMPLATE_USERDEFAULT', $serendipity['serendipityPath'] . $serendipity['templatePath'] . $serendipity['template']);
@define('S9Y_TEMPLATE_USERDEFAULT_BACKEND', $serendipity['serendipityPath'] . $serendipity['templatePath'] . $serendipity['template_backend']);
@define('S9Y_TEMPLATE_SECUREDIR', $serendipity['serendipityPath'] . $serendipity['templatePath']);
@ -29,7 +30,7 @@ class Serendipity_Smarty_Security_Policy extends Smarty_Security
public $secure_dir = array(S9Y_TEMPLATE_SECUREDIR); // do we need this then?
// actually no need, as template dirs are explicit defined as trusted_dirs. (unproofed)
public $trusted_dir = array(S9Y_TEMPLATE_USERDEFAULT, S9Y_TEMPLATE_FALLBACK); // do we need this then?
public $trusted_dir = array(S9Y_TEMPLATE_USERDEFAULT, S9Y_TEMPLATE_USERDEFAULT_BACKEND, S9Y_TEMPLATE_FALLBACK); // do we need this then?
#public $modifiers = array(); // can be omitted, when all allowed
@ -121,9 +122,15 @@ class Serendipity_Smarty extends Smarty
$template_engine = serendipity_get_config_var('template_engine');
$template_dirs = array();
if ($template_engine) {
$template_dirs[] = $serendipity['serendipityPath'] . $serendipity['templatePath'] . $template_engine;
}
$p = explode(',', $template_engine);
foreach($p AS $te) {
$template_dirs[] = $serendipity['serendipityPath'] . $serendipity['templatePath'] . trim($te) . '/';
}
}
$template_dirs[] = $serendipity['serendipityPath'] . $serendipity['templatePath'] . $serendipity['defaultTemplate'];
$template_dirs[] = $serendipity['serendipityPath'] . $serendipity['templatePath'] . $serendipity['template_backend'];
// add secure dir to template path, in case engine did have entries
if (S9Y_TEMPLATE_SECUREDIR != $serendipity['serendipityPath'] . $serendipity['templatePath']) {
$template_dirs[] = S9Y_TEMPLATE_SECUREDIR;

View File

@ -28,6 +28,8 @@ switch($css_mode) {
break;
case 'serendipity_admin.css':
// This constant is needed to properly set the template context for the backend.
@define('IN_serendipity_admin', true);
$css_hook = 'css_backend';
$css_file = 'admin/style.css';
break;

View File

@ -123,6 +123,11 @@ $serendipity['autolang'] = 'en';
/* Name of folder for the default theme */
$serendipity['defaultTemplate'] = '2k11';
/* Default backend theme */
if (!isset($serendipity['template_backend'])) {
$serendipity['template_backend'] = '2k11';
}
/* Availiable languages */
if (!isset($serendipity['languages'])) {
$serendipity['languages'] = array('en' => 'English',

View File

@ -60,12 +60,46 @@
<a class="button_link" href="?serendipity[adminModule]=templates&amp;serendipity[adminAction]=editConfiguration" title="{$CONST.CONFIGURATION}">{$CONST.CONFIGURATION}</a>
</article>
{if $cur_template_backend}
{assign var="cur_tpl_backend" value=$templates[$cur_template_backend]}
<h2>{$CONST.CURRENT_TEMPLATE} - {$CONST.BACKEND}</h2>
<article class="clearfix current_template">
<h3>{$cur_tpl_backend.info.name}</h3>
<div class="clearfix equal_heights template_wrap">
<div class="template_preview">
{if $cur_tpl_backend.fullsize_preview || $cur_tpl_backend.preview}
{if $cur_tpl_backend.fullsize_preview}
<a class="media_fullsize" href="{$cur_tpl_backend.fullsize_preview}" title="{$CONST.MEDIA_FULLSIZE}: {$cur_tpl_backend.info.name}">
<img src="{$cur_tpl_backend.fullsize_preview}" class="template_preview_img" alt="{$CONST.PREVIEW}" >
</a>
{else}
<img src="{$cur_tpl_backend.preview}" alt="{$CONST.PREVIEW}" >
{/if}
{/if}
<footer id="template_info_cur_backend" class="template_info additional_info">
<dl class="clearfix">
<dt class="template_author">{$CONST.AUTHOR}:</dt>
<dd>{$cur_tpl_backend.info.author}</dd>
<dt class="template_date">{$CONST.LAST_UPDATED}:</dt>
<dd>{$cur_tpl_backend.info.date}</dd>
<dt class="template_admin">{$CONST.CUSTOM_ADMIN_INTERFACE}:</dt>
<dd>{$cur_tpl_backend.info.custom_admin_interface}</dd>
</dl>
</footer>
</div>
</div>
<button class="template_show_info button_link" type="button" data-href="#template_info_cur_backend" title="{$CONST.TEMPLATE_INFO}"><span class="icon-info-circled"></span><span class="visuallyhidden"> {$CONST.TEMPLATE_INFO}</span></button>
</article>
{/if}
<h2>{$CONST.AVAILABLE_TEMPLATES}</h2>
<ul class="plainList clearfix">
{foreach $templates as $template=>$info}
{if $info.info.engine == 'yes' || $template == $cur_template}{continue}{/if}
{if !empty($template)}
{if !empty($template) && $info.info.engine != 'yes'}
<li><article class="clearfix {cycle values="odd,even"}">
<h3>{$info.info.name}</h3>
<div class="clearfix equal_heights template_wrap">
@ -85,7 +119,7 @@
<dd>{$info.info.author}</dd>
<dt class="template_date">{$CONST.LAST_UPDATED}:</dt>
<dd>{$info.info.date}</dd>
<dt class="template_admin">{$CONST.CUSTOM_ADMIN_INTERFACE}</dt>
<dt class="template_admin">{$CONST.CUSTOM_ADMIN_INTERFACE}:</dt>
<dd>{if $info.info.custom_admin_interface} {$info.info.custom_admin_interface} {else} {$CONST.NO} {/if}</dd>
</dl>
</footer>
@ -95,7 +129,12 @@
<button class="template_show_info button_link" type="button" data-href="#template_info_{$info@key}" title="{$CONST.TEMPLATE_INFO}"><span class="icon-info-circled"></span><span class="visuallyhidden"> {$CONST.TEMPLATE_INFO}</span></button>
{if !$info.unmetRequirements}
{if $info.info.custom_admin_interface == $CONST.YES}
<a class="button_link" href="?serendipity[adminModule]=templates&amp;serendipity[adminAction]=install-frontend&amp;serendipity[theme]={$template}{$info.info.customURI}" title="{$CONST.SET_AS_TEMPLATE}">{$CONST.INSTALL}: {$CONST.FRONTEND}</a>
<a class="button_link" href="?serendipity[adminModule]=templates&amp;serendipity[adminAction]=install-backend&amp;serendipity[theme]={$template}{$info.info.customURI}" title="{$CONST.SET_AS_TEMPLATE}">{$CONST.INSTALL}: {$CONST.BACKEND}</a>
{else}
<a class="button_link" href="?serendipity[adminModule]=templates&amp;serendipity[adminAction]=install&amp;serendipity[theme]={$template}{$info.info.customURI}" title="{$CONST.SET_AS_TEMPLATE}">{$CONST.INSTALL}</a>
{/if}
{else}
<span class="unmet_requirements msg_error"><span class="icon-attention-circled"></span> {$info.unmetRequirements}></span>
{/if}

View File

@ -1,4 +1,5 @@
Name: 2k11
Author: Matthias Mees, Veit Lehmann
Date: 2014-01-08
Require Serendipity: 1.6
Require Serendipity: 2.0
Backend: Yes

View File

@ -0,0 +1,5 @@
This directory contains the pre Serendipity 2.0 admin tepmlates.
Since Serendipity 2.0, the "2k11" is the default backend template and holds the current admin template.
The files here are deprecated and will be removed in future versions.