Lesson 3: Understanding the WordPress Plugin Lifecycle

In the previous lesson, we successfully installed and activated the Flipnzee Auctions plugin on our WordPress website. Even though the plugin doesn’t yet display any visible functionality, WordPress already recognizes it as a valid plugin and executes its code whenever appropriate.

But have you ever wondered what actually happens behind the scenes?

How does WordPress discover plugins?

When does it read the plugin header?

Why does the ABSPATH constant already exist?

When are activation hooks executed?

And why do they run only once?

Understanding these questions is one of the biggest differences between simply copying WordPress code and becoming a confident WordPress plugin developer.

In this lesson, we’ll follow the complete journey of our plugin—from the moment a visitor requests a page until our code is executed.


Learning Objectives

By the end of this lesson, you’ll understand:

  • How WordPress discovers installed plugins.
  • What happens during plugin activation.
  • What happens during every page request.
  • Why the ABSPATH security check works.
  • When your plugin code executes.
  • The purpose of activation and deactivation hooks.
  • Why understanding the plugin lifecycle makes debugging easier.

Why This Matters

Many beginners think WordPress “magically” loads plugins.

It doesn’t.

There is a very specific sequence of events.

Once you understand that sequence, many concepts become much easier:

  • Hooks
  • Filters
  • AJAX
  • REST APIs
  • Database creation
  • Custom Post Types
  • Scheduled tasks

Almost every advanced WordPress feature depends on understanding when your code runs.


The Journey Begins

Imagine someone visits:

https://flipnzee.com

The browser sends a request to the web server.

The web server loads WordPress.

WordPress then begins its own startup process.

Eventually it reaches the point where it starts loading plugins.


Step 1 — WordPress Finds Active Plugins

WordPress stores the list of active plugins in its database.

During startup it reads that list.

If your plugin is active:

Flipnzee Auctions

WordPress prepares to load:

flipnzee-auctions/flipnzee-auctions.php

This is why the main plugin file is so important.


Step 2 — WordPress Reads the Plugin Header

Before executing the plugin, WordPress reads the comment block at the top of the file.

/**
 * Plugin Name: Flipnzee Auctions
 * Version: 1.0.0
 * ...
 */

This information is displayed on:

Plugins → Installed Plugins

Notice something interesting.

The plugin header is metadata.

PHP ignores it.

WordPress reads it.


Step 3 — PHP Begins Executing Your File

Now PHP starts reading your code.

The very first executable line is:

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

At this point WordPress has already defined:

ABSPATH

So the condition evaluates to:

false

The plugin continues loading.

If someone tried opening the PHP file directly in a browser:

https://example.com/wp-content/plugins/flipnzee-auctions/flipnzee-auctions.php

ABSPATH wouldn’t exist.

The plugin would immediately exit.

That’s why this simple security check is so important.


Step 4 — Constants Are Defined

Next WordPress executes:

define('FLIPNZEE_AUCTION_VERSION', '1.0.0');

Then

define('FLIPNZEE_AUCTION_PATH', ...);

Then

define('FLIPNZEE_AUCTION_URL', ...);

These constants remain available throughout the rest of the request.


Step 5 — Activation Hooks Are Registered

WordPress encounters:

register_activation_hook(...)

Notice the wording carefully.

We are registering the activation hook.

We are not executing it.

This often confuses beginners.

WordPress simply remembers:

“If this plugin is activated in the future, run this function.”


Step 6 — Additional Files Are Loaded

Next we load:

includes/class-loader.php

PHP reads the file.

The class becomes available.

Then we create:

new Flipnzee_Auction_Loader();

Its constructor executes immediately.

Right now the constructor is empty.

Later it will register all our actions, filters, REST routes, AJAX handlers, database classes, auction engine, payment system, and more.


The Complete Lifecycle

Here’s the entire process.

Browser Request
        │
        ▼
Web Server
        │
        ▼
WordPress Starts
        │
        ▼
Find Active Plugins
        │
        ▼
Read Plugin Header
        │
        ▼
Execute PHP
        │
        ▼
Security Check
        │
        ▼
Define Constants
        │
        ▼
Register Hooks
        │
        ▼
Load Classes
        │
        ▼
Plugin Ready

Every page request follows this sequence.


What Happens During Activation?

Activation is different.

It occurs only when you click:

Activate Plugin

WordPress performs:

Load Plugin

↓

Execute Activation Function

↓

Return Control

Your activation function currently contains:

flush_rewrite_rules();

Later we’ll expand it to:

  • Create database tables.
  • Create default settings.
  • Set plugin version.
  • Prepare the auction system.

What Happens During Deactivation?

When you deactivate the plugin:

WordPress executes:

flipnzee_auction_deactivate()

Currently it refreshes rewrite rules.

Later we’ll also:

  • Remove scheduled tasks.
  • Clear caches.
  • Perform cleanup.

Notice that we won’t delete auction data during deactivation.

Users expect their data to remain if they reactivate the plugin later.


Understanding One Important Difference

Many beginners think:

Activation happens every time a page loads.

It doesn’t.

Activation occurs once.

Normal plugin loading occurs on every request.

Understanding this distinction prevents many common mistakes.


Improving Our Development Workflow

As our project grows, we’ll start generating temporary files such as plugin ZIP archives.

Rather than storing these generated files in Git, professional developers use a .gitignore file to tell Git which files should be ignored.

In the next lesson, we’ll create our first .gitignore file and begin adopting even more professional development practices.


Lesson Summary

In this lesson, we explored the complete lifecycle of a WordPress plugin. We learned how WordPress discovers plugins, reads plugin headers, executes PHP code, registers hooks, and loads classes. We also distinguished between activation, deactivation, and the normal loading process that occurs on every page request.

Understanding this lifecycle gives us a strong conceptual foundation for every feature we’ll build in the remaining lessons.


Key Takeaways

  • ✓ WordPress loads active plugins during every request.
  • ✓ Plugin headers are read by WordPress, not PHP.
  • ABSPATH exists because WordPress has already started.
  • ✓ Activation hooks are registered during loading but execute only during activation.
  • ✓ Classes are loaded only after the main plugin file executes.
  • ✓ Understanding the plugin lifecycle makes debugging much easier.

Common Mistakes

  • Assuming activation hooks run on every page load.
  • Placing expensive operations outside hooks, causing them to execute on every request.
  • Removing user data during plugin deactivation.
  • Confusing plugin registration with plugin execution.

Git Commands Used

git add .

git commit -m "Lesson 3: Understand the WordPress plugin lifecycle"

git push

Project Status

✅ Development environment

✅ Plugin skeleton

✅ Plugin installation

✅ Plugin lifecycle

⬜ .gitignore

⬜ Database tables

⬜ Auction data model

⬜ Bidding engine

⬜ Escrow

⬜ Payment gateways

⬜ Website transfer

⬜ Version 1.0

Developer’s Notebook

One of the biggest milestones in becoming a professional WordPress developer is realizing that your code doesn’t run in isolation. Every plugin participates in WordPress’s startup process. The better you understand that process, the easier it becomes to write efficient, secure, and maintainable plugins. Throughout the remainder of this series, we’ll continue referring back to the plugin lifecycle as we introduce hooks, database tables, AJAX, REST APIs, and background tasks.


Looking Ahead

In Lesson 4, we’ll create our first .gitignore file and begin preparing the project for long-term development. We’ll also discuss which files belong in Git, which should never be committed, and why professional developers treat generated files differently from source code.

Lesson 1: Creating Your First WordPress Plugin

Welcome to Lesson 1 of the Building Flipnzee Auctions series.

In the previous lesson, we created our GitHub repository, launched GitHub Codespaces, organized our project, and learned the basics of version control.

Now it’s time to write our first PHP code.

By the end of this lesson, you’ll have a WordPress plugin that appears in the Plugins page of your WordPress website and can be activated just like any other plugin.

Although the plugin won’t do anything yet, this is an exciting milestone because we’re laying the foundation for everything that follows.


What You’ll Learn

In this lesson you’ll learn how to:

  • Create the WordPress plugin folder
  • Create the main plugin file
  • Understand the plugin header
  • Protect your plugin from direct access
  • Define reusable plugin constants
  • Register activation and deactivation hooks
  • Create a simple loader class
  • Commit your changes to GitHub

Step 1: Enter the Plugin Folder

Open the integrated terminal in GitHub Codespaces.

Navigate into the plugin folder:

cd flipnzee-auctions

Confirm your location:

pwd

You should see something similar to:

/workspaces/flipnzee-auctions/flipnzee-auctions

From now on, everything we create belongs inside this folder.


Step 2: Create the Main Plugin File

Create the plugin’s main PHP file.

GUI Method

Click New File in the Explorer.

Create:

flipnzee-auctions.php

Terminal Method

touch flipnzee-auctions.php

Open it:

code flipnzee-auctions.php

Step 3: Add the Plugin Header

Copy the following code into the file.

<?php
/**
 * Plugin Name: Flipnzee Auctions
 * Plugin URI: https://flipnzee.com
 * Description: Professional website auction platform for Flipnzee.
 * Version: 1.0.0
 * Author: Splendid Digital Solutions
 * Author URI: https://flipnzee.com
 * License: GPL v2 or later
 * Text Domain: flipnzee-auctions
 * Domain Path: /languages
 * Requires at least: 6.5
 * Requires PHP: 8.1
 */

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

Save the file.

Congratulations!

You’ve just created the smallest possible WordPress plugin.


Understanding the Plugin Header

Everything inside the comment block is called the Plugin Header.

When WordPress scans the plugins directory, it looks for these special comments.

Let’s understand each line.

Plugin Name

Plugin Name: Flipnzee Auctions

This is the name displayed on the Installed Plugins page.


Plugin URI

Plugin URI: https://flipnzee.com

This points users to the official plugin website.


Description

Description: Professional website auction platform for Flipnzee.

A short explanation shown beneath the plugin name.


Version

Version: 1.0.0

Every release should have a version number.

Later we’ll learn about semantic versioning.


Author

Author: Splendid Digital Solutions

Displays the plugin developer.


Author URI

Author URI: https://flipnzee.com

Links to your website.


Text Domain

Used for translating the plugin into different languages.


Requires PHP

Requires PHP: 8.1

Prevents installation on servers running older PHP versions.


Step 4: Protect Against Direct Access

Immediately below the plugin header we added:

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

Why?

Imagine someone tries to visit:

https://example.com/wp-content/plugins/flipnzee-auctions/flipnzee-auctions.php

directly in their browser.

Without this check, PHP would execute the file outside of WordPress.

By checking whether ABSPATH exists, we ensure the file only runs when WordPress has already been loaded.

This is one of the simplest and most important WordPress security practices.


Step 5: Define Plugin Constants

Below the security check add:

define('FLIPNZEE_AUCTION_VERSION', '1.0.0');

define('FLIPNZEE_AUCTION_PATH', plugin_dir_path(__FILE__));

define('FLIPNZEE_AUCTION_URL', plugin_dir_url(__FILE__));

Constants allow us to define values once and reuse them throughout the plugin.

For example:

FLIPNZEE_AUCTION_PATH

is much cleaner than repeatedly writing:

plugin_dir_path(__FILE__)

Step 6: Register the Activation Hook

Add:

function flipnzee_auction_activate() {

    flush_rewrite_rules();

}

register_activation_hook(__FILE__, 'flipnzee_auction_activate');

This function runs automatically when the plugin is activated.

Today it only refreshes WordPress rewrite rules.

Later it will also create our database tables.


Step 7: Register the Deactivation Hook

Add:

function flipnzee_auction_deactivate() {

    flush_rewrite_rules();

}

register_deactivation_hook(__FILE__, 'flipnzee_auction_deactivate');

This runs whenever the plugin is deactivated.


Step 8: Create the Includes Folder

Professional plugins avoid placing thousands of lines inside one file.

Create a folder named:

includes

Inside it, create a new file:

class-loader.php

Step 9: Load the Loader Class

Back in flipnzee-auctions.php, add:

if (file_exists(FLIPNZEE_AUCTION_PATH . 'includes/class-loader.php')) {
    require_once FLIPNZEE_AUCTION_PATH . 'includes/class-loader.php';
}

This prepares the plugin for modular development.


Step 10: Create the Loader Class

Open:

includes/class-loader.php

Add:

<?php

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

class Flipnzee_Auction_Loader
{

    public function __construct()
    {

    }

}

new Flipnzee_Auction_Loader();

Although the class is currently empty, it will eventually load every component of our plugin, including auctions, bids, payments, reports, APIs, and notifications.


Folder Structure After Lesson 1

flipnzee-auctions/

│
├── flipnzee-auctions.php
│
└── includes/
      └── class-loader.php

Commit Your Changes

Open Source Control.

Use the commit message:

Lesson 1: Create plugin skeleton

Commit your changes.

Then click Sync Changes.

Your plugin skeleton is now safely stored in GitHub.


Summary

Congratulations!

You’ve officially written your first WordPress plugin.

Although it doesn’t yet contain any auction functionality, you’ve created the foundation that every future lesson will build upon.

Lesson Summary

In this lesson, we built the foundation of the Flipnzee Auctions plugin using GitHub Codespaces. We created the main plugin file, added the WordPress plugin header, protected the plugin from direct access, defined reusable constants, registered activation and deactivation hooks, and introduced a loader class to prepare for a modular architecture.

Although the plugin is still in its early stages, we’ve established a professional project structure that will allow us to add features in a clean and maintainable manner as the series progresses.


Key Takeaways

  • ✓ Every WordPress plugin begins with a properly formatted plugin header.
  • ✓ WordPress automatically discovers plugins by reading their headers.
  • ✓ The ABSPATH check prevents direct access to plugin files.
  • ✓ Plugin constants reduce repetition and improve maintainability.
  • ✓ Activation and deactivation hooks allow WordPress to execute code at important points in the plugin lifecycle.
  • ✓ A loader class helps organize larger plugins into smaller, reusable components.

Common Mistakes

When completing this lesson, beginners often encounter one or more of the following issues:

  • Creating files in the GitHub repository root instead of the flipnzee-auctions plugin folder.
  • Forgetting to save files before committing changes.
  • Omitting the opening <?php tag.
  • Misspelling one of the required plugin header fields.
  • Creating the includes folder in the wrong location.
  • Forgetting to commit and sync changes to GitHub.

If your plugin does not appear in the WordPress Plugins page, review each of these items before moving on.


Git Commands Used

During this lesson, we used the following Git and terminal commands:

cd flipnzee-auctions

touch flipnzee-auctions.php

mkdir includes

touch includes/class-loader.php

git add .

git commit -m "Lesson 1: Create plugin skeleton"

git push

Project Status

✅ Development environment ready

✅ GitHub repository created

✅ GitHub Codespaces configured

✅ Plugin skeleton completed

⬜ Database installation

⬜ Auction engine

⬜ Bidding system

⬜ Escrow workflow

⬜ Payment gateways

⬜ Website transfer

⬜ Reports & Analytics

⬜ REST API

⬜ Version 1.0 Release

Source Code

The complete source code for this project is maintained in the official GitHub repository.

Rather than embedding the full source code in every lesson, the GitHub repository serves as the single source of truth and always contains the latest version of the project. This allows the tutorial series to focus on explaining concepts and design decisions while ensuring readers have access to the most up-to-date implementation.

(Insert your GitHub repository link here.)


Developer’s Notebook

One of the biggest mistakes new developers make is trying to build an entire application before creating a solid foundation.

Professional software projects evolve incrementally. We start with a minimal but well-structured plugin, verify that it works, and then add one feature at a time. This approach makes debugging easier, keeps the codebase organized, and reduces the likelihood of introducing difficult-to-find bugs.

Throughout this series, you’ll see the Flipnzee Auctions plugin grow from a simple plugin skeleton into a fully featured website auction platform. By following this step-by-step approach, you’ll not only build a working plugin but also gain insight into how experienced WordPress developers approach large software projects.


Looking Ahead

In Lesson 2, we’ll package our plugin into a ZIP file, install it on a WordPress website, activate it, and verify that WordPress recognizes it as a valid plugin. This will be the first time we see the Flipnzee Auctions plugin running inside WordPress.


Lesson 0: Setting Up Your Development Environment with GitHub Codespaces

Welcome to Lesson 0 of the Building Flipnzee Auctions series.

Before writing a single line of PHP, let’s prepare our development environment.

Many WordPress tutorials begin by creating a folder inside wp-content/plugins and editing files directly on the server. While that approach works, it doesn’t scale well and doesn’t teach the workflow used by most professional developers.

Throughout this series, we’ll use GitHub Codespaces as our development environment. This means you can build your plugin entirely in your web browser, keep your code safely backed up in GitHub, and deploy it to any WordPress website by simply uploading a ZIP file.

Even if you’ve never used Git or GitHub before, don’t worry. We’ll learn everything step by step.


Why Use GitHub Codespaces?

GitHub Codespaces provides a complete Visual Studio Code development environment in your browser.

There is no need to install:

  • PHP
  • Apache
  • MySQL
  • Visual Studio Code
  • Git

Everything runs in the cloud.

Some of the benefits include:

  • Develop from any computer
  • Automatic backups with Git
  • Professional development workflow
  • Easy collaboration
  • No risk of accidentally breaking your live website
  • Perfect for open-source projects

By the end of this series, your entire plugin will be stored in a GitHub repository that you can continue improving for years.


Our Development Workflow

Every lesson in this series will follow the same workflow.

GitHub Repository
        │
        ▼
GitHub Codespaces
        │
        ▼
Develop & Test
        │
        ▼
Commit Changes
        │
        ▼
Push to GitHub
        │
        ▼
Download Plugin ZIP
        │
        ▼
WordPress Dashboard
        │
        ▼
Plugins → Add New
        │
        ▼
Upload Plugin
        │
        ▼
Activate Plugin

This is a modern workflow that combines version control with WordPress development.


Step 1: Create a GitHub Account

If you don’t already have one, create a free GitHub account.

Once your account is ready, sign in.


Step 2: Create a New Repository

Click the New Repository button.

Repository Name:

flipnzee-auctions

Choose:

  • Public (recommended for learning)
  • Add a README file
  • Add a .gitignore (choose None for now)
  • License: GPL-3.0 (or leave blank—we’ll add one later)

Click Create Repository.

Congratulations! You’ve just created the home of your plugin.


Step 3: Launch GitHub Codespaces

Inside your repository:

  1. Click the green Code button.
  2. Select the Codespaces tab.
  3. Click Create Codespace on main.

GitHub will prepare your development environment.

The first launch may take a minute or two.

When it finishes, you’ll see a browser-based version of Visual Studio Code.


Step 4: Explore the Interface

Spend a few minutes becoming familiar with the layout.

You’ll see:

  • Explorer (your project files)
  • Search
  • Source Control (Git)
  • Run & Debug
  • Extensions
  • Terminal

Don’t worry if some of these seem unfamiliar. We’ll use them throughout the series.


Step 5: Create the Plugin Folder

In the Explorer, create a new folder named:

flipnzee-auctions

This folder will eventually become the ZIP file that we’ll upload to WordPress.


Step 6: Open the Integrated Terminal

From the menu:

Terminal → New Terminal

Try a few basic commands:

pwd

Displays your current location.

ls

Lists files and folders.

Navigate into your plugin folder:

cd flipnzee-auctions

Confirm your location:

pwd

Learning a few terminal commands now will make development much easier later.


Step 7: Organize Your Repository

Before we start writing plugin code, let’s organize our GitHub repository like a professional software project.

It’s important to understand that a GitHub repository and a WordPress plugin are not exactly the same thing.

Think of the repository as the home for your entire project. Besides the plugin itself, it also contains documentation, licenses, changelogs, and other files that help you manage and distribute the project.

By the end of this step, your repository should look like this:

flipnzee-auctions/                 ← GitHub Repository

│
├── README.md
├── ROADMAP.md
├── LICENSE
├── CHANGELOG.md
│
└── flipnzee-auctions/             ← WordPress Plugin Folder

Notice that there are two folders named flipnzee-auctions.

The outer one is your GitHub repository, while the inner one will become the actual WordPress plugin.

When we eventually upload our plugin to WordPress, we’ll package only the inner folder into a ZIP file.


Step 8: Create the ROADMAP.md File

In the root of your GitHub repository (not inside the plugin folder), create a file named:

ROADMAP.md

Add the following content:

# Flipnzee Auctions Roadmap

## Version 1.0

- Plugin Skeleton
- Database Tables
- Auction Engine
- Website Listings
- Proxy Bidding
- Watchlist
- Buy Now
- Escrow Workflow
- Payment Methods
- Website Transfer
- Email Notifications
- Reports
- REST API

## Future Versions

- Live Bidding
- AI Website Valuation
- Multi-vendor Marketplace
- Stripe Integration
- WooCommerce Integration
- Mobile App API

This roadmap will evolve throughout the project and serve as our development checklist.


A Note About README.md

You may have noticed that your repository already contains a file named README.md.

That’s perfectly normal.

If you created your repository with the “Add a README file” option enabled, GitHub automatically generated this file for you. This is standard practice and gives every repository a landing page describing the project.

We’ll continue updating this README.md throughout the series as our plugin evolves. By the time we release Flipnzee Auctions v1.0, it will contain installation instructions, feature highlights, requirements, screenshots, and developer documentation.

For now, there’s nothing you need to change in README.md. We’ll focus on creating the remaining project files.

Step 9: Create a CHANGELOG.md File

Professional software projects maintain a changelog that records significant changes between releases.

Create a file named:

CHANGELOG.md

Add the following content:

# Changelog

## Version 1.0.0

- Initial project setup

As we complete each lesson, we’ll update this file with new features and improvements.


Step 10: Review the Repository Structure

Your repository should now look similar to this:

flipnzee-auctions/
│
├── README.md
├── ROADMAP.md
├── CHANGELOG.md
├── LICENSE
│
└── flipnzee-auctions/

At this stage, the inner flipnzee-auctions folder is intentionally empty.

In the next lesson, we’ll begin transforming it into a real WordPress plugin by creating our first PHP file and adding the plugin header.


Step 11: Commit Your Changes

Now that the repository is organized, it’s time to save your progress.

Open the Source Control panel in GitHub Codespaces.

You’ll see the newly created files waiting to be committed.

Use the following commit message:

Lesson 0: Initial project setup

If you prefer using the terminal, run:

git add .
git commit -m "Lesson 0: Initial project setup"
git push

This creates the first milestone in your project’s history and safely stores your work in GitHub.


Summary

Congratulations!

Although we haven’t written any PHP yet, you’ve already adopted a professional development workflow.

Your project now includes:

  • A GitHub repository
  • GitHub Codespaces as your development environment
  • A project roadmap
  • A changelog
  • A clean repository structure ready for development

In Lesson 1, we’ll move into the flipnzee-auctions plugin folder and create the first PHP file that WordPress recognizes as a plugin.

Introducing the Flipnzee Auctions Plugin Development Series

Have you ever wondered how website marketplaces like Flippa allow buyers to place bids, make offers, purchase websites, and complete secure transfers? If you’re a WordPress developer, you may have searched for an auction plugin only to discover that most are designed for physical products rather than digital assets such as websites and domain names.

In this new series on WPNzee, we’re going to build a professional WordPress auction plugin from the ground up.

This won’t be a collection of isolated code snippets. Instead, it will be a structured, real-world software development project where each lesson builds upon the previous one. By the end of the series, we’ll have created a fully functional plugin that powers website auctions for Flipnzee.

What We’re Building

The plugin, Flipnzee Auctions, is designed specifically for buying and selling websites. It will eventually include features such as:

  • Website auction listings
  • Starting price and reserve price
  • Buy Now option
  • Automatic proxy bidding
  • Bid history
  • Watchlist
  • Countdown timers
  • Escrow-based payments
  • Alternative payment methods including PayPal, Wise, Payoneer, bank transfer, and cryptocurrency
  • Buyer and seller dashboards
  • Website transfer checklist
  • Auction reports and analytics
  • Email notifications
  • Security and anti-fraud measures

Rather than trying to build everything at once, we’ll develop the plugin step by step, just as a professional software team would.

Who Is This Series For?

This series is intended for:

  • WordPress developers
  • PHP developers
  • Plugin developers
  • Freelancers
  • Agency owners
  • Computer science students
  • Anyone who wants to learn how large WordPress plugins are architected

A basic understanding of PHP and WordPress will be helpful, but every important concept will be explained along the way.

What Makes This Series Different?

Many tutorials stop after creating a simple plugin that displays “Hello World.”

This series is different.

We’ll discuss software architecture, database design, WordPress coding standards, security, performance, scalability, maintainability, and clean code. Every lesson will explain not only what we’re building, but also why we’re building it that way.

Our goal is to produce a plugin that is robust enough for production use while serving as an educational resource for developers who want to build professional WordPress applications.

How the Series Will Be Organized

The series will be divided into logical stages, including:

  1. Plugin foundation and architecture
  2. Database design
  3. Auction engine
  4. Bidding system
  5. Payment workflow
  6. Escrow integration
  7. Website transfer management
  8. Notifications
  9. Reporting and analytics
  10. Testing, optimization, and release

Each lesson will contain complete source code, detailed explanations, and practical insights that you can immediately apply to your own projects.

Learn by Building

The best way to learn software development is by building something meaningful.

Instead of reading about plugin development in theory, you’ll follow the complete journey of creating a commercial-quality WordPress auction plugin from scratch.

Whether your goal is to build your own marketplace, improve your PHP skills, or better understand WordPress internals, I hope this series helps you gain both confidence and practical experience.

Let’s begin our journey with Lesson 0: Setting Up Your Development Environment with GitHub Codespaces, where we’ll lay the foundation for everything that follows.

Creating Custom Admin Menus in WordPress

Series: WordPress Development From Scratch
Level: Beginner to Intermediate
Project Reference: Flipnzee Analytics


Introduction

One of the most powerful features of WordPress plugins is the ability to create custom pages inside the WordPress dashboard.

Have you ever installed a plugin and noticed a new menu item appear in the admin sidebar?

Examples include:

  • WooCommerce
  • Yoast SEO
  • Elementor
  • MonsterInsights
  • Flipnzee Analytics

These plugins create custom admin menus that allow users to configure settings, view reports, and manage plugin features.

In this tutorial you’ll learn:

  • How WordPress admin menus work
  • How plugins create dashboard pages
  • The purpose of menu permissions
  • Creating top-level menus
  • Creating submenu pages
  • Best practices for admin interfaces
  • How the Flipnzee Analytics plugin creates its dashboard

By the end, you’ll be able to add professional dashboard pages to your own plugins.


What Is an Admin Menu?

An admin menu is a navigation item inside the WordPress dashboard.

Examples:

Dashboard
Posts
Media
Pages
Comments
Appearance
Plugins
Users
Tools
Settings

Plugins can add their own entries:

Dashboard
Posts
Media
Pages
Flipnzee Analytics

Clicking the menu opens a custom admin page.


Why Create Admin Menus?

Many plugins need a place to:

  • Store settings
  • Display reports
  • Configure APIs
  • Show analytics
  • Manage users
  • Run maintenance tools

Without admin menus, users would have no easy way to interact with the plugin.


How WordPress Creates Menus

WordPress uses the:

admin_menu

hook.

Example:

add_action(
    'admin_menu',
    'wpnzee_admin_menu'
);

This tells WordPress:

“Run my function when admin menus are being built.”


Creating Your First Admin Menu

Example:

function wpnzee_admin_menu() {

    add_menu_page(
        'WPNzee Dashboard',
        'WPNzee Dashboard',
        'manage_options',
        'wpnzee-dashboard',
        'wpnzee_dashboard_page'
    );

}

add_action(
    'admin_menu',
    'wpnzee_admin_menu'
);

Understanding add_menu_page()

The function:

add_menu_page()

creates a top-level menu.

Example:

add_menu_page(
    'WPNzee Dashboard',
    'WPNzee Dashboard',
    'manage_options',
    'wpnzee-dashboard',
    'wpnzee_dashboard_page'
);

Let’s examine each parameter.


Page Title

'WPNzee Dashboard'

Displayed in the browser title.


Menu Title

'WPNzee Dashboard'

Displayed in the sidebar.


Capability

'manage_options'

Determines who can access the page.


Menu Slug

'wpnzee-dashboard'

Unique page identifier.


Callback Function

'wpnzee_dashboard_page'

Function that displays page content.


Creating the Dashboard Page

Now create the callback:

function wpnzee_dashboard_page() {

    echo '<div class="wrap">';

    echo '<h1>WPNzee Dashboard</h1>';

    echo '<p>Welcome to your first plugin dashboard.</p>';

    echo '</div>';

}

After activation, you’ll see a new menu inside the WordPress dashboard.


Understanding User Permissions

One of the most important concepts in WordPress administration is permissions.

Example:

'manage_options'

Only administrators can access pages using this capability.


Common Capabilities

CapabilityAccess
manage_optionsAdministrators
edit_postsAuthors and above
publish_postsEditors and above
activate_pluginsAdministrators
edit_pagesEditors and above

Choosing the correct capability is important for security.


Adding a Custom Icon

You can assign an icon:

add_menu_page(
    'WPNzee Dashboard',
    'WPNzee Dashboard',
    'manage_options',
    'wpnzee-dashboard',
    'wpnzee_dashboard_page',
    'dashicons-chart-line'
);

WordPress includes hundreds of Dashicons.

Examples:

dashicons-chart-line
dashicons-admin-generic
dashicons-analytics
dashicons-admin-tools
dashicons-chart-pie

Creating Submenus

Professional plugins usually contain multiple pages.

Example:

Flipnzee Analytics
├── Dashboard
├── Reports
├── Settings

WordPress provides:

add_submenu_page()

Example Submenu

add_submenu_page(
    'wpnzee-dashboard',
    'Reports',
    'Reports',
    'manage_options',
    'wpnzee-reports',
    'wpnzee_reports_page'
);

This creates a Reports page beneath the main menu.


Creating the Reports Page

Example:

function wpnzee_reports_page() {

    echo '<div class="wrap">';

    echo '<h1>Reports</h1>';

    echo '<p>Analytics reports appear here.</p>';

    echo '</div>';

}

Organizing Menu Code

As plugins grow, menu code should move into a dedicated file.

Example:

admin
├── menu.php
├── settings-page.php
└── reports-page.php

Then load it:

require_once plugin_dir_path(__FILE__) . 'admin/menu.php';

This keeps the plugin organized.


Real Example: Flipnzee Analytics

The Flipnzee Analytics plugin uses custom admin pages to manage:

  • Google Analytics connections
  • Property configuration
  • Reports
  • Dashboard widgets
  • Search Console integration

Instead of placing everything inside Settings, it provides a dedicated interface designed specifically for analytics management.

This creates a better user experience.


Typical Flow of an Admin Menu

Plugin Activated
          ↓
admin_menu Hook Fires
          ↓
add_menu_page()
          ↓
Menu Appears in Sidebar
          ↓
User Clicks Menu
          ↓
Callback Function Executes
          ↓
Dashboard Page Loads

Understanding this flow makes admin development much easier.


Common Beginner Mistakes

Using Duplicate Slugs

Bad:

'settings'

Good:

'wpnzee-settings'

Always use unique prefixes.


Incorrect Permissions

Avoid:

'read'

for administrative pages.

Choose capabilities carefully.


Mixing Logic and Presentation

Keep:

Menu Registration

separate from:

Page Rendering

This improves maintainability.


Creating Too Many Top-Level Menus

Bad:

Dashboard
Posts
Pages
Plugin A
Plugin B
Plugin C
Plugin D

Use submenus whenever possible.


What You’ve Learned

In this tutorial you learned:

✓ What admin menus are

✓ How plugins create dashboard pages

✓ How add_menu_page() works

✓ How add_submenu_page() works

✓ How permissions control access

✓ How menu callbacks work

✓ How Flipnzee Analytics organizes its admin interface

✓ Best practices for scalable dashboard development


Key Takeaway

Admin menus are the foundation of plugin user interfaces.

They provide a professional way for users to interact with plugin settings, reports, and tools.

Most successful WordPress plugins rely heavily on custom admin pages, making this an essential skill for every plugin developer.


Next Lesson

In the next tutorial we’ll explore:

Building a Professional Settings Page Using the WordPress Settings API

You’ll learn how plugins save settings securely, how WordPress stores configuration data, and how the Flipnzee Analytics plugin manages API credentials, analytics settings, and user preferences using professional WordPress development practices.

Loading CSS and JavaScript Properly in WordPress

Series: WordPress Development From Scratch
Level: Beginner to Intermediate
Project Reference: Flipnzee Analytics


Introduction

Almost every WordPress plugin eventually needs CSS and JavaScript.

You may want to:

  • Style an analytics dashboard
  • Create interactive charts
  • Add buttons and forms
  • Display notifications
  • Build modern user interfaces

Many beginners make the mistake of inserting raw HTML like:

<link rel="stylesheet" href="style.css">
<script src="script.js"></script>

directly into plugin files.

While this may seem to work, it ignores WordPress’s asset management system and can cause conflicts with themes and other plugins.

In this tutorial you’ll learn:

  • Why WordPress uses an asset loading system
  • What “enqueueing” means
  • How to load CSS files properly
  • How to load JavaScript files properly
  • How to load assets only when needed
  • Admin vs Frontend assets
  • How professional plugins manage assets
  • How Flipnzee Analytics organizes its CSS and JavaScript

By the end, you’ll know how professional WordPress plugins load styles and scripts safely and efficiently.


What Does “Enqueue” Mean?

In WordPress, assets are loaded using a queue system.

Instead of directly printing HTML tags, you tell WordPress:

“Please load this file when appropriate.”

WordPress then handles:

  • Correct ordering
  • Dependency management
  • Duplicate prevention
  • Compatibility

This process is called enqueueing.


Why Not Use Raw HTML?

Avoid:

echo '<link rel="stylesheet" href="style.css">';

and:

echo '<script src="script.js"></script>';

Problems include:

  • Duplicate loading
  • Incorrect ordering
  • Theme conflicts
  • Performance issues

Instead, use WordPress functions.


Plugin Folder Structure

A common structure looks like:

my-plugin
├── assets
│   ├── css
│   │   └── style.css
│   └── js
│       └── script.js
└── my-plugin.php

This keeps assets organized.


Loading CSS Properly

Create:

assets/css/style.css

Example:

.wpnzee-box {
    background: #f5f5f5;
    padding: 20px;
}

Now load it using:

function wpnzee_enqueue_styles() {

    wp_enqueue_style(
        'wpnzee-style',
        plugin_dir_url(__FILE__) . 'assets/css/style.css',
        array(),
        '1.0.0'
    );

}

add_action(
    'wp_enqueue_scripts',
    'wpnzee_enqueue_styles'
);

WordPress will automatically add the stylesheet to the page.


Understanding wp_enqueue_style()

The function:

wp_enqueue_style()

contains four important parts.

Example:

wp_enqueue_style(
    'wpnzee-style',
    plugin_dir_url(__FILE__) . 'assets/css/style.css',
    array(),
    '1.0.0'
);

Handle

'wpnzee-style'

Unique identifier.


File URL

plugin_dir_url(__FILE__)

Generates the plugin path.


Dependencies

array()

Files that must load first.


Version

'1.0.0'

Helps browsers refresh cached files.


Loading JavaScript Properly

Create:

assets/js/script.js

Example:

console.log("WPNzee Plugin Loaded");

Now enqueue it:

function wpnzee_enqueue_scripts() {

    wp_enqueue_script(
        'wpnzee-script',
        plugin_dir_url(__FILE__) . 'assets/js/script.js',
        array(),
        '1.0.0',
        true
    );

}

add_action(
    'wp_enqueue_scripts',
    'wpnzee_enqueue_scripts'
);

Understanding wp_enqueue_script()

Example:

wp_enqueue_script(
    'wpnzee-script',
    plugin_dir_url(__FILE__) . 'assets/js/script.js',
    array(),
    '1.0.0',
    true
);

The last parameter:

true

loads the script in the footer.

Benefits:

  • Faster page rendering
  • Better performance

Loading Both CSS and JavaScript

Many developers combine assets:

function wpnzee_enqueue_assets() {

    wp_enqueue_style(
        'wpnzee-style',
        plugin_dir_url(__FILE__) . 'assets/css/style.css'
    );

    wp_enqueue_script(
        'wpnzee-script',
        plugin_dir_url(__FILE__) . 'assets/js/script.js',
        array(),
        '1.0.0',
        true
    );

}

add_action(
    'wp_enqueue_scripts',
    'wpnzee_enqueue_assets'
);

This keeps asset management organized.


Frontend vs Admin Assets

Not every file should load everywhere.

WordPress provides separate hooks.


Frontend

add_action(
    'wp_enqueue_scripts',
    'wpnzee_enqueue_assets'
);

Loads assets on public pages.


Admin Dashboard

add_action(
    'admin_enqueue_scripts',
    'wpnzee_admin_assets'
);

Loads assets inside wp-admin.

Example:

function wpnzee_admin_assets() {

    wp_enqueue_style(
        'wpnzee-admin',
        plugin_dir_url(__FILE__) . 'assets/css/admin.css'
    );

}

Loading Assets Only When Needed

Professional plugins avoid loading files everywhere.

Bad:

Load analytics CSS on every page

Good:

Load analytics CSS only on analytics pages

Example:

if (is_page('analytics')) {

    wp_enqueue_style(
        'analytics-style'
    );

}

This improves performance.


Asset Dependencies

Sometimes JavaScript requires another library.

Example:

wp_enqueue_script(
    'custom-chart',
    plugin_dir_url(__FILE__) . 'assets/js/chart.js',
    array('jquery'),
    '1.0',
    true
);

WordPress ensures jQuery loads first.


Real Example: Flipnzee Analytics

The Flipnzee Analytics plugin uses assets for:

  • Analytics dashboard styling
  • Reports
  • Admin interfaces
  • Frontend widgets
  • User experience improvements

Its structure follows a professional approach:

assets
├── css
├── js
└── images

instead of mixing styles directly into PHP files.

This makes maintenance much easier.


Why Professional Plugins Use Asset Folders

Benefits include:

Better Organization

CSS → css/
JS → js/
Images → images/

Easier Maintenance

Developers instantly know where files belong.


Improved Scalability

As features grow, organization remains manageable.


Better Performance

Assets can be loaded conditionally.


Common Beginner Mistakes

Using Raw HTML Tags

Avoid:

<link>
<script>

Use enqueue functions instead.


Loading Assets Everywhere

Only load files when needed.


Forgetting Version Numbers

Versioning helps prevent browser caching issues.


Not Using Dependencies

Always declare required libraries.


Mixing CSS Inside PHP

Avoid large inline styles.

Store CSS in dedicated files.


What You’ve Learned

In this tutorial you learned:

✓ What enqueueing means

✓ Why WordPress uses an asset system

✓ How wp_enqueue_style() works

✓ How wp_enqueue_script() works

✓ Frontend vs admin assets

✓ Dependency management

✓ Asset versioning

✓ How Flipnzee Analytics organizes its assets


Key Takeaway

WordPress provides a powerful asset management system that ensures CSS and JavaScript are loaded safely and efficiently.

Professional plugins never hardcode script or stylesheet tags.

Instead, they use enqueue functions to maintain compatibility, improve performance, and create scalable plugin architectures.

Mastering asset loading is a major step toward becoming a professional WordPress plugin developer.


Next Lesson

In the next tutorial we’ll explore:

Creating Custom Admin Menus in WordPress

You’ll learn how plugins add new dashboard pages, how menu permissions work, and how the Flipnzee Analytics plugin creates its own administrative interface inside WordPress.

How Plugin Activation and Deactivation Hooks Work

Series: WordPress Development From Scratch
Level: Beginner to Intermediate
Project Reference: Flipnzee Analytics


Introduction

When you activate a WordPress plugin, something special happens behind the scenes.

WordPress doesn’t simply mark the plugin as “active.” Instead, it gives the plugin an opportunity to perform setup tasks before it starts running.

Similarly, when a plugin is deactivated, WordPress allows the plugin to clean up after itself.

This process is handled using Activation Hooks and Deactivation Hooks.

In this tutorial you’ll learn:

  • What activation hooks are
  • What deactivation hooks are
  • Why they are important
  • How WordPress executes them
  • Common setup tasks during activation
  • Common cleanup tasks during deactivation
  • How professional plugins use these hooks
  • How Flipnzee Analytics uses plugin initialization

By the end, you’ll understand one of the most important parts of building production-ready WordPress plugins.


What Happens When You Activate a Plugin?

Imagine installing a plugin that creates:

  • Custom database tables
  • Default settings
  • User roles
  • Scheduled tasks

These things must be created before the plugin can work properly.

WordPress solves this problem using an activation hook.

When a user clicks:

Plugins → Activate

WordPress automatically executes any activation function registered by the plugin.


Activation Hook Syntax

WordPress provides:

register_activation_hook()

Example:

register_activation_hook(
    __FILE__,
    'wpnzee_activate'
);

This tells WordPress:

“Run the function wpnzee_activate() when this plugin is activated.”


Creating Your First Activation Hook

Example:

function wpnzee_activate() {

    update_option(
        'wpnzee_version',
        '1.0.0'
    );

}

register_activation_hook(
    __FILE__,
    'wpnzee_activate'
);

When the plugin activates:

wpnzee_version = 1.0.0

is automatically stored in the database.


Why Store Plugin Settings During Activation?

Many plugins need default configuration values.

Example:

function wpnzee_activate() {

    add_option(
        'wpnzee_show_widget',
        'yes'
    );

}

Now the plugin starts with sensible defaults.

The user doesn’t need to configure everything manually.


What Happens Behind the Scenes?

The activation process looks like:

User clicks Activate
          ↓
WordPress loads plugin
          ↓
Activation Hook Executes
          ↓
Setup Tasks Run
          ↓
Plugin Becomes Active

Common Activation Tasks

Professional plugins often:

Create Default Settings

add_option(
    'plugin_color',
    'blue'
);

Create Database Tables

global $wpdb;

Custom tables are often created here.


Schedule Cron Jobs

wp_schedule_event(
    time(),
    'hourly',
    'my_plugin_event'
);

Create User Roles

add_role(
    'analytics_manager',
    'Analytics Manager'
);

Store Plugin Version

update_option(
    'plugin_version',
    '1.0'
);

This helps future upgrades.


Understanding Deactivation Hooks

Deactivation hooks perform cleanup.

WordPress provides:

register_deactivation_hook()

Example:

register_deactivation_hook(
    __FILE__,
    'wpnzee_deactivate'
);

When a user clicks:

Deactivate

the specified function runs.


Creating Your First Deactivation Hook

Example:

function wpnzee_deactivate() {

    wp_clear_scheduled_hook(
        'wpnzee_hourly_event'
    );

}

register_deactivation_hook(
    __FILE__,
    'wpnzee_deactivate'
);

This removes scheduled events when the plugin is disabled.


Why Deactivation Matters

Imagine a plugin schedules:

Every Hour:
Fetch Analytics Data

If the plugin is deactivated but the scheduled event continues running:

  • Resources are wasted
  • Errors may occur
  • Performance suffers

Deactivation hooks prevent this.


Activation vs Deactivation

ActivationDeactivation
Setup environmentClean up environment
Create settingsRemove temporary processes
Schedule tasksUnschedule tasks
Initialize pluginDisable plugin activity

Think of it like:

Activation   = Setup
Deactivation = Shutdown

What About Uninstall?

Many beginners confuse:

Deactivate

with:

Delete

They are different.

Deactivate

Plugin remains installed.

Delete

Plugin is removed entirely.

For deletion, WordPress provides:

uninstall.php

or

register_uninstall_hook()

These are used to permanently remove data.


Real Example: Analytics Plugin

Imagine Flipnzee Analytics is activated.

Possible activation tasks:

Store Plugin Version
Create Default Settings
Initialize Analytics Configuration
Prepare Cache System
Schedule Data Refresh Jobs

These ensure the plugin is ready before the user starts using it.


Example Plugin with Both Hooks

<?php

function wpnzee_activate() {

    add_option(
        'wpnzee_version',
        '1.0'
    );

}

function wpnzee_deactivate() {

    wp_clear_scheduled_hook(
        'wpnzee_hourly_event'
    );

}

register_activation_hook(
    __FILE__,
    'wpnzee_activate'
);

register_deactivation_hook(
    __FILE__,
    'wpnzee_deactivate'
);

This is a common pattern you’ll see in professional plugins.


Common Beginner Mistakes

Running Setup Code on Every Page Load

Bad:

add_option(
    'plugin_version',
    '1.0'
);

This executes constantly.

Use activation hooks instead.


Forgetting Cleanup

Always remove:

  • Scheduled events
  • Temporary files
  • Cached data

when appropriate.


Deleting User Data on Deactivation

Avoid:

delete_option(...)

during deactivation.

Users may reactivate later.

Save permanent cleanup for uninstall.


Not Checking Existing Settings

Before creating options:

if (!get_option('plugin_version')) {
    add_option(...);
}

Avoid overwriting user settings.


What You’ve Learned

In this tutorial you learned:

✓ What activation hooks are

✓ What deactivation hooks are

✓ How register_activation_hook() works

✓ How register_deactivation_hook() works

✓ Common setup tasks

✓ Common cleanup tasks

✓ The difference between deactivate and uninstall

✓ How professional plugins prepare their environment


Key Takeaway

Activation hooks allow a plugin to prepare itself before use.

Deactivation hooks allow a plugin to shut down gracefully.

Together they help create reliable, professional WordPress plugins that behave correctly throughout their lifecycle.

Every serious WordPress developer should understand these hooks before building larger projects.


Next Lesson

In the next tutorial we’ll explore:

Loading CSS and JavaScript Properly in WordPress

You’ll learn why professional plugins never use raw HTML <script> and <link> tags, how WordPress manages assets using enqueue functions, and how the Flipnzee Analytics plugin loads styles and scripts efficiently across the admin dashboard and frontend.

WordPress Plugin File Structure Explained

Series: WordPress Development From Scratch
Level: Beginner to Intermediate
Project Reference: Flipnzee Analytics


Introduction

As your WordPress plugins become more powerful, placing all your code inside a single PHP file quickly becomes difficult to manage.

While a simple plugin may only contain one file, professional plugins often contain dozens or even hundreds of files organized into folders.

In this tutorial you’ll learn:

  • Why plugin structure matters
  • How beginner plugins are organized
  • How professional plugins are organized
  • Common plugin folders and their purposes
  • How the Flipnzee Analytics plugin is structured
  • Best practices for scalable plugin development

By the end of this lesson, you’ll understand how to organize your WordPress projects like professional plugin developers.


The Problem with Single-File Plugins

In our first tutorial, we created a plugin using a single file:

my-first-plugin
└── my-first-plugin.php

This works perfectly for simple plugins.

However, imagine adding:

  • Admin settings pages
  • CSS files
  • JavaScript files
  • API integrations
  • Analytics reports
  • Dashboard widgets
  • Shortcodes

Soon your file may grow to thousands of lines.

Example:

my-first-plugin.php
  • 300 lines of settings code
  • 500 lines of API code
  • 400 lines of shortcode code
  • 600 lines of analytics code

Finding bugs becomes difficult.

Updating features becomes risky.

This is why professional developers organize plugins into folders.


A Better Structure

Instead of one giant file:

my-first-plugin.php

Use:

my-first-plugin
├── assets
├── includes
├── admin
├── templates
└── my-first-plugin.php

Each folder serves a specific purpose.

This makes development easier and more maintainable.


The Main Plugin File

Every plugin has an entry point.

Example:

my-first-plugin.php

This file usually contains:

  • Plugin header
  • Security checks
  • Constants
  • Required files
  • Initialization hooks

Example:

<?php

/*
Plugin Name: My First Plugin
Version: 1.0
*/

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

require_once plugin_dir_path(__FILE__) . 'includes/functions.php';

Think of this file as the plugin’s front door.


The Includes Folder

Most plugins have an:

includes/

directory.

Purpose:

  • Core functions
  • API integrations
  • Helper functions
  • Business logic

Example:

includes
├── functions.php
├── api.php
├── helpers.php

Instead of placing everything inside the main plugin file, we separate functionality into reusable modules.


The Admin Folder

Administrative functionality belongs inside:

admin/

Examples:

  • Settings pages
  • Dashboard menus
  • Reports
  • Administrative tools

Example:

admin
├── menu.php
├── settings-page.php
├── reports.php

This keeps backend functionality separate from frontend functionality.


The Assets Folder

Every plugin eventually needs styling.

The assets folder stores:

assets
├── css
├── js
└── images

Example:

assets
├── css
│   └── admin.css
├── js
│   └── admin.js
└── images
    └── logo.png

Benefits:

  • Cleaner organization
  • Easier maintenance
  • Better scalability

The Templates Folder

Many plugins generate frontend output.

Instead of mixing HTML and PHP together, templates help separate presentation from logic.

Example:

templates
├── dashboard.php
├── report.php
└── widget.php

Benefits:

  • Cleaner code
  • Easier customization
  • Better readability

Understanding Separation of Concerns

Professional developers follow a principle called:

Separation of Concerns

Each file should have one responsibility.

Bad:

settings
analytics
HTML
CSS
API calls
database queries

all inside one file.

Good:

admin/settings.php
includes/analytics.php
templates/dashboard.php
assets/css/style.css

Each component has a dedicated location.


Real Example: Flipnzee Analytics Plugin

The Flipnzee Analytics plugin follows a modular architecture.

Its structure looks similar to:

flipnzee-analytics
├── assets
├── includes
│   ├── admin
│   ├── ga-api.php
│   ├── shortcodes.php
│   └── meta-boxes.php
├── frontend
└── flipnzee-analytics.php

This structure allows the plugin to support:

  • Google Analytics integration
  • Search Console integration
  • Dashboard reports
  • Shortcodes
  • Admin settings
  • Frontend widgets

without becoming a maintenance nightmare.


Why Flipnzee Analytics Uses Multiple Files

Imagine if all functionality existed inside:

flipnzee-analytics.php

The file could easily exceed several thousand lines.

Instead:

ga-api.php

Handles:

  • Google Analytics requests
  • Authentication
  • Report generation

shortcodes.php

Handles:

  • Visitor statistics display
  • Analytics widgets
  • Listing output

admin/

Handles:

  • Dashboard menus
  • Plugin settings
  • Configuration pages

This organization makes the code easier to understand and extend.


Loading Files Using require_once

Professional plugins load modules using:

require_once

Example:

require_once plugin_dir_path(__FILE__) . 'includes/functions.php';

require_once plugin_dir_path(__FILE__) . 'admin/settings-page.php';

This allows WordPress to load functionality only when needed.


Naming Conventions

Good file names:

analytics.php
settings-page.php
shortcodes.php
helpers.php

Avoid:

test.php
new.php
random.php
stuff.php

File names should clearly describe their purpose.


Example Structure for Your Future Plugins

As your plugins grow, consider this structure:

my-awesome-plugin
├── admin
│   ├── menu.php
│   └── settings.php
│
├── assets
│   ├── css
│   ├── js
│   └── images
│
├── includes
│   ├── api.php
│   ├── helpers.php
│   └── shortcodes.php
│
├── templates
│   └── dashboard.php
│
└── my-awesome-plugin.php

This structure is suitable for most professional WordPress projects.


Common Beginner Mistakes

Putting Everything in One File

Works initially.

Becomes difficult later.


Mixing HTML and PHP Everywhere

Hard to maintain.

Use templates instead.


Not Using Folders

Twenty files in the plugin root becomes confusing.

Organize related files together.


Poor File Names

Use descriptive names.

Future-you will thank you.


What You’ve Learned

In this tutorial you learned:

✓ Why plugin structure matters

✓ The role of the main plugin file

✓ What the includes folder does

✓ What the admin folder does

✓ What the assets folder does

✓ What the templates folder does

✓ How Flipnzee Analytics organizes functionality

✓ Best practices for scalable plugin development


Key Takeaway

A plugin’s structure may seem unimportant when a project is small.

However, as features grow, good organization becomes essential.

Professional WordPress developers spend just as much time organizing code as they do writing it.

A clean structure makes plugins easier to:

  • Maintain
  • Debug
  • Extend
  • Scale

Next Lesson

In the next tutorial we’ll explore:

How Plugin Activation and Deactivation Hooks Work

You’ll learn what happens when a plugin is activated, how WordPress runs setup tasks automatically, and how professional plugins prepare their environment before users start using them.

Understanding the WordPress Hook System: Actions vs Filters

Series: WordPress Development From Scratch
Level: Beginner
Project Reference: Flipnzee Analytics


Introduction

If WordPress plugins are the engine that powers customization, then hooks are the fuel that makes everything work.

Virtually every WordPress plugin relies on hooks.

Whether you’re creating:

  • A contact form plugin
  • An SEO plugin
  • An analytics dashboard
  • An eCommerce extension

you’ll be working with hooks every day.

In fact, the Flipnzee Analytics plugin uses numerous hooks to integrate seamlessly with WordPress without modifying any core files.

In this tutorial you’ll learn:

  • What WordPress hooks are
  • Why hooks exist
  • The difference between Actions and Filters
  • How to create your own Action hooks
  • How to create your own Filter hooks
  • How real plugins use hooks

By the end, you’ll understand one of the most important concepts in WordPress development.


What Is a Hook?

A hook is a point in WordPress where developers can attach their own code.

Think of WordPress as a train traveling along a track.

At various stations, WordPress pauses and says:

“Would any plugin like to do something here?”

Those stations are called hooks.

Plugins register functions to run when a specific hook is reached.

This allows developers to extend WordPress without editing core files.


Why Hooks Matter

Without hooks, plugin developers would need to modify WordPress itself.

That would create several problems:

  • Updates would overwrite changes
  • Different plugins would conflict
  • Maintenance would become difficult

Hooks solve these problems by creating a standard extension system.


The Two Types of Hooks

WordPress provides two categories of hooks:

1. Actions

Actions perform tasks.

Examples:

  • Send an email
  • Add a menu
  • Display content
  • Load CSS files

Actions do something.


2. Filters

Filters modify data.

Examples:

  • Change a page title
  • Modify content
  • Adjust a URL
  • Alter settings

Filters change something and return the modified value.


Understanding Actions

An Action allows you to run a function at a specific point in WordPress.

Example:

function wpnzee_footer_message() {
    echo "<p>Learning WordPress Development with WPNzee</p>";
}

add_action('wp_footer', 'wpnzee_footer_message');

When WordPress reaches the footer:

do_action('wp_footer');

your function executes automatically.


How Actions Work Behind the Scenes

WordPress Core:

do_action('wp_footer');

Your Plugin:

add_action('wp_footer', 'wpnzee_footer_message');

Result:

WordPress reaches footer
↓
wp_footer fires
↓
Your function runs
↓
Message appears

Common Action Hooks

Here are some popular action hooks:

HookPurpose
initRun code during WordPress initialization
admin_menuAdd dashboard menus
wp_enqueue_scriptsLoad CSS and JavaScript
wp_footerOutput content in footer
wp_headOutput content in page head
save_postTrigger when a post is saved

Example: Adding an Admin Menu

function wpnzee_admin_menu() {

    add_menu_page(
        'WPNzee Plugin',
        'WPNzee Plugin',
        'manage_options',
        'wpnzee-plugin',
        'wpnzee_page'
    );

}

add_action('admin_menu', 'wpnzee_admin_menu');

This action creates a new menu inside the WordPress dashboard.


Understanding Filters

Filters work differently.

Instead of performing an action, they modify data and return it.

Example:

function wpnzee_change_title($title) {

    return "WPNzee: " . $title;

}

add_filter('the_title', 'wpnzee_change_title');

Original title:

Learning WordPress

Modified title:

WPNzee: Learning WordPress

How Filters Work Behind the Scenes

WordPress:

$title = apply_filters('the_title', $title);

Your Plugin:

add_filter('the_title', 'wpnzee_change_title');

Process:

Original Value
↓
Filter Hook
↓
Your Function
↓
Modified Value

Common Filter Hooks

HookPurpose
the_titleModify titles
the_contentModify content
excerpt_lengthChange excerpt size
body_classAdd CSS classes
widget_titleModify widget titles

Action vs Filter

ActionsFilters
Perform tasksModify data
Usually echo outputMust return value
Trigger eventsChange values
add_action()add_filter()

A simple rule:

Actions do. Filters modify.


Real Example from Flipnzee Analytics

The Flipnzee Analytics plugin relies heavily on action hooks.

Examples include:

add_action('admin_menu', ...);

Used to create plugin dashboard pages.


add_action('wp_enqueue_scripts', ...);

Used to load frontend CSS and JavaScript.


add_action('admin_init', ...);

Used to initialize plugin settings and administrative functionality.


Without hooks, the plugin would not integrate properly with WordPress.


Creating Your Own Custom Action Hook

You can create hooks inside your own plugins.

Example:

do_action('wpnzee_after_report_generated');

Other developers can then hook into it:

function notify_admin() {

    error_log("Report generated");

}

add_action(
    'wpnzee_after_report_generated',
    'notify_admin'
);

This makes your plugin extensible.


Creating Your Own Custom Filter Hook

You can also create filters.

Plugin code:

$title = apply_filters(
    'wpnzee_report_title',
    'Analytics Report'
);

Another plugin:

function custom_report_title($title) {

    return "Monthly Analytics Report";

}

add_filter(
    'wpnzee_report_title',
    'custom_report_title'
);

Output:

Monthly Analytics Report

Common Beginner Mistakes

Forgetting to Return a Value

Incorrect:

function change_title($title) {

    $title = "New Title";

}

Correct:

function change_title($title) {

    return "New Title";

}

Echoing Inside Filters

Avoid:

echo $title;

Filters should return values.


Using Generic Function Names

Bad:

function display_menu()

Good:

function wpnzee_display_menu()

Always use prefixes.


What You’ve Learned

In this tutorial you learned:

✓ What hooks are

✓ Why hooks exist

✓ The difference between Actions and Filters

✓ How add_action() works

✓ How add_filter() works

✓ How WordPress executes hooks

✓ How Flipnzee Analytics uses hooks

✓ How to create custom hooks


Next Lesson

In the next tutorial we’ll explore:

WordPress Plugin File Structure Explained

You’ll learn how professional plugins organize files and how the Flipnzee Analytics plugin structure can help you build scalable WordPress projects.

What Is a WordPress Plugin? Build Your First Plugin from Scratch

Series: WordPress Development From Scratch
Level: Beginner
Project Reference: Flipnzee Analytics


Introduction

One of the biggest reasons WordPress powers millions of websites worldwide is its plugin ecosystem.

A plugin allows developers to add new functionality to WordPress without modifying the core WordPress files. Whether you want to add contact forms, SEO features, analytics dashboards, membership systems, or eCommerce functionality, there’s usually a plugin available to do the job.

But have you ever wondered how WordPress plugins are built?

In this tutorial, you’ll learn:

  • What a WordPress plugin is
  • How WordPress loads plugins
  • How to create your first plugin
  • How plugin headers work
  • How to add functionality using WordPress hooks
  • How real-world plugins like Flipnzee Analytics are structured

By the end of this guide, you’ll have built your very first WordPress plugin from scratch.


What Is a WordPress Plugin?

A WordPress plugin is a collection of PHP files that extend or modify WordPress functionality.

Think of WordPress as a smartphone.

  • WordPress Core = Operating System
  • Plugins = Mobile Apps

Just as you install apps to add new features to your phone, you install plugins to add new capabilities to WordPress.

Examples include:

  • WooCommerce → Online stores
  • Yoast SEO → Search engine optimization
  • Contact Form 7 → Contact forms
  • MonsterInsights → Analytics reporting
  • Flipnzee Analytics → Google Analytics integration

Why Plugins Exist

Without plugins, every website owner would need to edit WordPress core files to add features.

That creates several problems:

  • Updates would overwrite changes
  • Security risks increase
  • Maintenance becomes difficult

Plugins solve this by providing a standardized way to extend WordPress.

Benefits include:

  • Easy installation
  • Easy updates
  • Better security
  • Modular development
  • Reusability

How WordPress Loads Plugins

When WordPress starts, it scans the:

/wp-content/plugins/

directory.

Every plugin lives inside its own folder.

Example:

wp-content
└── plugins
    ├── hello-dolly
    ├── woocommerce
    └── my-first-plugin

When a plugin is activated, WordPress loads its main PHP file and executes the code.

This process happens automatically during every page load.


Create Your First Plugin

Navigate to:

wp-content/plugins/

Create a folder:

my-first-plugin

Inside the folder create:

my-first-plugin.php

Your structure should look like:

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

Add the Plugin Header

Open:

<?php
/*
Plugin Name: My First Plugin
Plugin URI: https://wpnzee.com
Description: My first WordPress plugin.
Version: 1.0.0
Author: WPNzee
Author URI: https://wpnzee.com
License: GPLv2
*/

Save the file.

Now visit:

Dashboard → Plugins
plugin activated

You’ll see your plugin listed.

Congratulations!

You just created a valid WordPress plugin.


Activate the Plugin

Click Activate.

Nothing will happen visually because our plugin doesn’t do anything yet.

Let’s change that.


Add Your First Function

Below the plugin header, add:

function wpnzee_hello_world() {
    echo '<p>Hello from my first plugin!</p>';
}

This creates a function.

However, WordPress still doesn’t know when to run it.

That’s where hooks come in.


Understanding WordPress Hooks

Hooks allow developers to inject code into WordPress at specific points.

There are two major types:

Actions

Actions perform tasks.

Example:

add_action('wp_footer', 'wpnzee_hello_world');

Filters

Filters modify data.

Example:

add_filter('the_title', 'custom_title');

For now we’ll focus on actions.


Display Content in the Footer

Add:

function wpnzee_hello_world() {
    echo '<p>Hello from my first plugin!</p>';
}

add_action('wp_footer', 'wpnzee_hello_world');

Save the file.

Visit your website frontend.

Scroll to the footer.

You’ll see:

Hello from my first plugin!

Your plugin is now actively extending WordPress.


How the Hook Works

When WordPress reaches the footer section:

do_action('wp_footer');

it checks whether any plugins registered callbacks for that hook.

Our code:

add_action('wp_footer', 'wpnzee_hello_world');

tells WordPress:

“When the wp_footer hook fires, run the function wpnzee_hello_world().”

This is the foundation of plugin development.


Making It Look Better

Update the function:

function wpnzee_hello_world() {
    echo '
    <div style="padding:10px;background:#f5f5f5;text-align:center;">
        Welcome to WPNzee Plugin Development Tutorials
    </div>';
}

add_action('wp_footer', 'wpnzee_hello_world');

Refresh your website.

Now your plugin outputs a styled message.


Real-World Example: Flipnzee Analytics

Professional plugins rarely consist of a single file.

The Flipnzee Analytics plugin uses a more advanced structure:

flipnzee_screenshot
flipnzee-analytics
├── admin
├── assets
├── includes
├── templates
├── frontend
└── flipnzee-analytics.php

The main plugin file acts as the entry point.

It:

  • Loads required files
  • Registers hooks
  • Initializes settings
  • Connects WordPress with plugin components

As your plugins grow, you’ll adopt a similar architecture.


Common Beginner Mistakes

Editing WordPress Core Files

Never modify:

wp-admin
wp-includes

Always use plugins or themes.


Forgetting PHP Opening Tags

Every plugin file should start with:

<?php

Outputting Content Everywhere

Avoid:

echo "Hello";

outside hooks.

Always attach functionality to actions or filters.


Not Using Unique Function Names

Bad:

function display_message()

Good:

function wpnzee_display_message()

Prefixing prevents conflicts with other plugins.


What You’ve Learned

In this tutorial you learned:

✓ What a WordPress plugin is

✓ Why plugins exist

✓ How WordPress loads plugins

✓ How plugin headers work

✓ How hooks connect plugins to WordPress

✓ How to build and activate your first plugin

✓ How real-world plugins like Flipnzee Analytics are structured


Next Lesson

In the next tutorial we’ll explore the most important concept in WordPress development:

Understanding the WordPress Hook System: Actions vs Filters

Once you master hooks, you’ll understand how virtually every plugin in the WordPress ecosystem works.

Happy coding!

Recommended Resources