Tutorial – WordPress Themes & Website Templates https://techidem.com Startup and Technology Blog Tue, 27 May 2025 14:18:12 +0000 en-US hourly 1 https://wordpress.org/?v=6.9.4 https://techidem.com/wp-content/uploads/2021/12/cropped-favicon-32x32.png Tutorial – WordPress Themes & Website Templates https://techidem.com 32 32 Gutenberg Block Deprecation: Safely Updating Blocks Without Breaking Content https://techidem.com/gutenberg-block-deprecation-safely-updating-blocks-without-breaking-content/ https://techidem.com/gutenberg-block-deprecation-safely-updating-blocks-without-breaking-content/#respond Sat, 17 May 2025 17:23:31 +0000 https://techidem.com/?p=2551 Gutenberg Block Deprecation is crucial —— when you want to update a Gutenberg block’s code — such as changing its HTML output or renaming attributes — older versions of that block in existing posts may no longer match your new structure. This can cause warnings like:

“This block contains unexpected or invalid content.”

To prevent this, Gutenberg provides a deprecated property in your block registration. It lets you define how the block used to work, so WordPress can still recognize and render old content properly.

Why Should Use Gutenberg Block Deprecation?

  • Keep old posts working after block updates
  • Avoid “invalid block” errors in the editor
  • Support smooth migration from older block versions
  • Improve content editing experience for users

How Does It Work?

You define one or more old versions of your block using the deprecated array.

Each version includes:

  • The old attributes
  • The old save() function
  • An optional migrate() function to convert old data to the new format

For instance, you have a simple notice block that used to save its output like this:

Old Block:

// save() output
<div class="notice-block">
  { attributes.message }
</div>

Block Attribute:

attributes: {
  message: { type: 'string' },
}

Now you want to update the block into the updated version :

  • Use a different class structure for styling
  • Rename message to content
  • Add a type attribute ('info', 'warning', 'success')

Updated attributes:

attributes: {
  content: { type: 'string' },
  type: { type: 'string', default: 'info' },
}

Updated save function:

save({ attributes }) {
  const { content, type } = attributes;
  return (
    <div className={`notice notice-${type}`}>
      <p>{content}</p>
    </div>
  );
}

Add a deprecated section:

Now, add the old version to a deprecated array:

const deprecated = [
  {
    attributes: {
      message: { type: 'string' },
    },
    save({ attributes }) {
      return (
        <div className="notice-block">
          {attributes.message}
        </div>
      );
    },
    migrate(attributes) {
      return {
        content: attributes.message,
        type: 'info',
      };
    },
  },
];

The final block registration:

registerBlockType('my-namespace/notice-block', {
  title: 'Notice Block',
  attributes: {
    content: { type: 'string' },
    type: { type: 'string', default: 'info' },
  },
  edit: MyEditComponent,
  save({ attributes }) {
    const { content, type } = attributes;
    return (
      <div className={`notice notice-${type}`}>
        <p>{content}</p>
      </div>
    );
  },
  deprecated: deprecated,
});

How this work?

  1. Blocks saved using the old format (message + .notice-block) are still recognized.
  2. WordPress uses the migrate() function to transform old attributes into the new schema (message → content, adds type: 'info').
  3. Avoids block errors or content loss for older posts.

Learn more about Gutenberg Block: Mastering Gutenberg Block Development: The Expert WordPress Developer’s Roadmap

]]>
https://techidem.com/gutenberg-block-deprecation-safely-updating-blocks-without-breaking-content/feed/ 0
Mastering Gutenberg Block Development: The Expert WordPress Developer’s Roadmap https://techidem.com/mastering-gutenberg-block-development-the-expert-wordpress-developers-roadmap/ https://techidem.com/mastering-gutenberg-block-development-the-expert-wordpress-developers-roadmap/#respond Sat, 17 May 2025 15:13:10 +0000 https://techidem.com/?p=2533 Looking to become experts in Gutenberg block development and — this roadmap is designed for developers already familiar with the WordPress ecosystem — including custom themes and plugins.



Key Concepts

Block Registration (block.json): WordPress uses the block.json file to define metadata and settings for blocks. It allows automatic registration and better integration with tools like block directories.

Documentation: https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/

Edit vs Save Functions: Need to understand the separation between how a block appears in the editor (edit()) and how it saves data to post content (save() or render_callback for dynamic blocks).

Documentation: https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/

Attributes System: Master the definition and usage of attributes, including setting types (string, number, boolean, array, object) and sources (text, html, meta, query).

Block Props: Get comfortable with props in your block’s edit function, especially attributes, setAttributes, className, isSelected, and how they control interactivity and display.



Component Mastery for Gutenberg Block Development

@wordpress/components: Use the core UI component library to build block UIs. Common components include:

  • TextControl, TextAreaControl, SelectControl for inputs
  • ToggleControl, CheckboxControl, RadioControl
  • PanelBody, PanelRow for sidebar settings panels
  • ColorPalette, FontSizePicker, RangeControl


Component Reference: https://developer.wordpress.org/block-editor/reference-guides/components/



Editor Components of Gutenberg Block

  • BlockControls: Toolbar that appears above the block.
  • InspectorControls: Settings sidebar.
  • RichText: Inline editable text field.
  • InnerBlocks: Nest child blocks, useful for containers/layouts.
  • useBlockProps(), useInnerBlocksProps() for proper styling and block context.


React & WordPress Hooks

React Basics: Proficiency in useState, useEffect, and JSX is crucial.



WordPress Data Access:

  • useSelect to fetch data from the store (e.g., get current post meta, other blocks, or taxonomy terms).
  • useDispatch to dispatch actions (e.g., update meta, create entities).
  • useEntityProp to directly access and update entity props like post meta.
  • useBlockEditContext to work with parent/child relationships.


Data Module Docs: https://developer.wordpress.org/block-editor/reference-guides/packages/packages-data/



Dynamic Blocks & Server Rendering

  • Dynamic Blocks: Blocks rendered by PHP on the front-end using render_callback.
  • Use Cases: Good for data-driven blocks (e.g., post grids, recent posts, pricing tables etc.)
  • Hydration: Ensure any interactive behavior in JS still works after server render.


Dynamic Blocks Tutorial: https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/creating-dynamic-blocks/



Block Variations & Patterns

  • Block Variations: Create alternate versions of a block with different default settings or attributes.
  • Block Patterns: Pre-built layouts composed of multiple blocks. Useful for theme integration.
  • Block Transforms: Allow users to convert one block type to another (e.g., paragraph → heading)


Variations & Patterns Guide: https://developer.wordpress.org/block-editor/reference-guides/block-api/block-variations/



Inter-Block Communication

  • InnerBlocks Templates: Predefine layout templates within a container block.
  • Template Locking: Restrict changes to the structure using lock: ‘all’, ‘insert’, or ‘remove’.
  • Context API: Share data between parent and child blocks without props drilling.


InnerBlocks Docs: https://developer.wordpress.org/block-editor/reference-guides/block-api/inner-blocks/



REST API Integration

  • Custom REST Endpoints: Build endpoints to feed blocks with dynamic data.
  • apiFetch: Use @wordpress/api-fetch to make authenticated API requests from within the editor.
  • Data Loading: Load data asynchronously in the editor (e.g., showing loading spinner while fetching)


REST API Docs: https://developer.wordpress.org/rest-api/



Styling & Theming

  • Scoped CSS: Use style.scss for front-end, editor.scss for editor appearance.
  • Global Styles with theme.json: Declare colors, typography, spacing, and support features globally.
  • Dynamic Styling: Use inline styles via style attributes or conditional classNames.
  • Asset Management: Properly enqueue block scripts and styles using block.json or hooks like enqueue_block_assets()


Theme JSON Guide: https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-json/



Reusable Libraries & Tooling

  • @wordpress/scripts: Use built-in toolchain (Webpack, Babel, ESLint, etc.) for compiling and bundling your blocks.
  • Reusable Block Libraries: Create NPM-packaged block libraries for use across plugins or projects.
  • Explore 3rd Party Blocks: Study and extend libraries like ACF Blocks, Genesis Blocks, Kadence Blocks.


Toolchain Reference: https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/



Testing & Accessibility

Testing:

  • Snapshot testing using Jest for saved markup
  • Unit tests for block logic
  • ESLint and Prettier for code quality

Accessibility:

  • Use semantic HTML and proper ARIA attributes
  • Ensure keyboard navigation support
  • Test with screen readers and a11y tools


A11y Docs: https://developer.wordpress.org/block-editor/how-to-guides/accessibility/



Performance Optimization

  • Tree-shaking & Bundling: Eliminate unused code in production bundles
  • Lazy-loading: Load editor assets only when the block is used
  • Memoization: Optimize rendering with React.memo, useMemo, useCallback
  • Asset Split: Register only needed scripts/styles per block or context


Debugging & Dev Tools

  • Browser Dev Tools: Inspect block props, editor DOM, and styles
  • React Developer Tools: Inspect block component tree
  • WordPress Console: Use wp.data.select() and dispatch() for state inspection and manipulation.
  • Enable SCRIPT_DEBUG: Load unminified scripts for debugging.
  • Install Query Monitor: The developer tools panel for WordPress.

Now it is time to start a pro level project — This roadmap is your guide to becoming a true Gutenberg Block expert — not just building blocks, but designing scalable, performant, and editor-friendly experiences aligned with modern WordPress development.

]]>
https://techidem.com/mastering-gutenberg-block-development-the-expert-wordpress-developers-roadmap/feed/ 0
Complete Guide to WordPress Hooks in Order: From muplugins_loaded to shutdown https://techidem.com/complete-guide-to-wordpress-hooks-in-order/ https://techidem.com/complete-guide-to-wordpress-hooks-in-order/#respond Tue, 08 Apr 2025 17:03:25 +0000 https://techidem.com/?p=2517 Mastering WordPress hooks is key to crafting flawless plugins and themes—unlock error-free development with this exciting guide I’m creating just for you!

Below is a serialized list of key WordPress hooks in the order they typically fire during a standard page request, starting from the early initialization phase through to the end of the process. This includes the hooks we’ve discussed (plugins_loaded, after_setup_theme, init, wp_loaded, etc.) and others that fill out the sequence. Note that the exact order can vary slightly depending on specific conditions (e.g., multisite, custom plugins), but this represents the general flow for a typical front-end request.

Serialized WordPress Hooks Order

  1. muplugins_loaded
    • Fires after Must-Use plugins are loaded (early, before regular plugins).
  2. plugins_loaded
    • Fires after all active plugins are loaded and their main files executed.
  3. after_setup_theme
    • Fires after the active theme’s functions.php is loaded, for theme setup.
  4. init
    • Fires after WordPress core is initialized (e.g., globals set, rewrite rules ready).
  5. wp_loaded
    • Fires after WordPress is fully loaded, before the main query runs.
  6. parse_request
    • Fires during URL parsing, before query vars are finalized.
  7. send_headers
    • Fires when HTTP headers are about to be sent (can be used to modify headers).
  8. pre_get_posts
    • Fires just before the main WP_Query is executed, for query modification.
  9. posts_selection
    • Fires after the main query retrieves posts, but before further processing.
  10. wp
    • Fires after the main query is fully populated ($wp_query is set).
  11. template_redirect
    • Fires just before WordPress selects and loads the template file.
  12. get_header
    • Fires when the header template is about to be loaded (e.g., header.php).
  13. wp_head
    • Fires within the <head> section when wp_head() is called in the theme.
  14. loop_start
    • Fires at the beginning of The Loop in the template.
  15. the_post
    • Fires for each post in The Loop, setting up post data.
  16. loop_end
    • Fires after The Loop finishes processing posts.
  17. get_footer
    • Fires when the footer template is about to be loaded (e.g., footer.php).
  18. wp_footer
    • Fires just before the closing </body> tag when wp_footer() is called.
  19. shutdown
    • Fires at the very end of the PHP process, after all output is sent.

Notes

  • Conditional Hooks: Some hooks (e.g., ‘get_header’, ‘loop_start’) depend on the theme’s template structure and may not fire if the theme doesn’t call the corresponding functions (e.g., get_header()).
  • AJAX/Admin Variations: This sequence is for a front-end page load. Admin pages and AJAX requests have different flows (e.g., ‘admin_init’ instead of ‘init’ for admin).
  • Dynamic Hooks: Additional hooks like ‘wp_enqueue_scripts‘ (runs during ‘wp_head’) or custom hooks added by plugins/themes can intersperse this list.

Practical Example (Serialized in Code)

Here’s how you could test this sequence:

class HookChecker {
    public function __construct() {
        add_action( 'muplugins_loaded', array( $this, 'log_muplugins_loaded' ) );
        add_action( 'plugins_loaded', array( $this, 'log_plugins_loaded' ) );
        add_action( 'after_setup_theme', array( $this, 'log_after_setup_theme' ) );
        add_action( 'init', array( $this, 'log_init' ) );
        add_action( 'wp_loaded', array( $this, 'log_wp_loaded' ) );
        add_action( 'parse_request', array( $this, 'log_parse_request' ) );
        add_action( 'pre_get_posts', array( $this, 'log_pre_get_posts' ) );
        add_action( 'wp', array( $this, 'log_wp' ) );
        add_action( 'template_redirect', array( $this, 'log_template_redirect' ) );
        add_action( 'wp_head', array( $this, 'log_wp_head' ) );
        add_action( 'wp_footer', array( $this, 'log_wp_footer' ) );
        add_action( 'shutdown', array( $this, 'log_shutdown' ) );
    }

    public function log_muplugins_loaded() { error_log( '1. muplugins_loaded' ); }
    public function log_plugins_loaded() { error_log( '2. plugins_loaded' ); }
    public function log_after_setup_theme() { error_log( '3. after_setup_theme' ); }
    public function log_init() { error_log( '4. init' ); }
    public function log_wp_loaded() { error_log( '5. wp_loaded' ); }
    public function log_parse_request() { error_log( '6. parse_request' ); }
    public function log_pre_get_posts() { error_log( '7. pre_get_posts' ); }
    public function log_wp() { error_log( '8. wp' ); }
    public function log_template_redirect() { error_log( '9. template_redirect' ); }
    public function log_wp_head() { error_log( '10. wp_head' ); }
    public function log_wp_footer() { error_log( '11. wp_footer' ); }
    public function log_shutdown() { error_log( '12. shutdown' ); }
}

new HookChecker();

Log Output

1. muplugins_loaded
2. plugins_loaded
3. after_setup_theme
4. init
5. wp_loaded
6. parse_request
7. pre_get_posts
8. wp
9. template_redirect
10. wp_head
11. wp_footer
12. shutdown

Conclusion

This serialized list covers the main WordPress Hooks from start to finish for a typical front-end request. After wp_loaded, you’ve got hooks like wp, template_redirect, wp_head, wp_footer, and finally shutdown—each serving a specific purpose as WordPress builds and delivers the page. Let me know if you’d like me to expand on any of these!

]]>
https://techidem.com/complete-guide-to-wordpress-hooks-in-order/feed/ 0
How To Use Ajax Appropriately in WordPress Using Inline jQuery https://techidem.com/how-to-use-ajax-appropriately-in-wordpress-using-inline-jquery/ https://techidem.com/how-to-use-ajax-appropriately-in-wordpress-using-inline-jquery/#respond Sun, 07 Jan 2024 16:58:17 +0000 https://techidem.com/?p=2407 For some reason, I was inspired to write about WordPress Ajax using jQuery. Many WordPress developers are scared about WordPress Ajax including me 🙂 But it is super easy if you understand the basic process of Ajax in WordPress. Just using 3 steps you can complete your Ajax process. First and foremost, the selector, server-side process and jQuery script; then you can display content anywhere on your website.

Now it is time to write code –

HTML Button

First We are going to define a button where we will click for action.

<a href="proxy.php?url=javascript:void(0)" class="btn btn-primary" id="load-btn">Load Your Action</a>

Server-side process in PHP

In this step, We are going to receive data after the action is complete in jQuery. When we will click on the “Load Your Action” button jQuery will send data to the WordPress function. Now raise a question, how does WordPress identify the actual function? Yes, to identify this, we used a WordPress action hook, this hook’s name is “wp_ajax_” and the next part is “action name” and using this “action name” WordPress can invoke the absolute function. Example: wp_ajax_{your_action} So we can write this action like below –

add_action(‘wp_ajax_your_action’, ‘techidem_func’);

The action name is “your_action”, we will use this inside the jQuery Ajax “action”.

Note: The action name can be anything.

Now, how we can receive the data from jQuery to PHP? We can receive data using the PHP superglobal variable name $_POST. Just follow the below code snippet line no 2.

function techidem_func() {
    $recieved_data = $_POST['your_data'];

    // Send data to browser console
    wp_send_json_success($recieved_data);
}
add_action('wp_ajax_your_action', 'techidem_func'); // private call ( logged-in users )
add_action('wp_ajax_nopriv_your_action', 'techidem_func'); // This action for "No private call" ( non logged-in users )

Get more information about wp_ajax_{$action} and wp_ajax_nopriv_{$action}

Call Ajax using jQuery

<script type="text/javascript">

;(function ($) {

    'use strict';

    $(document).ready(function () {

        $('#load-btn').on('click', function(e) {
            $.ajax({
                type: "POST",
                url: '<?php echo esc_url( admin_url( 'admin-ajax.php' )); ?>',
                data: {
                    action: "your_action",  // the action to fire in the PHP server
                    your_data: {
                        name : "TechIdem",
                        url : "https://techidem.com/"
                    },
                },

                success: function (response) {
                    console.log( response );
                },
     
                complete: function (response) {     
                    console.log(JSON.parse(response.responseText).data);                                                                                                                                       
                },
            });
        });
    });

})(jQuery);

Eventually, we going to understand the jQuery part.

Previously we’ve discussed we will receive data using the PHP $_POST method because we are sending data through the POST method. That’s why we sent a POST request in Ajax.

Now where we are going to send our request?

Yeah, we are sending our request to “admin-ajax.php”. Using “admin-ajax.php” WordPress handle all Ajax requests. Please check line no 12.

Now we are ready to send our data. Using the data object we can send anything to the PHP. For example – action name, nonce, and so on. You can also create multiple JavaScript objects inside the jQuery data.

If the Ajax request is successfully submitted without any error and the status is 200, the success method will execute else error method.

For more details about jQuery Ajax please check the official documentation https://api.jquery.com/jQuery.ajax/

Note: I always love to write JavaScript code under “use strict” mode and it is best practice to avoid unwanted conflicts. And I believe every developer should obey this rule.

Check Result

How To Use Ajax Appropriately in WordPress Using Inline jQuery
Click on the browser Console or Network tab to see the result

]]>
https://techidem.com/how-to-use-ajax-appropriately-in-wordpress-using-inline-jquery/feed/ 0
Light & Dark Mode jQuery Toggle Using localStorage https://techidem.com/light-dark-mode-jquery-toggle-using-localstorage/ https://techidem.com/light-dark-mode-jquery-toggle-using-localstorage/#respond Fri, 25 Mar 2022 17:34:25 +0000 https://techidem.com/?p=1599 So, you are searching to accomplish light and dark mode jQuery toggle on your website. Yes, that is the tutorial for you. 

In this tutorial, I’m going to illustrate to you how to implement a jQuery toggle to switch the light and dark mode of your website and I shall use localStorage API to save switch mode in the browser. As a result, if a visitor refreshes the page or goes to another page it won’t change until another click on the toggle button.

I believe visitors will love this feature and really it is very convenient to read content/articles for a long time.

Now, let’s start –

First and foremost, going to declare the toggle class name as “mode-switcher” inside HTML div. You may use it anywhere on your website actually where you would like to show your toggle ( light and dark ) icon. Especially header is the best place what everyone doing this and it is UI and UX friendly. You can also put it on the sidebar. Eventually, I would like to say it should be visual for visitors.

<div class="mode-switcher">
    <i class="las mode-icon-change"></i>
</div>

Now, going to write jQuery code inside $(document).ready(function(){});

Step 2: First, check localStorage value that is saved or not and store it into a variable. I’ve declared a variable name as “switchMode”.

// Check for saved 'switchMode' in localStorage
let switchMode = localStorage.getItem('switchMode');

Step 3: Bind the selector class, which I’ve declared in the first snippet, and assign it to a variable name as “switchModeToggle”.

      // Get selector
      const switchModeToggle = $(' .mode-switcher ');

Step 4: Write a function for dark mode and assign this function to a variable whose name is “enableDarkMode”. When this function will trigger, it’ll add a class in the body tag. I’ve taken this class name “likhun-dark”. Besides, it’ll update the localStorage value as “enabled” for which the key is “switchMode”. 

      // Dark mode function
      const enableDarkMode = function() {
          // Add the class to the body
          $( 'body' ).addClass('likhun-dark');
          // Update switchMode in localStorage
          localStorage.setItem('switchMode', 'enabled');
      }

Step 5: In this step, I’m going to write another function to disable dark mode, which means enable light mode. Triggering this function will remove “likhun-dark” class from the body tag and it’ll update the localStorage value as “NULL”.

      // Light mdoe function
      const disableDarkMode = function() {
          // Remove the class from the body
          $( 'body' ).removeClass('likhun-dark');
          // Update switchMode in localStorage value
          localStorage.setItem('switchMode', null);
      }

Step 6: Here, I’ll keep mode enabled or disabled throughout the website. At first, check the switchMode value from localStorage; if it is “enabled”, show dark else light mode. That’s why I’m calling “enableDarkMode()” function when the localStorage “switchMode” value is enabled else value is NULL. Another interesting thing is added- change the trigger icon, when in dark mode, it’ll add the “la-moon” class for the night icon and remove the “la-sun” class for the light icon. The same work is also done in the light mode. 

Note: I’ve used Line Awesome icon class.

        // If the user already visited and enabled switchMode
        if (switchMode === 'enabled') {
            enableDarkMode();
            // Dark icon enabled
            $( '.mode-icon-change' ).addClass( 'la-moon' );
            $( '.mode-icon-change' ).removeClass( 'la-sun' );
        } else {
            // Light icon enabled
            $( '.mode-icon-change' ).addClass( 'la-sun' );
            $( '.mode-icon-change' ).removeClass( 'la-moon' );
        }

Step 7: In the final step, write a click event to change mode. When the event will happen, it’ll change the icon and verify the latest localStorage switchMode value. If localStorage value is “enabled”, dark mode will be active instantly; on the other hand, if localStorage value is “NULL” light mode will activate.

// When someone clicks the button
switchModeToggle.on('click', function() {
    // Change switch icon
    $( '.mode-icon-change' ).toggleClass( 'la-sun' );
    $( '.mode-icon-change' ).toggleClass( 'la-moon' );

    // get their switchMode setting
    switchMode = localStorage.getItem('switchMode');
   
    // if it not current enabled, enable it
    if (switchMode !== 'enabled') {
	enableDarkMode();              
    // if it has been enabled, turn it off  
    } else {  
	disableDarkMode();              
    }
});

Now you can write CSS code for your dark mode for instance –

body.likhun-dark {
    background: #191919;
    color: #ffffff;
}
.likhun-dark header.page-header.likhun-page-header {
    background: #333333;
    color: #ffffff;
}

Finally, I’m giving the complete HTML and jQuery code below –

HTML code:

<div class="mode-switcher">
    <i class="las mode-icon-change"></i>
</div>

jQuery code:

$(document).ready(function(){    

    /**
    * Light & Dark Mode jQuery Toggle Using localStorage
    */    

    // Check for saved 'switchMode' in localStorage
    let switchMode = localStorage.getItem('switchMode');

    // Get selector
    const switchModeToggle = $(' .mode-switcher ');

    // Dark mode function
    const enableDarkMode = function() {
        // Add the class to the body
        $( 'body' ).addClass('likhun-dark');
        // Update switchMode in localStorage
        localStorage.setItem('switchMode', 'enabled');
    }

    // Light mdoe function
    const disableDarkMode = function() {
        // Remove the class from the body
        $( 'body' ).removeClass('likhun-dark');
        // Update switchMode in localStorage value
        localStorage.setItem('switchMode', null);
    }

    // If the user already visited and enabled switchMode
    if (switchMode === 'enabled') {
        enableDarkMode();
        // Dark icon enabled
        $( '.mode-icon-change' ).addClass( 'la-moon' );
        $( '.mode-icon-change' ).removeClass( 'la-sun' );
    } else {
        // Light icon enabled
        $( '.mode-icon-change' ).addClass( 'la-sun' );
        $( '.mode-icon-change' ).removeClass( 'la-moon' );
    }

    // When someone clicks the button
    switchModeToggle.on('click', function() {
        // Change switch icon
        $( '.mode-icon-change' ).toggleClass( 'la-sun' );
        $( '.mode-icon-change' ).toggleClass( 'la-moon' );

        // get their switchMode setting
        switchMode = localStorage.getItem('switchMode');

        // if it not current enabled, enable it
        if (switchMode !== 'enabled') {
            enableDarkMode();              
        // if it has been enabled, turn it off  
        } else {  
            disableDarkMode();              
        }
    });

}); // End load document

Promotional:

If you are searching for web templates or themes for your business or freelance work, you may check our vast collections. I believe you’ll get your desired web template or theme for your startup.

]]>
https://techidem.com/light-dark-mode-jquery-toggle-using-localstorage/feed/ 0