Skip to content
Back to all articles
WordPress5 min readSeptember 30, 2026

How to Create Your First WordPress Plugin (Step by Step)

From an empty folder to a working, secure plugin with a settings page: the header, hooks, prefixes and habits that separate solid plugins from fragile ones.

How to Create Your First WordPress Plugin (Step by Step) article
In this guide
  1. Why a plugin instead of functions.php?
  2. Step 1: The smallest possible plugin
  3. Step 2: Hooks, the heart of every plugin
  4. Step 3: Prefix everything
  5. Step 4: Load assets the WordPress way
  6. Step 5: A settings page with the Settings API
  7. Step 6: Security basics from day one
  8. Skip the boilerplate
  9. Step 7: Activation, deactivation and uninstall
  10. Make it translation-ready
  11. Version it properly
  12. Step 8: Test before you trust it
  13. Where to go next

Most WordPress developers start the same way. You find a useful snippet, paste it into your theme's functions.php, and it works. Then another snippet, and another. A year later, functions.php is 900 lines long, and the day someone switches to a new theme, half the site's features vanish with it.

Writing a plugin is the grown-up version of that habit, and it is far less intimidating than it sounds. A plugin can be a single file with a comment at the top. This guide walks from an empty folder to a clean, secure plugin with its own settings page, covering the header, hooks, naming, the Settings API, and the habits that separate solid plugins from fragile ones.

Why a plugin instead of functions.php?

  • Features survive theme changes. A new design should not break your booking form or your custom post types.
  • You can switch features off by deactivating one plugin, which makes troubleshooting much easier.
  • Code stays organised in one place with a clear purpose.
  • It is reusable across sites and easy to share with a team.

A good rule of thumb: code that changes how the site looks belongs in the theme; code that changes what the site does belongs in a plugin.

Step 1: The smallest possible plugin

Create a folder in wp-content/plugins/, for example acme-tweaks, and inside it a file called acme-tweaks.php:

php
<?php
/**
 * Plugin Name: Acme Tweaks
 * Description: Small site-specific features for Acme.
 * Version: 1.0.0
 * Author: Acme Studio
 * Requires at least: 6.0
 * Requires PHP: 7.4
 * License: GPL v2 or later
 * Text Domain: acme-tweaks
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

That is a valid plugin. WordPress reads the header comment and lists it under Plugins, where you can activate it. The ABSPATH check stops the file from being run directly outside WordPress.

The Requires at least and Requires PHP lines matter: WordPress refuses to activate a plugin on older versions, which prevents fatal errors on sites that cannot run your code.

Step 2: Hooks, the heart of every plugin

Plugins do almost everything through hooks. Actions run your code at a specific moment; filters change a value and return it.

php
// Action: add a line to the footer.
function acme_footer_note() {
    echo &#039;<p class="acme-note">' . esc_html__( 'Thanks for visiting!', 'acme-tweaks' ) . '</p>';
}
add_action( 'wp_footer', 'acme_footer_note' );

// Filter: shorten excerpts to 30 words.
function acme_excerpt_length( $length ) {
    return 30;
}
add_filter( 'excerpt_length', 'acme_excerpt_length' );

Choosing the right hook is half the skill. Register post types on init, load scripts on wp_enqueue_scripts, add admin pages on admin_menu, and register settings on admin_init.

Step 3: Prefix everything

Every WordPress site runs code from many authors in the same global space. If your plugin defines a function called get_settings() and another plugin does too, the site crashes with a fatal error.

Prefix every function, constant, option name and hook with something unique, like acme_. Note that PHP names cannot contain hyphens, so a slug like acme-tweaks becomes the prefix acme_tweaks_. For larger plugins, a PHP class or namespace achieves the same thing more tidily.

Step 4: Load assets the WordPress way

Never hard-code script or style tags. Enqueue them so WordPress can manage dependencies and avoid loading the same file twice:

php
function acme_enqueue_assets() {
    wp_enqueue_style(
        'acme-tweaks',
        plugin_dir_url( __FILE__ ) . 'assets/css/frontend.css',
        array(),
        '1.0.0'
    );
}
add_action( 'wp_enqueue_scripts', 'acme_enqueue_assets' );

In the admin, load your CSS and JavaScript only on your own plugin's screen by checking the $hook value passed to admin_enqueue_scripts. Loading assets on every admin page slows down the whole dashboard.

Step 5: A settings page with the Settings API

The Settings API handles saving, sanitizing and security checks for you. Register a setting, a section and a field on admin_init:

php
function acme_register_settings() {
    register_setting( 'acme_tweaks', 'acme_tweaks_options', array(
        'type'              =&gt; 'array',
        'sanitize_callback' =&gt; 'acme_sanitize_options',
        'default'           =&gt; array( 'enabled' =&gt; 1 ),
    ) );
    add_settings_section( 'acme_main', __( 'Settings', 'acme-tweaks' ), '__return_false', 'acme_tweaks' );
    add_settings_field( 'acme_enabled', __( 'Enable features', 'acme-tweaks' ), 'acme_render_enabled', 'acme_tweaks', 'acme_main' );
}
add_action( 'admin_init', 'acme_register_settings' );

Then render the form on your admin page with settings_fields(), do_settings_sections() and submit_button(). The Settings API adds the nonce and saves through options.php, and your sanitize callback cleans the values before they are stored.

Step 6: Security basics from day one

Four habits prevent most plugin vulnerabilities: sanitize input, escape output, verify nonces, and check capabilities with current_user_can(). Our guide to WordPress security functions explains each one with examples, and the WordPress Functions Reference has copy-ready snippets.

Skip the boilerplate

Setting all of this up by hand is a great way to learn once, but tedious every time after. The WordPress Plugin Generator creates a ready-to-install ZIP with your details filled in: a valid header, a main plugin class, prefixed functions and options, text-domain loading, front-end assets, a readme.txt in the WordPress.org format, and optional extras: an admin page with tabs, a working Settings API form, an example widget, and documented hooks other developers can use. Admin CSS loads only on the plugin's own page.

Step 7: Activation, deactivation and uninstall

  • Activation hook: set default options or flush rewrite rules once, for example after registering a custom post type.
  • Deactivation hook: unschedule cron events and clean up temporary data, but keep the user's settings.
  • uninstall.php: delete your options and data when the plugin is deleted, so nothing is left behind.

Make it translation-ready

Wrap every piece of text users see in a translation function, such as __() for returning text and esc_html_e() for printing it, always with your text domain: esc_html__( 'Settings saved.', 'acme-tweaks' ). Load the translations with load_plugin_textdomain() and keep a languages folder in the plugin. It costs almost nothing when you start, and it lets anyone translate your plugin into their language later.

Version it properly

Keep the version number in one constant and use it everywhere: the plugin header, the asset version (so browsers fetch new CSS after an update) and the Stable tag in readme.txt. Put the plugin in Git from the first commit, and write a short changelog entry for every release. Future you will be grateful when something breaks and you need to know what changed.

Step 8: Test before you trust it

  • Turn on WP_DEBUG on a local or staging site and fix every warning.
  • Test with a default theme and with other common plugins active.
  • Deactivate and reactivate it to make sure nothing breaks.
  • Check the front end and admin on mobile.
  • Run the site through the WordPress Security Checker before going live.

Where to go next

A common next step is adding your own content type. Our guide to WordPress custom post types shows how to register one properly, and the code belongs in exactly the kind of plugin you have just created.

Your first plugin does not need to be impressive. It needs a clear header, prefixed names, the right hooks and a few security habits. Get those right once, and every plugin after that is just a new idea in a structure you already trust.

Was this article helpful?

Found this guide useful?

Share it with someone who is struggling with the same problem.

Free tool · No sign-up

WordPress Plugin Boilerplate Generator

Generate a WordPress plugin boilerplate with your name, prefix and requirements, plus an optional admin page, saved settings, a widget and documented hooks. Download a ready-to-install ZIP.

Open tool
Toolyconvert Team profile photo

Written by

Toolyconvert Team

Web Development & Software Engineering Team

The Toolyconvert Team builds, maintains, and improves free online tools designed to make everyday digital tasks faster and easier. Our team works across web development, software engineering, APIs, performance optimization, testing, and user experience to create reliable and practical tools.