Theme Architecture
BuddyX Pro uses a modern, component-based architecture with PSR-4 autoloading for organized, maintainable code.
Overview
The theme follows object-oriented principles with a modular component system. Each feature is encapsulated in its own component that implements the Component_Interface.
Key Features:
- PSR-4 autoloading with fallback
- Component-based architecture
- Template tag system
- Namespace:
BuddyxPro\BuddyxPro - Minimum requirements: WordPress 5.4+, PHP 8.0+
Directory Structure
buddyx-pro/
├── assets/ # CSS, JS, images, fonts
│ ├── css/
│ ├── js/
│ ├── images/
│ └── svg/
├── external/ # Third-party libraries (Kirki)
├── inc/ # Theme components (PSR-4 autoloaded)
│ ├── compatibility/ # Plugin integrations
│ │ ├── buddypress/
│ │ ├── woocommerce/
│ │ ├── learndash/
│ │ ├── fluentcart/
│ │ └── ...
│ ├── Customizer/ # Theme options
│ ├── Dynamic_Style/ # CSS generation
│ ├── Helpers/ # Helper classes
│ ├── widgets/ # Custom widgets
│ ├── Component_Interface.php
│ ├── Theme.php # Main theme class
│ ├── Template_Tags.php # Template tag system
│ └── functions.php # Entry point function
├── template-parts/ # Reusable template parts
├── vendor/ # Composer autoloader
├── functions.php # Theme initialization
└── style.css # Theme stylesheet
Core Architecture
Entry Point (functions.php)
// Setup autoloader (Composer or custom fallback)
if ( file_exists( get_template_directory() . '/vendor/autoload.php' ) ) {
require get_template_directory() . '/vendor/autoload.php';
} else {
spl_autoload_register( '_buddyxpro_autoload' );
}
// Load entry point function
require get_template_directory() . '/inc/functions.php';
// Initialize theme
call_user_func( 'BuddyxPro\BuddyxPro\buddyxpro' );
Component Interface
All theme components must implement Component_Interface:
namespace BuddyxPro\BuddyxPro;
interface Component_Interface {
/**
* Gets the unique identifier for the theme component.
*
* @return string Component slug.
*/
public function get_slug(): string;
/**
* Adds the action and filter hooks to integrate with WordPress.
*/
public function initialize();
}
Main Theme Class (Theme.php)
The Theme class orchestrates all components:
namespace BuddyxPro\BuddyxPro;
class Theme {
protected $components = array();
protected \BuddyxPro\BuddyxPro\Template_Tags $template_tags;
public function __construct( array $components = array() ) {
// Register components
foreach ( $components as $component ) {
$this->components[ $component->get_slug() ] = $component;
}
}
public function initialize() {
// Initialize all components
array_walk( $this->components, function( $component ) {
$component->initialize();
});
}
}
Default Components
Components registered in Theme.php:
Localization– Text domain and translationsBase_Support– WordPress theme featuresEditor– Block editor supportAccessibility– ARIA labels, skip linksImage_Sizes– Custom image sizesNav_Menus– Menu locationsSidebars– Widget areasCustomizer– Theme optionsDynamic_Style– CSS generation from customizerStyles– Stylesheet enqueuingScripts– JavaScript enqueuingBlocks– Gutenberg block supportKirki_Option– Kirki framework integration
Conditional Components:
// Jetpack integration (if active)
if ( defined( 'JETPACK__VERSION' ) ) {
$components[] = new Jetpack\Component();
}
// Dynamic styles (requires Kirki)
if ( class_exists( 'Kirki' ) ) {
$components[] = new Dynamic_Style\Component();
}
PSR-4 Autoloading
File-to-Class Mapping
Class namespace maps directly to file path:
Namespace: BuddyxPro\BuddyxPro\Customizer\Component
File: inc/Customizer/Component.php
Namespace: BuddyxPro\BuddyxPro\Dynamic_Style\Component
File: inc/Dynamic_Style/Component.php
Custom Autoloader (Fallback)
If Composer is unavailable:
function _buddyxpro_autoload( $class_name ) {
$namespace = 'BuddyxPro\BuddyxPro';
if ( 0 !== strpos( $class_name, $namespace . '\\' ) ) {
return false;
}
// Convert namespace to file path
$parts = explode( '\\', substr( $class_name, strlen( $namespace . '\\' ) ) );
$path = get_template_directory() . '/inc';
foreach ( $parts as $part ) {
$path .= '/' . $part;
}
$path .= '.php';
if ( file_exists( $path ) ) {
require_once $path;
return true;
}
return false;
}
spl_autoload_register( '_buddyxpro_autoload' );
Template Tag System
Accessing Template Tags
Template tags are accessible via the buddyxpro() function:
// In template files
buddyxpro()->display_header();
buddyxpro()->posted_on();
buddyxpro()->get_version();
Template_Tags Class
The Template_Tags class provides magic method access:
class Template_Tags {
protected $template_tags = array();
public function __call( string $method, array $args ) {
if ( ! isset( $this->template_tags[ $method ] ) ) {
throw new BadMethodCallException(
sprintf( 'The template tag %s does not exist.', $method )
);
}
return call_user_func_array(
$this->template_tags[ $method ]['callback'],
$args
);
}
}
Registering Template Tags
Components implement TemplatingComponentInterface:
namespace BuddyxPro\BuddyxPro\MyComponent;
use BuddyxPro\BuddyxPro\Component_Interface;
use BuddyxPro\BuddyxPro\Templating_Component_Interface;
class Component implements Component_Interface, Templating_Component_Interface {
public function template_tags(): array {
return array(
'my_custom_tag' => array( $this, 'render_custom_tag' ),
);
}
public function render_custom_tag() {
// Template tag logic
}
}
Plugin Integration Pattern
Plugin integrations are isolated in inc/compatibility/:
Directory Structure
inc/compatibility/
├── buddypress/
│ ├── buddypress-functions.php
│ └── README.md
├── woocommerce/
│ ├── woocommerce-functions.php
│ └── README.md
├── fluentcart/
│ ├── fluentcart-functions.php
│ ├── HOOKS-REFERENCE.md
│ └── README.md
└── learndash/
├── learndash-functions.php
└── README.md
Conditional Loading
In functions.php:
// Load WooCommerce functions
if ( class_exists( 'WooCommerce' ) ) {
require get_template_directory() . '/inc/compatibility/woocommerce/woocommerce-functions.php';
}
// Load FluentCart functions
if ( defined( 'FLUENTCART_PLUGIN_FILE_PATH' ) ) {
require get_template_directory() . '/inc/compatibility/fluentcart/fluentcart-functions.php';
}
// Load LearnDash functions
if ( class_exists( 'SFWD_LMS' ) ) {
require get_template_directory() . '/inc/compatibility/learndash/learndash-functions.php';
}
Integration Class Pattern
class BuddyXPro_FluentCart_Support {
private static $instance = null;
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
$this->init_hooks();
}
private function init_hooks() {
// Add hooks for plugin integration
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_styles' ) );
add_filter( 'body_class', array( $this, 'add_body_classes' ) );
}
}
// Initialize
BuddyXPro_FluentCart_Support::get_instance();
Customizer Architecture
Kirki Framework
BuddyX Pro uses Kirki for theme options:
// Load Kirki
require get_template_directory() . '/external/include-kirki.php';
// Register config
Kirki::add_config( 'buddyx_config', array(
'capability' => 'edit_theme_options',
'option_type' => 'theme_mod',
) );
Adding Customizer Options
// Panel
Kirki::add_panel( 'my_panel', array(
'title' => __( 'My Panel', 'buddyxpro' ),
'priority' => 10,
) );
// Section
Kirki::add_section( 'my_section', array(
'title' => __( 'My Section', 'buddyxpro' ),
'panel' => 'my_panel',
) );
// Control
Kirki::add_field( 'buddyx_config', array(
'type' => 'toggle',
'settings' => 'my_option',
'label' => __( 'Enable Feature', 'buddyxpro' ),
'section' => 'my_section',
'default' => false,
) );
Dynamic Style Generation
Component-Based CSS
The Dynamic_Style component generates CSS from customizer settings:
namespace BuddyxPro\BuddyxPro\Dynamic_Style;
class Component implements Component_Interface {
public function initialize() {
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_dynamic_css' ), 20 );
}
public function enqueue_dynamic_css() {
$css = $this->generate_css();
wp_add_inline_style( 'buddyx-style', $css );
}
private function generate_css() {
$primary_color = get_theme_mod( 'primary_color', '#ef5455' );
return "
:root {
--color-primary: {$primary_color};
}
";
}
}
Widget Registration
Custom Widgets
Widgets are in inc/widgets/:
// Load widgets
require get_template_directory() . '/inc/widgets/login-widget.php';
require get_template_directory() . '/inc/widgets/bp-profile-completion-widget.php';
Widget Class Example
class BuddyX_Login_Widget extends WP_Widget {
public function __construct() {
parent::__construct(
'buddyx_login_widget',
__( 'BuddyX Login', 'buddyxpro' ),
array( 'description' => __( 'Login form widget', 'buddyxpro' ) )
);
}
public function widget( $args, $instance ) {
// Widget output
}
}
// Register widget
function buddyx_register_login_widget() {
register_widget( 'BuddyX_Login_Widget' );
}
add_action( 'widgets_init', 'buddyx_register_login_widget' );
Helper Functions
Modular Helpers (inc/Helpers/)
// Login and registration popups
require_once get_template_directory() . '/inc/Helpers/Login_Forms.php';
// BuddyPress activity enhancements
require_once get_template_directory() . '/inc/Helpers/Activity_Functions.php';
// Side panel functionality
require_once get_template_directory() . '/inc/Helpers/Side_Panel.php';
// Dark mode toggle
require_once get_template_directory() . '/inc/Helpers/Dark_Mode.php';
Utility Functions (inc/extra.php)
Core template functions:
// Content wrapper hooks
add_action( 'buddyx_before_content', 'buddyx_content_top' );
add_action( 'buddyx_after_content', 'buddyx_content_bottom' );
// Sub header
add_action( 'buddyx_sub_header', 'buddyx_sub_header' );
// Menu icons
add_action( 'buddyx_header', 'buddyx_site_menu_icon' );
Version Management
Theme Version
// Get theme version
$version = wp_get_theme( get_template() )->get( 'Version' );
// Via template tags
buddyxpro()->get_version();
Asset Versioning
// Development: file modification time
// Production: theme version
buddyxpro()->get_asset_version( $filepath );
Best Practices
Do
- Use PSR-4 autoloading for new classes
- Implement
Component_Interfacefor new components - Use template tag system for reusable functions
- Add plugin integrations to
inc/compatibility/ - Use Kirki for customizer options
- Prefix all functions with
buddyxorbuddyxpro - Use namespace
BuddyxPro\BuddyxProfor classes
Don’t
- Modify core theme files directly
- Add business logic to templates
- Use global variables without prefixing
- Skip component initialization
- Bypass the autoloader
- Hardcode plugin paths
