Gemini Chat Block
A WordPress Gutenberg block that provides an interactive AI Assistant powered by Google's Gemini 2.5 Flash. Secure, customizable, and fully dynamic chat interface for posts and pages.
by The WordPress Contributors · github.com/babarali-67/gemini-chat-block
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/babarali-67/gemini-chat-block/archive/refs/heads/main.zipGemini Chat Block - Complete Technical Documentation
Table of Contents
- Overview
- Architecture & Flow
- File Structure & Purpose
- How WordPress Processes the Block
- Code Components Explained
- Customization Guide
- Hooks & Filters
- Troubleshooting
Overview
The Gemini Chat Block is a WordPress Gutenberg block that provides an interactive AI Assistant powered by Google's Gemini 2.5 Flash model. The block follows WordPress block development best practices and uses modern JavaScript (React) for the editor interface and vanilla JavaScript for the frontend.
Key Features
- Manual Block Addition: Block appears ONLY when admin manually adds it via the block editor
- Dynamic Rendering: Uses PHP server-side rendering for secure API key handling
- Customizable Styling: Full control over colors, spacing, and appearance
- Secure API Communication: Nonce-verified AJAX requests
- Markdown Support: Basic formatting in AI responses
Architecture & Flow
High-Level Workflow
┌─────────────────────────────────────────────────────────────┐
│ Plugin Activation │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Admin Configuration (Settings > Gemini Chat Block) │
│ - Admin enters Gemini API key │
│ - Sets default styling preferences │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Block Registration (init hook) │
│ - WordPress registers block type │
│ - Block becomes available in block inserter │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Admin Adds Block to Post/Page (Manual) │
│ - Admin clicks + button in editor │
│ - Searches for "Gemini Chat Block" │
│ - Adds block to content │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Block Editor (Edit Component) │
│ - React component renders preview │
│ - Shows inspector controls for customization │
│ - Checks API key configuration status │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Post is Published/Updated │
│ - Block attributes saved to post_content │
│ - Stored as HTML comment with JSON attributes │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Frontend Rendering (render.php) │
│ - WordPress parses post_content │
│ - Finds block markup │
│ - Calls render.php with block attributes │
│ - Generates HTML output │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ User Interaction (view.js) │
│ - User types message │
│ - JavaScript sends AJAX request │
│ - API handler processes request │
│ - Calls Gemini API │
│ - Returns response to user │
└─────────────────────────────────────────────────────────────┘
Data Flow for Chat Messages
User Types Message
↓
view.js captures input
↓
Creates FormData with:
- action: 'gemini_chat_request'
- message: user's text
- nonce: security token
↓
Sends to /wp-admin/admin-ajax.php
↓
WordPress routes to:
api-handler.php → handle_chat_request()
↓
Verifies nonce (security)
↓
Validates API key exists
↓
Sanitizes user message
↓
Calls call_gemini_api()
↓
Makes HTTP POST to:
https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent
↓
Receives JSON response
↓
Extracts text from:
data['candidates'][0]['content']['parts'][0]['text']
↓
Returns via wp_send_json_success()
↓
view.js receives response
↓
Parses markdown formatting
↓
Displays in chat interface
File Structure & Purpose
gemini-chat-block/
│
├── gemini-chat-block.php # Main plugin file
│ ├── Defines plugin constants
│ ├── Includes admin.php and api-handler.php
│ └── Registers block on 'init' hook
│
├── includes/
│ ├── admin.php # Admin settings page
│ │ ├── Creates settings page in WordPress admin
│ │ ├── Registers settings (API key, default styles)
│ │ ├── Renders admin form with color pickers
│ │ └── Enqueues admin CSS/JS
│ │
│ └── api-handler.php # AJAX & API communication
│ ├── Handles 'gemini_chat_request' AJAX action
│ ├── Handles 'check_gemini_api_key' AJAX action
│ ├── Verifies nonces for security
│ ├── Makes HTTP requests to Gemini API
│ └── Returns formatted responses
│
├── assets/
│ ├── admin.css # Styles for admin settings page
│ └── admin.js # JavaScript for admin settings page
│
├── src/ # Source files (compiled to build/)
│ └── gemini-chat-block/
│ ├── block.json # Block metadata & attributes
│ │ ├── Defines block name, category, icon
│ │ ├── Declares all attributes (colors, text, etc.)
│ │ ├── Specifies supports (spacing, typography)
│ │ └── Links to scripts and styles
│ │
│ ├── index.js # Block registration
│ │ └── Registers block with WordPress using metadata
│ │
│ ├── edit.js # Editor component (React)
│ │ ├── Renders block preview in editor
│ │ ├── Provides InspectorControls (sidebar settings)
│ │ ├── Shows color pickers, text inputs, range controls
│ │ ├── Checks API key configuration
│ │ └── Updates block attributes
│ │
│ ├── render.php # Server-side rendering
│ │ ├── Receives $block object from WordPress
│ │ ├── Extracts attributes safely
│ │ ├── Checks API key configuration
│ │ ├── Enqueues frontend scripts
│ │ ├── Localizes data for JavaScript
│ │ └── Outputs HTML with inline styles
│ │
│ ├── view.js # Frontend JavaScript
│ │ ├── Initializes chat functionality
│ │ ├── Handles user input
│ │ ├── Sends AJAX requests
│ │ ├── Parses markdown formatting
│ │ ├── Displays messages
│ │ └── Manages loading states
│ │
│ ├── style.scss # Frontend & editor styles
│ │ ├── CSS custom properties for theming
│ │ ├── Chat container layout
│ │ ├── Message bubble styles
│ │ ├── Input field styles
│ │ ├── Animations (fade-in, typing indicator)
│ │ └── Responsive design
│ │
│ └── editor.scss # Editor-only styles
│ └── Inspector control styling
│
└── build/ # Compiled files (generated)
├── blocks-manifest.php # Block metadata as PHP array
└── gemini-chat-block/
├── block.json # Copied from src/
├── render.php # Copied from src/
├── index.js # Compiled & minified JavaScript
├── index.css # Compiled editor CSS
├── view.js # Compiled frontend JavaScript
└── style-index.css # Compiled frontend CSS
How WordPress Processes the Block
1. Plugin Initialization
When WordPress loads, it runs the init action hook:
add_action( 'init', 'create_block_gemini_chat_block_block_init' );
This function registers the block using one of three methods (depending on WordPress version):
wp_register_block_types_from_metadata_collection()(WP 6.8+)wp_register_block_metadata_collection()(WP 6.7+)register_block_type()(WP 6.0+)
Important: Registration does NOT add the block to posts. It only makes it available in the block inserter.
2. Block Appears in Editor
When admin edits a post:
- WordPress loads the block editor (Gutenberg)
- The editor fetches all registered blocks
- Our block appears in the inserter under "Widgets" category
- Admin must MANUALLY click and add it
3. Block Attributes Storage
When admin adds the block and customizes it:
<!-- wp:create-block/gemini-chat-block {
"primaryColor":"#2563eb",
"backgroundColor":"#ffffff",
"textColor":"#374151",
"borderRadius":8,
"placeholder":"Ask me anything...",
"welcomeMessage":"Hello! I'm your AI Assistant."
} /-->
This HTML comment is stored in post_content in the database.
4. Frontend Rendering
When a visitor views the post:
- WordPress parses
post_content - Finds block markers (``)
- Creates
WP_Blockobject with attributes - Calls
render.phpwith the block object render.phpgenerates HTML output- HTML is inserted into page
view.jsis enqueued and runs- Chat interface becomes interactive
Code Components Explained
1. Main Plugin File (gemini-chat-block.php)
Purpose: Entry point for the plugin
What it does:
// Define constants for paths and URLs
define( 'GEMINI_CHAT_BLOCK_VERSION', '0.1.0' );
define( 'GEMINI_CHAT_BLOCK_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
define( 'GEMINI_CHAT_BLOCK_PLUGIN_PATH', plugin_dir_path( __FILE__ ) );
// Load admin functionality only in admin area
if ( is_admin() ) {
require_once GEMINI_CHAT_BLOCK_PLUGIN_PATH . 'includes/admin.php';
}
// Load API handler for AJAX requests
require_once GEMINI_CHAT_BLOCK_PLUGIN_PATH . 'includes/api-handler.php';
// Register block on WordPress init
add_action( 'init', 'create_block_gemini_chat_block_block_init' );
Key Points:
- Uses
is_admin()to conditionally load admin code - Registers block using WordPress standards
- Block only appears when manually added by admin
2. Admin Settings (includes/admin.php)
Purpose: Provide admin interface for configuration
Class: Gemini_Chat_Block_Admin
Hooks Used:
admin_menu: Adds settings pageadmin_init: Registers settingsadmin_enqueue_scripts: Loads CSS/JS
Settings Registered:
gemini_chat_block_api_key(string): Gemini API keygemini_chat_block_default_styles(array): Default color preferences
Settings Page Location: Settings > Gemini Chat Block
What it does:
// Adds submenu under Settings
add_options_page(
'Gemini Chat Block Settings', // Page title
'Gemini Chat Block', // Menu title
'manage_options', // Capability required
'gemini-chat-block-settings', // Menu slug
array( $this, 'admin_page' ) // Callback function
);
// Registers settings in WordPress options table
register_setting( 'gemini_chat_block_settings', 'gemini_chat_block_api_key' );
3. API Handler (includes/api-handler.php)
Purpose: Handle AJAX requests and communicate with Gemini API
Class: Gemini_Chat_Block_API
AJAX Actions Registered:
gemini_chat_request: Handle chat messages (logged-in & public)check_gemini_api_key: Verify API key is configured
Security Measures:
- Nonce verification:
wp_verify_nonce( $_POST['nonce'], 'gemini_chat_nonce' ) - Input sanitization:
sanitize_text_field( $_POST['message'] ) - Proper error handling with
wp_send_json_error()
Gemini API Call:
$url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=" . $api_key;
$data = array(
'contents' => array(
array(
'parts' => array(
array(
'text' => "You are a helpful AI assistant. [user message]"
)
)
)
),
'generationConfig' => array(
'temperature' => 0.7, // Creativity level
'topK' => 40, // Token sampling
'topP' => 0.95, // Cumulative probability
'maxOutputTokens' => 1024, // Response length limit
)
);
$response = wp_remote_request( $url, array(
'method' => 'POST',
'timeout' => 30,
'headers' => array( 'Content-Type' => 'application/json' ),
'body' => json_encode( $data )
) );
4. Block Metadata (block.json)
Purpose: Define block properties and capabilities
Key Fields:
{
"name": "create-block/gemini-chat-block", // Unique identifier
"category": "widgets", // Where it appears in inserter
"icon": "smiley", // Dashicon
"attributes": { // Customizable properties
"primaryColor": { "type": "string", "default": "#2563eb" },
// ... more attributes
},
"supports": { // WordPress features
"html": false, // No HTML editing
"spacing": { "padding": true, "margin": true },
"typography": { "fontSize": true }
},
"render": "file:./render.php" // Server-side rendering
}
Attributes Explained:
primaryColor: Main color for buttons and user messagesbackgroundColor: Chat container backgroundtextColor: Message text colorborderRadius: Corner roundness (0-20px)placeholder: Input field placeholder textwelcomeMessage: Initial AI Assistant message
Supports:
html: false: Prevents raw HTML editing (security)spacing: Allows padding/margin controlstypography: Allows font size controls
5. Editor Component (edit.js)
Purpose: Render block in WordPress editor
Framework: React (via @wordpress/element)
Key Components Used:
useBlockProps: Adds WordPress-required propsInspectorControls: Sidebar settings panelPanelBody: Collapsible settings groupColorPicker: Color selectionRangeControl: Slider for numbersTextControl: Text input fields
State Management:
const [apiKeyConfigured, setApiKeyConfigured] = useState(false);
useEffect(() => {
// Check API key on component mount
fetch('/wp-admin/admin-ajax.php', {
method: 'POST',
body: 'action=check_gemini_api_key'
})
.then(response => response.json())
.then(data => setApiKeyConfigured(data.success));
}, []);
Attribute Updates:
setAttributes({ primaryColor: newColor })
This updates the block's saved attributes in the database.
6. Server-Side Rendering (render.php)
Purpose: Generate HTML for frontend
Input: $block object (WP_Block instance)
Process:
// 1. Extract attributes safely
$attributes = array();
if (isset($block)) {
if (is_object($block) && isset($block->attributes)) {
$attributes = $block->attributes; // WP_Block object
} elseif (is_array($block) && isset($block['attrs'])) {
$attributes = $block['attrs']; // Array format (fallback)
}
}
// 2. Get individual attributes with defaults
$primary_color = $attributes['primaryColor'] ?? '#2563eb';
// 3. Check API key configuration
$api_key = get_option( 'gemini_chat_block_api_key' );
$is_configured = !empty( $api_key );
// 4. Enqueue frontend JavaScript
wp_enqueue_script( 'gemini-chat-block-view', ... );
// 5. Pass data to JavaScript
wp_localize_script( 'gemini-chat-block-view', 'geminiChatBlock', array(
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'gemini_chat_nonce' ),
'isConfigured' => $is_configured
) );
// 6. Generate HTML with inline styles
$wrapper_attributes = get_block_wrapper_attributes( array(
'style' => sprintf(
'--gemini-primary-color: %s; ...',
esc_attr( $primary_color )
)
) );
Output: HTML with CSS custom properties for dynamic styling
7. Frontend JavaScript (view.js)
Purpose: Make chat interface interactive
Key Functions:
// Parse markdown to HTML
function parseMarkdown(text) {
return text
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>') // **bold**
.replace(/\*(.*?)\*/g, '<em>$1</em>') // *italic*
.replace(/`(.*?)`/g, '<code>$1</code>') // `code`
.replace(/\n/g, '<br>'); // line breaks
}
// Send message to API
async function sendMessage() {
const formData = new FormData();
formData.append('action', 'gemini_chat_request');
formData.append('message', message);
formData.append('nonce', geminiChatBlock.nonce);
const response = await fetch(geminiChatBlock.ajaxUrl, {
method: 'POST',
body: formData
});
const data = await response.json();
// Display response
}
// Add message to chat
function addMessage(content, type) {
const messageDiv = document.createElement('div');
messageDiv.className = `gemini-message ${type}-message`;
// Append to messages container
}
Event Listeners:
- Click on send button
- Enter key in textarea (Shift+Enter for new line)
- Auto-resize textarea as user types
8. Styling (style.scss)
Purpose: Style chat interface
CSS Custom Properties:
.wp-block-create-block-gemini-chat-block {
--gemini-primary-color: #2563eb;
--gemini-background-color: #ffffff;
--gemini-text-color: #374151;
--gemini-border-radius: 8px;
}
These are overridden by inline styles from render.php based on user customization.
Key Styles:
.gemini-chat-container: Main flex container.gemini-chat-messages: Scrollable message area.user-message: User's messages (right-aligned, primary color).assistant-message: AI responses (left-aligned, gray background).gemini-typing-indicator: Animated dots for loading state
Animations:
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes typing {
0%, 60%, 100% { transform: translateY(0); opacity: 0.4; }
30% { transform: translateY(-10px); opacity: 1; }
}
Customization Guide
1. Change Default Colors
Option A: Via Admin Settings
- Go to Settings > Gemini Chat Block
- Use color pickers to set defaults
- These apply to all new blocks
Option B: Modify Code
Edit src/gemini-chat-block/block.json:
"attributes": {
"primaryColor": {
"type": "string",
"default": "#your-color-here"
}
}
2. Customize AI Behavior
Edit includes/api-handler.php in call_gemini_api():
// Change personality
'text' => "You are a [friendly/professional/technical] AI assistant. [instructions]"
// Adjust creativity
'temperature' => 0.7, // 0.0 = deterministic, 1.0 = creative
// Change response length
'maxOutputTokens' => 1024, // Increase for longer responses
3. Add Custom Styling
Edit src/gemini-chat-block/style.scss:
// Add custom animation
.gemini-message {
animation: slideIn 0.3s ease-out;
}
// Change message bubble shape
.gemini-message-content {
border-radius: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
After changes, rebuild:
npm run build
4. Modify Welcome Message
Per Block: Use Inspector Controls in editor
Default: Edit block.json:
"welcomeMessage": {
"type": "string",
"default": "Your custom welcome message"
}
5. Add New Attributes
-
Add to
block.json:"attributes": { "showTimestamps": { "type": "boolean", "default": false } } -
Add control in
edit.js:<ToggleControl label="Show Timestamps" checked={showTimestamps} onChange={(value) => setAttributes({ showTimestamps: value })} /> -
Use in
render.php:$show_timestamps = $attributes['showTimestamps'] ?? false; -
Rebuild:
npm run build
Hooks & Filters
WordPress Hooks Used
Actions
-
init(Priority: 10)- Where:
gemini-chat-block.php - Purpose: Register block with WordPress
- Function:
create_block_gemini_chat_block_block_init()
- Where:
-
admin_menu(Priority: 10)- Where:
includes/admin.php - Purpose: Add settings page to admin menu
- Function:
Gemini_Chat_Block_Admin::add_admin_menu()
- Where:
-
admin_init(Priority: 10)- Where:
includes/admin.php - Purpose: Register plugin settings
- Function:
Gemini_Chat_Block_Admin::register_settings()
- Where:
-
admin_enqueue_scripts(Priority: 10)- Where:
includes/admin.php - Purpose: Load admin CSS/JS on settings page
- Function:
Gemini_Chat_Block_Admin::enqueue_admin_scripts()
- Where:
-
wp_ajax_gemini_chat_request(Priority: 10)- Where:
includes/api-handler.php - Purpose: Handle chat requests from logged-in users
- Function:
Gemini_Chat_Block_API::handle_chat_request()
- Where:
-
wp_ajax_nopriv_gemini_chat_request(Priority: 10)- Where:
includes/api-handler.php - Purpose: Handle chat requests from non-logged-in users
- Function:
Gemini_Chat_Block_API::handle_chat_request()
- Where:
-
wp_ajax_check_gemini_api_key(Priority: 10)- Where:
includes/api-handler.php - Purpose: Check if API key is configured
- Function:
Gemini_Chat_Block_API::check_api_key()
- Where:
Custom Hooks (None Currently)
This plugin does not currently define custom hooks, but you could add them:
Example - Add filter for AI prompt:
// In api-handler.php
$prompt = apply_filters( 'gemini_chat_block_prompt',
"You are a helpful AI assistant.",
$message
);
Usage in theme:
add_filter( 'gemini_chat_block_prompt', function( $prompt, $message ) {
return "You are a technical support assistant. " . $prompt;
}, 10, 2 );
Post Types & Taxonomies
Post Types
None Used: This plugin does not register custom post types.
The block can be added to any post type that supports Gutenberg blocks:
- Posts (
post) - Pages (
page) - Custom post types with
show_in_rest => true
Taxonomies
None Used: This plugin does not register custom taxonomies.
Troubleshooting
Block Not Appearing in Inserter
Problem: Can't find block when clicking +
Solutions:
- Clear WordPress transients: Install "Transients Manager" plugin
- Rebuild block:
npm run buildin plugin directory - Deactivate and reactivate plugin
- Check PHP error logs for registration errors
Block Appearing Automatically on Posts
Problem: Block shows up without being added
This should NOT happen. Possible causes:
- Theme or another plugin auto-inserting blocks
- Post content was imported with block already in it
- WordPress transient cache issue
Solutions:
- Check post content in database for ``
- Deactivate other plugins temporarily
- Switch to default WordPress theme (Twenty Twenty-Four)
- Clear all caches
Block Not Selectable in Editor
Problem: Can't click on block to select/edit/delete it
Solution: Fixed in latest version - block is now properly wrapped with useBlockProps() for proper WordPress block selection handling.
API Key Not Working
Problem: Chat doesn't respond
Solutions:
- Verify API key: Go to Google AI Studio
- Check browser console for JavaScript errors
- Check WordPress debug log for PHP errors
- Test API key with curl:
curl -X POST \ "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"contents":[{"parts":[{"text":"Hello"}]}]}'
Styling Not Applying
Problem: Custom colors not showing
Solutions:
- Clear browser cache
- Rebuild block:
npm run build - Check for CSS conflicts in browser developer tools
- Verify inline styles in page source
AJAX Errors
Problem: "Security check failed" or no response
Solutions:
- Check that JavaScript is loading: View page source
- Verify nonce is being created in
render.php - Check AJAX URL is correct (should be
/wp-admin/admin-ajax.php) - Look for JavaScript errors in console
Development Workflow
Making Changes
- Edit source files in
src/gemini-chat-block/ - Rebuild with
npm run build - Test in WordPress
- Repeat
Build Commands
# Development build (watch mode)
npm start
# Production build (minified)
npm run build
# Format code
npm run format
# Lint JavaScript
npm run lint:js
# Lint CSS
npm run lint:css
# Create plugin ZIP
npm run plugin-zip
File Watching
For development, use:
npm start
This watches for changes and automatically rebuilds.
Security Considerations
1. Nonce Verification
All AJAX requests verify nonces to prevent CSRF attacks.
2. Input Sanitization
User messages are sanitized with sanitize_text_field().
3. API Key Storage
API key is stored in WordPress options table, not exposed to frontend.
4. Capability Checks
Admin settings require manage_options capability.
5. Escaping Output
All dynamic output is escaped:
esc_attr()for attributesesc_html()for text contentwp_kses_post()for HTML content
Performance Optimization
1. Asset Loading
- Scripts loaded only when block is present
- Admin assets loaded only on settings page
- Production builds are minified
2. API Calls
- Timeout set to 30 seconds
- Error handling prevents hanging
- Results cached in browser during conversation
3. CSS
- Uses CSS custom properties (fast)
- Compiled and minified SCSS
- Responsive design with mobile-first approach
Conclusion
This plugin follows WordPress coding standards and best practices. The block appears ONLY when manually added by an administrator via the block editor. It provides a secure, customizable, and performant AI chat interface powered by Google's Gemini 2.5 Flash model.
For questions or issues, check the troubleshooting section or review the code comments in each file.