[TOC]
# 模板制作快速入门
模板的制作并非难事,只要你写好了HTML和CSS,嵌套模板就非常简单了,你无需了解标签的内部结构,你只要会使用,模板就能迅速完成。这篇文章只简单的介绍了常用标签的使用方法,希望能带你进入模板的世界。^_^
本篇文章以Emlog的默认模板为例,您可以打开默认模板default边看边学习。该模板所在的路径为 /content/templates/default,每个模板都是一个单独的文件夹,文件夹以模板名字命名。通过后台上传安装的模板都保存在这个目录下。
进入该目录后,我们可以看到有许多文件,别犯愁,我们将在下文一一介绍。
## 模板文件结构说明
| 文件名 | 作用 | 必须 |
| --- | --- | --- |
| images文件夹 | 存放模板所需图片 | 否 |
| preview.jpg | 在后台模板选择界面显示的模板预览图,300×225 jpg格式。 | 否 |
| 404.php | 自定义404页面未找到时的报错页面 | 否 |
| header.php | 头部页面文件 | 是 |
| footer.php | 底部页面文件 | 否 |
| log_list.php | 显示日志列表内容 | 否 |
| echo_log.php | 显示日志内容 | 否 |
| module.php | 模板公共代码,包含侧边widgets、评论、引用、编辑等,该文件是模板最核心的模块。 | 否 |
| page.php | 自定义的页面内容的模板。 | 否 |
| side.php | 模板侧边栏文件,如制作单栏模板则该文件不是必须的。 | 否 |
| t.php | 显示emlog系统自带的微博(碎语)内容。 | 否 |
## 公共代码分析
> 通过预览整个模板中的各个文件,你会发现以下代码同时存在于多个文件中,这些代码分别有以下用途: if(!defined('EMLOG_ROOT')) {exit('error!');} 此行代码存在于模板目录下的每个php文件起始部分(事实上为了安全起见,该行代码也在admin目录下的几乎所有php文件起始部分存在),其作用是防止代码所在的php脚本被直接访问执行。 require_once View::getView('side'); require_once View::getView('footer'); 这两行代码存在于log_list.php、echo_log.php、page.php、t.php里面,其作用是调用模板文件夹下的side.php和footer.php的代码到当前文件的当前位置。View是emlog的模板视图控制器,View::getView('文件名','文件后缀')将返回当前模板安装路径下对应的文件。getView函数的第二个参数为缺省参数,在不传入值的情况下,将默认作为.php文件后缀返回文件路径。
## header.php
### 开头注释内容是模板信息,该信息显示在模板选择界面
```
/*
Template Name:模板名称
Description:模板介绍描述
Version:模板版本
ForEmlog:适用版本
Author:模板作者
Author Url:作者或模板发布的URL
Sidebar Amount:标记该模板有几个侧边栏,一般为1,有些模板有两个侧边栏则标记2。这样可以在后台widgets里识别管理
*/
```
### 编码
打开这个文件,见到的第一个php代码就是:
~~~
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
~~~
调用默认的编码,现在最经常用的大都是utf-8吧。所以我通常是直接写成utf-8,省去php处理时间。
### 页面标题
~~~
<title><?php echo $site_title; ?></title>
~~~
通常情况下直接复制使用,如果你没有时间的话。
### 导入样式
~~~
<link href="<?php echo TEMPLATE_URL; ?>style.css" rel="stylesheet" type="text/css" />
~~~
其中style.css是样式文件相对模板目录的路径和文件名。
### 其它HTML头部信息
~~~
<?php doAction('index_head'); ?>
~~~
别忘了这句,前台头部扩展,它关系到增加前台css样式、加载js以及插件的正常使用。
### 页面导航
~~~
<?php blog_navi();?>
~~~
它定义在了module.php中,使用缓存循环输出导航数据。
```
global $CACHE;
$navi_cache = $CACHE->readCache('navi');
```
### 网站名称
~~~
<?php echo BLOG_URL; ?>//网站的首页地址
<?php echo $blogname; ?>//网站名称
<?php echo $bloginfo; ?>//网站的一些简短描述、介绍
~~~
### 站内搜索
~~~
<form name="keyform" method="get" action="<?php echo BLOG_URL; ?>index.php">
<input name="keyword" type="text" />
</form>
~~~
当你的文章很多很多,这个搜索就必不可少。
### 一些模板公共代码
```
if(!defined('EMLOG_ROOT')) {exit('error!');}//该行代码同样存在于其它模板文件中,为防止该文件被直接执行。
require_once View::getView('module');
$site_title//站点标题
$site_key//关键字
$site_description//输出博客设置的摘要
BLOG_URL//博客首页的URL
TEMPLATE_URL//模板文件夹的URL,用于加载模板内的css、js及其他内容
Option::get('blogname')//使用Option配置类获取数据表options中的配置,此处获取的是博客名
<?php echo $curpage == CURPAGE_HOME ? 'current' : 'common';?> //判断当前是否首页,是则给导航加current类,用于表现当前位置。
<?php if($istwitter == 'y'):?><?php endif;?>//如后台设置在前台显示碎语,则输出…….中的内容。
<?php echo $curpage == CURPAGE_TW ? 'current' : 'common';?>
//判断当前URL是否为微语并选择加类名。
<?php foreach ($navibar as $key ⇒ $val):?><?php endforeach;?
>//输出自定义页面的链接
```
## index.php
### 显示文章
~~~
<?php
if (!empty($logs)){
foreach($logs as $value){
?>
<div>$value['logid']</div>
<?php
}
}
?>
~~~
进入文章循环,输出文章,剥开html代码,一句一句介绍
| 类型 | 代码 |
| --- | --- |
| 文章所在的连接 | Url::log($value['logid']) |
|文章标题|$value['log_title']|
|文章作者ID|$value['author']|
|文章作者地址|Url::author($value['author'])|
|文章的发布日期,格式可参考[PHP日期格式](http://cn.php.net/manual/zh/function.date.php "http://cn.php.net/manual/zh/function.date.php")|date('Y-n-j', $value['date'])|
|文章所在分类|blog_sort($value['logid'])//blog_sort在model.php中自己定义|
|文章评论数|$value['comnum']|
|文章内容|$value['log_description']|
好了,文章显示结束,别忘了结束循环。
### 文章分页
~~~
<?php echo $page_url;?>
~~~
文章输出结束后别忘了增加分页,至此,index.php的常见内容结束,应该不糊涂吧。
### 一些模板公共代码
~~~
<?php doAction('index_loglist_top');?>//文章列表顶部挂载点加入。
$value['logid']//该变量为当前日志的id
<?php topflg($value['top']); ?>//显示置顶标记,该函数位于模板module.php内。
<?php echo $value['log_url']; ?>//输出日志URL
<?php blog_author($value['author']);?>//输出日志的作者,该函数位于模板module.php内。
<?php editflg($value['logid'],$value['author']); ?>//当管理员或作者登陆时显示“编辑”链接,该函数位于模板module.php内。
<?php blog_att($value['logid']); ?>//如日志有附件则输出附件,该函数位于模板module.php内。
<?php blog_tag($value['logid']); ?>//输出日志的标签,该函数位于模板module.php内。
<?php echo $value['tbcount'];?>//输出当前日志的引用量
<?php echo $value['views']; ?>//输出当前日志的浏览量
<?php echo $page_url;?>//显示当前列表页的翻页功能。
<?php include View::getView('side'); include View::getView('footer');?>//加入侧边栏及加入页脚。
~~~
## footer.php
```
<a href="https://www.tongleer.com">同乐儿</a>//以示对同乐儿的支持
<?php echo BLOG_URL; ?>rss.php//RSS地址
Option::EMLOG_VERSION//获得版本号。
$icp//获得后台设置的ICP备案号。
<?php doAction('index_footer'); ?>//页脚底部挂载点加入。
```
## echo_log.php
该文件功能函数与列表页一致,但参数有区别,注意区分。 $logid 该变量为当前日志的id
~~~
<?php topflg($top); ?>//显示置顶标记,该函数位于模板module.php内。
<?php echo $log_title; ?>//输出日志标题。
<?php blog_author($author); ?>//输出日志的作者,该函数位于模板module.php内。
<?php echo date('Y-n-j G:i l', $date); ?>//输出日志发布时间,参数'Y-n-j G:i l'用于定义日期格式。
<?php blog_sort($logid); ?>//输出日志所属的分类,该函数位于模板module.php内。
<?php editflg($logid,$author); ?>//当管理员或作者登陆时显示“编辑”链接,该函数位于模板module.php内。
<?php echo $log_content; ?>//输出日志全文内容。
<?php blog_att($logid); ?>//如日志有附件则输出附件,该函数位于模板module.php内。
<?php blog_tag($logid); ?>//输出日志的标签,该函数位于模板module.php内。
<?php echo $comnum;?>//日志页显示评论数
<?php echo $tbcount; ?>//日志页显示引用数
<?php echo $views; ?>//日志页显示浏览量
<?php doAction('log_related', $logData); ?>//相关日志的挂载点,与3.x版本不同,4.0带第二参数。
<?php neighbor_log($neighborLog);?>//输出邻近,就是上一篇及下一篇,该函数位于模板module.php内。
<?php blog_trackback($tb, $tb_url, $allow_tb); ?>//输出该日志被引用的信息列表,与3.x不同注意区分。
<?php blog_comments($comments); ?>//输出该日志评论列表,与3.x不同注意区分。
<?php blog_comments_post($logid,$ckname,$ckmail,$ckurl,$verifyCode,$allow_remark); ?>//输出发表评论框,与3.x不同注意区分。
~~~
## page.php
> 该文件写法与echo_log.php类似,不再重复。
## t.php
> 与之前相同的内容不再重复。
~~~
<?php echo $avatar;?>//输出头像。
<?php echo $author; ?>// 输出作者名。
<?php echo $val['t'];?>//输出位微语内容。
<?php echo DYNAMIC_BLOGURL; ?>//根据当前url输出博客地址,主要用于js,解决跨域问题。
<?php echo $tid;?>//输出微语所在数据库中的id号。
<?php echo $val['date'];?>//发布微语的时间。
$reply_code//其值为‘n’或‘y’,后台设置是否启用碎语回复验证码。
<?php echo $rcode;?>//输出验证码。
~~~
## 404.php
> 用于自定义404页面的模板。
## side.php
> 侧边栏,主要负责根据后台widgets设置信息输出侧边栏内容。建议该文件内代码保持不变,主要代码如下:
```
<?php
$widgets = !empty($options_cache['widgets1']) ? unserialize($options_cache['widgets1']) : array();
doAction('diff_side');
foreach ($widgets as $val)
{
$widget_title = @unserialize($options_cache['widget_title']);
$custom_widget = @unserialize($options_cache['custom_widget']);
if(strpos($val, 'custom_wg_') === 0)
{
$callback = 'widget_custom_text';
if(function_exists($callback))
{
call_user_func($callback, htmlspecialchars($custom_widget[$val]['title']), $custom_widget[$val]['content']);
}
}else{
$callback = 'widget_'.$val;
if(function_exists($callback))
{
preg_match("/^.*\s\((.*)\)/", $widget_title[$val], $matchs);
$wgTitle = isset($matchs[1]) ? $matchs[1] : $widget_title[$val];
call_user_func($callback, htmlspecialchars($wgTitle));
}
}
}
?>
```
## module.php
> 模板公共代码,包含侧边widgets、评论、引用、编辑等。 该文件由若干函数组成,被博客前台文件调用,可在内自定义函数实现更多功能。 如在自定义函数内调用emlog缓存时,假设读取user缓存信息,则形如: global $CACHE; $user_cache = $CACHE->readCache('user'); 如需要操作数据库,则形如: $DB = Database::getInstance(); $res = $DB->query($sql);。
### 个人资料模块
```
function widget_blogger($title){
global $CACHE;
$user_cache = $CACHE->readCache('user');
……
}
```
### 日历模块
```
<?php function widget_calendar($title){?>
<div class="layui-row layui-col-space15" id="calendar"></div>
<script>sendinfo('<?php echo Calendar::url(); ?>','calendar');</script>
<?php }?>
```
### 标签模块
```
function widget_tag($title){
global $CACHE;
$tag_cache = $CACHE->readCache('tags');
……
}
```
### 分类模块
```
function widget_sort($title){
global $CACHE;
$sort_cache = $CACHE->readCache('sort');
……
}
```
### 最新微语模块
```
function widget_twitter($title){
global $CACHE;
$newtw_cache = $CACHE->readCache('newtw');
$istwitter = Option::get('istwitter');
……
}
```
### 最新评论模块
```
function widget_newcomm($title){
global $CACHE;
$comment_cache = $CACHE->readCache('comment');
……
}
```
### 最新文章模块
```
function widget_newlog($title){
global $CACHE;
$newlog_cache = $CACHE->readCache('newlog');
……
}
```
### 热门文章模块
```
function widget_hotlog($title){
$DB = Database::getInstance();
$index_hotlognum = Option::get('index_hotlognum');
$Log_Model = new Log_Model();
$randLogs = $Log_Model->getHotLog($index_hotlognum);
……
}
```
### 随机文章模块
```
function widget_random_log($title){
$DB = Database::getInstance();
$index_randlognum = Option::get('index_randlognum');
$Log_Model = new Log_Model();
$randLogs = $Log_Model->getRandLog($index_randlognum);
……
}
```
### 搜索模块
```
<?php function widget_search($title){ ?>
<form name="keyform" method="get" action="<?php echo BLOG_URL; ?>index.php">
<input name="keyword" type="text" />
</form>
<?php }?>
```
### 归档模块
```
function widget_archive($title){
global $CACHE;
$record_cache = $CACHE->readCache('record');
……
}
```
### 自定义组件模块
```
function widget_custom_text($title, $content){
……
}
```
### 链接模块
```
function widget_link($title){
global $CACHE;
$link_cache = $CACHE->readCache('link');
……
}
```
### 评论列表示例
~~~
<?php
function blog_comments($comments){
extract($comments);
if($commentStacks): ?>
<a name="comments"></a>
<p class="comment-header"><b></b></p>
<?php endif; ?>
<?php
$isGravatar = Option::get('isgravatar');
foreach($commentStacks as $cid):
$comment = $comments[$cid];
$comment['poster'] = $comment['url'] ? '<a href="'.$comment['url'].'" target="_blank">'.$comment['poster'].'</a>' : $comment['poster'];
?>
<div class="media-item comment" id="comment-<?php echo $comment['cid']; ?>">
<a name="<?php echo $comment['cid']; ?>"></a>
<?php if($isGravatar == 'y'): ?><div class="avatar media-item-left"><img class="img-xs" src="<?php echo getGravatar($comment['mail']); ?>" /></div><?php endif; ?>
<div class="media-text comment-info">
<a href="javascript:;"><?php echo $comment['poster']; ?></a>
<mdall class="comment-time"><?php echo $comment['date']; ?></mdall>
<a class="comment-reply" href="#comment-<?php echo $comment['cid']; ?>" onclick="commentReply(<?php echo $comment['cid']; ?>,this)">回复</a>
<div class="comment-content"><?php echo $comment['content']; ?></div>
</div>
</div>
<?php blog_comments_children($comments, $comment['children']); ?>
<?php endforeach; ?>
<div id="pagenavi">
<?php echo $commentPageUrl;?>
</div>
<?php }?>
~~~
### 子评论列表示例
```
<?php
function blog_comments_children($comments, $children){
$isGravatar = Option::get('isgravatar');
foreach($children as $child):
$comment = $comments[$child];
$comment['poster'] = $comment['url'] ? '<a href="'.$comment['url'].'" target="_blank">'.$comment['poster'].'</a>' : $comment['poster'];
?>
<div class="media-item comment comment-children" id="comment-<?php echo $comment['cid']; ?>">
<a name="<?php echo $comment['cid']; ?>"></a>
<?php if($isGravatar == 'y'): ?><div class="avatar media-item-left"><img class="img-xs" src="<?php echo getGravatar($comment['mail']); ?>" /></div><?php endif; ?>
<div class="media-text comment-info">
<a href="javascript:;"><?php echo $comment['poster']; ?></a>
<mdall class="comment-time"><?php echo $comment['date']; ?></mdall>
<?php if($comment['level'] < 4): ?><a class="comment-reply" href="#comment-<?php echo $comment['cid']; ?>" onclick="commentReply(<?php echo $comment['cid']; ?>,this)">回复</a><?php endif; ?>
<div class="comment-content"><?php echo $comment['content']; ?></div>
</div>
</div>
<?php blog_comments_children($comments, $comment['children']);?>
<?php endforeach; ?>
<?php }?>
```
### 评论输入表单示例
~~~
<?php
function blog_comments_post($logid,$ckname,$ckmail,$ckurl,$verifyCode,$allow_remark){
if($allow_remark == 'y'): ?>
<div id="comment-place">
<div class="comment-post" id="comment-post">
<div class="cancel-reply" id="cancel-reply" style="display:none"><a href="javascript:void(0);" onclick="cancelReply()" class="layui-btn layui-btn-primary">取消回复</a></div>
<p class="comment-header"><b></b><a name="respond"></a></p>
<form class="layui-form" method="post" name="commentform" action="<?php echo BLOG_URL; ?>index.php?action=addcom" id="commentform">
<input type="hidden" name="gid" value="<?php echo $logid; ?>" />
<?php if(ROLE == ROLE_VISITOR): ?>
<p>
<input class="layui-input" type="text" name="comname" maxlength="49" value="<?php echo $ckname; ?>" size="22" tabindex="1" placeholder="昵称">
</p>
<p>
<input class="layui-input" type="text" name="commail" maxlength="128" value="<?php echo $ckmail; ?>" size="22" tabindex="2" placeholder="邮件地址 (选填)">
</p>
<p>
<input class="layui-input" type="text" name="comurl" maxlength="128" value="<?php echo $ckurl; ?>" size="22" tabindex="3" placeholder="个人主页 (选填)">
</p>
<?php endif; ?>
<p><textarea class="layui-textarea" name="comment" id="comment" rows="10" tabindex="4" required="required" placeholder="评论内容"></textarea></p>
<p><?php echo $verifyCode; ?> <input class="layui-btn layui-btn-primary" type="submit" id="comment_submit" value="发表评论" tabindex="6" /></p>
<input type="hidden" name="pid" id="comment-pid" value="0" size="22" tabindex="1"/>
</form>
</div>
</div>
<?php endif; ?>
<?php }?>
~~~
## 前台模板部分挂载点一览
> doAction('index_footer'); 页脚底部挂载点
> doAction('index_loglist_top'); 首页日志列表顶部挂载点
> doAction('log_related', $logData); 相关日志挂载点
> doAction('diff_side'); 侧边栏挂载点
## 结束语
OK,这篇简短的入门讲解结束了,希望你看着不累,同时能对Emlog的模板系统了解一二,这样文章的目的也就达到了,针对当前文章的不明白的地方,欢迎到论坛提出问题。谢谢。