SponsoredHosinger Special Offer

WP+ WordPress Plugin Development

Build WordPress plugins from scratch: actions and filters, shortcodes, settings pages, custom post types, meta boxes, AJAX, REST endpoints, custom tables, cron and blocks.

Your First Plugin: Folder, File and Header

WordPress Plugin Development Lesson 2 of 27 ~3 min read

Overview

A plugin starts as a single PHP file inside its own folder in wp-content/plugins/, with a comment header that tells WordPress its name, version and requirements — that is all it takes to appear on the Plugins screen.

Create the folder and main file

cd wp-content/plugins
mkdir gdc-books
touch gdc-books/gdc-books.php

Name the main file after the folder. WordPress identifies a plugin by the path gdc-books/gdc-books.php, and that string is what it stores when the plugin is activated.

The plugin header

<?php
/**
 * Plugin Name:       GDC Books
 * Plugin URI:        https://gizdevcraft.in/learn/wordpress-plugins
 * Description:       Manage a catalogue of books with genres, details, a shortcode and a block.
 * Version:           1.0.0
 * Requires at least: 6.4
 * Requires PHP:      7.4
 * Author:            Your Name
 * Author URI:        https://example.com
 * License:           GPL v2 or later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:       gdc-books
 * Domain Path:       /languages
 */

// Stop direct access: this file must only ever be loaded by WordPress.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

Go to Plugins → Installed Plugins. GDC Books is listed, with your description and version. Activate it — nothing visible happens yet, and nothing breaks. That is a working plugin.

The header fields

FieldRequired?Purpose
Plugin NameYesThe only field WordPress strictly needs.
VersionRecommendedUsed for upgrades and for cache-busting your assets.
Requires at least / Requires PHPRecommendedWordPress refuses to activate the plugin on older versions instead of letting it crash.
Text DomainFor translationMust match the folder name, gdc-books.
LicenseFor WordPress.orgGPL-compatible, because WordPress is GPL.
Requires PluginsOptionalComma-separated slugs of plugins this one depends on (WordPress 6.5+).

Why the ABSPATH check?

Every PHP file in your plugin can be requested directly by URL: https://site.com/wp-content/plugins/gdc-books/gdc-books.php. Run that way, WordPress is not loaded, and code that calls WordPress functions throws errors that can reveal file paths. ABSPATH is defined only when WordPress itself is running, so the check exits early. Put it at the top of every PHP file.

Your first hook

Add this below the guard. It appends a line to the end of every single post:

<?php
/**
 * Adds a thank-you line after the content of single posts.
 *
 * @param string $content The post content.
 * @return string The content with the note appended.
 */
function gdc_books_thank_you_note( $content ) {
    if ( is_singular( 'post' ) && in_the_loop() && is_main_query() ) {
        $content .= '<p class="gdc-books-note">' . esc_html__( 'Thanks for reading!', 'gdc-books' ) . '</p>';
    }

    return $content; // A filter must always return the value.
}
add_filter( 'the_content', 'gdc_books_thank_you_note' );

Open any post: the note appears under it. Deactivate the plugin: it disappears, and the post content in the database was never touched. That is the plugin model in miniature.

Watch out: Never leave a closing ?> at the end of a plugin file. Any whitespace after it is sent to the browser before WordPress sends headers, causing "headers already sent" errors on redirects and logins.

Practice

  • Create gdc-books/gdc-books.php with the full header and activate it.
  • Add the thank-you filter, then change the condition so it also appears on pages.
  • Visit the plugin file's URL directly in the browser and confirm you get a blank response, not an error.
Create a free account to save which lessons you've finished. Save my progress