Claude
Skills
Sign in
Back

wordpress-plugin-fundamentals

Included with Lifetime
$97 forever

Modern WordPress plugin development with PHP 8.3+, OOP architecture, hooks system, database interactions, and Settings API

developmentwordpressphppluginhookswpdbsettings-apiwpcs

What this skill does


# WordPress Plugin Fundamentals

## Overview

WordPress plugin development using modern PHP 8.3+ practices, OOP architecture, Composer autoloading, and WordPress 6.7+ APIs. Build secure, maintainable plugins with proper hooks integration, database management, and settings pages.

**Current Standards**:
- **WordPress**: 6.7+ (Full Site Editing stable)
- **PHP**: 8.3 recommended (7.4 minimum)
- **Architecture**: OOP with PSR-4 autoloading
- **Security**: Three-layer model (sanitize, validate, escape)
- **Testing**: PHPUnit + WPCS compliance

**Installation**:
```bash
composer require --dev wp-coding-standards/wpcs:"^3.0"
composer require --dev phpunit/phpunit:"^9.6"
```

## Plugin Architecture

### Directory Structure

Modern plugin organization with Composer autoloading:

```
my-plugin/
├── my-plugin.php              # Main plugin file (metadata header)
├── composer.json               # Dependency management (REQUIRED)
├── includes/                   # Core business logic (PSR-4 autoloaded)
│   ├── Core.php               # Plugin bootstrap/loader class
│   ├── Admin/                 # Admin-specific functionality
│   │   ├── Settings.php
│   │   └── MetaBoxes.php
│   ├── Frontend/              # Public-facing functionality
│   │   └── Shortcodes.php
│   └── API/                   # REST API endpoints
│       └── CustomEndpoint.php
├── assets/                     # CSS, JS, images
│   ├── css/
│   ├── js/
│   └── images/
├── languages/                  # Translation files
├── tests/                      # PHPUnit tests
│   ├── unit/
│   ├── integration/
│   └── bootstrap.php
├── .phpcs.xml.dist            # PHP_CodeSniffer config (WPCS)
└── README.md
```

### Main Plugin File

**my-plugin.php**:
```php
<?php
/**
 * Plugin Name: Modern WordPress Plugin
 * Plugin URI: https://example.com/my-plugin
 * Description: Modern plugin following WordPress 6.x best practices
 * Version: 1.0.0
 * Requires at least: 6.4
 * Requires PHP: 8.1
 * 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: my-plugin
 * Domain Path: /languages
 */

// Security: Prevent direct access
if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}

// Define plugin constants
define( 'MY_PLUGIN_VERSION', '1.0.0' );
define( 'MY_PLUGIN_PATH', plugin_dir_path( __FILE__ ) );
define( 'MY_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
define( 'MY_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );

// Composer autoloader
if ( file_exists( MY_PLUGIN_PATH . 'vendor/autoload.php' ) ) {
    require_once MY_PLUGIN_PATH . 'vendor/autoload.php';
}

/**
 * Initialize plugin on plugins_loaded hook
 * Runs after all plugins are loaded
 */
add_action( 'plugins_loaded', 'my_plugin_init' );

function my_plugin_init() {
    // Initialize core plugin class
    if ( class_exists( 'MyPlugin\\Core' ) ) {
        $plugin = MyPlugin\Core::get_instance();
        $plugin->run();
    }
}

/**
 * Activation hook
 * Runs once when plugin is activated
 */
register_activation_hook( __FILE__, 'my_plugin_activate' );
function my_plugin_activate() {
    // Run activation tasks
    if ( class_exists( 'MyPlugin\\Activation' ) ) {
        MyPlugin\Activation::activate();
    }

    // Flush rewrite rules after plugin activation
    flush_rewrite_rules();
}

/**
 * Deactivation hook
 * Runs when plugin is deactivated
 */
register_deactivation_hook( __FILE__, 'my_plugin_deactivate' );
function my_plugin_deactivate() {
    // Cleanup tasks
    if ( class_exists( 'MyPlugin\\Deactivation' ) ) {
        MyPlugin\Deactivation::deactivate();
    }

    // Flush rewrite rules
    flush_rewrite_rules();
}
```

### Core Plugin Class (Singleton Pattern)

**includes/Core.php**:
```php
<?php
namespace MyPlugin;

/**
 * Main plugin class using Singleton pattern
 *
 * Design Decision: Singleton ensures single plugin instance
 * Trade-off: Testability vs. simplicity (use DI for complex plugins)
 * Extension Point: Hook system allows third-party extensions
 */
class Core {
    /**
     * Single instance of the plugin
     * @var Core|null
     */
    private static $instance = null;

    /**
     * Get plugin instance (Singleton)
     *
     * @return Core
     */
    public static function get_instance() {
        if ( null === self::$instance ) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Private constructor prevents direct instantiation
     */
    private function __construct() {
        $this->load_dependencies();
        $this->define_hooks();
        $this->load_textdomain();
    }

    /**
     * Load required classes and dependencies
     */
    private function load_dependencies() {
        // Dependencies auto-loaded via Composer PSR-4
        // Additional manual includes if needed
    }

    /**
     * Register WordPress hooks
     */
    private function define_hooks() {
        // Core hooks
        add_action( 'init', [ $this, 'on_init' ] );
        add_action( 'admin_menu', [ $this, 'register_admin_menu' ] );
        add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_assets' ] );
        add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_frontend_assets' ] );
        add_action( 'rest_api_init', [ $this, 'register_rest_routes' ] );
    }

    /**
     * Load plugin text domain for translations
     */
    private function load_textdomain() {
        load_plugin_textdomain(
            'my-plugin',
            false,
            dirname( MY_PLUGIN_BASENAME ) . '/languages'
        );
    }

    /**
     * Start plugin execution
     */
    public function run() {
        // Plugin is now running
        do_action( 'my_plugin_loaded' );
    }

    /**
     * Init hook callback
     * Register post types, taxonomies, etc.
     */
    public function on_init() {
        // Register custom post types
        $this->register_post_types();

        // Register taxonomies
        $this->register_taxonomies();
    }

    /**
     * Register custom post types
     */
    private function register_post_types() {
        register_post_type( 'book', [
            'labels' => [
                'name' => __( 'Books', 'my-plugin' ),
                'singular_name' => __( 'Book', 'my-plugin' ),
            ],
            'public' => true,
            'has_archive' => true,
            'supports' => [ 'title', 'editor', 'thumbnail' ],
            'show_in_rest' => true, // Enable block editor
            'menu_icon' => 'dashicons-book',
        ]);
    }

    /**
     * Register custom taxonomies
     */
    private function register_taxonomies() {
        register_taxonomy( 'genre', 'book', [
            'labels' => [
                'name' => __( 'Genres', 'my-plugin' ),
                'singular_name' => __( 'Genre', 'my-plugin' ),
            ],
            'hierarchical' => true,
            'show_in_rest' => true,
        ]);
    }

    /**
     * Register admin menu pages
     */
    public function register_admin_menu() {
        add_menu_page(
            __( 'My Plugin Settings', 'my-plugin' ),
            __( 'My Plugin', 'my-plugin' ),
            'manage_options',
            'my-plugin-settings',
            [ $this, 'render_settings_page' ],
            'dashicons-admin-generic',
            80
        );
    }

    /**
     * Render settings page
     */
    public function render_settings_page() {
        require_once MY_PLUGIN_PATH . 'includes/Admin/views/settings.php';
    }

    /**
     * Enqueue admin assets
     */
    public function enqueue_admin_assets( $hook ) {
        // Only load on our plugin pages
        if ( 'toplevel_page_my-plugin-settings' !== $hook ) {
            return;
        }

        wp_enqueue_style(
            'my-plugin-admin',
            MY_PLUGIN_URL . 'assets/css/admin.css',
            [],
            MY_PLUGIN_VERSION
        );

        wp_enqueue_script(
            'my-plugin-admin',
            MY_PLU

Related in development