Skip to main content

Theme Customization

Customizing WooCommerce themes requires understanding CSS styling, WordPress hooks, child theme architecture, and upgrade-safe development practices. This guide covers all aspects of theme customization from basic styling to advanced functionality modifications.

Child Themes

Child themes provide an upgrade-safe way to customize parent themes. Changes in child themes persist through parent theme updates, preventing loss of customizations.
This section covers classic child themes. For block theme child themes, see the WordPress Block Child Theme Guide.

Why Use Child Themes?

Update Safety

Customizations survive parent theme updates without being overwritten

Organized Customization

All modifications live in one directory, separate from parent theme

Easy Rollback

Deactivate child theme to revert to parent theme instantly

Development Flexibility

Override any parent template or add new functionality independently

Creating a Child Theme

1

Create Child Theme Directory

Create a new directory in wp-content/themes/:
wp-content/themes/storefront-child/
Name it descriptively: parenttheme-child
2

Create style.css

Create style.css with required header information:
/*
Theme Name:   Storefront Child
Theme URI:    https://example.com/storefront-child
Description:  Child theme for Storefront
Author:       Your Name
Author URI:   https://example.com
Template:     storefront
Version:      1.0.0
License:      GNU General Public License v2 or later
License URI:  http://www.gnu.org/licenses/gpl-2.0.html
Text Domain:  storefront-child
*/

/* --------------- Theme customization starts here ----------------- */
Critical: Template must match parent theme directory name exactly.
3

Create functions.php

Create a blank functions.php file:
<?php
/**
 * Storefront Child Theme Functions
 */

// Add your custom functions here
Do NOT copy parent theme’s functions.php content. Child theme functions.php loads before parent theme’s.
4

Activate Child Theme

Go to Appearance → Themes and activate your child theme. The parent theme must remain installed.

Child Theme File Structure

storefront-child/
├── style.css              # Required: Theme stylesheet and metadata
├── functions.php          # Theme functions and hooks
├── screenshot.png         # Theme thumbnail (880x660px recommended)
├── woocommerce/          # WooCommerce template overrides
│   ├── single-product.php
│   ├── archive-product.php
│   └── cart/
│       └── cart.php
├── template-parts/        # Custom template parts
├── assets/
│   ├── css/
│   │   └── custom.css
│   ├── js/
│   │   └── custom.js
│   └── images/
└── languages/             # Translation files

CSS Customization

CSS provides the primary method for visual customization. WooCommerce includes comprehensive CSS architecture that can be extended or completely replaced.

Basic CSS Overrides

Add custom CSS to child theme’s style.css:
/* Customize WooCommerce buttons */
.woocommerce a.button,
.woocommerce button.button,
.woocommerce input.button,
.woocommerce #respond input#submit {
    background-color: #2c3e50;
    color: #ffffff;
    border-radius: 4px;
    padding: 12px 24px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.woocommerce a.button:hover,
.woocommerce button.button:hover,
.woocommerce input.button:hover {
    background-color: #34495e;
}

/* Product page layout */
.woocommerce div.product .summary {
    margin-bottom: 2rem;
}

.woocommerce div.product .woocommerce-product-gallery {
    margin-bottom: 2rem;
}

/* Price styling */
.woocommerce div.product p.price,
.woocommerce div.product span.price {
    color: #e63946;
    font-size: 1.75rem;
    font-weight: 700;
}

/* Sale badge */
.woocommerce span.onsale {
    background-color: #e63946;
    color: #ffffff;
    border-radius: 50%;
    padding: 0.5rem;
}

Targeting WooCommerce Body Classes

WooCommerce adds helpful body classes for targeting specific pages:
/* Shop page only */
.woocommerce-shop .site-header {
    background-color: #f8f9fa;
}

/* Single product pages */
.single-product .site-main {
    max-width: 1200px;
    margin: 0 auto;
}

/* Product category pages */
.woocommerce-archive .woocommerce-breadcrumb {
    margin-bottom: 2rem;
}

/* Cart page */
.woocommerce-cart .woocommerce {
    padding: 2rem;
}

/* Checkout page */
.woocommerce-checkout .woocommerce-form-coupon-toggle {
    display: none;
}

Product Loop Customization

Customize product grid displays:
/* Product grid layout */
.woocommerce ul.products {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    gap: 2rem;
}

.woocommerce ul.products li.product {
    border: 1px solid #e0e0e0;
    border-radius: 8px;
    padding: 1.5rem;
    transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.woocommerce ul.products li.product:hover {
    transform: translateY(-4px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

/* Product images in loop */
.woocommerce ul.products li.product img {
    border-radius: 4px;
    margin-bottom: 1rem;
}

/* Product titles */
.woocommerce ul.products li.product .woocommerce-loop-product__title {
    font-size: 1.125rem;
    font-weight: 600;
    margin-bottom: 0.5rem;
}

/* Add to cart buttons in loop */
.woocommerce ul.products li.product .button {
    width: 100%;
    text-align: center;
}

Responsive Design

Add mobile-responsive styles:
/* Mobile styles */
@media (max-width: 768px) {
    .woocommerce div.product div.images,
    .woocommerce div.product div.summary {
        width: 100%;
        float: none;
    }
    
    .woocommerce table.shop_table {
        font-size: 0.875rem;
    }
    
    .woocommerce ul.products {
        grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
        gap: 1rem;
    }
}

/* Tablet styles */
@media (min-width: 769px) and (max-width: 1024px) {
    .woocommerce ul.products {
        grid-template-columns: repeat(3, 1fr);
    }
}

/* Desktop styles */
@media (min-width: 1025px) {
    .woocommerce ul.products {
        grid-template-columns: repeat(4, 1fr);
    }
}

Disabling WooCommerce Styles

For complete CSS control, disable WooCommerce’s default stylesheet:
// In child theme's functions.php
add_filter( 'woocommerce_enqueue_styles', '__return_false' );
Disabling WooCommerce styles requires styling all WooCommerce elements from scratch. Only use this for complete redesigns. See the WooCommerce Theme Testing Checklist for elements that need styling.

Hooks and Filters

WordPress hooks provide upgrade-safe functionality customization without modifying core files.

Understanding Actions vs Filters

Actions execute functions at specific points. Use for adding/removing content.
// Add custom content after product title
add_action( 'woocommerce_single_product_summary', 'mytheme_custom_badge', 6 );

function mytheme_custom_badge() {
    global $product;
    
    if ( $product->is_featured() ) {
        echo '<div class="featured-badge">Featured Product</div>';
    }
}
Priority matters: Lower numbers execute earlier (default is 10).

Common Customization Hooks

/**
 * Add custom content to product page
 */

// Add delivery information before add to cart
add_action( 'woocommerce_before_add_to_cart_form', 'mytheme_delivery_info' );
function mytheme_delivery_info() {
    echo '<div class="delivery-info">';
    echo '<p>Free delivery on orders over $50</p>';
    echo '</div>';
}

// Add trust badges after price
add_action( 'woocommerce_single_product_summary', 'mytheme_trust_badges', 11 );
function mytheme_trust_badges() {
    echo '<div class="trust-badges">';
    echo '<img src="' . get_stylesheet_directory_uri() . '/assets/images/secure-checkout.png" alt="Secure Checkout">';
    echo '</div>';
}

// Remove product meta (SKU, categories, tags)
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_meta', 40 );

// Reposition price after product title
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_price', 10 );
add_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_price', 6 );

Removing Default Hooks

Remove WooCommerce’s default functionality:
/**
 * Remove WooCommerce default actions
 */

// Remove breadcrumbs
remove_action( 'woocommerce_before_main_content', 'woocommerce_breadcrumb', 20 );

// Remove product rating
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_rating', 10 );

// Remove related products
remove_action( 'woocommerce_after_single_product_summary', 'woocommerce_output_related_products', 20 );

// Remove upsells
remove_action( 'woocommerce_after_single_product_summary', 'woocommerce_upsell_display', 15 );

// Remove product tabs
remove_action( 'woocommerce_after_single_product_summary', 'woocommerce_output_product_data_tabs', 10 );
Always use the same priority when removing an action that was used when adding it. Check WooCommerce template files for default priorities.

Enqueuing Custom Assets

Add custom CSS and JavaScript files properly:
/**
 * Enqueue child theme styles and scripts
 */
function mytheme_enqueue_assets() {
    // Enqueue parent theme styles (if needed)
    wp_enqueue_style( 'parent-style', 
        get_template_directory_uri() . '/style.css' 
    );
    
    // Enqueue child theme styles
    wp_enqueue_style( 'child-style',
        get_stylesheet_directory_uri() . '/style.css',
        array( 'parent-style' ),
        wp_get_theme()->get('Version')
    );
    
    // Enqueue custom CSS
    wp_enqueue_style( 'custom-woocommerce',
        get_stylesheet_directory_uri() . '/assets/css/custom.css',
        array( 'woocommerce-general' ),
        '1.0.0'
    );
    
    // Enqueue custom JavaScript
    wp_enqueue_script( 'custom-woocommerce-js',
        get_stylesheet_directory_uri() . '/assets/js/custom.js',
        array( 'jquery', 'wc-cart-fragments' ),
        '1.0.0',
        true
    );
    
    // Localize script with AJAX URL
    wp_localize_script( 'custom-woocommerce-js', 'mytheme_vars', array(
        'ajax_url' => admin_url( 'admin-ajax.php' ),
        'nonce'    => wp_create_nonce( 'mytheme_nonce' ),
    ) );
}
add_action( 'wp_enqueue_scripts', 'mytheme_enqueue_assets' );

/**
 * Enqueue custom scripts only on WooCommerce pages
 */
function mytheme_woocommerce_scripts() {
    if ( is_woocommerce() || is_cart() || is_checkout() ) {
        wp_enqueue_script( 'mytheme-woocommerce',
            get_stylesheet_directory_uri() . '/assets/js/woocommerce.js',
            array( 'jquery' ),
            '1.0.0',
            true
        );
    }
}
add_action( 'wp_enqueue_scripts', 'mytheme_woocommerce_scripts' );

Template Overrides in Child Themes

Override WooCommerce templates by copying them to child theme:
wp-content/themes/storefront-child/woocommerce/
├── single-product.php
├── archive-product.php
├── cart/
│   └── cart.php
└── single-product/
    ├── title.php
    └── price.php

Best Practices for Template Overrides

1

Copy Complete Template

Always copy the entire template file, never partial code.
2

Document Version

Add a comment noting the WooCommerce version you copied from:
/**
 * Overridden template from WooCommerce 8.5.0
 * @version 3.6.0
 */
3

Preserve Hooks

Never remove do_action() or apply_filters() calls. Plugins depend on these hooks.
4

Monitor Updates

Check WooCommerce → Status → System Status for outdated template warnings.

Advanced Customization Techniques

Adding Custom Product Fields

/**
 * Add custom product field to admin
 */
add_action( 'woocommerce_product_options_general_product_data', 'mytheme_custom_field' );
function mytheme_custom_field() {
    woocommerce_wp_text_input( array(
        'id'          => '_custom_field',
        'label'       => 'Custom Field',
        'desc_tip'    => 'true',
        'description' => 'Enter custom information here',
    ) );
}

/**
 * Save custom product field
 */
add_action( 'woocommerce_process_product_meta', 'mytheme_save_custom_field' );
function mytheme_save_custom_field( $post_id ) {
    $custom_field = isset( $_POST['_custom_field'] ) ? sanitize_text_field( $_POST['_custom_field'] ) : '';
    update_post_meta( $post_id, '_custom_field', $custom_field );
}

/**
 * Display custom field on product page
 */
add_action( 'woocommerce_single_product_summary', 'mytheme_display_custom_field', 25 );
function mytheme_display_custom_field() {
    global $product;
    $custom_field = get_post_meta( $product->get_id(), '_custom_field', true );
    
    if ( $custom_field ) {
        echo '<div class="custom-field">' . esc_html( $custom_field ) . '</div>';
    }
}

Modifying Product Query

/**
 * Exclude specific products from shop page
 */
add_action( 'woocommerce_product_query', 'mytheme_exclude_products' );
function mytheme_exclude_products( $q ) {
    if ( is_shop() ) {
        $q->set( 'post__not_in', array( 123, 456, 789 ) );
    }
}

/**
 * Show only products on sale
 */
add_action( 'woocommerce_product_query', 'mytheme_show_only_sale_products' );
function mytheme_show_only_sale_products( $q ) {
    if ( isset( $_GET['on_sale'] ) && $_GET['on_sale'] === '1' ) {
        $q->set( 'post__in', array_merge( array( 0 ), wc_get_product_ids_on_sale() ) );
    }
}

Custom Cart Item Data

/**
 * Add custom data to cart item
 */
add_filter( 'woocommerce_add_cart_item_data', 'mytheme_add_cart_item_data', 10, 2 );
function mytheme_add_cart_item_data( $cart_item_data, $product_id ) {
    if ( isset( $_POST['custom_option'] ) ) {
        $cart_item_data['custom_option'] = sanitize_text_field( $_POST['custom_option'] );
    }
    return $cart_item_data;
}

/**
 * Display custom data in cart
 */
add_filter( 'woocommerce_get_item_data', 'mytheme_display_cart_item_data', 10, 2 );
function mytheme_display_cart_item_data( $item_data, $cart_item ) {
    if ( isset( $cart_item['custom_option'] ) ) {
        $item_data[] = array(
            'name'  => 'Custom Option',
            'value' => $cart_item['custom_option'],
        );
    }
    return $item_data;
}

Best Practices

Always Use Child Themes

Never modify parent themes or plugin files directly. Use child themes for all customizations.

Prefer Hooks Over Templates

Use hooks whenever possible. They’re more maintainable than template overrides.

Sanitize and Validate

Always sanitize user input and validate data before saving or displaying.

Test After Updates

Test all customizations after WooCommerce, WordPress, or theme updates.

Document Your Code

Add clear comments explaining what customizations do and why they exist.

Version Control

Use Git or similar version control for all theme customizations.

Monitor Template Versions

Regularly check System Status for outdated template warnings.

Backup Before Changes

Always backup your site before making significant customizations.

Debugging and Testing

Enable Debugging

Add to wp-config.php for development:
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
define( 'SCRIPT_DEBUG', true );

Template Debugging

Identify which template is loading:
/**
 * Show template file path in HTML comments
 */
add_action( 'woocommerce_before_template_part', 'mytheme_template_debug_start', 10, 4 );
function mytheme_template_debug_start( $template_name, $template_path, $located, $args ) {
    if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
        echo "\n<!-- Template: " . esc_html( $template_name ) . " -->\n";
    }
}

Testing Checklist

1

Test All Page Types

Verify customizations on shop, product, cart, checkout, and account pages.
2

Test Responsive Design

Check mobile, tablet, and desktop views for all customizations.
3

Test Product Types

Ensure customizations work with simple, variable, grouped, and external products.
4

Cross-Browser Testing

Test in Chrome, Firefox, Safari, and Edge browsers.
5

Performance Testing

Measure page load times before and after customizations.

Common Pitfalls to Avoid

Never modify core WooCommerce files. Updates will overwrite your changes. Always use hooks or template overrides.
Don’t remove template hooks. Plugins rely on these hooks. Removing them breaks extensibility.
Avoid using !important in CSS. It creates specificity issues. Use more specific selectors instead.
Don’t override functions.php completely. Child theme functions.php should only contain additions, not parent theme content.

Resources and References

Next Steps

Classic Theme Development

Deep dive into PHP-based theme development

Block Theme Development

Explore modern FSE and block theme architecture

Build docs developers (and LLMs) love