• 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 user session manager block for Gutenberg using Tailwind CSS isolated elements

Step-by-Step Guide to building a custom user session manager block for Gutenberg using Tailwind CSS isolated elements

Gutenberg Block Development: A Custom User Session Manager with Isolated Tailwind CSS

This guide details the construction of a custom Gutenberg block designed to manage user sessions within a WordPress environment. We will focus on a robust, enterprise-grade implementation, emphasizing isolated styling using Tailwind CSS to prevent conflicts with global themes and plugins. This approach ensures predictable rendering and maintainability in complex WordPress deployments.

Project Setup and Block Registration

The foundation of any custom Gutenberg block lies in its registration within WordPress. We’ll leverage the `@wordpress/scripts` package for a streamlined build process and define our block’s metadata and registration logic in PHP.

First, ensure you have a WordPress development environment set up. Create a new plugin directory, for instance, wp-content/plugins/custom-session-manager. Inside this directory, create the main plugin file, custom-session-manager.php.

Plugin File: custom-session-manager.php

<?php
/**
 * Plugin Name: Custom Session Manager
 * Description: A custom Gutenberg block for managing user sessions with isolated Tailwind CSS.
 * Version: 1.0.0
 * Author: Antigravity
 * License: GPL-2.0-or-later
 * Text Domain: custom-session-manager
 *
 * @package CustomSessionManager
 */

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 context.
 *
 * @see https://developer.wordpress.org/reference/functions/register_block_type/
 */
function custom_session_manager_block_init() {
    register_block_type( __DIR__ . '/build' );
}
add_action( 'init', 'custom_session_manager_block_init' );

Next, we need to set up the JavaScript and build process. Initialize a Node.js project within your plugin directory:

cd wp-content/plugins/custom-session-manager
npm init -y
npm install @wordpress/scripts --save-dev

Create a package.json file with the following scripts:

{
  "name": "custom-session-manager",
  "version": "1.0.0",
  "description": "Custom Gutenberg block for user session management.",
  "main": "build/index.js",
  "scripts": {
    "build": "wp-scripts build",
    "start": "wp-scripts start"
  },
  "keywords": ["wordpress", "gutenberg", "block"],
  "author": "Antigravity",
  "license": "GPL-2.0-or-later",
  "devDependencies": {
    "@wordpress/scripts": "^26.0.0"
  }
}

Now, create a src directory for your block’s source files. Inside src, create index.js and block.json.

Block Metadata: block.json

The block.json file defines the block’s properties, including its name, title, category, and script/style dependencies. For isolated Tailwind CSS, we’ll specify our custom stylesheet here.

{
  "$schema": "https://schemas.wp.org/trunk/block.json",
  "apiVersion": 3,
  "name": "custom-session-manager/user-session",
  "version": "1.0.0",
  "title": "User Session Manager",
  "category": "widgets",
  "icon": "admin-users",
  "description": "Manages and displays user session information.",
  "keywords": ["session", "user", "auth", "management"],
  "attributes": {
    "sessionMessage": {
      "type": "string",
      "default": "Welcome, logged-in user!"
    },
    "guestMessage": {
      "type": "string",
      "default": "Please log in to access your session."
    }
  },
  "textdomain": "custom-session-manager",
  "editorScript": "file:./build/index.js",
  "editorStyle": "file:./build/index.css",
  "style": "file:./build/style-index.css"
}

Note the editorStyle and style properties. These will point to our compiled CSS, including the isolated Tailwind styles.

JavaScript for Block Logic: src/index.js

This file will contain the core JavaScript for registering the block and defining its editor and frontend rendering logic. We’ll use React components provided by the `@wordpress/element` and `@wordpress/block-editor` packages.

/**
 * WordPress dependencies
 */
import { registerBlockType } from '@wordpress/blocks';
import { useSelect } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import './style.scss'; // Main block styles
import './editor.scss'; // Editor-specific styles
import Edit from './edit';
import save from './save';

/**
 * Register the block
 */
registerBlockType( 'custom-session-manager/user-session', {
    edit: Edit,
    save,
} );

Editor Component: src/edit.js

The edit.js file defines how the block appears and behaves within the Gutenberg editor. We’ll use `useSelect` to fetch current user data and conditionally render content.

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
import { PanelBody, TextControl } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';

/**
 * Internal dependencies
 */
// No direct Tailwind import here, styles are handled by build process.

/**
 * The edit function describes the structure of your block in the context of the editor.
 * This represents what the editor will render when the block is used.
 *
 * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#edit
 *
 * @param {Object}   props               Properties passed to the function.
 * @param {Object}   props.attributes    Available block attributes.
 * @param {Function} props.setAttributes Function that updates block attributes.
 * @return {WPElement} Element to render.
 */
const Edit = ( { attributes, setAttributes } ) => {
    const { sessionMessage, guestMessage } = attributes;

    const currentUser = useSelect( ( select ) => {
        return select( coreStore ).getCurrentUser();
    }, [] );

    const blockProps = useBlockProps( {
        className: 'custom-session-manager-block', // Add a specific class for potential global overrides if needed, though Tailwind isolation is primary.
    } );

    const isLoggedIn = !! currentUser && currentUser.id !== 0;

    return (
        <>
            <InspectorControls>
                <PanelBody title={ __( 'Session Messages', 'custom-session-manager' ) }>
                    <TextControl
                        label={ __( 'Logged-in Message', 'custom-session-manager' ) }
                        value={ sessionMessage }
                        onChange={ ( value ) => setAttributes( { sessionMessage: value } ) }
                    />
                    <TextControl
                        label={ __( 'Guest Message', 'custom-session-manager' ) }
                        value={ guestMessage }
                        onChange={ ( value ) => setAttributes( { guestMessage: value } ) }
                    />
                </PanelBody>
            </InspectorControls>
            <div { ...blockProps }>
                { isLoggedIn ? (
                    <p>{ sessionMessage }</p>
                ) : (
                    <p>{ guestMessage }</p>
                ) }
                { /* Additional session details could be fetched and displayed here */ }
            </div>
        </>
    );
};

export default Edit;

Save Component: src/save.js

The save.js file defines the static HTML that will be saved to the database for the block’s frontend rendering. It should mirror the structure of the editor component but without interactive elements like InspectorControls.

/**
 * WordPress dependencies
 */
import { useBlockProps } from '@wordpress/block-editor';
import { useSelect } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 * No direct Tailwind import here, styles are handled by build process.
 */

/**
 * The save function defines the way in which the different attributes should
 * be combined into the final markup, which is then serialized by the block editor.
 *
 * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#save
 *
 * @param {Object}   props             Properties passed to the function.
 * @param {Object}   props.attributes  Available block attributes.
 * @return {WPElement} Element to render.
 */
const save = ( { attributes } ) => {
    const { sessionMessage, guestMessage } = attributes;

    // On the frontend, we cannot reliably determine login status via useSelect.
    // This block will render a placeholder or a default message.
    // A more advanced solution would involve a PHP-based shortcode or REST API call.
    // For simplicity here, we'll render a message that assumes a logged-in state
    // and rely on PHP to conditionally render it.
    // A common pattern is to output a placeholder and have PHP replace it.

    // For a purely static save, we'll output a message that *could* be dynamic.
    // The actual dynamic rendering will be handled by a PHP hook or shortcode.
    // However, for a block that *must* render something static, we can output
    // a generic message or rely on the attributes.

    // Let's output a placeholder that PHP can hook into.
    // A more robust approach for dynamic content is to use a shortcode within the block.
    // For this example, we'll output the logged-in message as a default,
    // and assume a PHP mechanism will handle the actual conditional rendering.

    // Alternative: Use a shortcode within the block's save function.
    // This requires registering a shortcode in PHP.
    // For this example, we'll stick to a simpler static output that implies dynamic content.

    const blockProps = useBlockProps.save( {
        className: 'custom-session-manager-block',
    } );

    // This static output will be rendered. For true dynamic behavior on the frontend
    // without JS, a PHP-based approach (shortcode or filter) is necessary.
    // We'll output the logged-in message as a default.
    return (
        <div { ...blockProps }>
            { /* This content is static. For dynamic rendering, consider a PHP shortcode. */ }
            <p>{ sessionMessage }</p>
        </div>
    );
};

export default save;

Important Note on Frontend Rendering: The save function in Gutenberg generates static HTML. Determining user login status reliably on the frontend without JavaScript can be challenging. For true dynamic rendering of session-specific content on the frontend, consider these strategies:

  • PHP Shortcode within Block: Register a shortcode in your PHP file and use it within the save function. The shortcode callback will handle the dynamic logic.
  • REST API Call: Use JavaScript in the frontend to fetch user status from the WordPress REST API and update the UI.
  • Server-Side Rendering (SSR): For blocks that require complex server-side logic, consider SSR, though this adds complexity to the build process.

For this example, we’ll proceed with the static output in save.js and acknowledge that a PHP-based solution is often preferred for critical dynamic content.

Styling with Isolated Tailwind CSS

To ensure Tailwind CSS styles are isolated to our block and do not affect the rest of the site, we will configure Tailwind to generate a specific CSS file and import it correctly. This involves setting up Tailwind’s configuration and build process.

Tailwind CSS Configuration

Install Tailwind CSS and its peer dependencies:

npm install tailwindcss postcss autoprefixer --save-dev

Initialize Tailwind CSS to create a tailwind.config.js file:

npx tailwindcss init

Configure tailwind.config.js to scan your block’s source files and specify the output CSS file. Crucially, we’ll use the content option to point to our block’s JavaScript and template files. We’ll also configure the prefix option to namespace all generated Tailwind classes, preventing global conflicts.

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './src/**/*.js', // Scan all JS files in src
    './src/**/*.jsx', // Scan all JSX files in src
    './block.json',   // Scan block.json for attributes and other metadata
    './**/*.php',     // Scan PHP files for potential shortcodes or dynamic content hooks
  ],
  prefix: 'tw-', // Prefix all Tailwind classes with 'tw-'
  theme: {
    extend: {},
  },
  plugins: [],
  // Ensure Tailwind doesn't purge styles needed by WordPress core or editor
  safelist: [
    // Add any classes that might be dynamically generated or essential for the editor UI
    // Example: 'tw-text-red-500', 'tw-bg-blue-200'
    // For this block, we'll rely on the prefix and specific class usage.
  ],
};

Next, create a postcss.config.js file:

module.exports = {
  plugins: [
    'tailwindcss/nesting',
    require('tailwindcss'),
    require('autoprefixer'),
  ],
};

Integrating Tailwind into the Build Process

We need to tell `@wordpress/scripts` to process our Tailwind CSS. Modify your package.json scripts to include PostCSS processing.

{
  "name": "custom-session-manager",
  "version": "1.0.0",
  "description": "Custom Gutenberg block for user session management.",
  "main": "build/index.js",
  "scripts": {
    "build": "wp-scripts build --experimental-modules",
    "start": "wp-scripts start --experimental-modules",
    "build:css": "npx tailwindcss -i ./src/style.scss -o ./build/style-index.css --minify",
    "watch:css": "npx tailwindcss -i ./src/style.scss -o ./build/style-index.css --watch"
  },
  "keywords": ["wordpress", "gutenberg", "block"],
  "author": "Antigravity",
  "license": "GPL-2.0-or-later",
  "devDependencies": {
    "@wordpress/scripts": "^26.0.0",
    "autoprefixer": "^10.4.16",
    "postcss": "^8.4.32",
    "tailwindcss": "^3.4.0"
  }
}

Now, create the main SCSS file for your block, src/style.scss. This file will import Tailwind and define the block’s specific styles.

/* Import Tailwind CSS */
@tailwind base;
@tailwind components;
@tailwind utilities;

/* Custom block styles */
.custom-session-manager-block {
    @apply tw-border tw-border-gray-300 tw-p-4 tw-rounded-md tw-bg-gray-50 tw-text-gray-800;

    p {
        @apply tw-text-lg tw-font-medium;
    }

    /* Styles for logged-in state */
    .logged-in > p {
        @apply tw-text-green-600;
    }

    /* Styles for guest state */
    .guest > p {
        @apply tw-text-red-600;
    }
}

/* Editor-specific styles */
.wp-block-custom-session-manager-user-session {
    @apply tw-border tw-border-dashed tw-border-blue-400 tw-p-4 tw-rounded-lg tw-bg-blue-50;

    p {
        @apply tw-text-base tw-italic;
    }
}

Create src/editor.scss for editor-only styles (optional, but good practice):

/* Editor-specific styles for the custom session manager block */
.wp-block-custom-session-manager-user-session {
    /* Example: Add a visual indicator in the editor */
    box-shadow: inset 0 0 0 2px rgba(0, 123, 255, 0.5);
    background-color: #eef7ff; /* Light blue background */
    padding: 1rem;
    border-radius: 0.5rem;
    border: 2px dashed #93c5fd; /* Dashed blue border */

    p {
        font-style: italic;
        color: #3b82f6; /* Tailwind blue-500 */
    }
}

Now, run the build commands. You’ll need to run both the WordPress scripts build and the Tailwind CSS build separately, or set up a watch process.

# For development (watches JS and CSS changes)
npm run start
# This will build JS and watch CSS separately.
# You might want a combined watch script:
# Add to package.json scripts: "dev": "npm run start & npm run watch:css"
# Then run: npm run dev

# For production build
npm run build
npm run build:css

After running the build commands, a build directory will be created containing index.js, index.css, and style-index.css. The PHP file registers the block using the contents of the build directory.

Frontend Dynamic Rendering (PHP Shortcode Approach)

To achieve dynamic user session display on the frontend, we’ll implement a PHP shortcode. This shortcode will be placed within the block’s save function, or used as a fallback if the block’s static save is insufficient.

Registering the Shortcode

Add the following to your custom-session-manager.php file:




With the shortcode registered, you can now modify the save.js to include this shortcode for dynamic frontend rendering:

/**
 * WordPress dependencies
 */
import { useBlockProps } from '@wordpress/block-editor';
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
// No direct Tailwind import here, styles are handled by build process.

const save = ( { attributes } ) => {
    const { sessionMessage, guestMessage } = attributes;

    // Use the shortcode for dynamic frontend rendering.
    // The attributes are passed as parameters to the shortcode.
    const shortcodeAttributes = `session_message="${sessionMessage.replace( /"/g, '"' )}" guest_message="${guestMessage.replace( /"/g, '"' )}"`;

    const blockProps = useBlockProps.save( {
        className: 'custom-session-manager-block',
    } );

    return (
        <div { ...blockProps }>
            { /* Render the shortcode for dynamic content on the frontend */ }
            { `[custom_session_manager ${shortcodeAttributes}]` }
        </div>
    );
};

export default save;

After updating save.js, re-run your build process (`npm run build` and `npm run build:css`). Now, when the block is used on the frontend, the [custom_session_manager] shortcode will be processed by WordPress, rendering the correct session message based on the user's login status.

Deployment and Considerations

To deploy this plugin:

  • Ensure the build directory is present and contains the compiled JavaScript and CSS files.
  • Upload the entire custom-session-manager plugin folder to your WordPress site's wp-content/plugins/ directory.
  • Activate the "Custom Session Manager" plugin through the WordPress admin panel.

Enterprise-Level Considerations:

  • Security: Always sanitize and escape output, especially when dealing with user-generated content or sensitive information. The use of `esc_html()` in the shortcode is a basic example. For more complex data, consider `wp_kses_post()` or specific sanitization functions.
  • Performance: For high-traffic sites, optimize asset loading. Consider using WordPress's built-in script and style enqueuing mechanisms effectively. The `filemtime()` function for cache busting is a good practice.
  • Scalability: The isolated Tailwind CSS approach with a prefix (`tw-`) is crucial for preventing style conflicts in large, multi-plugin environments. Ensure your Tailwind configuration (`content` paths) is comprehensive.
  • Accessibility: Ensure your block's UI and content are accessible. Use semantic HTML and ARIA attributes where appropriate.
  • Internationalization: Use `__()` and `_e()` for translatable strings, as demonstrated. Ensure your plugin has a proper text domain.
  • Error Handling: Implement robust error handling, especially for data fetching or API interactions.
  • Testing: Thoroughly test the block in various WordPress themes and with different user roles. Automated testing (unit, integration, e2e) is highly recommended for enterprise solutions.

By following these steps, you've built a custom Gutenberg block with isolated Tailwind CSS styling and dynamic frontend rendering capabilities, suitable for enterprise WordPress deployments.

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

  • Designing audit logs for enterprise WordPress setups tracking internal user modifications to custom product catalogs
  • Troubleshooting broken WP-Cron schedules in production when using modern Classic Core PHP wrappers
  • WordPress Development Recipe: Leveraging PHP 8.x Attributes to build type-safe, auto-wired hooks
  • Debugging Guide: Diagnosing broken WP-Cron schedules in multi-site network environments with modern tools
  • Troubleshooting guide: Resolving memory leak spikes caused by unclosed custom database loops in real estate agent listings

Categories

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

Recent Posts

  • Designing audit logs for enterprise WordPress setups tracking internal user modifications to custom product catalogs
  • Troubleshooting broken WP-Cron schedules in production when using modern Classic Core PHP wrappers
  • WordPress Development Recipe: Leveraging PHP 8.x Attributes to build type-safe, auto-wired hooks

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (872)
  • Debugging & Troubleshooting (658)
  • Security & Compliance (639)
  • 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