wp-plus / wp-oop-base
Opinionated OOP base for WordPress plugin and theme development.
Installs: 49
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
Open Issues: 0
pkg:composer/wp-plus/wp-oop-base
Requires
- php: ^8.0
Requires (Dev)
This package is auto-updated.
Last update: 2025-12-30 12:17:16 UTC
README
An opinionated object-oriented base library for WordPress plugin and theme development, providing a structured foundation for building maintainable WordPress extensions.
Overview
WP OOP Base offers a collection of abstract classes and interfaces that promote clean, object-oriented architecture in WordPress development. It provides standardized patterns for common WordPress functionality including plugins, hooks, shortcodes, custom post types, and taxonomies.
Features
- Plugin Architecture: Singleton-based plugin classes with extensible sub-plugin support
- Hook Management: Object-oriented wrapper for WordPress actions and filters
- Shortcode Framework: Structured approach to shortcode development with attribute validation
- Custom Post Types & Taxonomies: Abstract classes for registering custom content types
- Helper Utilities: Common WordPress development utilities
- Clean Architecture: Structured patterns for maintainable code organization
- PSR-4 Autoloading: Modern PHP autoloading standards
Requirements
- PHP 8.0 or higher
- WordPress 6.5 or higher (for development)
Installation
Via Composer
composer require wp-plus/wp-oop-base
When installed via Composer, the library is automatically loaded through Composer's autoloader and doesn't need to be placed in the WordPress plugins directory. Simply include Composer's autoloader in your project and the classes will be available.
Note: this will work only if Composer's autoloader is included - either manually or using a tool like composer-autoload for WordPress.
Manual Installation
- Download the library
- Place it in your
wp-content/plugins/wp-oop-base/directory - Activate the plugin through the WordPress admin
Must-Use Plugin Installation
For must-use plugin functionality (automatically loaded, before regular plugins):
- Follow the manual installation steps above
- Move
wp-oop-base.phptowp-content/mu-plugins/ - Keep all other files in
wp-content/plugins/wp-oop-base/
The bootstrap file will automatically detect the correct paths whether it's running as a regular plugin or must-use plugin.
Quick Start
Creating a Plugin
<?php use WpPlus\WpOopBase\Plugin\AbstractPlugin; class MyPlugin extends AbstractPlugin { protected function main(): void { // Initialize your plugin hooks and functionality here add_action('init', [$this, 'initialize']); } public function initialize(): void { // Plugin initialization logic } } // Initialize the plugin MyPlugin::runInstance(); // or // MyPlugin::getInstance()->run();
Creating a Hook
<?php use WpPlus\WpOopBase\Hook\AbstractHook; class MyCustomHook extends AbstractHook { public function getName(): string { return 'wp_head'; } public function getPriority(): int { return 20; } protected function callback(...$args): mixed { echo '<meta name="custom" content="my-plugin">'; return null; } } // Register the hook MyCustomHook::registerInstance();
Creating a Shortcode
<?php use WpPlus\WpOopBase\Shortcode\AbstractShortcode; class MyShortcode extends AbstractShortcode { public function getTag(): string { return 'my_shortcode'; } protected function getSupportedAttributes(): array { return [ 'title' => 'Default Title', 'color' => 'blue' ]; } protected function doShortcode(array $attributes, string|null $content): string { return sprintf( '<div style="color: %s"><h3>%s</h3>%s</div>', esc_attr($attributes['color']), esc_html($attributes['title']), $content ? wpautop($content) : '' ); } } // Register the shortcode (new MyShortcode())->register();
Creating a Custom Post Type
<?php use WpPlus\WpOopBase\Custom\PostType\AbstractCustomPostType; class ProductPostType extends AbstractCustomPostType { public static function getPostType(): string { return 'product'; } protected function getConfig(): array { return [ 'labels' => [ 'name' => 'Products', 'singular_name' => 'Product' ], 'public' => true, 'has_archive' => true, 'supports' => ['title', 'editor', 'thumbnail'] ]; } } // Register the post type ProductPostType::registerInstance();
Architecture
Core Components
Plugin System
AbstractPlugin: Base class for singleton plugin instancesAbstractExtensiblePlugin: Plugin class that can contain sub-pluginsPluginsContainerTrait: Manages collections of sub-plugins
Hook System
AbstractHook: Base class for WordPress actions and filtersAbstractActivationHook: Specialized hooks for plugin activationAbstractMultiHook: Container of multiple hooks with hook-like interface
Registration System
RegistrableInterface: Contract for registerable componentsAbstractRegistrable: Base implementation for registerable components
Content Types
AbstractCustomPostType: Framework for custom post typesAbstractCustomTaxonomy: Framework for custom taxonomies
Other
AbstractShortcode: Structured shortcode development with attribute validation
Design Patterns
Singleton Pattern
All plugin classes use the singleton pattern to ensure single instances:
$plugin = MyPlugin::getInstance();
Convenient Static Methods
The library provides convenient static methods for common operations:
// Register components directly MyHook::registerInstance(); // Run plugins directly MyPlugin::runInstance();
Registration Pattern
Components implement a consistent registration/unregistration pattern:
$component->register(); // Register with WordPress $component->unregister(); // Remove from WordPress
Helper Classes
DateTime Helper
Utilities for WordPress-aware date/time formatting:
use WpPlus\WpOopBase\Helper\DateTime; // Format timestamp with WordPress timezone $formatted = DateTime::format(time(), 'Y-m-d H:i:s'); // MySQL datetime format $mysql = DateTime::format(time(), 'mysql');
Post Helper
Utilities for post operations:
use WpPlus\WpOopBase\Helper\Post; // Get post by slug $post = Post::getPostBySlug('my-post-slug', 'product'); // Get post ID by slug $id = Post::getPostIdBySlug('my-post-slug', 'product');
Database Access Trait
Convenient access to the WordPress database object:
use WpPlus\WpOopBase\Support\WpDbTrait; class MyClass { use WpDbTrait; public function getSomething(): array { return $this->wpdb()->get_results("SELECT * FROM ..."); } }
Advanced Usage
Extensible Plugins
Create plugins that can contain other plugins:
<?php use WpPlus\WpOopBase\Plugin\AbstractExtensiblePlugin; class MainPlugin extends AbstractExtensiblePlugin { protected function main(): void { // Add sub-plugins $this->addPlugin(SubPlugin1::class); $this->addPlugin(new SubPlugin2()); } } MainPlugin::getInstance()->run(); // Runs main plugin and all sub-plugins
Multi-Hooks
Register multiple related hooks together:
<?php use WpPlus\WpOopBase\Hook\AbstractHook; use WpPlus\WpOopBase\Hook\AbstractMultiHook; class PostStatusFunctionality extends AbstractMultiHook { public function __construct(AbstractHook ...$hooks) { // Hook for when post is published $hooks[] = new class extends AbstractHook { public function getName(): string { return 'publish_post'; } protected function callback(...$args): mixed { // Handle post publication error_log('Post published: ' . $args[0]->ID); return null; } }; // Hook for when post is trashed $hooks[] = new class extends AbstractHook { public function getName(): string { return 'wp_trash_post'; } protected function callback(...$args): mixed { // Handle post deletion error_log('Post trashed: ' . $args[0]); return null; } }; parent::__construct(...$hooks); } } // Register all related hooks at once (new PostStatusFunctionality())->register();
Best Practices
- Use Dependency Injection: Set dependencies via setters in plugin constructors
- Follow WordPress Coding Standards: Maintain consistency with WordPress conventions
- Implement Proper Error Handling: Use exceptions for configuration errors
- Validate Input: Always validate and sanitize user input in shortcodes and hooks
- Use Static Methods Judiciously: Static convenience methods create new instances each time they're called
Contributing
Contributions are welcome! Please ensure your code follows PSR-4 autoloading standards and includes appropriate documentation.
License
This project is licensed under the MIT License - see the LICENSE file for details.