PluginProbe ʕ •ᴥ•ʔ
ElementsKit Elementor Addons – Advanced Widgets & Templates Addons for Elementor / 4.0.1
ElementsKit Elementor Addons – Advanced Widgets & Templates Addons for Elementor v4.0.1
4.0.2 4.0.1 4.0.0 3.10.02 3.10.01 3.9.10 3.9.9 3.9.8 3.9.7 3.9.5 3.9.6 3.9.3 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.3.1 2.3.1.1 2.3.2 2.3.3 2.3.4 2.3.5 2.3.6 2.3.7 2.4.0 2.5.0 2.5.1 2.5.10 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.8.5 2.8.6 2.8.7 2.8.8 2.9.0 2.9.1 2.9.2 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.6 3.4.7 3.4.8 3.4.9 3.5.0 3.5.1 3.5.2 3.5.3 3.5.4 3.5.5 3.5.6 3.6.0 3.6.1 3.7.0 3.7.1 3.7.2 3.7.3 3.7.4 3.7.5 3.7.6 3.7.7 3.7.8 3.7.9 3.8.0 3.8.1 3.8.2 3.9.0 3.9.1 3.9.2 trunk 1.2.6 1.2.7 1.2.9 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.10 1.5.11 1.5.12 1.5.2 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 2.0.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.13 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.0.9.1 2.0.9.2 2.0.9.3
elementskit-lite / modules / widget-builder / controls / widget-writer.php
elementskit-lite / modules / widget-builder / controls Last commit date
control-type-animation.php 4 years ago control-type-background.php 2 years ago control-type-border.php 2 years ago control-type-box-shadow.php 4 years ago control-type-choose.php 4 years ago control-type-code.php 4 years ago control-type-color.php 4 years ago control-type-date-time.php 1 year ago control-type-dimensions.php 4 years ago control-type-font.php 4 years ago control-type-gallery.php 4 years ago control-type-hover.php 4 years ago control-type-icons.php 4 years ago control-type-image-dimensions.php 4 years ago control-type-image-size.php 4 years ago control-type-input.php 4 years ago control-type-media.php 4 years ago control-type-number.php 4 years ago control-type-select.php 4 years ago control-type-select2.php 4 years ago control-type-slider.php 4 years ago control-type-switch.php 4 years ago control-type-text-area.php 4 years ago control-type-text-shadow.php 4 years ago control-type-typography.php 4 years ago control-type-url.php 4 years ago control-type-wys.php 4 years ago ct-base.php 4 years ago ct-contract.php 4 years ago ct-factory.php 4 years ago widget-writer.php 3 weeks ago
widget-writer.php
569 lines
1 <?php
2
3 namespace ElementsKit_Lite\Modules\Widget_Builder\Controls;
4
5 use ElementsKit_Lite\Modules\Widget_Builder\Widget_File;
6
7 defined( 'ABSPATH' ) || exit;
8
9 class Widget_Writer {
10
11 private $widget_name;
12 private $widget_id;
13 private $file_handler = '';
14 private $file_name;
15 private $enqueue_handler_prefix;
16 private $widget_class_name;
17 private $folder_name;
18 private $control_prefix;
19 private $name_prefix = 'ekit_wb_';
20 private $class_name_prefix = 'Ekit_Wb_';
21 private $widget_obj;
22 private $prepared_content = '';
23 public $text_domain = 'elementskit-lite';
24
25 const TAB_CONTENT = 'Controls_Manager::TAB_CONTENT';
26 const TAB_STYLE = 'Controls_Manager::TAB_STYLE';
27 const TAB_ADVANCE = 'Controls_Manager::TAB_ADVANCED';
28
29 const CONTROL_GROUP_TYPE_SINGLE = 'single';
30 const CONTROL_GROUP_TYPE_RESPONSIVE = 'responsive';
31 const CONTROL_GROUP_TYPE_GROUPED = 'group';
32
33
34 public function __construct( $widget, $widget_id, $txt_domain = 'elementskit-lite' ) {
35
36 $this->widget_obj = $widget;
37 $this->file_name = '';
38 $this->text_domain = $txt_domain;
39 $this->widget_id = $widget_id;
40
41 $this->folder_name = $this->name_prefix . $this->widget_id;
42 $this->widget_name = $this->name_prefix . $this->widget_id;
43 $this->widget_class_name = $this->class_name_prefix . $this->widget_id;
44 $this->control_prefix = $this->folder_name . '_';
45
46 $this->enqueue_handler_prefix = 'ekit-wb-' . $this->widget_id;
47 }
48
49
50 public function start_backing( $wp_filesystem ) {
51
52 $css_enqueue = $this->prepare_css_file( $this->widget_obj->css, $wp_filesystem );
53 $js_enqueue = $this->prepare_js_file( $this->widget_obj->js, $wp_filesystem );
54 $include_js = ! empty( $this->widget_obj->js_includes ) || ! empty( $this->widget_obj->css_includes );
55
56 $content = $this->prepare_php_file();
57
58 if ( $css_enqueue === true || $js_enqueue === true || $include_js === true ) {
59
60 $content .= $this->write_construct_method( $css_enqueue, $js_enqueue );
61 }
62
63 $content .= $this->write_name_method();
64 $content .= $this->write_title_method( $this->widget_obj->title );
65 $content .= $this->write_categories_method( $this->widget_obj->categories );
66 $content .= $this->write_icon_method( $this->widget_obj->icon );
67 $content .= $this->write_register_control_method( $this->widget_obj->tabs );
68 $content .= $this->write_render_method( $this->widget_obj->markup );
69 $content .= $this->close_widget_class();
70
71 $this->prepared_content = $content;
72 }
73
74
75 private function get_url_path() {
76
77 $upload = wp_upload_dir();
78
79 return $upload['baseurl'] . '/elementskit/custom_widgets/' . $this->folder_name;
80 }
81
82
83 private function get_file_path() {
84
85 $upload = wp_upload_dir();
86 $upload_dir = $upload['basedir'];
87 $upload_dir = $upload_dir . '/elementskit/custom_widgets/' . $this->folder_name;
88
89 if ( ! is_dir( $upload_dir ) ) {
90 wp_mkdir_p( $upload_dir );
91 }
92
93 return $upload_dir;
94 }
95
96
97 public static function delete_widget( $widget_id ) {
98
99 $fl_sys = Widget_File::get_wp_filesystem_pointer();
100
101 $wb = new self( array(), $widget_id );
102
103 $dir = $wb->get_file_path();
104
105 if ( file_exists( $dir ) ) {
106
107 $fl_sys->delete( $dir, true );
108 }
109
110 return true; // :P
111 }
112
113
114 private function prepare_css_file( $content, $file_system ) {
115
116 if ( empty( $content ) ) {
117 return false;
118 }
119
120 $trimmed = trim( $content );
121
122 if ( empty( $trimmed ) ) {
123 return false;
124 }
125
126 $path = $this->get_file_path();
127
128 return $file_system->put_contents( $path . '/style.css', $trimmed );
129 }
130
131
132 private function prepare_js_file( $content, $file_system ) {
133
134 if ( empty( $content ) ) {
135 return false;
136 }
137
138 $trimmed = trim( $content );
139
140 if ( empty( $trimmed ) ) {
141 return false;
142 }
143
144 $path = $this->get_file_path();
145
146 return $file_system->put_contents( $path . '/script.js', $trimmed );
147 }
148
149
150 public function finish_backing( $file_system ) {
151
152 $path = $this->get_file_path();
153
154 return $file_system->put_contents( $path . '/widget.php', $this->prepared_content );
155 }
156
157
158 private function prepare_php_file() {
159
160 $ret = '<?php' . PHP_EOL . PHP_EOL;
161 $ret .= 'namespace Elementor;' . PHP_EOL . PHP_EOL;
162 $ret .= 'defined(\'ABSPATH\') || exit;' . PHP_EOL . PHP_EOL;
163 $ret .= 'class ' . $this->widget_class_name . ' extends Widget_Base {' . PHP_EOL . PHP_EOL;
164
165 return $ret;
166 }
167
168
169 private function write_construct_method( $css = false, $js = false ) {
170
171 $nm = $this->enqueue_handler_prefix;
172 $url_path = $this->get_url_path();
173
174 $ret = "\t" . 'public function __construct($data = [], $args = null) {' . PHP_EOL;
175 $ret .= "\t\t" . 'parent::__construct($data, $args);' . PHP_EOL . PHP_EOL;
176
177 if ( $css === true ) {
178 $ret .= "\t\t" . 'wp_register_style( \'' . $nm . '-style-handle\', \'' . $url_path . '/style.css\');' . PHP_EOL;
179 }
180
181 if ( $js === true ) {
182 $ret .= "\t\t" . 'wp_register_script( \'' . $nm . '-script-handle\', \'' . $url_path . '/script.js\', [ \'elementor-frontend\' ], \'1.0.0\', true );' . PHP_EOL;
183 }
184
185 if ( ! empty( $this->widget_obj->css_includes ) ) {
186
187 $ret .= PHP_EOL;
188
189 foreach ( $this->widget_obj->css_includes as $idx => $cssInclude ) {
190
191 $ret .= "\t\t" . 'wp_enqueue_style( \'' . $nm . '-' . $idx . '-style-handle\', \'' . $cssInclude . '\');' . PHP_EOL;
192 }
193 }
194
195 if ( ! empty( $this->widget_obj->js_includes ) ) {
196
197 $ret .= PHP_EOL;
198
199 foreach ( $this->widget_obj->js_includes as $idx => $jsInclude ) {
200
201 $ret .= "\t\t" . 'wp_enqueue_script( \'' . $nm . '-' . $idx . '-script-handle\', \'' . $jsInclude . '\', [ \'elementor-frontend\' ], \'1.0.0\', true );' . PHP_EOL;
202 }
203 }
204
205 $ret .= "\t" . '}' . PHP_EOL . PHP_EOL;
206
207 if ( $css === true ) {
208 $ret .= "\n\t" . 'public function get_style_depends() {' . PHP_EOL;
209 $ret .= "\t\t" . 'return [ \'' . $nm . '-style-handle\' ];' . PHP_EOL;
210 $ret .= "\t" . '}' . PHP_EOL . PHP_EOL;
211 }
212
213 if ( $js === true ) {
214 $ret .= "\n\t" . 'public function get_script_depends() {' . PHP_EOL;
215 $ret .= "\t\t" . 'return [ \'' . $nm . '-script-handle\' ];' . PHP_EOL;
216 $ret .= "\t" . '}' . PHP_EOL . PHP_EOL;
217 }
218
219 return $ret;
220 }
221
222
223 private function write_name_method() {
224
225 $ret = "\t" . 'public function get_name() {' . PHP_EOL;
226 $ret .= "\t\t" . 'return \'' . $this->widget_name . '\';' . PHP_EOL;
227 $ret .= "\t" . '}' . PHP_EOL . PHP_EOL;
228
229 return $ret;
230 }
231
232
233 private function write_title_method( $title = 'empty_title' ) {
234
235 $ret = "\n\t" . 'public function get_title() {' . PHP_EOL;
236 $ret .= "\t\t" . 'return esc_html__( \'' . esc_html($title) . '\', \'' . $this->text_domain . '\' );' . PHP_EOL;
237 $ret .= "\t" . '}' . PHP_EOL . PHP_EOL;
238
239 return $ret;
240 }
241
242
243 private function write_categories_method( $cat = array( 'basic' ) ) {
244
245 $cat = empty( $cat ) ? array( 'basic' ) : $cat;
246
247 $joined = '\'';
248 $joined .= implode( '\', \'', $cat );
249 $joined .= '\'';
250
251 $ret = "\n\t" . 'public function get_categories() {' . PHP_EOL;
252 $ret .= "\t\t" . 'return [' . $joined . '];' . PHP_EOL;
253 $ret .= "\t" . '}' . PHP_EOL . PHP_EOL;
254
255 return $ret;
256 }
257
258
259 private function write_icon_method( $icon = 'eicon-cog' ) {
260
261 $ret = "\n\t" . 'public function get_icon() {' . PHP_EOL;
262 $ret .= "\t\t" . 'return \'' . $icon . '\';' . PHP_EOL;
263 $ret .= "\t" . '}' . PHP_EOL . PHP_EOL;
264
265 return $ret;
266 }
267
268
269 private function write_register_control_method( $conf = array() ) {
270
271 $ret = "\n\t" . 'protected function register_controls() {' . PHP_EOL;
272
273 if ( ! empty( $conf->content ) ) {
274
275 foreach ( $conf->content as $indx => $section ) {
276
277 $ret .= $this->write_section( $section->title, self::TAB_CONTENT, 'content', $indx );
278
279 if ( ! empty( $section->controls ) ) {
280
281 $ret .= $this->write_add_control( $section->controls );
282 }
283
284 $ret .= $this->close_section();
285 }
286 }
287
288 if ( ! empty( $conf->style ) ) {
289
290 foreach ( $conf->style as $indx => $section ) {
291
292 $ret .= $this->write_section( $section->title, self::TAB_STYLE, 'style', $indx );
293
294 if ( ! empty( $section->controls ) ) {
295
296 $ret .= $this->write_add_control( $section->controls );
297 }
298
299 $ret .= $this->close_section();
300 }
301 }
302
303 if ( ! empty( $conf->advanced ) ) {
304
305 foreach ( $conf->advanced as $indx => $section ) {
306
307 $ret .= $this->write_section( $section->title, self::TAB_ADVANCE, 'advance', $indx );
308
309 if ( ! empty( $section->controls ) ) {
310
311 $ret .= $this->write_add_control( $section->controls );
312 }
313
314 $ret .= $this->close_section();
315 }
316 }
317
318 $ret .= "\t" . '}' . PHP_EOL . PHP_EOL;
319
320 return $ret;
321 }
322
323
324 private function write_section( $label, $tab = 'Controls_Manager::TAB_CONTENT', $tab_name = 'content', $indx = '' ) {
325
326 $key = $tab_name . '_section_' . $this->widget_id . '_' . $indx;
327
328 $ret = "\n\t\t" . '$this->start_controls_section(' . PHP_EOL;
329 $ret .= "\t\t\t" . '\'' . $key . '\',' . PHP_EOL;
330 $ret .= "\t\t\t" . 'array(' . PHP_EOL;
331
332 $ret .= "\t\t\t\t" . '\'label\' => esc_html__( \'' . esc_html($label) . '\', \'' . $this->text_domain . '\' ),' . PHP_EOL;
333 $ret .= "\t\t\t\t" . '\'tab\' => ' . $tab . ',' . PHP_EOL;
334
335 $ret .= "\t\t\t" . ')' . PHP_EOL;
336 $ret .= "\t\t" . ');' . PHP_EOL;
337
338 return $ret;
339 }
340
341
342 private function write_add_control( $controls = array() ) {
343
344 $ret = '';
345
346 foreach ( $controls as $controlObj ) {
347
348 if ( $controlObj->control_group === self::CONTROL_GROUP_TYPE_SINGLE ) {
349
350 $ret .= $this->prepare_add_control( $controlObj );
351
352 } elseif ( $controlObj->control_group === self::CONTROL_GROUP_TYPE_RESPONSIVE ) {
353
354 $ret .= $this->prepare_responsive_control( $controlObj );
355
356 } elseif ( $controlObj->control_group === self::CONTROL_GROUP_TYPE_GROUPED ) {
357
358 $ret .= $this->prepare_group_control( $controlObj );
359 }
360 }
361
362 return $ret;
363 }
364
365
366 private function prepare_add_control( $controlObj ) {
367
368 $factory = new CT_Factory();
369 $cnt_obj = $factory->make( $controlObj->controlType, $this->text_domain );
370
371 $ret = "\n\t\t" . '$this->add_control(' . PHP_EOL;
372 $ret .= "\t\t\t" . '\'' . $this->control_prefix . $controlObj->key . '\',' . PHP_EOL;
373 $ret .= "\t\t\t" . 'array(' . PHP_EOL;
374
375 $ret .= "\t\t\t\t" . '\'label\' => esc_html__( \'' . esc_html($controlObj->label) . '\', \'' . $this->text_domain . '\' ),' . PHP_EOL;
376 $ret .= "\t\t\t\t" . '\'type\' => ' . $controlObj->control_type . ',' . PHP_EOL;
377
378 $ret .= $cnt_obj->start_writing_conf( $this->file_handler, $controlObj );
379
380 $ret .= "\t\t\t" . ')' . PHP_EOL;
381 $ret .= "\t\t" . ');' . PHP_EOL;
382
383 return $ret;
384 }
385
386
387 private function prepare_responsive_control( $controlObj ) {
388
389 $factory = new CT_Factory();
390 $cnt_obj = $factory->make( $controlObj->controlType, $this->text_domain, 'responsive' );
391
392 $ret = "\n\t\t" . '$this->add_responsive_control(' . PHP_EOL;
393 $ret .= "\t\t\t" . '\'' . $this->control_prefix . $controlObj->key . '\',' . PHP_EOL;
394 $ret .= "\t\t\t" . 'array(' . PHP_EOL;
395
396 $ret .= "\t\t\t\t" . '\'label\' => esc_html__( \'' . esc_html($controlObj->label) . '\', \'' . $this->text_domain . '\' ),' . PHP_EOL;
397 $ret .= "\t\t\t\t" . '\'type\' => ' . $controlObj->control_type . ',' . PHP_EOL;
398
399 //$cnt_obj->start_writing_conf($this->file_handler, $controlObj);
400
401 $ret .= "\t\t\t" . ')' . PHP_EOL;
402 $ret .= "\t\t" . ');' . PHP_EOL;
403
404 return $ret;
405 }
406
407
408 private function prepare_group_control( $controlObj ) {
409
410 $factory = new CT_Factory();
411 $cnt_obj = $factory->make( $controlObj->controlType, $this->text_domain, 'group' );
412
413 $ret = "\n\t\t" . '$this->add_group_control(' . PHP_EOL;
414 $ret .= "\t\t\t" . '' . $controlObj->control_type . ',' . PHP_EOL;
415 $ret .= "\t\t\t" . 'array(' . PHP_EOL;
416
417 $ret .= "\t\t\t\t" . '\'name\' => \'' . $this->control_prefix . $controlObj->key . '\',' . PHP_EOL;
418
419 $ret .= $cnt_obj->start_writing_conf( $this->file_handler, $controlObj );
420
421 $ret .= "\t\t\t" . ')' . PHP_EOL;
422 $ret .= "\t\t" . ');' . PHP_EOL;
423
424 return $ret;
425 }
426
427
428 private function close_section() {
429
430 return "\n\t\t" . '$this->end_controls_section();' . PHP_EOL . PHP_EOL;
431 }
432
433 private function is_allowed_render_php_block( $php_block ) {
434 $php_block = trim( $php_block );
435
436 $settings_path = '\$settings\["[A-Za-z0-9_\-]+"\](?:\["[A-Za-z0-9_\-]+"\])?';
437
438 $allowed_patterns = array(
439 '/^<\?php\s+echo\s+isset\(' . $settings_path . '\)\s+\?\s+' . $settings_path . '\s+:\s+"";\s+\?>$/',
440 '/^<\?php\s+echo\s+isset\(' . $settings_path . '\)\s+\?\s+(?:esc_url|esc_attr|wp_kses_post)\(' . $settings_path . '\)\s+:\s+"";\s+\?>$/',
441 '/^<\?php\s+Icons_Manager::render_icon\(\$settings\["[A-Za-z0-9_\-]+"\]\);\s+\?>$/',
442 );
443
444 foreach ( $allowed_patterns as $pattern ) {
445 if ( preg_match( $pattern, $php_block ) ) {
446 return true;
447 }
448 }
449
450 return false;
451 }
452
453 private function strip_unsafe_render_php( $markup ) {
454 return preg_replace_callback(
455 '/<\?(?:php|=)?[\s\S]*?\?>/i',
456 function( $matches ) {
457 return $this->is_allowed_render_php_block( $matches[0] ) ? $matches[0] : '';
458 },
459 $markup
460 );
461 }
462
463 /**
464 * Apply proper security escaping to widget markup
465 *
466 * @param string $markup The widget markup template
467 * @return string The processed markup with proper escaping
468 */
469 private function apply_escaping($markup) {
470 // Array of regex patterns and their replacements
471 $patterns = [
472 // Pattern 1: URL attributes in href, src, action with array access ["url"]
473 '/(href|src|action)=["\']\s*<\?php\s+echo\s+isset\s*\(\s*\$settings\s*\[\s*["\']([^"\']+)["\']\s*\]\s*\[\s*["\']url["\']\s*\]\s*\)\s*\?\s*\$settings\s*\[\s*["\']([^"\']+)["\']\s*\]\s*\[\s*["\']url["\']\s*\]\s*:\s*["\'][^"\']*["\']\s*;\s*\?>/i'
474 => '$1="<?php echo isset($settings["$2"]["url"]) ? esc_url($settings["$3"]["url"]) : ""; ?>"',
475
476 // Pattern 2: URL attributes in href, src, action (standard, not arrays)
477 '/(href|src|action)=["\']\s*<\?php\s+echo\s+isset\s*\(\s*\$settings\s*\[\s*["\']([^"\']+)["\']\s*\]\s*\)\s*\?\s*\$settings\s*\[\s*["\']([^"\']+)["\']\s*\]\s*:\s*["\'][^"\']*["\']\s*;\s*\?>/i'
478 => '$1="<?php echo isset($settings["$2"]) ? esc_url($settings["$3"]) : ""; ?>"',
479
480 // Pattern 3: Non-URL attributes (class, data-*, etc.) with array access
481 '/(?<!href|src|action)=["\']\s*<\?php\s+echo\s+isset\s*\(\s*\$settings\s*\[\s*["\']([^"\']+)["\']\s*\]\s*\[\s*["\'](?!url)([^"\']+)["\']\s*\]\s*\)\s*\?\s*\$settings\s*\[\s*["\']([^"\']+)["\']\s*\]\s*\[\s*["\']([^"\']+)["\']\s*\]\s*:\s*["\'][^"\']*["\']\s*;\s*\?>/i'
482 => '="<?php echo isset($settings["$1"]["$2"]) ? esc_attr($settings["$3"]["$4"]) : ""; ?>"',
483
484 // Pattern 4: Non-URL attributes (class, data-*, etc.) standard access
485 '/(?<!href|src|action)=["\']\s*<\?php\s+echo\s+isset\s*\(\s*\$settings\s*\[\s*["\']([^"\']+)["\']\s*\]\s*\)\s*\?\s*\$settings\s*\[\s*["\']([^"\']+)["\']\s*\]\s*:\s*["\'][^"\']*["\']\s*;\s*\?>/i'
486 => '="<?php echo isset($settings["$1"]) ? esc_attr($settings["$2"]) : ""; ?>"',
487
488 // Pattern 5: Text content (not in attributes) - use wp_kses_post()
489 '/>\s*<\?php\s+echo\s+isset\s*\(\s*\$settings\s*\[\s*["\']([^"\']+)["\']\s*\]\s*\)\s*\?\s*\$settings\s*\[\s*["\']([^"\']+)["\']\s*\]\s*:\s*["\'][^"\']*["\']\s*;\s*\?>\s*</i'
490 => '><?php echo isset($settings["$1"]) ? wp_kses_post($settings["$2"]) : ""; ?><',
491 ];
492
493 // Apply patterns in order
494 foreach ($patterns as $pattern => $replacement) {
495 $markup = preg_replace($pattern, $replacement, $markup);
496 }
497
498 // Additional safety check for any remaining URL array references
499 $markup = preg_replace_callback(
500 '/<\?php.*?\$settings\s*\[\s*["\']([^"\']+)["\']\s*\]\s*\[\s*["\']url["\']\s*\].*?\?>/i',
501 function($matches) {
502 $fullMatch = $matches[0];
503
504 // Only modify if it doesn't already have proper array checking
505 if (strpos($fullMatch, 'isset') === false || strpos($fullMatch, 'esc_url') === false) {
506 // Extract setting key
507 preg_match('/\$settings\s*\[\s*["\']([^"\']+)["\']\s*\]/', $fullMatch, $keyMatches);
508 $key = isset($keyMatches[1]) ? $keyMatches[1] : '';
509
510 if (!empty($key)) {
511 return '<?php echo isset($settings["' . $key . '"]["url"]) ? esc_url($settings["' . $key . '"]["url"]) : ""; ?>';
512 }
513 }
514
515 return $fullMatch;
516 },
517 $markup
518 );
519
520 return $markup;
521 }
522
523 private function write_render_method( $markup = '' ) {
524
525 $markup = \ElementsKit_Lite\Libs\Template\Loader::instance()->replace_tags( $markup, $this->control_prefix );
526
527 // Apply security escaping
528 $markup = $this->apply_escaping($markup);
529 $markup = $this->strip_unsafe_render_php($markup);
530
531 $ret = "\n\t" . 'protected function render() {' . PHP_EOL;
532
533 if ( ! empty( $markup ) ) {
534
535 $ret .= "\t\t" . '$settings = $this->get_settings_for_display();' . PHP_EOL . PHP_EOL;
536
537 $ret .= "\t\t" . '?>' . PHP_EOL;
538 $ret .= $markup . PHP_EOL;
539 $ret .= "\t\t" . '<?php' . PHP_EOL;
540 }
541
542 $ret .= "\t" . '}' . PHP_EOL . PHP_EOL;
543
544 return $ret;
545 }
546
547
548 private function close_widget_class() {
549
550 return PHP_EOL . '}' . PHP_EOL;
551 }
552
553
554 private function close_php_writer() {
555
556 fclose( $this->file_handler ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
557
558 return true;
559 }
560
561
562 /**
563 * @return string
564 */
565 public function get_widget_class_name() {
566 return $this->widget_class_name;
567 }
568 }
569