PluginProbe
Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits / 3.2.2
Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits v3.2.2
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 / modules / utilities / custom-css / custom-css.php

custom-css.php in Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits 3.2.2, at inc/modules/utilities/custom-css/custom-css.php

226 lines 6.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace MasterAddons\Modules\Utilities;
4
5 use \Elementor\Controls_Manager;
6
7 /**
8 * Author Name: Liton Arefin
9 * Author URL: https://jeweltheme.com
10 * Date: 1/2/20
11 */
12
13 if (!defined('ABSPATH')) {
14 exit;
15 } // Exit if accessed directly.
16
17 class CustomCss
18 {
19
20 /*
21 * Instance of this class
22 */
23 private static $instance = null;
24
25
26 public function __construct()
27 {
28 // Add new controls to advanced tab globally
29 add_action("elementor/element/after_section_end", array($this, 'jltma_add_section_custom_css_controls'), 25, 3);
30
31 // Render the custom CSS
32 add_action('elementor/element/parse_css', array($this, 'jltma_add_post_css'), 10, 2);
33
34 // Security: sanitize Custom CSS on save. The control is registered only for
35 // edit_posts users, but Elementor saves can be crafted directly via admin-ajax
36 // (elementor_ajax), so the stored value must be cleaned of tag-breakout vectors
37 // (e.g. "</style><script>") before it is persisted and later added to the
38 // (possibly inline) stylesheet.
39 add_filter('elementor/document/save/data', array($this, 'jltma_sanitize_custom_css_on_save'), 10, 2);
40 }
41
42 /**
43 * Sanitize the 'custom_css' element settings in the data being saved.
44 *
45 * @param array $data Document data ('settings' + 'elements').
46 * @param mixed $document Elementor document instance.
47 * @return array
48 */
49 public function jltma_sanitize_custom_css_on_save($data, $document)
50 {
51 if (isset($data['settings']['custom_css'])) {
52 $data['settings']['custom_css'] = $this->jltma_sanitize_css($data['settings']['custom_css']);
53 }
54
55 if (!empty($data['elements']) && is_array($data['elements'])) {
56 $data['elements'] = $this->jltma_sanitize_element_custom_css($data['elements']);
57 }
58
59 return $data;
60 }
61
62 /**
63 * Recursively sanitize the 'custom_css' setting in element data.
64 *
65 * @param array $elements
66 * @return array
67 */
68 private function jltma_sanitize_element_custom_css($elements)
69 {
70 foreach ($elements as &$element) {
71 if (isset($element['settings']['custom_css'])) {
72 $element['settings']['custom_css'] = $this->jltma_sanitize_css($element['settings']['custom_css']);
73 }
74 if (!empty($element['elements']) && is_array($element['elements'])) {
75 $element['elements'] = $this->jltma_sanitize_element_custom_css($element['elements']);
76 }
77 }
78 unset($element);
79
80 return $elements;
81 }
82
83 /**
84 * Strip tag-breakout and active vectors from a CSS string. Valid CSS never needs
85 * HTML tags, PHP tags, expression(), @import or javascript:/behavior: — removing
86 * them prevents breaking out of an inline <style> block (XSS) while leaving normal
87 * declarations intact.
88 *
89 * @param string $css
90 * @return string
91 */
92 private function jltma_sanitize_css($css)
93 {
94 if (!is_string($css) || '' === $css) {
95 return '';
96 }
97
98 $css = str_replace(chr(0), '', $css);
99
100 // PHP tags.
101 $css = preg_replace('/<\?php/i', '', $css);
102 $css = str_replace(array('<?=', '<?', '?>'), '', $css);
103
104 // Any HTML tag (kills </style>/<script> breakout).
105 $css = preg_replace('#</?[a-z!][^>]*>#i', '', $css);
106
107 // Dangerous CSS constructs.
108 $css = preg_replace('/expression\s*\(/i', '', $css);
109 $css = preg_replace('/(javascript|vbscript)\s*:/i', '', $css);
110 $css = preg_replace('/behavior\s*:/i', '', $css);
111 $css = preg_replace('/@import\b/i', '', $css);
112
113 return $css;
114 }
115
116
117
118 public function jltma_add_section_custom_css_controls($widget, $section_id, $args)
119 {
120
121 if ('section_custom_css_pro' !== $section_id) {
122 return;
123 }
124
125 // Skip when Elementor Pro is active — Pro provides its own Custom CSS
126 if (defined('ELEMENTOR_PRO_VERSION')) {
127 return;
128 }
129
130 if (!current_user_can('edit_posts')) {
131 return;
132 }
133
134 $widget->start_controls_section(
135 'jltma_custom_css_section',
136 array(
137 'label' => __(' Custom CSS', 'master-addons') . JLTMA_EXTENSION_BADGE,
138 'tab' => Controls_Manager::TAB_ADVANCED
139 )
140 );
141
142 $widget->add_control(
143 'custom_css',
144 array(
145 'type' => Controls_Manager::CODE,
146 'label' => __('Custom CSS', 'master-addons'),
147 'label_block' => true,
148 'language' => 'css'
149 )
150 );
151 ob_start(); ?>
152 <pre>
153 Examples:
154 // To target main element
155 selector { color: red; }
156 // For child element
157 selector .child-element{ margin: 10px; }
158 </pre>
159 <?php
160 $output = ob_get_clean();
161
162 $widget->add_control(
163 'custom_css_description',
164 array(
165 'raw' => __('Use "selector" keyword to target wrapper element.', 'master-addons') . $output,
166 'type' => Controls_Manager::RAW_HTML,
167 'content_classes' => 'elementor-descriptor',
168 'separator' => 'none'
169 )
170 );
171
172 $widget->end_controls_section();
173
174 }
175
176
177
178 public function jltma_add_post_css($post_css, $element)
179 {
180 if (defined('ELEMENTOR_PRO_VERSION')) {
181 return;
182 }
183
184 $element_settings = $element->get_settings();
185
186 if (empty($element_settings['custom_css'])) {
187 return;
188 }
189
190 $css = trim($element_settings['custom_css']);
191
192 // Defense in depth: strip tag-breakout/active vectors before adding the CSS to
193 // the (possibly inline) stylesheet — covers values saved before this fix.
194 $css = $this->jltma_sanitize_css($css);
195
196 if (empty($css)) {
197 return;
198 }
199
200 // Replace 'selector' keyword with the element's unique selector
201 $css = str_replace('selector', $post_css->get_element_unique_selector($element), $css);
202
203 // Add a css comment for debugging
204 $css = sprintf(
205 '/* Start custom CSS for %s, class: %s */ %s /* End custom CSS */',
206 $element->get_name(),
207 $element->get_unique_selector(),
208 $css
209 );
210
211 $post_css->get_stylesheet()->add_raw_css($css);
212 }
213
214
215
216 public static function get_instance()
217 {
218 if (!self::$instance) {
219 self::$instance = new self;
220 }
221 return self::$instance;
222 }
223 }
224
225 CustomCss::get_instance();
226