立即注册 登录
彼岸网 返回首页

天香公主的个人空间 http://www.bian-wang.com/discuz/?10005 [收藏] [复制] [分享] [RSS] https://github.com/txgz999/discuz/wiki

日志

Discuz插件开发:上下篇日志链接

热度 2已有 3876 次阅读2014-11-13 12:59 AM |个人分类:Discuz

如何开发Discuz插件(三):上下篇日志链接

美中网的博客有个很好的功能:在每篇博文内容的后面有该博主前一篇博文和后一篇博文的链接,方便读者在读完该篇后继续阅读该博主的其它博文。这里我们来考虑下如何用插件来实现这个功能。

在前文中我们介绍了开发和设置插件的基本步骤和规范(链接),更完整和权威的介绍见Discuz!插件开发手册。 我们这里要做的是一个包含页面嵌入模块的插件。首先我们看一下日志页上Discuz提供的嵌入点(又名钩子)。

一个适合安放上下篇链接的地方是嵌入点space_blog_title。我们要按前文所述的步骤在管理中心设置和启用新插件,这里不再赘述。假定在那里我们指定新插件的唯一标识符叫imyoona_pre_next而且它包括了一个名叫pre_next的页面嵌入模块,则我们需要建立一个新的文件夹source/plugin/imyoona_pre_next,其中加一个页面嵌入模块文件pre_next.class.php:

<?php if(!defined('IN_DISCUZ')) { exit('Access Denied'); } class plugin_imyoona_pre_next { } class plugin_imyoona_pre_next_home extends plugin_imyoona_pre_next { function space_blog_title() { $id = intval($_GET['id']); $uid = intval($_GET['uid']); if($id && $uid){ $blog = C::t('home_blog')->fetch($id); if ($blog && $blog['uid']==$uid) { $pre = DB::fetch_first("SELECT b.* FROM %t b WHERE b.uid=%d AND b.friend=0 AND b.status=0 AND b.dateline&gt;%d ORDER BY b.dateline", array(DB::table('home_blog'), $blog['uid'], $blog['dateline'])); if(!empty($pre)) { $spre = lang('plugin/imyoona_pre_next', 'pre').': < a href="home.php?mod=space&uid=$uid&do=blog&id='.$pre['blogid'].'" >'.$pre['subject'].'</a>'; } $next = DB::fetch_first("SELECT b.* FROM %t b WHERE b.uid=%d AND b.friend=0 AND b.status=0 AND b.dateline&lt;%d ORDER BY b.dateline DESC", array(DB::table('home_blog'), $blog['uid'], $blog['dateline'])); if(!empty($next)) { $snext = lang('plugin/imyoona_pre_next', 'next').': < a href="home.php?mod=space&uid=$uid&do=blog&id='.$next['blogid'].'" >'.$next['subject'].'</a>'; } } } return $spre."<br/>".$snext; } } ?> 注意在上面的SQL语句中,friend=0表示这个日志是全站用户可见,而status=0表示这个日志不在审核之中。还有我们要检查$blog是否为空,只有当它非空时才执行后面的语句。我们需要这个条件是因为当日志被删除可能还能在界面上看到,点击它就会执行$blog = C::t('home_blog')->fetch($id); 并返回空值,再执行后面的语句就出错了。

注意上面的SQL语句带有形式参数的格式化处理,它的安全性比下面旧式的SQL语句强,是Discuz官方推荐的办法,见Discuz技术文库里的介绍(链接$pre = DB::fetch_first("SELECT b.* FROM ".DB::table('home_blog')." b WHERE b.uid=".$blog['uid']." AND b.friend=0 AND b.status=0 AND b.dateline>".$blog['dateline']." ORDER BY b.dateline");
我们还需要一个语言包文件 data/plugindata/imyoona_pre_next.lang.php (此文件仅供插件设计者模式时使用)<?php $scriptlang['imyoona_pre_next'] = array( 'pre' => '上一篇', 'next' => '下一篇', ); ?> 这样我们就完成了上一篇下一篇链接这个功能。下面是效果图:


下面我们讨论三点改进,一是模板,二是数据层,三是自定义嵌入点。

象pre_next.class.php那样通过PHP代码来输出HTML代码并不是个好的做法,当输出的HTML更复杂时这种PHP代码里混杂HTML代码的做法会使得PHP代码很凌乱。有趣的是Discuz官方给出的插件开发实例:马甲插件 http://faq.comsenz.com/library/plug/plugin/plugin_example.htm 在这方面是个坏的榜样。更好的办法是将HTML代码写在一个单独的模板文件里。添加模板文件source/plugin/imyoona_pre_next/template/pn.htm: <!--{block spn}--> <!--{if !empty($pre) }--> {lang imyoona_pre_next:pre}: < a href="home.php?mod=space&uid=$uid&do=blog&id=$pre['blogid']"> {$pre['subject']} </a> <br/> <!--{/if}--> <!--{if !empty($next) }--> {lang imyoona_pre_next:next}: < a href="home.php?mod=space&uid=$uid&do=blog&id=$next['blogid']"> {$next['subject']} </a> <!--{/if}--> <!--{/block}--> 这样我们的页面嵌入模块文件里的嵌入点函数就可以简化成: function space_blog_title() { $id = intval($_GET['id']); $uid = intval($_GET['uid']); if($id && $uid){ $blog = C::t('home_blog')->fetch($id); if ($blog && $blog['uid']==$uid) { $pre = DB::fetch_first("SELECT b.* FROM %t b WHERE b.uid=%d AND b.friend=0 AND b.status=0 AND b.dateline&gt;%d ORDER BY b.dateline", array(DB::table('home_blog'), $blog['uid'], $blog['dateline'])); $next = DB::fetch_first("SELECT b.* FROM %t b WHERE b.uid=%d AND b.friend=0 AND b.status=0 AND b.dateline&lt;%d ORDER BY b.dateline DESC", array(DB::table('home_blog'), $blog['uid'], $blog['dateline'])); } } include template('imyoona_pre_next:pn'); return $spn; } 同时我们还要修改语言包文件如下: <?php $templatelang['imyoona_pre_next'] = array( 'pre' => '上一篇', 'next' => '下一篇', ); ?>
我们的应用层模块里含有SQL语句,这不是个好的做法。应该将它们放入数据层。 添加数据表文件source/plugin/imyoona_pre_next/table/table_home_blog_pn.php: <?php if(!defined('IN_DISCUZ')) { exit('Access Denied'); } class table_home_blog_pn extends table_home_blog { public function fetch_pre($blogid) { if (!$blogid) return null; $blog = $this->fetch($blogid); if (!$blog) return null; return DB::fetch_first("SELECT b.* FROM %t b WHERE b.uid=%d AND b.friend=0 AND b.status=0 AND b.dateline>%d ORDER BY b.dateline", array($this->_table, $blog['uid'], $blog['dateline'])); } public function fetch_next($blogid) { if (!$blogid) return null; $blog = $this->fetch($blogid); if (!$blog) return null; return DB::fetch_first("SELECT b.* FROM %t b WHERE b.uid=%d AND b.friend=0 AND b.status=0 AND b.dateline<%d ORDER BY b.dateline DESC", array($this->_table, $blog['uid'], $blog['dateline'])); } } ?> 这样我们的嵌入点函数就能进一步简化成: function space_blog_title() { $id = intval($_GET['id']); $uid = intval($_GET['uid']); if($id && $uid){ $blog = C::t('home_blog')->fetch($id); if ($blog && $blog['uid']==$uid) { $pre = C::t('#imyoona_pre_next#home_blog_pn')->fetch_pre($id); $next = C::t('#imyoona_pre_next#home_blog_pn')->fetch_next($id); } } include template('imyoona_pre_next:pn'); return $ss; }
如果我们要象美中网那样将这个上下篇链接加在博文内容的结尾处,我们需要在那里添加一个自定义嵌入点,因为Discuz在那个位置没有提供嵌入点。 通过页面分析不难看出我们要添加的嵌入点的位置是标识符为blog_article的div的后面,我们在日志页模板文件template/default/home/space_blog_view.htm里加入了一个名叫space_blog_pn的嵌入点: <div id="blog_article" class="d cl"> <!--{ad/blog/a_b}--> $blog[message] </div> <!--{hook/space_blog_pn}--> 然后把前面我们定义的嵌入点函数space_blog_title改名为space_blog_pn就可以了。

注意这里为简单起见我们只给出全站用户可见的博文链接,美中网的功能更细致一点,同一篇博文的上下篇链接会因当前用户的不同而改变。对上面的代码略做修改后这不难实现。

最后谈一下如何将插件供他人用。在管理中心的插件设计页里有个导出的按钮,可用来产生一个描述插件的XML文件:discuz_plugin_imyoona_pre_next.xml。注意这个文件里已经包括了语言包文件imyoona_pre_next.lang.php的内容,这也是我们不同将这个文件交给用户的原因。将这个XML文件放入文件夹source/plugin/imyoona_pre_next。然后将整个文件夹交给用户,让用户放在他的网站的同样位置。然后他就能在网站的管理中心的插件页看到这个新插件,先安装:

然后再启用:


注:在本文中的代码中,在<符号和a字符相连的地方在两者之间加了一个不应该有的空格,以避免Discuz在保存日志时自动改变日志内容。


插件下载: http://www.bian-wang.com/discuz/data/userupload/10005/txgz_pre_next.zip

发表评论 评论 (16 个评论)

回复 艾芯 2017-12-10 09:05 AM
天香公主:      我把相关文件放在 http://www.bian-wang.com/discuz/data/userupload/10005/txgz_pre_next.zip 了。解压后放在plugin 里,安装启用,然后还要加入嵌入 ...
可以了,谢谢 天香公主
回复 天香公主 2017-12-9 07:26 PM
艾芯: 更新了的,
    我把相关文件放在 http://www.bian-wang.com/discuz/data/userupload/10005/txgz_pre_next.zip 了。解压后放在plugin 里,安装启用,然后还要加入嵌入点,见 note.txt 里的说明。试试看吧?
回复 艾芯 2017-12-4 08:45 AM
天香公主: 哦,还有一个问题,做完那些改动后,去管理中心->工具里更新缓存了吗?
更新了的,
回复 天香公主 2017-12-3 08:10 AM
艾芯: 去掉了的啊!
哦,还有一个问题,做完那些改动后,去管理中心->工具里更新缓存了吗?
回复 艾芯 2017-12-3 04:18 AM
天香公主: 你把文中代码里有的<和a中间的空格去掉了吗?如果不是这问题的话,等过两天我把插件文件上传上来后你再试试 ...
去掉了的啊!
回复 天香公主 2017-12-3 02:06 AM
艾芯: 我一步一步按照做了,插件也启用了,日志模板也添加了嵌入点,可日志下面没有出现  上一篇 下一篇链接呢?
你把文中代码里有的<和a中间的空格去掉了吗?如果不是这问题的话,等过两天我把插件文件上传上来后你再试试
回复 艾芯 2017-12-3 01:55 AM
我一步一步按照做了,插件也启用了,日志模板也添加了嵌入点,可日志下面没有出现  上一篇 下一篇链接呢?
回复 天香公主 2014-11-14 11:03 PM
lawandorder: 这个插件按照我们前些天的讨论你应该是享受版权保护的,但你显然是放弃这个权利,并公开授权大众使用。
哈,我也就是在熟悉这个软件的过程中练练手而已。关于你上次问我的那个记录回复层次的修改能否写成插件的形式,我想了想感觉不行。
回复 天香公主 2014-11-14 11:00 PM
lawandorder: 我认为就是“最新评论文章”栏比较简单,另外我们首页已经有了最热文章栏,不是吗?
好,我们可以将博文按它们的最新评论时间来排序列出前N篇来。
回复 lawandorder 2014-11-14 10:57 PM
天香公主: 好主意。可以加个当前热点日志栏,列出在最近一段时间(如一天或几个小时)内新加评论最多的日志。我去试试。 ...
我认为就是“最新评论文章”栏比较简单,另外我们首页已经有了最热文章栏,不是吗?
回复 lawandorder 2014-11-14 10:55 PM
天香公主: 谢谢    
这两个功能各有用途。不管你当前看的日志多旧,其它最新日志栏总是显示最新的几篇日志,没法看到当前看的日志的前一篇和后一篇。 ...
这个插件按照我们前些天的讨论你应该是享受版权保护的,但你显然是放弃这个权利,并公开授权大众使用。
回复 天香公主 2014-11-14 10:39 PM
lawandorder: 如果把我们首页中的“最新评论”栏目中的评论,改为“最新评论文章” (即, 列出的不是“最新评论”而是被最新评论的文章), 这样的插件很复杂吗?我认为这样 ...
好主意。可以加个当前热点日志栏,列出在最近一段时间(如一天或几个小时)内新加评论最多的日志。我去试试。
回复 天香公主 2014-11-14 10:35 PM
lawandorder: 向博主无私奉献知识产权表示敬意。

但是这个功能在文章下面体现上一篇和下一篇,我认为和右下角 “作者的其他最新日志” 的功能有重叠之处。 看不出有什么不同 ...
谢谢    
这两个功能各有用途。不管你当前看的日志多旧,其它最新日志栏总是显示最新的几篇日志,没法看到当前看的日志的前一篇和后一篇。
回复 lawandorder 2014-11-14 10:34 PM
如果把我们首页中的“最新评论”栏目中的评论,改为“最新评论文章” (即, 列出的不是“最新评论”而是被最新评论的文章), 这样的插件很复杂吗?我认为这样改动有很多好处,其中一个是无论多少新的评论,将占用一个位置。你认为如何?
回复 lawandorder 2014-11-14 10:29 PM
天香公主: 看到检测说在夜夜城里添加了这个功能,谢谢欣赏。
向博主无私奉献知识产权表示敬意。

但是这个功能在文章下面体现上一篇和下一篇,我认为和右下角 “作者的其他最新日志” 的功能有重叠之处。 看不出有什么不同。
回复 天香公主 2014-11-13 11:54 PM
看到检测说在夜夜城里添加了这个功能,谢谢欣赏。

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 立即注册

小黑屋|Archiver|彼岸网  

Powered by Discuz! X3.1 © 2001-2014 Comsenz Inc.
GMT-4, 2024-3-29 11:08 AM , Processed in 0.019704 second(s), 10 queries. ,ApcOn

返回顶部