| name | Elementor Widget Development |
| description | Expert knowledge in creating custom Elementor widgets with 3D integration, responsive controls, and SkyyRose branding. Triggers on keywords like "elementor", "widget", "elementor widget", "custom element", "elementor pro", "page builder". |
| version | 1.0.0 |
Elementor Widget Development
Build custom Elementor widgets with advanced features including 3D viewers, luxury animations, and SkyyRose brand integration.
When to Use This Skill
Activate when working on:
- Custom Elementor widget development
- 3D product viewer widgets
- Collection grid widgets
- Pre-order form widgets
- Luxury testimonial carousels
- Interactive product galleries
- Custom Elementor controls
- Widget responsive settings
Widget Structure
Basic Widget Class
<?php
namespace SkyyRose\Elementor\Widgets;
use Elementor\Widget_Base;
use Elementor\Controls_Manager;
use Elementor\Group_Control_Typography;
use Elementor\Core\Schemes\Typography;
if (!defined('ABSPATH')) {
exit;
}
class Product_3D_Viewer extends Widget_Base {
public function get_name() {
return 'skyyrose-3d-viewer';
}
public function get_title() {
return __('3D Product Viewer', 'skyyrose');
}
public function get_icon() {
return 'eicon-3d-sphere';
}
public function get_categories() {
return ['skyyrose'];
}
public function get_keywords() {
return ['3d', 'product', 'viewer', 'skyyrose', 'jewelry'];
}
protected function register_controls() {
$this->start_controls_section(
'content_section',
[
'label' => __('3D Model', 'skyyrose'),
'tab' => Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'product_id',
[
'label' => __('Select Product', 'skyyrose'),
'type' => Controls_Manager::SELECT2,
'options' => $this->get_products(),
'default' => '',
'label_block' => true,
]
);
$this->add_control(
'model_url',
[
'label' => __('3D Model URL (.gltf or .glb)', 'skyyrose'),
'type' => Controls_Manager::URL,
'placeholder' => __('https://assets.skyyrose.co/models/product.glb', 'skyyrose'),
'default' => [
'url' => '',
],
]
);
$this->add_control(
'auto_rotate',
[
'label' => __('Auto Rotate', 'skyyrose'),
'type' => Controls_Manager::SWITCHER,
'label_on' => __('Yes', 'skyyrose'),
'label_off' => __('No', 'skyyrose'),
'return_value' => 'yes',
'default' => 'yes',
]
);
$this->add_control(
'camera_position',
[
'label' => __('Initial Camera Position', 'skyyrose'),
'type' => Controls_Manager::DIMENSIONS,
'size_units' => ['px'],
'default' => [
'top' => 0,
'right' => 0,
'bottom' => 5,
'left' => 0,
],
]
);
$this->end_controls_section();
$this->start_controls_section(
'style_section',
[
'label' => __('Viewer Style', 'skyyrose'),
'tab' => Controls_Manager::TAB_STYLE,
]
);
$this->add_responsive_control(
'viewer_height',
[
'label' => __('Height', 'skyyrose'),
'type' => Controls_Manager::SLIDER,
'size_units' => ['px', 'vh'],
'range' => [
'px' => [
'min' => 300,
'max' => 1000,
],
'vh' => [
'min' => 30,
'max' => 100,
],
],
'default' => [
'unit' => 'px',
'size' => 600,
],
'selectors' => [
'{{WRAPPER}} .skyyrose-3d-viewer' => 'height: {{SIZE}}{{UNIT}};',
],
]
);
$this->add_control(
'background_color',
[
'label' => __('Background Color', 'skyyrose'),
'type' => Controls_Manager::COLOR,
'default' => '#F5F5F5',
'selectors' => [
'{{WRAPPER}} .skyyrose-3d-viewer' => 'background-color: {{VALUE}};',
],
]
);
$this->add_control(
'lighting_preset',
[
'label' => __('Lighting Preset', 'skyyrose'),
'type' => Controls_Manager::SELECT,
'options' => [
'studio' => __('Studio', 'skyyrose'),
'outdoor' => __('Outdoor', 'skyyrose'),
'luxury' => __('Luxury (Rose Gold)', 'skyyrose'),
'dramatic' => __('Dramatic', 'skyyrose'),
],
'default' => 'luxury',
]
);
$this->end_controls_section();
$this->start_controls_section(
'controls_section',
[
'label' => __('Viewer Controls', 'skyyrose'),
'tab' => Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'show_controls',
[
'label' => __('Show Controls', 'skyyrose'),
'type' => Controls_Manager::SWITCHER,
'label_on' => __('Yes', 'skyyrose'),
'label_off' => __('No', 'skyyrose'),
'return_value' => 'yes',
'default' => 'yes',
]
);
$this->add_control(
'enable_zoom',
[
'label' => __('Enable Zoom', 'skyyrose'),
'type' => Controls_Manager::SWITCHER,
'label_on' => __('Yes', 'skyyrose'),
'label_off' => __('No', 'skyyrose'),
'return_value' => 'yes',
'default' => 'yes',
'condition' => [
'show_controls' => 'yes',
],
]
);
$this->add_control(
'enable_ar',
[
'label' => __('Enable AR (Beta)', 'skyyrose'),
'type' => Controls_Manager::SWITCHER,
'label_on' => __('Yes', 'skyyrose'),
'label_off' => __('No', 'skyyrose'),
'return_value' => 'yes',
'default' => 'no',
]
);
$this->end_controls_section();
}
protected function get_products() {
$products = [];
$query = new \WP_Query([
'post_type' => 'product',
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC',
]);
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
$products[get_the_ID()] = get_the_title();
}
wp_reset_postdata();
}
return $products;
}
protected function render() {
$settings = $this->get_settings_for_display();
$model_url = $settings['model_url']['url'] ?? '';
$product_id = $settings['product_id'] ?? 0;
if (empty($model_url) && $product_id) {
$model_url = get_post_meta($product_id, '_3d_model_url', true);
}
if (empty($model_url)) {
if (\Elementor\Plugin::$instance->editor->is_edit_mode()) {
echo '<div class="elementor-alert elementor-alert-warning">';
echo __('Please select a product or provide a 3D model URL.', 'skyyrose');
echo '</div>';
}
return;
}
wp_enqueue_script('threejs');
wp_enqueue_script('gltf-loader');
wp_enqueue_script('orbit-controls');
wp_enqueue_script('skyyrose-3d-viewer');
$this->add_render_attribute('wrapper', 'class', 'skyyrose-3d-viewer');
$this->add_render_attribute('wrapper', 'data-model-url', esc_url($model_url));
$this->add_render_attribute('wrapper', 'data-auto-rotate', $settings['auto_rotate']);
$this->add_render_attribute('wrapper', 'data-lighting', $settings['lighting_preset']);
$this->add_render_attribute('wrapper', 'data-enable-zoom', $settings['enable_zoom']);
$this->add_render_attribute('wrapper', 'data-enable-ar', $settings['enable_ar']);
?>
<div <?php echo $this->get_render_attribute_string('wrapper'); ?>>
<canvas class="viewer-canvas"></canvas>
<?php if ($settings['show_controls'] === 'yes') : ?>
<div class="viewer-controls">
<button class="control-btn" data-action="reset">
<span class="icon">↻</span>
<span class="sr-only"><?php _e('Reset View', 'skyyrose'); ?></span>
</button>
<?php if ($settings['enable_zoom'] === 'yes') : ?>
<button class="control-btn" data-action="zoom-in">
<span class="icon">+</span>
<span class="sr-"><? (' ', ''); ?></>
</>
< ="-" -="-">
< ="">-</>
< ="-"><? (' ', ''); ?></>
</>
<? ; ?>
<? ($[''] === '') : ?>
< ="- -" -="">
< ="">📱</>
< =""><? (' ', ''); ?></>
</>
<? ; ?>
</>
<? ; ?>
< ="-">
< =""></>
<><? (' 3 ...', ''); ?></>
</>
</>
<?
}
/**
*
*/
() {
?>
<
var modelUrl = settings.model_url.url || '';
if (!modelUrl) {
<div class="elementor-alert elementor-alert-warning">
{{{ '<?php _e("Please select a product or provide a 3D model URL.", "skyyrose"); ?>' }}}
</div>
<
return;
}
<div class="skyyrose-3d-viewer"
data-model-url="{{ modelUrl }}"
data-auto-rotate="{{ settings.auto_rotate }}"
data-lighting="{{ settings.lighting_preset }}">
<canvas class="viewer-canvas"></canvas>
<# if (settings.show_controls === 'yes') { #>
<div class="viewer-controls">
<button class="control-btn" data-action="reset">↻</button>
<# if (settings.enable_zoom === 'yes') { #>
<button class="control-btn" data-action="zoom-in">+</button>
<button class="control-btn" data-action="zoom-out">-</button>
<# } #>
</div>
<# } #>
</div>
<?php
}
}
Widget Registration
Register Custom Category
<?php
add_action('elementor/elements/categories_registered', 'skyyrose_register_elementor_category');
function skyyrose_register_elementor_category($elements_manager) {
$elements_manager->add_category(
'skyyrose',
[
'title' => __('SkyyRose', 'skyyrose'),
'icon' => 'fa fa-gem',
]
);
}
Register Widgets
<?php
add_action('elementor/widgets/register', 'skyyrose_register_elementor_widgets');
function skyyrose_register_elementor_widgets($widgets_manager) {
require_once SKYYROSE_THEME_DIR . '/elementor-widgets/product-3d-viewer.php';
require_once SKYYROSE_THEME_DIR . '/elementor-widgets/collection-grid.php';
require_once SKYYROSE_THEME_DIR . '/elementor-widgets/pre-order-form.php';
$widgets_manager->register(new \SkyyRose\Elementor\Widgets\Product_3D_Viewer());
$widgets_manager->register(new \SkyyRose\Elementor\Widgets\Collection_Grid());
$widgets_manager->register(new \SkyyRose\Elementor\Widgets\Pre_Order_Form());
}
Advanced Widget Examples
Collection Grid Widget
<?php
namespace SkyyRose\Elementor\Widgets;
class Collection_Grid extends \Elementor\Widget_Base {
public function get_name() {
return 'skyyrose-collection-grid';
}
public function get_title() {
return __('Collection Grid', 'skyyrose');
}
protected function register_controls() {
$this->start_controls_section(
'query_section',
[
'label' => __('Query', 'skyyrose'),
]
);
$this->add_control(
'collection',
[
'label' => __('Collection', 'skyyrose'),
'type' => \Elementor\Controls_Manager::SELECT,
=> [
=> (, ),
=> (, ),
=> (, ),
=> (, ),
],
=> ,
]
);
->(
,
[
=> (, ),
=> ::,
=> ,
=> ,
=> ,
]
);
->(
,
[
=> (, ),
=> ::,
=> [
=> (, ),
=> (, ),
=> (, ),
=> (, ),
],
=> ,
]
);
->();
->(
,
[
=> (, ),
]
);
->(
,
[
=> (, ),
=> ::,
=> ,
=> ,
=> ,
=> ,
=> ,
]
);
->(
,
[
=> (, ),
=> ::,
=> [],
=> [
=> [
=> ,
=> ,
],
],
=> [
=> ,
],
=> [
=> ,
],
]
);
->();
}
{
= ->();
= [
=> ,
=> [],
=> [],
];
([] !== ) {
[] = [
[
=> ,
=> [],
],
];
}
= ();
(!->()) {
. (, ) . ;
;
}
= [
=> [],
=> [] ?? ,
=> [] ?? ,
];
<div
Custom Controls
3D Model Picker Control
<?php
namespace SkyyRose\Elementor\Controls;
class Model_Picker extends \Elementor\Base_Data_Control {
public function get_type() {
return 'skyyrose-model-picker';
}
public function content_template() {
?>
<div class="elementor-control-field">
<label class="elementor-control-title">{{{ data.label }}}</label>
<div class="elementor-control-input-wrapper">
<button class="elementor-button" type="button">
<?php _e('Select 3D Model', 'skyyrose'); ?>
</button>
<input type="hidden" data-="{{ data.name }}model-preview
Widget JavaScript
3D Viewer Init Script
(function($) {
'use strict';
class SkyyRose3DViewer {
constructor(element) {
this.$element = $(element);
this.canvas = this.$element.find('.viewer-canvas')[0];
this.modelUrl = this.$element.data('model-url');
this.autoRotate = this.$element.data('auto-rotate') === 'yes';
this.lighting = this.$element.data('lighting');
this.init();
}
init() {
this.scene = new THREE.Scene();
this.camera = .(
,
..() / ..(),
,
);
...(, , );
. = .({
: .,
: ,
:
});
..(..(), ..());
..(.);
. = .(., ..);
.. = .;
.. = ;
.. = ;
.(.);
.();
.();
.();
}
() {
(preset === ) {
keyLight = .(, );
keyLight..(, , );
..(keyLight);
fillLight = .(, );
fillLight..(-, , -);
..(fillLight);
ambientLight = .(, );
..(ambientLight);
}
}
() {
loader = .();
..();
loader.(
.,
{
. = gltf.;
..(.);
box = .().(.);
center = box.( .());
...(center);
..();
},
{
percent = (progress. / progress.) * ;
..().();
},
{
.(, error);
..().();
}
);
}
() {
..(, , {
action = $(e.).();
.(action);
});
$().(, .());
}
() {
(action) {
:
.();
;
:
... -= ;
;
:
... += ;
;
:
.();
;
}
}
() {
...(, , );
..();
}
() {
.. = ..() / ..();
..();
..(..(), ..());
}
() {
( .());
..();
..(., .);
}
() {
(.) {
} {
anchor = .();
anchor. = ;
anchor. = ..(, );
anchor.();
}
}
}
$().(, () {
elementorFrontend..(, () {
($scope.());
});
});
})(jQuery);
SkyyRose Branding
Widget Styles
:root {
--skyyrose-primary: #B76E79;
--skyyrose-secondary: #2C2C2C;
}
.skyyrose-3d-viewer {
position: relative;
background: #F5F5F5;
border-radius: 12px;
overflow: hidden;
}
.viewer-controls {
position: absolute;
bottom: 20px;
right: 20px;
display: flex;
gap: 8px;
}
.control-btn {
width: 44px;
height: 44px;
border-radius: 50%;
background: var(--skyyrose-primary);
color: white;
border: none;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 2px 8px rgba(183, 110, 121, 0.3);
}
.control-btn:hover {
transform: scale(1.1);
box-shadow: (, , , );
}
{
: absolute;
: ;
: ;
: (-, -);
}
References
See references/ for:
elementor-api-reference.md - Complete Elementor API docs
custom-controls-guide.md - Building custom controls
widget-best-practices.md - Widget optimization
3d-integration-patterns.md - Three.js + Elementor
Examples
See examples/ for:
product-3d-viewer.php - Complete 3D viewer widget
collection-grid.php - Filterable product grid
pre-order-form.php - Custom form widget
luxury-testimonials.php - Testimonial carousel widget