A free, open-source, lightweight alternative to Redux Framework. Build powerful theme options panels with a beautiful React UI β no bloat, no paywalls, no legacy code.
Features Β· Field Types Β· Installation Β· Usage Β· White-label Β· Conditional Logic Β· REST API Β· Contributing
Β
- π¨ React-Powered Admin UI β Modern, polished interface built with React and WordPress components
- π§© 30 Field Types β Every input type a theme could need, nothing more
- π·οΈ Full White-label Support β Rename everything: menu title, slug, icon, option key β it becomes your theme's own settings panel
- π Sections & Subsections β Organise options into a clean hierarchical sidebar with
themeplus_add_section()andthemeplus_add_subsection() - π Conditional Logic β Show or hide any field based on the value of another; 10 operators, AND/OR relations, dot-notation sub-keys
- π€ Google Fonts Integration β Browse and load from 1,899 Google Fonts with live preview inside the Typography field
π °οΈ Custom Fonts Module β Upload and manage self-hosted fonts (WOFF2, WOFF); magic-byte verified, capability-gated, auto-enqueued- π Per-field Sanitization β Every saved value passes through
ThemePlus_Sanitizerβ type-checked, key-whitelisted, safe - π€ Import / Export β Backup and restore all theme settings as JSON with one click
- π Live Search β Instantly search across all fields and sections by title, subtitle, description, or ID
- π Dark & Light Mode β Admin UI respects the user's WordPress colour scheme with a manual toggle
β οΈ Unsaved Changes Detection β Warns before navigating away with unsaved changes- π REST API β Full CRUD endpoints under the
themeplus/v1namespace; capability-gated with nonce verification - π οΈ Developer Panel β Dev-mode-only panel showing field metadata, current values, PHP data types, and copy-ready code snippets
- πͺΆ 392KB total β Lightweight alternative to Redux Framework with a fraction of the footprint
- π§Ή Modern PHP 8.0+ β Clean, singleton-pattern architecture with type hints throughout
- π i18n Ready β Full internationalisation support with
.potfile included
30 field types across 12 categories β everything a theme needs, nothing it doesn't.
| Category | Fields |
|---|---|
| Text | Text, Textarea |
| Number | Number / Spinner, Slider |
| Choice | Select, Button Set, Radio, Checkbox, Select Image |
| Toggle | Toggle / Switch |
| Color | Color Picker, Gradient Picker |
| Media | Image, Gallery, Icon (FontAwesome 6) |
| Layout | Typography, Dimensions, Spacing, Border |
| Special | Info, Section, Shortcode, Raw |
| Date | Date Picker (date only or date + time) |
| Social | Social Media Links (20 platforms) |
| Code | Code Editor (CSS, JavaScript, HTML) |
| Advanced | Repeater, Background, Link, Group |
Every field returns a documented, consistent value. Key shapes:
| Field | Returns |
|---|---|
image |
{ id, url, width, height, alt, title } β empty array when removed |
gallery |
[{ id, url, alt }, ...] |
border |
{ width, style, color, radius } |
spacing |
{ top, right, bottom, left, unit } |
dimensions |
{ width, height, unit } |
background |
{ mode, color, image, position, size, repeat, attachment, gradient } |
link |
{ url, text, target, rel } |
social_media |
[{ platform, url }, ...] |
typography |
{ font-family, font-size, font-weight, font-style, line-height, letter-spacing, text-transform, subsets } |
gradient_picker |
Complete CSS linear-gradient() string |
repeater |
Array of row arrays, each keyed by sub-field id |
group |
Single row array keyed by sub-field id |
| Context | Format | Example |
|---|---|---|
Section / subsection icon |
FontAwesome name only | 'pen', 'palette', 'code' |
Icon field default |
Full FontAwesome class | 'fa-solid fa-star', 'fa-brands fa-github' |
| Requirement | Version |
|---|---|
| WordPress | 6.8 or higher |
| PHP | 8.0 or higher |
ThemePlus has been submitted to the WordPress.org plugin directory. Once approved, search for ThemePlus in Plugins β Add New.
- Go to Releases
- Download the latest
themeplus.zip - In your WordPress admin go to Plugins β Add New β Upload Plugin
- Upload the ZIP and activate
cd wp-content/plugins
git clone https://github.com/fronttheme/themeplus.gitActivate from Plugins in your WordPress admin.
Note for Git / direct ZIP installs: WordPress.org auto-loads translations for directory-listed plugins. For installs outside WordPress.org, add
load_plugin_textdomain( 'themeplus', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' )to your theme if you need translations.
$plugins = [
[
'name' => 'ThemePlus',
'slug' => 'themeplus',
'source' => 'https://github.com/fronttheme/themeplus/releases/latest/download/themeplus.zip',
'required' => true,
],
];ThemePlus does nothing on its own β it is a framework for theme developers. To add a settings panel to your theme:
- Copy
includes/config/sample-config.phpfrom the plugin into your theme (rename thethemeplus_sample_prefix to your own theme prefix) - Include it in
functions.php:require_once get_template_directory() . '/inc/themeplus-config.php'; - Configure
themeplus_framework_config()with your theme's details - Add sections and fields using
themeplus_add_section() - Retrieve values with
themeplus_get_option( 'field_id' )
// In inc/themeplus-config.php
add_action( 'after_setup_theme', function () {
if ( ! function_exists( 'themeplus_framework_config' ) ) {
return;
}
$theme = wp_get_theme();
themeplus_framework_config([
'display_name' => $theme->get( 'Name' ),
'opt_name' => 'my_theme_options', // Unique DB key β must be unique per theme
'menu_slug' => 'my-theme-settings',
'menu_title' => __( 'Theme Settings', 'your-textdomain' ),
'menu_icon' => 'dashicons-admin-appearance',
'text_domain' => 'your-textdomain',
]);
} );i18n convention: ThemePlus translates its own fallback strings using the
themeplusdomain. Every string you pass intothemeplus_framework_config()orthemeplus_add_section()should already be wrapped in__()with your theme's own text domain β the plugin never translates your theme's config strings.
add_action( 'init', function () {
if ( ! function_exists( 'themeplus_add_section' ) ) {
return;
}
themeplus_add_section([
'id' => 'general',
'title' => __( 'General Settings', 'your-textdomain' ),
'icon' => 'cog', // FontAwesome name only β the part after 'fa-solid fa-'
'fields' => [
[
'id' => 'enable_preloader',
'type' => 'toggle',
'title' => __( 'Enable Preloader', 'your-textdomain' ),
'default' => true,
],
[
'id' => 'primary_color',
'type' => 'color',
'title' => __( 'Primary Color', 'your-textdomain' ),
'default' => '#2271b1',
],
[
'id' => 'body_font',
'type' => 'typography',
'title' => __( 'Body Typography', 'your-textdomain' ),
'font-size' => true,
'font-weight' => true,
'line-height' => true,
'default' => [
'font-family' => 'Inter',
'font-size' => '16',
'font-weight' => '400',
],
],
[
'id' => 'brand_icon',
'type' => 'icon',
'title' => __( 'Brand Icon', 'your-textdomain' ),
'default' => 'fa-solid fa-star', // Full FontAwesome class for icon field default
],
],
]);
} );Nest subsections inline or attach them from a separate hook β the pattern for child themes and extension plugins:
// Inline subsections
themeplus_add_section([
'id' => 'header',
'title' => __( 'Header', 'your-textdomain' ),
'icon' => 'layout',
'fields' => [],
'subsections' => [
[
'id' => 'logo',
'title' => __( 'Logo', 'your-textdomain' ),
'icon' => 'image',
'fields' => [
[
'id' => 'logo_image',
'type' => 'image',
'title' => __( 'Logo Image', 'your-textdomain' ),
// Returns: { id, url, width, height, alt, title }
],
],
],
],
]);
// Attach from a separate hook (child theme / plugin extension pattern)
add_action( 'init', function () {
if ( ! function_exists( 'themeplus_add_subsection' ) ) {
return;
}
themeplus_add_subsection( 'header', [
'id' => 'sticky_header',
'title' => __( 'Sticky Header', 'your-textdomain' ),
'icon' => 'arrow-up',
'fields' => [
// ...
],
]);
}, 20 ); // Priority 20+ β after the parent section is registered// Single option
$color = themeplus_get_option( 'primary_color', '#2271b1' );
// All options at once β best for multiple fields on one template
$options = themeplus_get_option();
$color = $options['primary_color'] ?? '#2271b1';
$enabled = $options['enable_preloader'] ?? true;
// Structured field β image returns an array
$logo = themeplus_get_option( 'logo_image', [] );
$logo_url = $logo['url'] ?? '';
$logo_alt = $logo['alt'] ?? get_bloginfo( 'name' );
// Update programmatically
themeplus_update_option( 'primary_color', '#ff6b6b' );// Get a single option value
$value = themeplus_get_option( 'option_key', 'default_value' );
// Get all options as an array
$options = themeplus_get_option();
// Update a single option
themeplus_update_option( 'option_key', $new_value );
// Check if ThemePlus is active β safe to call before the plugin loads
if ( themeplus_is_active() ) {
// ...
}
// Get plugin version
$version = themeplus_get_version();Show or hide any field based on another field's value using the required key.
| Operator | Description |
|---|---|
== |
Equal to |
!= |
Not equal to |
> |
Greater than |
< |
Less than |
>= |
Greater than or equal to |
<= |
Less than or equal to |
contains |
Value contains string, or array contains item |
!contains |
Value does not contain string, or array does not contain item |
empty |
Field has no value (note: false and 0 are NOT empty) |
!empty |
Field has a value |
empty/!emptynote:falseand0are not considered empty β only absent values, empty strings, empty arrays, andnull. This matches PHP'sempty()semantics for booleans and integers.
// Format 1 β Single condition
'required' => [ 'enable_preloader', '==', true ],
// Format 2 β Multiple AND conditions (all must pass)
'required' => [
[ 'enable_header', '==', true ],
[ 'header_style', '!=', 'minimal' ],
],
// Format 3 β OR relation (any must pass)
'required' => [
'relation' => 'OR',
'conditions' => [
[ 'header_bg', '==', 'color' ],
[ 'header_bg', '==', 'gradient' ],
],
],
// Format 4 β Array value (matches any in list)
'required' => [ 'header_elements', '==', [ 'logo', 'search' ] ],
// Format 5 β Dot-notation sub-key (one level deep)
'required' => [ 'body_typography.font-family', '==', 'Inter' ],ThemePlus is designed to disappear into your theme. Your users see your theme's own settings panel β never "ThemePlus".
themeplus_framework_config([
// Branding
'display_name' => 'Nijhum Theme',
'opt_name' => 'nijhum_options', // Unique DB key β MUST be unique per theme
// Admin menu
'menu_slug' => 'nijhum-settings',
'menu_title' => 'Nijhum Settings',
'page_title' => 'Nijhum Theme Options',
'menu_icon' => 'dashicons-admin-appearance',
'menu_position' => 61,
'capability' => 'edit_theme_options', // Default; change to restrict access
// Features
'admin_bar' => true,
'show_search' => true,
'dev_mode' => defined( 'WP_DEBUG' ) && WP_DEBUG,
// i18n
'text_domain' => 'nijhum',
]);Important: Always set a unique
opt_nameper theme. If two themes share the same key, their settings will collide in the database.
- All saved options pass through
ThemePlus_Sanitizerβ unknown keys are dropped, every value is sanitized by its field type (numbers clamped, choices validated against registered options, URLs escaped, CSS stripped of tags) - REST endpoints require the configured capability (default
edit_theme_options) with nonce verification on every POST - Font uploads are MIME-type and magic-byte verified β a file renamed to
.woffwithout valid font headers is rejected - All output is escaped at every render point (
esc_attr,esc_url,wp_strip_all_tags) - Custom Fonts are not affected by Reset All or Reset Section β they are uploaded assets, not option values. Use the per-font Delete button to remove them
Full REST API under the themeplus/v1 namespace. All endpoints require the configured capability (default edit_theme_options) with nonce verification.
| Method | Endpoint | Description |
|---|---|---|
GET |
/themeplus/v1/options |
Get all saved options |
POST |
/themeplus/v1/options |
Save all options |
POST |
/themeplus/v1/options/reset |
Reset all options to defaults |
POST |
/themeplus/v1/options/reset-section |
Reset a single section to defaults |
GET |
/themeplus/v1/config |
Get full sections and fields configuration |
GET |
/themeplus/v1/dev-panel |
Field metadata and statistics (dev mode only) |
Enable dev mode to access the built-in Developer Panel β a dedicated admin section showing every registered field with its current saved value, PHP data type, dependency metadata, and copy-ready code snippets for all three access patterns.
// wp-config.php
define( 'WP_DEBUG', true );
define( 'THEMEPLUS_DEV', true );
THEMEPLUS_DEVmust be the booleantrueβ not the string"true". Remove it on production sites.
- Node.js 18+
- npm
- Local WordPress install (LocalWP recommended)
- PHP 8.0+
cd wp-content/plugins
git clone https://github.com/fronttheme/themeplus.git
cd themeplus
npm install# Start Vite dev server (SCSS with HMR β requires THEMEPLUS_DEV)
npm run dev
# Start webpack watch (JS/React)
npm run blocks:start
# Production build β SCSS via Vite
npm run build
# Production build β JS/React via wp-scripts
npm run blocks:build
# Generate translation .pot file
npm run pot
# Build and package release ZIP
npm run packageRun
npm run devandnpm run blocks:startin two separate terminals during development.
ThemePlus uses a hybrid build system β a deliberate choice that plays to each tool's strengths:
| Tool | Handles | Output |
|---|---|---|
| Vite | SCSS β CSS (with HMR in dev) | assets/css/admin.css |
| webpack / wp-scripts | React / JSX β JS + dependency manifest | assets/js/admin.js + admin.asset.php |
wp-scripts generates admin.asset.php with a content-hash version and the full WordPress dependency array (wp-components, wp-element, wp-api-fetch, wp-i18n, react) β the plugin enqueues from this file in production for correct cache busting.
- Build: Vite 7 (CSS) + webpack via
@wordpress/scripts(JS) - CSS: SCSS β modular 7-1 architecture with BEM methodology
- JS/UI: React (via
@wordpress/element), WordPress Components - PHP: Singleton pattern, PHP 8.0+, type hints throughout
- Fonts: Google Fonts API (1,899 fonts) + custom font upload system
Contributions are welcome! See CONTRIBUTING.md for the full guide including how to add new field types and the coding standards.
ThemePlus is licensed under GPL-2.0-or-later β the same licence as WordPress itself. Use it freely in personal projects, client work, and commercial themes.
Faruk Ahmed
- Website: farukdesign.com
- Brand: fronttheme.com
- GitHub: @fronttheme
Made with β€οΈ for the WordPress community Β· fronttheme.com
