WordPress Plugin Development Guide: Building Your First Plugin from Scratch

3-minute read
2026-03-19
2026-06-03
2,714
I earn commissions when you shop through the links below, at no additional cost to you.

Preparatory work and environment setup

Before you start writing code, you need a suitable development environment. This includes a local installation of WordPress, a code editor, and some basic knowledge of PHP. For a local development environment, tools such as XAMPP, MAMP, or Local by Flywheel are recommended; they allow you to quickly set up a server environment with PHP and MySQL on your local computer.

Creating the basic directory and files for a plugin

Every WordPress plugin must have a main file, which serves as the entry point for the plugin. First of all, you need to create this main file within WordPress. wp-content/plugins Create a new folder within the directory, for example… my-first-pluginThen, create a main PHP file inside that folder; this file usually has the same name as the folder itself. my-first-plugin.php

The beginning of this main file must contain a standard plugin information header comment. WordPress uses this information to identify and display your plugin in the backend administration interface.

Recommended Reading From Zero to One: A Step-by-Step Guide to Mastering the Core Skills of WordPress Plugin Development

<?php
/**
 * Plugin Name:       我的第一个插件
 * Plugin URI:        https://example.com/my-first-plugin
 * Description:       这是一个用于学习 WordPress 插件开发的示例插件。
 * Version:           1.0.0
 * Author:            你的名字
 * Author URI:        https://example.com
 * License:           GPL v2 or later
 * Text Domain:       my-first-plugin
 * Domain Path:       /languages
 */

Understanding the basic structure of WordPress plugin development

A fully functional plugin usually consists of more than one file. In addition to the main file, you may also have resource files such as JavaScript, CSS, and images, as well as language files for internationalization. A well-structured directory organization helps to keep the code organized and easy to maintain.

UltaHost WordPress Hosting
30-day refund guarantee, unlimited bandwidth and database usage, free DDoS protection; purchase for 3 years and get a discount of 50%.

A recommended structure is as follows:
- my-first-plugin/ (Plugin root directory)
- my-first-plugin.php (Main File)
- includes/ (Files containing core functionality classes or functions)
- admin/ (Contains code related to the backend administration interface)
- public/ (Contains code related to front-end display.)
- assets/ (Storage for CSS, JavaScript, images, and other resources)
- languages/ (Storage for internationalization translation files)

Core PHP code writing

All the functional logic of the plugin is implemented through PHP code. WordPress provides a large number of…动作钩子and过滤器钩子This is the foundation upon which plugins interact with the core of WordPress.

Implement a simple short code function

Shortcodes are powerful tools that allow users to easily embed plugin functionality into articles or pages. Let’s create a simple shortcode that displays a greeting message on the page.

In your main file… my-first-plugin.php Below the header comments, add the following functions and hooks:

Recommended Reading An in-depth analysis of WordPress plugin development: Building your first functional extension from scratch

// 注册短代码
function mfp_greeting_shortcode( $atts ) {
    // 使用 shortcode_atts 设置默认参数并合并用户传入的参数
    $atts = shortcode_atts( array(
        'name' =&gt; '访客',
    ), $atts, 'mfp_greeting' );

// 返回要显示的内容
    return '<p>Hello, '. esc_html($atts['name'])'. ‘! Welcome to use my first plugin.</p>'add_shortcode( 'mfp_greeting', 'mfp_greeting_shortcode' );

Now, users can enter text in the article editor. [mfp_greeting name=“小明”]The front-end will display: “Hello, Xiaoming! Welcome to use my first plugin.”

Add a setting option to the backend.

In order to make plugin functions configurable, we usually need to add a settings page. This demonstration shows how to add a sub-menu page to the “Settings” menu.

First of all, we use… add_action The hook is registered during the administrator initialization process for setting up configurations.

hosting.com Shared Hosting
High performance with AMD EPYC CPUs, NVMe SSD storage and LiteSpeed, 24/7, 24x7 expert in-house support, advanced security measures including SSL, brute force, malware and DDoS protection, savings of up to 73%
// 初始化插件设置
function mfp_settings_init() {
    // 注册一个新的设置 section
    add_settings_section(
        'mfp_settings_section', // section ID
        '我的插件设置', // 标题
        'mfp_settings_section_callback', // 回调函数,用于输出 section 描述
        'general' // 显示在哪个设置页,这里是“常规”设置页
    );

// 在 section 内注册一个字段
    add_settings_field(
        'mfp_default_greeting', // 字段 ID
        '默认问候人名', // 字段标题
        'mfp_default_greeting_callback', // 渲染字段输入框的回调函数
        'general', // 设置页面
        'mfp_settings_section' // 所属 section
    );

// 在 WordPress 的 `option` 表中注册这个设置
    register_setting( 'general', 'mfp_default_greeting' );
}
add_action( 'admin_init', 'mfp_settings_init' );

Then, define the two callback functions used above to render the interface:

// Section 描述的回调函数
function mfp_settings_section_callback() {
    echo '<p>Here, I am configuring the relevant options for my first plugin.</p>';
}

// 字段输入框的回调函数
function mfp_default_greeting_callback() {
    // 从数据库获取已保存的值,如果没有则使用默认值
    $option = get_option( 'mfp_default_greeting', 'WordPress 用户' );
    // 输出一个输入框
    echo '<input type="text" name="mfp_default_greeting" value="' . esc_attr( $option ) . '" />';
}

Now, you can find this setting option at the bottom of the “Settings -> General” page in the WordPress admin dashboard.

Front-end Resource Management and Ajax Interaction

Modern plugins usually require their own styles and interaction logic. WordPress provides standard methods for securely registering and loading CSS and JavaScript files.

Recommended Reading Starting from scratch: Why choose WordPress plugin development?

Loading CSS and JavaScript securely

Never directly include code from other sources into your PHP files. <link> Or <script> The resource path is hardcoded in the tag. This should be avoided. wp_enqueue_style and wp_enqueue_script Function.

// 注册并加载前端资源
function mfp_enqueue_public_assets() {
    // 加载一个 CSS 文件
    wp_enqueue_style(
        'mfp-public-style', // 样式表句柄
        plugin_dir_url( __FILE__ ) . 'assets/css/public-style.css', // 样式表 URL
        array(), // 依赖项
        '1.0.0' // 版本号,可用于清除缓存
    );

// 加载一个 JavaScript 文件
    wp_enqueue_script(
        'mfp-public-script', // 脚本句柄
        plugin_dir_url( __FILE__ ) . 'assets/js/public-script.js', // 脚本 URL
        array( 'jquery' ), // 依赖项,这里依赖 jQuery
        '1.0.0',
        true // 是否在页面底部加载
    );

// 重要:将 PHP 变量安全地传递到 JavaScript
    wp_localize_script(
        'mfp-public-script',
        'mfp_ajax_object', // 在 JS 中访问的对象名
        array(
            'ajax_url' => admin_url( 'admin-ajax.php' ),
            'nonce'    => wp_create_nonce( 'mfp_ajax_nonce' ),
            'default_name' => get_option( 'mfp_default_greeting', 'WordPress 用户' )
        )
    );
}
// 在前端页面加载资源
add_action( 'wp_enqueue_scripts', 'mfp_enqueue_public_assets' );
// 在后台管理页面加载资源(如果需要)
// add_action( 'admin_enqueue_scripts', 'mfp_enqueue_admin_assets' );

Implement a simple Ajax request

Ajax allows for interaction with the server without having to refresh the page. WordPress comes with a built-in Ajax handler.

InterServer Shared Hosting
Shared hosting $2.50 USD per month , first month $0.1 USD promo code tryinterserver, 461 cloud apps scripts, one click install.

First of all, in the front-end JavaScript file… public-script.js Send a request to:

jQuery(document).ready(function($) {
    $('#my-button').on('click', function(e) {
        e.preventDefault();
        $.post(
            mfp_ajax_object.ajax_url, // WordPress 提供的 Ajax URL
            {
                action: 'mfp_get_server_time', // 触发的 PHP 钩子标识
                nonce: mfp_ajax_object.nonce, // 安全随机数
            },
            function(response) {
                if (response.success) {
                    $('#result-container').html('服务器时间:' + response.data);
                } else {
                    alert('请求失败:' + response.data);
                }
            }
        );
    });
});

Then, process this request on the PHP side. It is necessary to have separate registration handling functions for logged-in users and unlogged-in users (or handle them both simultaneously).

// 处理 Ajax 请求的函数
function mfp_ajax_get_server_time() {
    // 验证 nonce,防止 CSRF 攻击
    check_ajax_referer( 'mfp_ajax_nonce', 'nonce' );

// 处理逻辑
    $server_time = current_time( 'mysql' );

// 返回成功响应(JSON 格式)
    wp_send_json_success( $server_time );
}
// 为登录用户注册处理函数
add_action( 'wp_ajax_mfp_get_server_time', 'mfp_ajax_get_server_time' );
// 为未登录用户注册处理函数(如果功能允许)
add_action( 'wp_ajax_nopriv_mfp_get_server_time', 'mfp_ajax_get_server_time' );

Plugin internationalization and release preparation

To make your plugin available to WordPress users around the world, internationalization (i18n) is an essential step. It is also crucial to conduct thorough testing and optimization before releasing the plugin.

Implementing text translation using the gettext function

WordPress uses the GNU gettext framework for translation. You need to wrap all user-facing strings with specific functions.

Modify the previous short code function to support translation:

function mfp_greeting_shortcode_i18n( $atts ) {
    $atts = shortcode_atts( array(
        'name' =&gt; __( '访客', 'my-first-plugin' ), // 默认值也可翻译
    ), $atts, 'mfp_greeting' );

// 使用 sprintf 和 __ 函数组合翻译字符串
    return '<p>' . sprintf( __( '你好,%s!欢迎使用我的第一个插件。', 'my-first-plugin' ), esc_html( $atts['name'] ) ) . '</p>'add_shortcode( 'mfp_greeting', 'mfp_greeting_shortcode_i18n' );

You need to use tools like Poedit to scan all similar elements within the plugin. __(‘文本’, ‘my-first-plugin’) Generate a string of characters. .pot Template files, and then create corresponding files for each language (such as Chinese). .po And the compiled version .mo File, and place it there. /languages Catalog.

Perform final testing and code cleanup.

Before releasing a plugin, please make sure to perform the following checks:
1. Functional Testing: Activate the plugin on a brand-new WordPress installation and test whether all features (shortcodes, settings, Ajax, etc.) are working as expected.
2. Code Review: Verify that all user inputs have been properly processed or validated. esc_html, esc_attr, wp_kses_post Use functions such as security escaping to ensure proper handling of user input. Should all database queries employ these security measures? $wpdb The class includes preparatory statements to prevent SQL injection attacks.
Performance check: Ensure that scripts and styles are only loaded on the required pages (you can use conditional tags such as <). is_admin(), is_single() Make judgments accordingly. Avoid performing unnecessary database queries every time the page is loaded.
4. File Cleanup: Remove debug code used during the development process, unnecessary comments, and any unused files.
5. README File: Create a detailed one readme.txt The file must comply with the requirements of WordPress.org in terms of format, and should include a description, installation instructions, and answers to common questions. This file is essential for submitting the plugin to the official WordPress repository.

summarize

By following this guide, you have completed the process of transforming a blank file into a fully functional WordPress plugin that includes shortcodes, backend settings, front-end resource loading, Ajax interactions, and internationalization support. The key steps involved were: setting up the environment and creating the main file with a standard header; using action hooks and filter hooks to add functionality; securely managing resource files; implementing asynchronous communication between the front and backends; and preparing the plugin for translation and testing for global release. Remember that security (escaping data, validation, using nonces), performance (loading resources on demand), and compliance with WordPress coding standards are the three pillars of developing high-quality plugins. Continuously learning and practicing more advanced APIs, such as custom post types, REST APIs, and Blocks editor development, will make your plugin even more powerful.

FAQ Frequently Asked Questions

Does plugin development necessarily require the use of object-oriented programming?

Not necessarily. For simple plugins, using procedural programming (a set of functions) is completely feasible and even simpler and more straightforward. However, for medium to large, complex plugins, adopting object-oriented programming (OOP) and class structures can help organize the code more effectively, enable encapsulation and reuse, and reduce the likelihood of naming conflicts. This is the more recommended approach.

How to debug problems in a WordPress plugin?

First, make sure that... wp-config.php The file is open in the program WP_DEBUG and WP_DEBUG_LOG As a constant, this way the error message will be recorded. /wp-content/debug.log The file content will not be displayed to the user. Secondly, the following method can be used… error_log() The function outputs variable values to the log. For Ajax or complex logic, the “Network” and “Console” panels in the browser developer tools are essential for debugging.

How can my plugin be compatible with the theme and other plugins?

The best practices for maintaining compatibility are: strictly adhering to the official WordPress API and coding standards; and adding a unique prefix to the names of your functions, classes, and action hooks. mfp_To avoid conflicts, it is essential to check whether any global variables or functions exist before using them. function_exists() Or class_exists()); and clearly explain in the documentation the database tables created by your plugin.选项Or 用户元数据

What are the requirements for submitting a plugin to the WordPress.org repository?

You need to have a WordPress.org account and ensure that the plugin fully complies with the official requirements. These include: the code being licensed under a GPL-compatible license (usually GPLv2+); the plugin being 100% open-source and not relying on any external paid services to function its core features; and the plugin including standard formatting. readme.txt The file and the code contain no malicious or junk content; they have also passed the inspection by a team of human reviewers. Please read the official plugin development manual and submission guidelines carefully before submitting.