How to Create and Publish Your Own WordPress Plugin
2 July 2026 · 14 min read
WordPress powers a significant proportion of websites on the internet, and one reason it has remained widely used for so long is its plugin architecture. Plugins allow functionality to be added to a WordPress site without touching the core code, in a way that is modular, updatable and, when done correctly, straightforward to maintain.
Creating your own plugin sounds more complicated than it is. If you are comfortable writing PHP, you already have everything you need to build one. If you are less experienced, this article walks through the process from the beginning, explaining not just what to do but why, so that the resulting plugin is built on solid foundations rather than assembled from copied code that nobody fully understands.
This guide covers building a simple but complete plugin, understanding the WordPress hook system that makes plugins work, and publishing your plugin to the WordPress.org repository if you want to share it with others.
What a WordPress Plugin Actually Is
A plugin is a PHP file or a collection of PHP files that WordPress automatically discovers and makes available for activation from the admin dashboard. When activated, the plugin’s code runs alongside WordPress’s own code, adding or modifying functionality without altering the core WordPress files themselves.
This separation is what makes the plugin architecture sensible. Core WordPress files can be updated without overwriting your custom code. Your plugin can be deactivated without breaking the rest of the site. And if your plugin is well written, it can be installed on any WordPress site, not just the one it was built for.
The difference between a plugin and a theme function
A common question for those new to WordPress development is whether a piece of functionality should go in a plugin or in the theme’s functions.php file. The practical answer is that anything not directly tied to the visual presentation of a specific theme belongs in a plugin. If you switch themes and need the functionality to persist, it should be a plugin. If the functionality would be meaningless without the specific theme, it can reasonably sit in functions.php.
Setting Up the Plugin File
Every WordPress plugin requires, at a minimum, a single PHP file with a specific comment block at the top. This comment block is what WordPress reads to identify the plugin and display its details in the admin dashboard.
Step 1: Create the plugin folder and file
Navigate to wp-content/plugins/ in your WordPress installation and create a new folder. The folder name should be unique, lowercase, and use hyphens rather than spaces or underscores. Inside that folder, create a PHP file with the same name as the folder.
wp-content/plugins/my-first-plugin/my-first-plugin.php
Step 2: Add the plugin header
Open that PHP file and add the following comment block at the very top. WordPress reads this to identify your plugin.
<?php
/**
* Plugin Name: My First Plugin
* Plugin URI: https://markexcell.co.uk/plugins/my-first-plugin/
* Description: A simple example plugin to demonstrate the basics.
* Version: 1.0.0
* Author: Mark Excell
* Author URI: https://markexcell.co.uk/
* License: GPL-2.0+
*/
Two of these fields are worth a specific note. The Plugin URI should point to a dedicated page for this plugin, such as a page on your website that describes what it does, where to find documentation, and how to get support. The Author URI points to you as the author, typically your homepage or about page. WordPress and the plugin repository require these to be different URLs. Using the same URL for both will cause your submission to be rejected during the review process if you intend to publish to the repository.
Save this file, then go to Plugins in your WordPress admin dashboard. Your plugin should now appear in the list, ready to activate. It does not do anything yet, but WordPress has recognised it as a valid plugin.
Understanding WordPress Hooks
The mechanism that allows plugins to add or modify WordPress functionality without editing core files is called the hook system. Understanding hooks is the single most important concept for WordPress plugin development. Everything else follows from it.
Actions
An action is a point in the WordPress execution process where your code can be inserted. WordPress fires dozens of actions as it loads a page, from initialising itself, to loading the header, to sending the page to the browser. Your plugin registers a function to run at any of these points using add_action.
add_action( ‘wp_footer’, ‘my_plugin_footer_message’ );
function my_plugin_footer_message() {
echo ‘<p>This text appears in the footer.</p>’;
}
The first argument is the name of the action hook. The second is the name of the function to call when that hook fires. WordPress will now call my_plugin_footer_message every time the wp_footer action runs, which happens just before the closing body tag on every page.
Filters
A filter is similar to an action, but instead of simply running code at a specific point, a filter allows you to receive a value, modify it, and return the modified version. WordPress passes a piece of data through a filter; your function changes it, and the changed version continues through the rest of the process.
add_filter( ‘the_title’, ‘my_plugin_modify_title’ );
function my_plugin_modify_title( $title ) {
return $title . ‘ | My Site’;
}
This example adds a suffix to every post title on the site. The filter receives the title; the function appends the extra text; the modified title is returned and used by WordPress in place of the original.
A Complete Working Example: Adding a Custom Footer Message
The following is a complete, functional plugin that adds a simple configurable message to the footer of every page. It demonstrates the header, hooks, a settings page in the admin dashboard, and secure handling of user input.
<?php
/**
* Plugin Name: Footer Message
* Plugin URI: https://markexcell.co.uk/plugins/footer-message/
* Description: Adds a configurable message to the site footer.
* Version: 1.0.0
* Author: Mark Excell
* Author URI: https://markexcell.co.uk/
*/
// Add a settings page to the admin menu
add_action( ‘admin_menu’, ‘fm_add_settings_page’ );
function fm_add_settings_page() {
add_options_page(
‘Footer Message Settings’,
‘Footer Message’,
‘manage_options’,
‘footer-message’,
‘fm_render_settings_page’
);
}
// Render the settings page
function fm_render_settings_page() {
if ( ! current_user_can( ‘manage_options’ ) ) {
return;
}
if ( isset( $_POST[‘fm_message’] ) ) {
check_admin_referer( ‘fm_save_settings’ );
update_option( ‘fm_message’, sanitize_text_field( $_POST[‘fm_message’] ) );
echo ‘<div class=”updated”><p>Settings saved.</p></div>’;
}
$message = get_option( ‘fm_message’, ” );
?>
<div class=”wrap”>
<h1>Footer Message Settings</h1>
<form method=”post”>
<?php wp_nonce_field( ‘fm_save_settings’ ); ?>
<table class=”form-table”>
<tr>
<th><label for=”fm_message”>Footer message</label></th>
<td><input type=”text” id=”fm_message” name=”fm_message”
value=”<?php echo esc_attr( $message ); ?>” class=”regular-text”></td>
</tr>
</table>
<?php submit_button(); ?>
</form>
</div>
<?php
}
// Output the message in the footer
add_action( ‘wp_footer’, ‘fm_output_footer_message’ );
function fm_output_footer_message() {
$message = get_option( ‘fm_message’, ” );
if ( ! empty( $message ) ) {
echo ‘<p class=”footer-message”>’ . esc_html( $message ) . ‘</p>’;
}
}
This complete plugin creates a settings page under Settings in the WordPress admin, saves a message securely to the database, and outputs it in the footer of every page. It uses nonce verification to prevent cross-site request forgery, capability checking to ensure only administrators can save settings, and output escaping to prevent cross-site scripting.
Security: The Non-Negotiable Requirements
WordPress plugin security is not optional, and poorly secured plugins are one of the most common causes of WordPress sites being compromised. These four practices should be present in every plugin that handles user input or database operations.
Nonce verification
A nonce, short for “number used once,” is a security token that WordPress generates for each form submission. Checking the nonce before processing any form data confirms the submission came from your own form and not an external source. Use wp_nonce_field to add the nonce to a form and check_admin_referer to verify it on submission.
Capability checking
Before performing any action that modifies data, confirm the current user has the appropriate capability using current_user_can. The manage_options capability is appropriate for site-wide settings. Other capabilities are available for more specific operations, such as editing posts or managing users.
Sanitisation
Any data received from user input must be sanitised before it is stored. WordPress provides a range of sanitisation functions for different data types, including sanitize_text_field for plain text, sanitize_email for email addresses, and absint for integers. Using the right function for the data type removes potentially harmful content before it reaches the database.
Escaping
Any data output to the browser, whether from the database or elsewhere, must be escaped to prevent it being interpreted as HTML or JavaScript. Use esc_html for plain text output, esc_attr for HTML attribute values, and esc_url for URLs. Escaping on output is the last line of defence against cross-site scripting.
Organising a Larger Plugin
For a simple plugin like the example above, a single file is perfectly adequate. For anything more complex, a clear file structure makes the plugin significantly easier to maintain and extend over time.
my-plugin/
my-plugin.php (main plugin file, header and bootstrapping only)
includes/
class-my-plugin.php (main plugin class)
admin/
settings.php (admin settings page)
public/
frontend.php (public-facing functionality)
assets/
css/
js/
The main plugin file handles only the plugin header and the initial bootstrapping, loading the other files and registering any hooks that need to fire at the earliest opportunity. All functional code lives in the includes directory, separated by concern.
Publishing to the WordPress.org Plugin Repository
If you have built a plugin that would be useful to others, publishing it to the WordPress.org repository makes it discoverable and installable by any WordPress user. The repository is free to submit to, and published plugins can be installed directly from the WordPress admin dashboard.
Before you submit
- Ensure the plugin follows the WordPress plugin guidelines, available on the developer documentation pages at developer.wordpress.org
- Test the plugin against the current version of WordPress and confirm it produces no PHP errors or warnings.
- Ensure all user input is sanitised and all output is escaped
- Write a clear readme.txt file using the standard WordPress plugin readme format, which the repository uses to generate the plugin’s public listing page
- Choose a plugin slug, the unique identifier for your plugin, that is not already in use in the repository
The submission process
- Create a free account at wordpress.org if you do not already have one
- Visit the plugin submission page at wordpress.org/plugins/developers/add/ and upload a zip file of your plugin folder
- The WordPress plugin review team will review the submission, usually within a few weeks, and either approve it or request changes
- Once approved, you will receive access to a Subversion (SVN) repository where the plugin lives
- Use SVN to upload your plugin files and create version tags for each release
- The plugin then appears publicly in the repository and can be installed by any WordPress user
The readme.txt file
The readme.txt is worth taking care with. It powers the plugin’s public listing page, including the description, installation instructions, frequently asked questions and changelog. Well-written readme content helps potential users understand what the plugin does and builds confidence that it is actively maintained.
Quick Reference Checklist
☐ Plugin folder created in wp-content/plugins/ with a unique, lowercase, hyphenated name
☐ Main PHP file named identically to the folder
☐ Plugin header comment block present at the top of the main file
☐ All functionality added via add_action and add_filter rather than direct code execution
☐ Nonce verification in place for all form submissions
☐ Capability checking in place before any data modification
☐ All user input sanitised before storage
☐ All output escaped before rendering
☐ Plugin tested against the current WordPress version with no errors or warnings
☐ readme.txt written in the standard WordPress format before submission to the repository
Frequently Asked Questions
Do I need to know PHP to write a WordPress plugin?
Yes. WordPress plugins are written in PHP, and a working knowledge of PHP is a prerequisite. You do not need to be an expert, but understanding variables, functions, arrays and basic control flow is necessary to write a plugin that works reliably and securely. If you are new to PHP, working through a beginner PHP course before attempting plugin development will save a significant amount of frustration.
Can I write a plugin without using hooks?
Technically, a plugin file can contain PHP that runs directly rather than through hooks. In practice, doing so means the code runs at an unpredictable point in the WordPress loading process, which causes problems. Using hooks is not just convention; it is the correct way to integrate code with WordPress and ensures your plugin behaves predictably alongside other plugins and themes.
How do I debug a plugin that is not working as expected?
The first step is to enable WordPress debug mode by adding define( ‘WP_DEBUG’, true ); to your wp-config.php file. This surfaces PHP errors and warnings that are hidden by default. The Query Monitor plugin is also extremely useful for identifying which code is running, which database queries are being executed, and where errors occur during page load.
What is the difference between a free and a premium plugin?
Free plugins are typically distributed through the WordPress.org repository or directly by the developer at no cost. Premium plugins are sold through third-party marketplaces or directly by the developer, usually with additional features, dedicated support, or both. There is no technical difference in how they are built, only in how they are distributed and licensed.
Is it safe to activate multiple plugins at once?
In principle, yes. In practice, conflicts between plugins do occur, particularly when two plugins try to modify the same functionality or load incompatible versions of the same library. Testing new plugins on a staging environment before activating them on a live site is the most reliable way to identify conflicts before they affect real visitors.
Need a Custom WordPress Plugin?
If you have a specific piece of functionality in mind that no existing plugin quite delivers, or if you need something built to integrate with your existing systems, get in touch for a straightforward conversation with no obligation and no sales pitch.
Browse by topic
Further reading