By default, WordPress provides several built-in sections you can hook into or build upon:

  • Site Identity: Site title, tagline, and logo/favicon.

  • Colors: Background colors, header colors.

  • Header Media: Header images or videos.

  • Background Image: Site-wide background image settings.

  • Menus: Menu creation and location assignment.

  • Widgets: Managing widget areas directly from the front end.

  • Homepage Settings: Choosing between a static page or latest posts.

  • Additional CSS: A built-in code editor for custom styles.


The Hierarchy: Panels, Sections, Settings, and Controls

Understanding the Customizer requires understanding its structural hierarchy. Think of it like a filing cabinet.

  • Panels (The Drawers): Panels group multiple sections together. You only need a Panel if you have a massive amount of settings (e.g., a “Typography” panel containing “Heading” and “Body Text” sections).

  • Sections (The Folders): Sections are UI containers that group related controls. For example, a “Header Settings” section might contain controls for header color, logo height, and layout style.

  • Settings (The Documents/Data): Settings handle data mapping. They link the UI elements to the WordPress database. A setting determines the default value, how the data is sanitized (cleaned for security), and how it is updated (via page refresh or live JavaScript).

  • Controls (The Interactive Elements): Controls are the actual HTML elements the user interacts with: text inputs, color pickers, dropdowns, radio buttons, or image uploaders. A control must be linked to a Setting to save data, and it must be placed inside a Section to be visible.


To add anything to the Customizer, you must hook into the customize_register action. This hook passes the $wp_customize object (an instance of the WP_Customize_Manager class) into your function. This object contains all the methods you need to add, remove, or modify Customizer elements.


function my_theme_customize_css() {
    ?>
    <style>
        header h1 {
            /* Retrieves the setting. If no setting exists, it falls back to empty (or the default if you specify it here) */
            color: <?php echo esc_html( get_theme_mod( 'header_text_color' ) ); ?>;
        }
    </style>
    <?php
}
add_action( 'wp_head', 'my_theme_customize_css' );
function my_theme_customizer_live_preview() {
    wp_enqueue_script( 
        'my-theme-customizer-preview', 
        get_template_directory_uri() . '/js/customizer-preview.js', 
        array( 'customize-preview' ), // Dependency: ensures wp.customize is loaded
        null, 
        true 
    );
}
add_action( 'customize_preview_init', 'my_theme_customizer_live_preview' );
( function() {
    // Listen for the 'header_text_color' setting change
    wp.customize( 'header_text_color', function( value ) {
        // This function runs every time the user moves the color picker
        value.bind( function( newColor ) {
            // Find the element and update its style directly
            const headerTitle = document.querySelector( 'header h1' );
            
            if ( headerTitle ) {
                headerTitle.style.color = newColor;
            }
        } );
        
    } );
} )();

  • To remove core sections you dont want $wp_customize->get_section('colors')->active_callback = '__return_false';
  • To implement a new type of control
class My_Social_Icons_Control extends WP_Customize_Control {
    public $type = 'social_icons';
    public function render_content() {
        // Output your custom HTML/JS for the control here
    }
}
// Retrieve the header color, or use '#fff' if nothing is set.
$color = get_theme_mod( 'header_text_color', '#fff' );
echo '<style>h1 { color: ' . esc_attr( $color ) . '; }</style>';

get_theme_mods() This retrieves every single setting associated with the current theme as an associative array.

set_theme_mod( $name, $value ) This saves a value to the database for the current theme. Note: Usually, the Customizer API handles this automatically when a user clicks “Publish.”

remove_theme_mod( $name ) This deletes a specific setting from the database. Use Case: Resetting a single option to its absolute default. Once removed, get_theme_mod() will return the $default value you provided.

remove_theme_mods() This is the “nuclear option.” It deletes all settings for the currently active theme.

  • Change setting before it returns to user
// Force the header color to be red on Fridays, regardless of the Customizer setting.
add_filter( 'theme_mod_header_text_color', function( $current_value ) {
    if ( date('l') === 'Friday' ) {
        return '#ff0000';
    }
    return $current_value;
});

  • All theme modifications are stored in the wp_options table. However, they are not saved as individual rows. Instead, WordPress creates one single row for your entire theme.
    • Option Name: theme_mods_your-theme-slug
    • Option Value: A “Serialized” Array (a long string of text containing all your settings).

Full refresh / Selective refresh / Post message

add_theme_support( 'customize-selective-refresh-widgets' );

// 1. Add the Setting
$wp_customize->add_setting( 'site_tagline', array(
    'transport' => 'postMessage', // Required for Selective Refresh
) );

// 2. Add the Partial
$wp_customize->selective_refresh->add_partial( 'site_tagline_partial', array(
    'selector'            => '.site-description', // The CSS selector of the HTML to replace
    'settings'            => array( 'site_tagline' ), // The setting that triggers the refresh
    'render_callback'     => function() {
        return get_bloginfo( 'description' ); // The PHP function that generates the HTML
    },
    'container_inclusive' => false, // Set to true if you want to replace the <div> itself
) );
MethodTechnical StrategyAnalogy
RefreshFull Browser ReloadBuying a new house because you wanted to change the front door color.
postMessageClient-Side JS DOM ManipulationPainting the front door yourself while standing in the driveway.
Selective RefreshServer-Side Ajax InjectionOrdering a pre-painted door and having a contractor swap only the door out.

Webpack/Babel

Webpack is a module bundler. Imagine you have dozens of small JavaScript files, some CSS, and several images. If you link them all individually in your HTML, your site will slow down due to too many requests. Webpack takes all those separate pieces (modules), figures out how they depend on each other, and bundles them into a few highly optimized files.

Gemini said

Building modern WordPress themes and plugins has shifted from simply writing .js files to managing a complex “build pipeline.” Let’s break down how Webpack and Babel work together to transform your modern code into something every browser can understand.


1. Webpack: The Master Organizer

At its core, Webpack is a module bundler. Imagine you have dozens of small JavaScript files, some CSS, and several images. If you link them all individually in your HTML, your site will slow down due to too many requests. Webpack takes all those separate pieces (modules), figures out how they depend on each other, and bundles them into a few highly optimized files.

How it Works

  1. Entry: You tell Webpack where to start (usually src/index.js).

  2. Dependency Graph: Webpack looks at your import and require statements to map out every file your project needs.

  3. Output: It spits out a “dist” or “build” folder with the final assets.

  • Loaders: These act as “translators” for individual files. By default, Webpack only understands JavaScript and JSON. Loaders allow Webpack to process other file types, like converting Sass to CSS (sass-loader) or processing images (file-loader).

  • Plugins: These are “power-ups” that perform actions on the entire bundle. For example, a plugin can minify your code to make it smaller, or automatically generate an index.html file.

If Webpack is the organizer, Babel is the translator. JavaScript evolves every year (ES6, ES7, etc.), but browsers don’t all update at the same speed. Babel is a transpiler—it takes your modern, “fancy” JavaScript and rewrites it into an older version (ES5) that older browsers (like Internet Explorer or older Safari versions) can understand.

  • Presets: Instead of picking every translation rule manually, you use a “Preset.” A preset is a bundle of plugins. The most common is @babel/preset-env, which automatically determines which JS features need to be transformed based on your target browsers.

  • Polyfills: Transpiling only changes the syntax (e.g., changing () => {} to function() {}). But if a browser simply doesn’t have a new feature (like Promise or Array.from), a Polyfill is a piece of code that provides that functionality from scratch.


WordPress created @wordpress/scripts.

It is a zero-config wrapper. It comes with a pre-configured Webpack and Babel setup optimized specifically for WordPress development (Gutenberg blocks, React, etc.).

You only need Babel when you start using modern features like Arrow Functions, Classes, or JSX.


A. Module Bundling B. Asset Transformation (With Babel & Loaders) - Babel Transpilation: - CSS/Sass Processing - Image Optimization C. Performance Optimization - Tree Shaking - Code Splitting - Minification D. Development Workflow - Hot Module Replacement (HMR): Updates your code in the browser instantly when you save a file without refreshing the page. - Source Maps: Since the bundled code is unreadable, source maps tell the browser where the original code was, making debugging easy.


const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = (env, argv) => {
    const isProduction = argv.mode === 'production';

    return {
        // 1. Entry point: Where Webpack starts looking at your code
        entry: './src/index.js',

        // 2. Output: Where the bundled files go
        output: {
            path: path.resolve(__dirname, 'dist'),
            filename: isProduction ? 'js/[name].[contenthash].js' : 'js/[name].js',
            clean: true, // Automatically clears the dist folder before each build
        },

        // 3. Dev Server: For local development with live reloading
        devServer: {
            static: './dist',
            hot: true,     // Enable Hot Module Replacement
            port: 3000,    // Run on http://localhost:3000
            open: true,    // Open the browser automatically
        },

        // 4. Module Rules: How to handle different file types (Loaders)
        module: {
            rules: [
                // JavaScript: Transpile ES6+ to ES5 using Babel
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    use: {
                        loader: 'babel-loader',
                        options: {
                            presets: ['@babel/preset-env']
                        }
                    }
                },
                // SCSS/CSS: Compile Sass to CSS and extract into a file
                {
                    test: /\.(s[ac]ss|css)$/i,
                    use: [
                        isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
                        'css-loader',
                        'sass-loader'
                    ],
                },
                // Images & Assets
                {
                    test: /\.(png|svg|jpg|jpeg|gif)$/i,
                    type: 'asset/resource',
                    generator: {
                        filename: 'images/[name][ext]'
                    }
                }
            ]
        },

        // 5. Plugins: Extra functionality
        plugins: [
            // Generates an HTML file and injects the <script> tags automatically
            new HtmlWebpackPlugin({
                template: './src/index.html',
                title: 'My Webpack Project'
            }),
            // Extracts CSS into separate files (used for production)
            new MiniCssExtractPlugin({
                filename: 'css/[name].[contenthash].css'
            })
        ],

        // 6. Source Maps: Makes debugging easier in the browser
        devtool: isProduction ? 'source-map' : 'eval-source-map',
    };
};

npm install --save-dev @babel/core @babel/cli

@babel/preset-env

npm install --save-dev @babel/preset-typescript
npm install --save-dev @babel/preset-env

npm install --save-dev @wordpress/scripts directly configures webpack/babel

{
    "scripts": {
        "start": "wp-scripts start src/index.js",
        "build": "wp-scripts build src/index.js"
    },
    "devDependencies": {
        "@wordpress/scripts": "^[replace-with-latest-version]"
    }
}

![[Pasted image 20260323095838.png]]


Here is the breakdown of the WordPress loading sequence:

1. The Entry Point: index.php and wp-blog-header.php

When a user visits your URL, the server hits index.php first.

  • index.php: This is a tiny file. Its only job is to define a constant called WP_USE_THEMES (telling WordPress to actually load your design) and then load wp-blog-header.php.

  • wp-blog-header.php: This acts as the project manager. It does two main things:

    1. It calls wp-load.php to “boot up” the WordPress environment.

    2. Once the environment is ready, it calls template-loader.php to figure out which page template (like single.php or archive.php) should be shown.

2. The Bridge: wp-load.php

The wp-load.php file is responsible for finding the “instructions” for your specific site.

  • Locating Configuration: It searches for wp-config.php. If it can’t find it in the root folder, it even checks one directory above (a security feature).

  • Setting Constants: It defines ABSPATH (the absolute path to your WordPress files) and sets up basic error reporting.

  • Initialization: Once it finds wp-config.php, it loads it. If it fails to find a config file, it will redirect the user to the WordPress installation screen.

3. The Heart: wp-config.php

This is arguably the most important file in your installation. It doesn’t contain WordPress logic; it contains your site’s specific data.

  • Database Connection: It defines the constants DB_NAME, DB_USER, DB_PASSWORD, and DB_HOST. Without these, WordPress cannot talk to MySQL.

  • Security Salts: It stores unique keys that encrypt the information in user cookies.

  • Global Overrides: You use it to set WP_DEBUG (for developers) or increase memory limits.

  • The Hand-off: At the very bottom, it contains the line require_once ABSPATH . 'wp-settings.php';. This is the signal that the configuration is done and the engine should start.

4. The Engine Room: wp-settings.php

While wp-config.php has the data, wp-settings.php does the heavy lifting of setting up the environment.

  • Loading Core Files: it includes all the internal library files (like functions.php, plugin.php, and class-wp-db.php).

  • Global Variables: It initializes the most famous global variables, such as:

    • $wpdb: The database abstraction object.

    • $wp_query: The object that handles the logic of what posts to show.

    • $wp_roles: Manages user permissions.

  • Plugin Loading: It loads all of your Active Plugins. This is why you can use plugin functions in your theme—because wp-settings.php loaded them before the theme.

  • Hooks and Actions: It sets up the default filters and actions that make WordPress extensible.



customize_preview_init: The hook that fires when the Customizer preview window is being initialized. The 'customize-preview' handle refers to a built-in WordPress JavaScript library. This library provides the wp.customize object.