wordpress插件开发从创建一个新的菜单开始

创建插件的目的

1.我们为什么要创建一个插件?

  • IT界有一个知名的论调叫做不要造重复的轮子,如果有可能的话,你应该尽可能的从现有的网络资源上选择一个已有的插件来使用,而不是重新创造一个。它耗费的精力很可能是没有相应价值的。所以在创建一个插件之前,你应该先去wordpress的插件仓库搜索关键词,看一下是不是已经有了满足需求的插件。

2.你希望你的插件具有什么功能?

  • 在开始开发之前,想好这个问题,能帮你省去很多麻烦。比如,你的插件是提供给前台页面使用的还是在后台页面使用的?是后台的独立模块么?它应该有哪几个页面,页面上应该有哪些功能?怎么去设计这个页面的布局?这些问题,都需要有一个清晰的规划。

前置工作

尽管我们在梳理开发流程中已经提到了如何创建一个插件,但是我们还是要再说一次,以防有些读者没有看到。

1.打开WordPress安装目录下的wp-content目录。

2.打开plugins目录。

3.创建一个新目录并在插件后命名(例如plugin-name)。

4.打开新插件的目录。

5.创建一个新的PHP文件(例如,在插件后命名此文件也很好plugin-name.php)。

开始开发

就像下面的示例一样,你必须在你创建的主插件文件的开头加上一段doc注释来告诉wordpress这是个插件,当然也可以加上作者,邮箱等信息,下面只是简单示例,详细可以在我们梳理流程的那边博文/或者官网中看到。

1
2
3
4
5
6
7
8
9
//wp-content/plugin-name/plugin-name.php
<?php
/**
* Plugin Name: 插件名称
*/
function do_something_else()
{
//.....你的代码
}

还记得我们在第一篇梳理中提到的三个基础插件钩子么?

1.register_activation_hook //启用插件时触发的钩子

2.register_deactivation_hook//禁用插件时触发的钩子

3.register_uninstall_hook//删除插件时触发的钩子

我们可以通过这三个钩子函数来做一下一些前置/后置的处理,比如说插件被启用时创建一个自定义数据表,初始化一些配置,禁用时恢复初始化设置,删除时删除自定义的数据表。

这里我们先不展开来讲我们在讲OptionApi的时候再讲这个。

准备工作都已经做好了,我们现在开始正式的开发。我们假设说我们要做的是一个额外的内容管理插件。那我们现在想要在后台创建一个定制内容管理菜单,该怎么做呢?

wordpress向我们提供了一个add_menu_page的函数:

1
2
3
4
5
6
7
8
9
10
11
12
/**
//我们先看一下函数的参数
add_menu_page(
string $page_title, //页面标题
string $menu_title, //菜单名称
string $capability, //权限级别
string $menu_slug, //菜单标识 唯一
callable $function = '', //回调函数 其实就是点击这个菜单后触发的函数 我们可以返回一个页面
string $icon_url = '', //图标,可以为空
int $position = null //位置 决定了菜单应该插入在第几个
);
**/

那我们应该怎么使用呢?

for-example :

你的wp-content/plugin-name/plugin-name.php文件,看起来应该像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?php
/*
Plugin Name: 定制内容管理
Plugin URI: http://ergou.fun
Description: 内容管理模块(自定义内容非posts)
Version: 1.0
Author: ergou
Author URI: http://ergou.fun

Copyright 2019 ergou (email : 531432012@qq.com)

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

/** 第1步:创建自定义菜单的函数**/
function ergou_cms_plugin_menu()
{
add_menu_page('定制内容管理', '内容管理', 'manage_options', 'ergou-cms-manager', 'ergou_cms_plugin_options', '', 7);

}

/** 第2步:将函数注册到钩子中 */
add_action('admin_menu', 'ergou_cms_plugin_menu');

/** 第3步:定义选项被点击时打开的页面 */
function ergou_cms_plugin_options()
{
if (!current_user_can('manage_options')) {
wp_die(__('You do not have sufficient permissions to access this page.'));
}
//include_once(plugin_dir_path(__FILE__) . 'detail/index.php');

//也可以直接返回HTML,不过我建议是额外放一个文件,这样以后维护起来好处理

//你可以直接 echo "hello world"
echo "Hello World";
wp_die();
}

我们现在回到我们的后台管理页面点击插件管理你会发现多了一个,定制内容管理的菜单,点击启用。菜单就会增加在左侧顶级菜单里。点击定制内容管理菜单,页面输出了"Hello World"。至此,我们算是完成了第一步。

本篇内容就是这些。That’s all .Thank you .

wordpress插件开发流程梳理(二)插件最佳实践

开发插件的最佳实践

避免命名冲突

当您的插件对变量,函数或类使用相同的名称作为另一个插件时,会发生命名冲突。

幸运的是,您可以使用以下方法避免命名冲突。

程序性

默认情况下,所有变量,函数和类都在全局命名空间中定义,这意味着您的插件可以覆盖由另一个插件设置的变量,函数和类,反之亦然。在函数或类中定义的变量不受此影响。

前缀一切

所有变量,函数和类都应以唯一标识符为前缀。前缀可防止其他插件覆盖您的变量并意外调用您的函数和类。它也会阻止你做同样的事情。

检查现有实现

PHP提供了许多函数来验证变量,函数,类和常量的存在。如果实体存在,所有这些都将返回true。

  • 变量: isset() (包括数组,对象等)
  • 函数: function_exists()
  • 类: class_exists()
  • 常量:defined()

OOP面向对象

解决命名冲突问题的一种更简单的方法是使用类来获取插件的代码。

您仍然需要检查是否已经使用了您想要的类的名称,但其余的将由PHP处理。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
if ( !class_exists( 'WPOrg_Plugin' ) ) {
class WPOrg_Plugin
{
public static function init() {
register_setting( 'wporg_settings', 'wporg_option_foo' );
}

public static function get_foo() {
return get_option( 'wporg_option_foo' );
}
}

WPOrg_Plugin::init();
WPOrg_Plugin::get_foo();
}

目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
/plugin-name
plugin-name.php //插件主文件,必须和文件夹名保持一致
uninstall.php //卸载插件时自动运行的脚本
/languages //国际化语言包
/includes //其他功能脚本
/admin
/js
/css
/images
/public
/js
/css
/images

条件加载

将管理代码与公共代码分开是有帮助的。使用条件is_admin()。

示例:

1
2
3
4
5
<?php
if ( is_admin() ) {
// we are in admin mode
require_once( dirname( __FILE__ ) . '/admin/plugin-name-admin.php' );
}

文件结构参考

参考模板

对于您编写的每个新插件,您可能希望从样板开始,而不是从头开始。使用样板的一个优点是在您自己的插件之间保持一致。如果使用他们熟悉的样板,使用模板也可以让其他人更容易为您的代码做出贡献。

这些也可作为不同但可比较的架构的进一步示例。

注:本篇,完全是由官方文档翻译而来,描述了一个好的插件的最佳实践。该用什么样的目录结构,什么时候该做一些权限的判定,甚至Github上提供了一些可参考的模板,以防我们的代码写出来像坨屎一样。我也希望自己写出来的插件,且不说功能如何,最起码不被喷This is shit .所以你看到,我们现在花一些功夫来从头梳理,流程。真正开发流程中遇到的问题,我会在后边的时候提到。

wordpress插件开发流程梳理

1.声明一个插件

首先我们必须明白,wordpress的插件可以是单文件,也可以是多文件,css/html都不是必须的,以下举例暂且在单文件模式下

比如我们要创建一个名为 hellophp的插件,那我们就需要在wp-content/plugins目录下新建hellophp文件夹和hellophp.php文件,但是这还是不能让系统识别这个插件。插件的主文件名要和目录一致。

在wordpress中,要让系统识别一个插件,首先要做的就是,声明一个DOCBLOCK(文档块)

示例:

wp-content/plugins/hellophp/hellophp.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

<?php
/**
* Plugin Name: hellophp
* Plugin URI: https://example.com/plugins/the-basics/
* Description: Basic WordPress Plugin Header Comment
* Version: 0.0.0
* Author: WordPress.org
* Author URI: https://author.example.com/
* License: GPL2
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: wporg
* Domain Path: /languages
*/

//完整的示例是这样,但是除了Plugin Name其他都不是必须的

2.初始化插件

  • wordpress-hook

    • register_activation_hook( FILE, ‘pluginprefix_function_to_run’ ); //启用插件时的钩子
    • register_deactivation_hook( FILE, ‘pluginprefix_function_to_run’ );//停用插件时的钩子

示例:

示例摘自官方文档,启动插件钩子最常见的用途之一是当插件注册自定义帖子类型时刷新WordPress永久链接。这摆脱了令人讨厌的404错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//启用插件时的处理
function pluginprefix_setup_post_type() {
// register the "book" custom post type
register_post_type( 'book', ['public' => 'true'] );
}
add_action( 'init', 'pluginprefix_setup_post_type' );

function pluginprefix_install() {
// trigger our function that registers the custom post type
pluginprefix_setup_post_type();

// clear the permalinks after the post type has been registered
flush_rewrite_rules();
}
register_activation_hook( __FILE__, 'pluginprefix_install' );

//停用插件时的处理
function pluginprefix_deactivation() {
// unregister the post type, so the rules are no longer in memory
unregister_post_type( 'book' );
// clear the permalinks to remove our post type's rules from the database
flush_rewrite_rules();
}
register_deactivation_hook( __FILE__, 'pluginprefix_deactivation' );

如果您不熟悉注册自定义帖子类型,请不要担心 - 稍后将对此进行介绍。使用这个例子只是因为它很常见。

注:这部分看不懂也没关系,这两个钩子也并不是必须的,如果你要做一些必要的前置工作,比如说启用插件时,创建一个新的数据表,初始化一些变量之类的前置操作来保证插件的正常运行,可以使用这个钩子,如果没有这样的操作,这个钩子不用也可以。

3.插件的卸载

从站点卸载插件时,您的插件可能需要进行一些清理。

如果用户已停用插件,则会认为已卸载插件,然后单击WordPress管理中的删除链接。

卸载插件时,您需要清除插件和/或其他数据库实体(如表)的任何插件选项和/或设置。

卸载插件有两种方法:

  • 系统的钩子函数

    1
    register_uninstall_hook(__FILE__, 'pluginprefix_function_to_run');
  • 自定义卸载脚本uninstall.php

你需要在你插件的根目录创建一个uninstall.php文件

示例:

示例脚本演示了一个删除自定义表的清理工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// if uninstall.php is not called by WordPress, die
// 防止误操作直接访问该文件
if (!defined('WP_UNINSTALL_PLUGIN')) {
die;
}

$option_name = 'wporg_option';

//这两行是删除插件的一些附加配置,后边我会继续说这个
delete_option($option_name);

// for site options in Multisite
delete_site_option($option_name);

// drop a custom database table
global $wpdb;
$wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}mytable");

这是wordpress插件开发流程梳理的第一篇,就先这样,后续会继续梳理。本文的示例和描述,大部分来自官方文档。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×