Install
This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.
Install straight from GitHub with WP-CLI:
wp plugin install https://github.com/crazyswami/hustle-elementor/archive/refs/heads/main.zip🐼 Hustle Widget AI - Comprehensive Documentation
Overview
Hustle Widget AI is a WordPress plugin that uses AI (OpenAI, Anthropic, Google Gemini) to generate fully functional Elementor widgets on-demand. Instead of manually coding widgets, you describe what you want in plain English, and the AI generates production-ready PHP code that integrates seamlessly with Elementor.
Version: 18.0.0
Author: Hustle Inc
Repository: github.com/CrazySwami/hustle-elementor
Last Updated: November 19, 2025
🚀 Quick Start
Installation
-
Clone the repository:
cd wp-content/plugins/ git clone https://github.com/CrazySwami/hustle-elementor.git -
Activate the plugin:
- Go to WordPress Admin → Plugins
- Find "Hustle Widget AI"
- Click "Activate"
-
Configure API Keys:
- Go to WordPress Admin → Hustle AI → Settings
- Add your API key(s):
- OpenAI: Get from platform.openai.com
- Anthropic: Get from console.anthropic.com
- Google Gemini: Get from aistudio.google.com
- Select your preferred model
- Click "Save Settings"
-
Generate Your First Widget:
- Go to WordPress Admin → Hustle AI → Widget Library
- Enter a prompt: "Create a modern pricing card with hover effects"
- Click "Generate Widget"
- Wait for the AI to generate your widget
- Refresh the page to see it in the library
-
Use in Elementor:
- Open any page in Elementor
- Search for your widget name in the widget panel
- Drag and drop onto the page
- Customize using the controls
Requirements
- WordPress 6.4 or higher
- Elementor 3.18 or higher
- PHP 8.0 or higher
- At least one AI API key (OpenAI, Anthropic, or Google Gemini)
🎯 What This Plugin Does
- AI-Powered Code Generation: Converts natural language prompts into complete Elementor widget PHP classes
- Multi-Provider Support: Works with OpenAI GPT-5.1, Anthropic Claude 4.5, and Google Gemini 3
- Automatic Registration: Generated widgets are automatically loaded and registered with Elementor
- Code Inspector: Built-in modal to view and debug generated code before it's saved
- Validation Layer: Prevents broken code from being saved to your site
📁 File Structure
Hustle-Elementor/
├── hustle-widget-generator.php # Main plugin file (core logic)
├── universal-widget-class.php # Legacy JSON-based widget class (deprecated)
├── editor.js # Elementor editor integration (floating button)
├── index.php # Security file (prevents directory listing)
├── widgets/ # Generated widget files stored here
│ ├── .gitkeep # Ensures folder is tracked in git
│ └── class-hustle-widget-{ID}.php # Auto-generated widget classes
└── README.md # This file
🚀 How It Works
Architecture Overview
The plugin uses a PHP Generation Model instead of the original JSON approach. Here's why:
❌ Why We Abandoned JSON
Initially, the plugin generated JSON objects that were parsed by a "Universal Widget Class". This approach had critical flaws:
- Escaping Hell: HTML, CSS, and JavaScript had to be escaped as JSON strings, causing:
"n n n"artifacts from literal newlines- Double-escaping issues
- Invalid JSON from AI responses
- Limited Flexibility: Couldn't use complex PHP logic or dynamic rendering
- AI Struggles: LLMs are better at generating code than JSON data structures
✅ Why PHP Generation Works
Now, the AI generates native Elementor widget classes as PHP files:
- No Escaping: HTML, CSS, and PHP can be written naturally
- Full Power: Access to all Elementor features (repeaters, typography controls, etc.)
- AI-Friendly: LLMs excel at generating structured code
- Validation: We can check syntax before saving
🔧 Technical Deep Dive
1. Generation Flow
User Prompt → AI API → Raw Response → Validation → File Save → Elementor Registration
Step-by-Step Process
Step 1: User Input
- User enters a prompt like "Create a 90s retro pricing card"
- Plugin determines which AI provider to use (from settings)
Step 2: System Prompt Engineering
$system_prompt = "You are an Expert Elementor Widget Developer.
Create a COMPLETE, VALID PHP class for a custom Elementor Widget.
CRITICAL RULES - FOLLOW EXACTLY:
1. Class Name MUST be: Hustle_Widget_{$temp_id}
2. Extend: \Elementor\Widget_Base (MUST include backslash)
3. ALL Elementor classes MUST use full namespace with backslash
4. Methods required: get_name(), get_title(), get_icon(), get_categories(), register_controls(), render()
...
";
Key Points:
- Uses
%%ID%%placeholder (replaced after post creation) - Emphasizes namespace requirements (
\Elementor\prefix) - Provides concrete examples to guide the AI
Step 3: API Call
$response = wp_remote_post( $url, [
'headers' => $headers,
'body' => json_encode($body),
'timeout' => 120 // 2 minutes for complex widgets
]);
Step 4: Response Extraction Handles different API response structures:
- OpenAI:
$raw_body['choices'][0]['message']['content'] - Anthropic:
$raw_body['content'][0]['text'] - Gemini:
$raw_body['candidates'][0]['content']['parts'][0]['text']
Step 5: Code Cleaning
// Remove markdown wrappers
if (preg_match('/```php\s*([\s\S]*?)\s*```/', $content_str, $matches))
$clean_code = $matches[1];
// Remove opening <?php tag (we add it back safely)
$clean_code = preg_replace('/^<\?php\s*/', '', $clean_code);
Step 6: Validation
// Check for missing backslashes (CRITICAL ERRORS)
if (strpos($clean_code, 'ElementorWidget_Base') !== false) {
$validation_errors[] = "CRITICAL: Missing backslash...";
}
Why This Matters:
ElementorWidget_Base→ Fatal Error (class not found)\Elementor\Widget_Base→ ✅ Works
Step 7: File Creation
$post_id = wp_insert_post([...]);
$final_code = str_replace('%%ID%%', $post_id, $clean_code);
$file_content = "<?php\nif ( ! defined( 'ABSPATH' ) ) exit;\n\n" . $final_code;
$file_path = plugin_dir_path(__FILE__) . 'widgets/class-hustle-widget-' . $post_id . '.php';
file_put_contents($file_path, $file_content);
Step 8: Elementor Registration
public function register_elementor_widgets( $widgets_manager ) {
$files = glob( plugin_dir_path(__FILE__) . 'widgets/*.php' );
foreach ( $files as $file ) {
require_once $file;
// Extract ID from filename and instantiate class
$class_name = "Hustle_Widget_" . $matches[1];
$widgets_manager->register( new $class_name() );
}
}
🐛 Troubleshooting Journey
Problem 1: "Invalid Data" and "n n n" Artifacts
Symptoms:
- Widget previews showed gibberish:
n n n n HUSTLE TOGETHER n LOG_IN|n|NT|n - JSON decode errors
Root Cause: AI was returning JSON with literal newlines inside strings:
{
"html_template": "<div>
Line 1
Line 2
</div>"
}
Why It Failed:
- JSON spec requires escaped newlines:
\n - Literal newlines break JSON parsing
- Our regex replacements created more issues
Solution: Switched from JSON to PHP generation entirely.
Problem 2: Missing Backslashes in Namespaces
Symptoms:
- Fatal Error:
Class 'ElementorWidget_Base' not found - Site crashed on widget load
Root Cause: AI generated:
class Hustle_Widget_123 extends ElementorWidget_Base {
// Missing backslash!
}
Why It Failed:
- PHP looks for
ElementorWidget_Basein global namespace - Actual class is
\Elementor\Widget_Base
Solution: Added validation to reject code with missing backslashes:
if (strpos($clean_code, 'ElementorWidget_Base') !== false) {
wp_send_json_error(['message' => 'CRITICAL: Missing backslash...']);
}
Problem 3: Auto-Fix Catastrophe
Symptoms:
- Site crashed with "Critical Error"
- PHP syntax errors
What We Tried:
Auto-fixing missing <?php tags:
// BAD APPROACH
$clean_code = str_replace('<?php', '', $clean_code); // Strip ALL tags
$clean_code = preg_replace('/^(\s+)foreach\s*\(/m', '$1<?php foreach (', $clean_code); // Add back
Why It Failed:
- Stripped tags from valid code
- Regex couldn't handle all edge cases
- Created malformed PHP
Solution: Removed auto-fix entirely. Better to reject bad code than risk breaking the site.
Problem 4: False Positive Validation
Symptoms:
- Valid code rejected with "No valid class declaration found"
Root Cause: Validation ran before ID replacement:
// Validation sees this:
class Hustle_Widget_%%ID%% extends \Elementor\Widget_Base
// Regex expects this:
class Hustle_Widget_123 extends \Elementor\Widget_Base
Solution: Removed the class declaration check. Only validate critical namespace errors.
✅ Current Validation Strategy
What We Check (Pre-Save)
-
Missing Backslashes (CRITICAL)
ElementorWidget_Base→ ❌ RejectElementorControls_Manager→ ❌ RejectElementorRepeater→ ❌ RejectElementorGroup_Control→ ❌ Reject
-
What We DON'T Check
- Class declaration format (too prone to false positives)
- PHP syntax (would need
php -l, not available in all environments) - Missing
<?phptags (AI usually gets this right now)
Why This Works
- Focused: Only checks for errors that cause fatal crashes
- Reliable: Simple string matching, no complex regex
- Safe: Rejects code before it's saved to disk
🎨 UI/UX Features
Admin Interface
Settings Tab:
- API key inputs for OpenAI, Anthropic, Gemini
- Model selector dropdown
- Save button
Widget Library Tab:
- Generation prompt textarea
- "Generate Widget" button
- Grid of existing widgets with:
- Widget title
- "View Code" button (
</>) - Class name display
Code Inspector Modal
Features:
- Dark theme (VS Code style)
- Syntax-highlighted display
- Shows on every generation (success or failure)
Success View:
✅ GENERATION SUCCESS
Provider: google
Class: Hustle_Widget_123
⬇️ FINAL PHP CODE (SAVED TO FILE) ⬇️
[Full PHP code here]
Error View:
❌ GENERATION FAILED
Message: AI Generated Invalid PHP Code - Please regenerate
💡 HINT: The AI did not follow the instructions. Try regenerating with a simpler prompt.
⚠️ VALIDATION ERRORS:
• CRITICAL: Found 'ElementorControls_Manager' - should be '\Elementor\Controls_Manager'
⬇️ GENERATED CODE (WITH ERRORS) ⬇️
[Broken code here]
🔐 Security Measures
1. File System Protection
// Every generated file starts with:
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
Purpose: Prevents direct file access via URL
2. Capability Checks
if ( ! current_user_can( 'edit_posts' ) )
wp_send_json_error( 'Unauthorized' );
Purpose: Only editors/admins can generate widgets
3. Input Sanitization
$prompt = sanitize_text_field( $_POST['prompt'] );
Purpose: Prevents XSS attacks
4. Output Escaping
echo esc_html($widget->post_title);
echo esc_attr($widget->post_content);
echo esc_url($link_url);
Purpose: Prevents XSS in admin interface
📊 Model Comparison
OpenAI GPT-5.1 Thinking
- Pros: Best at following complex instructions, great code quality
- Cons: Slower, more expensive
- Best For: Complex widgets with many controls
Anthropic Claude 4.5 Sonnet
- Pros: Fast, excellent at structured output, good balance
- Cons: Sometimes adds extra explanations
- Best For: General-purpose widget generation
Google Gemini 3 Pro
- Pros: Very fast, good at creative designs
- Cons: Occasionally misses namespace requirements
- Best For: Quick prototypes, visual-heavy widgets
🎓 Best Practices
Writing Effective Prompts
❌ Bad Prompt:
make a pricing table
✅ Good Prompt:
Create a 90s retro-style pricing card grid with:
- 3 columns
- Bold titles with drop shadows
- Repeater for features list
- Brutalist design with hard shadows
- Glitch effect on hover
Why It's Better:
- Specific design direction
- Mentions desired controls (repeater)
- Clear visual style
- Interactive elements specified
Debugging Generated Widgets
If Widget Doesn't Appear in Elementor:
- Check browser console for JS errors
- Check PHP error logs for fatal errors
- Click "View Code" button to inspect the generated class
- Verify file exists in
widgets/folder - Check class name matches filename
If Widget Appears But Doesn't Work:
- Open widget in Elementor
- Check browser console for errors
- Inspect the
render()method in generated code - Look for missing
<?phptags or syntax errors
🔄 Migration Notes
From JSON (v17) to PHP (v18)
Breaking Changes:
- Old JSON-based widgets will NOT work with new system
universal-widget-class.phpis now deprecated- Widget storage changed from
post_contentJSON to PHP files
Migration Path:
- Export old widget JSON from database
- Manually convert to PHP class format
- Save to
widgets/folder - OR: Just regenerate widgets with AI
🚨 Known Limitations
- No Syntax Validation: We can't run
php -lto check syntax before saving - AI Inconsistency: Different models may generate different quality code
- No Version Control: Regenerating overwrites the old widget
- No Editing: Can't edit generated code in admin (must edit PHP file directly)
🛠️ Development Roadmap
Potential Future Features
High Priority
-
[ ] HTML Preview in Admin - Render widget preview on settings page without Elementor
- Parse generated PHP to extract HTML/CSS
- Create sandboxed iframe preview
- Show with default control values
- Update preview when controls change
-
[ ] Smart Control Detection & Auto-Add
- Scan generated code for missing controls
- Detect FAQ patterns → suggest Accordion/Toggle controls
- Detect color usage → suggest Color Picker controls
- Detect typography → suggest Typography Group Control
- Prompt user: "We detected 3 colors but only 1 control. Add missing controls?"
-
[ ] Programmatic Control Identifiers
- Auto-generate semantic control names based on purpose:
primary_color,secondary_color,accent_colorheading_typography,body_typographyfaq_items(for repeaters)cta_button_text,cta_button_link
- Use AI to analyze widget purpose and suggest control naming conventions
- Enforce consistent naming across all generated widgets
- Auto-generate semantic control names based on purpose:
Elementor Globals Integration
-
[ ] Global Colors Support
$this->add_control( 'primary_color', [ 'label' => 'Primary Color', 'type' => \Elementor\Controls_Manager::COLOR, 'default' => '', 'global' => [ 'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_PRIMARY, ], ] ); -
[ ] Global Fonts Support
$this->add_group_control( \Elementor\Group_Control_Typography::get_type(), [ 'name' => 'heading_typography', 'global' => [ 'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_PRIMARY, ], 'selector' => '{{WRAPPER}} h2', ] ); -
[ ] Dynamic Tags Support
$this->add_control( 'title', [ 'label' => 'Title', 'type' => \Elementor\Controls_Manager::TEXT, 'dynamic' => [ 'active' => true, 'categories' => [ \Elementor\Modules\DynamicTags\Module::TEXT_CATEGORY, \Elementor\Modules\DynamicTags\Module::POST_META_CATEGORY, ], ], ] );
Medium Priority
- [ ] Syntax validation using
php -l(if available) - [ ] Widget versioning system
- [ ] In-admin code editor with syntax highlighting
- [ ] Widget templates library (pre-built starting points)
- [ ] Export/import functionality
- [ ] Multi-language support
- [ ] Automated testing for generated widgets
- [ ] Widget analytics (usage tracking)
Low Priority
- [ ] AI-powered widget optimization suggestions
- [ ] A/B testing framework for widgets
- [ ] Widget marketplace integration
- [ ] Collaborative widget editing
- [ ] Widget documentation auto-generation
🎨 Using Elementor Globals (Colors, Fonts, Dynamic Tags)
What Are Elementor Globals?
Elementor Globals allow widgets to inherit site-wide design settings from the Site Settings > Global Colors/Fonts. This ensures design consistency across all pages.
Global Colors
Benefits:
- Users can change site-wide colors from one place
- Widgets automatically update across all pages
- Maintains brand consistency
Implementation:
$this->add_control(
'heading_color',
[
'label' => 'Heading Color',
'type' => \Elementor\Controls_Manager::COLOR,
'default' => '', // Empty = use global default
'global' => [
'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_PRIMARY,
],
'selectors' => [
'{{WRAPPER}} .my-heading' => 'color: {{VALUE}};',
],
]
);
Available Global Colors:
Global_Colors::COLOR_PRIMARY- Primary brand colorGlobal_Colors::COLOR_SECONDARY- Secondary brand colorGlobal_Colors::COLOR_TEXT- Default text colorGlobal_Colors::COLOR_ACCENT- Accent/highlight color
How It Works:
- User opens widget in Elementor
- Color picker shows "Global" tab
- Selecting a global color links the control to site settings
- Changing global color updates all widgets using it
Global Fonts (Typography)
Benefits:
- Consistent typography across site
- Easy font family changes
- Responsive font sizing
Implementation:
$this->add_group_control(
\Elementor\Group_Control_Typography::get_type(),
[
'name' => 'title_typography',
'label' => 'Title Typography',
'global' => [
'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_PRIMARY,
],
'selector' => '{{WRAPPER}} .widget-title',
]
);
Available Global Typography:
Global_Typography::TYPOGRAPHY_PRIMARY- Primary heading fontGlobal_Typography::TYPOGRAPHY_SECONDARY- Secondary heading fontGlobal_Typography::TYPOGRAPHY_TEXT- Body text fontGlobal_Typography::TYPOGRAPHY_ACCENT- Accent text font
What It Controls:
- Font family
- Font size (with responsive breakpoints)
- Font weight
- Line height
- Letter spacing
- Text transform
Dynamic Tags
What Are Dynamic Tags? Dynamic content that pulls from WordPress (post titles, custom fields, user data, etc.)
Benefits:
- No hardcoding content
- Automatic updates when data changes
- Works with ACF, Toolset, etc.
Implementation:
$this->add_control(
'dynamic_title',
[
'label' => 'Title',
'type' => \Elementor\Controls_Manager::TEXT,
'default' => 'Default Title',
'dynamic' => [
'active' => true,
'categories' => [
\Elementor\Modules\DynamicTags\Module::TEXT_CATEGORY,
\Elementor\Modules\DynamicTags\Module::POST_META_CATEGORY,
],
],
]
);
Available Categories:
TEXT_CATEGORY- Post title, excerpt, author nameURL_CATEGORY- Post URL, featured image URLIMAGE_CATEGORY- Featured image, author avatarPOST_META_CATEGORY- Custom fieldsNUMBER_CATEGORY- Post ID, comment countDATE_CATEGORY- Post date, modified date
Example Use Cases:
- Display current post title in a custom hero section
- Show author bio from user meta
- Pull pricing from ACF fields
- Display dynamic copyright year
Complete Example: Widget with All Globals
protected function register_controls() {
// Content Section
$this->start_controls_section(
'content_section',
[
'label' => 'Content',
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
// Dynamic Title
$this->add_control(
'title',
[
'label' => 'Title',
'type' => \Elementor\Controls_Manager::TEXT,
'default' => 'My Widget Title',
'dynamic' => [
'active' => true,
'categories' => [
\Elementor\Modules\DynamicTags\Module::TEXT_CATEGORY,
],
],
]
);
$this->end_controls_section();
// Style Section
$this->start_controls_section(
'style_section',
[
'label' => 'Style',
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
// Global Color
$this->add_control(
'title_color',
[
'label' => 'Title Color',
'type' => \Elementor\Controls_Manager::COLOR,
'global' => [
'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_PRIMARY,
],
'selectors' => [
'{{WRAPPER}} .widget-title' => 'color: {{VALUE}};',
],
]
);
// Global Typography
$this->add_group_control(
\Elementor\Group_Control_Typography::get_type(),
[
'name' => 'title_typography',
'global' => [
'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_PRIMARY,
],
'selector' => '{{WRAPPER}} .widget-title',
]
);
$this->end_controls_section();
}
Result:
- Title can pull from post meta (dynamic)
- Color inherits from site primary color (global)
- Typography inherits from site primary heading (global)
- User can override any of these at widget level
Best Practices for Globals
-
Always Provide Globals as Defaults
'global' => [ 'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_PRIMARY, ], -
Allow Custom Overrides
- Don't force globals, let users choose custom colors if needed
- Empty default = use global, user can still pick custom
-
Use Semantic Naming
primary_colorfor main brand colorheading_typographyfor headingsbody_text_colorfor body text
-
Group Related Controls
- Put all color controls together
- Put all typography controls together
- Makes it easier for users to find globals
-
Document Global Usage
- Add descriptions explaining what each global does
- Example:
'description' => 'Uses site primary color by default'
📝 Code Examples
Example Generated Widget Structure
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
class Hustle_Widget_123 extends \Elementor\Widget_Base {
public function get_name() {
return 'hustle_widget_123';
}
public function get_title() {
return '90s Retro Pricing';
}
public function get_icon() {
return 'eicon-price-table';
}
public function get_categories() {
return [ 'general' ];
}
protected function register_controls() {
// Content Section
$this->start_controls_section(
'content_section',
[
'label' => 'Content',
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'title',
[
'label' => 'Title',
'type' => \Elementor\Controls_Manager::TEXT,
'default' => 'Hello World',
]
);
$this->end_controls_section();
}
protected function render() {
$settings = $this->get_settings_for_display();
?>
<div class="my-widget">
<h2><?php echo esc_html($settings['title']); ?></h2>
</div>
<?php
}
}
🤝 Contributing
We welcome contributions! Here's how you can help:
Reporting Issues
Found a bug? Open an issue and include:
- WordPress version
- Elementor version
- PHP version
- AI model used
- Prompt that caused the issue
- Generated code (from Code Inspector)
- Error messages from browser console and PHP logs
Submitting Pull Requests
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes
- Test thoroughly
- Commit:
git commit -m "Add amazing feature" - Push:
git push origin feature/amazing-feature - Open a Pull Request
Code Style
- Follow WordPress Coding Standards
- Use tabs for indentation
- Document complex logic with comments
- Keep functions focused and single-purpose
- Add PHPDoc blocks for all functions
📄 License
This plugin is licensed under the MIT License - see the LICENSE file for details.
Copyright (c) 2025 Hustle Inc
🙏 Acknowledgments
- Elementor Team: For the excellent widget API
- OpenAI, Anthropic, Google: For powerful AI models
- WordPress Community: For the robust plugin ecosystem
- Contributors: Thank you to everyone who has contributed to this project!
📞 Support
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Documentation: README.md
⭐ Show Your Support
If you find this plugin helpful, please consider:
- Starring the repository on GitHub
- Sharing it with other WordPress developers
- Contributing improvements or bug fixes
Last Updated: November 19, 2025
Plugin Version: 18.0.0
Tested With: WordPress 6.4+, Elementor 3.18+, PHP 8.0+