WordPress Plugin Development from Scratch: Architecture & Lifecycle

While theme development controls the visual presentation, Plugin Development is where real full-stack software engineering happens in WordPress. Plugins allow you to encapsulate business logic — such as an automated course enrollment system, an algorithmic calculator, or a third-party CRM integration — into a portable, standalone package that can be distributed to clients or published on the official WordPress.org repository. In this class, we build a production plugin called Veewom Quick Notice.

The Plugin Directory & File Structure

Navigate to /wp-content/plugins/ and create a directory named after your plugin slug:

/wp-content/plugins/veewom-quick-notice/

Inside this folder, create your primary PHP file with the same name: veewom-quick-notice.php.

Step 1: The Standard Plugin Header Comment

WordPress identifies a plugin strictly by parsing the comment header at the top of the main PHP file:

<?php
/**
 * Plugin Name:       Veewom Quick Notice
 * Plugin URI:        https://veewom.com/wordpress/
 * Description:       Displays customizable alert notices and banner shortcodes across your site.
 * Version:           1.0.0
 * Requires at least: 6.0
 * Requires PHP:      8.0
 * Author:            Veewom Engineering Team
 * Author URI:        https://veewom.com
 * License:           GPL v2 or later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:       veewom-quick-notice
 */

// Block direct execution outside WordPress
if ( ! defined('ABSPATH') ) {
    exit;
}

Step 2: Activation and Deactivation Lifecycle Hooks

WordPress provides specialized lifecycle hooks to execute setup routines (like creating custom database tables or seeding options) when a user clicks "Activate", and cleanup routines on "Deactivate":

// 1. Activation Hook
register_activation_hook(__FILE__, 'veewom_notice_activate');
function veewom_notice_activate() {
    // Add default options if not already present
    if ( ! get_option('veewom_notice_text') ) {
        add_option('veewom_notice_text', 'Welcome to Veewom Tutorials!');
    }
}

// 2. Deactivation Hook
register_deactivation_hook(__FILE__, 'veewom_notice_deactivate');
function veewom_notice_deactivate() {
    // Clean up temporary caches or transients
    delete_transient('veewom_notice_cache');
}

Step 3: Creating an Administrative Settings Menu in wp-admin

To give administrators a dedicated control panel in the left sidebar, use add_menu_page() hooked into admin_menu:

add_action('admin_menu', 'veewom_notice_add_admin_menu');

function veewom_notice_add_admin_menu() {
    add_menu_page(
        __('Quick Notice Settings', 'veewom-quick-notice'), // Page Title
        __('Quick Notice', 'veewom-quick-notice'),          // Menu Label
        'manage_options',                                   // Required Capability
        'veewom-quick-notice',                              // Menu Slug
        'veewom_notice_render_settings_page',               // Callback Function
        'dashicons-megaphone',                              // Dashicon
        25                                                  // Menu Position
    );
}

function veewom_notice_render_settings_page() {
    // Save settings if form submitted
    if ( isset($_POST['veewom_save_notice']) && check_admin_referer('veewom_notice_nonce') ) {
        $notice = sanitize_text_field($_POST['notice_message']);
        update_option('veewom_notice_text', $notice);
        echo '<div class="updated"><p>Settings successfully saved!</p></div>';
    }

    $current_text = get_option('veewom_notice_text', '');
    ?>
    <div class="wrap">
        <h1>Veewom Quick Notice Settings</h1>
        <form method="post" action="">
            <?php wp_nonce_field('veewom_notice_nonce'); ?>
            <table class="form-table">
                <tr>
                    <th><label for="notice_message">Banner Message:</label></th>
                    <td>
                        <input type="text" name="notice_message" id="notice_message" value="<?php echo esc_attr($current_text); ?>" class="regular-text" />
                    </td>
                </tr>
            </table>
            <input type="submit" name="veewom_save_notice" class="button button-primary" value="Save Changes" />
        </form>
    </div>
    <?php
}

Step 4: Registering a Custom Shortcode [quick_notice]

Shortcodes allow content creators to embed your plugin's dynamic output anywhere inside a Gutenberg block or page by typing [quick_notice type="warning"]:

// Register [quick_notice] Shortcode
add_shortcode('quick_notice', 'veewom_render_notice_shortcode');

function veewom_render_notice_shortcode($atts, $content = null) {
    // Parse user attributes with default fallbacks
    $args = shortcode_atts(array(
        'type' => 'info', // default type
    ), $atts, 'quick_notice');

    $border_color = ($args['type'] === 'warning') ? '#ef4444' : '#ff6600';
    $message = $content ? $content : get_option('veewom_notice_text');

    return '<div style="border-left: 5px solid ' . esc_attr($border_color) . '; background: #fffaf6; padding: 14px 18px; margin: 15px 0;">' 
            . esc_html($message) . 
           '</div>';
}

Security Imperative: Data Sanitization & Escaping

In professional code audits, any plugin failing the Sanitize Early, Escape Late rule is rejected. Always clean incoming input using sanitize_text_field() or intval() before saving to the database, and always escape output using esc_html(), esc_attr(), or esc_url() before echoing to HTML.

Frequently Asked Questions (FAQ) - Student & Interview Review

Q1. What is the difference between uninstall.php and register_deactivation_hook()?

`register_deactivation_hook()` runs when a user clicks 'Deactivate' and should NEVER delete user data or database tables. `uninstall.php` executes only when a user explicitly clicks **'Delete'**, which is the appropriate time to prune options and drop custom tables.

Q2. How can I prefix functions to avoid PHP namespace collisions?

Always prefix all function names, constants, and global variables with a unique vendor prefix (e.g., `veewom_`), or encapsulate your plugin logic within an Object-Oriented PHP Class or PHP Namespace.

Q3. Can a WordPress plugin create its own custom database tables?

Yes! Using the core function `dbDelta()`, plugins can execute SQL DDL statements on activation to create high-speed custom tables with bespoke indexes.

Explore Related WordPress Tutorials & Next Steps

Expand your CMS mastery by studying these tightly integrated WordPress development topics:

Action & Filter Hooks

The foundational building blocks for every WordPress plugin.

Security Hardening

Implement nonces, capability checks, and data sanitization in plugins.

Custom Post Types (CPT)

Register custom post types inside plugins rather than themes.

WordPress REST API

Register custom REST API routes using register_rest_route().

Share Share on Facebook Share on Twitter Share on LinkedIn Pin on Pinterest Share on Reddit

You may also like this!