<?php
/*
Plugin Name: My First Plugin
Plugin URI: https://example.com/my-first-plugin
Description: This is my first WordPress plugin.
Version: 1.0
Author: Your Name
Author URI: https://example.com
License: GPL2
*/
4.3 插件的基本功能
添加一些基本功能,如在 WordPress 后台显示一个简单的信息:
function my_first_plugin_admin_notice() {
echo '<div class="notice notice-success is-dismissible">
<p>My First Plugin is activated!</p>
</div>';
}
add_action('admin_notices', 'my_first_plugin_admin_notice');
// 动作钩子
add_action('wp_footer', 'my_first_plugin_footer_message');
function my_first_plugin_footer_message() {
echo '<p>Thank you for visiting my website!</p>';
}
// 过滤器钩子
add_filter('the_content', 'my_first_plugin_content_filter');
function my_first_plugin_content_filter($content) {
return $content . '<p>Custom content added by My First Plugin.</p>';
}
class My_First_Plugin {
public function __construct() {
add_action('init', array($this, 'init'));
}
public function init() {
// 初始化代码
}
public function register_post_type() {
$args = array(
'public' => true,
'label' => 'Custom Post',
);
register_post_type('custom_post', $args);
}
}
$my_first_plugin = new My_First_Plugin();
17.2 使用命名空间
使用命名空间可以避免类名和函数名冲突:
namespace MyFirstPlugin;
class Main {
public function __construct() {
add_action('init', array($this, 'init'));
}
public function init() {
// 初始化代码
}
public function register_post_type() {
$args = array(
'public' => true,
'label' => 'Custom Post',
);
register_post_type('custom_post', $args);
}
}
$main = new Main();
function my_first_plugin_form_handler() {
if (!isset($_POST['my_first_plugin_nonce']) || !wp_verify_nonce($_POST['my_first_plugin_nonce'], 'my_first_plugin_form_nonce')) {
wp_die(__('Nonce verification failed', 'my-first-plugin'));
}
if (!current_user_can('manage_options')) {
wp_die(__('You do not have sufficient permissions to access this page.', 'my-first-plugin'));
}
$name = sanitize_text_field($_POST['name']);
// 处理表单数据,例如保存到数据库
wp_redirect(admin_url('options-general.php?page=my-first-plugin&message=success'));
exit;
}
add_action('admin_post_my_first_plugin_form_action', 'my_first_plugin_form_handler');
32. 使用 AJAX
32.1 注册 AJAX 动作
function my_first_plugin_ajax_handler() {
check_ajax_referer('my_first_plugin_nonce', 'security');
if (!current_user_can('manage_options')) {
wp_send_json_error(__('You do not have sufficient permissions to access this page.', 'my-first-plugin'));
}
$response = array('message' => __('Hello, World!', 'my-first-plugin'));
wp_send_json_success($response);
}
add_action('wp_ajax_my_first_plugin_action', 'my_first_plugin_ajax_handler');
function my_first_plugin_create_db_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'my_first_plugin_table';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
name tinytext NOT NULL,
value text NOT NULL,
PRIMARY KEY (id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
register_activation_hook(__FILE__, 'my_first_plugin_create_db_table');
global $wpdb;
$results = $wpdb->get_results($wpdb->prepare("SELECT * FROM $wpdb->posts WHERE post_status = %s", 'publish'));
48. 高级插件架构
48.1 使用面向对象编程(OOP)
通过面向对象编程(OOP),可以使插件的代码更加模块化、可维护和可扩展。
创建基础类: 创建一个基础类来管理插件的初始化和加载: class MyFirstPlugin { protected static $instance = null;public static function get_instance() { if (null === self::$instance) { self::$instance = new self(); } return self::$instance; } private function __construct() { $this->setup_hooks(); } private function setup_hooks() { add_action('init', array($this, 'init')); } public function init() { // 初始化代码 }} MyFirstPlugin::get_instance();
模块化插件功能: 将插件的不同功能模块化,以便更好地管理和扩展: class MyFirstPlugin_Admin { public function __construct() { add_action('admin_menu', array($this, 'add_admin_menu')); }public function add_admin_menu() { add_menu_page('My First Plugin', 'My First Plugin', 'manage_options', 'my-first-plugin', array($this, 'admin_page')); } public function admin_page() { echo '<h1>My First Plugin Settings</h1>'; }} if (is_admin()) { new MyFirstPlugin_Admin(); }
48.2 使用依赖注入(DI)
依赖注入(DI)是一种设计模式,它可以使类的依赖更显式,并且更容易进行单元测试。
创建依赖注入容器: 使用一个简单的 DI 容器来管理类的实例: class DIContainer { protected $instances = array();public function set($name, $instance) { $this->instances[$name] = $instance; } public function get($name) { return $this->instances[$name]; }} $container = new DIContainer();
使用 DI 容器: 注册和使用依赖: $container->set('admin', new MyFirstPlugin_Admin()); $admin = $container->get('admin');
49. REST API
49.1 创建自定义 REST API 端点
WordPress 提供了一个内置的 REST API,可以用来创建自定义端点。
注册自定义端点: 使用 register_rest_route 函数注册一个自定义 REST API 端点: function my_first_plugin_register_api_routes() { register_rest_route('my-first-plugin/v1', '/data', array( 'methods' => 'GET', 'callback' => 'my_first_plugin_get_data', )); } add_action('rest_api_init', 'my_first_plugin_register_api_routes'); function my_first_plugin_get_data($request) { return new WP_REST_Response(array('data' => 'Hello, World!'), 200); }
学习 WordPress 插件开发是一个非常有益且实用的技能,可以帮助你扩展和定制 WordPress 网站的功能。以下是一个详细的指南,帮助你从零开始学习 WordPress 插件开发。
1. 基础知识准备
在开始插件开发之前,你需要具备一些基本知识:
2. 设置开发环境
为插件开发设置一个合适的开发环境:
3. 了解 WordPress 插件结构
一个简单的 WordPress 插件通常包含以下文件和文件夹:
plugin-name.php
,包含插件的主要功能代码。4. 创建第一个插件
下面是创建一个简单插件的步骤:
4.1 创建插件目录和主文件
在
wp-content/plugins
目录下创建一个新文件夹,例如my-first-plugin
。在该文件夹中创建一个 PHP 文件,例如my-first-plugin.php
。4.2 插件头部信息
在
my-first-plugin.php
文件中添加插件的头部信息:4.3 插件的基本功能
添加一些基本功能,如在 WordPress 后台显示一个简单的信息:
5. 学习 WordPress 钩子(Hooks)
WordPress 插件开发的核心是钩子(Hooks),它包括动作钩子(Action Hooks)和过滤器钩子(Filter Hooks)。通过钩子,你可以在特定的时间点执行代码:
例子:
6. 学习 WordPress 插件 API
WordPress 提供了丰富的 API 供插件开发者使用:
7. 学习插件国际化和本地化
为了使你的插件可以被翻译成不同的语言,了解如何国际化和本地化插件是很重要的:
8. 探索插件开发资源
9. 配置插件设置页面
为插件添加一个设置页面是常见的需求。以下是如何使用 Settings API 创建一个简单的插件设置页面的步骤:
9.1 添加菜单项
首先,需要在 WordPress 管理菜单中添加一个新的菜单项:
9.2 创建设置页面
在回调函数
my_first_plugin_settings_page
中定义设置页面的内容:9.3 注册设置
使用 Settings API 注册插件设置:
10. 创建短代码
短代码允许用户在文章和页面中插入自定义内容。以下是如何创建一个简单的短代码:
11. 创建小工具
小工具可以在 WordPress 侧边栏等小工具区域显示内容。以下是如何创建一个简单的小工具:
“`php
class My_First_Plugin_Widget extends WP_Widget {
function construct() { parent::_construct( ‘my_first_plugin_widget’, // ID (‘My First Plugin Widget’, ‘text_domain’), // 名称
array(‘description’ => _(‘A simple widget’, ‘text_domain’)) // 描述
);
}
11. 创建小工具(续)
11.1 完成小工具的表单和更新方法
在上面的代码基础上,继续完成小工具的表单和更新方法:
12. 使用 WordPress REST API
WordPress REST API 允许你创建和访问自定义端点,从而使你的插件能够与外部应用程序进行通信。
12.1 创建自定义 REST 端点
以下是如何创建一个简单的自定义 REST 端点:
13. 安全性和最佳实践
确保你的插件是安全的,并遵循最佳实践:
13.1 数据验证和清理
在处理用户输入时,确保对数据进行验证和清理:
13.2 使用非ces (Nonces) 进行安全验证
在处理表单提交时,使用非ces 来防止跨站请求伪造 (CSRF) 攻击:
13.3 避免直接文件访问
在插件的每个文件顶部添加以下代码,防止直接访问:
14. 插件国际化和本地化(续)
确保你的插件可以被翻译成不同的语言:
14.1 创建语言文件
在插件目录下创建一个
languages
文件夹,并使用.pot
文件保存插件的翻译字符串。例如,创建一个my-first-plugin.pot
文件。14.2 加载语言文件
在插件初始化时加载语言文件:
15. 发布和分发插件
当你完成插件开发后,可以考虑将插件发布到 WordPress 插件目录中。
15.1 准备插件
确保你的插件包含以下文件:
.pot
文件和翻译文件。15.2 创建 README 文件
使用 Markdown 编写 README 文件,并确保它包含以下部分:
15.3 提交插件
访问 WordPress 插件提交页面 并按照指南提交你的插件。一旦审核通过,你的插件将出现在 WordPress 插件目录中。
16. 进一步学习资源
要深入学习 WordPress 插件开发,以下资源非常有用:
16.1 官方文档
16.2 在线课程和教程
16.3 开发者社区
16.4 博客和文章
17. 高级插件开发技巧
17.1 面向对象编程 (OOP)
使用面向对象编程风格可以使你的插件代码更具可维护性和可扩展性。以下是一个简单的 OOP 插件示例:
17.2 使用命名空间
使用命名空间可以避免类名和函数名冲突:
17.3 自动加载
使用自动加载器可以简化类文件的加载:
17.4 单例模式
使用单例模式确保插件的主类只实例化一次:
18. 性能优化
确保你的插件不会对网站性能产生负面影响:
18.1 使用缓存
利用 WordPress 内置的缓存功能:
19. 数据库操作
19.1 创建自定义数据库表
有时候,插件需要创建自定义数据库表来存储特定的数据。以下是创建自定义表的示例:
19.2 插入数据
19.3 获取数据
20. AJAX 操作
使用 AJAX 可以在不刷新页面的情况下与服务器进行交互。
20.1 在前端调用 AJAX
20.2 在后端处理 AJAX 请求
21. 使用自定义钩子和过滤器
创建自定义钩子和过滤器,使其他开发者可以扩展你的插件功能。
21.1 创建自定义动作钩子
21.2 创建自定义过滤器
22. 使用第三方库
有时,你可能需要在插件中使用第三方库。你可以通过 Composer 来管理依赖关系。
22.1 安装 Composer
确保在你的开发环境中安装了 Composer。
22.2 创建
composer.json
文件在插件根目录下创建一个
composer.json
文件:22.3 安装依赖
在终端中运行以下命令:
22.4 在插件中加载 Composer 自动加载器
在插件的主文件中添加以下代码:
23. 测试和调试(续)
23.1 使用 WP_DEBUG
在
wp-config.php
文件中启用调试模式:此设置会将错误记录到
wp-content/debug.log
文件中,而不是直接显示在页面上。23.2 使用 PHPStorm 和 Xdebug 进行调试
php.ini
文件:zend_extension="path/to/xdebug.so" xdebug.remote_enable=1 xdebug.remote_host=127.0.0.1 xdebug.remote_port=9000 xdebug.remote_handler=dbgp
24. 国际化与本地化
24.1 准备插件以进行翻译
使用
__()
和_e()
函数准备你的插件代码:24.2 创建 POT 文件
使用
xgettext
或 Poedit 等工具生成 POT 文件:24.3 加载翻译文件
在插件初始化时加载翻译文件:
25. 安全性
25.1 数据验证和清理
确保所有用户输入的数据都经过验证和清理:
25.2 权限检查
在处理敏感操作之前检查用户权限:
25.3 防止 SQL 注入
使用
$wpdb->prepare()
函数来防止 SQL 注入:26. 创建设置页面
26.1 添加设置页面
26.2 创建设置页面内容
26.3 注册设置
“`php
function my_first_plugin_settings_init() {
register_setting(‘my_first_plugin_options’, ‘my_first_plugin_options’);
26. 创建设置页面(续)
26.3 注册设置(续)
27. 创建自定义小工具
27.1 定义小工具类
27.2 注册小工具
28. 使用 REST API
28.1 创建自定义 REST API 路由
28.2 使用 REST API
在前端使用 JavaScript 访问自定义 REST API 路由:
29. 自定义短代码
29.1 注册短代码
29.2 使用短代码
在文章或页面中使用短代码:
30. 单元测试(续)
30.1 设置 PHPUnit(续)
在
tests
目录中创建bootstrap.php
文件以初始化测试环境:在
tests
目录中创建test-sample.php
文件以编写第一个测试:30.2 运行测试
使用以下命令运行 PHPUnit 测试:
31. 使用自定义表单
31.1 创建自定义表单
在插件中使用 HTML 和 PHP 创建自定义表单:
31.2 处理表单提交
在插件中处理表单提交:
32. 使用 AJAX
32.1 注册 AJAX 动作
32.2 在前端使用 AJAX
在前端脚本中使用 AJAX 进行请求:
在插件中注册和本地化脚本:
33. 创建自定义数据库表
33.1 激活时创建表
在插件激活时创建自定义数据库表:
33.2 插入数据
在插件中插入数据到自定义表:
33.3 查询数据
从自定义表中查询数据:
34. 本地化
34.1 加载插件的翻译文件
在插件中加载翻译文件:
34.2 创建翻译文件
使用 Poedit 或其他翻译工具创建
.po
和.mo
文件,并将它们放在languages
目录中。例如,创建my-first-plugin-zh_CN.po
和my-first-plugin-zh_CN.mo
文件。35. 安全性
35.1 数据验证和清理
在处理用户输入时,确保数据的验证和清理:
35.2 非可信数据的输出
在输出非可信数据时,使用适当的 WordPress 函数进行转义:
35.3 使用非ces
使用 Nonces 来验证请求的合法性:
36. 优化性能
36.1 减少数据库查询
缓存频繁使用的数据以减少数据库查询次数:
36.2 异步处理
使用异步方式处理耗时操作:
37. 与第三方服务集成
37.1 使用 API 密钥
存储和使用 API 密钥:
37.2 处理 API 响应
处理第三方 API 的响应:
38. 版本控制
38.1 使用 Git
使用 Git 进行版本控制是现代开发的最佳实践。以下是一些基本步骤来初始化和使用 Git:
git init
.gitignore
文件: 创建一个.gitignore
文件,以忽略不需要版本控制的文件和目录。例如:/vendor/ /node_modules/ /wp-content/uploads/ .env
git add . git commit -m "Initial commit"
git remote add origin <remote-repository-URL> git push -u origin master
38.2 使用 GitHub Actions 进行 CI/CD
GitHub Actions 可以帮助你自动化测试、构建和部署插件。
.github/workflows/main.yml
文件:name: CI on: push: branches: - master pull_request: branches: - master jobs: build: runs-on: ubuntu-lateststeps: - name: Checkout code uses: actions/checkout@v2 - name: Set up PHP uses: shivammathur/setup-php@v2 with: php-version: '7.4' - name: Install dependencies run: composer install - name: Run tests run: vendor/bin/phpunit</code></pre></li>
39. 钩子和过滤器
39.1 自定义钩子
创建自定义钩子,让其他开发者可以扩展你的插件功能:
使用自定义钩子:
39.2 自定义过滤器
创建自定义过滤器以便于修改数据:
使用自定义过滤器:
40. REST API
40.1 注册自定义 REST API 路由
使用 WordPress REST API 注册自定义路由:
40.2 处理 REST API 请求
处理 REST API 请求并返回响应:
41. Gutenberg 块
41.1 创建自定义 Gutenberg 块
继续创建和注册自定义 Gutenberg 块。
src
目录中继续创建index.js
文件的内容:import { registerBlockType } from '@wordpress/blocks'; import { useBlockProps, RichText } from '@wordpress/block-editor'; registerBlockType('my-first-plugin/my-custom-block', { edit({ attributes, setAttributes }) { const blockProps = useBlockProps(); return ( <div {...blockProps}> <RichText tagName="p" onChange={(content) => setAttributes({ content })} value={attributes.content} placeholder="Write your content here..." /> </div> ); }, save({ attributes }) { const blockProps = useBlockProps.save(); return ( <div {...blockProps}> <RichText.Content tagName="p" value={attributes.content} /> </div> ); }, attributes: { content: { type: 'string', source: 'html', selector: 'p' } } });
package.json
以添加构建脚本:{ "scripts": { "build": "wp-scripts build", "start": "wp-scripts start" }, "devDependencies": { "@wordpress/scripts": "^23.0.0" } }
然后运行构建命令:npm run build
function my_first_plugin_register_block() { wp_register_script( 'my-first-plugin-editor-script', plugins_url('build/index.js', __FILE__), array('wp-blocks', 'wp-element', 'wp-editor') );register_block_type('my-first-plugin/my-custom-block', array( 'editor_script' => 'my-first-plugin-editor-script', ));} add_action('init', 'my_first_plugin_register_block');
42. 使用 WP-CLI
WP-CLI 是一个强大的命令行工具,可以用于管理 WordPress 安装,包括插件的开发和调试。
42.1 创建自定义 WP-CLI 命令
if (defined('WP_CLI') && WP_CLI) { WP_CLI::add_command('my_first_plugin', 'My_First_Plugin_CLI_Command'); } class My_First_Plugin_CLI_Command { public function hello($args, $assoc_args) { WP_CLI::success('Hello, World!'); } }
wp my_first_plugin hello
43. 单元测试
43.1 使用 PHPUnit 进行单元测试
composer require --dev phpunit/phpunit
phpunit.xml.dist
文件以配置测试环境:<phpunit bootstrap="tests/bootstrap.php"> <testsuites> <testsuite name="My First Plugin Test Suite"> <directory>tests</directory> </testsuite> </testsuites> </phpunit>
tests
目录中创建测试文件,例如test-sample.php
:class SampleTest extends WP_UnitTestCase { public function test_sample() { $this->assertTrue(true); } }
vendor/bin/phpunit
44. 代码质量和静态分析
44.1 使用 PHPCS 检查代码规范
phpcs.xml.dist
文件,以定义代码检查规则:<?xml version="1.0"?> <ruleset name="My First Plugin"> <description>WordPress Plugin Coding Standards</description> <rule ref="WordPress-Core"/> <rule ref="WordPress-Docs"/> <rule ref="WordPress-Extra"/> <file>./</file> <exclude-pattern>*/vendor/*</exclude-pattern> </ruleset>
vendor/bin/phpcs
44.2 使用 PHPStan 进行静态分析
composer require --dev phpstan/phpstan
phpstan.neon
文件:includes: - vendor/phpstan/phpstan/conf/bleedingEdge.neon parameters: level: max paths: - %currentWorkingDirectory%/src excludePaths: - %currentWorkingDirectory%/vendor
vendor/bin/phpstan analyse
45. 安全性
45.1 数据验证和清理
为了防止安全漏洞,必须对所有用户输入进行验证和清理。
sanitize_*
系列函数来清理输入数据:$email = sanitize_email($_POST['email']); $url = esc_url($_POST['url']);
wp_verify_nonce
和check_admin_referer
来验证非ces:if (!wp_verify_nonce($_POST['_wpnonce'], 'my_action')) { die('Security check failed'); }
45.2 SQL 注入防护
使用
prepare
方法来防止 SQL 注入:46. 国际化和本地化
46.1 准备插件进行翻译
function my_first_plugin_load_textdomain() { load_plugin_textdomain('my-first-plugin', false, dirname(plugin_basename(__FILE__)) . '/languages'); } add_action('plugins_loaded', 'my_first_plugin_load_textdomain');
__
,_e
,_n
等函数进行国际化:$message = __('Hello, World!', 'my-first-plugin'); _e('Welcome to my plugin!', 'my-first-plugin');
wp i18n
工具来生成 POT 文件:npx wp i18n make-pot . languages/my-first-plugin.pot
47. 优化性能
47.1 缓存
$data = get_transient('my_first_plugin_data'); if ($data === false) { $data = costly_database_query(); set_transient('my_first_plugin_data', $data, 12 * HOUR_IN_SECONDS); }
wp_cache_set
和wp_cache_get
进行对象缓存:wp_cache_set('my_cache_key', $data); $cached_data = wp_cache_get('my_cache_key');
47.2 优化数据库查询
确保数据库查询高效,避免不必要的查询和数据加载:
48. 高级插件架构
48.1 使用面向对象编程(OOP)
通过面向对象编程(OOP),可以使插件的代码更加模块化、可维护和可扩展。
class MyFirstPlugin { protected static $instance = null;public static function get_instance() { if (null === self::$instance) { self::$instance = new self(); } return self::$instance; } private function __construct() { $this->setup_hooks(); } private function setup_hooks() { add_action('init', array($this, 'init')); } public function init() { // 初始化代码 }} MyFirstPlugin::get_instance();
class MyFirstPlugin_Admin { public function __construct() { add_action('admin_menu', array($this, 'add_admin_menu')); }public function add_admin_menu() { add_menu_page('My First Plugin', 'My First Plugin', 'manage_options', 'my-first-plugin', array($this, 'admin_page')); } public function admin_page() { echo '<h1>My First Plugin Settings</h1>'; }} if (is_admin()) { new MyFirstPlugin_Admin(); }
48.2 使用依赖注入(DI)
依赖注入(DI)是一种设计模式,它可以使类的依赖更显式,并且更容易进行单元测试。
class DIContainer { protected $instances = array();public function set($name, $instance) { $this->instances[$name] = $instance; } public function get($name) { return $this->instances[$name]; }} $container = new DIContainer();
$container->set('admin', new MyFirstPlugin_Admin()); $admin = $container->get('admin');
49. REST API
49.1 创建自定义 REST API 端点
WordPress 提供了一个内置的 REST API,可以用来创建自定义端点。
register_rest_route
函数注册一个自定义 REST API 端点:function my_first_plugin_register_api_routes() { register_rest_route('my-first-plugin/v1', '/data', array( 'methods' => 'GET', 'callback' => 'my_first_plugin_get_data', )); } add_action('rest_api_init', 'my_first_plugin_register_api_routes'); function my_first_plugin_get_data($request) { return new WP_REST_Response(array('data' => 'Hello, World!'), 200); }
http://your-site/wp-json/my-first-plugin/v1/data
以测试自定义端点。50. 多站点支持
50.1 多站点激活和停用
50.2 处理多站点特定功能
get_site_option
和update_site_option
来存储和检索全局设置:function my_first_plugin_get_global_setting($key) { return get_site_option($key); } function my_first_plugin_set_global_setting($key, $value) { update_site_option($key, $value); }
switch_to_blog
和restore_current_blog
函数在不同站点之间切换,以同步数据:function my_first_plugin_sync_data_across_sites($data) { global $wpdb; $blog_ids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs"); foreach ($blog_ids as $blog_id) { switch_to_blog($blog_id); update_option('my_first_plugin_data', $data); restore_current_blog(); } }
51. 单元测试
51.1 使用 PHPUnit 进行测试
composer require --dev phpunit/phpunit
phpunit.xml.dist
文件:<phpunit bootstrap="tests/bootstrap.php"> <testsuites> <testsuite name="My Plugin Test Suite"> <directory>tests/</directory> </testsuite> </testsuites> </phpunit>
tests/test-sample.php
:class SampleTest extends WP_UnitTestCase { public function test_sample() { $this->assertTrue(true); } }
vendor/bin/phpunit
52. 钩子和过滤器
52.1 创建自定义钩子
do_action('my_first_plugin_custom_action', $arg1, $arg2);
$value = apply_filters('my_first_plugin_custom_filter', $value, $arg1, $arg2);
52.2 使用钩子和过滤器
add_action
函数来挂载自定义动作钩子:add_action('my_first_plugin_custom_action', 'my_custom_action_function', 10, 2); function my_custom_action_function($arg1, $arg2) { // 自定义动作处理逻辑 }
add_filter
函数来挂载自定义过滤器钩子:add_filter('my_first_plugin_custom_filter', 'my_custom_filter_function', 10, 3); function my_custom_filter_function($value, $arg1, $arg2) { // 自定义过滤逻辑 return $value; }