Customization Guide
Comprehensive guide to customizing BuddyX Pro theme appearance and functionality.
Getting Started
Prerequisites
- Active BuddyX Pro installation
- Child theme created (recommended)
- Basic PHP, CSS, and JavaScript knowledge
- FTP/SFTP access or File Manager
- Code editor (VS Code, Sublime Text, etc.)
Recommended Setup
buddyx-pro-child/
├── style.css # Custom CSS
├── functions.php # Custom functions
├── assets/
│ ├── css/
│ │ └── custom.css # Additional CSS
│ ├── js/
│ │ └── custom.js # Custom JavaScript
│ └── images/ # Custom images
└── inc/
└── customizations.php # Organized customizations
CSS Customization
Method 1: Customizer Additional CSS
Location: Appearance → Customize → Additional CSS
Quick CSS changes without creating files:
/* Change primary color */
:root {
--color-primary: #007bff;
--color-secondary: #6c757d;
}
/* Custom header styling */
.site-header {
background-color: #ffffff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
/* Modify button styles */
.button,
button[type="submit"] {
border-radius: 5px;
text-transform: uppercase;
letter-spacing: 1px;
}
Method 2: Child Theme style.css
Location: buddyx-pro-child/style.css
For permanent, version-controlled changes:
/*
Theme Name: BuddyX Pro Child
Template: buddyx-pro
*/
/* ==========================================================================
Typography
========================================================================== */
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 16px;
line-height: 1.6;
color: #333333;
}
h1, h2, h3, h4, h5, h6 {
font-weight: 700;
line-height: 1.3;
margin-bottom: 1rem;
}
/* ==========================================================================
Layout
========================================================================== */
.container {
max-width: 1200px;
}
.site-wrapper {
padding-top: 2rem;
padding-bottom: 2rem;
}
/* ==========================================================================
Header
========================================================================== */
.site-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 1rem 0;
}
.site-header .site-logo-wrapper img {
max-width: 180px;
}
/* ==========================================================================
Navigation
========================================================================== */
.main-navigation ul {
gap: 1.5rem;
}
.main-navigation a {
color: #ffffff;
font-weight: 500;
transition: opacity 0.3s ease;
}
.main-navigation a:hover {
opacity: 0.8;
}
/* ==========================================================================
BuddyPress
========================================================================== */
#buddypress .activity-list .activity-content .activity-inner {
background-color: #f8f9fa;
border-radius: 8px;
padding: 1.5rem;
}
#buddypress .activity-meta a {
color: var(--color-primary);
}
/* ==========================================================================
Footer
========================================================================== */
.site-footer {
background-color: #1a1a1a;
color: #ffffff;
padding: 3rem 0 1rem;
}
.site-footer a {
color: #ffffff;
}
Method 3: Separate CSS File
File: buddyx-pro-child/assets/css/custom.css
Enqueue in functions.php:
function buddyx_child_custom_styles() {
wp_enqueue_style(
'buddyx-child-custom',
get_stylesheet_directory_uri() . '/assets/css/custom.css',
array( 'buddyx-child-style' ),
'1.0.0'
);
}
add_action( 'wp_enqueue_scripts', 'buddyx_child_custom_styles', 30 );
CSS Variables Override
BuddyX Pro uses CSS custom properties:
:root {
/* Colors */
--color-primary: #ef5455;
--color-secondary: #6c757d;
--color-success: #28a745;
--color-danger: #dc3545;
--color-warning: #ffc107;
--color-info: #17a2b8;
/* Typography */
--font-primary: 'Roboto', sans-serif;
--font-secondary: 'Open Sans', sans-serif;
/* Spacing */
--spacing-small: 0.5rem;
--spacing-medium: 1rem;
--spacing-large: 2rem;
/* Border Radius */
--border-radius-small: 3px;
--border-radius-medium: 5px;
--border-radius-large: 10px;
/* Shadows */
--box-shadow-small: 0 2px 4px rgba(0, 0, 0, 0.1);
--box-shadow-medium: 0 4px 6px rgba(0, 0, 0, 0.1);
--box-shadow-large: 0 10px 20px rgba(0, 0, 0, 0.15);
}
JavaScript Customization
Adding Custom JavaScript
File: buddyx-pro-child/assets/js/custom.js
/**
* BuddyX Pro Child Theme JavaScript
*
* @package BuddyX Pro Child
*/
(function($) {
'use strict';
/**
* Document ready
*/
$(document).ready(function() {
console.log('BuddyX Child Theme Loaded');
// Smooth scroll to anchor links
$('a[href^="#"]').on('click', function(e) {
e.preventDefault();
var target = $(this.hash);
if (target.length) {
$('html, body').animate({
scrollTop: target.offset().top - 80
}, 600);
}
});
// Add active class to current menu item
var currentUrl = window.location.href;
$('.main-navigation a').each(function() {
if (this.href === currentUrl) {
$(this).parent().addClass('active');
}
});
// Custom search toggle
$('#custom-search-toggle').on('click', function(e) {
e.preventDefault();
$('.search-form-wrapper').toggleClass('active');
});
// Lazy load images
if ('loading' in HTMLImageElement.prototype) {
$('img[data-src]').each(function() {
$(this).attr('src', $(this).attr('data-src'));
$(this).removeAttr('data-src');
});
}
});
/**
* Window load
*/
$(window).on('load', function() {
// Remove preloader
$('.site-loader').fadeOut(300);
});
/**
* Window scroll
*/
$(window).on('scroll', function() {
var scroll = $(window).scrollTop();
// Sticky header
if (scroll >= 100) {
$('.site-header').addClass('sticky');
} else {
$('.site-header').removeClass('sticky');
}
// Back to top button
if (scroll >= 300) {
$('.back-to-top').fadeIn();
} else {
$('.back-to-top').fadeOut();
}
});
/**
* Back to top
*/
$('.back-to-top').on('click', function(e) {
e.preventDefault();
$('html, body').animate({ scrollTop: 0 }, 600);
});
})(jQuery);
Enqueue in functions.php:
function buddyx_child_custom_scripts() {
wp_enqueue_script(
'buddyx-child-custom',
get_stylesheet_directory_uri() . '/assets/js/custom.js',
array( 'jquery' ),
'1.0.0',
true
);
// Pass PHP data to JavaScript
wp_localize_script(
'buddyx-child-custom',
'buddyxChildData',
array(
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'buddyx_child_nonce' ),
'siteUrl' => get_site_url(),
'themeUrl' => get_stylesheet_directory_uri(),
'isLoggedIn' => is_user_logged_in(),
)
);
}
add_action( 'wp_enqueue_scripts', 'buddyx_child_custom_scripts' );
AJAX Example
JavaScript:
// custom.js
$('#custom-form').on('submit', function(e) {
e.preventDefault();
var formData = {
action: 'buddyx_child_ajax_action',
nonce: buddyxChildData.nonce,
data: $(this).serialize()
};
$.ajax({
url: buddyxChildData.ajaxurl,
type: 'POST',
data: formData,
beforeSend: function() {
$('.loading').show();
},
success: function(response) {
if (response.success) {
alert(response.data.message);
} else {
alert('Error: ' + response.data.message);
}
},
complete: function() {
$('.loading').hide();
}
});
});
PHP Handler:
// functions.php
function buddyx_child_ajax_handler() {
check_ajax_referer( 'buddyx_child_nonce', 'nonce' );
// Process form data
parse_str( $_POST['data'], $form_data );
// Your logic here
$result = true; // Your processing result
if ( $result ) {
wp_send_json_success( array(
'message' => __( 'Success!', 'buddyx-pro-child' ),
) );
} else {
wp_send_json_error( array(
'message' => __( 'Error occurred.', 'buddyx-pro-child' ),
) );
}
}
add_action( 'wp_ajax_buddyx_child_ajax_action', 'buddyx_child_ajax_handler' );
add_action( 'wp_ajax_nopriv_buddyx_child_ajax_action', 'buddyx_child_ajax_handler' );
PHP Customization
Custom Functions
File: buddyx-pro-child/inc/customizations.php
<?php
/**
* Custom Theme Functions
*
* @package BuddyX Pro Child
*/
/**
* Add custom body classes
*/
function buddyx_child_body_classes( $classes ) {
// Add page-specific classes
if ( is_page( 'about' ) ) {
$classes[] = 'page-about';
}
// Add user role class
if ( is_user_logged_in() ) {
$user = wp_get_current_user();
$classes[] = 'user-role-' . $user->roles[0];
}
// Add custom class based on customizer setting
if ( get_theme_mod( 'custom_layout', false ) ) {
$classes[] = 'custom-layout';
}
return $classes;
}
add_filter( 'body_class', 'buddyx_child_body_classes' );
/**
* Custom excerpt length
*/
function buddyx_child_excerpt_length( $length ) {
if ( is_front_page() ) {
return 30;
}
return 55;
}
add_filter( 'excerpt_length', 'buddyx_child_excerpt_length', 999 );
/**
* Custom excerpt more
*/
function buddyx_child_excerpt_more( $more ) {
return '... <a class="read-more" href="' . get_permalink() . '">' . __( 'Read More', 'buddyx-pro-child' ) . '</a>';
}
add_filter( 'excerpt_more', 'buddyx_child_excerpt_more' );
/**
* Add custom image sizes
*/
function buddyx_child_image_sizes() {
add_image_size( 'custom-thumbnail', 300, 200, true );
add_image_size( 'custom-featured', 800, 600, true );
add_image_size( 'custom-hero', 1920, 1080, true );
}
add_action( 'after_setup_theme', 'buddyx_child_image_sizes' );
/**
* Modify main query
*/
function buddyx_child_pre_get_posts( $query ) {
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
// Show 12 posts per page on archive
if ( is_archive() ) {
$query->set( 'posts_per_page', 12 );
}
// Exclude category from home
if ( $query->is_home() ) {
$query->set( 'cat', '-5' ); // Exclude category ID 5
}
}
add_action( 'pre_get_posts', 'buddyx_child_pre_get_posts' );
/**
* Custom post meta
*/
function buddyx_child_post_meta() {
if ( ! is_single() ) {
return;
}
echo '<div class="custom-post-meta">';
echo '<span class="author">' . get_the_author() . '</span>';
echo '<span class="date">' . get_the_date() . '</span>';
echo '<span class="comments">' . get_comments_number() . ' Comments</span>';
echo '</div>';
}
add_action( 'buddyx_after_content', 'buddyx_child_post_meta' );
Load in functions.php:
// Load customizations
require_once get_stylesheet_directory() . '/inc/customizations.php';
Widget Customization
Custom Widget Area
// functions.php
function buddyx_child_register_sidebars() {
register_sidebar( array(
'name' => __( 'Custom Sidebar', 'buddyx-pro-child' ),
'id' => 'custom-sidebar',
'description' => __( 'Custom widget area', 'buddyx-pro-child' ),
'before_widget' => '<div id="%1$s" class="widget %2$s">',
'after_widget' => '</div>',
'before_title' => '<h3 class="widget-title">',
'after_title' => '</h3>',
) );
}
add_action( 'widgets_init', 'buddyx_child_register_sidebars' );
Display Custom Widget Area
// In template file or via hook
<?php
if ( is_active_sidebar( 'custom-sidebar' ) ) {
dynamic_sidebar( 'custom-sidebar' );
}
?>
Custom Widget
// inc/widgets/custom-widget.php
class BuddyX_Custom_Widget extends WP_Widget {
public function __construct() {
parent::__construct(
'buddyx_custom_widget',
__( 'Custom Widget', 'buddyx-pro-child' ),
array(
'description' => __( 'Display custom content', 'buddyx-pro-child' ),
'classname' => 'buddyx-custom-widget',
)
);
}
public function widget( $args, $instance ) {
$title = ! empty( $instance['title'] ) ? $instance['title'] : '';
$content = ! empty( $instance['content'] ) ? $instance['content'] : '';
echo $args['before_widget'];
if ( ! empty( $title ) ) {
echo $args['before_title'] . esc_html( $title ) . $args['after_title'];
}
echo '<div class="widget-content">';
echo wp_kses_post( wpautop( $content ) );
echo '</div>';
echo $args['after_widget'];
}
public function form( $instance ) {
$title = ! empty( $instance['title'] ) ? $instance['title'] : '';
$content = ! empty( $instance['content'] ) ? $instance['content'] : '';
?>
<p>
<label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>">
<?php esc_html_e( 'Title:', 'buddyx-pro-child' ); ?>
</label>
<input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>">
</p>
<p>
<label for="<?php echo esc_attr( $this->get_field_id( 'content' ) ); ?>">
<?php esc_html_e( 'Content:', 'buddyx-pro-child' ); ?>
</label>
<textarea class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'content' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'content' ) ); ?>" rows="5"><?php echo esc_textarea( $content ); ?></textarea>
</p>
<?php
}
public function update( $new_instance, $old_instance ) {
$instance = array();
$instance['title'] = sanitize_text_field( $new_instance['title'] );
$instance['content'] = wp_kses_post( $new_instance['content'] );
return $instance;
}
}
function buddyx_child_register_custom_widget() {
register_widget( 'BuddyX_Custom_Widget' );
}
add_action( 'widgets_init', 'buddyx_child_register_custom_widget' );
Customizer Integration
Add Customizer Panel
// inc/customizer.php
function buddyx_child_customize_register( $wp_customize ) {
// Add panel
$wp_customize->add_panel( 'buddyx_child_panel', array(
'title' => __( 'Child Theme Options', 'buddyx-pro-child' ),
'description' => __( 'Customize child theme settings', 'buddyx-pro-child' ),
'priority' => 30,
) );
// Add section
$wp_customize->add_section( 'buddyx_child_colors', array(
'title' => __( 'Custom Colors', 'buddyx-pro-child' ),
'panel' => 'buddyx_child_panel',
) );
// Add setting: Primary color
$wp_customize->add_setting( 'child_primary_color', array(
'default' => '#007bff',
'sanitize_callback' => 'sanitize_hex_color',
'transport' => 'postMessage',
) );
// Add control
$wp_customize->add_control( new WP_Customize_Color_Control(
$wp_customize,
'child_primary_color',
array(
'label' => __( 'Primary Color', 'buddyx-pro-child' ),
'section' => 'buddyx_child_colors',
)
) );
// Add setting: Toggle option
$wp_customize->add_setting( 'child_enable_feature', array(
'default' => false,
'sanitize_callback' => 'wp_validate_boolean',
) );
$wp_customize->add_control( 'child_enable_feature', array(
'label' => __( 'Enable Custom Feature', 'buddyx-pro-child' ),
'section' => 'buddyx_child_colors',
'type' => 'checkbox',
) );
// Add setting: Text option
$wp_customize->add_setting( 'child_custom_text', array(
'default' => '',
'sanitize_callback' => 'sanitize_text_field',
) );
$wp_customize->add_control( 'child_custom_text', array(
'label' => __( 'Custom Text', 'buddyx-pro-child' ),
'section' => 'buddyx_child_colors',
'type' => 'text',
) );
}
add_action( 'customize_register', 'buddyx_child_customize_register' );
Use Customizer Values
// In template or functions
$primary_color = get_theme_mod( 'child_primary_color', '#007bff' );
$enable_feature = get_theme_mod( 'child_enable_feature', false );
$custom_text = get_theme_mod( 'child_custom_text', '' );
// Generate CSS from customizer
function buddyx_child_customizer_css() {
$primary_color = get_theme_mod( 'child_primary_color', '#007bff' );
$css = "
:root {
--child-primary: {$primary_color};
}
.button-primary {
background-color: {$primary_color};
}
";
wp_add_inline_style( 'buddyx-child-style', $css );
}
add_action( 'wp_enqueue_scripts', 'buddyx_child_customizer_css', 50 );
Shortcode Creation
Simple Shortcode
// functions.php
function buddyx_child_button_shortcode( $atts, $content = null ) {
$atts = shortcode_atts( array(
'url' => '#',
'style' => 'primary',
'size' => 'medium',
'icon' => '',
), $atts );
$class = 'btn btn-' . esc_attr( $atts['style'] ) . ' btn-' . esc_attr( $atts['size'] );
$icon_html = '';
if ( ! empty( $atts['icon'] ) ) {
$icon_html = '<i class="fa fa-' . esc_attr( $atts['icon'] ) . '"></i> ';
}
return sprintf(
'<a href="%s" class="%s">%s%s</a>',
esc_url( $atts['url'] ),
esc_attr( $class ),
$icon_html,
esc_html( $content )
);
}
add_shortcode( 'button', 'buddyx_child_button_shortcode' );
// Usage: [button url="/signup/" style="primary" icon="user"]Sign Up[/button]
Advanced Shortcode with Query
function buddyx_child_recent_posts_shortcode( $atts ) {
$atts = shortcode_atts( array(
'posts' => 3,
'category' => '',
'layout' => 'grid',
), $atts );
$args = array(
'post_type' => 'post',
'posts_per_page' => intval( $atts['posts'] ),
'post_status' => 'publish',
);
if ( ! empty( $atts['category'] ) ) {
$args['category_name'] = sanitize_text_field( $atts['category'] );
}
$query = new WP_Query( $args );
if ( ! $query->have_posts() ) {
return '';
}
ob_start();
?>
<div class="recent-posts layout-<?php echo esc_attr( $atts['layout'] ); ?>">
<?php
while ( $query->have_posts() ) {
$query->the_post();
?>
<article class="recent-post-item">
<?php if ( has_post_thumbnail() ) : ?>
<div class="post-thumbnail">
<a href="<?php the_permalink(); ?>">
<?php the_post_thumbnail( 'medium' ); ?>
</a>
</div>
<?php endif; ?>
<div class="post-content">
<h3 class="post-title">
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
</h3>
<div class="post-excerpt">
<?php the_excerpt(); ?>
</div>
</div>
</article>
<?php
}
?>
</div>
<?php
wp_reset_postdata();
return ob_get_clean();
}
add_shortcode( 'recent_posts', 'buddyx_child_recent_posts_shortcode' );
// Usage: [recent_posts posts="5" category="news" layout="grid"]
Translation/Internationalization
Setup Translation
// functions.php
function buddyx_child_load_textdomain() {
load_child_theme_textdomain(
'buddyx-pro-child',
get_stylesheet_directory() . '/languages'
);
}
add_action( 'after_setup_theme', 'buddyx_child_load_textdomain' );
Translatable Strings
// Use translation functions
__( 'Text', 'buddyx-pro-child' ); // Return translated
_e( 'Text', 'buddyx-pro-child' ); // Echo translated
esc_html__( 'Text', 'buddyx-pro-child' ); // Return and escape
esc_html_e( 'Text', 'buddyx-pro-child' ); // Echo and escape
esc_attr__( 'Text', 'buddyx-pro-child' ); // Return for attributes
// With placeholders
sprintf(
__( 'Hello %s!', 'buddyx-pro-child' ),
$name
);
// Plurals
_n(
'%s item',
'%s items',
$count,
'buddyx-pro-child'
);
Generate Translation Files
# Install WP-CLI i18n command
wp package install wp-cli/i18n-command
# Generate POT file
wp i18n make-pot . languages/buddyx-pro-child.pot
# Update PO files
wp i18n update-po languages/buddyx-pro-child.pot languages/
Performance Optimization
Conditional Script Loading
function buddyx_child_conditional_scripts() {
// Load only on specific pages
if ( is_page( 'contact' ) ) {
wp_enqueue_script( 'google-maps', 'https://maps.googleapis.com/maps/api/js?key=YOUR_KEY', array(), null, true );
}
// Load only for logged-in users
if ( is_user_logged_in() ) {
wp_enqueue_script( 'user-dashboard', get_stylesheet_directory_uri() . '/assets/js/dashboard.js', array( 'jquery' ), '1.0.0', true );
}
// Load only on BuddyPress pages
if ( function_exists( 'is_buddypress' ) && is_buddypress() ) {
wp_enqueue_script( 'bp-custom', get_stylesheet_directory_uri() . '/assets/js/buddypress-custom.js', array( 'jquery' ), '1.0.0', true );
}
}
add_action( 'wp_enqueue_scripts', 'buddyx_child_conditional_scripts' );
Defer/Async Scripts
function buddyx_child_defer_scripts( $tag, $handle, $src ) {
// Defer non-critical scripts
$defer_scripts = array( 'buddyx-child-custom', 'analytics' );
if ( in_array( $handle, $defer_scripts, true ) ) {
return str_replace( ' src', ' defer src', $tag );
}
return $tag;
}
add_filter( 'script_loader_tag', 'buddyx_child_defer_scripts', 10, 3 );
Image Optimization
// Add WebP support
function buddyx_child_upload_mimes( $mimes ) {
$mimes['webp'] = 'image/webp';
return $mimes;
}
add_filter( 'upload_mimes', 'buddyx_child_upload_mimes' );
// Lazy load images
function buddyx_child_lazy_load_images( $content ) {
if ( is_feed() || is_admin() ) {
return $content;
}
$content = preg_replace( '/<img(.*?)src=/i', '<img$1loading="lazy" src=', $content );
return $content;
}
add_filter( 'the_content', 'buddyx_child_lazy_load_images' );
Security Enhancements
Nonce Verification
// Form with nonce
function buddyx_child_custom_form() {
?>
<form method="post" action="">
<?php wp_nonce_field( 'buddyx_child_form_action', 'buddyx_child_nonce' ); ?>
<input type="text" name="custom_field" />
<button type="submit">Submit</button>
</form>
<?php
}
// Process form
function buddyx_child_process_form() {
if ( ! isset( $_POST['buddyx_child_nonce'] ) || ! wp_verify_nonce( $_POST['buddyx_child_nonce'], 'buddyx_child_form_action' ) ) {
wp_die( __( 'Security check failed', 'buddyx-pro-child' ) );
}
$custom_field = sanitize_text_field( $_POST['custom_field'] );
// Process data
}
Sanitization and Validation
// Sanitize different input types
$text = sanitize_text_field( $_POST['text'] );
$email = sanitize_email( $_POST['email'] );
$url = esc_url_raw( $_POST['url'] );
$html = wp_kses_post( $_POST['html'] );
$int = absint( $_POST['number'] );
// Validate email
if ( ! is_email( $email ) ) {
// Invalid email
}
// Validate URL
if ( ! filter_var( $url, FILTER_VALIDATE_URL ) ) {
// Invalid URL
}
Best Practices Checklist
Development
- Use child theme for all customizations
- Prefix all custom functions
- Follow WordPress Coding Standards
- Comment your code
- Use version control (Git)
- Test on multiple devices
- Check browser compatibility
- Validate HTML/CSS
Security
- Escape all output
- Sanitize all input
- Verify nonces
- Check capabilities
- Use prepared statements for database queries
- Don’t trust user input
Performance
- Minimize HTTP requests
- Optimize images
- Use conditional loading
- Defer non-critical scripts
- Enable caching
- Minimize CSS/JS
Accessibility
- Use semantic HTML
- Add alt text to images
- Ensure keyboard navigation
- Test with screen readers
- Use ARIA labels
- Maintain color contrast
