Basics of WordPress Plugin Development
Before diving into the code, it's crucial to understand the basic concepts and structure of WordPress plugins. A WordPress plugin is essentially an additional PHP script that interacts with the core through the hook system provided by WordPress to extend or modify the functionality of the website. It can be a single file or a complete directory containing multiple files, CSS stylesheets, and JavaScript scripts.
The first task of plugin development is to create a main file that complies with the standards. Usually, this main file is named after the plugin, for example,my-custom-plugin.phpAt the beginning of the file, it must include a standard plugin information annotation block. This annotation is not only used to describe your plugin to WordPress, but will also be displayed on the plugin management page in the backend.
/**
* Plugin Name: 我的自定义功能扩展
* Plugin URI: https://example.com/my-custom-plugin
* Description: 这是一个用于演示的WordPress插件,用于添加自定义功能。
* Version: 1.0.0
* Author: 开发者名称
* Author URI: https://example.com
* License: GPL v2 or later
* Text Domain: my-custom-plugin
*/ In the annotations,Plugin NameThis is a mandatory field. All other fields are optional, but it is recommended to fill them out. After creating this file, please put it in the specified location./wp-content/plugins/An independent folder under the directory (for example, )my-custom-pluginAfter uploading the plugin to the WordPress server, you can view and activate it on the “Plugins” page in the WordPress backend.
Recommended Reading From Beginner to Practitioner: A Comprehensive Guide and Advanced Techniques for WordPress Plugin Development。
The core operating mechanism of WordPress plugins is based on “hooks”. There are two types of hooks: action hooks.(Action Hooks)and filter hooks(Filter Hooks)Action hooks allow you to execute custom code at specific moments, such as when the page header is loaded or when an article is published.add_action()The function mounts your function to the action hook.
Filter hooks allow you to modify the data generated during the process. For example, the content of an article will go through a series of filters before it is displayed. To use this feature, you need to install the appropriate plugin.add_filter()Functions can modify this data.
Internationalization and localization are an indispensable part of professional plugins. By using them,__( ‘文本’, ‘text-domain’ )Or_e( ‘文本’, ‘text-domain’ )The function wraps all user-visible strings and, when combined with the loading of text fields, enables the plugin to support multiple languages.Text DomainIt must be consistent with the information defined in the plugin header, which is usually the slug version of the plugin directory name or the main file name.
Create your first functional plug-in
Let's start by creating a simple plugin that will add a custom management column to the website article list, which will display the word count statistics of the articles. This example covers the basic process of plugin creation, hook usage, and safe output.
Firstly, in your/wp-content/plugins/Create a new folder under the directory and name itmy-first-extensionIn this folder, create the main filemy-first-extension.phpAnd add the plug-in header information described in the previous section.
Recommended Reading Introduction to WordPress Plugin Development: Build Your Customized Functional Modules from Scratch。
Next, we need to add a new column to the article management list. This involves two action hooks:manage_posts_columnsandmanage_posts_custom_columnThe former is used to define the header of the new column, and the latter is used to fill in the content of each row of the column.
// 为文章列表添加“字数统计”列
function mfe_add_word_count_column( $columns ) {
$columns['word_count'] = __( '字数统计', 'my-first-extension' );
return $columns;
}
add_filter( 'manage_posts_columns', 'mfe_add_word_count_column' );
// 填充“字数统计”列的内容
function mfe_display_word_count_column( $column, $post_id ) {
if ( $column === 'word_count' ) {
$post_content = get_post_field( 'post_content', $post_id );
$word_count = str_word_count( strip_tags( $post_content ) );
echo esc_html( $word_count );
}
}
add_action( 'manage_posts_custom_column', 'mfe_display_word_count_column', 10, 2 ); In this piece of code,mfe_add_word_count_columnThe function receives the existing column array and adds a new one.word_countPress the Enter key and return the modified array.add_filterConnect it tomanage_posts_columnsOn the filter.mfe_display_word_count_columnThe function first checks whether the column currently being processed is the “word_count” we added, and then retrieves the article content and uses it.strip_tags()Remove the HTML tags and then use <str_word_count()Calculate the number of words (or characters, in the case of Chinese), and finally use it.esc_html()Output after performing safe escaping.
This simple plugin already has basic functionality, but a more professional plugin should also consider performing some actions when the plugin is activated and deactivated. For example, we can create custom database tables or clean up temporary options. This can be achieved by registering activation and deactivation hooks.
// 插件激活时执行的操作
function mfe_plugin_activation() {
// 例如:添加一个版本号选项,用于后续升级判断
if ( ! get_option( 'mfe_plugin_version' ) ) {
add_option( 'mfe_plugin_version', '1.0.0' );
}
// 触发一个自定义动作,供其他开发者扩展
do_action( 'mfe_plugin_activated' );
}
register_activation_hook( __FILE__, 'mfe_plugin_activation' );
// 插件停用时执行的操作
function mfe_plugin_deactivation() {
// 例如:清除计划任务或临时数据
// 注意:通常不在停用时删除用户数据(如表)
}
register_deactivation_hook( __FILE__, 'mfe_plugin_deactivation' ); Please note that,register_activation_hookandregister_deactivation_hookYou need the full path to the main file.FILEThe logic of activating, deactivating, and uninstalling (uninstallation occurs when the user deletes the plug-in) should be handled separately, with the constant serving as the first parameter.
Implement the plugin settings page
A fully functional plugin usually needs to provide users with configuration options. The most standard way to do this is to create a settings page in the WordPress backend. This can be achieved by usingadd_menu_page()Oradd_options_page()It can be implemented using functions such as `math.cos`, `math.sin`, and `math.tan`.
First, let's create a top-level menu item. In the following example,mfe_create_admin_menuThe function is used to...add_menu_page()To add a new page. This function requires a page title, a menu title, the required permissions, a menu slug, a callback function to output the page content, an icon URL, and the position in the menu.
Recommended Reading Starting from scratch: A complete guide to WordPress plugin development and sharing of best practices。
// 创建后台管理菜单
function mfe_create_admin_menu() {
add_menu_page(
__( '我的扩展设置', 'my-first-extension' ), // 页面标题
__( '我的扩展', 'my-first-extension' ), // 菜单标题
'manage_options', // 权限(管理员)
'mfe-settings', // 菜单slug
'mfe_settings_page_html', // 显示页面内容的函数
'dashicons-admin-generic', // 图标
80 // 位置
);
}
add_action( 'admin_menu', 'mfe_create_admin_menu' ); Next, we need to definemfe_settings_page_htmlWe use functions to render the page content. A professional settings page should use WordPress's standard settings API, which handles tasks like form submissions, field validation, and other security-related work. First, we need to useregister_setting()Register a settings group and fields.
// 初始化设置
function mfe_settings_init() {
// 注册一个新的设置组 “mfe_settings_group” 到页面 “mfe-settings”
register_setting( 'mfe-settings', 'mfe_settings_options' );
// 在设置组内添加一个区域(Section)
add_settings_section(
'mfe_settings_section',
__( '基本设置', 'my-first-extension' ),
'mfe_settings_section_cb',
'mfe-settings'
);
// 在区域内添加一个字段
add_settings_field(
'mfe_field_api_key',
__( 'API密钥', 'my-first-extension' ),
'mfe_field_api_key_cb',
'mfe-settings',
'mfe_settings_section',
[ 'label_for' => 'mfe_field_api_key' ]
);
}
add_action( 'admin_init', 'mfe_settings_init' ); Then, we need to define the area callback and field callback functions to output HTML. The field callback function is particularly important, as it renders the form input boxes and ensures that their values are associated with the saved settings.
// 设置区域的说明文本
function mfe_settings_section_cb( $args ) {
?>
<p id="<?php echo esc_attr( $args['id'] ); ?>"><?php esc_html_e( '请在此配置插件的基本参数。', 'my-first-extension' ); ?></p>
<?php
}
// API密钥字段的回调函数
function mfe_field_api_key_cb( $args ) {
// 从已注册的设置选项中获取值
$options = get_option( 'mfe_settings_options' );
$value = $options[ $args['label_for'] ] ?? '';
?>
<input type="text"
id="<?php echo esc_attr( $args['label_for'] ); ?>"
name="mfe_settings_options[<?php echo esc_attr( $args['label_for'] ); ?>]"
value="<?php echo esc_attr( $value ); ?>"
class="regular-text">
<p class="description"><?php esc_html_e( '请输入您的服务API密钥。', 'my-first-extension' ); ?></p>
<?php
} Finally, create the function for the main settings page, usingsettings_fields()anddo_settings_sections()Output the entire form safely.
// 设置页面的HTML结构
function mfe_settings_page_html() {
// 检查用户权限
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
?>
<div class="wrap">
<h1></h1>
<form action="/en/options.php/" method="post" data-trp-original-action="options.php">
<?php
// 输出安全字段、区域和字段
settings_fields( 'mfe-settings' );
do_settings_sections( 'mfe-settings' );
submit_button( __( '保存设置', 'my-first-extension' ) );
?>
<input type="hidden" name="trp-form-language" value="en"/></form>
</div>
<?php
} In this way, by creating the setup page, all form data validation, cleaning, and saving are automatically handled by the WordPress settings API and stored in the database.wp_optionsThe name in the table ismfe_settings_optionsAmong the options, it greatly enhances the security and convenience.
Plugin security and best practices
To develop a professional, secure, and easy-to-maintain plug-in, it is essential to follow a series of best practices. The first principle is to never trust user input. All input from external sources, such as$_GET、$_POST、$_COOKIEEven the data in the database must be properly validated, cleaned, and escaped before it is output, used, or stored.
Data validation and cleaning: Before using the data for logical judgment, it should be verified whether it meets the expected format. For example, if a field is expected to be a number, it should be checked using the following method:intval()Oris_numeric()WordPress provides many auxiliary functions, such assanitize_text_field()It is used to clean up text strings.sanitize_email()It's used to clean up email addresses.
Data Escaping: When outputting any data to HTML, JavaScript, or URLs, it is necessary to perform data escaping to prevent cross-site scripting (XSS) attacks. Use <esc_html()Output pure text to HTML format.esc_attr()Output it into the HTML attribute.esc_url()Output the URL,wp_json_encode()combinationwp_slash()Output to JavaScript.
A common security mistake is to directly use unverified variables for database queries, which can lead to SQL injection. Never manually concatenate SQL statements. You should use the ones provided by WordPress instead.$wpdbThe class and its preparation query method.
global $wpdb;
$user_input = $_POST['search_term'];
// 错误做法:直接拼接
// $sql = “SELECT * FROM {$wpdb->posts} WHERE post_title LIKE ‘%$user_input%’”;
// 正确做法:使用prepare方法
$sql = $wpdb->prepare(
“SELECT * FROM {$wpdb->posts} WHERE post_title LIKE %s”,
‘%’ . $wpdb->esc_like( $user_input ) . ‘%’
);
$results = $wpdb->get_results( $sql ); Permission check: Before performing any management operations, data modification, or sensitive information output in the plug-in, it is necessary to check whether the current user has the right to perform the operation. Usecurrent_user_can( $capability )Orcheck_admin_referer()And then proceed to the verification process.
The scripts and style sheets are loaded in a queue: Never load them directly in the plug-in.<link>Or<script>Introduce CSS and JS files into the tags. You should use and tags to do this.wp_enqueue_style()andwp_enqueue_script()Output:
The function, and make sure to use the appropriate hooks (such aswp_enqueue_scriptsFor the front-end,admin_enqueue_scriptsThis is done in the background. This can avoid conflicts and ensure that dependencies are loaded correctly.
Code organization and naming conventions: Use a unique prefix (such as "plug") for your plug-in functions, classes, variables, and option names.mfe_), to prevent conflicts with the theme, other plugins, or the WordPress core. Organizing complex plugins into multiple files and using object-oriented programming (OOP) can improve the readability and reusability of the code.
Provide an uninstall and cleanup function: If the plugin creates database tables or custom options, it should consider providing a cleanup function when users “delete” (rather than “deactivate”) the plugin. This can be achieved through a separate uninstallation file. In the main file of the plugin, you can use the following code:
```python
def uninstall(self):
# Uninstall the plugin's database tables and custom options
# ...
```register_uninstall_hook( FILE, ‘mfe_plugin_uninstall’ )To register the uninstall function, but a more common approach is to create a file in the plugin directory.uninstall.phpThe file. WordPress will automatically execute this file when deleting the plugin.
summarize
WordPress plugin development is a process that combines structured thinking and a deep understanding of the WordPress core architecture. From writing standardized plugin header information to understanding and skillfully using action hooks and filter hooks, these are the cornerstones of building any functional extension. Creating a practical plugin not only requires implementing front-end functionality, but also building a clear and secure backend settings interface, which can be efficiently accomplished through the WordPress settings API.
Security is an indispensable lifeline throughout the entire process, from input validation and output escaping to permission checks and secure database operations—every step must be taken seriously. Following best practices, such as properly queuing script loading, using unique prefixes, and organizing code structures in a clear manner, will make your plugin more robust, easier to maintain, and able to coexist harmoniously with the vast WordPress ecosystem. By following the steps in this guide, you have mastered the core knowledge and skills needed to build a professional-level WordPress plugin from scratch.
FAQ Frequently Asked Questions
How to add a shortcode to my plugin?
Shortcodes allow users to easily insert plugin functions into articles or pages. To use them, you need to add the shortcode to the content you want to display, and then the plugin will automatically execute the corresponding function when the page is loaded.add_shortcode()Use the function to register your short code.
Create a callback function to handle the logic of short codes, which receives the attribute as input.$atts) and content ($content(Note: The translation of the last sentence should be adjusted to match the actual syntax of PHP.)
The function receives the parameters and returns the processed HTML. Remember, the shortcode callback function must return the content, rather than outputting it directly (echo). The returned content also needs to be properly escaped to ensure security.
Where should the plugin options be stored?
For simple key-value pair settings, it is highly recommended to use WordPress's Options API, that is,add_option()、get_option()andupdate_option()A function. This data will be automatically stored inwp_optionsIn the database table.
If your plugin needs to store a large amount of structured data (such as form entries, logs), you should consider creating custom database tables. UsedbDelta()The function is used to ensure that the creation and updating of the table structure are safe and compatible. The creation of custom tables is usually handled in the plugin activation hook.
How can my plugin be compatible with other plugins or themes?
The key to improving compatibility is to follow WordPress coding standards, use unique prefixes, and provide extension points through hooks. Avoid directly modifying core files or global variables.
In your plugin, usedo_action()Orapply_filters()To create custom hooks that allow other developers to modify or extend the behavior of your plugin. At the same time, use conditional checks or provide a close option before performing actions that may cause conflicts, such as adding styles or scripts.
How to add an update mechanism to a plug-in?
For plugins hosted in the official WordPress plugin directory, updates are handled automatically. For private or commercial plugins, you need to implement a custom update checker.
This usually involves creating a class that regularly checks your remote server for new versions and allows users to update with a single click. You can refer to libraries like “Plugin Update Checker” or implement it yourself. The core of it is to useset_site_transient()Hooks (such aspre_set_site_transient_update_plugins) to inject your updated information. Make sure the update server is safe and reliable.
What's next, what's next?
Extended reading and practical knowledge
The following are related to the topic of this article and are suitable for further in-depth reading. Prioritize starting with the article that is closest to your current problem, and gradually expanding to surrounding topics usually works better.
- Beginner's Guide to Website Construction: Mastering the Modern Website Development Process from Scratch
- WordPress Plugin Development Guide: Creating Your First Custom Plugin from Scratch
- What is a WordPress subtheme?
- Becoming a WordPress Plugin Developer: A Complete Guide from Scratch
- Mastering WordPress Theme Development: A Comprehensive Guide to Building Professional Websites from Scratch