在上高中时,我就一直想开发一个wordpress插件,但奈何水平有限,网上教程一大堆,却硬是一个也看不懂。

上了大学后,还专门去请教过老师,但也没有了下文…

本文,我将会从零开始,手把手教你怎么创建一个属于自己的插件。

阶段一:徒有其表

首先,你需要创建一个php文件,将名字设置为demo.php,文件的内容如下:

<?php
/*
Plugin Name: 示例插件
Description: 没有什么卵用的插件
Author: 高小调
Version: 1.0.0
Author URI: http://gaoxiaodiao.com/
*/

然后,把这个文件压缩成一个zip文件,得到一个:demo.php.zip

接下来,来到Wordpress后台页面,点击插件->安装插件->上传插件->立即安装: file

file

file

稍等片刻后,就可以在插件列表里看到出现了一个新插件: file

由于,demo.php文件里没有任何可以执行的php代码,所以即使你启用示例插件也不会产生任何的效果。

阶段二:了解action与filter

我想开发一个wordpress的插件,必然是要通过它实现某个功能,wordpress提供了两个函数add_actionadd_filter来供我们在某个特定的时间点来做一些事情。

在介绍进一步内容之前,我先来简述一下actionfilter的区别:

  • action: 在某个特定的时间点,去做特定的事情。
  • filter: 在某个特定的时间点,修改特定的内容。

那么问题来了:这个“特定的时间点”是什么时候呢?

这里有一篇官方文档,里面包含了所有actionfilter可以进行hookhookname:

接下来,我们通过使用add_action函数,来做一个简单的小练习。

阶段三: 实战之使用action

我们可以从Plugin API/Action Reference这篇文档中,可以找到一个为admin_head的hook name。

从其介绍中,我们可以了解到,admin_head会在后台页面的head标签中被调用,经常用于包含CSS或者JS。

那我们的demo.php就可以扩充为以下代码:

<?php 
/*
Plugin Name: 示例插件
Description: add_action初体验
Author: 高小调
Version: 1.0.1
Author URI: http://gaoxiaodiao.com/
*/

function add_custom_js_script_code(){
    echo "<script>alert(\"I'm in!\");</script>";
}

add_action( 'admin_head', 'add_custom_js_script_code' );

其中,add_custom_js_script_code函数功能非常简单,打印出一个script标签,执行alert("I'm in!")

add_custom_js_script_code函数什么时候执行呢?

没错,就是在后台页面的<head></head>标签里会执行add_custom_js_script_code函数,有点类似于以下逻辑:

<html>
<head>
<?php add_custom_js_script_code(); ?>
</head>
...
</html>

接下来,将demo.php压缩为demo.php.zip文件,重新上传,启用。

启用后,无论你访问哪个后台页面,都会弹出一个弹窗I'm in,并且能在源码中找到<script>alert("I'm in!");</script>

阶段四: 实战之使用filter

上述的例子,太过于偏向于Demo,可能会有读者心想:哦,那样做有什么用呢?

所以,接下来,我来以一个模拟场景举例,来示范filter的用法。

在前文开发Wordpress蜜罐(一):项目概述中,我想留下黑客入侵后的所有痕迹,其中一种实现方案就是通过Wordpress的插件来实现。蜜罐的功能之一是要:记录黑客的弱口令字典。

所以,本小节目标就是让插件实现记录登录失败的功能,做法很简单,找到登录验证的hookname,然后是否判断登录失败,登录失败后,将失败的用户名/密码记录下来。

步骤一:找hookname

我们可以从Plugin API/Filter Reference这篇文档中,可以找到一个为authenticate的hook name,它的解释是“过滤用户登录的凭证是否有效”。

步骤二:调用add_filter函数

我们在demo.php中,就可以调用add_filter函数,来对其进行Hook,其中:

  • 第一个参数,代表hook的名称。

  • 第二个参数,代表hook的优先级,0代表最高,99代表最低。

  • 第三个参数,代表hook名所对应的参数个数。

    add_filter( 'authenticate', 'gxd_login_check', 30 ,3 );
    

    注意:在这里,针对authenticatehook的优先级必须设置为21及其以上,否则会和Wordpress Core的源码里的hook冲突

步骤三:记录用户名密码

因为,Wordpress Core源码里也是通过authenticate来进行真正的登录验证的,如下所示:

// /wp-includes/default-filters.php
add_filter( 'authenticate', 'wp_authenticate_username_password',  20, 3 );
add_filter( 'authenticate', 'wp_authenticate_email_password',     20, 3 );
add_filter( 'authenticate', 'wp_authenticate_spam_check',         99    );

所以,我们可以借鉴它源码内的实现并加以改动。

function gxd_login_check($user,$username, $password){
    if ( $user instanceof WP_User ) {
        return $user;
    }
    if ( is_wp_error( $user ) ) {
        if( $username != "" && $password!= "" ){
            $ip = "";
            if( isset($_SERVER['HTTP_CLIENT_IP']) ){
                $ip = $_SERVER['HTTP_CLIENT_IP'];
            }else if( isset($_SERVER['HTTP_X_FORWARDED_FOR']) ){
                $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
            }else{
                $ip = $_SERVER['REMOTE_ADDR'];
            }
            $myfile = fopen("login_history.txt", "a+") or die("Unable to open file!");
            fwrite($myfile,"[$ip] $username --- $password\r\n");
            fclose($myfile);
        }
        return $user;
    }
}

最终效果,你可以:访问此处

更多资料

wordpress插件官方文档

启用/停用的Hook示例

卸载的Hook示例