PluginProbe
Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits / 3.0.9
Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits v3.0.9
3.2.2 3.2.3 3.2.1 3.2.0 3.1.9 3.1.8 3.1.7 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.9 trunk 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.3 1.1.4 1.1.5 All 174 releases
master-addons / inc / admin / widget-builder / widget-builder.php

widget-builder.php in Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits 3.0.9, at inc/admin/widget-builder/widget-builder.php

700 lines 24.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace MasterAddons\Inc\Admin\WidgetBuilder;
4
5 if (!defined('ABSPATH')) {
6 exit; // Exit if accessed directly.
7 }
8
9 use MasterAddons\Inc\Classes\Extension_Prototype;
10
11 /**
12 * Master Addons Widget Builder
13 * No-code custom widget creation for Elementor
14 */
15
16 class Widget_Builder extends Extension_Prototype {
17
18 public static $instance = null;
19
20 public function __construct() {
21 // NOTE: admin_menu is now handled by JLTMA_Widget_Admin class
22 // add_action('admin_menu', array($this, 'add_widget_builder_menu'));
23
24 // NOTE: admin_enqueue_scripts is now handled by JLTMA_Widget_Admin class
25 // add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));
26
27 add_action('wp_ajax_jltma_save_custom_widget', array($this, 'save_custom_widget'));
28 add_action('wp_ajax_jltma_delete_custom_widget', array($this, 'delete_custom_widget'));
29 add_action('wp_ajax_jltma_get_custom_widgets', array($this, 'get_custom_widgets'));
30 add_action('wp_ajax_jltma_get_widget_fields', array($this, 'get_widget_fields'));
31 add_action('elementor/widgets/widgets_registered', array($this, 'register_custom_widgets'));
32 add_action('wp_enqueue_scripts', array($this, 'enqueue_widget_styles'));
33 }
34
35 /**
36 * Add Widget Builder submenu under Master Addons
37 * NOTE: Menu is now handled by JLTMA_Widget_Admin class
38 */
39 public function add_widget_builder_menu() {
40 // Menu registration moved to JLTMA_Widget_Admin class
41 // This method kept for backward compatibility but does nothing
42 }
43
44 /**
45 * Enqueue admin scripts and styles
46 */
47 public function admin_enqueue_scripts($hook) {
48 // Only load on Widget Builder page
49 if ($hook !== 'master-addons_page_jltma-widget-builder') {
50 return;
51 }
52
53 // Enqueue Widget Builder React app
54 wp_enqueue_script(
55 'jltma-widget-builder-app',
56 JLTMA_URL . '/assets/js/admin/widget-builder-app.js',
57 array('wp-element', 'wp-i18n'),
58 JLTMA_VER,
59 true
60 );
61
62 // Enqueue Widget Builder styles
63 wp_enqueue_style(
64 'jltma-widget-builder',
65 JLTMA_URL . '/assets/css/admin/widget-builder.css',
66 array(),
67 JLTMA_VER
68 );
69
70 // Localize script data
71 $localize_data = array(
72 'ajaxurl' => admin_url('admin-ajax.php'),
73 'nonce' => wp_create_nonce('jltma_widget_builder_nonce'),
74 'pluginUrl' => JLTMA_URL,
75 'strings' => array(
76 'widgetBuilder' => __('Widget Builder', 'master-addons'),
77 'createWidget' => __('Create New Widget', 'master-addons'),
78 'editWidget' => __('Edit Widget', 'master-addons'),
79 'deleteWidget' => __('Delete Widget', 'master-addons'),
80 'saveWidget' => __('Save Widget', 'master-addons'),
81 'widgetName' => __('Widget Name', 'master-addons'),
82 'widgetTitle' => __('Widget Title', 'master-addons'),
83 'widgetIcon' => __('Widget Icon', 'master-addons'),
84 'widgetCategory' => __('Widget Category', 'master-addons'),
85 'addField' => __('Add Field', 'master-addons'),
86 'fieldType' => __('Field Type', 'master-addons'),
87 'fieldLabel' => __('Field Label', 'master-addons'),
88 'fieldName' => __('Field Name', 'master-addons'),
89 'preview' => __('Preview', 'master-addons'),
90 'livePreview' => __('Live Preview', 'master-addons'),
91 'widgetCode' => __('Widget Code', 'master-addons'),
92 'exportWidget' => __('Export Widget', 'master-addons'),
93 'importWidget' => __('Import Widget', 'master-addons'),
94 'noCodeBuilder' => __('No-Code Widget Builder', 'master-addons'),
95 'dragDropInterface' => __('Drag & Drop Interface', 'master-addons'),
96 'unlimitedWidgets' => __('Create Unlimited Custom Widgets', 'master-addons'),
97 'searchWidgets' => __('Search widgets...', 'master-addons'),
98 'filterByCategory' => __('Filter by Category', 'master-addons'),
99 'allCategories' => __('All Categories', 'master-addons'),
100 'basic' => __('Basic', 'master-addons'),
101 'advanced' => __('Advanced', 'master-addons'),
102 'ecommerce' => __('eCommerce', 'master-addons'),
103 'forms' => __('Forms', 'master-addons'),
104 'media' => __('Media', 'master-addons'),
105 'fieldTypes' => array(
106 'text' => __('Text Input', 'master-addons'),
107 'textarea' => __('Textarea', 'master-addons'),
108 'wysiwyg' => __('WYSIWYG Editor', 'master-addons'),
109 'select' => __('Select Dropdown', 'master-addons'),
110 'choose' => __('Choose Control', 'master-addons'),
111 'color' => __('Color Picker', 'master-addons'),
112 'media' => __('Media Upload', 'master-addons'),
113 'gallery' => __('Gallery', 'master-addons'),
114 'icon' => __('Icon Picker', 'master-addons'),
115 'url' => __('URL Input', 'master-addons'),
116 'number' => __('Number Input', 'master-addons'),
117 'slider' => __('Range Slider', 'master-addons'),
118 'date_time' => __('Date Time Picker', 'master-addons'),
119 'switcher' => __('Switcher Toggle', 'master-addons'),
120 'border' => __('Border Control', 'master-addons'),
121 'typography' => __('Typography', 'master-addons'),
122 'background' => __('Background', 'master-addons'),
123 'box_shadow' => __('Box Shadow', 'master-addons'),
124 'text_shadow' => __('Text Shadow', 'master-addons'),
125 'repeater' => __('Repeater Fields', 'master-addons')
126 )
127 ),
128 );
129
130 wp_localize_script('jltma-widget-builder-app', 'JLTMAWidgetBuilder', $localize_data);
131 }
132
133 /**
134 * Render Widget Builder page
135 * NOTE: This is now handled by JLTMA_Widget_Admin class
136 * When widget_id is present, it loads React editor
137 * When no widget_id, it shows list table (handled by JLTMA_Widget_Admin)
138 */
139 public function widget_builder_page() {
140 // Check if we're editing a specific widget
141 $widget_id = isset($_GET['widget_id']) ? intval($_GET['widget_id']) : 0;
142
143 if ($widget_id) {
144 // Render the Widget Builder React app editor
145 ?>
146 <div class="wrap jltma-widget-builder-wrap">
147 <div id="jltma-widget-builder-app"></div>
148 </div>
149 <?php
150 } else {
151 // List table is handled by JLTMA_Widget_Admin class
152 // This ensures backward compatibility
153 ?>
154 <div class="wrap jltma-widget-builder-wrap">
155 <div id="jltma-widget-builder-app"></div>
156 </div>
157 <?php
158 }
159 }
160
161
162 /**
163 * AJAX: Save custom widget
164 */
165 public function save_custom_widget() {
166 check_ajax_referer('jltma_widget_builder_nonce', 'nonce');
167
168 if (!current_user_can('manage_options')) {
169 wp_send_json_error(__('Insufficient permissions', 'master-addons'));
170 return;
171 }
172
173 $widget_data = isset($_POST['widget_data']) ? json_decode(stripslashes($_POST['widget_data']), true) : array();
174
175 if (empty($widget_data['name']) || empty($widget_data['title'])) {
176 wp_send_json_error(__('Widget name and title are required', 'master-addons'));
177 return;
178 }
179
180 // Sanitize widget data
181 $widget_data = $this->sanitize_widget_data($widget_data);
182
183 // Validate widget name format
184 if (!preg_match('/^[a-z0-9_-]+$/', $widget_data['name'])) {
185 wp_send_json_error(__('Widget name must contain only lowercase letters, numbers, hyphens and underscores', 'master-addons'));
186 return;
187 }
188
189 // Save to database
190 $widgets = get_option('jltma_custom_widgets', array());
191 $widget_id = isset($widget_data['id']) ? $widget_data['id'] : uniqid('jltma_widget_');
192 $widget_data['id'] = $widget_id;
193 $widgets[$widget_id] = $widget_data;
194
195 if (update_option('jltma_custom_widgets', $widgets)) {
196 // Generate widget class file
197 if ($this->generate_widget_class($widget_data)) {
198 wp_send_json_success(array(
199 'message' => __('Widget saved successfully', 'master-addons'),
200 'widget_id' => $widget_id
201 ));
202 } else {
203 wp_send_json_error(__('Widget saved but failed to generate class file', 'master-addons'));
204 }
205 } else {
206 wp_send_json_error(__('Failed to save widget', 'master-addons'));
207 }
208 }
209
210 /**
211 * AJAX: Delete custom widget
212 */
213 public function delete_custom_widget() {
214 check_ajax_referer('jltma_widget_builder_nonce', 'nonce');
215
216 if (!current_user_can('manage_options')) {
217 wp_send_json_error(__('Insufficient permissions', 'master-addons'));
218 }
219
220 $widget_id = sanitize_text_field($_POST['widget_id']);
221 $widgets = get_option('jltma_custom_widgets', array());
222
223 if (isset($widgets[$widget_id])) {
224 unset($widgets[$widget_id]);
225 update_option('jltma_custom_widgets', $widgets);
226
227 // Delete widget class file
228 $this->delete_widget_class($widget_id);
229
230 wp_send_json_success(__('Widget deleted successfully', 'master-addons'));
231 } else {
232 wp_send_json_error(__('Widget not found', 'master-addons'));
233 }
234 }
235
236 /**
237 * AJAX: Get custom widgets
238 */
239 public function get_custom_widgets() {
240 check_ajax_referer('jltma_widget_builder_nonce', 'nonce');
241
242 $widgets = get_option('jltma_custom_widgets', array());
243 wp_send_json_success($widgets);
244 }
245
246 /**
247 * AJAX: Get widget field types
248 */
249 public function get_widget_fields() {
250 check_ajax_referer('jltma_widget_builder_nonce', 'nonce');
251
252 wp_send_json_success($this->get_available_field_types());
253 }
254
255 /**
256 * Register custom widgets with Elementor
257 */
258 public function register_custom_widgets() {
259 if (!class_exists('\\Elementor\\Plugin')) {
260 return;
261 }
262
263 // Register custom categories first
264 $this->register_custom_categories();
265
266 $widgets = get_option('jltma_custom_widgets', array());
267
268
269 if (empty($widgets) || !is_array($widgets)) {
270 return;
271 }
272
273 foreach ($widgets as $widget_id => $widget_data) {
274 if (is_array($widget_data) && !empty($widget_data['name'])) {
275 $this->register_single_widget($widget_id, $widget_data);
276 }
277 }
278 }
279
280 /**
281 * Register custom Elementor categories
282 */
283 private function register_custom_categories() {
284 if (!class_exists('\\Elementor\\Plugin')) {
285 return;
286 }
287
288 // Get custom categories from options
289 $custom_categories = get_option('jltma_custom_widget_categories', array());
290
291 if (empty($custom_categories) || !is_array($custom_categories)) {
292 return;
293 }
294
295 $elements_manager = \Elementor\Plugin::$instance->elements_manager;
296
297 // Register each custom category
298 foreach ($custom_categories as $slug => $title) {
299 // Check if category doesn't already exist
300 $existing_categories = $elements_manager->get_categories();
301
302 if (!isset($existing_categories[$slug])) {
303 $elements_manager->add_category(
304 $slug,
305 array(
306 'title' => $title,
307 'icon' => 'eicon-posts-ticker',
308 )
309 );
310 }
311 }
312 }
313
314 /**
315 * Register a single custom widget
316 */
317 private function register_single_widget($widget_id, $widget_data) {
318 $widget_file = JLTMA_PATH . 'inc/admin/widgetbuilder/generated/' . $widget_id . '.php';
319
320 if (file_exists($widget_file)) {
321 require_once $widget_file;
322
323 $class_name = 'Custom_Widget_' . ucfirst($widget_id);
324 if (class_exists($class_name)) {
325 \Elementor\Plugin::instance()->widgets_manager->register_widget_type(new $class_name());
326 }
327 }
328 }
329
330 /**
331 * Sanitize widget data
332 */
333 private function sanitize_widget_data($data) {
334 if (!is_array($data)) {
335 return array();
336 }
337
338 $sanitized = array();
339
340 $sanitized['id'] = isset($data['id']) ? sanitize_key($data['id']) : '';
341 $sanitized['name'] = isset($data['name']) ? sanitize_key($data['name']) : '';
342 $sanitized['title'] = isset($data['title']) ? sanitize_text_field($data['title']) : '';
343 $sanitized['icon'] = isset($data['icon']) ? sanitize_text_field($data['icon']) : 'eicon-star';
344 $sanitized['category'] = isset($data['category']) ? sanitize_key($data['category']) : 'basic';
345 $sanitized['description'] = isset($data['description']) ? sanitize_textarea_field($data['description']) : '';
346 $sanitized['fields'] = isset($data['fields']) && is_array($data['fields']) ? $this->sanitize_fields($data['fields']) : array();
347 $sanitized['template'] = isset($data['template']) ? wp_kses($data['template'], wp_kses_allowed_html('post')) : '';
348 $sanitized['css'] = isset($data['css']) ? $this->sanitize_css($data['css']) : '';
349 $sanitized['js'] = isset($data['js']) ? $this->sanitize_js($data['js']) : '';
350 $sanitized['created_at'] = isset($data['created_at']) ? sanitize_text_field($data['created_at']) : current_time('mysql');
351 $sanitized['updated_at'] = current_time('mysql');
352
353 return $sanitized;
354 }
355
356 /**
357 * Sanitize widget fields
358 */
359 private function sanitize_fields($fields) {
360 $sanitized = array();
361
362 foreach ($fields as $field) {
363 $sanitized_field = array();
364 $sanitized_field['id'] = sanitize_key($field['id']);
365 $sanitized_field['type'] = sanitize_text_field($field['type']);
366 $sanitized_field['label'] = sanitize_text_field($field['label']);
367 $sanitized_field['name'] = sanitize_key($field['name']);
368 $sanitized_field['default'] = isset($field['default']) ? sanitize_text_field($field['default']) : '';
369 $sanitized_field['options'] = isset($field['options']) ? array_map('sanitize_text_field', $field['options']) : array();
370 $sanitized_field['condition'] = isset($field['condition']) ? $field['condition'] : array();
371
372 $sanitized[] = $sanitized_field;
373 }
374
375 return $sanitized;
376 }
377
378 /**
379 * Sanitize CSS content
380 */
381 private function sanitize_css($css) {
382 // Remove potentially dangerous CSS
383 $css = sanitize_textarea_field($css);
384
385 // Remove @import, javascript:, and other potentially dangerous CSS
386 $css = preg_replace('/@import\s+/i', '', $css);
387 $css = preg_replace('/javascript\s*:/i', '', $css);
388 $css = preg_replace('/expression\s*\(/i', '', $css);
389 $css = preg_replace('/behavior\s*:/i', '', $css);
390
391 return $css;
392 }
393
394 /**
395 * Sanitize JavaScript content
396 */
397 private function sanitize_js($js) {
398 // Basic sanitization for JavaScript
399 $js = sanitize_textarea_field($js);
400
401 // Remove potentially dangerous functions
402 $dangerous_functions = array(
403 'eval',
404 'setTimeout',
405 'setInterval',
406 'Function',
407 'XMLHttpRequest',
408 'fetch'
409 );
410
411 foreach ($dangerous_functions as $func) {
412 $js = preg_replace('/\b' . preg_quote($func, '/') . '\s*\(/i', '/* ' . $func . ' removed */ (', $js);
413 }
414
415 return $js;
416 }
417
418 /**
419 * Generate widget class file
420 */
421 private function generate_widget_class($widget_data) {
422 $generated_dir = JLTMA_PATH . 'inc/admin/widgetbuilder/generated/';
423
424 if (!file_exists($generated_dir)) {
425 if (!wp_mkdir_p($generated_dir)) {
426 return false;
427 }
428 }
429
430 if (!is_writable($generated_dir)) {
431 return false;
432 }
433
434 $widget_id = $widget_data['id'];
435 $class_name = 'Custom_Widget_' . ucfirst($widget_id);
436 $widget_name = sanitize_key($widget_data['name']);
437
438 $class_content = $this->get_widget_class_template($widget_data, $class_name, $widget_name);
439
440 $result = file_put_contents($generated_dir . $widget_id . '.php', $class_content);
441 return $result !== false;
442 }
443
444 /**
445 * Get widget class template
446 */
447 private function get_widget_class_template($widget_data, $class_name, $widget_name) {
448 // Generate field controls
449 $field_controls = '';
450 foreach ($widget_data['fields'] as $field) {
451 $field_controls .= $this->generate_field_control($field) . "\n";
452 }
453
454 // Generate template rendering code
455 $template_code = '';
456 if (!empty($widget_data['template'])) {
457 $template_escaped = addslashes($widget_data['template']);
458 $template_code = "
459 // Custom template
460 \$template = '{$template_escaped}';
461
462 // Replace placeholders with actual values
463 foreach (\$settings as \$key => \$value) {
464 if (is_string(\$value)) {
465 \$template = str_replace('{{' . \$key . '}}', \$value, \$template);
466 } elseif (is_array(\$value) && isset(\$value['url'])) {
467 \$template = str_replace('{{' . \$key . '}}', \$value['url'], \$template);
468 }
469 }
470
471 echo wp_kses_post(\$template);";
472 } else {
473 // Generate default template
474 foreach ($widget_data['fields'] as $field) {
475 if ($field['type'] === 'text' || $field['type'] === 'textarea') {
476 $template_code .= "
477 if (!empty(\$settings['{$field['name']}'])) {
478 echo '<div class=\"field-{$field['name']}\">' . esc_html(\$settings['{$field['name']}']) . '</div>';
479 }";
480 } elseif ($field['type'] === 'wysiwyg') {
481 $template_code .= "
482 if (!empty(\$settings['{$field['name']}'])) {
483 echo '<div class=\"field-{$field['name']}\">' . wp_kses_post(\$settings['{$field['name']}']) . '</div>';
484 }";
485 } elseif ($field['type'] === 'media') {
486 $template_code .= "
487 if (!empty(\$settings['{$field['name']}']['url'])) {
488 echo '<img src=\"' . esc_url(\$settings['{$field['name']}']['url']) . '\" alt=\"{$field['label']}\" class=\"field-{$field['name']}\">';
489 }";
490 }
491 }
492 }
493
494 // Optional dependencies
495 $style_depends = !empty($widget_data['css']) ? "
496 public function get_style_depends() {
497 return ['jltma-custom-widget-{$widget_name}'];
498 }" : '';
499
500 $script_depends = !empty($widget_data['js']) ? "
501 public function get_script_depends() {
502 return ['jltma-custom-widget-{$widget_name}'];
503 }" : '';
504
505 $template = "<?php
506
507 namespace MasterAddons\\Inc\\Admin\\WidgetBuilder\\Generated;
508
509 use Elementor\\Widget_Base;
510 use Elementor\\Controls_Manager;
511 use Elementor\\Group_Control_Typography;
512 use Elementor\\Group_Control_Background;
513 use Elementor\\Group_Control_Border;
514 use Elementor\\Group_Control_Box_Shadow;
515 use Elementor\\Group_Control_Text_Shadow;
516
517 if (!defined('ABSPATH')) {
518 exit;
519 }
520
521 /**
522 * Custom Widget: {$widget_data['title']}
523 * Generated by Master Addons Widget Builder
524 */
525 class {$class_name} extends Widget_Base {
526
527 public function get_name() {
528 return '{$widget_name}';
529 }
530
531 public function get_title() {
532 return __('{$widget_data['title']}', 'master-addons');
533 }
534
535 public function get_icon() {
536 return '{$widget_data['icon']}';
537 }
538
539 public function get_categories() {
540 return ['{$widget_data['category']}'];
541 }
542
543 public function get_keywords() {
544 return ['master-addons', 'custom', 'widget', '{$widget_name}'];
545 }
546
547 protected function _register_controls() {
548 \$this->start_controls_section(
549 'content_section',
550 [
551 'label' => __('Content', 'master-addons'),
552 'tab' => Controls_Manager::TAB_CONTENT,
553 ]
554 );
555
556 {$field_controls}
557 \$this->end_controls_section();
558
559 // Style section
560 \$this->start_controls_section(
561 'style_section',
562 [
563 'label' => __('Style', 'master-addons'),
564 'tab' => Controls_Manager::TAB_STYLE,
565 ]
566 );
567
568 \$this->add_group_control(
569 Group_Control_Typography::get_type(),
570 [
571 'name' => 'widget_typography',
572 'label' => __('Typography', 'master-addons'),
573 'selector' => '{{WRAPPER}} .jltma-custom-widget',
574 ]
575 );
576
577 \$this->end_controls_section();
578 }
579
580 protected function render() {
581 \$settings = \$this->get_settings_for_display();
582
583 echo '<div class=\"jltma-custom-widget jltma-{$widget_name}\">';
584 \$this->render_widget_content(\$settings);
585 echo '</div>';
586 }
587
588 private function render_widget_content(\$settings) {
589 {$template_code}
590 }
591 {$style_depends}
592 {$script_depends}
593 }";
594
595 return $template;
596 }
597
598 /**
599 * Generate field control code
600 */
601 private function generate_field_control($field) {
602 $control_type = $this->get_elementor_control_type($field['type']);
603
604 $control_code = " \$this->add_control(\n";
605 $control_code .= " '{$field['name']}',\n";
606 $control_code .= " [\n";
607 $control_code .= " 'label' => __('{$field['label']}', 'master-addons'),\n";
608 $control_code .= " 'type' => {$control_type},\n";
609
610 if (!empty($field['default'])) {
611 $control_code .= " 'default' => '{$field['default']}',\n";
612 }
613
614 if (!empty($field['options'])) {
615 $options_export = var_export($field['options'], true);
616 $control_code .= " 'options' => {$options_export},\n";
617 }
618
619 if (!empty($field['condition'])) {
620 $condition_export = var_export($field['condition'], true);
621 $control_code .= " 'condition' => {$condition_export},\n";
622 }
623
624 $control_code .= " ]\n";
625 $control_code .= " );\n";
626
627 return $control_code;
628 }
629
630 /**
631 * Get Elementor control type
632 */
633 private function get_elementor_control_type($field_type) {
634 $type_mapping = array(
635 'text' => 'Controls_Manager::TEXT',
636 'textarea' => 'Controls_Manager::TEXTAREA',
637 'wysiwyg' => 'Controls_Manager::WYSIWYG',
638 'select' => 'Controls_Manager::SELECT',
639 'choose' => 'Controls_Manager::CHOOSE',
640 'color' => 'Controls_Manager::COLOR',
641 'media' => 'Controls_Manager::MEDIA',
642 'gallery' => 'Controls_Manager::GALLERY',
643 'icon' => 'Controls_Manager::ICONS',
644 'url' => 'Controls_Manager::URL',
645 'number' => 'Controls_Manager::NUMBER',
646 'slider' => 'Controls_Manager::SLIDER',
647 'date_time' => 'Controls_Manager::DATE_TIME',
648 'switcher' => 'Controls_Manager::SWITCHER',
649 'border' => 'Controls_Manager::BORDER',
650 'repeater' => 'Controls_Manager::REPEATER'
651 );
652
653 return isset($type_mapping[$field_type]) ? $type_mapping[$field_type] : 'Controls_Manager::TEXT';
654 }
655
656 /**
657 * Delete widget class file
658 */
659 private function delete_widget_class($widget_id) {
660 $widget_file = JLTMA_PATH . 'inc/admin/widgetbuilder/generated/' . $widget_id . '.php';
661
662 if (file_exists($widget_file)) {
663 unlink($widget_file);
664 }
665 }
666
667 /**
668 * Enqueue widget styles and scripts
669 */
670 public function enqueue_widget_styles() {
671 $widgets = get_option('jltma_custom_widgets', array());
672
673 foreach ($widgets as $widget_id => $widget_data) {
674 if (!empty($widget_data['css'])) {
675 wp_add_inline_style('elementor-frontend', $widget_data['css']);
676 }
677
678 if (!empty($widget_data['js'])) {
679 wp_add_inline_script('elementor-frontend', $widget_data['js']);
680 }
681 }
682 }
683
684 /**
685 * Get instance
686 */
687 public static function get_instance() {
688 if (null === self::$instance) {
689 self::$instance = new self();
690 }
691 return self::$instance;
692 }
693 }
694
695 // Initialize Widget Builder
696 Widget_Builder::get_instance();
697
698
699 // Widget Builder - Production Ready
700