How to Create a WordPress Plugin From Scratch (2026 Step-by-Step Guide) | Growwp
growwp.in Free WordPress Tutorials
WordPress Plugin Development

How to Create a WordPress Plugin From Scratch (My Complete 2026 Process)

No copy-paste theory — just the exact folder structure, hooks, and habits I use every time I build a plugin, broken down the way I wish someone had explained it to me three years ago.

Why You Can Trust This Guide

I've been writing WordPress plugins professionally since 2023. Every code block here is from a plugin I've actually shipped, not copied from a tutorial.

Every snippet is tested on a fresh WordPress 6.7+ install before publishing. If it's in this guide, it ran without errors on my screen first.

I revisit this guide whenever a WordPress core update changes how plugins should be built, so the steps stay current, not frozen in 2023.

What Is a WordPress Plugin, Really?

A WordPress plugin is a self-contained package of PHP code that adds, removes, or changes functionality on a site without editing WordPress's core files or your theme. It lives in its own folder inside wp-content/plugins/, and it talks to WordPress through a system of "hooks" instead of modifying anything directly.

That separation is the entire point. Your theme should control how a site looks. A plugin should control what a site does — a contact form, a custom post type, a tracking script, a shortcode. Mix the two, and the moment you switch themes, your functionality disappears with it. I've fixed that exact mistake for three different clients in my first year alone.

Before You Start: What You Actually Need

  • A local WordPress install — I use Local by WP Engine, but XAMPP or MAMP work fine too.
  • A code editor. VS Code with the PHP Intelephense extension is what I run daily.
  • Basic PHP comfort: variables, functions, arrays, and if/else logic. You don't need to be advanced.
  • Patience for one wrong character breaking an entire page. It happens to everyone, including me, still.
STEP 01

Set Up a Local WordPress Environment

Never write your first plugin directly on a live site. Install WordPress locally so you can break things freely — and you will break things. Local by WP Engine takes about five minutes: download it, click "Create a new site," and you'll have a working WordPress install with admin access on your own machine.

Why this matters

Testing locally means zero risk to a real site, and you can reset the whole environment in seconds if something breaks.

STEP 02

Create the Plugin Folder and Main File

Inside wp-content/plugins/, create a new folder. Name it exactly how you'll name your plugin — lowercase, hyphen-separated. I'll use my-first-plugin for this guide. Inside that folder, create one PHP file with the same name: my-first-plugin.php. That file is what WordPress will read.

wp-content/plugins/my-first-plugin/
my-first-plugin/
  my-first-plugin.php
  assets/
    style.css
    script.js
  readme.txt
STEP 03

Write the Plugin Header

This is the part beginners skip and then wonder why their plugin never shows up in the dashboard. The header is a PHP comment block at the very top of your main file. WordPress parses it to know your plugin's name, version, and author — without it, your file is just inert PHP that WordPress ignores completely.

my-first-plugin.php
<?php
/**
 * Plugin Name: My First Plugin
 * Plugin URI: https://growwp.in
 * Description: A simple starter plugin built step by step.
 * Version: 1.0.0
 * Author: Akash Vishwakarma
 * Author URI: https://growwp.in
 * License: GPL v2 or later
 * Text Domain: my-first-plugin
 */

// Block direct access to this file.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}
Don't skip the ABSPATH check

Without it, someone could open this file directly through a browser URL and trigger errors or expose file paths. It's one line, and I add it to every plugin I write.

STEP 04

Activate Your Plugin and Confirm It Works

Log in to wp-admin → Plugins. You should see "My First Plugin" listed with the description and author you wrote in the header. Click Activate. If nothing shows up, double-check that your header comment block sits at the very top of the file with no stray characters before <?php.

STEP 05

Make It Do Something — Your First Hook

This is where it stops being a blank file and becomes an actual plugin. WordPress runs on hooks: actions let you run code at a specific moment, and filters let you change data before WordPress uses it. Let's add a small credit line to the site footer using the wp_footer action.

my-first-plugin.php
<?php
function gwp_add_footer_credit() {
    echo '<p class="gwp-credit">This site runs My First Plugin.</p>';
}
add_action( 'wp_footer', 'gwp_add_footer_credit' );

Save, refresh your site's front end, and you'll see the line appear right before the closing </body> tag. Notice the function name starts with gwp_ — that prefix matters, and I'll explain why in the mistakes section below.

STEP 06

Add a Shortcode

Shortcodes let users drop dynamic content into posts and pages using simple tags like [gwp_welcome]. They're one of the most common things clients ask for, so it's worth getting comfortable early.

my-first-plugin.php
<?php
function gwp_welcome_shortcode( $atts ) {
    $atts = shortcode_atts( array(
        'name' => 'Friend',
    ), $atts );

    return '<div class="gwp-welcome">Welcome, ' . esc_html( $atts['name'] ) . '!</div>';
}
add_shortcode( 'gwp_welcome', 'gwp_welcome_shortcode' );

Now typing [gwp_welcome name="Akash"] into any post outputs "Welcome, Akash!" Notice I used esc_html() around the attribute — never echo a value straight from user input without escaping it first.

STEP 07

Enqueue CSS and JavaScript the Right Way

Never link a stylesheet or script with a raw <link> or <script> tag in a plugin. Use wp_enqueue_scripts so WordPress can manage loading order, avoid duplicate files, and let other plugins play nicely with yours.

my-first-plugin.php
<?php
function gwp_enqueue_assets() {
    wp_enqueue_style(
        'gwp-style',
        plugin_dir_url( __FILE__ ) . 'assets/style.css',
        array(),
        '1.0.0'
    );

    wp_enqueue_script(
        'gwp-script',
        plugin_dir_url( __FILE__ ) . 'assets/script.js',
        array(),
        '1.0.0',
        true
    );
}
add_action( 'wp_enqueue_scripts', 'gwp_enqueue_assets' );
STEP 08

Build a Settings Page in wp-admin

Most real plugins need at least one settings screen. Use add_options_page() to register the page and the WordPress Settings API to handle saving — it gives you nonce protection and sanitization callbacks for free.

my-first-plugin.php
<?php
function gwp_register_settings_page() {
    add_options_page(
        'My First Plugin Settings',
        'My First Plugin',
        'manage_options',
        'gwp-settings',
        'gwp_render_settings_page'
    );
}
add_action( 'admin_menu', 'gwp_register_settings_page' );

function gwp_render_settings_page() {
    ?>
    <div class="wrap">
        <h1>My First Plugin Settings</h1>
        <form method="post" action="options.php">
            <?php
            settings_fields( 'gwp_settings_group' );
            do_settings_sections( 'gwp-settings' );
            submit_button();
            ?>
        </form>
    </div>
    <?php
}
STEP 09

Secure Every Input — Nonces, Sanitize, Escape

This is the step that separates a plugin you can actually ship from one that gets flagged in a security review. Three habits, every single time: verify a nonce before processing a form, sanitize data coming in, and escape data going out.

my-first-plugin.php
<?php
if ( ! isset( $_POST['gwp_nonce'] ) || ! wp_verify_nonce( $_POST['gwp_nonce'], 'gwp_save_action' ) ) {
    wp_die( 'Security check failed.' );
}

// Sanitize incoming data.
$safe_input = sanitize_text_field( wp_unslash( $_POST['gwp_name'] ) );

// Escape on the way out.
echo '<p>Hello, ' . esc_html( $safe_input ) . '</p>';
This is non-negotiable

I've audited plugins that skipped this and got hit with form spam and stored XSS within weeks of launch. Three lines of security code now save days of cleanup later.

STEP 10

Add Activation and Deactivation Hooks

Use these to set up anything your plugin needs on activation — like a default option — and clean it up on deactivation, so you don't leave orphaned data in the database.

my-first-plugin.php
<?php
function gwp_on_activate() {
    add_option( 'gwp_version', '1.0.0' );
}
register_activation_hook( __FILE__, 'gwp_on_activate' );

function gwp_on_deactivate() {
    delete_option( 'gwp_version' );
}
register_deactivation_hook( __FILE__, 'gwp_on_deactivate' );
STEP 11

Make It Translation-Ready

Even if you only plan an English version today, wrapping visible text in translation functions costs nothing now and saves a full rewrite later. Use the Text Domain you set in your header.

my-first-plugin.php
<?php
echo esc_html__( 'Welcome to my plugin!', 'my-first-plugin' );
STEP 12

Debug Properly Using WP_DEBUG

Stop guessing why something isn't working. Open wp-config.php on your local install and turn on debugging so PHP errors show up in a log file instead of silently failing or breaking the page.

wp-config.php
<?php
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );

With this on, every error gets logged to wp-content/debug.log instead of showing on screen — readable for you, invisible to visitors. I keep this on for every local build, no exceptions.

STEP 13

Package and Deploy Your Plugin

Once it's tested, zip the entire plugin folder — not just the PHP file — keeping the folder structure intact. That zip is what you upload through wp-admin → Plugins → Add New → Upload Plugin on any other site, or what you submit to the WordPress.org Plugin Directory for review if you're releasing it publicly.

Before zipping, I always do one final pass: deactivate and reactivate the plugin on a clean install, check the browser console for JS errors, and read through debug.log one more time. Five minutes here has saved me from shipping broken plugins more than once.

Download Free PDF Guide

Get the complete step-by-step WordPress plugin development guide as a beautifully formatted PDF. Perfect for offline reading and reference.

Download PDF

Mistakes I See Beginners Make (Because I Made Them Too)

  • Skipping function name prefixes.

    A function called save_settings() will silently clash with another plugin using the same name and crash the site. Prefix everything — I use gwp_ across all my plugins.

  • Forgetting the ABSPATH check.

    Leaves the file directly accessible by URL, which can expose errors and server paths to anyone who finds it.

  • Echoing raw user input.

    Printing form data straight back to the page without esc_html() opens the door to stored XSS — one of the most common reasons plugins fail security review.

  • Loading scripts on every page.

    Enqueuing your CSS/JS globally instead of only where it's needed quietly slows down the entire site, not just the page that uses your plugin.

  • Skipping readme.txt.

    If you ever plan to submit to the WordPress.org repository, the readme.txt format is mandatory — writing it after the fact wastes more time than writing it as you go.

Frequently Asked Questions

Yes, at least basic PHP — variables, functions, conditionals, and arrays — since plugin code is plain PHP running through WordPress's hook system. You don't need to be an expert; most plugin code follows repeatable patterns like the ones in this guide.
A theme controls how a site looks; a plugin controls what a site does. Functionality built in a plugin keeps working even if you change your theme later, which is why custom functionality should never live only inside theme files.
You can assemble very basic functionality with no-code plugin generators, but you hit a ceiling fast. Anything beyond simple shortcodes or form fields needs hand-written PHP, which is what this guide focuses on.
Inside wp-content/plugins/your-plugin-name/, with a main PHP file matching the folder name. WordPress scans this directory automatically and lists every valid plugin header it finds in the dashboard.
Build and test on a local WordPress install first — Local or XAMPP both work — then move to a staging site before production. I never write plugin code directly on a live client site.
A hook is a point in WordPress's execution where your code can run. Actions let you add new behavior, and filters let you modify existing data before WordPress uses it.
Create a free developer account, submit your code for a manual security review through the Plugin Directory, and once approved you get SVN access to upload your files. Reviews typically take anywhere from a few days to a few weeks.
Either works — WordPress core mixes both styles. Small utility plugins are fine procedurally, like in this guide; switching to OOP classes makes sense once a plugin grows past four or five files.

Conclusion

Building your first WordPress plugin isn't about memorizing every function in the codex — it's about understanding four things: the folder structure, the plugin header, the hook system, and basic security habits. Once those click, every plugin you build afterward is just a variation on the same pattern.

Start small. Get the footer credit working, then the shortcode, then the settings page. Don't try to build a complex plugin on day one. If you'd rather start from working code than a blank file, grab the free PDF guide and build on top of it. If you get stuck, that's normal — I still hit walls on plugins three years in. Read the error, check the line it points to, and work backward from there.

Written by Akash Vishwakarma for growwp.in — Free WordPress & coding tutorials.

Latest Articles

Explore our latest blog posts, tutorials, SEO tips and WordPress guides.