📁 Asset Organization in Themes
Structure your theme assets for maintainability and performance
Learn best practices for organizing CSS, JavaScript, images, and other assets
Learning Objectives
- Understand WordPress theme file structure
- Organize CSS and JavaScript files effectively
- Implement proper naming conventions
- Structure assets for modularity
- Manage vendor and third-party assets
- Set up build tools and workflows
- Organize media and font files
- Create maintainable asset architecture
Why Asset Organization Matters
Proper asset organization is crucial for theme maintainability, performance, and collaboration. A well-structured asset architecture makes development faster, debugging easier, and enables efficient team collaboration.
Key Concept
WordPress Theme File Structure
Complete Theme Directory Structure
theme-name/ ├── style.css // Theme information and base styles ├── functions.php // Theme functions and features ├── index.php // Main template file ├── screenshot.png // Theme preview (1200x900px) │ ├── assets/ // All theme assets │ ├── css/ // Stylesheets │ │ ├── main.css // Main compiled CSS │ │ ├── admin.css // Admin styles │ │ ├── editor-style.css // Editor styles │ │ └── vendor/ // Third-party CSS │ │ ├── bootstrap.min.css │ │ └── font-awesome.min.css │ │ │ ├── js/ // JavaScript files │ │ ├── main.js // Main theme JS │ │ ├── navigation.js // Navigation scripts │ │ ├── customizer.js // Customizer preview │ │ ├── admin.js // Admin scripts │ │ └── vendor/ // Third-party JS │ │ ├── jquery.min.js │ │ └── slick.min.js │ │ │ ├── images/ // Theme images │ │ ├── logo.svg │ │ ├── placeholder.jpg │ │ └── icons/ // Icon files │ │ └── sprite.svg │ │ │ ├── fonts/ // Custom fonts │ │ ├── custom-font.woff2 │ │ ├── custom-font.woff │ │ └── custom-font.ttf │ │ │ └── scss/ // Sass source files │ ├── main.scss // Main Sass file │ ├── abstracts/ // Variables, mixins, functions │ │ ├── _variables.scss │ │ ├── _mixins.scss │ │ └── _functions.scss │ ├── base/ // Reset, typography, base │ │ ├── _reset.scss │ │ ├── _typography.scss │ │ └── _base.scss │ ├── components/ // Component styles │ │ ├── _buttons.scss │ │ ├── _cards.scss │ │ └── _forms.scss │ ├── layout/ // Layout components │ │ ├── _header.scss │ │ ├── _footer.scss │ │ ├── _sidebar.scss │ │ └── _grid.scss │ ├── pages/ // Page-specific styles │ │ ├── _home.scss │ │ ├── _about.scss │ │ └── _contact.scss │ └── vendor/ // Third-party Sass │ └── _normalize.scss │ ├── inc/ // PHP includes │ ├── enqueue.php // Asset enqueuing │ ├── customizer.php // Customizer settings │ ├── template-functions.php │ └── template-tags.php │ ├── template-parts/ // Reusable template parts │ ├── content/ │ ├── header/ │ └── footer/ │ ├── templates/ // Page templates │ ├── template-full-width.php │ └── template-sidebar-left.php │ ├── languages/ // Translation files │ └── theme-name.pot │ ├── src/ // Source files (development) │ ├── js/ // ES6+ JavaScript modules │ └── scss/ // Sass source files │ ├── dist/ // Compiled/built files │ ├── css/ │ └── js/ │ ├── node_modules/ // NPM packages (git-ignored) ├── package.json // NPM configuration ├── webpack.config.js // Webpack configuration ├── .gitignore // Git ignore file └── README.md // Theme documentation
Core Organization Principles
1. Separation of Concerns
- Keep different types of assets in separate directories
- Separate source files from compiled files
- Isolate vendor/third-party code
- Keep development and production assets separate
2. Logical Grouping
- Group related files together
- Use subdirectories for better organization
- Create component-based structures
- Maintain consistent hierarchy
3. Scalability
- Structure should accommodate growth
- Easy to add new components
- Modular architecture
- Clear patterns for extension
CSS/Sass Organization
7-1 Pattern for Sass
A popular architecture pattern with 7 folders and 1 main file:
scss/ ├── main.scss // Main file that imports all others ├── abstracts/ │ ├── _variables.scss // Sass variables │ ├── _functions.scss // Sass functions │ ├── _mixins.scss // Sass mixins │ └── _placeholders.scss // Sass placeholders ├── base/ │ ├── _reset.scss // Reset/normalize │ ├── _typography.scss // Typography rules │ └── _base.scss // Base styles ├── components/ │ ├── _buttons.scss // Buttons │ ├── _carousel.scss // Carousel │ └── _dropdown.scss // Dropdown ├── layout/ │ ├── _navigation.scss // Navigation │ ├── _grid.scss // Grid system │ ├── _header.scss // Header │ ├── _footer.scss // Footer │ └── _sidebar.scss // Sidebar ├── pages/ │ ├── _home.scss // Home specific styles │ ├── _contact.scss // Contact specific styles │ └── _about.scss // About specific styles ├── themes/ │ ├── _theme.scss // Default theme │ └── _admin.scss // Admin theme └── vendors/ ├── _bootstrap.scss // Bootstrap └── _jquery-ui.scss // jQuery UI
main.scss Import Structure
// main.scss
@charset "UTF-8";
// 1. Configuration and helpers
@import 'abstracts/variables';
@import 'abstracts/functions';
@import 'abstracts/mixins';
@import 'abstracts/placeholders';
// 2. Vendors
@import 'vendors/normalize';
@import 'vendors/bootstrap';
// 3. Base stuff
@import 'base/reset';
@import 'base/typography';
@import 'base/base';
// 4. Layout-related sections
@import 'layout/navigation';
@import 'layout/grid';
@import 'layout/header';
@import 'layout/footer';
@import 'layout/sidebar';
@import 'layout/forms';
// 5. Components
@import 'components/buttons';
@import 'components/carousel';
@import 'components/dropdown';
@import 'components/cards';
// 6. Page-specific styles
@import 'pages/home';
@import 'pages/about';
@import 'pages/contact';
// 7. Themes
@import 'themes/theme';
@import 'themes/admin';
JavaScript Organization
Modular JavaScript Structure
src/js/ ├── main.js // Entry point ├── modules/ │ ├── navigation.js // Navigation module │ ├── slider.js // Slider functionality │ ├── forms.js // Form handling │ └── ajax.js // AJAX operations ├── utils/ │ ├── helpers.js // Helper functions │ ├── constants.js // Constants │ └── api.js // API utilities ├── components/ │ ├── accordion.js // Accordion component │ ├── modal.js // Modal component │ └── tabs.js // Tabs component └── vendor/ └── third-party.js // Third-party scripts
ES6 Module Example
// src/js/modules/navigation.js
export class Navigation {
constructor() {
this.menu = document.querySelector('.main-navigation');
this.toggleButton = document.querySelector('.menu-toggle');
this.init();
}
init() {
if (!this.menu || !this.toggleButton) return;
this.toggleButton.addEventListener('click', () => {
this.toggleMenu();
});
this.handleMobileMenu();
this.handleStickyNav();
}
toggleMenu() {
this.menu.classList.toggle('is-active');
this.toggleButton.classList.toggle('is-active');
const isExpanded = this.toggleButton.getAttribute('aria-expanded') === 'true';
this.toggleButton.setAttribute('aria-expanded', !isExpanded);
}
handleMobileMenu() {
// Mobile menu logic
}
handleStickyNav() {
// Sticky navigation logic
}
}
// src/js/main.js
import { Navigation } from './modules/navigation';
import { Slider } from './modules/slider';
import { Forms } from './modules/forms';
document.addEventListener('DOMContentLoaded', () => {
// Initialize modules
new Navigation();
new Slider();
new Forms();
});
File Naming Conventions
| File Type | Convention | Examples |
|---|---|---|
| PHP Templates | kebab-case | single-post.php, page-about.php |
| CSS/Sass Files | kebab-case with underscore prefix for partials | main.css, _header.scss |
| JavaScript Files | camelCase or kebab-case | mainScript.js, form-handler.js |
| Images | kebab-case, descriptive | hero-background.jpg, logo-dark.svg |
| Vendor Files | Keep original naming | jquery.min.js, bootstrap.css |
| Build Files | Include version or hash | main.min.css, app.bundle.js |
Proper Asset Enqueuing
inc/enqueue.php
<?php
/**
* Enqueue scripts and styles
*/
function theme_name_scripts() {
// Get theme version for cache busting
$theme_version = wp_get_theme()->get('Version');
// CSS
// Vendor styles
wp_enqueue_style(
'bootstrap',
get_template_directory_uri() . '/assets/css/vendor/bootstrap.min.css',
array(),
'5.1.3'
);
// Main theme style
wp_enqueue_style(
'theme-name-style',
get_template_directory_uri() . '/assets/css/main.css',
array('bootstrap'),
$theme_version
);
// JavaScript
// Deregister WordPress jQuery and use custom version if needed
if (!is_admin()) {
wp_deregister_script('jquery');
wp_enqueue_script(
'jquery',
get_template_directory_uri() . '/assets/js/vendor/jquery-3.6.0.min.js',
array(),
'3.6.0',
true
);
}
// Vendor scripts
wp_enqueue_script(
'bootstrap',
get_template_directory_uri() . '/assets/js/vendor/bootstrap.bundle.min.js',
array('jquery'),
'5.1.3',
true
);
// Main theme script
wp_enqueue_script(
'theme-name-script',
get_template_directory_uri() . '/assets/js/main.js',
array('jquery', 'bootstrap'),
$theme_version,
true
);
// Localize script for AJAX
wp_localize_script('theme-name-script', 'themeAjax', array(
'ajaxurl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('theme-ajax-nonce')
));
// Conditional scripts
if (is_singular() && comments_open() && get_option('thread_comments')) {
wp_enqueue_script('comment-reply');
}
}
add_action('wp_enqueue_scripts', 'theme_name_scripts');
/**
* Enqueue admin scripts and styles
*/
function theme_name_admin_scripts() {
wp_enqueue_style(
'theme-name-admin',
get_template_directory_uri() . '/assets/css/admin.css',
array(),
wp_get_theme()->get('Version')
);
wp_enqueue_script(
'theme-name-admin',
get_template_directory_uri() . '/assets/js/admin.js',
array('jquery'),
wp_get_theme()->get('Version'),
true
);
}
add_action('admin_enqueue_scripts', 'theme_name_admin_scripts');
/**
* Enqueue block editor assets
*/
function theme_name_block_editor_assets() {
wp_enqueue_style(
'theme-name-block-editor',
get_template_directory_uri() . '/assets/css/editor-style.css',
array(),
wp_get_theme()->get('Version')
);
}
add_action('enqueue_block_editor_assets', 'theme_name_block_editor_assets');
Build Tools and Development Workflow
Package.json Structure
{
"name": "theme-name",
"version": "1.0.0",
"scripts": {
"dev": "webpack --mode development --watch",
"build": "webpack --mode production",
"sass": "sass src/scss:assets/css --watch",
"lint": "eslint src/js"
},
"devDependencies": {
"webpack": "^5.0.0",
"sass": "^1.0.0",
"eslint": "^7.0.0"
}
}
Webpack Configuration
module.exports = {
entry: './src/js/main.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader'
}
]
}
};
Media and Font Organization
Image Organization
images/ ├── icons/ // Icon files │ ├── sprite.svg // SVG sprite │ └── social/ // Social icons ├── backgrounds/ // Background images │ ├── hero-home.jpg │ └── pattern.svg ├── content/ // Content images │ └── placeholder.jpg └── ui/ // UI elements ├── logo.svg └── loading.gif
Font Organization
fonts/ ├── custom-font/ │ ├── custom-font-regular.woff2 │ ├── custom-font-regular.woff │ ├── custom-font-bold.woff2 │ └── custom-font-bold.woff └── fonts.css // @font-face declarations
Best Practices
Asset Organization Best Practices
- Consistent Structure: Maintain the same organization pattern throughout
- Clear Naming: Use descriptive, consistent file names
- Version Control: Track source files, ignore compiled/vendor files
- Documentation: Document your structure in README.md
- Separation: Keep development and production files separate
- Modularity: Break large files into smaller, focused modules
- Dependencies: Clearly manage and document dependencies
- Performance: Organize for optimal loading and caching
Never edit vendor/third-party files directly. If customization is needed, override styles in your own files or create a fork of the library.
Practice Exercise
Organize Your Theme Assets