标签wordpress下的文章

Jerry Bendy 发布于 01月02, 2015

在自己的PHP程序中实现插件机制:提取Wordpress插件机制代码

本人写代码有个毛病:不喜欢把代码写死,总要留出些扩展的余地(其实也不算什么缺点吧,好处是有的,但老是这样对于一些小项目来说太浪费时间了)。对于写一个可扩展的项目而言,插件机制似乎是必须的。例如我们需要在从数据库中获取到文章内容后执行一些操作,如转换代码高亮的符号为对应的pre标签、转换Emoji表情符号为图片地址或类、给文章内所有的图片加上LightBox效果的代码等等,如果把这些操作统统都写到Post类中,这个类将会在以后的代码升级过程中变得越来越大,并且越来越难维护。

了解过Wordpress的插件机制的可能都知道,WP会这么做(演示代码,并非抄自WP):

// 插件内
// 添加过滤器函数
add_filter('the_content', 'func_apply_hightlight');
add_filter('the_content', 'func_conv_emoji');
add_filter('the_content', 'func_show_lightbox');
...
function func_apply_hightlight{
    ...
}
...

// Post类内部
// 应用以上过滤器函数
$this->content = apply_filters('the_content', $this->content);

程序运行到add_filter的时候把过滤器函数暂时保存起来,并且在apply_filters的时候再去查找有没有指定的过滤器函数,如果有则依次执行它们。即在需要对文章内容执行操作的地方加上多个过滤器,并在apply_filters的时候运行它们。

其实自己写一个类似的插件机制并不难,基于Wordpress已经有写好的成熟的代码了,不用白不用,遂提取之~~

以下从WP提取的代码主要为了自己写代码时方便,我一般使用CodeIgniter框架,所以代码自然是按着CI框架来的,可以直接命名为Hooks.php并放在/application/core目录中替换CI原生的Hook机制。当然这个类库同样适用于别的框架或者无框架的环境,自己改下类名什么的就OK了。

<?php
/**
 * 使用WP的插件机制替代CI原生的HOOK类
 * @author        Jerry Bendy
 * @since        Version 2.0
 */
class CI_Hooks {

    /**
     * 保存已经注册到系统中的Hook和Filter,数组应该是这样的形式:
     * $_hooks = array(
     *                 'hook_a' => array(
     *                         'function_a',
     *                         'function_b',
     *                         array('class_c', 'functions_c')
     *                 ),
     *                 'hook_b' => array ( ....
     *
     * 即数组包含另一个数组,且数组的键名即为Hook名(或Filter名),
     * 子数组内保存每个每个Hook的函数名,以便直接调用执行
     */
    private $_actions = array();

    private $_filters = array();

    /**
     * Constructor
     *
     */
    function __construct(){

    }

    // --------------------------------------------------------------------

    /**
     * Call Hook
     *
     * 这个函数用于支持CI原生Hook里的_call_hook方法,
         * 因为/system/core/codeigniter.php中多次调用此方法并判断返回值以确定输出
         * 删除此函数会导致CI无法运行(其实框架可无视或删除此函数)
     *
     * @access    public
     * @param    string    the hook name
     * @return    mixed
     */
    function _call_hook($which = ''){
        if ( ! isset($this->_actions[$tag]) ){
            return FALSE;
        }
        $this->do_action($which);
        return TRUE;
    }
    // --------------------------------------------------------------------

    /**
     * 注册一个Filter到系统中
     * @param string $tag Filter的名字
     * @param callback $function_to_add 要执行的函数回调名
     * @param int $priority Filter执行的优先级,数字越小优先级越高
     * @param int $accepted_args 接收的参数数量
     * @return boolean
    */
    function add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
        $idx = $this->_ig_filter_build_unique_id($tag,$function_to_add,$priority);
        $this->_filters[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args);
        return true;
    }

    // --------------------------------------------------------------------

    /**
     * 检查一个Filter是否被注册,如果指定了要检查的函数则会返回这个函数
     * 是否已经被注册到了这个Filter中
     * @param unknown_type $tag
     * @param unknown_type $function_to_check
     */
    function has_filter($tag, $function_to_check = FALSE){
        $has = !empty($this->_filters[$tag]);
        if ( false === $function_to_check || false == $has )
            return FALSE;

        if ( !$idx = $this->_ig_filter_build_unique_id($tag,$function_to_check, FALSE) )
            return false;

        foreach ( (array) array_keys($this->_filters[$tag]) as $priority ) {
            if ( isset($this->_filters[$tag][$priority][$idx]) )
                return $priority;
        }

        return false;
    }

    // --------------------------------------------------------------------

    /**
     * 执行一个Filter,
     * @param unknown_type $tag
     * @param unknown_type $value
     * @return unknown|mixed
     */
    function apply_filters( $tag, $value ) {
        //检查要执行的Filter是否被注册,如果没有则直接返回传入的Value
        if ( !isset($this->_filters[$tag]) )
            return $value;

        // 对数组按照优先级排序,并将数组指针指向第一个元素
        ksort($this->_filters[$tag]);
        reset( $this->_filters[ $tag ] );

        $args = func_get_args();

        do {
            foreach( (array) current($this->_filters[$tag]) as $the_ ){
                if ( !is_null($the_['function']) ){
                    $args[1] = $value;
                    $value = call_user_func_array($the_['function'], array_slice($args, 1, (int) $the_['accepted_args']));
                }
            }
        } while ( next($this->_filters[$tag]) !== false );

        return $value;
    }

    // --------------------------------------------------------------------

    /**
     * 删除一个已经定义的Filter
     * @param $tag Filter的名称
     * @param $function_to_remove 要删除的Filter的函数名
     * @param $priority 优先级
     * @return Bool
     */
    function remove_filter( $tag, $function_to_remove, $priority = 10 ) {
        $function_to_remove = $this->_ig_filter_build_unique_id($tag,$function_to_remove,$priority);

        $r = isset($this->_filters[$tag][$priority][$function_to_remove]);

        if ( true === $r) {
            unset($this->_filters[$tag][$priority][$function_to_remove]);
            if ( empty($this->_filters[$tag][$priority]) )
                unset($this->_filters[$tag][$priority]);
            //unset($GLOBALS['merged_filters'][$tag]);
        }

        return $r;
    }

    // --------------------------------------------------------------------

    /**
     * 添加一个动作
     * @param $tag 要添加Hook的点
     * @param $function_to_add 要添加的函数名
     * @param $priority 优先级,默认为10
     * @param $accepted_args 接受的参数数量
     * @return
     */
    function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
        return $this->add_filter($tag, $function_to_add, $priority, $accepted_args);
    }

    // --------------------------------------------------------------------
    /**
     * 执行一个动作
     * @param $tag
     * @param $arg
     */
    function do_action($tag, $arg = '') {

        if ( ! isset($this->_actions[$tag]) )
            $this->_actions[$tag] = 1;
        else
            ++$this->_actions[$tag];

        if ( !isset($this->_filters[$tag]) ) {
            return;
        }

        $args = array();
        if ( is_array($arg) &amp;&amp; 1 == count($arg) &amp;&amp; isset($arg[0]) &amp;&amp; is_object($arg[0]) ) // array(&amp;$this)
            $args[] =&amp; $arg[0];
        else
            $args[] = $arg;
        for ( $a = 2; $a < func_num_args(); $a++ )
            $args[] = func_get_arg($a);

        // Sort
        ksort($this->_filters[$tag]);
        reset($this->_filters[ $tag ] );

        do {
            foreach ( (array) current($this->_filters[$tag]) as $the_ )
                if ( !is_null($the_['function']) )
                    call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));

        } while ( next($this->_filters[$tag]) !== false );
    }
    // --------------------------------------------------------------------
    /**
     * 判断一个Action是否已被注册
     * @param $tag
     * @param $function_to_check
     */
    function has_action($tag, $function_to_check = false) {
        return $this->has_filter($tag, $function_to_check);
    }
    // --------------------------------------------------------------------
    /**
     * 删除一个Action
     * @param $tag
     * @param $function_to_remove
     * @param $priority
     */
    function remove_action( $tag, $function_to_remove, $priority = 10 ) {
        return $this->remove_filter( $tag, $function_to_remove, $priority );
    }
    // --------------------------------------------------------------------
    /**
     * 为传入的钩子生成一个唯一的标识符,以便区分不同的钩子,
     * 使用对Tag、函数名、优先级一起格式化后返回
     * 方式创建唯一标识
     * @param $tag
     * @param $function
     * @param $priority
     */
    private function _ig_filter_build_unique_id($tag, $function, $priority){
        static $filter_id_count = 0;

        if ( is_string($function) )
            return $function;

        if ( is_object($function) ) {
            // Closures are currently implemented as objects
            $function = array( $function, '' );
        } else {
            $function = (array) $function;
        }

        if (is_object($function[0]) ) {
            // Object Class Calling
            if ( function_exists('spl_object_hash') ) {
                return spl_object_hash($function[0]) . $function[1];
            } else {
                $obj_idx = get_class($function[0]).$function[1];
                if ( !isset($function[0]->wp_filter_id) ) {
                    if ( false === $priority )
                        return false;
                    $obj_idx .= isset($this->_filters[$tag][$priority]) ? count((array)$this->_filters[$tag][$priority]) : $filter_id_count;
                    $function[0]->wp_filter_id = $filter_id_count;
                    ++$filter_id_count;
                } else {
                    $obj_idx .= $function[0]->wp_filter_id;
                }

                return $obj_idx;
            }
        } else if ( is_string($function[0]) ) {
            // Static Calling
            return $function[0] . '::' . $function[1];
        }

    }

}

光有类库还不太方便,因为这样的话就需要创建一个全局变量(CI的类库不需要创建全局变量,默认可以直接通过$this->hook的方式调用),并在每次使用的时候执行一下声明,如:

// 创建一个全局变量(适用于除CI以外框架)
global $hook;
$hook = new CI_Hook();

// 调用代码
global $hook;
$hook->add_action('xxxx', 'xxxxxxx');

显然这样相当繁琐。不过如果把这些函数整理起来并且成一个个辅助函数就会方便很多:

// 辅助函数  hook_helper.php
global $hook;
$hook = new CI_Hook();

function add_action($a, $b, $c=10, $d=1){
    global $hook;
    $hook->add_action($a, $b, $c, $d);
}
...

// 调用函数
add_action('xxx', 'xxxxxx');

这样还不够,add_filter必须要在apply_filters之前运行才会有效,所以插件机制需要在系统之前加载,并在还要在系统真正执行对内容的操作之前加载所有插件,这样就需要在系统运行前,如控制器函数构造前、系统核心部件加载时(或完成后)就加载所有插件,再附上我写的一个加载插件文件的函数:

/**
 * 载入一个插件目录中的所有PHP文件,
 * 这通常应该在系统初始化的过程中完成,这样可以保证
 * 所有的插件文件能够在运行前被加载
 * (2014-07-22 更新)
 *
 * @param $path 要加载的插件目录
 * @param $include_sub_dir 默认为TRUE,是否加载子目录中的PHP文件,
 *         值为TRUE时除了加载根目录的PHP文件,也会加载子目录中与子目录同名的文件
 *         值为FALSE时仅加载根目录的PHP文件
 * @return 加载完成后返回TRUE,错误返回FALSE,文件不存在时自动忽略而不提示
 */
function load_plugin_dir($path, $include_sub_dir = TRUE){
    if( ! file_exists($path) || ! is_dir($path))
        return FALSE;
    $path = rtrim($path, '/') . '/*';
    $ret = glob($path);
    foreach($ret as $file){
        if(is_dir($file)){
            if($include_sub_dir){
                $dirname = substr($file, strripos($file, '/') + 1);
                if(file_exists($file . '/' . $dirname . '.php'))
                    include_once $file . '/' . $dirname . '.php';
            }
        } else {
            if(strtolower(pathinfo($file, PATHINFO_EXTENSION)) == 'php')
                include_once $file;
        }
    }
}

例如你把你的插件都放在一个叫做/usr/plugin的目录中,并且一个插件创建一个文件夹,这时你需要让这个插件的入口文件与文件夹同名,并使用以下方法加载它们,此函数可以多次调用以加载不同位置的插件:

load_plugin_dir('/usr/plugin', TRUE);

剩下的自己补充吧,附上整理好的CI类库使用的Helper函数:

/**
 *  插件机制的HELPER函数部分
 */
/**
 * 注册一个动作到系统中
 * @param string $tag 动作的名字
 * @param callback $function_to_add 要执行的函数回调名
 * @param int $priority 动作执行的优先级,数字越小优先级越高
 * @param int $accepted_args 接收的参数数量
 * @return boolean
 */
function add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
    $CI = &amp;get_instance();
    return $CI->hooks->add_filter($tag, $function_to_add, $priority, $accepted_args);
}
/**
 * 检查一个Filter是否被注册,如果指定了要检查的函数则会返回这个函数
 * 是否已经被注册到了这个Filter中
 * @param unknown_type $tag
 * @param unknown_type $function_to_check
 */
function has_filter($tag, $function_to_check = FALSE){
    $CI = &amp;get_instance();
    return $CI->hooks->has_filter($tag, $function_to_check);
}
/**
 * 执行一个Filter,
 * @param unknown_type $tag
 * @param unknown_type $value
 * @return unknown|mixed
 */
function apply_filters( $tag, $value ) {
    $CI = &amp;get_instance();
    $args = func_get_args();
    return call_user_func_array(array($CI->hooks, 'apply_filters'), $args);
}
/**
 * 删除一个已经定义的Filter
 * @param $tag Filter的名称
 * @param $function_to_remove 要删除的Filter的函数名
 * @param $priority 优先级
 * @return Bool
 */
function remove_filter( $tag, $function_to_remove, $priority = 10 ) {
    $CI=&amp;get_instance();
    return $CI->hooks->remove_filter($tag, $function_to_remove, $priority);
}
/**
 * 添加一个动作
 * @param $tag 要添加Hook的点
 * @param $function_to_add 要添加的函数名
 * @param $priority 优先级,默认为10
 * @param $accepted_args 接受的参数数量
 * @return
 */
function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
    $CI=&amp;get_instance();
    return $CI->hooks->add_action($tag, $function_to_add, $priority, $accepted_args);
}
/**
 * 执行一个动作
 * @param $tag
 * @param $arg
 */
function do_action($tag, $arg = '') {
    $CI=&amp;get_instance();
    $args = func_get_args();
    return call_user_func_array(array($CI->hooks, 'do_action'), $args);
}
/**
 * 判断一个Action是否已被注册
 * @param $tag
 * @param $function_to_check
 */
function has_action($tag, $function_to_check = false) {
    $CI=&amp;get_instance();
    return $CI->hooks->has_action($tag, $function_to_check);
}
/**
 * 删除一个Action
 * @param $tag
 * @param $function_to_remove
 * @param $priority
 */
function remove_action( $tag, $function_to_remove, $priority = 10 ) {
    $CI=&amp;get_instance();
    return $CI->hooks->remove_action($tag, $function_to_remove, $priority);
}
/**
 * 载入一个插件目录中的所有PHP文件,
 * 这通常应该在系统初始化的过程中完成,这样可以保证
 * 所有的插件文件能够在运行前被加载
 * (2014-07-22 更新)
 *
 * @param $path 要加载的插件目录
 * @param $include_sub_dir 默认为TRUE,是否加载子目录中的PHP文件,
 *         值为TRUE时除了加载根目录的PHP文件,也会加载子目录中与子目录同名的文件
 *         值为FALSE时仅加载根目录的PHP文件
 * @return 加载完成后返回TRUE,错误返回FALSE,文件不存在时自动忽略而不提示
 */
function load_plugin_dir($path, $include_sub_dir = TRUE){
    if( ! file_exists($path) || ! is_dir($path))
        return FALSE;
    $path = rtrim($path, '/') . '/*';
    $ret = glob($path);
    foreach($ret as $file){
        if(is_dir($file)){
            if($include_sub_dir){
                $dirname = substr($file, strripos($file, '/') + 1);
                if(file_exists($file . '/' . $dirname . '.php'))
                    include_once $file . '/' . $dirname . '.php';
            }
        } else {
            if(strtolower(pathinfo($file, PATHINFO_EXTENSION)) == 'php')
                include_once $file;
        }
    }
}

按下来我们就可以像Wordpress那样使用插件机制啦~

阅读全文 »

Jerry Bendy 发布于 09月08, 2014

推荐一个WP代码高亮插件SyntaxHighlighter

网络关于Wordpress代码高亮插件有很多,我之前使用的是一款叫做Crayon Syntax Highlighter的插件,界面比较漂亮,而且设置项丰富。在使用Crayon Syntax Highlighter一段时间后发现此插件占用系统资源比较高,容易导致网页打开速度变慢,而且此插件似乎还与我用的主题有些冲突,以致于前台的复制、小窗打开等功能不能用,无奈之下去寻求别的插件。

在各WP论坛上见除了Crayon Syntax Highlighter之外被讨论最多的就属SyntaxHighlighter了,网上关于此插件的说明多如牛毛,我也就带过了,挑一些有用的说下。

SyntaxHighlighter Evolved基于开源的JS核心库:SyntaxHighlighter JavaScript package by Alex Gorbatchev二次开发扩展的。安装后只需简单设置一下,不用修改任何代码即可达到很好的效果。

插件效果可以参见我的另一篇文章中的代码部分:WordPress文章和评论中自动应用短网址

特点

  1. 代码高亮
  2. 支持Eclips、Emacs等多种样式,可搭配不同风格的主题
  3. 特色——显示工具条。右上角显示工具条,可以”查看源代码”、”复制源代码”、”打印源代码”。(只有第2版支持)
  4. 显示行号
  5. 长代码自动换行(只有第2版支持)
  6. 可以点击代码中的超文本链接
  7. 可以收缩代码框
  8. 高亮显示模式—某一行高亮
  9. 设置开始行号
  10. 自定义样式

插件安装

直接在WP后台安装插件处搜索SyntaxHighlighter Evolved安装即可,或者从Wordpress官网下载后安装到plugins目录下。

使用方法

这款插件不像Crayon Syntax Highlighter在后台编辑页面直接有可用的按钮,它需要在文本模式下编辑标签才可以使用,如(注意:请把前面的@去掉):

 [@php]这里写你的代码[/php]

 [@css autolinks="false" classname="myclass" collapse="false" firstline="1" gutter="true" highlight="1-3,6,9" htmlscript="false" light="false" padlinenumbers="false" smarttabs="true" tabsize="4" toolbar="true" title="example-filename.php"]这里写你的代码[/css]

 [@code lang="js"]这里写你的代码[/code]

 [@sourcecode language="plain"]这里写你的代码[/sourcecode]

方括号里面是语言标签,也可以添加一些属性,像代码高亮的行、是否显示工具条等。可用的语言标签还有很多,如:bash、shell、cli、cpp、c、css、delphi、diff、patch、java、js、javascript、text、perl、php、powershell、py、python、ruby、sql、vb、vbnet、xml、html等等数十种(完整的支持列表请参见官网文档)。

需要注意的地方

1、设置中提供了Highlighter Version的两个版本,即Version2.X和Version3.X,推荐使用Version2.X,因为像代码自动换行功能以及右上角的源码/打印工具条只有在2.X版本下才能显示。

2、编辑代码时最好在源代码模式下,即WP的“文本”模式下编辑,以避免“可视化”编辑中出现的代码转义。

3、像HTML实体中的大于号、小于号等在文本模式下不需要转义书写,直接粘贴源代码进去就可以了,而这种转义字符在“预览”时会被显示成转义后的,不用管它,直接发布(或更新)文章,发布后文章可以正常显示。

阅读全文 »

Jerry Bendy 发布于 03月11, 2014

Wordpress文章和评论中自动应用短网址

前几天冰翼博客推出了自己的短网址程序并且对外开放了调用API(见《冰翼短网址程序改版上线,开放API》),今天就实战下,讲述如何在Wordpress中应用短网址。

至于在博客中使用短网址的好处我就不多说啦,都是为了SEO。以下代码可单独创建为一个插件,也可以加在主题 functions.php 的后面使用,代码中有两个add_filter函数,如果不需要使用评论或文章中的应用短网址操作直接把对应的add_filter删除(或注释)掉即可:

======================================= 【更新】2014-09-08 Version 1.07 之前的代码使用的PHP的内联函数,而这一特性在低版本的PHP中不支持,就会导致某些虚拟主机服务启用插件是报错

```php WP短网址代码 <?php / Plugin Name: icewingcc_short_url Plugin URI: http://blog.icewingcc.com Description: 自动在发表文章和评论中将文中的URL替换成短网址 Version: 1.07 Author: Jerry Bendy Author URI: http://blog.icewingcc.com Text Domain: icewingcc_functions /

//在发表评论时应用短网址
add_filter('pre_comment_content', 'icewingcc_comment_short_url'); function icewingcc_comment_short_url($content){ $text = stripslashes($content); $text = icewingcc_short_url($text); $text = wp_slash($text); return $text; }

//在发表文章时应用短网址 add_filter('content_save_pre', 'icewingcc_comment_short_url');

function icewingcc_short_url($content){ $text= preg_replace_callback('/()/i' , 'icewingcc_short_url_callback', $content ); return $text; }

//PHP5.3以下版本不支持内联函数,只能这样做了。。。 function icewingcc_short_url_callback($matches){ //匹配到的数组,0一般表示完整的匹配,1表示第一个匹配到的子串 if(isset($matches[0])){ try{ //过滤所有链接是u.byi.pw的情况 if(strpos(strtolower($matches[2]), 'u.byi.pw') !== FALSE){ return $matches[0]; } //过滤链接是本站地址的情况 if(strpos(strtolower($matches[2]), parse_url(get_bloginfo('url'), PHP_URL_HOST)) !== FALSE){ return $matches[0]; } //初始化并设置CURL参数 $ch = curl_init(); curl_setopt($ch,CURLOPT_URL,"http://u.byi.pw/api/create"); curl_setopt($ch,CURLOPT_POST,true); curl_setopt($ch,CURLOPT_RETURNTRANSFER,true); //数据参数 $data = array('url' => $matches[2]); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); $strRes = curl_exec($ch); curl_close($ch); //解析服务器返回的JSON字符串 $arrRspn = json_decode($strRes, TRUE);

        if($arrRspn['status'] > 0){
            return $matches[0];
        } else {
            return $matches[1] . $arrRspn['tinyurl'] . $matches[3];
        }
    }catch(Exception $e){
        return $matches[0];
    }
}

} ```

代码打包下载:

下载地址

阅读全文 »

Jerry Bendy 发布于 02月06, 2014

Wordpress可扩展函数(pluggable)的作用及用法

Wordpress核心函数中有一些函数称为可扩展函数(pluggable functions),这些函数都是在wp-include/pluggable.php中被定义的,正如它们的名字一样,我们可以通过插件来重写或者加强它们的功能。

可扩展函数的真正强大之处在于我们可以自定义函数来增强或改变原有函数的行为。在pluggable.php中可以找到这些函数的定义,或者在WP文档Pluggable Functions中找到它们。以下有几个经常被重写的核心函数:

  • wp_logout用于登出WP系统,你可以在这里加入一些自定义的操作(如移除自定义SESSION等)。
  • wp_mail是被扩展的最多的WP函数,可以通过覆写它来使用自己的邮件模版、使用其它的发送邮件方式(如SMTP)等。
  • wp_new_user_notification可以修改新用户注册时发送邮件的方式。
  • auth_redirect用于在用户未登录时重定向操作到登录页,可以用它来显示一些自定义的信息。 下面来了解一下如何扩展一个pluggable函数。以wp_logout为例。

怎样使用

首先,打开pluggable.php并复制wp_logout函数部分的代码,并且在你的文件里粘贴,默认的代码如下:

if ( ! function_exists( 'wp_logout' ) ) {
    /**
     * Log the current user out.
     *
     * @since 2.5.0
     */
    function wp_logout() {
        wp_clear_auth_cookie();
        do_action( 'wp_logout' );
    }
}

下面是重写后的版本:

if ( ! function_exists( 'wp_logout' ) ) {
    /**
     * Log the current user out.
     *
     * @since 2.5.0
     */
    function wp_logout() {
        remove_sessions() ; // 自定义的函数调用
        wp_clear_auth_cookie();
        do_action( 'wp_logout' );
    }

    function remove_sessions() {
        // 在这里移除自定义SESSION和Cookie
    }
}

以上仅仅是在自己的插件里面实现了对WP核心函数的重写,并且添加了自定的函数调用。有一个细节性的问题是在函数定义前必须要加上if(!function_exists('wp_logout')){,这一行会在定义函数前检查这个函数是否已经在前面被定义过了,如果不加上这句会在函数已被定义的情况下产生一个致命错误。

有一个问题就是在使用了“function_exists”来检测函数是否被定义过时我如何才能知道我写的扩展函数到底是否被执行了呢?这个关系到WP系统的执行顺序,下面会提到。

可以在自定义函数中省略“function_exists”的检查吗?

当然可以,不过你需要承担因此带来的一切后果。如果你要重写的函数在其它插件中已经被重写过了,这时就有可能会出现一个PHP致命错误“Cannot redeclare wp_logout()”。所以在重写之前最好还是检查一下函数是否已经被定义过。

既然已经知道了可扩展函数的使用方法,下面就提下这些函数应该被放置在什么位置。

可扩展函数的执行顺序

我见过很多人在主题的functions.php中重写pluggable函数,结果没能如预期般正确执行,所以你有必要了解下WP的pluggable函数的执行顺序。

在WP文档的Action Reference中有提到,这里引用一张图片(虽然是英文)来简单说下可扩展函数的执行顺序。

wordpress-action-execution-order

 

这张图展示了通常的WP函数的执行顺序。基本意思是最先执行必须加载的插件函数,然后是MU插件、已激活的插件、pluggable函数、主题,也就是说pluggable.php会在主题之前被加载。也就是说:

  • 所以的自定义扩展函数都应该放在pluggable.php文件被加载之前定义,即在插件中定义;
  • 如果插件中没有定义扩展函数,将会默认执行pluggable.php中定义的函数;
  • 你无法在主题中定义扩展数,因为主题会在pluggable.php之后加载,此时这些可扩展函数都是已经被定义过的了。 所以我们只能够在插件中来重写这些函数(自己创建一个插件的方式非常简单)。接下来的问题就是如果多个插件中同时重写了同一个可扩展函数时将会怎样呢?这个时候就无法再像我们预期那样执行了,系统总会调用第一次被定义的那个函数。

当然,有一个非主流的并且被称为不推荐使用的方法可以避免上面的问题,并且保证总是调用你的函数,即使用PHP的APD函数。PHP有个函数叫做rename_function,使用这个函数可以改变一个已经定义的函数的函数名,于是可以衍生出以下用法:

if ( function_exists( 'wp_logout' ) ) { //注意这行没有加叹号
    // 把已被定义过的wp_logout函数改名为wp_logout_orig,并定义自己的wp_logout函数
    rename_function('wp_logout', 'wp_logout_orig');
}

/**
* Log the current user out.
*
* @since 2.5.0
*/
function wp_logout() {
   remove_sessions() ; // Custom Function Call
   wp_clear_auth_cookie();
   do_action( 'wp_logout' );
}

function remove_sessions() {
   // Remove custom session and cookie information
}

即在定义这个函数时先检查这个函数是否已经被定义过,如果定义过的话就把这个函数的名字改掉,并重新定义这个函数。

WP的可扩展函数允许我们自己来扩展Wordpress的核心函数,当然它的基本思路还是简单的在定义函数之前检测下这个函数是否已经被定义过,同样的道理我们也可以在自己的主题functions.php中使用这个方法,以方便在子主题中轻松地扩展主题函数。Wordpress系统是在不断更新的,使用可扩展函数的最大实用是可以100%的自定义,并且超出actions可以做到的限度。当然使用这些函数也有不好的地方,如重复定义的问题等。不过可喜的是现在大部分原来必须要重写可扩展函数才能完成的功能逐渐被WP强大的插件体系完善了。如之前必须重写或者修改源代码才能完成的使用SMTP发送邮件的方法现在也可以使用phpmailer_init动作来完成了。WP是在不断进步的,还有更多惊喜等着被发现。

部分内容来源于tutsplus

阅读全文 »

Jerry Bendy 发布于 01月13, 2014

与垃圾评论战斗在一线~~

由于以前使用的多说评论,几乎看不到什么垃圾评论,自从朋友说使用多说后收不到我回复时的邮件通知(其实我自己出收不到通知邮件)我就把多说给禁了,从此后垃圾评论满天飞啊~~

试过各种方法去拦截,后来又发现我所用的空间不支持PHP的Mail函数所以导致不能发送邮件(现在开始怀疑多说收不到通知邮件是不是也是这个原因),就尝试重写了wp_mail函数,邮件功能恢复后就开始了邮件满天飞的情况,垃圾邮件到了不得不阻止的地步了。

开始是自己写了个简单的插件,虽然写个小插件与直接改funcions.php效果一样,插件只实现一个简单的功能:就是当评论的内容包含一个以上的链接时将其标记为垃圾评论,误判率低于5%!尽管如此可还是能收到每条垃圾评论的邮件通知。又试着修改“wp-comment-post.php”的文件名,似乎没什么用,又修改其源代码在“wp-comment-post.php”的前面加上了一个额外的字段的判断,并且在主题上添加对应的隐藏字段,这样一来理论上可以防止所有机器人的评论,郁闷的是竟然没起作用?!

if( ! isset($_POST['icewingcc_spam_check'])  || $_POST['icewingcc_spam_check'] != 'oi;D]m*92.rZAMl/b<14}CTczbHdG2KzjvEq,DLKw|t0)#LLd/f5OV/%{!=^+HFk'){
    die('Spam comment is not allowed');
}

真的很纠结,换个思路吧,既然垃圾评论已经被识别为垃圾评论了,只要阻止垃圾评论的邮件通知不就可以了吗?查找邮件通知的代码,发现在“wp-includes/pluggable.php”中有一个叫做“wp_notify_postauthor”的函数是控制评论邮件通知的,从Wordpress3.7开始这个函数里面定义了个新的Filter “comment_notification_recipients”,它接受两个参数,如果mail为空的话便会返回FALSE,就不会继续发送邮件啦。

在上面的插件函数中检测到是垃圾评论时执行以下方法:

wp_spam_comment($comment_id);
add_filter('comment_notification_recipients', 'icewingcc_prevent_notification', 10, 2);

function icewingcc_prevent_notification($emails, $comment_id){
    return array();
}

郁闷的是这些代码在本地测试的时候有效,放在空间却没有执行~~因为这是个新出的Filter,网上也找不到相关的说明,不知用法对不对呢。

以下是完整的插件代码:

<?php
/*
Plugin Name: icewingcc_functions
Plugin URI: http://blog.icewingcc.com
Description: 一些额外的函数集合,不可以禁用此插件,以免出错
Version: 1.06
Author: Jerry Bendy
Author URI: http://blog.icewingcc.com
Text Domain: icewingcc_functions
*/

/**
* 自动将hotmail和gmail里面带链接的评论加入到垃圾评论
* @since 1.01 2014-1-9
*/
add_action('comment_post', 'icewingcc_comment_auto_spam');
function icewingcc_comment_auto_spam($comment_id){
    $comment = get_comment($comment_id);
    $comment_author_email = trim($comment->comment_author_email);
    $comment_author_ip = $comment->comment_author_IP;

    //指定邮箱禁止存在链接
    if (preg_match('/(hotmail\.com|gmail\.com|outlook)/i', $comment_author_email)){
        if(preg_match('/<a href=/i', $comment->comment_content)){
            icewingcc_log_file('spam', "the ID is {$comment_id}, IP is {$comment_author_ip},  Get gmail or hotmail Spam comment");
            icewingcc_spam_comment($comment_id);
            return;
        }
    }

    //全局禁止一个以上的链接出现
    if(preg_match_all('/<\/a>/i', $comment->comment_content,  $out, PREG_PATTERN_ORDER) > 1){
        icewingcc_log_file('spam', "the ID is {$comment_id}, IP is {$comment_author_ip}, Get the Spam with more links");
        icewingcc_spam_comment($comment_id);
        return;
    }

    icewingcc_send_email($comment_id);
}

/**
 * 把一条评论加入到垃圾评论,并阻止WP系统发送通知邮件
 */
function icewingcc_spam_comment($comment_id){
    wp_spam_comment($comment_id);

    //通过Filter :comment_notification_recipients清空收件人列表以阻止发送邮件
    //这个Filter在pluggable.php 文件中的 wp_notify_postauthor函数中被定义
    add_filter('comment_notification_recipients', 'icewingcc_prevent_notification', 10, 2);
}

//执行阻止发送邮件的过程
function icewingcc_prevent_notification($emails, $comment_id){
    icewingcc_log_file('filter', "阻止发送邮件{$comment_id}");
    return array();
}

/**
 * 写入一行日志
 */
function icewingcc_log_file($filename, $content){
    $dir = dirname(__FILE__) . '/';
    $filepath = $dir . $filename . '.log';

    $content = '##' . date('Y-m-d H:i:s', time()) . ': ' . $content . "\n";
    return file_put_contents($filepath, $content, FILE_APPEND);
}

/**
* 发送邮件
* @param $comment_id 传入评论的ID,自动根据ID生成邮件内容
*/
function icewingcc_send_email($comment_id){
    $admin_email = get_bloginfo ('admin_email');
    $comment = get_comment($comment_id);
    $comment_author_email = trim($comment->comment_author_email);
    $parent_id = $comment->comment_parent ? $comment->comment_parent : '';
    $to = $parent_id ? trim(get_comment($parent_id)->comment_author_email) : '';
    $spam_confirmed = $comment->comment_approved;

    //管理回复评论时,发送邮件给发表评论的读者
    if (($parent_id != '') &amp;&amp; ($spam_confirmed != 'spam') &amp;&amp; ($to != $admin_email) &amp;&amp; ($comment_author_email == $admin_email)) {
        $subject = '您在 [' . get_option("blogname") . '] 的评论有新的回复';

$temp_msg = <<<EOF
<div style="background-color:#eef2fa; border:1px solid #d8e3e8; color:#111; padding:0 15px; -moz-border-radius:5px; -webkit-border-radius:5px; -khtml-border-radius:5px; border-radius:5px;">
    <p>{parent_comment_author}, 您好!</p>
    <p>您曾在 [{blog_name}] 的文章 《{post_title}》 上发表评论:<br />
        {parent_comment_content}</p>
    <p>{comment_author} 给您的回复如下:<br />
        {comment_content}<br /></p>
    <p>您可以点击 <a href="{comment_link}">查看回复的完整內容</a></p>
    <p>欢迎再次光临 <a href="{site_url}">{blog_name}</a></p>
    <p>(此郵件由系統自動發出, 請勿回覆.)</p>
</div>
EOF;
        $message = str_replace(
                array(
                        '{parent_comment_author}', //1
                        '{blog_name}', //2
                        '{post_title}', //3
                        '{parent_comment_content}', //4     
                        '{comment_author}',  //5
                        '{comment_content}', //6
                        '{comment_link}', //7
                        '{site_url}'  //8
                        ),
                array(
                        trim(get_comment($parent_id)->comment_author),  //1
                        get_option("blogname"),  //2
                        get_the_title($comment->comment_post_ID),  //3
                        nl2br(get_comment($parent_id)->comment_content), //4
                        trim($comment->comment_author), //5
                        nl2br($comment->comment_content), //6
                        htmlspecialchars(get_comment_link($parent_id)),  //7
                        get_option('home') //8
                        ),
                $temp_msg
                );

        $from = 'From: "' . get_option('blogname') . ' <' . ICEWINGCC_MAIL_ADDR . ">";
        $headers = "$from\nContent-Type: text/html; charset=" . get_option('blog_charset') . "\n";
        wp_mail( $to, $subject, $message, $headers );
    }
}

不知为何,代码运行良好,没收到任何错误,却不能阻止邮件的发送,又想到了另一个方法:重写“pluggable.php”中的“wp_notify_postauthor”方法并加入判断机制,当然我并没有这样做,而是安装了一个Akismet插件去过滤垃圾评论。

在这场垃圾评论的对抗赛中又失败了,最终还是不得不使用了插件~

阅读全文 »

Jerry Bendy 发布于 09月02, 2013

8个简单方法提升WordPress速度

WordPress是一个很棒的开源程序,几乎我认识的站长朋友当中,粗略估算有80%使用Wordpress。但很棒不等于完美,就在我所认识的这些朋友中,几乎所有人都会抱怨Wordpress太臃肿,运行效率太低了,大家有无同感?

所以,今天这篇博文和大家分享8个小贴士来提升WP的运行效率,如果您运用了这些方法后发现确实有帮助,请把这篇博文分享给更多的人好吧?当然为了尊重劳动成果,也烦请指明出处。

1、使用高效的缓存插件

WordPress的插件们是非常有用的, 我推荐一款缓存插件可以改善页面载入时间,它就是W3 Total Cache,有了这个插件之后咱就不再推荐你其他缓存插件了,因为所有缓存插件有的功能它都有了,而且安装和使用非常方便。

拥有这款插件之后,你的页面载入速度会加快,因为网站的主要元素已经被缓存了。

2. 使用内容分发网络 (CDN)

基本上所有你喜欢的大网站都会使用CDN。简单来说,CDN是把你站点上的文件们(CSS\JS\图片等)发布到最接近用户所在的网络区域,让用户就近下载,这样就能提高站点运行速度。在国内ChinaCache是比较有名的CDN供应商,不过价格贵了一些,像各大门户网站,比如腾讯、新浪、网易等等都是用ChinaCache。所以不管你在哪里,访问这些门户网站都会觉得速度很快。当然啦,对于小站来说,这个成本可能会高一些,

所以,你无论是在南方,或者北方,还是在北美,访问这些门户网站,感觉速度都很快,最主要的原因之一就是CDN发挥了效果。一般小网站是用不起这服务的,所以慢点就慢点了吧,可以租用互联互通的6线机房(6线机房是指包括网通、电信、铁通、移动、联通、教育网等多线接入的骨干网IDC机房,彻底消除各地网络瓶颈,保证互联网访问畅通无阻的高速机房。)

顺便提一下,还有一个Wordpress插件叫Free-CDN,号称也能达到类似的效果,虽然我还没有做过测试…

3、图片优化很重要

Yahoo! 有一个图片优化软件叫Smush.it可以最大程度无损压缩图片,不过,除非你超级有耐心,否则一张张压缩图片的话太浪费时间了,好在,还有一个很给力的WP插件叫WP-SmushIt,这货可以为你网站上所有的图片做一次性压缩,所以没有理由不去用它。

4、优化你的WP数据库

你可以用WP-Optimize这个插件来优化你的WP数据库(清理spam,反复改版的文章,草稿,表格等等为你的服务器腾出更多空间从而提升效率);还有一些插件如WP-CleanerDB-Manger等。

5、开启防盗链机制

盗链是带宽的窃贼,当其他网站直接引用你站点的图片的时候,这会影响占用你本身的服务器资源从而影响网站运行效率,你的站点越出名,就会有越多的人盗用你的图片,解决方法是Wordpress有现成的插件Hotlink Protection。当然也可以通过重写htaccess文件来达到同样的效果,欲深入了解的童鞋可以询问自己的空间商如何设置。

6、为文件添加过期时间

关于这个文件过期时间,听起来很玄乎,其实就是通过header报文来指定特定类型的文件在浏览器中的缓存时间。有些文件(例如样式表中调用的背景图片和一些装饰性图片)其实在很长一段时间内这些图片都不会有很大的变化,所以对这类文件我们不妨设置长一些的缓存时间,这样浏览器就不需要每次从服务器下载这些文件而直接从缓存中读取,这样绝对可以提升加载速度。

当然,所以做法很简单,只需要在网站的.htaccess文件中加入以下代码,

<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault A600
ExpiresByType image/x-icon A2592000
ExpiresByType application/x-javascript A604800
ExpiresByType text/css A604800
ExpiresByType image/gif A2592000
ExpiresByType image/png A2592000
ExpiresByType image/jpeg A2592000
ExpiresByType text/plain A86400
ExpiresByType application/x-shockwave-flash A2592000
ExpiresByType video/x-flv A2592000
ExpiresByType application/pdf A2592000
ExpiresByType text/html A600
</IfModule>

稍微解释一下,text/css表示样式表文件,text/plain代表的纯文本类文件,依次类推。其中A2592000就表示这种类型文件在浏览器中的缓存时间,以秒为单位。一天86400秒,2592000就表示这类文件可以缓存30天。

如果你不是经常修改模板,那样式表文件和javasctipt文件基本上也可以设置缓存一周到一个月左右。text/html文件不要设置太长的缓存时间,因为这些东西修改的频率很高,一天更新一次是有必要的。

7、为你的图片添加延时加载

延时加载就是当用户停留在第一屏的时候,不加载任何第一屏以下的图片信息,只有当用户把鼠标往下滚动的时候,这些图片才开始加载。这玩意儿不仅可以提升站点载入速度,更是可以节省带宽。要轻松的拥有这项功能,请安装WP的jQuery Image Lazy Load 插件吧。

8、控制文章草稿存数数

通常一篇博文我会保存10次以上的草稿,而Wordpress会无限制的存储每个草稿;如果我的博文已经发布了,为啥我还需要这些储存的草稿文章呢?所以这就是为啥我会用 Revision Control 插件来确保这些草稿内容的最小化。通常我会设置只存储2-3篇草稿来防止万一,但存储的数量绝对不会太高,否则你的WordPress backend只会被这些无意义的内容塞满从而降低运行效率。

好了,今天的分享就到这里,希望对大家有帮助,其实这些要点不仅仅对Wordpress有帮助,对其他开源网站也同样奏效。:-)

 

来源:SEOTime

阅读全文 »

Jerry Bendy 发布于 04月05, 2013

Wordpress非插件实现自定义表情及修改表情目录

或许我们每天都会浏览大量博客,这其中大多数是基于Wordpress的,我们也会留言表示来过,偶尔看到别人博客上漂亮的表情很是心动,或者早已厌倦了Wordpress自带的22个丑到爆的表情,想要换成自己喜欢的风格,下面我们就来实现这种自定义表情!!!

首先你应该准备一些表情图片,不要太大,可以在网上找,也可以去我的百度云盘下载,文章最后有下载地址,里面是52个常用的QQ表情和下面将会用到的代码。

根据个人习惯,我把表情解压到了根目录的res/smilies/文件夹下,这个位置可以自己定义,不过代码要改成自己定义的文件夹路径。

OK,闲话少说,上代码 !

第一步:添加筛选器

打开主题目录下的“functions.php”,找到最后的那个“?>”符号,这是PHP的结束标记。

在这个符号前面添加如下代码:

//添加表情筛选器
add_filter('smilies_src','custom_smilies_src',1,10);
function custom_smilies_src ($img_src, $img, $siteurl){
    return '/res/smilies/'.$img;

以上代码里面需要把对应的路径改成自己的路径。

关于add_filter的文档可以参见网友“山的那边很漂亮”的文章:wordpress之插件 add_filter,add_action()机制

第二步:定义表情符号对应的文件名

关于这一步有多种实现方法。

方法一:修改“wp-includes/functions.php”

这个是系统的文件,打开后转到第2426行(至少我的是第2426行)或者搜索“function smilies_init”,可以看到在“$wpsmiliestrans = array(”后面放满了类似':mrgreen:' => 'icon_mrgreen.gif'这种对表情代码和表情文件间的映射,既然我们是自定义表情和表情路径,那么这些自带的映射就完全可以不要了,删除之(注意这些映射前后的括号不能删)。

接下来要做的就是依样画葫芦,把自己的表情标识和文件名之间映射起来,我是用文件名做的标识,即 【‘:tp:’=>’tp.gif’,】,别忘了每两项之间的逗号!

其实稍微懂些PHP的都能看明白,这是定义了一个数组。

方法二:修改主题目录下的“functions.php”

方法一虽然简单直接,但毕竟是修改了系统文件,而对系统文件的任何修改都是不推荐的(如果以后遇到WP升级就会把修改的文件替换掉)。

如果不想修改系统文件可以在主题目录的“functions.php”的最后,即第一步中添加筛选器的后面添加如下代码:

//进行表情定义
if ( !isset( $wpsmiliestrans ) ) {
    $wpsmiliestrans = array(
        ':bs:' => 'bs.gif',
        ':by:' => 'by.gif',
        ':bye:' => 'bye.gif',
        ':bz:' => 'bz.gif',
        ':ch:' => 'ch.gif',
        ':cy:' => 'cy.gif',
    );
}

因为篇幅的问题我就不把所有的映射都写完了,可以下载我编写好的代码直接添加。

其实这个方法和方法一是一样的,只是修改的文件不同罢了。

方法三:使用遍历文件夹的方法

这个方法我研究了好久,起初是看到恋羽的日志上的内容,但不知道是代码有问题还是我把代码放错了位置,一直起不到作用,最后又修改了一下,代码如下:

//使用遍历文件夹的方法添加表情
if (!isset($wpsmiliestrans)){
    $wpsmiliestrans = array();
    $s_path="res/smilies/"; //表情的路径,改成你自己的路径
    $s_filedata=glob("$s_path*.gif"); //这里只针对了gif文件
    foreach($s_filedata as $s_id){
        $s_name=str_replace("$s_path","",$s_id); //文件名
        $s_tage=str_replace(".gif","",$s_name);  //标志
        $wpsmiliestrans[":".$s_tage.":"] = $s_name;
    }
}

这里需要把路径改成自己表情文件夹的路径,另外,如果你有除了gif格式的图片外还有别的如jpg格式的图片,可以改成

$s_filedata=glob("$s_path{*.gif,*.jpg}");

这段代码的意思是遍历表情文件夹里面的所有gif格式的文件,并把这些文件加入到数组wpsmiliestrans中去,如果你的文件命名方法不同请自行修改“文件名”和“标志”行上的代码。

第三步:添加表情到评论

添加筛选器和表情定义只是为了能让表情正常显示,接下来还需要把表情添加到评论页。

找到主题文件夹下的“comments.php”文件,在其中搜索“textarea”,这个“textarea”指的是评论框,可以找找附近是否有类似于“<?php include(TEMPLATEPATH . '/includes/smiley.php'); ?>”这句话,如果有就可以直接打开这个“'/includes/smiley.php'”文件,如果没有可以自己在需要的位置添加这么一句,另外再在对应的位置建立一个smiley.php文件。

打开smiley.php,并且把以下代码粘贴进去:

<script type="text/javascript">
/* <![CDATA[ */
    function grin(tag) {
        var myField;
        tag = ' ' + tag + ' ';
        if (document.getElementById('comment') &amp;&amp; document.getElementById('comment').type == 'textarea') {
            myField = document.getElementById('comment');
        } else {
            return false;
        }
        if (document.selection) {
            myField.focus();
            sel = document.selection.createRange();
            sel.text = tag;
            myField.focus();
        }
        else if (myField.selectionStart || myField.selectionStart == '0') {
            var startPos = myField.selectionStart;
            var endPos = myField.selectionEnd;
            var cursorPos = endPos;
            myField.value = myField.value.substring(0, startPos)
                          + tag
                          + myField.value.substring(endPos, myField.value.length);
            cursorPos += tag.length;
            myField.focus();
            myField.selectionStart = cursorPos;
            myField.selectionEnd = cursorPos;
        }
        else {
            myField.value += tag;
            myField.focus();
        }
    }
/* ]]> */
</script>

这是javescript的内容,紧接着是把每个表情对应的链接以下面的格式添加:

<a href="javascript:grin(':by:')"><img src="/res/smilies/by.gif" alt=":by:" /></a>

或者仍然使用遍历文件夹的方法:

<?php
    global $wpsmiliestrans;
    foreach($wpsmiliestrans as $s_tage => $s_name){
      echo "<a href=javascript:grin('".$s_tage."')><img src=/res/smilies/".$s_name." alt=".$s_tage."; /></a>";
    }
?>

建议:除非文件很多的情况下不要使用遍历的方法,因为这样会增加函数调用,理论上会降低代码的执行效率。使用遍历方法的好处是如果以后增加或删除部分表情的话不需要再改代码

完成

到这里如果没有什么意外的话已经可以正常运行了,试下吧!

下载打包好的表情文件及代码  

参考文档:

恋羽:自定义增加wordpress表情及修改目录

万戈:WordPress 默认的22个表情不够用?

万戈:将 WordPress 中的表情符号转化为图片

山的那边很漂亮:wordpress之插件 add_filter,add_action()机制

阅读全文 »

Jerry Bendy 发布于 03月26, 2013

WordPress插件:Widget Logic,轻松实现不同页面显示不同侧边栏

WordPress 本身的侧栏显示效果是全站的,这样显示不是非常合理的。如何让不同的页面显示不同的侧边栏,可以说是让不懂代码的童鞋们非常头痛的事。就拿童鞋们做友情链接吧,如果你不懂代码,只能全站侧边栏显示对方的链接,而对方却只在首页显示你的链接,让自己感觉心里不是很平衡。

不懂代码没关系,只要懂得使用插件,一样可以做到。Widget Logic侧边栏管理插件就很好的实现了这一功能,让你的博客不同的页面显示不同的侧边栏。

Widget Logic 侧边栏管理插件给每个 widget 一个扩展控制 Widget logic,你可以通过它根据不同页面自定义你的侧边栏内,只需要在 widget 新增的 Widget logic 选项里加入相应的标记代码,就可以轻松实现博客侧边栏的管理,实现你的个性化设置。

 

点击下载
 

Widget Logic 插件使用方法

1.下载 Widget Logic 插件,你可以在后台下载,如果你的后台不能直接下载,可以去官网下载(点击下载)。

2.安装好 Widget Logic 插件,然后再启用。

3.进入外观里的小工具管理栏,你会发现下面多了一个 Widget Logic options 的设置选择项,钩选 Use 'widget_content' filter 选项,并点击 Save 保存,如下图:

4.再查看 widget ,会发现每个里都多了一个 Widget logic 选择项。只要在 Widget logic 选项里填上相应的标记代码,就能实现不同的页面侧栏显示效果。如下图:

Widget Logic 插件设置方法

如果你只需要某个 widget 只在首页显示,只要在 widget 的 Widget logic 选项里填上 is_home() 这个标记代码就可以了。更多详细设置方法点击这里查看。

Widget Logic 常用的标记

is_home() 主页

is_single() 文章页

is_page() 页面

is_category() 文章分类页

is_tag() 文章标签页

is_archive() 归档页

is_404() 404页

is_search() 搜索结果页

 

is_home() 仅主页显示

!is_home() 除主页以外的页面显示

!is_category(5) 仅在ID非5的分类显示

is_home() || is_category('baked-goods')在主页或名称为baked-goods的分类显示

is_page('about')仅在关于页显示

 

 

文章转自:http://www.chenguangblog.com/archives/wordpress-widget-logic

有改动

阅读全文 »

Jerry Bendy 发布于 03月26, 2013

WordPress插件:Comment Info Detector/Show UserAgent,评论中显示国旗、操作系统、浏览器图标

WordPress自带的评论功能虽然很实用、易用,但是千篇一律的评论看多了也会视觉疲劳, 试想如果能在评论中显示评论者的一些信息,例如操作系统、浏览器等,岂不是很酷?顺便也可以小小地统计一下读者的状况(呵呵,目前也就只有这3个功能吧)

也许大家已经在别人的博客上见到了这个小工具的样貌,还在苦于查找是什么工具,或许能实现这个功能的插件有很多,在这里我向大家推荐一款我自己在用的插件 : Comment Info Detector.还有一款插件与其功能相同,叫Show UserAgent,设置方法基本相同。

点击下载

主要功能

1、发现并且显示评论者的国旗、浏览器和操作系统标志;

2、支持多种浏览器和操作系统;

3、返回的字符串配置成适合您主题的格式。

安装方法

1、通过上面的链接转到WP的官网下载并上传,或者直接在WP后台插件处搜索并安装;

2、安装后直接启用,OK!

3、启用后并不能起到作用,还需要手动配置一下:单击控制台左侧的“设置”-->“Comment Info Detector”;

使用方法

设置界面比较简单,就不再截图了,就随便翻译一下吧:

Country Flag Icons Base URL: 用于查找国旗的目录,指向存放国旗图标的文件夹(默认即可);

Restore Default URL: 还原成默认的URL,后面几个Restore按钮就不说了,还原默认;

Country Flag Template: 国旗模板,主要是定义图标的文件名及路径、图片标题和注释的格式;

Web Browser and OS Icons Base URL:和第一个国旗的目录一样,这个是浏览器和操作系统图标存储的路径;

Web Browser and OS Template:与Country Flag Tempate相同,是浏览器和操作系统的格式;

Display Country Flags Automatically:是否显示国旗,看个人需要吧,如果阅读者都是中国人的话可以不用显示(明显都是中国嘛,呵呵);

Display Web Browsers and OS Automatically:同上,这个是问你是否要显示浏览器和操作系统图标(这个是我们安装此插件的目的,自然不用说),选Yes就行了。

最后不要忘记单击下面的Save Changes保存所有的设置。

最下面的Uinstall按钮是卸除插件用的。

 

此时插件已经可以使用了,去看看你的评论有什么变化吧^_^

(另外可以通过修改插件目录下的comment-info-detector.css来改变显示的方式,因本人对CSS不太了解就不班门弄斧了,有兴趣的可以试试)

 

阅读全文 »