AdminForge - WordPress Admin Framework
Modern WordPress Admin Framework for building admin panels, settings pages, meta boxes, and custom fields with PSR-4 architecture.
by Amirhossein · github.com/amirhossein103/adminforge · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/amirhossein103/adminforge/archive/refs/heads/master.zipWordPress-native admin framework for theme and plugin developers.
AdminForge is a modern, PSR-4 compliant library for building WordPress admin interfaces. It provides an intuitive API for creating settings pages, meta boxes, and custom fields—all designed exclusively for WordPress environments.
Why AdminForge?
- WordPress-First Design: Built on WordPress APIs, not abstracted away from them
- Modern PHP: PHP 8.0+, strict types, union types, named parameters
- Zero Configuration: Sensible defaults, works out of the box
- Type-Safe: Full IDE autocomplete support with comprehensive type hints
- Performance-Optimized: O(1) meta access, two-tier caching, conditional asset loading
- Security-Conscious: Auto-nonce verification, comprehensive sanitization, capability checks
- Extensible: Designed with clear extension points for custom implementations
Requirements
- PHP: 8.0 or higher
- WordPress: 5.8 or higher
Installation
Via Composer (Recommended)
composer require amirhossein103/adminforge
In Your WordPress Plugin
<?php
/**
* Plugin Name: My Awesome Plugin
*/
// Composer autoloader
require_once __DIR__ . '/vendor/autoload.php';
// Start using AdminForge
use AdminForge\Admin\MenuPage;
use AdminForge\MetaBox\MetaBox;
use AdminForge\Settings\Settings;
In Your WordPress Theme
<?php
// functions.php
// Composer autoloader
require_once get_template_directory() . '/vendor/autoload.php';
// Start using AdminForge
Quick Start Examples
1. Create a Settings Page
use AdminForge\Admin\SettingsPage;
add_action('admin_menu', function() {
$page = new SettingsPage('My Plugin Settings', 'my_plugin', [
'slug' => 'my-plugin-settings',
'icon' => 'dashicons-admin-settings',
'position' => 30
]);
// Add fields
$page->addField('text', 'api_key', 'API Key', [
'hint' => 'Enter your API key',
'required' => true
]);
$page->addField('checkbox', 'enable_cache', 'Enable Caching', [
'hint' => 'Improve performance with caching'
]);
$page->addField('select', 'theme_color', 'Theme Color', [
'options' => [
'blue' => 'Blue',
'red' => 'Red',
'green' => 'Green'
]
]);
$page->register();
});
// Retrieve settings anywhere
$api_key = Settings::get('my_plugin.api_key', '');
$cache_enabled = Settings::getBool('my_plugin.enable_cache', false);
2. Create a Meta Box
use AdminForge\MetaBox\MetaBox;
add_action('add_meta_boxes', function() {
$metaBox = new MetaBox('product_info', 'Product Information', ['product', 'post']);
$metaBox->addField([
'id' => 'price',
'type' => 'number',
'label' => 'Price',
'hint' => 'Enter product price in USD'
]);
$metaBox->addField([
'id' => 'sku',
'type' => 'text',
'label' => 'SKU',
'placeholder' => 'PROD-12345'
]);
$metaBox->addField([
'id' => 'in_stock',
'type' => 'checkbox',
'label' => 'In Stock'
]);
$metaBox->register();
});
// Retrieve meta values (performance-optimized)
use AdminForge\Helpers\MetaHelper;
// Option 1: Individual access
$price = get_post_meta($post_id, 'price', true);
// Option 2: Batch loading (single DB query)
MetaHelper::loadAll($post_id);
$price = MetaHelper::get($post_id, 'price', 0);
$sku = MetaHelper::get($post_id, 'sku', '');
$in_stock = MetaHelper::get($post_id, 'in_stock', false);
3. Create a Custom Admin Page
use AdminForge\Admin\MenuPage;
class MyCustomPage extends MenuPage
{
protected string $pageTitle = 'My Dashboard';
protected string $menuTitle = 'Dashboard';
protected string $slug = 'my-dashboard';
protected string $icon = 'dashicons-dashboard';
public function render(): void
{
?>
<div class="wrap">
<h1><?php echo esc_html($this->pageTitle); ?></h1>
<p>Welcome to your custom dashboard!</p>
<?php
// Use WordPress functions naturally
$user = wp_get_current_user();
echo '<p>Hello, ' . esc_html($user->display_name) . '</p>';
?>
</div>
<?php
}
}
// Register the page
add_action('admin_menu', function() {
(new MyCustomPage())->register();
});
4. Create Custom Fields
use AdminForge\Fields\FieldFactory;
// Text field
$field = FieldFactory::create('text', 'username', [
'label' => 'Username',
'placeholder' => 'Enter username',
'required' => true
]);
echo $field->render();
// Color picker
$color = FieldFactory::create('color', 'brand_color', [
'label' => 'Brand Color',
'default' => '#3498db'
]);
echo $color->render();
// Media uploader
$media = FieldFactory::create('media', 'featured_image', [
'label' => 'Featured Image',
'button_text' => 'Select Image'
]);
echo $media->render();
// Repeater field (complex repeating sections)
$repeater = FieldFactory::create('repeater', 'team_members', [
'label' => 'Team Members',
'fields' => [
['id' => 'name', 'type' => 'text', 'label' => 'Name'],
['id' => 'role', 'type' => 'text', 'label' => 'Role'],
['id' => 'bio', 'type' => 'textarea', 'label' => 'Bio']
]
]);
echo $repeater->render();
Available Field Types
AdminForge includes 12+ built-in field types:
| Field Type | Description | Usage |
|---|---|---|
text |
Single-line text input | Names, titles, URLs |
email |
Email input with validation | Email addresses |
url |
URL input with validation | Website links |
number |
Numeric input | Prices, quantities |
tel |
Telephone input | Phone numbers |
password |
Password input (masked) | Credentials |
textarea |
Multi-line text | Descriptions, notes |
select |
Dropdown selection | Categories, options |
checkbox |
Boolean checkbox | Enable/disable features |
radio |
Radio button group | Exclusive choices |
color |
WordPress color picker | Theme colors |
media |
WordPress media uploader | Images, files |
editor |
WordPress visual editor (TinyMCE) | Rich text content |
repeater |
Repeating field groups | Lists, galleries |
Settings API
AdminForge provides a powerful settings management system with dot notation support:
use AdminForge\Settings\Settings;
// Simple get/set
Settings::set('my_plugin.api_key', 'abc123');
$key = Settings::get('my_plugin.api_key', '');
// Nested arrays
Settings::set('appearance.colors', [
'primary' => '#0073aa',
'secondary' => '#00a0d2'
]);
$primary = Settings::get('appearance.colors.primary'); // '#0073aa'
// Type-safe getters
$port = Settings::getInt('server.port', 8080);
$enabled = Settings::getBool('features.cache', false);
$name = Settings::getString('site.name', 'My Site');
$options = Settings::getArray('menu.items', []);
// Array operations (useful for checkboxes)
Settings::pushToArray('features.enabled', 'dark_mode');
Settings::removeFromArray('features.enabled', 'old_feature');
Settings::toggleInArray('features.beta', 'feature_x');
// Check if setting exists
if (Settings::has('my_plugin.configured')) {
// ...
}
// Group-based access
$appearance = Settings::group('appearance');
$appearance->set('theme', 'dark');
$theme = $appearance->get('theme');
$all = $appearance->all();
// Import/Export
$json = Settings::export('my_plugin'); // Export specific group
Settings::import($json, $merge = true); // Import and merge
// Backups
Settings::backup('pre-update-backup');
Settings::restore('pre-update-backup');
$backups = Settings::listBackups();
Performance Optimization
MetaHelper: O(1) Meta Access
use AdminForge\Helpers\MetaHelper;
// Without MetaHelper: N database queries
foreach ($posts as $post) {
$price = get_post_meta($post->ID, 'price', true); // Query 1
$sku = get_post_meta($post->ID, 'sku', true); // Query 2
$stock = get_post_meta($post->ID, 'in_stock', true); // Query 3
}
// With MetaHelper: 1 database query total
$post_ids = wp_list_pluck($posts, 'ID');
MetaHelper::preload($post_ids); // Single query loads all meta
foreach ($posts as $post) {
$price = MetaHelper::get($post->ID, 'price', 0); // O(1) array access
$sku = MetaHelper::get($post->ID, 'sku', ''); // O(1) array access
$stock = MetaHelper::get($post->ID, 'in_stock', false); // O(1) array access
}
Two-Tier Caching
AdminForge uses a two-tier caching strategy:
- Runtime cache: In-memory cache for the current request (fastest)
- WordPress Object Cache: Persistent cache across requests (Redis, Memcached compatible)
use AdminForge\Core\Cache;
// Cached for 1 hour
$data = Cache::remember('expensive_operation', 3600, function() {
return expensive_database_query();
});
// Clear specific cache
Cache::forget('expensive_operation');
// Clear all caches
Cache::flush();
Security Best Practices
AdminForge follows WordPress security standards:
Automatic Nonce Verification
// Meta boxes automatically include nonces
$metaBox = new MetaBox('product_info', 'Product Information', 'product');
$metaBox->register(); // Nonces handled automatically
// Settings pages automatically verify nonces
$page = new SettingsPage('Settings', 'my_plugin');
// Form submissions automatically verified
Comprehensive Sanitization
use AdminForge\Security\SecurityTrait;
class MyPlugin
{
use SecurityTrait;
public function saveData($input)
{
$sanitized = [
'email' => $this->sanitizeEmail($input['email']),
'url' => $this->sanitizeUrl($input['url']),
'text' => $this->sanitizeText($input['text']),
'html' => $this->sanitizeHtml($input['content']),
'int' => $this->sanitizeInt($input['count']),
];
// Or use type-based sanitization
$value = $this->sanitizeByType($input['field'], 'email');
return $sanitized;
}
}
Capability Checks
// Built into admin pages
class MyPage extends MenuPage
{
protected string $capability = 'manage_options'; // Requires admin
public function render(): void
{
// Only accessible to users with 'manage_options' capability
}
}
// Manual capability checks
use AdminForge\Security\SecurityTrait;
if ($this->userCan('edit_posts')) {
// User can edit posts
}
Extending AdminForge
Custom Field Types
use AdminForge\Fields\BaseField;
use AdminForge\Fields\FieldFactory;
class SliderField extends BaseField
{
public function render(): string
{
$value = $this->getValue() ?? $this->config['default'] ?? 50;
$min = $this->config['min'] ?? 0;
$max = $this->config['max'] ?? 100;
return sprintf(
'<input type="range" id="%s" name="%s" min="%d" max="%d" value="%d" />',
esc_attr($this->id),
esc_attr($this->id),
$min,
$max,
$value
);
}
}
// Register custom field type
FieldFactory::register('slider', SliderField::class);
// Use it
$field = FieldFactory::create('slider', 'volume', [
'label' => 'Volume',
'min' => 0,
'max' => 100,
'default' => 50
]);
Custom Page Types
use AdminForge\Admin\MenuPage;
class AnalyticsDashboard extends MenuPage
{
protected string $pageTitle = 'Analytics';
protected string $menuTitle = 'Analytics';
protected string $slug = 'my-analytics';
protected string $capability = 'view_analytics'; // Custom capability
protected function init(): void
{
// Called during construction
// Add custom initialization logic
}
public function enqueueAssets(string $hook): void
{
// Only load on this specific page
if ($hook !== $this->getHookSuffix()) {
return;
}
wp_enqueue_script('chart-js', '//cdn.example.com/chart.js');
wp_enqueue_style('my-analytics', plugin_dir_url(__FILE__) . 'analytics.css');
}
public function render(): void
{
// Use WordPress data naturally
$stats = new WP_Query(['post_type' => 'product', 'posts_per_page' => -1]);
?>
<div class="wrap">
<h1>Analytics Dashboard</h1>
<p>Total Products: <?php echo $stats->found_posts; ?></p>
<div id="chart-container"></div>
</div>
<?php
}
}
WordPress Integration
AdminForge embraces WordPress conventions:
Hooks and Filters
// Register pages on admin_menu
add_action('admin_menu', function() {
(new MySettingsPage())->register();
});
// Register meta boxes on add_meta_boxes
add_action('add_meta_boxes', function() {
(new MyMetaBox())->register();
});
// Access WordPress globals naturally
global $wpdb;
$results = $wpdb->get_results("SELECT * FROM {$wpdb->posts} WHERE post_type = 'product'");
Translations
// All strings are translatable
__('Settings saved successfully', 'my-plugin');
esc_html__('Welcome to AdminForge', 'my-plugin');
WordPress APIs
// Use WordPress functions naturally
$user = wp_get_current_user();
$post = get_post($post_id);
$meta = get_post_meta($post_id, 'key', true);
// WordPress hooks work as expected
do_action('my_plugin_before_save', $data);
$value = apply_filters('my_plugin_value', $value);
Library vs. Plugin Mode
AdminForge can be used as a library in your plugin/theme OR as a standalone plugin.
As a Library (Recommended)
composer require amirhossein103/adminforge
// Your plugin/theme code
use AdminForge\Admin\MenuPage;
use AdminForge\Settings\Settings;
// Use only the components you need
// No unwanted admin menus or automatic initialization
As a Standalone Plugin
- Download/clone the repository
- Place in
wp-content/plugins/adminforge - Activate through WordPress admin
Note: When activated as a plugin, AdminForge creates a demo admin page. You can disable this by not initializing the core singleton:
// Remove the default init hook
remove_action('plugins_loaded', 'AdminForge\adminforge_init');
API Reference
Core Classes
AdminForge\Settings\Settings- Settings management with dot notationAdminForge\Fields\FieldFactory- Create field instancesAdminForge\Helpers\MetaHelper- Performance-optimized meta accessAdminForge\Core\Cache- Two-tier caching systemAdminForge\Core\Config- Configuration management
Page Classes
AdminForge\Admin\MenuPage- Top-level admin menu pagesAdminForge\Admin\SubMenuPage- Submenu pagesAdminForge\Admin\SettingsPage- Settings pages with auto-formsAdminForge\Admin\BasePage- Abstract base for custom pages
Meta Boxes
AdminForge\MetaBox\MetaBox- Custom meta boxes with auto-nonce
Fields
AdminForge\Fields\FieldInterface- Field contractAdminForge\Fields\BaseField- Abstract base field classAdminForge\Fields\TextField- Text input fieldsAdminForge\Fields\SelectField- Select dropdownsAdminForge\Fields\CheckboxField- CheckboxesAdminForge\Fields\MediaField- WordPress media uploaderAdminForge\Fields\RepeaterField- Repeating field groups- And more...
Utilities
AdminForge\Helpers\Helper- General utility functionsAdminForge\Helpers\DataHydrator- Data extraction and filteringAdminForge\Security\SecurityTrait- Security helpers (trait)
Contributing
Contributions are welcome! This is a WordPress-native library, so contributions should:
- Follow WordPress coding standards
- Use WordPress APIs (not reinvent them)
- Include PHPDoc blocks
- Maintain backward compatibility in minor versions
- Add tests for new features
See CONTRIBUTING.md for detailed guidelines.
Changelog
1.0.0 (2025-12-29)
Initial stable release for Packagist
- ✅ PSR-4 autoloading with PHP 8.0+ strict types
- ✅ Settings API with dot notation support
- ✅ 12+ field types including Repeater
- ✅ Meta box system with auto-nonce security
- ✅ Performance-optimized MetaHelper (O(1) access)
- ✅ Two-tier caching system
- ✅ Comprehensive security sanitization
- ✅ Admin page system with tabs support
- ✅ Full WordPress integration
- ✅ Production-ready and stable
License
MIT License - see LICENSE for details.
Credits
Author: Amirhossein (@amirhossein103)
Special Thanks:
- WordPress Core Team for the excellent APIs
- The PHP community for modern standards (PSR-4, PSR-12)
Support
- Issues: GitHub Issues
- Documentation: GitHub Wiki
- Source: GitHub Repository
Made with ❤️ for WordPress developers