• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Step-by-Step Guide to building a custom multi-currency switcher block for Gutenberg using Svelte standalone templates

Step-by-Step Guide to building a custom multi-currency switcher block for Gutenberg using Svelte standalone templates

Setting Up the Development Environment

Before we dive into building the Gutenberg block, ensure you have a local WordPress development environment set up. This typically involves:

  • A local server (e.g., Local by Flywheel, MAMP, XAMPP).
  • WordPress installed and configured.
  • Node.js and npm (or yarn) installed for JavaScript development.

We’ll be using the WordPress `@wordpress/scripts` package to handle the build process for our JavaScript and Svelte components. This package provides a convenient way to compile modern JavaScript, CSS, and manage dependencies.

Creating the Plugin Structure

Let’s start by creating the basic file structure for our WordPress plugin. Navigate to your WordPress installation’s `wp-content/plugins/` directory and create a new folder for your plugin, for example, `custom-currency-switcher`.

Inside this folder, create the following files and directories:

  • `custom-currency-switcher.php` (The main plugin file)
  • `package.json` (For npm dependencies and scripts)
  • `src/` (Directory for our source code)
    • `index.js` (Entry point for our Gutenberg block registration)
    • `block.json` (Block metadata)
    • `edit.js` (Editor component)
    • `save.js` (Frontend rendering component)
    • `components/` (Directory for Svelte components)
      • `CurrencySwitcher.svelte` (The Svelte component for the switcher)

Initializing npm and Installing Dependencies

Navigate to your plugin’s root directory (`custom-currency-switcher/`) in your terminal and initialize npm. This will create the `package.json` file.

npm init -y

Next, install the necessary development dependencies. We need `@wordpress/scripts` for the build process and `svelte` and `@sveltejs/compiler` for our Svelte components.

npm install @wordpress/scripts @sveltejs/compiler svelte --save-dev

Now, let’s configure the build scripts in your `package.json` file. Add the following to the `scripts` section:

{
    "name": "custom-currency-switcher",
    "version": "1.0.0",
    "description": "A custom Gutenberg block for multi-currency switching using Svelte.",
    "main": "build/index.js",
    "scripts": {
        "build": "wp-scripts build",
        "start": "wp-scripts start",
        "lint:css": "wp-scripts lint-css",
        "lint:js": "wp-scripts lint-js"
    },
    "keywords": ["wordpress", "gutenberg", "block", "svelte", "currency switcher"],
    "author": "Your Name",
    "license": "GPL-2.0-or-later",
    "devDependencies": {
        "@sveltejs/compiler": "^3.0.0",
        "@wordpress/scripts": "^26.0.0",
        "svelte": "^4.0.0"
    }
}

The `build` script will compile your Svelte components and JavaScript into a production-ready format, while `start` will watch for changes and recompile automatically during development.

Configuring `block.json`

The `block.json` file defines the metadata for your Gutenberg block. Create this file in the `src/` directory with the following content:

{
    "apiVersion": 2,
    "name": "custom-currency-switcher/block",
    "version": "0.1.0",
    "title": "Currency Switcher",
    "category": "widgets",
    "icon": "money-alt",
    "description": "A custom block to switch between different currencies.",
    "keywords": ["currency", "switcher", "money", "ecommerce"],
    "attributes": {
        "defaultCurrency": {
            "type": "string",
            "default": "USD"
        },
        "availableCurrencies": {
            "type": "array",
            "default": ["USD", "EUR", "GBP"]
        }
    },
    "editorScript": "file:./index.js",
    "editorStyle": "file:./index.css",
    "style": "file:./style-index.css"
}

Here’s a breakdown of the key properties:

  • name: A unique identifier for your block.
  • title: The human-readable name of the block.
  • category: Where the block will appear in the Gutenberg inserter.
  • icon: The icon to represent the block.
  • description: A brief explanation of the block.
  • attributes: Defines the data that your block will store. We’ve added `defaultCurrency` and `availableCurrencies` to control the switcher’s behavior.
  • editorScript: Points to the JavaScript file that registers the block in the editor.
  • editorStyle: The CSS file for the block in the editor.
  • style: The CSS file for the block on the frontend.

Registering the Block in PHP

Create the main plugin file, `custom-currency-switcher.php`, in the plugin’s root directory. This file will enqueue the necessary scripts and styles.

<?php
/**
 * Plugin Name: Custom Currency Switcher
 * Description: A custom Gutenberg block to switch between different currencies using Svelte.
 * Version: 1.0.0
 * Author: Your Name
 * License: GPL-2.0-or-later
 * Text Domain: custom-currency-switcher
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly.
}

/**
 * Registers the block using the metadata loaded from the `block.json` file.
 * Behind the scenes, it registers also all assets so they can be enqueued
 * through the block editor in the corresponding `block.json` metadata.
 *
 * @since 1.0.0
 */
function custom_currency_switcher_block_init() {
    register_block_type( __DIR__ . '/build' );
}
add_action( 'init', 'custom_currency_switcher_block_init' );

This PHP code uses `register_block_type` to register our block. When `wp-scripts` builds our project, it will output the necessary files into a `build/` directory. `register_block_type` will automatically pick up the `block.json` from there and enqueue the associated scripts and styles.

Creating the Svelte Component

Now, let’s create our Svelte component for the currency switcher. This component will handle the UI and logic for selecting a currency. Create `src/components/CurrencySwitcher.svelte`:

<script>
    import { createEventDispatcher } from 'svelte';

    export let availableCurrencies = ['USD', 'EUR', 'GBP'];
    export let defaultCurrency = 'USD';

    let selectedCurrency = defaultCurrency;
    const dispatch = createEventDispatcher();

    function handleCurrencyChange(event) {
        selectedCurrency = event.target.value;
        dispatch('currencyChange', selectedCurrency);
    }
</script>

<div class="currency-switcher">
    <label for="currency-select">Select Currency: </label>
    <select id="currency-select" bind:value={selectedCurrency} on:change={handleCurrencyChange}>
        {#each availableCurrencies as currency}
            <option value={currency}>{currency}</option>
        {/each}
    </select>
</div>

<style>
    .currency-switcher {
        display: flex;
        align-items: center;
        gap: 10px;
        padding: 10px;
        border: 1px solid #ccc;
        border-radius: 4px;
        background-color: #f9f9f9;
    }
    .currency-switcher label {
        font-weight: bold;
    }
    .currency-switcher select {
        padding: 5px;
        border: 1px solid #ddd;
        border-radius: 3px;
    }
</style>

In this Svelte component:

  • We import `createEventDispatcher` to emit events when the currency changes.
  • `availableCurrencies` and `defaultCurrency` are props that will be passed from the Gutenberg block’s attributes.
  • `selectedCurrency` is a local state variable bound to the `<select>` element.
  • The `on:change` directive calls `handleCurrencyChange` when the user selects a new currency.
  • `handleCurrencyChange` updates the `selectedCurrency` state and dispatches a `currencyChange` event with the new currency value.
  • Basic styling is included within the `<style>` tag.

Implementing the Editor Component (`edit.js`)

The `edit.js` file defines how the block will appear and behave within the Gutenberg editor. We’ll use the `useBlockProps` hook and render our Svelte component here.

// src/edit.js
import { __ } from '@wordpress/i18n';
import { useBlockProps } from '@wordpress/block-editor';
import { useState, useEffect } from '@wordpress/element';
import CurrencySwitcher from './components/CurrencySwitcher.svelte';

// Import Svelte component and compile it for the editor
// Note: This requires a build step to handle Svelte compilation.
// The @wordpress/scripts package handles this automatically.

export default function Edit({ attributes, setAttributes }) {
    const blockProps = useBlockProps();
    const { defaultCurrency, availableCurrencies } = attributes;

    // State to manage the selected currency in the editor
    const [selectedCurrency, setSelectedCurrency] = useState(defaultCurrency);

    // Update the block attribute when the Svelte component dispatches an event
    const handleCurrencyChange = (event) => {
        const newCurrency = event.detail; // Svelte custom events pass data in 'detail'
        setSelectedCurrency(newCurrency);
        setAttributes({ defaultCurrency: newCurrency });
    };

    // Ensure the local state is updated if attributes change externally
    useEffect(() => {
        setSelectedCurrency(defaultCurrency);
    }, [defaultCurrency]);

    return (
        <div {...blockProps}>
            <CurrencySwitcher
                availableCurrencies={availableCurrencies}
                defaultCurrency={selectedCurrency}
                on:currencyChange={handleCurrencyChange}
            />
        </div>
    );
}

In `edit.js`:

  • We import necessary WordPress components like `useBlockProps` and `useState`, `useEffect` from `@wordpress/element`.
  • We import our `CurrencySwitcher.svelte` component.
  • `useBlockProps` provides the necessary props for the block’s wrapper element.
  • We destructure `defaultCurrency` and `availableCurrencies` from the block’s `attributes`.
  • We use `useState` to manage the `selectedCurrency` within the editor’s context.
  • The `handleCurrencyChange` function is passed to the Svelte component as an event handler. It receives the new currency from the Svelte component’s `currencyChange` event and updates both the local state and the block’s attributes using `setAttributes`.
  • A `useEffect` hook ensures that if the `defaultCurrency` attribute changes from somewhere else (e.g., another block or a theme setting), our local `selectedCurrency` state is updated accordingly.
  • The `CurrencySwitcher` component is rendered, passing the `availableCurrencies` and the current `selectedCurrency` as props, and attaching the `handleCurrencyChange` function to the `currencyChange` event.

Implementing the Save Component (`save.js`)

The `save.js` file determines how the block’s content is rendered on the frontend. For blocks that primarily use JavaScript for their UI and don’t need to output static HTML, we can return `null` or a simple wrapper. However, if we want the Svelte component to render on the frontend, we need to register it as a dynamic block or use `InnerBlocks` with a specific render callback. For simplicity in this example, we’ll assume the Svelte component will be initialized client-side on the frontend.

// src/save.js
import { useBlockProps } from '@wordpress/block-editor';

export default function save({ attributes }) {
    const blockProps = useBlockProps.save();
    const { defaultCurrency, availableCurrencies } = attributes;

    // We return a placeholder div with data attributes that our frontend
    // JavaScript will use to initialize the Svelte component.
    return (
        <div {...blockProps}
            data-default-currency={defaultCurrency}
            data-available-currencies={JSON.stringify(availableCurrencies)}
        >
            <!-- This content will be replaced by the Svelte component on the frontend -->
            <!-- Or, you can render a static representation if needed -->
        </div>
    );
}

In `save.js`:

  • We use `useBlockProps.save()` to get the necessary props for the frontend wrapper.
  • We return a `div` element. Crucially, we attach the block’s attributes (`defaultCurrency` and `availableCurrencies`) as `data-*` attributes to this element.
  • These `data-*` attributes will serve as the configuration for our Svelte component when it’s initialized on the frontend.
  • The content inside this div will be replaced by the Svelte component’s output.

Registering the Block in JavaScript (`index.js`)

The `index.js` file is the entry point for our block’s JavaScript. It registers the block with Gutenberg and tells it where to find the editor and save components.

// src/index.js
import { registerBlockType } from '@wordpress/blocks';
import './style.scss'; // Import editor styles
import './editor.scss'; // Import frontend styles

import Edit from './edit';
import save from './save';
import metadata from './block.json';

registerBlockType(metadata.name, {
    edit: Edit,
    save,
});

In `index.js`:

  • We import `registerBlockType` from `@wordpress/blocks`.
  • We import our `edit` and `save` components.
  • We import the `block.json` file to get the block’s metadata.
  • We call `registerBlockType` with the block’s name and an object containing the `edit` and `save` functions.
  • We also import `style.scss` and `editor.scss` for styling. These files will be processed by `@wordpress/scripts`.

Frontend Initialization of Svelte Component

Since our `save.js` returns a placeholder with data attributes, we need a separate JavaScript file to initialize the Svelte component on the frontend. This script will find all instances of our block on the page and mount the Svelte component into them.

Create a new file `src/frontend.js`:

// src/frontend.js
import CurrencySwitcher from './components/CurrencySwitcher.svelte';

document.addEventListener('DOMContentLoaded', () => {
    const blockElements = document.querySelectorAll('.wp-block-custom-currency-switcher-block'); // Adjust selector based on your block name

    blockElements.forEach(blockElement => {
        const defaultCurrency = blockElement.dataset.defaultCurrency;
        const availableCurrencies = JSON.parse(blockElement.dataset.availableCurrencies);

        // Dynamically import and mount the Svelte component
        // This approach ensures the Svelte component is only loaded if the block is present.
        import('./components/CurrencySwitcher.svelte').then(({ default: SvelteCurrencySwitcher }) => {
            new SvelteCurrencySwitcher({
                target: blockElement, // Mount inside the block element
                props: {
                    defaultCurrency: defaultCurrency,
                    availableCurrencies: availableCurrencies,
                }
            });
        });
    });
});

In `src/frontend.js`:

  • We listen for the `DOMContentLoaded` event to ensure the DOM is fully loaded.
  • We select all elements with the class corresponding to our block (e.g., `.wp-block-custom-currency-switcher-block`). The class name is generated by Gutenberg based on the block’s name.
  • For each block element found, we extract the `defaultCurrency` and `availableCurrencies` from its `dataset`.
  • We dynamically import the `CurrencySwitcher.svelte` component. This is a good practice for performance, as the component’s code is only loaded if the block is actually on the page.
  • We create a new instance of the `CurrencySwitcher` component, setting its `target` to the block element and passing the extracted `props`.

Enqueuing the Frontend Script

We need to tell WordPress to load our `frontend.js` script on the frontend. We can do this by modifying our main plugin file (`custom-currency-switcher.php`) to enqueue the script conditionally.

<?php
/**
 * Plugin Name: Custom Currency Switcher
 * Description: A custom Gutenberg block to switch between different currencies using Svelte.
 * Version: 1.0.0
 * Author: Your Name
 * License: GPL-2.0-or-later
 * Text Domain: custom-currency-switcher
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly.
}

/**
 * Registers the block using the metadata loaded from the `block.json` file.
 * Behind the scenes, it registers also all assets so they can be enqueued
 * through the block editor in the corresponding `block.json` metadata.
 *
 * @since 1.0.0
 */
function custom_currency_switcher_block_init() {
    // Register the block type from the build directory.
    register_block_type( __DIR__ . '/build' );

    // Enqueue the frontend script only if the block is present on the page.
    // This is a basic check; more robust checks might be needed for complex scenarios.
    add_action( 'wp_enqueue_scripts', 'custom_currency_switcher_enqueue_frontend_script' );
}
add_action( 'init', 'custom_currency_switcher_block_init' );

/**
 * Enqueues the frontend JavaScript file for the currency switcher block.
 */
function custom_currency_switcher_enqueue_frontend_script() {
    // Check if the block is registered and if its script needs to be enqueued.
    // A more robust check would involve parsing post content to see if the block exists.
    // For simplicity, we'll enqueue it if the block type is known.
    if ( has_block( 'custom-currency-switcher/block' ) ) {
        wp_enqueue_script(
            'custom-currency-switcher-frontend',
            plugin_dir_url( __FILE__ ) . 'build/frontend.js',
            array( 'wp-element' ), // Dependencies, including React/ReactDOM if used by WP
            filemtime( plugin_dir_path( __FILE__ ) . 'build/frontend.js' ),
            true // Load in footer
        );
    }
}

In the updated PHP file:

  • We’ve added a new function `custom_currency_switcher_enqueue_frontend_script`.
  • This function uses `has_block(‘custom-currency-switcher/block’)` to check if our block exists in the current post content. This is a crucial optimization to avoid loading the frontend script on every page.
  • If the block is present, `wp_enqueue_script` is called to load `build/frontend.js`.
  • We’ve added `wp-element` as a dependency, which is often required for frontend JavaScript that interacts with WordPress’s React-based components or DOM manipulation utilities.
  • The script is loaded in the footer (`true` as the last argument).
  • The `filemtime` function is used for cache-busting the script version.
  • The `custom_currency_switcher_enqueue_frontend_script` function is hooked into `wp_enqueue_scripts`.

Building the Assets

Now that we have all our source files in place, it’s time to build the project. Navigate to your plugin’s root directory in the terminal and run:

npm run build

This command will:

  • Compile your Svelte components into JavaScript.
  • Bundle all your JavaScript files.
  • Process your SCSS files into CSS.
  • Output the compiled files into the `build/` directory.

You should now see `index.js`, `index.asset.php`, `style-index.css`, `editor.css`, and `frontend.js` (and potentially others) inside the `build/` folder.

Testing the Block

Activate your `Custom Currency Switcher` plugin in the WordPress admin area. Then, create or edit a post or page. You should be able to find the “Currency Switcher” block in the Gutenberg inserter. Add it to your content.

In the editor, you should see the Svelte-powered currency switcher. You can select different currencies, and the block’s `defaultCurrency` attribute will update accordingly. When you save the post and view it on the frontend, the Svelte component should initialize and display the switcher based on the saved attributes.

Further Enhancements

This guide provides a foundational implementation. Here are some ideas for further enhancements:

  • Dynamic Currency Rates: Integrate with a currency exchange rate API to display real-time rates or convert prices.
  • User Preferences: Store the user’s selected currency in local storage or cookies for a persistent experience.
  • E-commerce Integration: If using with an e-commerce plugin (like WooCommerce), dynamically update product prices based on the selected currency.
  • Advanced Editor Controls: Add more controls in the block inspector (sidebar) for customizing the appearance or behavior of the switcher (e.g., adding/removing currencies, styling options).
  • Server-Side Rendering: For SEO benefits or to avoid client-side JavaScript dependency, consider implementing server-side rendering for the Svelte component. This would involve a PHP callback function that renders the initial HTML for the Svelte component.
  • Internationalization (i18n): Use WordPress’s i18n functions for translatable strings within the block.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • How to design secure Salesforce CRM webhook listeners using signature validation and payload queues
  • How to securely integrate Stripe Payment webhook endpoints into WordPress custom plugins using WP HTTP API
  • How to securely integrate Stripe Payment webhook endpoints into WordPress custom plugins using REST API Controllers
  • WordPress Development Recipe: High-efficiency server-side rendering for Gutenberg blocks using Named Arguments
  • Debugging Guide: Diagnosing nonce validation collisions in multi-site network environments with modern tools

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (653)
  • Desktop Applications (14)
  • DevOps (7)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (4)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (869)
  • PHP (5)
  • PHP Development (38)
  • Plugins & Themes (244)
  • Programming Languages (9)
  • Python (20)
  • Ruby on Rails (1)
  • Security & Compliance (638)
  • SEO & Growth (492)
  • Server (23)
  • Ubuntu (9)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (22)
  • WordPress Plugin Development (323)
  • WordPress Theme Development (357)

Recent Posts

  • How to design secure Salesforce CRM webhook listeners using signature validation and payload queues
  • How to securely integrate Stripe Payment webhook endpoints into WordPress custom plugins using WP HTTP API
  • How to securely integrate Stripe Payment webhook endpoints into WordPress custom plugins using REST API Controllers

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (869)
  • Debugging & Troubleshooting (653)
  • Security & Compliance (638)
  • SEO & Growth (492)
  • Business & Monetization (390)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala