Posted in

How to Build Your Own WordPress Plugin

Create WordPress Plugin
Create WordPress Plugin

WordPress powers over 40% of all websites — and a big reason for its success is the rich plugin ecosystem that allows anyone to extend its functionality. From contact forms and SEO tools to e-commerce engines and social media integrations, plugins are what transform WordPress from “just a blog” into anything you want it to be.

But what if you can’t find a plugin that does exactly what you need? Or maybe you want to learn how WordPress works under the hood? That’s where building your own plugin comes in.

🧠 Think of a plugin as a mini-app that adds features or modifies behavior — all without touching the WordPress core.

🚀 Why You Might Want to Create Your Own Plugin

  • ✅ Add custom functionality specific to your site or client project
  • ✅ Learn how WordPress’s hook system works
  • ✅ Keep code modular instead of putting it in the functions.php of your theme.
  • ✅ Share or sell your plugin to help others in the WP community

Whether you’re a beginner or an experienced developer, building a plugin gives you a deeper appreciation for how powerful — and flexible — WordPress really is.

💡 What You’ll Learn in This Guide

We’ll walk through the process step by step, from setting up a dev environment to publishing a working plugin. You’ll learn about:

  • 🔧 Plugin file structure and naming conventions
  • 🪝 Actions, filters, and the hook system
  • 🔐 Security best practices
  • 🧰 Building admin settings pages
  • 🚀 Packaging and sharing your plugin

So grab your code editor, fire up a local WordPress site, and let’s build something awesome together. 💻🎉


🏗️ Plugin Anatomy: Files & Structure

Before we write a single line of code, it’s important to understand what makes up a WordPress plugin. At its core, a plugin is just a PHP file (or group of files) living in a special folder inside your WordPress installation.

📁 Where Do Plugins Live?

All plugins are stored in the wp-content/plugins/ directory of your WordPress installation. To create your own, simply make a new folder here — for example:

wp-content/
└── plugins/
    └── my-first-plugin/
        └── my-first-plugin.php

The folder name and file name should be lowercase, with dashes instead of spaces. This keeps things clean and consistent.

🧩 The Main Plugin File

Every plugin needs at least one PHP file that includes a special plugin header comment at the top. This comment tells WordPress how to recognize and register your plugin.

<?php
/**
 * Plugin Name: My First Plugin
 * Description: A simple starter plugin for learning.
 * Version: 1.0
 * Author: Your Name
 */

This file acts as the plugin’s entry point — WordPress looks for this header to display your plugin in the admin dashboard.

🧱 Common Folder Structure

As your plugin grows, you’ll likely want to organize it into separate files and folders. A good starting structure might look like this:

my-first-plugin/
├── my-first-plugin.php
├── includes/
│   └── core-functions.php
├── assets/
│   ├── style.css
│   └── script.js
└── readme.txt

What each part is for:

  • my-first-plugin.php — main plugin file with the header
  • includes/ — reusable PHP files (logic, functions, classes)
  • assets/ — static files like CSS, JS, images
  • readme.txt — optional, used for distribution via WordPress.org

💡 Pro Tip: Start small, but organize early. It’s easier to grow a well-structured plugin than to refactor a messy one.

📦 Bonus: Naming Your Plugin

Use unique prefixes for functions and classes (e.g. myplugin_) to avoid conflicts with other plugins.

function myplugin_do_something() {
    // your code here
}

This tiny habit can save you hours of debugging in the future.


⚙️ Setting Up Your Development Environment

Before we dive into writing code, we need the right tools — your plugin-building toolkit. A good development environment helps you code faster, debug smarter, and avoid nasty surprises in production.

💻 Step 1: Set Up a Local WordPress Installation

Working locally means you can break things without consequences. Here are some popular local dev tools:

  • 🔸 Local (by Flywheel) – Friendly UI, fast setup, ideal for beginners
  • 🔸 XAMPP / MAMP – Classic options with Apache, MySQL, PHP bundled
  • 🔸 DevKinsta or Laravel Valet – Great for power users and Mac devs

Once you’ve installed WordPress locally, navigate to wp-content/plugins — this is where your plugin will live.

🛠️ Step 2: Choose a Code Editor

Any editor will do, but here are some popular choices for WordPress devs:

Make sure your editor supports PHP syntax highlighting, linting, and has an integrated terminal if possible.

🧪 Step 3: Enable Debugging in WordPress

To catch bugs early, enable debugging in your wp-config.php file:

define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );

This logs errors to wp-content/debug.log so your users don’t see them.

🐛 Bonus: Install the Query Monitor plugin to get real-time insights into hooks, queries, and PHP errors.

🌱 Step 4: Version Control with Git (Optional but Smart)

Version control isn’t just for big projects. Even small plugins benefit from Git:

  • Track changes as you code
  • Roll back when things break
  • Collaborate easily with others

Run this in your plugin folder to initialize Git:

git init
git add .
git commit -m "Initial commit of my plugin"

🔧 Tools Summary

  • 🧰 Local WP Install: Local by Flywheel or MAMP
  • 🧠 Code Editor: VS Code with PHP extensions
  • 📋 Debugging: WP_DEBUG and Query Monitor
  • 🧾 Version Control: Git

With your dev setup ready, it’s time to start building! Next up: writing your first plugin — the classic “Hello World.”


💾 Creating Your First “Hello World” Plugin

Let’s build a simple plugin that displays a friendly “Hello, World!” message on your WordPress site. This will show you how a plugin is structured, where to place it, and how to activate it inside WordPress.

📁 Step 1: Create the Plugin Folder and File

Inside your WordPress installation, navigate to wp-content/plugins. Create a new folder named:

hello-world-plugin

Inside that folder, create a file named:

hello-world-plugin.php

🧩 Step 2: Add the Plugin Header

Open hello-world-plugin.php in your code editor and paste the following:

<?php
/**
 * Plugin Name: Hello World Plugin
 * Description: A simple plugin that prints "Hello, World!" on your site.
 * Version: 1.0
 * Author: Your Name
 */

// Hook our function to 'wp_footer' so it displays at the bottom of the page
function hello_world_message() {
    echo '<p style="text-align:center; font-size:18px;">Hello, World! From my first plugin.</p>';
}
add_action( 'wp_footer', 'hello_world_message' );

Here’s what’s happening:

  • 🔹 The plugin header tells WordPress to recognize your plugin.
  • 🔹 We’re using add_action() to hook into wp_footer, which lets us print something just before the closing </body> tag.

⚙️ Step 3: Activate the Plugin

Head over to your WordPress admin dashboard, then go to:

Plugins → Installed Plugins

You’ll see “Hello World Plugin” in the list. Click Activate, visit your site, and scroll to the bottom of any page — your message should appear!

🎉 Congrats! You’ve just created your first functional WordPress plugin.

🧠 What You Learned

  • ✅ How to create a plugin folder and main file
  • ✅ How to add the plugin header
  • ✅ How to use a WordPress hook to output content
  • ✅ How to activate your plugin from the admin panel

Now that you’ve dipped your toes into plugin development, let’s explore how WordPress’s powerful event system works — through hooks, actions, and filters.


🧩 Hooks, Actions & Filters: The WordPress Event System

One of the key things that makes WordPress so extensible is its powerful event-driven system. With hooks, you can “plug into” WordPress at specific points during execution — and either add functionality (actions) or modify data (filters).

🔁 Think of hooks as WordPress saying: “Hey, I’m doing something important — want to jump in and help or change something?”

🛎️ What Are Actions?

Actions are hooks that allow you to add behavior. For example, printing a message in the footer, sending an email, or enqueueing a script.

add_action( 'wp_footer', 'myplugin_footer_message' );

function myplugin_footer_message() {
    echo '<p>Powered by My Plugin</p>';
}

This tells WordPress: “When you’re about to render the footer, run this function.”

🧪 What Are Filters?

Filters allow you to intercept and modify data before it’s displayed or saved. For example:

add_filter( 'the_content', 'myplugin_add_note' );

function myplugin_add_note( $content ) {
    return $content . '<p><em>Thanks for reading!</em></p>';
}

This appends a note after every post’s content — without editing any theme files. Magic. ✨

🧠 Understanding Hook Priorities & Arguments

You can control when your function runs using a “priority” number (lower = earlier):

add_action( 'init', 'my_init_function', 20 );

Some hooks also pass additional arguments. You can declare them like this:

add_filter( 'example_hook', 'my_function', 10, 2 );

function my_function( $arg1, $arg2 ) {
    // do something
}

📘 Pro Tip: Hooks are everywhere. You can even write your own using do_action() or apply_filters().

🔍 How Do You Find Available Hooks?

  • Check the WordPress Hook Reference
  • Use the Query Monitor plugin to see live hooks on your pages
  • Search core/plugin/theme code for do_action or apply_filters

📎 Recap

  • Actions → do something (enqueue scripts, print HTML, send emails)
  • Filters → change something (modify content, tweak output, sanitize data)
  • Both are essential to building real-world plugins the “WordPress way”

Next up: We’ll look at how to turn your plugin into something users can configure — by adding settings to the WordPress admin dashboard. 🎛️


🎛️ Adding Plugin Settings to the Admin Dashboard

What’s a plugin without customization? Giving users a way to tweak options makes your plugin truly flexible. Thankfully, WordPress provides everything you need to create admin settings — no hacking required.

🧰 Step 1: Add a Settings Menu

Let’s create a settings page that lives under the Settings menu:

add_action( 'admin_menu', 'hello_world_add_menu' );

function hello_world_add_menu() {
    add_options_page(
        'Hello World Settings',    // Page title
        'Hello World',             // Menu title
        'manage_options',          // Capability
        'hello-world-settings',    // Menu slug
        'hello_world_settings_page'// Callback to output the HTML
    );
}

🧾 Step 2: Register a Setting

This registers a setting value in the WordPress database:

add_action( 'admin_init', 'hello_world_register_settings' );

function hello_world_register_settings() {
    register_setting( 'hello_world_options_group', 'hello_world_message' );
}

🖊️ Step 3: Create the Settings Page UI

This is where users will enter their custom “Hello World” message:

function hello_world_settings_page() {
    ?>
    <div class="wrap">
        <h1>Hello World Plugin Settings</h1>
        <form method="post" action="options.php">
            <?php
                settings_fields( 'hello_world_options_group' );
                do_settings_sections( 'hello_world_options_group' );
                $message = esc_attr( get_option( 'hello_world_message', 'Hello, World!' ) );
            ?>

            <table class="form-table">
                <tr valign="top">
                    <th scope="row">Custom Message</th>
                    <td><input type="text" name="hello_world_message" value="<?php echo $message; ?>" size="40"></td>
                </tr>
            </table>

            <?php submit_button(); ?>
        </form>
    </div>
    <?php
}

🧠 Step 4: Output the Setting on the Frontend

Update the function from our “Hello World” plugin to use the saved value:

function hello_world_message() {
    $message = get_option( 'hello_world_message', 'Hello, World!' );
    echo '<p style="text-align:center;">' . esc_html( $message ) . '</p>';
}
add_action( 'wp_footer', 'hello_world_message' );

🛠️ Note: Always sanitize and escape output from settings to protect against malicious input.

🎉 What You’ve Achieved

  • ✅ Added a settings page under the Settings menu
  • ✅ Registered a custom plugin setting
  • ✅ Created a form that saves and retrieves values
  • ✅ Displayed a custom message on the frontend based on user input

Up next, we’ll take things further by loading custom styles and scripts in your plugin. 🎨🧩


🎨 Enqueueing Styles and Scripts the Right Way

Want to make your plugin more interactive or give it a polished visual touch? Whether it’s a dash of CSS or some JavaScript magic, WordPress gives you a safe, reliable way to add these assets — it’s called wp_enqueue_script() and wp_enqueue_style().

🎯 Why Use wp_enqueue_* Instead of <link> or <script> Tags?

  • ✅ Avoids conflicts with other plugins and themes
  • ✅ Ensures dependencies load in the correct order
  • ✅ Prevents duplicate scripts from loading
  • ✅ Supports WordPress features like script versioning and localization

📁 Step 1: Organize Your Plugin Folder

Let’s set up a proper folder structure:

hello-world-plugin/
├── hello-world-plugin.php
├── css/
│   └── hello-style.css
└── js/
    └── hello-script.js

🧩 Step 2: Enqueue the Files

Inside your main plugin file (hello-world-plugin.php), hook into wp_enqueue_scripts:

add_action( 'wp_enqueue_scripts', 'hello_world_enqueue_assets' );

function hello_world_enqueue_assets() {
    $plugin_url = plugin_dir_url( __FILE__ );
    
    wp_enqueue_style(
        'hello-world-style',
        $plugin_url . 'css/hello-style.css',
        array(),
        '1.0'
    );

    wp_enqueue_script(
        'hello-world-script',
        $plugin_url . 'js/hello-script.js',
        array('jquery'), // dependencies
        '1.0',
        true // load in footer
    );
}

🎨 Step 3: Add Some Styling and Interactivity

hello-style.css

.hello-message {
    text-align: center;
    font-weight: bold;
    color: #0073aa;
}

hello-script.js

jQuery(document).ready(function($) {
    console.log('Hello World Plugin script loaded!');
});

Now, you can add class="hello-message" to your frontend output:

echo '<p class="hello-message">' . esc_html( $message ) . '</p>';

🧠 Bonus Tip: Load Assets Only When Needed

If your plugin has an admin settings page, don’t load your assets on every page — target only where needed using is_admin() or get_current_screen().

💡 Efficient plugins are polite plugins. Only load what’s necessary, when it’s necessary.

✅ Summary

  • 📦 Create organized folders for CSS/JS
  • 🔗 Use wp_enqueue_style() and wp_enqueue_script() for loading assets
  • 🎯 Target frontend or backend only when needed
  • 🎉 Add polish and interactivity to your plugin

Next up, we’ll go beyond basics and look at how to create custom shortcodes and Gutenberg blocks in your plugin. 🧱


🧱 Creating Custom Shortcodes & Gutenberg Blocks

Giving users the ability to insert plugin content directly into pages or posts is a game-changer. You can do this through:

  • Shortcodes — Tiny text snippets like [hello_message] that get replaced with content
  • Gutenberg Blocks — Visual drag-and-drop elements in the block editor

📎 Part 1: Creating a Simple Shortcode

Let’s start with a basic shortcode that displays the saved “Hello World” message:

add_shortcode( 'hello_message', 'hello_world_shortcode' );

function hello_world_shortcode() {
    $message = get_option( 'hello_world_message', 'Hello, World!' );
    return '<p class="hello-message">' . esc_html( $message ) . '</p>';
}

Now users can add [hello_message] anywhere in their posts or pages. 🎉

⚙️ Bonus: Add Attributes to Your Shortcode

You can make your shortcode more flexible by accepting attributes:

function hello_world_shortcode( $atts ) {
    $atts = shortcode_atts( array(
        'color' => '#0073aa',
    ), $atts );

    $message = get_option( 'hello_world_message', 'Hello, World!' );

    return '<p style="color:' . esc_attr( $atts['color'] ) . ';">' . esc_html( $message ) . '</p>';
}

Usage:

[hello_message color="#cc0000"]

🎨 Part 2: Creating a Custom Gutenberg Block

This is more advanced but gives a modern and user-friendly experience. Here’s a very basic way to do it using the @wordpress/scripts build tool (Node.js + React).

🧱 Step 1: Scaffold Your Block

Run this in your plugin directory:

npx @wordpress/create-block hello-world-block

This sets up a full block plugin with build tools, boilerplate code, and everything you need.

🔧 Step 2: Customize the Block

Inside src/edit.js, replace the JSX to pull your plugin’s message:

import { useState, useEffect } from '@wordpress/element';

export default function Edit() {
    const [message, setMessage] = useState('');

    useEffect(() => {
        fetch( '/wp-json/hello/v1/message' )
            .then( res => res.json() )
            .then( data => setMessage( data.message ) );
    }, []);

    return <p>{ message || 'Loading message...' }</p>;
}

This example assumes you’ve exposed your plugin’s message via a custom REST API endpoint — a more advanced technique we’ll save for a future article. 😉

✅ Step 3: Register and Use

Once built, your custom block appears in the Gutenberg editor — users can drag and drop it like any other block.

🛠️ Tip: If you’re not ready for React and npm tools, stick with shortcodes — they work beautifully and are backward-compatible.

🧠 Which Should You Use?

  • Shortcodes: Easy, great for content creators, quick to implement
  • Blocks: Modern, visual, ideal for custom layouts or content components

Coming up: we’ll wrap everything up with final thoughts and tips on best practices for plugin development. 🚀


🚀 Wrapping Up: Final Thoughts & Best Practices

Congratulations! 🎉 You’ve built a working WordPress plugin — from the first line of PHP to creating settings, styling it with CSS, adding JavaScript, and even integrating it into the editor with shortcodes and blocks.

Whether it’s your first or fiftieth plugin, this experience forms the foundation for doing more powerful things with WordPress. Here are some final thoughts and best practices as you level up:

🧭 Best Practices for WordPress Plugin Development

  • Use Namespacing or Prefixes: Prevent function and variable conflicts by prefixing everything (e.g. hello_world_).
  • Keep It Secure: Always sanitize input (sanitize_text_field, etc.) and escape output (esc_html, esc_attr).
  • Use Hooks Wisely: Tap into the right add_action or add_filter to stay “WordPress native.”
  • Don’t Load Everything Everywhere: Enqueue only what’s needed on the frontend or backend.
  • Document Your Code: Helpful comments now will save you (and others) time later.
  • Follow WordPress Coding Standards: Tools like PHPCS can help enforce consistency.

🧪 Testing and Debugging Tips

  • Enable WP_DEBUG: Turn it on in your wp-config.php to catch errors.
  • Use error_log(): Great for simple debugging without breaking output.
  • Try Query Monitor Plugin: A lifesaver for performance issues and hook tracking.
  • Check Console Logs: Don’t forget the browser side of things when working with JS.

🌍 Ready to Share with the World?

Once your plugin is solid, you can consider submitting it to the official WordPress Plugin Repository! Make sure to:

  • Include a proper readme.txt file
  • Follow the WordPress plugin guidelines
  • Use version control (like Git)
  • Test thoroughly before every release

✨ Final Words

Plugins are what make WordPress magical. They turn ordinary sites into online stores, directories, communities, and more. By writing your own, you’re no longer just a WordPress user — you’re a creator, shaping the web one feature at a time.

💡 “The best way to learn is to build.” — So go build. Experiment. Break things. Fix them. And don’t forget to have fun!

Thanks for following along, and keep creating! 🙌