PluginProbe ʕ •ᴥ•ʔ
Kirki – Freeform Page Builder, Website Builder & Customizer / 6.1.1
Kirki – Freeform Page Builder, Website Builder & Customizer v6.1.1
6.1.1 6.1.0 6.0.14 6.0.13 6.0.12 6.0.11 6.0.10 6.0.9 6.0.8 6.0.7 6.0.6 6.0.5 6.0.4 6.0.3 6.0.2 6.0.1 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 4.0.19 4.0.20 4.0.21 4.0.22 4.0.23 4.0.24 4.1 4.2.0 5.0.0 5.1.0 5.1.1 5.2.0 5.2.1 5.2.2 5.2.3 6.0.0 trunk 3.0.40 3.0.41 3.0.42 3.0.43 3.0.44 3.0.45 3.1.0 3.1.1 3.1.2
kirki / includes / Ajax / Symbol.php
kirki / includes / Ajax Last commit date
Collaboration 2 weeks ago Apps.php 2 weeks ago Collection.php 1 month ago Comments.php 2 months ago DynamicContent.php 1 month ago ExportImport.php 2 days ago Form.php 2 weeks ago Media.php 2 days ago Page.php 2 days ago PageSettings.php 2 weeks ago RBAC.php 2 weeks ago Symbol.php 2 weeks ago Taxonomy.php 2 months ago TemplateExportImport.php 2 months ago UserData.php 2 weeks ago Users.php 2 months ago Walkthrough.php 2 months ago WordpressData.php 2 months ago WpAdmin.php 2 days ago
Symbol.php
447 lines
1 <?php
2 /**
3 * Manage Symbol
4 *
5 * @package kirki
6 */
7
8 namespace Kirki\Ajax;
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit; // Exit if accessed directly.
12 }
13
14 use Kirki\HelperFunctions;
15
16
17 /**
18 * Symbol API Class
19 */
20 class Symbol {
21
22 /**
23 * Create/save a symbol
24 *
25 * @return void wp_send_json.
26 *
27 * @deprecated
28 * @see \Kirki\App\Managers\SymbolManager::save()
29 */
30 public static function save() {
31 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
32 $post_symbol_data = isset( $_POST['data'] ) ? $_POST['data'] : null;
33 if ( ! empty( $post_symbol_data ) ) {
34 $wp_post = array(
35 'post_type' => KIRKI_SYMBOL_TYPE,
36 );
37
38 $post_id = wp_insert_post( $wp_post );
39 if ( isset( $post_id ) ) {
40
41 $symbol_data = json_decode( stripslashes( $post_symbol_data ), true );
42 $symbol_data['data'][ $symbol_data['root'] ]['properties']['symbolId'] = $post_id;
43
44 add_post_meta( $post_id, 'kirki', $symbol_data );
45 add_post_meta( $post_id, KIRKI_META_NAME_FOR_POST_EDITOR_MODE, 'kirki' );
46
47 $data = array(
48 'id' => $post_id,
49 'symbolData' => $symbol_data,
50 'type' => isset( $symbol_data['category'] ) ? $symbol_data['category'] : 'other',
51 );
52 $data['html'] = self::get_symbol_html_preview( $data );
53 wp_send_json( $data );
54 }
55 };
56
57 die();
58 }
59
60 /**
61 * @deprecated
62 * @see \Kirki\App\Managers\SymbolManager::save()
63 */
64 public static function save_to_db( $data ) {
65 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
66 $post_symbol_data = $data ? $data : null;
67
68 if ( ! empty( $post_symbol_data ) ) {
69 unset( $post_symbol_data['id'] );
70 unset( $post_symbol_data['elementId'] );
71
72 $post_symbol_data = $post_symbol_data['symbolData'];
73
74 $wp_post = array(
75 'post_type' => KIRKI_SYMBOL_TYPE,
76 );
77
78 $post_id = wp_insert_post( $wp_post );
79
80 if ( isset( $post_id ) ) {
81
82 $symbol_data = $post_symbol_data;
83 $symbol_data['data'][ $symbol_data['root'] ]['properties']['symbolId'] = $post_id;
84
85 add_post_meta( $post_id, 'kirki', $symbol_data );
86 add_post_meta( $post_id, KIRKI_META_NAME_FOR_POST_EDITOR_MODE, 'kirki' );
87
88 $data = array(
89 'id' => $post_id,
90 'symbolData' => $symbol_data,
91 'type' => isset( $symbol_data['category'] ) ? $symbol_data['category'] : 'other',
92 );
93 $data['html'] = self::get_symbol_html_preview( $data );
94
95 return $data;
96 }
97 };
98
99 return null;
100
101 }
102
103 /**
104 * Fetch symbol list
105 * if $internal is true then it will return array
106 * otherwise it will return json for api call
107 *
108 * @param boolean $internal if function call from internally.
109 * @param boolean $html if need html string.
110 * @return array|void wp_send_json.
111 */
112 public static function fetch_list( $internal = false, $html = false ) {
113 $posts = get_posts(
114 array(
115 'post_type' => KIRKI_SYMBOL_TYPE,
116 'post_status' => 'draft',
117 'numberposts' => -1,
118 )
119 );
120
121 $symbols = array();
122
123 if ( ! empty( $posts ) ) {
124 $symbols = array_map(
125 function( $post ) use ( $html, $internal ) {
126 $single_symbol = self::get_single_symbol( $post->ID, true, $html );
127 if ( ! $internal ) {
128 try {
129 unset( $single_symbol['symbolData']['data'] );
130 unset( $single_symbol['symbolData']['styleBlocks'] );
131 } catch ( \Throwable $th ) {
132 // throw $th;
133 }
134 }
135 return $single_symbol;
136 },
137 $posts
138 );
139 }
140
141 if ( $internal ) {
142 return $symbols;
143 }
144 wp_send_json( $symbols );
145 }
146 /**
147 * Fetch symbol
148 *
149 * @return void wp_send_json.
150 */
151 public static function fetch_symbol() {
152 $symbol_id = HelperFunctions::sanitize_text( isset( $_POST['id'] ) ? $_POST['id'] : null );
153 $symbol_element_prop = isset( $_POST['symbolElementProp'] ) ? $_POST['symbolElementProp'] : null;
154 $collection_item = isset( $_POST['collectionItem'] ) ? $_POST['collectionItem'] : null;
155 $variable_css = isset( $_POST['variableCSS'] ) ? $_POST['variableCSS'] : true;
156 $options = $collection_item ? json_decode( stripslashes( $collection_item ), true ) : array();
157 foreach ( $options as $key => $value ) {
158 if ( is_array( $value ) && $key !== 'user' ) {
159 $options[ $key ] = json_decode( json_encode( $value ) );
160 }
161 }
162 self::get_single_symbol( $symbol_id, false, true, $symbol_element_prop, $options, $variable_css );
163 }
164
165
166 /**
167 * get single symbol
168 * if $internal is true then it will return array
169 * otherwise it will return json for api call
170 *
171 * @param int $symbol_id symbol id.
172 * @param boolean $internal if the function call from internally.
173 * @param boolean $html if need html preview string.
174 * @return array|void
175 */
176 public static function get_single_symbol( $symbol_id = null, $internal = false, $html = false, $symbol_element_prop = false, $options = array(), $variable_css = true ) {
177 //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated,WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
178 $symbol_id = $symbol_id ? $symbol_id : HelperFunctions::sanitize_text( isset( $_GET['symbol_id'] ) ? $_GET['symbol_id'] : null );
179 $post = get_post( $symbol_id );
180 $symbol = null;
181 if ( $post && $post->post_type == KIRKI_SYMBOL_TYPE ) {
182 $symbol = array();
183 $symbol_data = get_post_meta( $post->ID, 'kirki', true );
184 $symbol['id'] = $post->ID;
185 $symbol['symbolData'] = $symbol_data;
186 $symbol['type'] = isset( $symbol_data['category'] ) ? $symbol_data['category'] : 'other';
187 $symbol['setAs'] = isset( $symbol_data['setAs'] ) ? $symbol_data['setAs'] : '';
188
189 if ( ! $internal ) {
190 $symbol_element_prop = json_decode( stripslashes( $symbol_element_prop ), true );
191 }
192 if ( $symbol_element_prop !== false && is_array( $symbol_element_prop ) ) {
193 foreach ( $symbol_element_prop as $key => $value ) {
194 foreach ( $symbol['symbolData']['data'] as $key2 => $value2 ) {
195 if ( isset( $value2['properties']['symbolElPropId'] ) && $value2['properties']['symbolElPropId'] == $key ) {
196 if ( isset( $value['contents'] ) ) {
197 $symbol['symbolData']['data'][ $key2 ]['properties']['contents'] = $value['contents'];
198 }
199 if ( isset( $value['contentElement'] ) ) {
200 foreach ( $value['contentElement'] as $new_item ) {
201 if ( isset( $new_item['id'] ) ) {
202 $symbol['symbolData']['data'][ $new_item['id'] ] = $new_item;
203 }
204 }
205 }
206 if ( isset( $value['attributes'] ) ) {
207 $symbol['symbolData']['data'][ $key2 ]['properties']['attributes'] = $value['attributes'];
208 }
209 if ( isset( $value['wp_attachment_id'] ) ) {
210 $symbol['symbolData']['data'][ $key2 ]['properties']['wp_attachment_id'] = $value['wp_attachment_id'];
211 }
212 if ( isset( $value['lottie'] ) ) {
213 $symbol['symbolData']['data'][ $key2 ]['properties']['lottie'] = $value['lottie'];
214 }
215 if ( isset( $value['svgOuterHtml'] ) ) {
216 $symbol['symbolData']['data'][ $key2 ]['properties']['svgOuterHtml'] = $value['svgOuterHtml'];
217 }
218 if ( isset( $value['tag'] ) ) {
219 $symbol['symbolData']['data'][ $key2 ]['properties']['tag'] = $value['tag'];
220 }
221 if ( isset( $value['type'] ) ) {
222 $symbol['symbolData']['data'][ $key2 ]['properties']['type'] = $value['type'];
223 }
224 if ( isset( $value['isActive'] ) ) {
225 $symbol['symbolData']['data'][ $key2 ]['properties']['isActive'] = $value['isActive'];
226 }
227 if ( isset( $value['preload'] ) ) {
228 $symbol['symbolData']['data'][ $key2 ]['properties']['preload'] = $value['preload'];
229 }
230 if ( isset( $value['dynamicContent'] ) ) {
231 $symbol['symbolData']['data'][ $key2 ]['properties']['dynamicContent'] = $value['dynamicContent'];
232 }
233 if (
234 isset( $symbol['symbolData']['data'][ $key2 ]['properties']['dynamicContent'] ) &&
235 $symbol['symbolData']['data'][ $key2 ]['properties']['dynamicContent']['type'] === 'manual'
236 ) {
237 unset( $symbol['symbolData']['data'][ $key2 ]['properties']['dynamicContent'] );
238 }
239 }
240 }
241 }
242 }
243
244 if ( $html === true ) {
245 $symbol['html'] = self::get_symbol_html_preview( $symbol, $options, $variable_css );
246 }
247 }
248
249 if ( $internal ) {
250 return $symbol;
251 }
252 wp_send_json( $symbol );
253 }
254
255 /**
256 * @deprecated
257 * @see \Kirki\App\Managers\SymbolManager::get_preview_html()
258 */
259 private static function get_symbol_html_preview( $symbol, $options = array(), $variable_css = true ) {
260 if ( ! $symbol['symbolData'] ) {
261 return '';
262 }
263 $symbol_data = $symbol['symbolData'];
264
265 $params = array(
266 'blocks' => $symbol_data['data'],
267 'style_blocks' => $symbol_data['styleBlocks'],
268 'root' => $symbol_data['root'],
269 'post_id' => $symbol['id'],
270 'options' => $options,
271 'get_style' => true,
272 'get_variable' => HelperFunctions::isTruthy( $variable_css ),
273 'should_take_app_script' => false,
274 'prefix' => 'kirki-s' . $symbol['id'],
275 );
276
277 $s = HelperFunctions::get_html_using_preview_script( $params );
278 return $s;
279 }
280
281 /**
282 * Update Symbol data
283 *
284 * @return void wp_send_json.
285 */
286 public static function update() {
287 //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated,WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
288 $symbol_id = HelperFunctions::sanitize_text( isset( $_POST['symbol_id'] ) ? $_POST['symbol_id'] : null );
289 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
290 $post_symbol_data = isset( $_POST['data'] ) ? $_POST['data'] : null;
291 if ( $symbol_id && ! empty( $post_symbol_data ) ) {
292 $data = json_decode( stripslashes( $post_symbol_data ), true );
293 $symbol_data = get_post_meta( $symbol_id, 'kirki', true );
294
295 if ( $symbol_data ) {
296 if ( isset( $data['data'] ) ) {
297 $symbol_data['data'] = $data['data'];
298 }
299 if ( isset( $data['styleBlocks'] ) ) {
300 $symbol_data['styleBlocks'] = $data['styleBlocks'];
301 }
302 if ( isset( $data['customFonts'] ) ) {
303 $symbol_data['customFonts'] = $data['customFonts'];
304 }
305 if ( isset( $data['name'] ) ) {
306 $symbol_data['name'] = $data['name'];
307 }
308 if ( isset( $data['category'] ) ) {
309 $symbol_data['category'] = $data['category'];
310 }
311 if ( isset( $data['root'] ) ) {
312 $symbol_data['root'] = $data['root'];
313 }
314 // if ( isset( $data['conditions'] ) ) {
315 // $symbol_data['conditions'] = $data['conditions'];
316 // }
317
318 $set_as_toggle_success = true;
319 if ( isset( $data['setAs'] ) ) {
320 $symbol_data['setAs'] = $data['setAs'];
321
322 if ( $data['setAs'] != '' ) {
323 $all_symbol = self::fetch_list( true );
324 foreach ( $all_symbol as $key => $value ) {
325 if ( $value['id'] != $symbol_id && isset( $value['symbolData'], $value['symbolData']['setAs'] ) && $value['symbolData']['setAs'] == $data['setAs'] ) {
326 $all_symbol[ $key ]['symbolData']['setAs'] = '';
327 $set_as_toggle_success = update_post_meta( $value['id'], 'kirki', $all_symbol[ $key ]['symbolData'] );
328 }
329 }
330 }
331 }
332
333 if ( $set_as_toggle_success !== true ) {
334 wp_send_json( false );
335 }
336
337 $updated = update_post_meta( $symbol_id, 'kirki', $symbol_data );
338
339 $updated === true && $set_as_toggle_success === true ? wp_send_json( self::get_single_symbol( $symbol_id, true, true ) ) : wp_send_json( false );
340 } else {
341 wp_send_json( false );
342 }
343 }
344 die();
345 }
346
347 /**
348 * Delete a symbol
349 *
350 * @return void
351 */
352 public static function delete() {
353 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
354 $symbol_id = HelperFunctions::sanitize_text( isset( $_POST['symbol_id'] ) ? $_POST['symbol_id'] : null );
355 if ( $symbol_id ) {
356 $post = wp_delete_post( $symbol_id );
357 isset( $post ) ? wp_send_json( true ) : wp_send_json( false );
358 }
359 die();
360 }
361
362 public static function get_pre_built_html_using_url() {
363 $raw_url = isset( $_GET['elementUrl'] ) ? wp_unslash( $_GET['elementUrl'] ) : '';
364
365 if ( empty( $raw_url ) ) {
366 wp_send_json_error( 'Missing elementUrl', 400 );
367 }
368 $allowed_host = wp_parse_url( home_url(), PHP_URL_HOST );
369 $requested = wp_parse_url( $raw_url );
370
371 if (
372 ! $requested ||
373 empty( $requested['host'] ) ||
374 strtolower( $requested['host'] ) !== strtolower( $allowed_host )
375 ) {
376 wp_send_json_error( 'URL not permitted', 403 );
377 }
378
379 $resolved_ip = gethostbyname( $requested['host'] );
380
381 if ( self::is_private_or_loopback_ip( $resolved_ip ) ) {
382 wp_send_json_error( 'URL not permitted', 403 );
383 }
384
385 $safe_url = self::rebuild_url( $requested );
386
387 $response = HelperFunctions::http_get( $safe_url, array(
388 'timeout' => 30,
389 'sslverify' => false,
390 'redirection' => 0,
391 ));
392
393 if ( is_wp_error( $response ) ) {
394 wp_send_json_error( 'Request failed', 502 );
395 }
396
397 $body = wp_remote_retrieve_body( $response );
398 $data = json_decode( $body, true );
399
400
401 $params = array(
402 'blocks' => $data['blocks'],
403 'style_blocks' => $data['styles'],
404 'root' => $data['root'],
405 'post_id' => false,
406 'options' => array(),
407 'get_style' => true,
408 'get_variable' => false,
409 'should_take_app_script' => false,
410 );
411
412 $html = HelperFunctions::get_html_using_preview_script( $params );
413
414 wp_send_json_success( $html );
415 }
416
417 /**
418 * Returns true for any IP that should never be reached from a server-side fetch.
419 * Covers loopback, RFC 1918, link-local (APIPA / cloud metadata), and IPv6 equivalents.
420 */
421 private static function is_private_or_loopback_ip( string $ip ): bool {
422 if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
423 return true;
424 }
425
426 return ! filter_var(
427 $ip,
428 FILTER_VALIDATE_IP,
429 FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
430 );
431 }
432
433
434 /**
435 * Reconstructs a URL from wp_parse_url parts so the raw user string
436 * is never passed directly to the HTTP client.
437 */
438 private static function rebuild_url( array $parts ): string {
439 $scheme = isset( $parts['scheme'] ) && strtolower( $parts['scheme'] ) === 'https' ? 'https' : 'https';
440 $host = $parts['host'];
441 $path = isset( $parts['path'] ) ? $parts['path'] : '/';
442 $query = isset( $parts['query'] ) ? '?' . $parts['query'] : '';
443
444 return "{$scheme}://{$host}{$path}{$query}";
445 }
446 }
447