An opinionated object-oriented base library for WordPress plugin and theme development, providing a structured foundation for building maintainable WordPress extensions.
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.
- 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
- PHP 8.0 or higher
- WordPress 6.5 or higher (for development)
composer require wp-plus/wp-oop-baseWhen 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.
- Download the library
- Place it in your
wp-content/plugins/wp-oop-base/directory - Activate the plugin through the WordPress admin
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.
<?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();<?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();<?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();<?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();AbstractPlugin: Base class for singleton plugin instancesAbstractExtensiblePlugin: Plugin class that can contain sub-pluginsPluginsContainerTrait: Manages collections of sub-plugins
AbstractHook: Base class for WordPress actions and filtersAbstractActivationHook: Specialized hooks for plugin activationAbstractMultiHook: Container of multiple hooks with hook-like interface
RegistrableInterface: Contract for registerable componentsAbstractRegistrable: Base implementation for registerable components
AbstractCustomPostType: Framework for custom post typesAbstractCustomTaxonomy: Framework for custom taxonomies
AbstractShortcode: Structured shortcode development with attribute validation
All plugin classes use the singleton pattern to ensure single instances:
$plugin = MyPlugin::getInstance();The library provides convenient static methods for common operations:
// Register components directly
MyHook::registerInstance();
// Run plugins directly
MyPlugin::runInstance();Components implement a consistent registration/unregistration pattern:
$component->register(); // Register with WordPress
$component->unregister(); // Remove from WordPressUtilities 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');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');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 ...");
}
}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-pluginsRegister 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();- 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
Contributions are welcome! Please ensure your code follows PSR-4 autoloading standards and includes appropriate documentation.
This project is licensed under the MIT License - see the LICENSE file for details.