PluginProbe ʕ •ᴥ•ʔ
Kirki – Freeform Page Builder, Website Builder & Customizer / 6.1.0
Kirki – Freeform Page Builder, Website Builder & Customizer v6.1.0
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 / HelperFunctions.php
kirki / includes Last commit date
API 3 days ago Admin 3 weeks ago Ajax 3 days ago ExportImport 3 days ago FormValidator 2 months ago Frontend 3 days ago Manager 1 week ago API.php 3 days ago Admin.php 2 months ago Ajax.php 3 days ago Apps.php 3 weeks ago ContentManager.php 2 months ago DbQueryUtils.php 2 months ago ElementVisibilityConditions.php 2 months ago Frontend.php 2 months ago HelperFunctions.php 3 days ago KirkiBase.php 3 weeks ago PostsQueryUtils.php 2 months ago Staging.php 3 days ago View.php 1 month ago
HelperFunctions.php
4657 lines
1 <?php
2 /**
3 * Helper class for kirki project
4 *
5 * @package kirki
6 */
7
8 namespace Kirki;
9
10 if (!defined('ABSPATH')) {
11 exit; // Exit if accessed directly.
12 }
13
14 use DateTime;
15 use Kirki\Ajax\Collaboration\Collaboration;
16 use Kirki\Ajax\Page;
17 use Kirki\Ajax\RBAC;
18 use Kirki\Staging;
19 use Kirki\Ajax\Symbol;
20 use Kirki\Ajax\UserData;
21 use Kirki\Ajax\Users;
22 use Kirki\Ajax\WpAdmin;
23 use Kirki\API\ContentManager\ContentManagerHelper;
24 use Kirki\App\Supports\Facades\Page as FacadesPage;
25 use Kirki\App\Supports\FileHandler;
26 use Kirki\Frontend\Preview\DataHelper;
27 use Kirki\Frontend\Preview\Preview;
28 use WP_Post;
29 use WP_Query;
30 use WP_Term;
31 use WP_User;
32
33 /**
34 * HelperFunctions Class
35 */
36 class HelperFunctions
37 {
38
39 public static $custom_sections = [];
40 public static $global_session_id = false;
41 private static $printed_font_family_tracker = array();
42
43 private static $posts_where_filter_params = array();
44 /**
45 * Load assets for Editor
46 *
47 * @param string $for TheFrontend | null.
48 * @return false || array
49 */
50 public static function is_kirki_type_data($post_id = false, $staging_version = false)
51 {
52 if (!$post_id) {
53 $post_id = self::get_post_id_if_possible_from_url();
54 if (!$post_id)
55 return false;
56 }
57
58 if (!self::is_editor_mode_is_kirki($post_id)) {
59 return false;
60 }
61 if ($staging_version) {
62 return Staging::get_page_staging_data($post_id, $staging_version);
63 }
64
65 $kirki_data = get_post_meta($post_id, 'kirki', true);
66 if (!$kirki_data) {
67 $kirki_data = array();
68 $kirki_data['blocks'] = null;
69 }
70
71 $styles = self::get_page_styleblocks($post_id, $staging_version);
72
73 $kirki_data['styles'] = isset($styles) ? $styles : '';
74
75 return $kirki_data;
76 }
77
78 /**
79 * @deprecated
80 * @see \Kirki\App\Utils\PostUtil::get_post_id_from_url()
81 */
82 public static function get_post_id_if_possible_from_url()
83 {
84 if (isset($GLOBALS['wp']->query_vars[KIRKI_CONTENT_MANAGER_PREFIX . '_child_post'])) {
85 return $GLOBALS['wp']->query_vars[KIRKI_CONTENT_MANAGER_PREFIX . '_child_post'];
86 } else if (isset($GLOBALS['wp']->query_vars[KIRKI_CONTENT_MANAGER_PREFIX . '_parent_post']) && false) {//disable content manager archive page logic
87 return $GLOBALS['wp']->query_vars[KIRKI_CONTENT_MANAGER_PREFIX . '_parent_post'];
88 }
89
90 $post_id = get_the_ID();
91 $post_id = self::sanitize_text(isset($_GET['post_id']) ? $_GET['post_id'] : $post_id);
92 $post_id = self::sanitize_text(isset($_POST['post_id']) ? $_POST['post_id'] : $post_id);
93 $post_id = self::sanitize_text(isset($_GET['p']) ? $_GET['p'] : $post_id);
94
95 return (int) $post_id;
96 }
97
98 /**
99 * Get author/user id if possible from url
100 */
101 public static function get_user_id_if_possible_from_url()
102 {
103 if (isset($GLOBALS['wp']->query_vars[KIRKI_CONTENT_MANAGER_PREFIX . '_user'])) {
104 return $GLOBALS['wp']->query_vars[KIRKI_CONTENT_MANAGER_PREFIX . '_user'];
105 }
106
107 $user_id = '';
108 if (isset($GLOBALS['wp']->query_vars['author_name'])) {
109 $user = get_user_by('slug', $GLOBALS['wp']->query_vars['author_name']);
110 if ($user instanceof WP_User) {
111 $user_id = $user->ID;
112 }
113 } else {
114 $user_id = get_current_user_id();
115 }
116
117 return (int) $user_id;
118 }
119
120
121 /**
122 * Get all user roles by access levels
123 * @param array $access_levels access levels => array(KIRKI_ACCESS_LEVELS['FULL_ACCESS'], KIRKI_ACCESS_LEVELS['CONTENT_ACCESS']);
124 *
125 * @return array roles => array ('editor', 'author');
126 */
127 public static function get_all_user_roles_by_access_levels($access_levels = array())
128 {
129 $all_roles = RBAC::get_all_roles();
130 $roles_with_access = RBAC::get_access_level($all_roles);
131
132 $filtered_roles = [];
133
134 $filtered_roles = array_filter($roles_with_access, function ($level) use ($access_levels) {
135 return in_array($level, $access_levels);
136 });
137
138 return array_keys($filtered_roles);
139 }
140
141 /**
142 * Get term or tag id if possible from url
143 */
144 public static function get_term_id_if_possible_from_url()
145 {
146 if (isset($GLOBALS['wp']->query_vars[KIRKI_CONTENT_MANAGER_PREFIX . '_term'])) {
147 return $GLOBALS['wp']->query_vars[KIRKI_CONTENT_MANAGER_PREFIX . '_term'];
148 }
149
150 // http://kirki.test/tag/wp-tag-2/
151 $term_id = get_queried_object_id();
152 $term = null;
153
154 if ($term_id) {
155 $term = get_term($term_id);
156 } else if (isset($GLOBALS['wp']->query_vars['tag'])) {
157 $term = get_term_by('slug', $GLOBALS['wp']->query_vars['tag'], 'post_tag');
158 }
159
160 if ($term instanceof WP_Term) {
161 $term_id = $term->term_id;
162 }
163
164 if (!$term_id) {
165 // get all terms and return the first one
166 $term = get_terms(array(
167 'taxonomy' => 'category',
168 'hide_empty' => false,
169 'number' => 1,
170 ));
171
172 $term_id = isset($term[0], $term[0]->term_id) ? $term[0]->term_id : 1;
173 }
174
175 return (int) $term_id;
176 }
177
178 /**
179 * @deprecated
180 * @see Kirki\App\Services\PageService::save_page_data()
181 * @see \Kirki\App\Services\GlobalDataService::save_styles()
182 */
183 public static function save_kirki_data_to_db($post_id, $page_data, $is_staging = false)
184 {
185 $version_where_saved = false;
186 if ($is_staging) {
187 $data = Staging::save_page_staging_data_to_db($post_id, $page_data);
188 $page_data = $data['page_data'];
189 $version_where_saved = $data['version'];
190 }
191
192 if (isset($page_data['styles'])) {
193 $global_style_blocks_for_collaboration = [];
194 foreach ($page_data['styles'] as $key => $sb) {
195 if ((isset($sb['isDefault']) && $sb['isDefault'] === true) || (isset($sb['isGlobal']) && $sb['isGlobal'] === true)) {
196 if (isset($sb['fromStage'])) {
197 unset($page_data['styles'][$key]['fromStage']);
198 $global_style_blocks_for_collaboration[$key] = $page_data['styles'][$key];
199 } else
200 unset($page_data['styles'][$key]);
201 }
202 }
203 if (count($global_style_blocks_for_collaboration) > 0) {
204 $session_id = self::sanitize_text(isset($_REQUEST['session_id']) ? $_REQUEST['session_id'] : '');
205 if ($session_id && $is_staging === false) {
206 // cause template import also called this method without session_id
207 $data = array(
208 'type' => 'COLLABORATION_UPDATE_GLOBAL_STYLE',
209 'payload' => array('styleBlock' => $global_style_blocks_for_collaboration),
210 );
211 Collaboration::save_action_to_db('global', 0, $data, 1, $session_id);
212 }
213 }
214
215 self::update_page_styleblocks($post_id, $page_data['styles']);
216 unset($page_data['styles']);
217 }
218
219 if (isset($page_data['usedStyles'])) {
220 update_post_meta($post_id, KIRKI_META_NAME_FOR_USED_STYLE_BLOCK_IDS, $page_data['usedStyles']);
221 unset($page_data['usedStyles']);
222 }
223
224 if (isset($page_data['usedStyleIdsRandom'])) {
225 update_post_meta($post_id, KIRKI_META_NAME_FOR_USED_STYLE_BLOCK_IDS . '_random', $page_data['usedStyleIdsRandom']);
226 unset($page_data['usedStyleIdsRandom']);
227 }
228
229 if (isset($page_data['usedFonts'])) {
230 update_post_meta($post_id, KIRKI_META_NAME_FOR_USED_FONT_LIST, $page_data['usedFonts']);
231 unset($page_data['usedFonts']);
232 }
233
234 if (isset($page_data['customFonts'])) {
235 //save others data if isset. this is for template import
236 $custom_fonts = self::get_global_data_using_key(KIRKI_USER_CUSTOM_FONTS_META_KEY);
237 foreach ($page_data['customFonts'] as $key => $cf) {
238 $custom_fonts[$key] = $cf;
239 }
240 self::update_global_data_using_key(KIRKI_USER_CUSTOM_FONTS_META_KEY, $custom_fonts);
241 unset($page_data['customFonts']);
242 }
243
244 if (isset($page_data['viewportList'])) {
245 //save others data if isset. this is for template import
246 $controller_data = self::get_global_data_using_key(KIRKI_USER_CONTROLLER_META_KEY);
247 if (!$controller_data) {
248 $init = array(
249 'active' => 'md',
250 'defaults' => ["md", "tablet", "mobileLandscape", "mobile"],
251 'list' => $page_data['viewportList'],
252 'mdWidth' => 1200,
253 "scale" => 1,
254 "width" => 2484,
255 "zoom" => 1
256 );
257 $controller_data = array('viewport' => $init);
258 } else if (isset($controller_data['viewport'], $controller_data['viewport']['list'])) {
259 $controller_data['viewport']['list'] = $page_data['viewportList'];
260 }
261
262 HelperFunctions::update_global_data_using_key(KIRKI_USER_CONTROLLER_META_KEY, $controller_data);
263 unset($page_data['viewportList']);
264 }
265
266 if (isset($page_data['blocks'])) {
267 update_post_meta($post_id, 'kirki', array('blocks' => $page_data['blocks']));
268 // $data = array(
269 // 'type' => 'COLLABORATION_PAGE_DATA',
270 // 'payload' => array( 'data' => $page_data['blocks'] ),
271 // );
272 //Collaboration::save_action_to_db( 'post', $post_id, $data, 1 );
273 }
274
275
276
277 update_post_meta($post_id, KIRKI_META_NAME_FOR_POST_EDITOR_MODE, 'kirki');
278 return $version_where_saved;
279 }
280
281 /**
282 *
283 */
284 function abc()
285 {
286
287 }
288
289 /**
290 * This function will return page style blocks from option meta and post meta
291 * post meta for migration and option meta for global style block
292 *
293 * @param int $post_id post id.
294 * @return object
295 *
296 * @todo:
297 *
298 * @deprecated
299 * @see Kirki\App\Managers\PageManager::get_page_styleblocks()
300 */
301 public static function get_page_styleblocks($post_id, $stage_version = false)
302 {
303 return FacadesPage::get_page_styleblocks($post_id, $stage_version);
304
305 // $random_style_blocks = get_post_meta($post_id, KIRKI_GLOBAL_STYLE_BLOCK_META_KEY . '_random', true);
306 // $global_style_blocks = self::get_global_data_using_key(KIRKI_GLOBAL_STYLE_BLOCK_META_KEY);
307
308 // $random_style_blocks = self::fix_duplicate_class_name_from_random_sbs($random_style_blocks, $global_style_blocks);
309
310 // $merged_style_blocks = array();
311 // if ($random_style_blocks) {
312 // $merged_style_blocks = array_merge($merged_style_blocks, $random_style_blocks);
313 // }
314 // if ($global_style_blocks) {
315 // $merged_style_blocks = array_merge($merged_style_blocks, $global_style_blocks);
316 // }
317
318 // $published_version = Staging::get_published_stage_version($post_id);
319 // if ($published_version && $stage_version !== $published_version) {
320 // $staging_style_blocks = array();
321 // $meta_key = Staging::get_staged_meta_name(KIRKI_GLOBAL_STYLE_BLOCK_META_KEY, $post_id, $stage_version);
322 // $stage_style = get_post_meta($post_id, $meta_key, true);
323 // if ($stage_style)
324 // $staging_style_blocks = array_merge($staging_style_blocks, $stage_style);
325
326 // $meta_key = $meta_key . '_random';
327 // $stage_style = get_post_meta($post_id, $meta_key, true);
328 // if ($stage_style)
329 // $staging_style_blocks = array_merge($staging_style_blocks, $stage_style);
330 // if ($stage_version)
331 // $merged_style_blocks = self::merge_style_blocks($merged_style_blocks, $staging_style_blocks);
332 // else
333 // $merged_style_blocks = self::merge_style_blocks($staging_style_blocks, $merged_style_blocks);
334 // }
335
336 // return $merged_style_blocks;
337 }
338
339 /**
340 * @deprecated
341 * @see Kirki\App\Managers\PageManager::merge_style_blocks()
342 */
343 public static function merge_style_blocks($a, $b)
344 {
345 $names_in_a = [];
346 foreach ($a as $val) {
347 if (!empty($val['name']) && is_string($val['name'])) {
348 $names_in_a[strtolower($val['name'])] = true;
349 }
350 }
351
352 $names_in_b = [];
353 foreach ($b as $val) {
354 if (!empty($val['name']) && is_string($val['name'])) {
355 $names_in_b[strtolower($val['name'])] = true;
356 }
357 }
358
359 foreach ($b as $id_b => &$value_b) {
360 if (empty($value_b['name']) || !is_string($value_b['name'])) {
361 continue;
362 }
363
364 $b_name = strtolower($value_b['name']);
365
366 // If same ID exists in A, remove it first (old behavior)
367 if (isset($a[$id_b])) {
368 unset($a[$id_b]);
369 if (isset($names_in_a[$b_name])) {
370 unset($names_in_a[$b_name]);
371 }
372 }
373
374 // If name already exists in A, make it unique
375 if (isset($names_in_a[$b_name])) {
376 $i = 1;
377 while (isset($names_in_a[$b_name . '_' . $i]) || isset($names_in_b[$b_name . '_' . $i])) {
378 $i++;
379 }
380 $new_name = $value_b['name'] . '_' . $i;
381
382 foreach ($b as &$v) {
383 if (isset($v['name']) && is_array($v['name'])) {
384 $v['name'] = array_map(fn($item) => $item === $value_b['name'] ? $new_name : $item, $v['name']);
385 }
386 }
387
388 $value_b['name'] = $new_name;
389 unset($names_in_b[$b_name]);
390 $names_in_b[strtolower($new_name)] = true;
391 }
392 }
393 unset($value_b);
394
395 // Use array_merge to keep old semantics
396 return array_merge($a, $b);
397 }
398
399
400 /**
401 * @deprecated
402 * @see Kirki\App\Managers\PageManager::resolve_duplicate_current_style_block_names()
403 */
404 private static function fix_duplicate_class_name_from_random_sbs($random_style_blocks, $global_style_blocks)
405 {
406 $global_class_names = [];
407 $random_class_names = [];
408 if ($global_style_blocks) {
409 foreach ($global_style_blocks as $key => $value) {
410 if (isset($value['name']) && is_string($value['name'])) {
411 $global_class_names[self::get_class_name_from_string($value['name'])] = true;
412 }
413 }
414 }
415 if ($random_style_blocks) {
416 foreach ($random_style_blocks as $key => $value) {
417 if (isset($value['name']) && is_string($value['name'])) {
418 $random_class_names[self::get_class_name_from_string($value['name'])] = true;
419 }
420 }
421 }
422
423 $class_match = [];
424 foreach ($random_class_names as $key => $value) {
425 if (isset($global_class_names[$key])) {
426 $class_match[$key] = true;
427 }
428 }
429
430 $class_match = self::check_or_generate_new_class_names($class_match, $global_class_names, $random_class_names);
431
432 if (count($class_match) > 0) {
433 foreach ($random_style_blocks as $key => $value) {
434 if (isset($value['name']) && is_string($value['name'])) {
435 $class_name = self::get_class_name_from_string($value['name']);
436 if (isset($class_match[$class_name])) {
437 $random_style_blocks[$key]['name'] = $class_match[$class_name];
438 }
439 } else if (isset($value['name']) && is_array($value['name'])) {
440 //array
441 foreach ($value['name'] as $key2 => $v2) {
442 $class_name = self::get_class_name_from_string($v2);
443 if (isset($class_match[$class_name])) {
444 $random_style_blocks[$key]['name'][$key2] = $class_match[$class_name];
445 }
446 }
447 }
448 }
449 }
450 return $random_style_blocks;
451 }
452
453 /**
454 * @deprecated
455 * @see Kirki\App\Managers\PageManager::generate_unique_style_block_name()
456 */
457 private static function check_or_generate_new_class_names($class_match, $global_class_names, $random_class_names)
458 {
459 foreach ($class_match as $key => $value) {
460 $temp_class = $key;
461 $found = true;
462 while ($found) {
463 if (isset($global_class_names[$temp_class]) || isset($random_class_names[$temp_class])) {
464 $temp_class = $temp_class . '-copy';
465 } else {
466 $found = false;
467 }
468 }
469 $class_match[$key] = $temp_class;
470 }
471 return $class_match;
472 }
473
474 /**
475 * @deprecated
476 * @see Kirki\App\Managers\PageManager::normalize_style_block_name()
477 */
478 public static function get_class_name_from_string($s)
479 {
480 $s = strtolower(str_replace(' ', '-', $s));
481 return $s;
482 }
483
484 public static function get_selector_from_sb_name($name)
485 {
486 if (!$name)
487 return '';
488 $class_name = '';
489 if (is_string($name)) {
490 $class_name = '.' . self::get_class_name_from_string($name);
491 } else {
492 foreach ($name as $key2 => $cn) {
493 $class_name .= '.' . self::get_class_name_from_string($cn);
494 }
495 }
496 return $class_name;
497 }
498
499 /**
500 * This function will update page style blocks into option meta and post meta
501 * post meta for migration and option meta for global style block
502 *
503 * @param int $post_id post id.
504 * @param object $style_blocks styleblocks.
505 *
506 * @deprecated the method is not used anymore. handle separately in GlobalDataManager and PageManager
507 */
508 public static function update_page_styleblocks($post_id, $style_blocks)
509 {
510 $prev_style_blocks = self::get_page_styleblocks($post_id);
511 $style_blocks = array_merge($prev_style_blocks, $style_blocks);
512
513 $global_style_blocks = array();
514 foreach ($style_blocks as $key => $sb) {
515 if ((isset($sb['isDefault']) && $sb['isDefault'] === true) || (isset($sb['isGlobal']) && $sb['isGlobal'] === true)) {
516 $global_style_blocks[$sb['id']] = $sb;
517 unset($style_blocks[$key]);
518 }
519 }
520
521 self::save_global_style_blocks($global_style_blocks);
522 self::save_random_style_blocks($post_id, $style_blocks);
523 }
524
525 /**
526 * Save global style blocks in option table. Also save collaboration data.
527 *
528 * @param array $style //take styleblocs if isDefault and isGlobal key is true.
529 * @return void
530 * @deprecated
531 * @see Kirki\App\Managers\GlobalDataManager::update_deprecated_global_style_blocks()
532 */
533 public static function save_global_style_blocks($style)
534 {
535 // $session_id = self::sanitize_text(isset($_REQUEST['session_id']) ? $_REQUEST['session_id'] : '');
536 self::update_global_data_using_key(KIRKI_GLOBAL_STYLE_BLOCK_META_KEY, $style);
537
538 // if($session_id){
539 // // cause template import also called this method without session_id
540 // $data = array(
541 // 'type' => 'COLLABORATION_UPDATE_GLOBAL_STYLE',
542 // 'payload' => array( 'styleBlock' => $style ),
543 // );
544 // Collaboration::save_action_to_db( 'global', 0, $data, 1, $session_id);
545 // }
546 }
547
548 /**
549 * Save post related random style blocks in option table. Also save collaboration data.
550 *
551 * @param array $post_id //current post id.
552 * @param array $style //take styleblocs if not isDefault and isGlobal key is true.
553 * @return void
554 * @deprecated
555 * @see Kirki\App\Managers\PageManager::save_style_blocks()
556 */
557 public static function save_random_style_blocks($post_id, $style)
558 {
559 update_post_meta($post_id, KIRKI_GLOBAL_STYLE_BLOCK_META_KEY . '_random', $style);
560 // $data = array(
561 // 'type' => 'COLLABORATION_UPDATE_GLOBAL_STYLE',
562 // 'payload' => array( 'styleBlock' => $style ),
563 // );
564 //Collaboration::save_action_to_db( 'post', $post_id, $data, 1 );
565 }
566
567 /**
568 * Save staged style blocks for a specific post and staged meta key.
569 *
570 * @param int $post_id Post ID.
571 * @param string $meta_key Staged meta key (can be normal or random).
572 * @param array $styles Styles array to save.
573 *
574 * @deprecated
575 * @see \Kirki\App\Managers\PageManager::save_deprecated_global_style_blocks()
576 * @see \Kirki\App\Managers\PageManager::save_style_blocks()
577 */
578 public static function save_staged_style_blocks($post_id, $meta_key, $styles)
579 {
580 update_post_meta($post_id, $meta_key, $styles);
581 // $data = array(
582 // 'type' => 'COLLABORATION_UPDATE_GLOBAL_STYLE',
583 // 'payload' => array('styleBlock' => $styles),
584 // );
585 // Collaboration::save_action_to_db('post', $post_id, $data, 1);
586 }
587
588 /**
589 * No module import this method right now
590 *
591 * @return array
592 */
593 public static function get_custom_code_block_element()
594 {
595 return array(
596 'name' => 'custom-code',
597 'title' => 'Code',
598 'visibility' => true,
599 'properties' => array(
600 'tag' => 'div',
601 'content' => '',
602 'data-type' => 'code',
603 ),
604 'styleIds' => array(),
605 'className' => '',
606 'id' => 'kirki' . uniqid(),
607 'parentId' => 'body',
608 );
609 }
610 /**
611 * Get current editor mode is kirki or others
612 *
613 * @param int $post_id post id.
614 * @return bool true if kirki.
615 * @deprecated
616 * @see Kirki\App\Managers\PageManager::is_kirki_editor_mode()
617 */
618 public static function is_editor_mode_is_kirki($post_id)
619 {
620 $editor_mode = get_post_meta($post_id, KIRKI_META_NAME_FOR_POST_EDITOR_MODE, true);
621 if ('kirki' === $editor_mode) {
622 return true;
623 }
624 return false;
625 }
626
627 /**
628 * Get post url arr from post id
629 * preview_url, iframe_url, post_url
630 *
631 * @param int $post_id post id.
632 * @return array
633 *
634 * @deprecated
635 * @see \Kirki\App\Supports\PageUrl::class
636 */
637 public static function get_post_url_arr_from_post_id($post_id, $options = array())
638 {
639 $post_perma_link = self::get_page_perma_url($post_id);
640
641 $obj = ['post_url' => $post_perma_link, 'post_id' => $post_id];
642 if (isset($options['ajax_url']) && $options['ajax_url']) {
643 $protocol = strpos(home_url(), 'https://') !== false ? 'https' : 'http';
644 $obj['ajax_url'] = admin_url('admin-ajax.php', $protocol);
645 }
646
647 if (isset($options['preview_url']) && $options['preview_url']) {
648 $preview_url = self::get_page_preview_url($post_id);
649 $obj['preview_url'] = $preview_url;
650 }
651
652 if (isset($options['editor_url']) && $options['editor_url']) {
653 $obj['editor_url'] = add_query_arg(
654 array(
655 'action' => KIRKI_EDITOR_ACTION,
656 ),
657 $post_perma_link
658 );
659
660 if (HelperFunctions::is_api_call_from_editor_preview() && HelperFunctions::is_api_header_post_editor_preview_token_valid()) {
661 $headers = self::getallheaders();
662 $obj['editor_url'] = add_query_arg(
663 array(
664 'editor-preview-token' => isset($headers['Editor-Preview-Token']) ? $headers['Editor-Preview-Token'] : null,
665 ),
666 $obj['editor_url']
667 );
668 }
669 }
670 if (isset($options['iframe_url']) && $options['iframe_url']) {
671 $iframe_url_params = array(
672 'action' => KIRKI_EDITOR_ACTION,
673 'load_for' => 'kirki-iframe',
674 'post_id' => $post_id,
675 );
676 if (isset($_GET['editor-preview-token'])) {
677 $iframe_url_params['editor-preview-token'] = self::sanitize_text($_GET['editor-preview-token']);
678 }
679 $obj['iframe_url'] = add_query_arg(
680 $iframe_url_params,
681 $post_perma_link
682 );
683 }
684
685 if (isset($options['nonce']) && $options['nonce']) {
686 $obj['nonce'] = wp_create_nonce('wp_rest');
687 }
688
689 if (isset($options['editor_preview_token']) && $options['editor_preview_token']) {
690 $obj['editor_preview_token'] = isset($_GET['editor-preview-token']) ? self::sanitize_text($_GET['editor-preview-token']) : false;
691 }
692
693 if (isset($options['site_url']) && $options['site_url']) {
694 $obj['site_url'] = get_site_url();
695 }
696
697 if (isset($options['admin_url']) && $options['admin_url']) {
698 $obj['admin_url'] = get_admin_url();
699 }
700
701 if (isset($options['core_plugin_url']) && $options['core_plugin_url']) {
702 $obj['core_plugin_url'] = KIRKI_CORE_PLUGIN_URL;
703 }
704
705 if (isset($options['rest_url']) && $options['rest_url']) {
706 try {
707 $rest_url = rest_url();
708 $obj['rest_url'] = $rest_url;
709 } catch (\Throwable $th) {
710 $obj['rest_url'] = '';
711 }
712 }
713
714 return $obj;
715 }
716
717 /**
718 * @deprecated
719 * @see \Kirki\App\Supports\PageUrl::get_preview_url()
720 */
721 private static function get_page_preview_url($post_id)
722 {
723 $post = get_post($post_id);
724 if ($post && $post->post_type === 'kirki_template') {
725 $conditions = get_post_meta($post->ID, 'kirki_template_conditions', true);
726
727 $d = self::get_collection_items_from_conditions($conditions);
728 if ($d['type'] === 'post' && count($d['data']) > 0) {
729 return self::get_page_perma_url($d['data'][0]['ID']);
730 }
731 if ($d['type'] === 'user' && count($d['data']) > 0) {
732 return get_author_posts_url($d['data'][0]['ID']);
733 }
734 if ($d['type'] === 'term' && count($d['data']) > 0) {
735 return get_term_link($d['data'][0]['ID']);
736 }
737 }
738 return self::get_page_perma_url($post_id);
739 }
740
741 /**
742 * @deprecated
743 * @see \Kirki\App\Supports\PageUrl::get_page_permalink()
744 */
745 private static function get_page_perma_url($post_id)
746 {
747 $post_perma_link = get_permalink($post_id);
748 $protocol = strpos(home_url(), 'https://') !== false ? 'https' : 'http';
749 if ($protocol === 'https') {
750 $post_perma_link = str_replace('http://', 'https://', $post_perma_link);
751 } else {
752 $post_perma_link = str_replace('https://', 'http://', $post_perma_link);
753 }
754
755 return $post_perma_link;
756 }
757
758 /**
759 * @deprecated
760 * @see \Kirki\App\Supports\CollectionItem::get_items_from_condition()
761 */
762 public static function get_collection_items_from_conditions($conditions, $query = '')
763 {
764 $data = [];
765 $type = 'post';
766 $post_type = 'post';
767 $role = '';
768
769 if (is_array($conditions) && count($conditions) > 0) {
770 if (isset($conditions[0]['type'])) {
771 $type = $conditions[0]['type'];
772
773 if ($type === 'post') {
774 $post_type = $conditions[0]['post_type'];
775
776 // if the conditions has from key then it is term. then it will be term type.
777 if (isset($conditions[0]['from']) && $conditions[0]['from'] === 'term') {
778 $type = 'term';
779 }
780 }
781 if ($type === 'user') {
782 $role = $conditions[0]['to'];
783 }
784 } else {
785 //legacy support
786 $post_type = $conditions[0]['category'];
787 }
788 }
789
790
791 $numberposts = 20;
792 $post_status = array('publish', 'draft', 'future');
793
794 if ($type === 'post' && HelperFunctions::user_has_post_edit_access()) { // type will be wordpress post type
795 $arg = array(
796 'post_type' => $post_type,
797 'post_status' => $post_status,
798 'numberposts' => $numberposts,
799 'orderby' => 'ID',
800 'order' => 'DESC',
801 );
802 if ($query) {
803 $arg['s'] = $query;
804 }
805 $posts = get_posts($arg);
806 foreach ($posts as $key => $post) {
807 $data[] = array(
808 'ID' => $post->ID,
809 'title' => $post->post_title,
810 );
811 }
812 }
813
814 if ($type === 'user' && HelperFunctions::user_has_post_edit_access()) {
815 // get all users
816 $arg = array(
817 'role' => $role === '*' ? '' : $role,
818 'number' => $numberposts,
819 'orderby' => 'ID',
820 'order' => 'DESC',
821 );
822
823 if ($query) {
824 $arg['search'] = '*' . $query . '*';
825 }
826
827 $users = get_users($arg);
828 foreach ($users as $key => $user) {
829 $data[] = array(
830 'ID' => $user->ID,
831 'title' => $user->display_name,
832 );
833 }
834 }
835
836 if ($type === 'term' && HelperFunctions::user_has_post_edit_access()) {
837 // conditions
838 $taxonomy = [];
839
840 foreach ($conditions as $key => $condition) {
841 if ($condition['from'] === 'term') {
842 $taxonomy[] = $condition['where'];
843 }
844 }
845
846 $arg = array(
847 'taxonomy' => $taxonomy,
848 'number' => $numberposts,
849 'orderby' => 'ID',
850 'order' => 'DESC',
851 );
852
853 if ($query) {
854 $arg['search'] = $query;
855 }
856
857 $terms = get_terms($arg);
858
859 if (!is_wp_error($terms) && is_array($terms)) {
860 foreach ($terms as $term) {
861 // Handle both object and array cases safely
862 $term_id = is_object($term) ? $term->term_id : ($term['term_id'] ?? null);
863 $term_name = is_object($term) ? $term->name : ($term['name'] ?? null);
864
865 $data[] = [
866 'ID' => $term_id,
867 'title' => $term_name,
868 ];
869 }
870 }
871 }
872
873 return ['data' => $data, 'type' => $type];
874 }
875 /**
876 * Get post content from content value. like => id, title, description, content
877 *
878 * @param string $content_value for post dynamic content.
879 * @param object $post post object.
880 *
881 * @return string
882 */
883 public static function get_post_dynamic_content($content_value, $post = null, $meta_name = '', $dynamic_options = [])
884 {
885 if (isset($post) && !empty($post)) {
886 $post_id = $post->ID;
887 }
888
889 if (empty($post_id)) {
890 $post_id = self::get_post_id_if_possible_from_url();
891 }
892
893 $content = null;
894
895 switch ($content_value) {
896 case 'post_id': {
897 $content = $post_id;
898 break;
899 }
900
901 case 'post_title': {
902 $content = get_the_title($post_id);
903 break;
904 }
905
906 case 'post_excerpt': {
907
908 // Excerpt length global variable is only for kirki editor but not for the frontend.
909 if (isset($GLOBALS['kirki_post_excerpt_length']) && $GLOBALS['kirki_post_excerpt_length'] > 0) {
910 $content = wp_trim_words(get_the_excerpt($post_id), $GLOBALS['kirki_post_excerpt_length'], '[...]');
911 } else {
912 $content = get_the_excerpt($post_id);
913 }
914 break;
915 }
916
917 case 'post_author': {
918 $post = get_post($post_id);
919 if (!$post)
920 return "";
921 $content = get_the_author_meta('display_name', $post->post_author);
922 break;
923 }
924
925 case 'post_date': {
926 $content = get_the_date('', $post_id);
927 if (isset($dynamic_options['format'])) {
928 $content = HelperFunctions::format_date($content, $dynamic_options['format']);
929 }
930 break;
931 }
932
933 case 'post_time': {
934 $content = get_the_time('', $post_id);
935 if (isset($dynamic_options['timeFormat'])) {
936 $content = HelperFunctions::convert_time_format($content, $dynamic_options['timeFormat']);
937 }
938 break;
939 }
940
941 case 'post_content': {
942 $content = self::retrieve_post_content($post_id);
943 break;
944 }
945
946 case 'post_status': {
947 $content = get_post_status($post_id);
948 break;
949 }
950
951 case 'featured_image': {
952 $content = array(
953 'wp_attachment_id' => get_post_thumbnail_id($post_id),
954 'src' => get_the_post_thumbnail_url($post_id)
955 );
956 break;
957 }
958
959 case 'site_name': {
960 $content = get_bloginfo('name');
961 break;
962 }
963 case 'site_description': {
964 $content = get_bloginfo('description');
965 break;
966 }
967 case 'site_url': {
968 $content = get_site_url();
969 break;
970 }
971
972 case 'site_logo': {
973 $content = '';
974
975 // Try site icon first
976 $site_icon_id = get_option('site_icon');
977 if ($site_icon_id) {
978 $content = wp_get_attachment_url($site_icon_id);
979 }
980
981 // If no site icon, try get_site_icon_url()
982 if (!$content) {
983 $content = get_site_icon_url(512);
984 }
985
986 // If still nothing, try custom logo
987 if (!$content) {
988 $custom_logo_id = get_theme_mod('custom_logo');
989 if ($custom_logo_id) {
990 $imgs = wp_get_attachment_image_src($custom_logo_id, 'full');
991 if ($imgs && isset($imgs[0])) {
992 $content = $imgs[0];
993 }
994 }
995 }
996
997 break;
998 }
999
1000 case 'author_profile_picture': {
1001 $post = get_post($post_id);
1002
1003 if (!empty($post)) {
1004 $post_author = $post->post_author;
1005 $content = get_avatar_url($post_author);
1006 } else {
1007 $content = 'Something wrong!';
1008 }
1009
1010 break;
1011 }
1012
1013 case 'user_profile_picture': {
1014 $content = get_avatar_url(get_current_user_id());
1015 break;
1016 }
1017
1018 case 'post_page_link': {
1019 $url = \get_permalink($post_id);
1020 $content = !empty($url) ? $url : '';
1021 break;
1022 }
1023
1024 case 'author_posts_page_link': {
1025 $post = \get_post($post_id);
1026 $url = \get_author_posts_url($post->post_author);
1027 $content = !empty($url) ? $url : '';
1028 break;
1029 }
1030
1031 case 'post_meta': {
1032 if (!empty($meta_name)) {
1033 $meta = get_post_meta($post_id, $meta_name, true);
1034
1035 // For now, only string is supported!
1036 if (is_string($meta)) {
1037 $content = $meta;
1038 }
1039 }
1040
1041 break;
1042 }
1043
1044 default: {
1045 $post = get_post($post_id);
1046 if (isset($post) && 0 !== strpos(KIRKI_CONTENT_MANAGER_PREFIX, $post->post_type)) {
1047 $meta_key = ContentManagerHelper::get_child_post_meta_key_using_field_id($post->post_parent, $content_value);
1048 $content = get_post_meta($post->ID, $meta_key, true);
1049 $fields = ContentManagerHelper::get_post_type_custom_field_keys($post->post_parent);
1050
1051 if (!$content && isset($fields[$content_value], $fields[$content_value]['default_value'])) {
1052 $content = $fields[$content_value]['default_value'];
1053 }
1054
1055 if (isset($fields[$content_value]) && $fields[$content_value]['type'] === 'date') {
1056 $content = self::format_date($content, $fields[$content_value]['default_format']); //TODO: need to check with editor format
1057 }
1058 if (isset($fields[$content_value]['type']) && $fields[$content_value]['type'] === 'image') {
1059 $content = array(
1060 'wp_attachment_id' => $content['id'] ?? '',
1061 'src' => $content['url'] ?? '',
1062 );
1063 }
1064 if (isset($fields[$content_value]['type']) && $fields[$content_value]['type'] === 'time') {
1065 $time = "";
1066
1067 if (isset($fields[$content_value], $fields[$content_value]['default_value']) && $fields[$content_value]['default_value']) {
1068 $default_time = $fields[$content_value]['default_value'];
1069
1070 $value = isset($default_time['value']) ? $default_time['value'] : '00:00';
1071 $unit = isset($default_time['unit']) ? strtolower($default_time['unit']) : 'am';
1072
1073 $time = $value . ' ' . $unit;
1074 }
1075
1076 $content = $content ? $content['value'] . ' ' . $content['unit'] : $time;
1077
1078 if (isset($dynamic_options['timeFormat']) && $dynamic_options['timeFormat']) {
1079 $content = HelperFunctions::convert_time_format($content, $dynamic_options['timeFormat']);
1080 }
1081 }
1082
1083 } else {
1084 $content = 'Not Implemented';
1085 }
1086
1087 break;
1088 }
1089 }
1090
1091 return $content ? $content : '';
1092 }
1093
1094 /**
1095 * The function `get_user_dynamic_content` retrieves specific dynamic content related to a user based
1096 * on the provided content value.
1097 */
1098 public static function get_user_dynamic_content($content_value, $user_id = null, $meta_name = '', $dynamic_options = [])
1099 {
1100 $content = '';
1101
1102 // Get the user by ID
1103 $user = get_user_by('id', $user_id);
1104
1105 // fall back to the current user
1106 if (empty($user)) {
1107 $user = get_user_by('id', get_current_user_id());
1108 }
1109
1110
1111 if (empty($user)) {
1112 return $content;
1113 }
1114
1115 // Switch statement to handle dynamic content based on the content_value
1116 switch ($content_value) {
1117 case 'display_name':
1118 return $user->display_name;
1119
1120 case 'user_email':
1121 return $user->user_email;
1122
1123 case 'user_nicename':
1124 return $user->user_nicename;
1125
1126 case 'registered_date': {
1127 $date = $user->user_registered;
1128
1129 if (isset($dynamic_options['format'])) {
1130 return HelperFunctions::format_date($date, $dynamic_options['format']);
1131 }
1132
1133 $date = new DateTime($date);
1134
1135 return $date->format('F j, Y');
1136 }
1137
1138 case 'registered_time': {
1139 $date = new DateTime($user->user_registered);
1140 return $date->format('H:i:a');
1141 }
1142
1143 case 'user_url':
1144 return get_author_posts_url($user->ID);
1145
1146 case 'profile_image':
1147 return get_avatar_url($user->ID);
1148
1149 case 'user_meta': {
1150 if (!empty($meta_name)) {
1151 $meta = get_user_meta($user->ID, $meta_name, true);
1152
1153 if (is_string($meta)) {
1154 return $meta;
1155 }
1156 return '';
1157 }
1158 }
1159
1160 case 'initials': {
1161 $first_name = isset($user->first_name) ? $user->first_name : '';
1162 $last_name = isset($user->last_name) ? $user->last_name : '';
1163
1164 $initials = '';
1165 if ($first_name) {
1166 $initials .= strtoupper(substr($first_name, 0, 1));
1167 }
1168
1169 if ($last_name) {
1170 $initials .= strtoupper(substr($last_name, 0, 1));
1171 }
1172
1173 // if initials are lenght 1 or empty, then the first two letters of the username
1174 if (empty($initials) || strlen($initials) < 2) {
1175 $username = isset($user->user_login) ? $user->user_login : '';
1176 $initials = strtoupper(substr($username, 0, 2));
1177 }
1178
1179 return $initials;
1180 }
1181
1182 default:
1183 return '';
1184 }
1185 }
1186
1187 private static function get_value($data, $key)
1188 {
1189 if (is_array($data)) {
1190 return $data[$key] ?? '';
1191 }
1192
1193 if (is_object($data)) {
1194 return $data->$key ?? '';
1195 }
1196
1197 return '';
1198 }
1199
1200 public static function get_term_dynamic_content($content_value, $term_id = null, $meta_name = '')
1201 {
1202 $term = get_term($term_id);
1203
1204 if (empty($term)) {
1205 return '';
1206 }
1207
1208 switch ($content_value) {
1209 case 'name':
1210 return self::get_value($term, 'name');
1211
1212 case 'description':
1213 return self::get_value($term, 'description');
1214
1215 case 'slug':
1216 return self::get_value($term, 'slug');
1217
1218 case 'count':
1219 return self::get_value($term, 'count');
1220
1221 case 'meta':
1222 if (!empty($meta_name)) {
1223 $term_id = self::get_value($term, 'term_id');
1224 $meta = get_term_meta($term_id, $meta_name, true);
1225
1226 return is_scalar($meta) ? (string) $meta : '';
1227 }
1228 return '';
1229
1230 default:
1231 return '';
1232 }
1233 }
1234
1235 public static function retrieve_post_content($post_id)
1236 {
1237 $content = apply_filters('the_content', get_the_content(null, false, $post_id));
1238
1239 $load_for = HelperFunctions::sanitize_text(isset($_GET['load_for']) ? $_GET['load_for'] : '');
1240
1241 if ($load_for !== 'kirki-iframe' && $kirki_data = HelperFunctions::is_kirki_type_data($post_id)) {
1242 $params = array(
1243 'blocks' => $kirki_data['blocks'],
1244 'style_blocks' => $kirki_data['styles'],
1245 'root' => 'root',
1246 'post_id' => $post_id,
1247 );
1248 $content = apply_filters('the_content', HelperFunctions::get_html_using_preview_script($params));
1249 }
1250
1251 return $content;
1252 }
1253
1254 /**
1255 * This methos is for if Theme enque some style and css then it will remove those styel and css codes.
1256 *
1257 * @return void
1258 */
1259 public static function remove_theme_style()
1260 {
1261 $theme = wp_get_theme();
1262 $parent_style = $theme->stylesheet . '-style';
1263 wp_dequeue_style($parent_style);
1264 wp_deregister_style($parent_style);
1265 wp_dequeue_style($parent_style . '-css');
1266 wp_deregister_style($parent_style . '-css');
1267 }
1268
1269 public static function dequeue_all_except_my_plugin()
1270 {
1271
1272 global $wp_scripts, $wp_styles, $kirki_editor_assets;
1273
1274 foreach ($wp_scripts->queue as $handle) {
1275
1276 // Keep WordPress media scripts
1277 if (
1278 str_starts_with($handle, 'media') ||
1279 str_starts_with($handle, 'wp-media') ||
1280 in_array($handle, ['underscore', 'backbone', 'jquery', 'wp-util'])
1281 ) {
1282 continue;
1283 }
1284
1285 wp_dequeue_script($handle);
1286 }
1287
1288 foreach ($wp_styles->queue as $handle) {
1289
1290 // Keep media related styles
1291 if (
1292 str_starts_with($handle, 'media') ||
1293 in_array($handle, ['buttons', 'dashicons', 'imgareaselect'])
1294 ) {
1295 continue;
1296 }
1297
1298 wp_dequeue_style($handle);
1299 }
1300
1301 if (!empty($kirki_editor_assets['scripts'])) {
1302 foreach ($kirki_editor_assets['scripts'] as $script_handle) {
1303 wp_enqueue_script($script_handle);
1304 }
1305 }
1306
1307 if (!empty($kirki_editor_assets['styles'])) {
1308 foreach ($kirki_editor_assets['styles'] as $style_handle) {
1309 wp_enqueue_style($style_handle);
1310 }
1311 }
1312 }
1313
1314 /**
1315 * Generate html using Preview script.
1316 *
1317 * @param array $data blocks.
1318 * @param array $style_blocks style_blocks.
1319 * @param string $root data root.
1320 * @param int $id if need prefix like symbol or popup post_id.
1321 * @return string the html string.
1322 */
1323 public static function get_html_using_preview_script(array $params = [])
1324 {
1325
1326 $blocks = $params['blocks'] ?? null;
1327 $style_blocks = $params['style_blocks'] ?? null;
1328 $root = $params['root'] ?? null;
1329 $options = $params['options'] ?? [];
1330 $post_id = $params['post_id'] ?? null;
1331 $get_style = $params['get_style'] ?? true;
1332 $get_variable = $params['get_variable'] ?? true;
1333 $get_fonts = $params['get_fonts'] ?? true;
1334 $should_take_app_script = $params['should_take_app_script'] ?? true;
1335 $prefix = $params['prefix'] ?? false;
1336 $get_all_style_forcefully_if_get_style_true = $params['get_all_style_forcefully_if_get_style_true'] ?? false;
1337
1338 if ($blocks) {
1339 $options['search_related_collection_ids'] = isset($params['search_related_collection_ids']) ? $params['search_related_collection_ids'] : self::collect_search_related_collection_ids($blocks);
1340 }
1341
1342 //set initial context data start
1343 if (!isset($options['post'])) {
1344 $post = get_post(get_the_ID());
1345 if ($post) {
1346 $options['post'] = $post;
1347 $options['itemType'] = 'post';
1348 }
1349 }
1350 if (!isset($options['user'])) {
1351 $user = get_user_by('id', get_current_user_id());
1352 if ($user) {
1353 $options['user'] = Users::get_format_single_user_data($user);
1354 }
1355 }
1356 //set initial context data end
1357
1358 $preview = new Preview($blocks, $style_blocks, $root, $post_id, $prefix);
1359 $html = $preview->getHtml($options);// this method need to call first cause after that only used style block array construct.
1360 $only_used_style_blocks = $get_all_style_forcefully_if_get_style_true ? $style_blocks : $preview->get_only_used_style_blocks();
1361 $s = '';
1362 if ($get_fonts) {
1363 $s .= $preview->getCustomFontsLinks();
1364 }
1365
1366 if ($get_style) {
1367 //style will be false when it calls from collection single item. only first item will generate style. others item will be same.
1368 $s .= $preview->getStyleTag($only_used_style_blocks);
1369 }
1370
1371 $s .= $preview->get_interaction_set_as_initial_css();
1372
1373
1374
1375 $s .= $html;
1376 $s .= $preview->getScriptTag($should_take_app_script);
1377 return $s;
1378 }
1379
1380 private static function collect_search_related_collection_ids($data)
1381 {
1382 $result = array();
1383 foreach ($data as $item) {
1384 if (
1385 isset($item['properties']['dynamicContent']['related']) &&
1386 $item['properties']['dynamicContent']['related'] === true &&
1387 !empty($item['properties']['dynamicContent']['relatedCollection'])
1388 ) {
1389 $result[$item['properties']['dynamicContent']['relatedCollection']] = true;
1390 }
1391 }
1392 return $result;
1393 }
1394
1395 public static function get_custom_fonts_tags()
1396 {
1397 $custom_fonts = HelperFunctions::get_global_data_using_key(KIRKI_USER_CUSTOM_FONTS_META_KEY);
1398 if ($custom_fonts) {
1399 $s = '';
1400 foreach ($custom_fonts as $key => $fonts_data) {
1401 $s .= self::getFontsHTMLMarkup($fonts_data);
1402 }
1403 return $s;
1404 }
1405 }
1406
1407 public static function getFontsHTMLMarkup($fonts_data)
1408 {
1409 $font_family = str_replace(' ', '+', $fonts_data['family']);
1410 if (isset($fonts_data['fontUrl']) && !in_array($font_family, self::$printed_font_family_tracker, true)) {
1411 self::$printed_font_family_tracker[] = $font_family;
1412
1413 $font_url = isset($fonts_data['localUrl']) ? $fonts_data['localUrl'] : $fonts_data['fontUrl'];
1414
1415 //phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet
1416 return '<link class="' . 'kirki-custom-fonts-link" href="' . $font_url . '" rel="stylesheet">';
1417 }
1418 return '';
1419 }
1420
1421 /**
1422 * Generate new id and html string for: symbol, collection etc.
1423 *
1424 * @param array $data blocks.
1425 * @param array $style_blocks style_blocks.
1426 * @param string $root data root.
1427 */
1428 public static function rec_update_data_id_then_return_new_html($data, $style_blocks, $root = 'body', $options = [], $get_style = true)
1429 {
1430 $data_helper = new DataHelper();
1431 $data_helper->rec_update_data_id_to_new_id($data, $style_blocks, $root, null);
1432 $data = $data_helper->temp_data;
1433 $style_blocks = $data_helper->temp_styles;
1434 $root = isset($data_helper->temp_ids[$root]) ? $data_helper->temp_ids[$root] : false;
1435
1436 $params = array(
1437 'blocks' => $data,
1438 'style_blocks' => $style_blocks,
1439 'root' => $root,
1440 'post_id' => null,
1441 'options' => $options,
1442 'get_style' => $get_style,
1443 'get_all_style_forcefully_if_get_style_true' => true,//this will generate collection first item all style
1444 );
1445
1446 return self::get_html_using_preview_script($params);
1447 }
1448
1449 // hook
1450 public static function kirki_html_generator($s, $post_id, $staging_version = false)
1451 {
1452 $d = self::is_kirki_type_data($post_id, $staging_version);
1453 if ($d) {
1454 $params = array(
1455 'blocks' => $d['blocks'],
1456 'style_blocks' => $d['styles'],
1457 'root' => 'root',
1458 'post_id' => $post_id,
1459 );
1460 return self::get_html_using_preview_script($params);
1461 }
1462 return false;
1463 }
1464
1465 /**
1466 * Find symbol for post id using condition
1467 * it will find and return selected symbols html and css;
1468 *
1469 * @param string $type : post | user
1470 * @param array $context : post object or user object
1471 * @return symbol || bool(false)
1472 */
1473 public static function find_template_for_this_context($type = 'post', $context = null)
1474 {
1475 $templates = Page::fetch_list('kirki_template', true, array('publish'));
1476 if (!$templates || !$context)
1477 return false;
1478 foreach ($templates as $key => $template) {
1479 if (isset($template['conditions'])) {
1480 $conditions = $template['conditions'];
1481 if ($type === 'user') {
1482 if (self::check_all_conditions_for_this_user($context, $conditions)) {
1483 return $template;
1484 }
1485 } else if ($type === 'post') {
1486 if (self::check_all_conditions_for_this_post($context, $conditions)) {
1487 return $template;
1488 }
1489 } else if ($type === 'term') {
1490 if (self::check_all_conditions_for_this_term($context, $conditions)) {
1491 return $template;
1492 }
1493 }
1494 }
1495 }
1496 return false;
1497 }
1498
1499 /**
1500 * Generate popup html
1501 *
1502 * @return strint
1503 */
1504 public static function get_page_popups_html()
1505 {
1506 global $post;
1507 if ($post) {
1508 $popups = self::get_page_popups();
1509 if (count($popups) > 0) {
1510 $s = '';
1511 foreach ($popups as $key => $popup) {
1512 $params = array(
1513 'blocks' => $popup['blocks'],
1514 'style_blocks' => $popup['styleBlocks'],
1515 'root' => $popup['root'],
1516 'post_id' => $popup['id'],
1517 );
1518 $s .= self::get_html_using_preview_script($params);
1519 }
1520 return do_shortcode($s);
1521 }
1522 }
1523 return '';
1524 }
1525
1526 /**
1527 * Get Custom popups
1528 * it will find and return selected popups;
1529 *
1530 * @return array
1531 */
1532 public static function get_page_popups()
1533 {
1534 global $post;
1535 if ($post) {
1536 $popups = Page::fetch_list('kirki_popup', true, array('publish'));
1537 return self::find_popups_for_this_post($popups, $post);
1538 }
1539 return array();
1540 }
1541
1542 /**
1543 * Find popups for post id using condition
1544 * it will find and return selected popups arr;
1545 *
1546 * @param object $popups popup block object.
1547 * @param object $post post object.
1548 * @return popups || [];
1549 */
1550 public static function find_popups_for_this_post($popups, $post)
1551 {
1552 $arr = array();
1553 $post_id = $post->ID;
1554 foreach ($popups as $key => $popup) {
1555 $popup = self::format_single_popup_data_for_html_print($popup);
1556 if (self::check_popup_pagearr_logic($popup, $post_id)) {
1557 $arr[] = $popup;
1558 }
1559 }
1560 return $arr;
1561 }
1562
1563 private static function format_single_popup_data_for_html_print($popup)
1564 {
1565 if (!$popup['blocks'])
1566 return $popup;
1567 $root = false;
1568 foreach ($popup['blocks'] as $key2 => &$b) {
1569 if ('root' === $b['parentId']) {
1570 $root = $b['id'];
1571
1572 if (isset($b['properties']['attributes'])) {
1573 $b['properties']['attributes']['popup-id'] = $popup['id'];
1574 } else {
1575 $b['properties']['attributes'] = array(
1576 'popup-id' => $popup['id'],
1577 );
1578 }
1579 $popup['root'] = $root;
1580 }
1581 }
1582
1583 return $popup;
1584 }
1585
1586 /**
1587 * Check popup is active apply for this post or not.
1588 *
1589 * @param array $popup popup from Page::fetch_list.
1590 * @param int $post_id wp post id.
1591 * @return bool
1592 */
1593 private static function check_popup_pagearr_logic($popup, $post_id)
1594 {
1595 if (!isset($popup['root']))
1596 return false;
1597 $root = $popup['root'];
1598 if ($root && isset($popup['blocks'][$root]['properties']['popup']['visibilityConditions'])) {
1599 $conditions = $popup['blocks'][$root]['properties']['popup']['visibilityConditions'];
1600 $post = get_post($post_id);
1601 if (self::check_all_conditions_for_this_post($post, $conditions) || in_array($popup['id'], Preview::$only_used_popup_id_array, true)) {
1602 return true;
1603 }
1604 }
1605 return false;
1606 }
1607
1608 /**
1609 * Check all conditon for this post
1610 * This method will match all the condition and return true or false
1611 * category = * || post_type
1612 * taxonomy = 1=single post || * = all post || taxonomy slug
1613 * apply[to] = * = all || id = post id || term id
1614 * visibility = show || hide
1615 *
1616 * @param object $post post object.
1617 * @param object $conditions symbol visibility condiotions object.
1618 *
1619 * @return Boolean
1620 */
1621 public static function check_all_conditions_for_this_post($post, $conditions)
1622 {
1623 $show_flag = false;
1624 $hide_flag = false;
1625
1626 foreach ($conditions as $key => $condition) {
1627 if (!isset($condition['from'])) {
1628 $condition['from'] = 'post';
1629 }
1630 if ($condition['from'] === 'term') {
1631 return false;
1632 }
1633 if (isset($condition['category'])) {
1634 //legacy
1635 if ($condition['category'] === '*') {
1636 $condition['type'] = '*';
1637 } else {
1638 $condition['post_type'] = $condition['category'];
1639 $condition['type'] = 'post';
1640 }
1641 }
1642
1643 if (!isset($condition['visibility'])) {
1644 $condition['visibility'] = 'show';
1645 }
1646
1647 if ($condition['type'] === '*') {
1648 // Entire site
1649 $show_flag = $condition['visibility'] === 'show';
1650 } elseif ($condition['type'] === 'post') {
1651 if ($condition['post_type'] === $post->post_type) {
1652 // Post type related
1653 if ($condition['where'] == '*') {
1654 // All posts
1655 $show_flag = $condition['visibility'] === 'show';
1656 } elseif ($condition['where'] == 'single') {
1657 // Single post
1658 if ($condition['to'] === $post->ID) {
1659 $show_flag = $condition['visibility'] === 'show';
1660 $hide_flag = $condition['visibility'] === 'hide';
1661 }
1662 } else {
1663 // Taxonomy
1664 $taxonomy = $condition['where'];
1665 $term = $condition['to'];
1666 if ($term === '*') {
1667 // All terms
1668 $show_flag = $condition['visibility'] === 'show';
1669 } else {
1670 if (has_term($term, $taxonomy, $post->ID)) {
1671 $show_flag = $condition['visibility'] === 'show';
1672 $hide_flag = $condition['visibility'] === 'hide';
1673 }
1674 }
1675 }
1676 }
1677 }
1678
1679 // If hide flag is set, stop and return false
1680 if ($hide_flag) {
1681 return false;
1682 }
1683 }
1684 return $show_flag;
1685 }
1686
1687
1688 public static function check_all_conditions_for_this_term($term, $conditions)
1689 {
1690 $show_flag = false;
1691 $hide_flag = false;
1692 foreach ($conditions as $key => $condition) {
1693 if (!isset($condition['visibility'])) {
1694 $condition['visibility'] = 'show';
1695 }
1696 if (!isset($condition['from'])) {
1697 $condition['from'] = 'post';
1698 }
1699
1700 if ($condition['from'] !== 'term') {
1701 return false;
1702 }
1703
1704 if ($condition['type'] === '*') {
1705 // Entire site
1706 $show_flag = $condition['visibility'] === 'show';
1707 } elseif ($condition['type'] === 'post') {
1708
1709 if ($condition['post_type'] === $term['post_type']) {
1710 // Post type related
1711 if ($condition['where'] == '*') {
1712 // All posts
1713 $show_flag = $condition['visibility'] === 'show';
1714 } else {
1715 // Taxonomy
1716 $taxonomy = $condition['where'];
1717 $con_term = $condition['to'];
1718 if ($con_term === '*') {
1719 // All terms
1720 $show_flag = $condition['visibility'] === 'show';
1721 } else {
1722 if ($term['taxonomy'] == $con_term) {
1723 $show_flag = $condition['visibility'] === 'show';
1724 $hide_flag = $condition['visibility'] === 'hide';
1725 }
1726 }
1727 }
1728 }
1729 }
1730
1731 // If hide flag is set, stop and return false
1732 if ($hide_flag) {
1733 return false;
1734 }
1735 }
1736 return $show_flag;
1737 }
1738
1739 public static function check_all_conditions_for_this_user($user, $conditions)
1740 {
1741 $show_flag = false;
1742 $hide_flag = false;
1743 foreach ($conditions as $key => $condition) {
1744
1745 if (isset($condition['category'])) {
1746 //legacy
1747 if ($condition['category'] === '*') {
1748 $condition['type'] = '*';
1749 } else {
1750 $condition['post_type'] = $condition['category'];
1751 $condition['type'] = 'post';
1752 }
1753 }
1754
1755 if (!isset($condition['visibility'])) {
1756 $condition['visibility'] = 'show';
1757 }
1758
1759 if ($condition['type'] === '*') {
1760 // Entire site
1761 $show_flag = $condition['visibility'] === 'show';
1762 } elseif ($condition['type'] === 'user') {
1763 if ($condition['where'] === '*') {
1764 $show_flag = $condition['visibility'] === 'show';
1765 } elseif ($condition['where'] === 'role') {
1766 $user_role = $condition['to'];
1767
1768 if ($user_role === '*') {
1769 $show_flag = $condition['visibility'] === 'show';
1770 } else {
1771 $curr_user = $user;
1772 if (in_array($user_role, $curr_user['roles'])) {
1773 $show_flag = $condition['visibility'] === 'show';
1774 }
1775 }
1776 }
1777 }
1778
1779 if ($hide_flag) {
1780 return false;
1781 }
1782 }
1783
1784 return $show_flag;
1785 }
1786
1787
1788 private static function attribute_in_post_table($attr = '')
1789 {
1790 $post_table_attributes = array(
1791 'ID',
1792 'post_author',
1793 'post_date',
1794 'post_date_gmt',
1795 'post_content',
1796 'post_title',
1797 'post_excerpt',
1798 'post_status',
1799 'post_name',
1800 'post_type',
1801 'post_category',
1802 'term'
1803 );
1804
1805 return in_array($attr, $post_table_attributes, true);
1806 }
1807
1808 private static function sort_filters_by_relation($filter_items = array())
1809 {
1810 $sorted_array = array();
1811
1812 if (is_array($filter_items)) {
1813 array_walk($filter_items, function ($item) use (&$sorted_array) {
1814 $relation_raw = isset($item['relation']) ? $item['relation'] : 'OR';
1815 $relation = in_array(strtoupper($relation_raw), ['AND', 'OR'], true) ? strtoupper($relation_raw) : 'OR';
1816
1817 if (!isset($sorted_array[$relation])) {
1818 $sorted_array[$relation] = array();
1819 }
1820
1821 unset($item['relation']);
1822
1823 $sorted_array[$relation][] = $item;
1824 });
1825 }
1826
1827 return $sorted_array;
1828 }
1829
1830 /**
1831 * text, number, date/time, options, switch
1832 */
1833 private static function post_table_filter_query($filter_item, $data_type)
1834 {
1835 $field_name = $filter_item['id'];
1836 $sorted_array = self::sort_filters_by_relation($filter_item['items']);
1837
1838 $where_sql = '';
1839
1840 array_walk($sorted_array, function ($sorted_array_item, $condition) use ($data_type, $field_name, &$where_sql) {
1841 global $wpdb;
1842
1843 $conditions = array();
1844 $column_name = "$wpdb->posts.$field_name";
1845
1846 array_walk($sorted_array_item, function ($filter_condition_item) use ($data_type, $column_name, &$conditions) {
1847 switch ($data_type) {
1848 case 'text': {
1849 $conditions[] = PostsQueryUtils::post_table_text_query($column_name, $filter_condition_item['condition'], $filter_condition_item['value']);
1850 break;
1851 }
1852
1853 // case 'date': {
1854 // $conditions[] = PostsQueryUtils::post_table_text_query($column_name, $filter_condition_item['condition'], $filter_condition_item['value']);
1855 // break;
1856 // }
1857
1858 // case 'number': {
1859 // $conditions[] = PostsQueryUtils::post_table_number_query($column_name, $filter_condition_item['condition'], $filter_condition_item['value']);
1860 // break;
1861 // }
1862
1863 // case 'option': {
1864 // $conditions[] = PostsQueryUtils::post_table_options_query($column_name, $filter_condition_item['condition'], $filter_condition_item['value']);
1865 // break;
1866 // }
1867
1868 // case 'switch': {
1869 // $conditions[] = PostsQueryUtils::post_table_switch_query($column_name, $filter_condition_item['condition'], $filter_condition_item['value']);
1870 // break;
1871 // }
1872
1873 default: {
1874 break;
1875 }
1876 }
1877 });
1878
1879 if (empty($conditions)) {
1880 return;
1881 }
1882
1883 $condition_sql = implode(" {$condition} ", $conditions);
1884
1885 if ('OR' === $condition) {
1886 $condition_sql = "({$condition_sql})";
1887 }
1888
1889 /**
1890 * A query to
1891 * [x start with 'JoomShaper' or 'IcoFont' or 'Kirki'
1892 * and contains 'website' and ends with 'Ollyo']
1893 * will be like below:
1894 *
1895 * AND (x LIKE 'JoomShaper%' OR x LIKE 'IcoFont%' OR x LIKE 'Kirki%') AND x LIKE '%website%' AND x LIKE '%Ollyo'
1896 */
1897 $where_sql .= " AND $condition_sql";
1898 });
1899
1900 if (empty($where_sql)) {
1901 return null;
1902 }
1903
1904 $callback = function ($where) use ($where_sql) {
1905 $where .= $where_sql;
1906 return $where;
1907 };
1908
1909 add_filter('posts_where', $callback);
1910
1911 return $callback;
1912 }
1913
1914 /**
1915 * text, number, date/time, options, switch
1916 * help: https://wordpress.stackexchange.com/questions/159426/meta-query-with-string-starting-like-pattern
1917 */
1918
1919 private static function post_meta_table_filter_query($filter_item, $key, $data_type)
1920 {
1921 $sorted_array = self::sort_filters_by_relation($filter_item['items']);
1922 $meta_query = array();
1923
1924 array_walk($sorted_array, function ($sorted_array_item, $condition) use (&$meta_query, $key, $data_type) {
1925 if (count($sorted_array_item) > 0) {
1926 $condition_arr = array('relation' => $condition);
1927
1928 array_walk($sorted_array_item, function ($filter_condition_item) use (&$condition_arr, $key, $data_type) {
1929
1930 switch ($data_type) {
1931 case 'text': {
1932 $condition_arr[] = PostsQueryUtils::post_meta_table_text_query($key, $filter_condition_item['condition'], $filter_condition_item['value']);
1933 break;
1934 }
1935
1936 case 'date': {
1937 $condition_arr[] = PostsQueryUtils::post_meta_table_date_query($key, $filter_condition_item); // ['start-date' => '', 'end-date' => '']);
1938 break;
1939 }
1940
1941 case 'number': {
1942 $condition_arr[] = PostsQueryUtils::post_meta_table_number_query($key, $filter_condition_item['condition'], $filter_condition_item['value']);
1943 break;
1944 }
1945
1946 case 'option': {
1947 $condition_arr[] = PostsQueryUtils::post_meta_table_options_query($key, $filter_condition_item['condition'], $filter_condition_item['values']);
1948 break;
1949 }
1950
1951 case 'switch': {
1952 $condition_arr[] = PostsQueryUtils::post_meta_table_switch_query($key, $filter_condition_item['condition']);
1953 break;
1954 }
1955
1956 default: {
1957 break;
1958 }
1959 }
1960 });
1961
1962 $meta_query[] = $condition_arr;
1963 }
1964 });
1965
1966 return $meta_query;
1967 }
1968
1969 /**
1970 * filter query for reference table
1971 *
1972 * @param object $filter_item filter item.
1973 * @param string $key field meta key.
1974 * @param array $args args.
1975 *
1976 * @return array args
1977 */
1978
1979 private static function cm_reference_table_filter_query($filter_item, $key, $args)
1980 {
1981 global $wpdb;
1982
1983 $sorted_array = self::sort_filters_by_relation($filter_item['items']);
1984
1985 $post_ids_in = [];
1986 $post_ids_not_in = [];
1987
1988 $has_in_condition = false;
1989 $has_not_in_condition = false;
1990
1991 foreach ($sorted_array as $relation_str => $filters_by_relation) {
1992 foreach ($filters_by_relation as $filter_condition_item) {
1993 $condition = $filter_condition_item['condition'];
1994 $value = isset($filter_condition_item['value']) ? (int) $filter_condition_item['value'] : null;
1995
1996 if (!$value)
1997 continue;
1998
1999 $results = $wpdb->get_col($wpdb->prepare(
2000 "SELECT post_id FROM {$wpdb->prefix}kirki_cm_reference WHERE field_meta_key = %s AND ref_post_id = %d",
2001 $key,
2002 $value
2003 ));
2004
2005 $results = array_map('intval', $results);
2006
2007 if ($condition === 'in') {
2008 $has_in_condition = true;
2009 if ($relation_str === 'AND') {
2010 $post_ids_in[] = $results;
2011 } else {
2012 $post_ids_in = array_merge($post_ids_in, $results);
2013 }
2014 } elseif ($condition === 'not-in') {
2015 $has_not_in_condition = true;
2016 if ($relation_str === 'AND') {
2017 $post_ids_not_in[] = $results;
2018 } else {
2019 $post_ids_not_in = array_merge($post_ids_not_in, $results);
2020 }
2021 }
2022 }
2023 }
2024
2025 // Handle post__in only if there was an 'in' condition
2026 if ($has_in_condition) {
2027 if (!empty($post_ids_in)) {
2028 $post_ids_in = is_array(reset($post_ids_in))
2029 ? array_reduce($post_ids_in, 'array_intersect', array_shift($post_ids_in)) // ids-> [[1,2], [2,3]] -> array_reduce($ids, 'array_intersect', [1,2])
2030 : $post_ids_in;
2031
2032 $args['post__in'] = isset($args['post__in'])
2033 ? array_intersect($args['post__in'], $post_ids_in)
2034 : $post_ids_in;
2035
2036 if (empty($args['post__in'])) {
2037 $args['post__in'] = [0];
2038 }
2039 } else {
2040 // 'in' condition was given, but returned nothing
2041 $args['post__in'] = [0];
2042 }
2043 }
2044
2045 // Handle post__not_in normally
2046 if ($has_not_in_condition && !empty($post_ids_not_in)) {
2047 $post_ids_not_in = is_array(reset($post_ids_not_in))
2048 ? array_merge(...$post_ids_not_in)
2049 : $post_ids_not_in;
2050
2051 $args['post__not_in'] = isset($args['post__not_in'])
2052 ? array_merge($args['post__not_in'], $post_ids_not_in)
2053 : $post_ids_not_in;
2054 }
2055
2056 return $args;
2057 }
2058
2059 /**
2060 * handle legacy filter data
2061 *
2062 * @param object $params filter array.
2063 *
2064 * @return array filter array
2065 */
2066 public static function handle_legacy_filter_to_new_filter($filters)
2067 {
2068 $new_filters = array();
2069
2070 if (is_array($filters)) {
2071 foreach ($filters as $key => $item) {
2072 if (!isset($item['id']) && isset($item['type']) && $item['type']) {
2073 switch ($item['type']) {
2074 case 'date': {
2075 $new_filters[] = array(
2076 'type' => 'post_date',
2077 'id' => 'post_date',
2078 'title' => 'Post Date',
2079 'items' => [
2080 array(
2081 'start-date' => isset($item['start-date']) ? $item['start-date'] : '',
2082 'end-date' => isset($item['end-date']) ? $item['end-date'] : '',
2083 'relation' => 'OR',
2084 )
2085 ],
2086 );
2087
2088 break;
2089 }
2090
2091 case 'author': {
2092 $new_filters[] = array(
2093 'type' => 'post_author',
2094 'id' => 'post_author',
2095 'title' => 'Author',
2096 'items' => [
2097 array(
2098 'condition' => 'in',
2099 'values' => $item['values'],
2100 'relation' => 'OR',
2101 )
2102 ],
2103 );
2104
2105 break;
2106 }
2107
2108 case 'category': {
2109 $new_filters[] = array(
2110 'type' => 'post_category',
2111 'id' => 'post_category',
2112 'title' => 'Category',
2113 'items' => [
2114 array(
2115 'condition' => 'in',
2116 'values' => $item['values'],
2117 'relation' => 'OR',
2118 )
2119 ],
2120 );
2121 break;
2122 }
2123
2124 default: {
2125 break;
2126 }
2127 }
2128 } else {
2129 $new_filters[] = $item;
2130 }
2131 }
2132 }
2133 return $new_filters;
2134 }
2135
2136 /**
2137 * Static callback for posts_where filter to allow removal with remove_filter.
2138 *
2139 * @param string $where The WHERE clause.
2140 * @return string Modified WHERE clause.
2141 */
2142 public static function posts_where_filter_callback($where)
2143 {
2144 global $wpdb;
2145
2146 $params = self::$posts_where_filter_params;
2147 if (empty($params)) {
2148 return $where;
2149 }
2150
2151 $query = $params['query'];
2152 $reference_where_sql = $params['reference_where_sql'];
2153 $post_parent = $params['post_parent'];
2154
2155 $search = esc_sql($wpdb->esc_like($query));
2156
2157 $where .= $wpdb->prepare(
2158 " OR (
2159 ({$wpdb->posts}.post_title LIKE %s OR {$wpdb->posts}.post_content LIKE %s)
2160 AND {$wpdb->posts}.post_parent = %d
2161 )",
2162 "%{$search}%",
2163 "%{$search}%",
2164 $post_parent
2165 );
2166
2167 if (!empty($reference_where_sql)) {
2168 $where .= " {$reference_where_sql}";
2169 }
2170
2171 return $where;
2172 }
2173
2174 /**
2175 * Get dynamic collection data
2176 *
2177 * @param object $params query object.
2178 *
2179 * @return array post array
2180 */
2181 public static function get_posts($params)
2182 {
2183 $name = isset($params['name']) ? $params['name'] : null;
2184 $sorting = isset($params['sorting']) ? $params['sorting'] : null;
2185 $filters = isset($params['filters']) ? $params['filters'] : null;
2186 $inherit = (bool) ($params['inherit'] ?? false);
2187 $related = (bool) ($params['related'] ?? false);
2188 $post_parent = (int) ($params['post_parent'] ?? 0);
2189 $post_status = isset($params['post_status']) ? $params['post_status'] : 'publish';
2190 $query = isset($params['q']) ? $params['q'] : '';
2191 $IDs = isset($params['IDs']) ? $params['IDs'] : [];
2192 $related_post_parent = isset($params['related_post_parent']) ? $params['related_post_parent'] : self::get_post_id_if_possible_from_url();
2193
2194 // add new
2195 $current_page = isset($params['current_page']) ? $params['current_page'] : 1;
2196 $item_per_page = isset($params['item_per_page']) ? $params['item_per_page'] : 3;
2197 $offset = isset($params['offset']) ? $params['offset'] : 0;
2198 $context = isset($params['context']) ? $params['context'] : null;
2199 $tax_query = [
2200 'relation' => 'AND',
2201 ];
2202
2203 // Calculate the offset
2204 $offset = ($current_page - 1) * $item_per_page + $offset;
2205
2206 $args = array(
2207 'posts_per_page' => $item_per_page,
2208 'paged' => $current_page,
2209 'offset' => $offset,
2210 'post_type' => $name,
2211 'suppress_filters' => false,
2212 'post_status' => $post_status,
2213 's' => $query,
2214 );
2215
2216 if (!empty($query)) {
2217 self::search_posts_by_query($name, $query, $post_parent, $args);
2218 } else {
2219 remove_filter('posts_where', [HelperFunctions::class, 'posts_where_filter_callback']);
2220 }
2221
2222 if (count($IDs) > 0) {
2223 $args['post__in'] = $IDs;
2224 unset($args['post_parent']);
2225 $args['post_type'] = 'any';
2226 $inherit = false;
2227 $post_parent = false;
2228 }
2229
2230 $filters = self::handle_legacy_filter_to_new_filter($filters);
2231 $added_filters = array();
2232
2233 if (isset($filters) && is_array($filters)) {
2234 foreach ($filters as $filter_item) {
2235 if (isset($filter_item['parent']) && $filter_item['parent']) {
2236 $filter_item['id'] = 'term';
2237 }
2238 $field_name = isset($filter_item['id']) ? $filter_item['id'] : '';
2239
2240 if (!$field_name) {
2241 continue;
2242 }
2243
2244 if (self::attribute_in_post_table($filter_item['id']) && is_array($filter_item['items'])) {
2245
2246 switch ($field_name) {
2247 case 'post_excerpt':
2248 case 'post_content':
2249 case 'post_title': {
2250 $callback = self::post_table_filter_query($filter_item, 'text');
2251 if ($callback) {
2252 $added_filters[] = $callback;
2253 }
2254 }
2255
2256 case 'post_date':
2257 case 'post_date_gmt': {
2258 /**
2259 * $filter_item['items'] max contain one array.
2260 * in array may contain start-date, end-date
2261 * Like: [{"start-date": "2020-01-01","end-date": "2020-01-02"}]
2262 */
2263
2264 if (isset($filter_item['items'], $filter_item['items'][0])) {
2265 $items = $filter_item['items'];
2266 $item = $items[0]; // Get first item in array.
2267
2268 $date_query = array('column' => $field_name);
2269 $date_query['inclusive'] = true;
2270
2271 if (!empty($item['start-date'])) {
2272 $date_query['after'] = $item['start-date'];
2273 }
2274
2275 if (!empty($item['end-date'])) {
2276 $date_query['before'] = $item['end-date'];
2277 }
2278
2279 $args['date_query'] = $date_query;
2280 }
2281
2282 break;
2283 }
2284
2285 case 'post_author': {
2286
2287 /**
2288 * $filter_item['items'] must not contain more than 2 array of conditions.
2289 * 1 array may contain 'in' conditions and another for 'not-in' conditions
2290 * And values of 'in' and 'not-in' conditions should not collide
2291 * Like: the condition should not be author 'in' [1, 2, 3] and 'not-in' [2, 4, 5]
2292 */
2293 $items = $filter_item['items'];
2294
2295 foreach ($items as $item) {
2296 if (isset($item['condition'], $item['values']) && is_array($item['values'])) {
2297 if ($item['condition'] === 'in') {
2298 $args['author__in'] = $item['values'];
2299 }
2300
2301 if ($item['condition'] === 'not-in') {
2302 $args['author__not_in'] = $item['values'];
2303 }
2304 }
2305 }
2306
2307 break;
2308 }
2309
2310 case 'term': {
2311 $items = $filter_item['items'];
2312
2313
2314 foreach ($items as $item) {
2315 if (isset($item['condition'], $item['values']) && is_array($item['values'])) {
2316
2317 if ($item['condition'] === 'in' && !empty($item['values'])) {
2318 array_push($tax_query, [
2319 'taxonomy' => $filter_item['type'],
2320 'field' => 'term_id',
2321 'terms' => $item['values'],
2322 'operator' => 'IN',
2323 ]);
2324 }
2325
2326 if ($item['condition'] === 'not-in' && !empty($item['values'])) {
2327 array_push($tax_query, [
2328 'taxonomy' => $filter_item['type'],
2329 'field' => 'term_id',
2330 'terms' => $item['values'],
2331 'operator' => 'NOT IN',
2332 ]);
2333 }
2334 }
2335 }
2336 break;
2337 }
2338 }
2339 } else {
2340 $key = ContentManagerHelper::get_child_post_meta_key_using_field_id($post_parent, $field_name);
2341 $data_type = $filter_item['type'] ?? 'text';
2342
2343 if (isset($args['meta_query']) && !is_array($args['meta_query'])) {
2344 $args['meta_query'] = array();
2345 }
2346
2347 switch ($data_type) {
2348 default:
2349 case 'rich_text':
2350 case 'text':
2351 case 'phone':
2352 case 'url':
2353 case 'email': {
2354 $args['meta_query'][] = self::post_meta_table_filter_query($filter_item, $key, 'text');
2355 break;
2356 }
2357
2358 case 'date': {
2359 $args['meta_query'][] = self::post_meta_table_filter_query($filter_item, $key, 'date');
2360 break;
2361 }
2362
2363 case 'number': {
2364 $args['meta_query'][] = self::post_meta_table_filter_query($filter_item, $key, 'number');
2365 break;
2366 }
2367
2368 case 'option': {
2369 $args['meta_query'][] = self::post_meta_table_filter_query($filter_item, $key, 'option');
2370 break;
2371 }
2372
2373 case 'switch': {
2374 $args['meta_query'][] = self::post_meta_table_filter_query($filter_item, $key, 'switch');
2375 break;
2376 }
2377
2378 case 'taxonomy': {
2379 if (empty($args['tax_query'])) {
2380 $tax_query = array(
2381 'relation' => 'AND'
2382 );
2383 }
2384
2385 if (
2386 isset($filter_item['taxonomy'], $filter_item['terms']) &&
2387 is_array($filter_item['terms'])
2388 ) {
2389 $operators = array('NOT IN', 'IN');
2390
2391 $operator = 'IN';
2392
2393 if (isset($filter_item['operator']) && in_array($filter_item['operator'], $operators, true)) {
2394 $operator = $filter_item['operator'];
2395 }
2396
2397 array_push($tax_query, [
2398 'taxonomy' => $filter_item['taxonomy'],
2399 'field' => 'term_id', // So far this is fixed
2400 'terms' => $filter_item['terms'],
2401 'operator' => $operator,
2402 ]);
2403 }
2404 break;
2405 }
2406
2407 case 'author': {
2408 if (isset($filter_item['condition'], $filter_item['values']) && is_array($filter_item['values'])) {
2409 if ($filter_item['condition'] === 'is-equal') {
2410 $args['author__in'] = $filter_item['values'];
2411 }
2412
2413 if ($filter_item['condition'] === 'is-not-equal') {
2414 $args['author__not_in'] = $filter_item['values'];
2415 }
2416 }
2417 break;
2418 }
2419
2420 case 'multi-reference':
2421 case 'reference': {
2422 $args = self::cm_reference_table_filter_query($filter_item, $key, $args);
2423 break;
2424 }
2425 }
2426 }
2427 }
2428 }
2429
2430 if (count($tax_query) > 1) {
2431 $args['tax_query'] = $tax_query;
2432 }
2433
2434 if (isset($sorting)) {
2435 // Set the sort order (ASC/DESC)
2436 if (isset($sorting['order'])) {
2437 $args['order'] = $sorting['order'];
2438 }
2439
2440 // Check if the name is set and contains 'kirki_cm' && not include 'kirki_cm_post_meta'
2441 if (isset($name) && str_contains($name, KIRKI_CONTENT_MANAGER_PREFIX) && !in_array($sorting['orderby'], KIRKI_WORDPRESS_SORT_BY_OPTIONS)) {
2442 $args['orderby'] = 'meta_value'; // Use 'meta_value' or 'meta_value_num' as needed
2443 if (isset($sorting['orderby']) && !empty($sorting['orderby'])) {
2444 $args['meta_key'] = ContentManagerHelper::get_child_post_meta_key_using_field_id($post_parent, $sorting['orderby']);
2445 }
2446 } else {
2447 // For other cases, set the orderby based on the sorting parameter
2448 if (isset($sorting['orderby']) && !empty($sorting['orderby'])) {
2449 $args['orderby'] = $sorting['orderby'];
2450 }
2451 }
2452 }
2453
2454 if ($inherit || $post_parent) {
2455 //TODO: if terms page then show terms post only. like tag, category.
2456 $args['post_parent'] = $post_parent;
2457 }
2458
2459 if (!empty($context) && $inherit) {
2460 if ($context['collectionType'] == 'user') {
2461 $args['author'] = $context['id'];
2462 unset($args['post_parent']);
2463 }
2464 if ($context['collectionType'] == 'term') {
2465 $args['tax_query'] = array(
2466 array(
2467 'taxonomy' => $context['taxonomy'], // Replace 'category' with your taxonomy
2468 'field' => 'term_id', // Use 'slug' if you want to query by slug
2469 'terms' => $context['id'], // Replace 123 with your term ID
2470 )
2471 );
2472 unset($args['post_parent']);
2473 }
2474 }
2475
2476 if ($related) {
2477 $post = get_post($related_post_parent);
2478
2479 if ($post) {
2480 $args['post_type'] = $post->post_type;
2481 if (str_contains($post->post_type, 'kirki_cm_')) {
2482 // filter related posts for content manager post
2483 $referenced_post_ids = self::get_referenced_post_ids($post_parent, $post);
2484 $args['post__in'] = array_map('intval', $referenced_post_ids);
2485 } else {
2486 $args['tax_query'] = self::buildTaxonomyForRelatedPosts($post);
2487 $args['post__not_in'] = [$post->ID];
2488 }
2489
2490 }
2491 }
2492
2493 // Run the WP_Query
2494
2495 $query = new WP_Query($args);
2496 foreach ($added_filters as $callback) {
2497 remove_filter('posts_where', $callback);
2498 }
2499
2500 $posts = $query->posts;
2501
2502
2503 $custom_logo_id = get_theme_mod('custom_logo');
2504 $image = wp_get_attachment_image_src($custom_logo_id, 'full');
2505
2506 $kirki_content_manager_post_type_fields = array();
2507
2508 if (isset($args['post_type']) && KIRKI_CONTENT_MANAGER_PREFIX === $args['post_type']) {
2509 $post_parent = $args['post_parent'];
2510 $kirki_content_manager_post_type_fields = ContentManagerHelper::get_post_type_custom_field_keys($post_parent);
2511 }
2512
2513 foreach ($posts as $key => &$post) {
2514 if (is_null($post)) {
2515 unset($posts[$key]);
2516 continue;
2517 }
2518 if (
2519 KIRKI_CONTENT_MANAGER_PREFIX === $post->post_type && is_array($kirki_content_manager_post_type_fields)
2520 ) {
2521 foreach ($kirki_content_manager_post_type_fields as $field_key) {
2522 $meta_key = ContentManagerHelper::get_child_post_meta_key_using_field_id($post->post_parent, $field_key['id']);
2523 $post->{$field_key['id']} = get_post_meta($post->ID, $meta_key, true);
2524
2525 if (
2526 isset($field_key['type']) &&
2527 $field_key['type'] === 'image' &&
2528 $post->{$field_key['id']}
2529 ) {
2530 $post->{$field_key['id']} = array(
2531 'wp_attachment_id' => $post->{$field_key['id']}['id'],
2532 'src' => $post->{$field_key['id']}['url'],
2533 );
2534 }
2535 }
2536 }
2537
2538
2539 $post->post_id = $post->ID;
2540 $post->author_profile_picture = array(
2541 'src' => get_avatar_url($post->post_author)
2542 );
2543 $post->post_author = get_the_author_meta('display_name', $post->post_author);
2544 $post->post_time = get_the_time('', $post->ID);
2545 $post->featured_image = array(
2546 'wp_attachment_id' => get_post_thumbnail_id($post->ID),
2547 'src' => get_the_post_thumbnail_url($post->ID)
2548 );
2549 $post->site_logo = isset($image[0]) ? $image[0] : '';
2550 $post->post_page_link = \get_permalink($post->ID);
2551 $post->author_posts_page_link = \get_author_posts_url($post->post_author);
2552
2553 unset($post->post_excerpt);
2554 }
2555 ;
2556
2557 // Get total posts and total pages for pagination
2558 $total_posts = $query->found_posts;
2559 $total_posts_updated = max(0, $total_posts - $offset);
2560 $total_pages = ceil($total_posts_updated / $item_per_page);
2561
2562 // Calculate previous and next page numbers
2563 $prev_page = ($current_page > 1) ? $current_page - 1 : null;
2564 $next_page = ($current_page < $total_pages) ? $current_page + 1 : null;
2565
2566 // Return the query and pagination info
2567 return array(
2568 'data' => $posts,
2569 'pagination' => array(
2570 'per_page' => $item_per_page,
2571 'current_page' => $current_page,
2572 'total_pages' => $total_pages,
2573 'total_count' => $total_posts,
2574 'previous' => $prev_page,
2575 'next' => $next_page,
2576 ),
2577 );
2578 }
2579
2580
2581 public static function search_posts_by_query($name, $query, $post_parent, &$args)
2582 {
2583 global $wpdb;
2584
2585 if (!str_contains($name, 'kirki_cm_')) {
2586 return;
2587 }
2588
2589 unset($args['s']);
2590
2591 $all_custom_fields = ContentManagerHelper::get_post_type_custom_field_keys($post_parent);
2592 $meta_query_args = ['relation' => 'OR'];
2593 $reference_where_sql = '';
2594
2595 foreach ($all_custom_fields as $data) {
2596 if (!$data)
2597 continue;
2598
2599 $meta_key = ContentManagerHelper::get_child_post_meta_key_using_field_id($post_parent, $data['id']);
2600
2601 if (in_array($data['type'], ['text'], true)) {
2602 $meta_query_args[] = [
2603 'key' => $meta_key,
2604 'value' => $query,
2605 'compare' => 'LIKE',
2606 ];
2607 }
2608
2609 if (in_array($data['type'], ['reference'], true)) {
2610 $matched_post_ids = self::get_matched_post_ids_recursive($data['ref_collection'], $query);
2611
2612 if (!empty($matched_post_ids)) {
2613 $ids = implode(',', array_map('intval', $matched_post_ids));
2614 $reference_where_sql .= " OR {$wpdb->posts}.ID IN (
2615 SELECT post_id
2616 FROM {$wpdb->prefix}kirki_cm_reference
2617 WHERE field_meta_key = '{$meta_key}'
2618 AND ref_post_id IN ($ids)
2619 )";
2620 }
2621 }
2622 }
2623
2624 if (count($meta_query_args) > 1) {
2625 $args['meta_query'] = $meta_query_args;
2626 }
2627
2628 // Store filter parameters for the callback
2629 self::$posts_where_filter_params = [
2630 'query' => $query,
2631 'reference_where_sql' => $reference_where_sql,
2632 'post_parent' => $post_parent,
2633 ];
2634
2635 add_filter('posts_where', [__CLASS__, 'posts_where_filter_callback']);
2636 }
2637
2638 public static function get_matched_post_ids_recursive($post_parent, $query, $depth = 0, $max_depth = 5)
2639 {
2640 global $wpdb;
2641
2642 if ($depth > $max_depth) {
2643 return [];
2644 }
2645
2646 $post_type = 'kirki_cm_' . $post_parent;
2647
2648 $matched_post_ids = $wpdb->get_col(
2649 $wpdb->prepare(
2650 "SELECT ID FROM {$wpdb->posts}
2651 WHERE post_title LIKE %s
2652 AND post_status = 'publish'
2653 AND post_type = %s",
2654 '%' . $wpdb->esc_like($query) . '%',
2655 $post_type
2656 )
2657 );
2658
2659 $ref_custom_fields = ContentManagerHelper::get_post_type_custom_field_keys($post_parent);
2660 $meta_conditions = [];
2661
2662 foreach ($ref_custom_fields as $ref_field) {
2663 if (!$ref_field)
2664 continue;
2665
2666 if (in_array($ref_field['type'], ['text'], true)) {
2667 $ref_meta_key = ContentManagerHelper::get_child_post_meta_key_using_field_id($post_parent, $ref_field['id']);
2668 $meta_conditions[] = $wpdb->prepare(
2669 "(meta_key = %s AND meta_value LIKE %s)",
2670 $ref_meta_key,
2671 "%{$search}%"
2672 );
2673 }
2674 }
2675
2676 if (!empty($meta_conditions)) {
2677 $where_meta = implode(' OR ', $meta_conditions);
2678 $meta_post_ids = $wpdb->get_col("SELECT DISTINCT post_id FROM {$wpdb->postmeta} WHERE {$where_meta}"); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2679 $matched_post_ids = array_merge($matched_post_ids, $meta_post_ids);
2680 }
2681
2682 foreach ($ref_custom_fields as $ref_field) {
2683 if (!$ref_field || !in_array($ref_field['type'], ['reference'], true)) {
2684 continue;
2685 }
2686
2687 $ref_post_parent = $ref_field['ref_collection'];
2688 $nested_matched_ids = self::get_matched_post_ids_recursive($ref_post_parent, $query, $depth + 1, $max_depth);
2689
2690 if (!empty($nested_matched_ids)) {
2691 $meta_key = ContentManagerHelper::get_child_post_meta_key_using_field_id($post_parent, $ref_field['id']);
2692 $ids = implode(',', array_map('intval', $nested_matched_ids));
2693 $ref_post_ids = $wpdb->get_col($wpdb->prepare("SELECT post_id FROM {$wpdb->prefix}kirki_cm_reference WHERE field_meta_key = %s AND ref_post_id IN ($ids)", $meta_key)); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared
2694 $matched_post_ids = array_merge($matched_post_ids, $ref_post_ids);
2695 }
2696 }
2697
2698 return array_unique(array_map('intval', $matched_post_ids));
2699 }
2700
2701 public static function get_referenced_post_ids($post_parent, $post)
2702 {
2703 global $wpdb;
2704
2705 $allData = ContentManagerHelper::get_post_type_custom_field_keys($post_parent);
2706 $post_ids = [];
2707
2708 foreach ($allData as $data) {
2709 if ($data && in_array($data['type'], ['reference', 'multi-reference'], true)) {
2710 $meta_key = 'kirki_cm_field_' . $post_parent . '_' . $data['id'];
2711
2712 $results = $wpdb->get_results(
2713 $wpdb->prepare(
2714 "SELECT ref_post_id FROM {$wpdb->prefix}kirki_cm_reference WHERE field_meta_key = %s AND post_id = %d",
2715 $meta_key,
2716 $post->ID
2717 ),
2718 ARRAY_A
2719 );
2720
2721 foreach ($results as $id) {
2722 $related_posts = $wpdb->get_results(
2723 $wpdb->prepare(
2724 "SELECT post_id FROM {$wpdb->prefix}kirki_cm_reference WHERE field_meta_key = %s AND ref_post_id = %d",
2725 $meta_key,
2726 (int) $id['ref_post_id']
2727 ),
2728 ARRAY_A
2729 );
2730
2731 foreach ($related_posts as $related) {
2732 $related_id = (int) $related['post_id'];
2733
2734 if ($related_id !== (int) $post->ID) {
2735 $post_ids[] = $related_id;
2736 }
2737 }
2738
2739
2740 }
2741 }
2742 }
2743 $post_ids = array_values(array_unique($post_ids));
2744
2745 return !empty($post_ids) ? $post_ids : [0];
2746 }
2747
2748 public static function get_terms($params)
2749 {
2750 $terms_array = [];
2751 $current_page = isset($params['current_page']) ? (int) $params['current_page'] : 1;
2752 $item_per_page = isset($params['item_per_page']) ? (int) $params['item_per_page'] : 3;
2753 $offset = isset($params['offset']) ? (int) $params['offset'] : 0;
2754
2755 if (!empty($params['inherit'])) {
2756 $terms_array = get_the_terms($params['post_parent'], $params['taxonomy']);
2757 if (is_array($terms_array)) {
2758 // Convert WP_Term objects to arrays only if needed
2759 $terms_array = array_map(function ($term) {
2760 return is_object($term) && method_exists($term, 'to_array')
2761 ? $term->to_array()
2762 : (array) $term;
2763 }, $terms_array);
2764
2765 $calculated_offset = (($current_page - 1) * $item_per_page) + $offset;
2766 $terms_array = array_slice($terms_array, $calculated_offset, $item_per_page);
2767 } else {
2768 $terms_array = [];
2769 }
2770 } else {
2771 $params['offset'] = (($current_page - 1) * $item_per_page) + $offset;
2772 $params['number'] = $item_per_page;
2773
2774 $terms_array = get_terms($params);
2775
2776 if (is_array($terms_array)) {
2777 foreach ($terms_array as &$item) {
2778 if (is_object($item) && method_exists($item, 'to_array')) {
2779 $item = $item->to_array();
2780 } elseif (is_object($item)) {
2781 $item = (array) $item;
2782 }
2783 }
2784 } else {
2785 $terms_array = [];
2786 }
2787 }
2788
2789 // Count total terms
2790 $total_terms = 0;
2791 if (!empty($params['inherit'])) {
2792 $t = get_the_terms($params['post_parent'], $params['taxonomy']);
2793 if (is_array($t)) {
2794 $total_terms = count($t);
2795 } else {
2796 $total_terms = wp_count_terms(['taxonomy' => $params['taxonomy']]);
2797 }
2798 } else {
2799 $total_terms = wp_count_terms(['taxonomy' => $params['taxonomy']]);
2800 }
2801
2802 $total_pages = ($item_per_page > 0) ? ceil($total_terms / $item_per_page) : 1;
2803 $prev_page = ($current_page > 1) ? $current_page - 1 : null;
2804 $next_page = ($current_page < $total_pages) ? $current_page + 1 : null;
2805
2806 return [
2807 'data' => $terms_array,
2808 'pagination' => [
2809 'per_page' => $item_per_page,
2810 'current_page' => $current_page,
2811 'total_pages' => $total_pages,
2812 'total_count' => $total_terms,
2813 'previous' => $prev_page,
2814 'next' => $next_page,
2815 ],
2816 ];
2817 }
2818
2819 public static function buildTaxonomyForRelatedPosts(\WP_Post $post)
2820 {
2821 $taxonomies = get_object_taxonomies($post->post_type);
2822 $taxQuery = [
2823 'relation' => 'OR',
2824 ];
2825
2826 foreach ($taxonomies as $taxonomy) {
2827 $taxQuery[] = [
2828 'taxonomy' => $taxonomy,
2829 'field' => 'slug',
2830 'terms' => array_filter(wp_get_object_terms($post->ID, $taxonomy, ['fields' => 'slugs']), function ($termSlug) {
2831 return strtolower($termSlug) !== 'uncategorized';
2832 }),
2833 ];
2834 }
2835
2836
2837 return $taxQuery;
2838 }
2839
2840
2841 /**
2842 * Get dynamic collectiond data
2843 *
2844 * @param object $params query object.
2845 *
2846 * @return array post array
2847 */
2848 public static function get_comments($params)
2849 {
2850 $parent = (int) ($params['parent'] ?? 0);
2851 $post_id = (int) ($params['post_id'] ?? 0);
2852 $type = ($params['type'] ?? 'comment');
2853 $sorting = isset($params['sorting']) ? $params['sorting'] : null;
2854 $filters = isset($params['filters']) ? $params['filters'] : null;
2855 // add new
2856 $current_page = isset($params['current_page']) ? $params['current_page'] : 1;
2857 $item_per_page = isset($params['item_per_page']) ? $params['item_per_page'] : 3;
2858 $offset = isset($params['offset']) ? $params['offset'] : 0;
2859
2860 // Calculate the offset
2861 $offset_cal = ($current_page - 1) * $item_per_page + $offset;
2862
2863 $args = array(
2864 'parent' => $parent,
2865 'post_id' => $post_id,
2866 'type' => $type,
2867 'number' => $item_per_page,
2868 'paged' => $current_page,
2869 'offset' => $offset_cal,
2870 'count' => false
2871 );
2872
2873 if (isset($filters) && is_array($filters)) {
2874 foreach ($filters as $filter_item) {
2875 $field_name = isset($filter_item['id']) ? $filter_item['id'] : '';
2876
2877 if (!$field_name) {
2878 continue;
2879 }
2880 switch ($field_name) {
2881 case 'comment_date':
2882 case 'comment_date_gmt': {
2883 /**
2884 * $filter_item['items'] max contain one array.
2885 * in array may contain start-date, end-date
2886 * Like: [{"start-date": "2020-01-01","end-date": "2020-01-02"}]
2887 */
2888 if (isset($filter_item['items'], $filter_item['items'][0])) {
2889 $items = $filter_item['items'];
2890 $item = $items[0]; // Get first item in array.
2891
2892 $date_query = array('column' => $field_name);
2893 $date_query['inclusive'] = true;
2894
2895 if (!empty($item['start-date'])) {
2896 $date_query['after'] = $item['start-date'];
2897 }
2898
2899 if (!empty($item['end-date'])) {
2900 $date_query['before'] = $item['end-date'];
2901 }
2902
2903 $args['date_query'] = $date_query;
2904 }
2905
2906 break;
2907 }
2908
2909 case 'comment_author': {
2910 $items = $filter_item['items']; // $items['items'] max contain one array.
2911
2912 foreach ($items as $item) {
2913 if (isset($item['condition'], $item['values']) && is_array($item['values'])) {
2914 if ($item['condition'] === 'in') {
2915 $args['author__in'] = $item['values'];
2916 }
2917
2918 if ($item['condition'] === 'not-in') {
2919 $args['author__not_in'] = $item['values'];
2920 }
2921 }
2922 }
2923
2924 break;
2925 }
2926
2927 case 'comment_approved': {
2928 $items = $filter_item['items']; // $items['items'] max contain one array.
2929
2930 foreach ($items as $item) {
2931 if (isset($item['condition'], $item['values']) && is_array($item['values'])) {
2932 if ($item['condition'] === 'in') {
2933 $args['status'] = $item['values'];
2934 }
2935 }
2936 }
2937 }
2938 }
2939 }
2940 }
2941
2942 if (isset($sorting)) {
2943 // Set the sort order (ASC/DESC)
2944 if (isset($sorting['order'])) {
2945 $args['order'] = $sorting['order'];
2946 }
2947
2948 if (isset($sorting['orderby']) && !empty($sorting['orderby'])) {
2949 $args['orderby'] = $sorting['orderby'];
2950 }
2951 }
2952
2953 $comments = get_comments($args);
2954 unset($args['number']);
2955 unset($args['paged']);
2956
2957 if (is_array($comments)) {
2958 foreach ($comments as &$comment) {
2959 $comment = (object) (array) $comment;
2960
2961 $author_posts_page_link = $comment->comment_author_url;
2962
2963 if (!$author_posts_page_link) {
2964 $author_posts_page_link = \get_author_posts_url($comment->user_id);
2965 }
2966
2967 $comment->author_profile_picture = array(
2968 'src' => get_avatar_url($comment->user_id)
2969 );
2970 $comment->author_posts_page_link = $author_posts_page_link;
2971 }
2972 }
2973
2974 // Get total comments count
2975 $total_comments = get_comments(array_merge($args, array('count' => true)));
2976 $total_comments = $total_comments - $offset;
2977
2978 // Calculate total pages
2979 $total_pages = ceil($total_comments / $item_per_page);
2980
2981 // Calculate previous and next pages
2982 $prev_page = ($current_page > 1) ? $current_page - 1 : null;
2983 $next_page = ($current_page < $total_pages) ? $current_page + 1 : null;
2984
2985 // return $comments;
2986 return array(
2987 'data' => $comments, // Raw comments data
2988 'pagination' => array(
2989 'per_page' => $item_per_page,
2990 'current_page' => $current_page,
2991 'total_pages' => $total_pages,
2992 'total_count' => $total_comments,
2993 'previous' => $prev_page,
2994 'next' => $next_page,
2995 ),
2996 );
2997 }
2998
2999
3000 /**
3001 * Remove all default assets
3002 *
3003 * @return void
3004 */
3005 public static function remove_wp_assets()
3006 {
3007 /*
3008 // Remove all WordPress actions
3009 // remove_all_actions('wp_head');
3010 // remove_all_actions('wp_print_styles');
3011 // remove_all_actions('wp_print_head_scripts');
3012 // remove_all_actions('wp_footer');
3013
3014 // // Handle `wp_head`
3015 // add_action('wp_head', 'wp_enqueue_scripts', 1);
3016 // add_action('wp_head', 'wp_print_styles', 8);
3017 // add_action('wp_head', 'wp_print_head_scripts', 9);
3018 // add_action('wp_head', 'wp_site_icon');
3019
3020 // // Handle `wp_footer`
3021 // add_action('wp_footer', 'wp_print_footer_scripts', 20);
3022
3023 // // Handle `wp_enqueue_scripts`
3024 // remove_all_actions('wp_enqueue_scripts');
3025
3026 // // Also remove all scripts hooked into after_wp_tiny_mce.
3027 // remove_all_actions('after_wp_tiny_mce');
3028 */
3029 // remove admin-bar.
3030 add_filter('show_admin_bar', '__return_false', PHP_INT_MAX);
3031 }
3032
3033 /**
3034 * Get server protocol
3035 * currently not in use
3036 *
3037 * @return string protocol name.
3038 */
3039 public static function get_protocol()
3040 {
3041 $protocol = isset($_SERVER['HTTPS']) ? 'https' : 'http';
3042 return $protocol;
3043 }
3044
3045 /**
3046 * Check if the current user has specific role ($role)
3047 *
3048 * @param string $role The role to check.
3049 * @return boolean
3050 */
3051 public static function user_is($role)
3052 {
3053 $user = wp_get_current_user();
3054 $roles = $user->roles;
3055
3056 return is_array($roles) && count($roles) && in_array($role, $roles, true) ? true : false;
3057 }
3058
3059 /**
3060 * Check if the user has access to edit/create specific/all post
3061 *
3062 * @param int $post_id post id.
3063 * @return boolean
3064 *
3065 * @deprecated
3066 * @see Kirki\App\Wordpress\User::has_edit_access()
3067 */
3068 public static function user_has_post_edit_access()
3069 {
3070 return self::has_access(
3071 array(
3072 KIRKI_ACCESS_LEVELS['FULL_ACCESS'],
3073 KIRKI_ACCESS_LEVELS['CONTENT_ACCESS'],
3074 )
3075 );
3076 }
3077
3078 /**
3079 * Check if the user has access to editor
3080 *
3081 * @return boolean
3082 */
3083 public static function user_has_editor_access()
3084 {
3085 if (isset($_GET['editor-preview-token'])) {
3086 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
3087 $editor_preview_token = self::sanitize_text(isset($_GET['editor-preview-token']) ? $_GET['editor-preview-token'] : '');
3088 return self::is_post_editor_preview_token_valid($editor_preview_token);
3089 }
3090 return self::has_access(
3091 array(
3092 KIRKI_ACCESS_LEVELS['FULL_ACCESS'],
3093 KIRKI_ACCESS_LEVELS['CONTENT_ACCESS'],
3094 KIRKI_ACCESS_LEVELS['VIEW_ACCESS'],
3095 )
3096 );
3097 }
3098
3099 public static function getallheaders()
3100 {
3101 $headers = [];
3102
3103 foreach ($_SERVER as $name => $value) {
3104 if (strpos($name, 'HTTP_') === 0) {
3105 $key = substr($name, 5);
3106 } elseif (in_array($name, ['CONTENT_TYPE', 'CONTENT_LENGTH', 'CONTENT_MD5'])) {
3107 $key = $name;
3108 } else {
3109 continue;
3110 }
3111
3112 // Convert HEADER_NAME → Header-Name
3113 $key = str_replace('_', ' ', strtolower($key));
3114 $key = ucwords($key);
3115 $key = str_replace(' ', '-', $key);
3116
3117 $headers[$key] = $value;
3118 }
3119
3120 return $headers;
3121 }
3122
3123 /**
3124 * Check if the request is from the editor preview.
3125 *
3126 * @deprecated Use Kirki\App\Supports\EditorPreview::has_valid_token
3127 * @see \Kirki\App\Supports\EditorPreview::has_valid_token()
3128 * @return bool
3129 */
3130 public static function is_api_call_from_editor_preview()
3131 {
3132 // Check the Editor-Preview-Token header
3133 $headers = self::getallheaders();
3134 $editor_preview_token = isset($headers['Editor-Preview-Token']) ? $headers['Editor-Preview-Token'] : null;
3135 if ($editor_preview_token && HelperFunctions::is_post_editor_preview_token_valid($editor_preview_token)) {
3136 return true;
3137 }
3138 return false;
3139 }
3140
3141 /**
3142 * Check if the Editor-Preview-Token header is valid
3143 *
3144 * @deprecated Use Kirki\App\Supports\EditorPreview::has_valid_token
3145 * @see Kirki\App\Supports\EditorPreview::has_valid_token()
3146 * @return bool
3147 */
3148 public static function is_api_header_post_editor_preview_token_valid()
3149 {
3150 // Check the Editor-Preview-Token header
3151 $headers = self::getallheaders();
3152 $editor_preview_token = isset($headers['Editor-Preview-Token']) ? $headers['Editor-Preview-Token'] : null;
3153 if (HelperFunctions::is_post_editor_preview_token_valid($editor_preview_token)) {
3154 return true;
3155 }
3156 return false;
3157 }
3158
3159
3160 /**
3161 * Check if the Editor-Preview-Token header is valid
3162 *
3163 * @deprecated Use Kirki\App\Supports\EditorPreview::has_valid_token
3164 * @see Kirki\App\Supports\EditorPreview::has_valid_token()
3165 * @return bool
3166 */
3167 public static function is_post_editor_preview_token_valid($token)
3168 {
3169 $status = HelperFunctions::get_global_data_using_key('kirki_editor_read_only_access_status');
3170 if ($status) {
3171 $kirki_editor_read_only_access_token = HelperFunctions::get_global_data_using_key('kirki_editor_read_only_access_token');
3172 if ($kirki_editor_read_only_access_token && $kirki_editor_read_only_access_token === $token) {
3173 return true;
3174 }
3175 }
3176 return false;
3177 }
3178
3179 /**
3180 * Check if the current user has specific access
3181 *
3182 * @deprecated Use Kirki\App\Wordpress\User::has_access
3183 * @see Kirki\App\Wordpress\User
3184 * @param string|string[] $access_level The access level to check access.
3185 *
3186 */
3187 public static function has_access($access_level)
3188 {
3189 if (!function_exists('wp_get_current_user')) {
3190 return false;
3191 }
3192
3193 $user = wp_get_current_user();
3194 $roles = $user->roles;
3195 $has_access = false;
3196
3197 if (is_array($access_level)) {
3198 foreach ($roles as $role) {
3199 $access = get_option('kirki_' . $role);
3200 if (!empty($access) && in_array($access, $access_level, true)) {
3201 $has_access = true;
3202 break;
3203 }
3204 }
3205 } elseif (is_string($access_level)) {
3206 foreach ($roles as $role) {
3207 $access = get_option('kirki_' . $role);
3208 if (!empty($access) && $access === $access_level) {
3209 $has_access = true;
3210 break;
3211 }
3212 }
3213 }
3214
3215 return $has_access;
3216 }
3217
3218 /**
3219 * This method will collect license info from kirki.com
3220 *
3221 * @param string $license_key user license key.
3222 * @return array license info.
3223 */
3224 public static function get_my_license_info($license_key)
3225 {
3226 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
3227 $info = self::http_get(KIRKI_CORE_PLUGIN_URL . '/?license_key=' . $license_key . '&host=' . rawurlencode(self::sanitize_text(isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : null)));
3228 $info = json_decode($info, true);
3229 if ($info && isset($info['success'])) {
3230 return $info['data'];
3231 } else {
3232 return array('key' => $license_key);
3233 }
3234 }
3235
3236 /**
3237 * HTTP get
3238 *
3239 * @param string $url api endpoint url.
3240 * @return string|bool response.
3241 *
3242 * @deprecated
3243 * @see \Kirki\Framework\Supports\Facades\Http::get()
3244 */
3245 public static function http_get($url, $args = array())
3246 {
3247 try {
3248 $response = wp_remote_get($url, $args);
3249
3250 if ((!is_wp_error($response)) && (200 === wp_remote_retrieve_response_code($response))) {
3251 $responseBody = $response['body'];
3252
3253 return $responseBody;
3254 }
3255
3256 return false;
3257 } catch (\Exception $ex) {
3258 return false;
3259 }
3260 }
3261
3262 /**
3263 * HTTP post
3264 *
3265 * @param string $url api endpoint url.
3266 * @param array $options options.
3267 * @return array|WP_Error response.
3268 *
3269 * @deprecated
3270 * @see \Kirki\Framework\Supports\Facades\Http::post()
3271 */
3272 public static function http_post($url, $options)
3273 {
3274 $res = wp_remote_post($url, $options);
3275 return $res;
3276 }
3277
3278 /**
3279 * Text domain load hooks
3280 *
3281 * @param string $handle kirki handle.
3282 * @return void
3283 */
3284 public static function load_script_text_domain($handle)
3285 {
3286 wp_set_script_translations($handle, 'kirki', KIRKI_PLUGIN_PATH . 'languages/');
3287 }
3288
3289 /**
3290 * Delete kirki related meta if a post is deleted.
3291 *
3292 * @param int $post_id post id.
3293 * @return void
3294 */
3295 public static function delete_post_with_meta_key($post_id)
3296 {
3297 delete_post_meta($post_id, KIRKI_META_NAME_FOR_USED_STYLE_BLOCK_IDS);
3298 delete_post_meta($post_id, KIRKI_META_NAME_FOR_USED_STYLE_BLOCK_IDS . '_random');
3299 delete_post_meta($post_id, 'kirki');
3300 delete_post_meta($post_id, KIRKI_META_NAME_FOR_POST_EDITOR_MODE);
3301 delete_post_meta($post_id, KIRKI_GLOBAL_STYLE_BLOCK_META_KEY);
3302 delete_post_meta($post_id, KIRKI_GLOBAL_STYLE_BLOCK_META_KEY . '_random');
3303 delete_post_meta($post_id, KIRKI_META_NAME_FOR_USED_FONT_LIST);
3304 }
3305 /**
3306 * Get the query string for the media type
3307 *
3308 * @param string $type media type.
3309 * @return string The query string.
3310 * @example HelperFunctions::get_media_type_query_string('image') => 'image/jpeg, image/png, image/gif'
3311 */
3312 public static function get_media_type_query_string($type)
3313 {
3314 return implode(
3315 ', ',
3316 array_map(
3317 function ($v) {
3318 return "'" . $v . "'";
3319 },
3320 KIRKI_SUPPORTED_MEDIA_TYPES[$type]
3321 )
3322 );
3323 }
3324
3325 /**
3326 * This is for component configuration/object javascript variable.
3327 *
3328 * @return string script tag
3329 */
3330 public static function get_empty_variables()
3331 {
3332 $s = "<script id='kirki-elements-property-empty-vars'>";
3333 $s .= 'var ' . 'kirkiSliders = [], ' . 'kirkiMaps = [], ' . 'kirkiLotties = [], ' . 'kirkiPopups = [], ' . 'kirkiLightboxes = [], ' . 'kirkiReCaptchas = [], ' . 'kirkiVideos = [], ' . 'kirkiTabs = [], ' . 'kirkiInteractions = [], ' . 'kirkiCollections = [], ' . 'kirkiDropdown = [], ' . 'kirkiForms = [];';
3334 $s .= '</script>';
3335 return $s;
3336 }
3337
3338 /**
3339 * Check kirki and kirki pro is active or not
3340 *
3341 * @param string $plugin_main_file plugin main PHP file name.
3342 * @return boolean
3343 */
3344 public static function is_plugin_activate($plugin_main_file)
3345 {
3346 if (in_array($plugin_main_file, apply_filters('active_plugins', get_option('active_plugins')), true)) {
3347 // plugin is activated.
3348 return true;
3349 }
3350 return false;
3351 }
3352
3353 /**
3354 * This function will verify nonce
3355 * ACT like API calls auth middleware
3356 *
3357 * @param string $action ajax action name.
3358 *
3359 * @return void
3360 */
3361 public static function verify_nonce($action = -1)
3362 {
3363 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
3364 $headers = static::getallheaders();
3365 $header_nonce = isset($headers['X-Wp-Nonce']) ? static::sanitize_text($headers['X-Wp-Nonce']) : '';
3366 $nonce = $header_nonce ? $header_nonce : static::sanitize_text(isset($_GET['_wpnonce']) ? $_GET['_wpnonce'] : '');
3367
3368 if (!wp_verify_nonce($nonce, $action)) {
3369 wp_send_json_error('Not authorized');
3370 exit;
3371 }
3372 }
3373
3374 /**
3375 * Unslash and sanitize text
3376 *
3377 * @param string $v text.
3378 * @return string sanitized text.
3379 */
3380 public static function sanitize_text($v)
3381 {
3382 return sanitize_text_field(wp_unslash($v));
3383 }
3384
3385 /**
3386 * Get current WordPress session ID.
3387 * This method generates a unique session ID if none exists.
3388 *
3389 * @return string Session ID.
3390 */
3391 public static function get_session_id()
3392 {
3393
3394 // First, check if a session ID is already stored in the static variable.
3395 if (self::$global_session_id) {
3396 return self::$global_session_id;
3397 }
3398
3399 // Check if a session ID exists in a cookie.
3400 if (isset($_COOKIE['kirki_session_id'])) {
3401 self::$global_session_id = sanitize_text_field($_COOKIE['kirki_session_id']);
3402 return self::$global_session_id;
3403 }
3404
3405 // Generate a new session ID.
3406 self::$global_session_id = wp_generate_uuid4();
3407 // Set the session ID in a cookie.
3408 setcookie('kirki_session_id', self::$global_session_id, time() + (DAY_IN_SECONDS * 7), COOKIEPATH, COOKIE_DOMAIN, is_ssl(), true);
3409
3410 return self::$global_session_id;
3411 }
3412
3413 /**
3414 * Get session data by key using WordPress transients.
3415 *
3416 * @param string $key The key of the session data to retrieve.
3417 * @return mixed|null The session data if found, null otherwise.
3418 */
3419 public static function get_session_data($key)
3420 {
3421 // Get the current session ID.
3422 $session_id = self::get_session_id();
3423
3424 // Retrieve the session data.
3425 $session_data = get_transient('kirki_session_' . $session_id);
3426
3427 if (isset($session_data[$key])) {
3428 return $session_data[$key];
3429 }
3430
3431 return null;
3432 }
3433
3434 /**
3435 * Add or update session data using WordPress transients.
3436 *
3437 * @param string $key The key of the session data.
3438 * @param mixed $value The value of the session data.
3439 * @return void
3440 */
3441 public static function set_session_data($key, $value)
3442 {
3443 // Get the current session ID.
3444 $session_id = self::get_session_id();
3445
3446 // Retrieve existing session data.
3447 $session_data = get_transient('kirki_session_' . $session_id) ?: array();
3448
3449 // Update the session data.
3450 $session_data[$key] = $value;
3451
3452 // Save the updated session data with a 24-hour expiration time.
3453 set_transient('kirki_session_' . $session_id, $session_data, DAY_IN_SECONDS);
3454 }
3455
3456 /**
3457 * Delete session data by key using WordPress transients.
3458 *
3459 * @param string $key The key of the session data to delete.
3460 * @return void
3461 */
3462 public static function delete_session_data($key)
3463 {
3464 // Get the current session ID.
3465 $session_id = self::get_session_id();
3466
3467 // Retrieve existing session data.
3468 $session_data = get_transient('kirki_session_' . $session_id);
3469
3470 if (isset($session_data[$key])) {
3471 unset($session_data[$key]);
3472
3473 // Save the updated session data or delete the transient if empty.
3474 if (!empty($session_data)) {
3475 set_transient('kirki_session_' . $session_id, $session_data, DAY_IN_SECONDS);
3476 } else {
3477 delete_transient('kirki_session_' . $session_id);
3478 }
3479 }
3480 }
3481
3482
3483 /**
3484 * Is Pro user checking function.
3485 *
3486 * @return bool
3487 */
3488 public static function is_pro_user()
3489 {
3490 $common_data = WpAdmin::get_common_data(true);
3491
3492 $bool = isset($common_data['license_key']['valid']) && boolval($common_data['license_key']['valid']) === true;
3493
3494 return $bool;
3495 }
3496
3497
3498 /**
3499 * Get all view port lists
3500 *
3501 * @return string viewports list variable in script markup.
3502 */
3503 public static function get_view_port_lists()
3504 {
3505 $s = '';
3506 $list = UserData::get_view_port_list();
3507 if ($list) {
3508 $s .= "<script id='kirki-viewport-lists'>";
3509 $s .= 'var ' . 'kirkiViewports = ' . wp_json_encode($list) . ';';
3510 $s .= '</script>';
3511 }
3512 return $s;
3513 }
3514
3515 /**
3516 * Get all css variables
3517 *
3518 * @return string variables in script markup.
3519 */
3520 public static function get_kirki_css_variables_data()
3521 {
3522 $s = '';
3523 $variableData = UserData::get_kirki_variable_data();
3524 if ($variableData) {
3525 $s .= "<script id='kirki-variable-lists'>";
3526 $s .= 'var ' . 'kirkiCSSVariable = ' . wp_json_encode($variableData) . ';';
3527 $s .= '</script>';
3528 }
3529 return $s;
3530 }
3531
3532 /**
3533 * Get smooth scroll script
3534 *
3535 * @return string script markup.
3536 */
3537 public static function get_smooth_scroll_script()
3538 {
3539 $common_data = WpAdmin::get_common_data(true);
3540 $smooth_scroll_enabled = isset($common_data['smooth_scroll'], $common_data['smooth_scroll']['enabled']) ? $common_data['smooth_scroll']['enabled'] : false;
3541
3542 $smooth_scroll_value = isset($common_data['smooth_scroll'], $common_data['smooth_scroll']['value']) ? $common_data['smooth_scroll']['value'] : 1;
3543
3544 /**
3545 * User value 1 to 200
3546 *
3547 * Min duration 1s
3548 * Max duration 12s
3549 *
3550 */
3551 $duration = ceil(($smooth_scroll_value / 200) * 12);
3552
3553 $s = '';
3554
3555 if ($smooth_scroll_enabled) {
3556 $s .= "<script id='kirki-smooth-scroll'>";
3557 $s .= "
3558 window.document.addEventListener('DOMContentLoaded', function () {
3559 if (typeof KirkiSmoothScroll !== 'undefined') {
3560 const params = {
3561 autoRaf: true,
3562 anchors: true,
3563 allowNestedScroll: true,
3564 duration: $duration,
3565 };
3566
3567 const kirkiSmoothScroll = new KirkiSmoothScroll(params);
3568
3569 kirkiSmoothScroll.on('scroll');
3570 }
3571 });
3572 ";
3573 $s .= '</script>';
3574 }
3575
3576 return $s;
3577 }
3578
3579 /**
3580 * Format the date with date format
3581 *
3582 * @return string
3583 */
3584 public static function format_date($date, $format)
3585 {
3586 if ($date && $format) {
3587 $date_formats_arr = [
3588 'DD/MM/YYYY' => 'd/m/Y',
3589 'DD-MM-YYYY' => 'd-m-Y',
3590 'DD.MM.YYYY' => 'd.m.Y',
3591 'MM/DD/YYYY' => 'm/d/Y',
3592 'MM-DD-YYYY' => 'm-d-Y',
3593 'MM.DD.YYYY' => 'm.d.Y',
3594 'MMMM DD, YYYY' => 'F j, Y',
3595 'MMM DD, YYYY' => 'M j, Y',
3596 'YYYY-MM-DD' => 'Y-m-d',
3597 'YYYY/MM/DD' => 'Y/m/d',
3598 'YY.MM.DD' => 'y.m.d',
3599 'YY/MM/DD' => 'y/m/d',
3600 'YY-MM-DD' => 'y-m-d',
3601 ];
3602
3603 $timestamp = strtotime($date);
3604 if ($timestamp === false) {
3605 return $date; // fallback (avoid fatal)
3606 }
3607
3608 $datetime = (new \DateTime())->setTimestamp($timestamp);
3609 return $datetime->format($date_formats_arr[$format] ?? $format);
3610 }
3611
3612 return $date;
3613 }
3614
3615 /**
3616 * Format the time with time format
3617 *
3618 * @return string
3619 */
3620 public static function convert_time_format($timeString, $format = 'h:i a')
3621 {
3622 $dateTime = null;
3623
3624 try {
3625 $dateTime = new \DateTime($timeString);
3626 if ($dateTime && $timeString) {
3627 return $dateTime->format($format);
3628 }
3629 } catch (\Exception $e) {
3630 // if timeString is an invalid time format
3631 $parts = explode(' ', $timeString);
3632 if (count($parts) > 1) {
3633 // Remove the last part (am/pm)
3634 $time_value = $parts[0];
3635 try {
3636 $dateTime = new \DateTime($time_value);
3637 if ($dateTime && $timeString) {
3638 return $dateTime->format($format);
3639 }
3640 } catch (\Exception $e2) {
3641 return $timeString;
3642 }
3643 }
3644 return $timeString;
3645 }
3646
3647 return $timeString;
3648 }
3649
3650 /**
3651 * Get single post if has a kirki type post
3652 *
3653 * @return object|bool
3654 */
3655 public static function get_last_edited_kirki_editor_type_page()
3656 {
3657 $args = array(
3658 'post_type' => 'page', // Change to 'post' if you want to search for posts
3659 'post_status' => ['publish', 'draft'],
3660 'numberposts' => 1, // Number of results to retrieve (change as needed)
3661 'meta_key' => 'kirki_editor_mode',
3662 'meta_value' => 'kirki',
3663 'orderby' => 'modified', // Order by post date
3664 'order' => 'DESC', // Sort in descending order
3665 );
3666
3667 $pages = get_posts($args);
3668 if (count($pages) > 0) {
3669 return $pages[0];
3670 }
3671 return false;
3672 }
3673
3674 public static function get_kirki_version_from_db()
3675 {
3676 $version = wp_cache_get('kirki_version', 'kirki');
3677
3678 if (false === $version) {
3679 $version = get_option('kirki_version', '');
3680
3681 if (!empty($version)) {
3682 wp_cache_set('kirki_version', $version, 'kirki');
3683 }
3684 }
3685
3686 return $version;
3687 }
3688
3689 public static function set_kirki_version_in_db()
3690 {
3691 $version = self::get_kirki_version_from_db();
3692
3693 if ($version && version_compare($version, KIRKI_VERSION, '==')) {
3694 // No need to update the version if it's already equal to the current version.
3695 return;
3696 }
3697
3698 update_option('kirki_version', KIRKI_VERSION, false);
3699 wp_cache_set('kirki_version', KIRKI_VERSION, 'kirki');
3700 }
3701
3702 public static function accepted_file_types_by_plugin($accepted_media_types = KIRKI_SUPPORTED_MEDIA_TYPES)
3703 {
3704 $result = array();
3705
3706 foreach ($accepted_media_types as $value) {
3707 if (is_array($value)) {
3708 $result = array_merge($result, self::accepted_file_types_by_plugin($value));
3709 } else {
3710 $result[] = $value;
3711 }
3712 }
3713
3714 return $result;
3715 }
3716
3717 public static function content_manager_link_filter($dynamic_content = array(), $href = "#")
3718 {
3719 $current_post = get_post(self::get_post_id_if_possible_from_url());
3720
3721 if ($current_post->post_type === KIRKI_CONTENT_MANAGER_PREFIX) {
3722 $fields = ContentManagerHelper::get_post_type_custom_field_keys($current_post->post_parent);
3723
3724 if (isset($fields[$dynamic_content['value']]) && is_array($fields[$dynamic_content['value']])) {
3725 if ('email' === $fields[$dynamic_content['value']]['type']) {
3726 $href = "mailto:$href";
3727 } else if ('phone' === $fields[$dynamic_content['value']]['type']) {
3728 $href = "tel:$href";
3729 }
3730 }
3731 }
3732
3733 return $href;
3734 }
3735
3736 public static function check_string_has_this_tags($string, $tag)
3737 {
3738 // Check if the string contains either a <p> tag or an <h1> tag
3739 return preg_match("/<" . $tag . "[^>]*>/i", $string) === 1;
3740 }
3741
3742 /**
3743 * @deprecated
3744 * @see Kirki\App\Managers\GlobalDataManager::get_post_id()
3745 */
3746 private static function get_global_data_post_id()
3747 {
3748 $post_id = get_option('KIRKI_GLOBAL_DATA_POST_TYPE_ID', get_option('DROIP_GLOBAL_DATA_POST_TYPE_ID', false));
3749 if ($post_id) {
3750 return $post_id;
3751 } else {
3752 //this block will run only once
3753 $posts = get_posts(array(
3754 'post_type' => KIRKI_GLOBAL_DATA_POST_TYPE_NAME,
3755 'numberposts' => 1,
3756 ));
3757 if ($posts) {
3758 $post_id = $posts[0]->ID;
3759 } else {
3760 //create new post
3761 $post = array(
3762 'post_title' => KIRKI_GLOBAL_DATA_POST_TYPE_NAME,
3763 'post_type' => KIRKI_GLOBAL_DATA_POST_TYPE_NAME,
3764 'post_status' => 'draft'
3765 );
3766 $post_id = wp_insert_post($post);
3767 }
3768 update_option('KIRKI_GLOBAL_DATA_POST_TYPE_ID', $post_id, true);
3769 }
3770
3771 return $post_id;
3772 }
3773
3774 /**
3775 * Get global data using key
3776 *
3777 * @deprecated
3778 * @see Kirki\App\Managers\GlobalDataManager::get()
3779 */
3780 public static function get_global_data_using_key($key)
3781 {
3782 //first get post using KIRKI_GLOBAL_DATA_POST_TYPE_NAME post_type name. if not found then create new one.
3783 $post_id = self::get_global_data_post_id();
3784 if (metadata_exists('post', $post_id, $key)) {
3785 return get_post_meta($post_id, $key, true);
3786 }
3787
3788 // this block will run only once for a legacy option key.
3789 $value = get_option($key, null);
3790 if (null !== $value) {
3791 update_post_meta($post_id, $key, $value);
3792 delete_option($key);
3793 }
3794
3795 return $value;
3796 }
3797
3798 /**
3799 * Get global data using key
3800 *
3801 * @deprecated
3802 * @see Kirki\App\Managers\GlobalDataManager::update()
3803 */
3804 public static function update_global_data_using_key($key, $value)
3805 {
3806 $post_id = self::get_global_data_post_id();
3807 update_post_meta($post_id, $key, $value);
3808
3809 }
3810
3811 public static function get_template_data_if_current_page_is_kirki_template()
3812 {
3813 $custom_data = get_query_var('kirki_custom_data');
3814 $data = false;
3815 $builder_div = '';
3816 if ($custom_data && isset($custom_data['kirki_template_content'])) {
3817 $action = HelperFunctions::sanitize_text(isset($_GET['action']) ? $_GET['action'] : null);
3818 $load_for = HelperFunctions::sanitize_text(isset($_GET['load_for']) ? $_GET['load_for'] : '');
3819
3820 if ($action === KIRKI_EDITOR_ACTION && $load_for === 'kirki-iframe' && !str_contains($custom_data['kirki_template_content'], 'kirki-builder')) {
3821 $template_edit_url = HelperFunctions::get_post_url_arr_from_post_id($custom_data['kirki_template_id'], ['editor_url' => true])['editor_url'];
3822 $builder_div = '<div id="' . 'kirki-builder' . '" template-error="' . $template_edit_url . '"></div>';
3823 }
3824
3825 $data = array(
3826 'content' => $custom_data['kirki_template_content'] . $builder_div,
3827 'template_id' => $custom_data['kirki_template_id']
3828 );
3829 }
3830 return $data;
3831 }
3832
3833 public static function get_custom_data_if_current_page_is_kirki_custom_post()
3834 {
3835 $custom_data = get_query_var('kirki_custom_data');
3836 $data = false;
3837 $builder_div = '';
3838 if ($custom_data && isset($custom_data['kirki_custom_post_content'])) {
3839 $action = HelperFunctions::sanitize_text(isset($_GET['action']) ? $_GET['action'] : null);
3840 $load_for = HelperFunctions::sanitize_text(isset($_GET['load_for']) ? $_GET['load_for'] : '');
3841
3842 if ($action === KIRKI_EDITOR_ACTION && $load_for === 'kirki-iframe' && !str_contains($custom_data['kirki_custom_post_content'], 'kirki-builder')) {
3843 $template_edit_url = HelperFunctions::get_post_url_arr_from_post_id($custom_data['kirki_custom_post_id'], ['editor_url' => true])['editor_url'];
3844 $builder_div = '<div id="' . 'kirki-builder' . '" template-error="' . $template_edit_url . '"></div>';
3845 }
3846
3847 $data = array(
3848 'content' => $custom_data['kirki_custom_post_content'] . $builder_div,
3849 'post_id' => $custom_data['kirki_custom_post_id']
3850 );
3851 }
3852 return $data;
3853 }
3854
3855 /**
3856 * Validate slug for a post.
3857 *
3858 * @param int|null $post_id
3859 * @param string $post_type
3860 * @param string $post_name
3861 * @return bool
3862 *
3863 * @deprecated Use Kirki\App\Supports\ContentManager::validate_slug() instead.
3864 * @see Kirki\App\Supports\ContentManager
3865 */
3866 public static function validate_slug($post_id, $post_type, $post_name)
3867 {
3868 global $wpdb;
3869 // Execute the query
3870 $result = $wpdb->get_var($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_name = %s AND post_type = %s AND ID != %d", $post_name, $post_type, $post_id ? $post_id : 0));
3871
3872 // If a post with the same slug exists, return false
3873 if ($result) {
3874 return false;
3875 }
3876
3877 // If no post with the same slug exists, return true
3878 return true;
3879 }
3880
3881 /**
3882 * Summary of find_utility_page_for_this_context
3883 * @param mixed $type
3884 * @param mixed $get_by id | type.
3885 * @return mixed
3886 */
3887 public static function find_utility_page_for_this_context($value = '404', $get_by = 'type')
3888 {
3889 $utility_pages = Page::fetch_list('kirki_utility', true, array('publish'));
3890 if (count($utility_pages) > 0) {
3891 foreach ($utility_pages as $key => $page) {
3892 if ($get_by === 'type') {
3893 if ($page['utility_page_type'] === $value) {
3894 return $page;
3895 }
3896 } else if ($get_by === 'id') {
3897 if ($page['id'] === (int) $value) {
3898 return $page;
3899 }
3900 }
3901 }
3902 }
3903 return false;
3904 }
3905 public static function get_current_page_context()
3906 {
3907 $context = array(); // {id, type}
3908
3909 $obj = get_queried_object();
3910
3911 if (is_404()) {
3912 $context['type'] = '404';
3913 } else if ($obj instanceof WP_Post) {
3914 $context['id'] = $obj->ID;
3915 $context['type'] = 'post';
3916 } else if ($obj instanceof WP_User) {
3917 $context['id'] = $obj->ID;
3918 $context['type'] = 'user';
3919 } elseif ($obj instanceof WP_Term) {
3920 $context['id'] = $obj->term_id;
3921 $context['type'] = 'term';
3922 }
3923 // elseif ($obj instanceof WP_Post_Type) {
3924 // echo 'This is a WP_Post_Type object';
3925 // } elseif (is_null($obj)) {
3926 // echo 'No queried object (null)';
3927 // }
3928 else {
3929 $kirki_utility_page_type = get_query_var('kirki_utility_page_type');
3930 $kirki_utility_page_id = get_query_var('kirki_utility_page_id');
3931 if (!empty($kirki_utility_page_type)) {
3932 if (!self::check_utility_page_visibility_condition($kirki_utility_page_type)) {
3933 $context['type'] = '404';
3934 } else {
3935 $context['type'] = 'kirki_utility';
3936 $context['kirki_utility_page_type'] = $kirki_utility_page_type;
3937 $context['kirki_utility_page_id'] = $kirki_utility_page_id;
3938 }
3939 }
3940 }
3941 return $context;
3942 }
3943
3944
3945 /**
3946 * Get utility page slug using type.
3947 * { type: 'login', title: 'Login' },
3948 * { type: 'sign_up', title: 'Registration' },
3949 * { type: 'forgot_password', title: 'Forgot Password' },
3950 * { type: 'reset_password', title: 'Reset Password' },
3951 * { type: 'retrive_username', title: 'Retrive Username' },
3952 * { type: '404', title: '404' },
3953 *
3954 * @param string $type //utility page type.
3955 * @return string||bool //string or false.
3956 */
3957 public static function get_utility_page_url($type)
3958 {
3959 $utility_pages = Page::fetch_list('kirki_utility', true, array('publish'));
3960 foreach ($utility_pages as $key => $page) {
3961 $utility_page_type = $page['utility_page_type'];
3962
3963 $slug = $page['slug'];
3964 if ($utility_page_type === $type) {
3965 return home_url('/' . $slug);
3966 }
3967 }
3968 return false;
3969 }
3970 public static function check_utility_page_visibility_condition($type)
3971 {
3972 if ($type === 'login' || $type === 'sign_up' || $type === 'forgot_password' || $type === 'reset_password' || $type === 'retrive_username') {
3973 // Check if the user is already logged in
3974 if (is_user_logged_in()) {
3975 return false; // User is logged in, so the page should not be visible
3976 }
3977 // Add other conditions based on the type if needed
3978 if ($type === 'signup') {
3979 // Example: Check if registrations are enabled in WordPress
3980 if (!get_option('users_can_register')) {
3981 return false; // Registration is disabled
3982 }
3983 }
3984 // If the user is not logged in and other conditions pass, allow the page to be visible
3985 return true;
3986 }
3987 // If the type is not 'login' or 'signup', return false by default
3988 return true;
3989 }
3990
3991 /**
3992 * @deprecated
3993 * @see \Kirki\Framework\Supports\Facades\File::delete()
3994 */
3995 public static function delete_directory($dirname)
3996 {
3997 global $wp_filesystem;
3998 if (empty($wp_filesystem)) {
3999 require_once ABSPATH . 'wp-admin/includes/file.php';
4000 WP_Filesystem();
4001 }
4002
4003 if ($wp_filesystem->exists($dirname)) {
4004 return $wp_filesystem->delete($dirname, true);
4005 }
4006
4007 return false;
4008 }
4009
4010 /**
4011 * @deprecated
4012 * @see \Kirki\App\Supports\FileHandler::get_temp_folder_path()
4013 */
4014 public static function get_temp_folder_path()
4015 {
4016 $upload_dir = wp_upload_dir();
4017 $temp_folder = 'kirki_temp';
4018 $temp_folder_path = $upload_dir['basedir'] . '/' . $temp_folder;
4019
4020 return $temp_folder_path;
4021 }
4022
4023 /**
4024 * @deprecated
4025 * @see \Kirki\App\Managers\GlobalDataManager::get_initial_viewports()
4026 */
4027 public static function get_initial_view_ports()
4028 {
4029 return json_decode('{
4030 "active":"md",
4031 "scale":1,
4032 "zoom":1,
4033 "width":1200,
4034 "mdWidth":"",
4035 "defaults":[
4036 "md",
4037 "tablet",
4038 "mobileLandscape",
4039 "mobile"
4040 ],
4041 "list":{
4042 "md":{
4043 "value":1200,
4044 "scale":1,
4045 "minWidth":1200,
4046 "maxWidth":1200,
4047 "title":"Desktop",
4048 "icon":"desktop",
4049 "activeIcon":"desktop-hover"
4050 },
4051 "tablet":{
4052 "value":991,
4053 "scale":1,
4054 "minWidth":991,
4055 "maxWidth":991,
4056 "title":"Tablet",
4057 "icon":"tablet-default",
4058 "activeIcon":"tablet-hover"
4059 },
4060 "mobileLandscape":{
4061 "value":767,
4062 "scale":1,
4063 "minWidth":767,
4064 "maxWidth":767,
4065 "title":"Landscape",
4066 "icon":"phone-hr-default",
4067 "activeIcon":"phone-hr-hover"
4068 },
4069 "mobile":{
4070 "value":575,
4071 "scale":1,
4072 "minWidth":575,
4073 "maxWidth":575,
4074 "title":"Mobile",
4075 "icon":"phone-vr-default",
4076 "activeIcon":"phone-vr-hover"
4077 }
4078 }
4079 }', true);
4080 }
4081
4082 /**
4083 * @deprecated
4084 * @see \Kirki\App\Supports\FileHandler::download_zip_from_remote()
4085 */
4086 public static function download_zip_from_remote($remote_file, $new_name)
4087 {
4088 return FileHandler::download_zip_from_remote($remote_file, $new_name);
4089 // $file_ext = explode('.', $remote_file); // ['file', 'ext']
4090 // $file_ext = strtolower(end($file_ext)); // 'ext'
4091 // $allowed = ['zip'];
4092 // if (!in_array($file_ext, $allowed)) {
4093 // return false;
4094 // }
4095
4096 // try {
4097 // // error_reporting(E_ALL);
4098 // // ini_set('display_errors', 1);
4099 // // Download the file from the remote server.
4100 // // Create a stream context to disable SSL verification
4101 // $options = [
4102 // "http" => [
4103 // "method" => "GET",
4104 // "header" => "User-Agent: WordPress\r\n"
4105 // ],
4106 // "ssl" => [
4107 // "verify_peer" => false, // Disable verification of the peer's certificate
4108 // "verify_peer_name" => false // Disable verification of the peer's name
4109 // ]
4110 // ];
4111 // $context = stream_context_create($options);
4112 // $file_contents = file_get_contents($remote_file, false, $context);
4113
4114 // // Save the file locally.
4115 // if ($file_contents !== false) {
4116 // // Local path to save the downloaded file.
4117 // $local_file = wp_upload_dir()['basedir'] . '/' . $new_name;
4118 // file_put_contents($local_file, $file_contents);
4119 // return $local_file;
4120 // }
4121 // } catch (\Throwable $th) {
4122 // // throw $th;
4123 // }
4124 // return false;
4125 }
4126
4127 public static function filterZipFile($zip, $zip_file_path)
4128 {
4129 // Temporary filtered ZIP path
4130 $filtered_zip_path = sys_get_temp_dir() . '/filtered.zip';
4131 $filtered_zip = new \ZipArchive;
4132
4133 if ($filtered_zip->open($filtered_zip_path, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) === TRUE) {
4134 // Loop through all files in the archive
4135 for ($i = 0; $i < $zip->numFiles; $i++) {
4136 $filename = $zip->getNameIndex($i);
4137 $file_path = 'zip://' . $zip_file_path . '#' . $filename;
4138
4139 // Get MIME type based on file extensioncm_f
4140 $file_mime = self::getMimeTypeByExtension($filename);
4141
4142 // Additional JSON validation
4143 if ($file_mime === 'application/json' && !self::isJsonFile($file_path)) {
4144 $file_mime = 'text/plain'; // Fallback if not valid JSON
4145 }
4146
4147 // Check if the file MIME type matches supported types
4148 $is_supported = false;
4149 foreach (KIRKI_SUPPORTED_MEDIA_TYPES as $types) {
4150 if (in_array($file_mime, $types)) {
4151 $is_supported = true;
4152 break;
4153 }
4154 }
4155
4156 // Add the file to the filtered archive if supported
4157 if ($is_supported) {
4158 $file_contents = $zip->getFromIndex($i);
4159 $filtered_zip->addFromString($filename, $file_contents);
4160 }
4161 }
4162
4163 $filtered_zip->close();
4164 return $filtered_zip_path;
4165 } else {
4166 return false;
4167 }
4168 }
4169
4170 // Helper function to get MIME type by file extension
4171 private static function getMimeTypeByExtension($filename)
4172 {
4173 $extension_to_mime = [
4174 'json' => 'application/json',
4175 'jpg' => 'image/jpeg',
4176 'jpeg' => 'image/jpeg',
4177 'png' => 'image/png',
4178 'gif' => 'image/gif',
4179 'webp' => 'image/webp',
4180 'svg' => 'image/svg+xml',
4181 'pdf' => 'application/pdf',
4182 'mp4' => 'video/mp4',
4183 'ogg' => 'audio/ogg',
4184 'lottie' => 'text/plain',
4185 'mov' => 'video/quicktime',
4186 'mp3' => 'audio/mpeg',
4187 'wav' => 'audio/wav',
4188
4189 // Add more extensions as needed
4190 ];
4191
4192 $ext = pathinfo($filename, PATHINFO_EXTENSION);
4193 return $extension_to_mime[strtolower($ext)] ?? 'application/octet-stream';
4194 }
4195
4196 // Helper function to validate JSON file content
4197 private static function isJsonFile($file_path)
4198 {
4199 $file_contents = @file_get_contents($file_path);
4200 $trimmed = trim($file_contents);
4201 return $trimmed[0] === '{' || $trimmed[0] === '[';
4202 }
4203
4204 public static function is_remote_url($url)
4205 {
4206 // Parse the URL to get components
4207 $parsed_url = wp_parse_url($url);
4208 return isset($parsed_url['scheme']);
4209 }
4210
4211 public static function is_element_accessible($access)
4212 {
4213 switch ($access) {
4214 case 'all':
4215 return true; // Accessible to everyone
4216
4217 case 'guest':
4218 return !is_user_logged_in();
4219
4220 case 'logged-in':
4221 return is_user_logged_in(); // Accessible to any logged-in user
4222
4223 case 'admin':
4224 // Administrators and Super Admins
4225 return current_user_can('manage_options');
4226
4227 case 'editor':
4228 // Editors, Admins, and Super Admins can see this
4229 return current_user_can('edit_pages');
4230
4231 case 'author':
4232 // Authors, Editors, Admins, etc.
4233 return current_user_can('publish_posts');
4234
4235 case 'subscriber':
4236 // Subscribers and EVERY logged-in user above them
4237 return current_user_can('read');
4238
4239 default:
4240 return false; // Safely hide if the access rule is unrecognized
4241 }
4242 }
4243
4244 /**
4245 * Find symbol for post id using condition
4246 * it will find and return selected symbols html and css;
4247 *
4248 * @param string $type : symbol type.
4249 * @param string $post : post object.
4250 * @return symbol || bool(false)
4251 */
4252 public static function find_symbol_for_this_page($type)
4253 {
4254 $all_symbols = Symbol::fetch_list(true, false);
4255 foreach ($all_symbols as $key => $symbol) {
4256 if (isset($symbol['setAs']) && $symbol['setAs'] === $type) {
4257 return $symbol;
4258 }
4259 }
4260 return false;
4261 }
4262 /**
4263 * Get Custom Header
4264 * it will find and return selected symbols html and css;
4265 *
4266 * @param string $type stymbol type header|footer.
4267 * @param string $html if true the function will return html otherwise return symbol object.
4268 * @return string|object custom section html or stymbol object.
4269 */
4270 public static function get_page_custom_section($type, $html = true)
4271 {
4272 $show = apply_filters('kirki_show_custom_section_' . $type, true);
4273 if (!$show) {
4274 return '';
4275 }
4276
4277
4278 $symbol = self::find_symbol_for_this_page($type);
4279 if (!$html) {
4280 return $symbol;
4281 }
4282
4283 if (isset(self::$custom_sections[$type])) {
4284 return self::$custom_sections[$type];
4285 }
4286
4287 $s = self::isShowWPThemeHeaderFooter() ? '' : ' '; // this is for disableing theme header footer forcefully if is_show_wp_theme_header_footer is false
4288
4289 if ($symbol) {
4290 $action = HelperFunctions::sanitize_text(isset($_GET['action']) ? $_GET['action'] : '');
4291 $symbol_data = $symbol['symbolData'];
4292 $set_as = isset($symbol['setAs']) ? $symbol['setAs'] : '';
4293
4294 $post_id = self::get_post_id_if_possible_from_url();
4295 $template_data = self::get_template_data_if_current_page_is_kirki_template();
4296 if ($template_data)
4297 $post_id = $template_data['template_id'];
4298
4299
4300 $custom_page_data = self::get_custom_data_if_current_page_is_kirki_custom_post();
4301 if ($custom_page_data)
4302 $post_id = $custom_page_data['post_id'];
4303
4304 $is_page_symbol_disabled = get_post_meta($post_id, KIRKI_META_NAME_FOR_PAGE_HF_SYMBOL_DISABLE_STATUS, true);
4305 if (isset($is_page_symbol_disabled) && is_array($is_page_symbol_disabled) && isset($is_page_symbol_disabled[$type])) {
4306 $is_page_symbol_disabled = $is_page_symbol_disabled[$type];
4307 } else {
4308 $is_page_symbol_disabled = false;
4309 }
4310
4311 $params = array(
4312 'blocks' => $symbol_data['data'],
4313 'style_blocks' => $symbol_data['styleBlocks'],
4314 'root' => $symbol_data['root'],
4315 'post_id' => $symbol['id'],
4316 'options' => [],
4317 'get_style' => true,
4318 'get_variable' => false,
4319 'should_take_app_script' => false,
4320 'prefix' => 'kirki-s' . $symbol['id']
4321 );
4322 if ($action === KIRKI_EDITOR_ACTION) {
4323 $extra_attr_for_hf_symbol = '';
4324 if ($is_page_symbol_disabled)
4325 $extra_attr_for_hf_symbol = ' style="display:none;"';
4326 $s = '<' . $type . $extra_attr_for_hf_symbol . ' data-kirki-symbol_set_as="' . $set_as . '" data-kirki-symbol="' . $symbol['id'] . '" data-kirki="' . $type . '">' . self::get_html_using_preview_script($params) . '</' . $type . '>'; //added data-kirki="$type" => We removed theme header and footer using preg_replace in TheFrontendHooks.php file
4327 } else if (!$is_page_symbol_disabled) {
4328 $params['should_take_app_script'] = true;
4329 $params['get_variable'] = true;
4330 $s = self::get_html_using_preview_script($params);
4331 } else if ($is_page_symbol_disabled) {
4332 $s = '<!-- ' . $type . ' is disabled -->';
4333 }
4334 }
4335
4336 $s = do_shortcode($s);
4337
4338 self::$custom_sections[$type] = $s;
4339
4340 return $s;
4341 }
4342
4343 public static function isShowWPThemeHeaderFooter()
4344 {
4345 $common_data = WpAdmin::get_common_data(true);
4346 return $common_data['is_show_wp_theme_header_footer'];
4347 }
4348
4349 /**
4350 * Check if a value is considered true or false.
4351 *
4352 * @param mixed $value The value to check.
4353 * @return bool Returns true if the value is considered "truthy", otherwise false.
4354 *
4355 * @deprecated
4356 * @see function \Kirki\App\is_truthy()
4357 */
4358 public static function isTruthy($value): bool
4359 {
4360 return filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ?? false;
4361 }
4362
4363 /**
4364 * Get the upload directory path has upload or write permission.
4365 *
4366 * @deprecated
4367 * @see Kirki\Framework\Supports\Facades\File::is_writable()
4368 * @see function Kirki\App\get_upload_directory()
4369 */
4370 public static function get_upload_dir_has_write_permission()
4371 {
4372 if (!function_exists('request_filesystem_credentials')) {
4373 require_once ABSPATH . 'wp-admin/includes/file.php';
4374 }
4375
4376 if (WP_Filesystem()) {
4377 global $wp_filesystem;
4378 $upload_dir = wp_upload_dir();
4379 return $wp_filesystem->is_writable($upload_dir['basedir']);
4380 }
4381
4382 return false;
4383 }
4384
4385 /**
4386 * $name = [] or string
4387 * @deprecated
4388 * @see Kirki\App\Supports\Template::add_prefix_to_class_name()
4389 */
4390 public static function add_prefix_to_class_name($prefix, $name)
4391 {
4392 if (is_array($name)) {
4393 foreach ($name as $key => $c) {
4394 $c = strtolower($c);
4395 if (in_array($c, KIRKI_PRESERVED_CLASS_LIST)) {
4396 $name[$key] = $c;
4397 } else {
4398 $name[$key] = $prefix ? strtolower($prefix) . '-' . $c : $c;
4399 }
4400 }
4401 } else {
4402 $name = strtolower($name);
4403 if (!in_array($name, KIRKI_PRESERVED_CLASS_LIST)) {
4404 $name = $prefix ? strtolower($prefix) . '-' . $name : $name;
4405 }
4406 }
4407 return $name;
4408 }
4409
4410 public static function checkVisibilityConditions($element, $options)
4411 {
4412 $conditions = $element['properties']['visibilityConditions'] ?? [];
4413 if (!count($conditions))
4414 return true;
4415 foreach ($conditions as $and_group) {
4416 $and_result = true;
4417 foreach ($and_group as $condition) {
4418 $source = (string) ($condition['source'] ?? 'kirki');
4419 $condition_result = apply_filters('kirki_visibility_condition_check_' . $source, false, $condition, $options);
4420 if (!$condition_result) {
4421 $and_result = false;
4422 break; // If any condition fails in AND group
4423 }
4424 }
4425 if ($and_result) {
4426 return true; // If any OR group passes
4427 }
4428 }
4429 return false; // No group passed
4430 }
4431
4432 private static function update_slider_style_blocks($blocks, $styles)
4433 {
4434
4435 $slider_mask_styleIds = [];
4436 $slider_item_styleIds = [];
4437
4438
4439 // slider_item
4440 foreach ($blocks as $id => $block) {
4441 // Check if the block has a 'name' key
4442 if (isset($block['name'])) {
4443 if (isset($block['name']) && $block['name'] === 'slider_mask') {
4444 // Loop through each item in $block['styleIds']
4445 foreach ($block['styleIds'] as $styleId) {
4446 // Check if the styleId is NOT already in the $slider_mask_styleIds array
4447 if (!in_array($styleId, $slider_mask_styleIds)) {
4448 // If not present, push it into the array
4449 $slider_mask_styleIds[] = $styleId;
4450 }
4451 }
4452 }
4453
4454 if (isset($block['name']) && $block['name'] === 'slider_item') {
4455 // Loop through each item in $block['styleIds']
4456 foreach ($block['styleIds'] as $styleId) {
4457 // Check if the styleId is NOT already in the $slider_item_styleIds array
4458 if (!in_array($styleId, $slider_item_styleIds)) {
4459 // If not present, push it into the array
4460 $slider_item_styleIds[] = $styleId;
4461 }
4462 }
4463 }
4464 }
4465 }
4466
4467 if (count($slider_mask_styleIds) > 0) {
4468 foreach ($slider_mask_styleIds as $styleId) {
4469 if ($styles[$styleId]) {
4470 $style = $styles[$styleId];
4471 $style_variants = $style['variant'];
4472
4473 $styleVariants = [];
4474
4475 if ($style_variants && count($style_variants) > 0) {
4476 foreach ($style_variants as $key => $css) {
4477 $css = preg_replace('/overflow\s*:\s*hidden;?/', '', $css);
4478 $css = preg_replace('/pointer-events\s*:\s*none;?/', '', $css);
4479
4480 $css = trim($css);
4481 $styleVariants[$key] = $css;
4482 }
4483 }
4484 $styles[$styleId]['variant'] = $styleVariants;
4485 }
4486 }
4487 }
4488
4489
4490 if (count($slider_item_styleIds) > 0) {
4491 foreach ($slider_item_styleIds as $styleId) {
4492 $style = $styles[$styleId];
4493 $style_variants = $style['variant'];
4494
4495 $styleVariants = [];
4496
4497 if ($style_variants && count($style_variants) > 0) {
4498 foreach ($style_variants as $key => $css) {
4499 $css = preg_replace('/position\s*:\s*absolute;?/', '', $css);
4500 $css = preg_replace('/display\s*:\s*none;?/', '', $css);
4501
4502 $css = trim($css);
4503 $styleVariants[$key] = $css;
4504 }
4505
4506 $styles[$styleId]['variant'] = $styleVariants;
4507 }
4508 }
4509 }
4510
4511 return $styles;
4512 }
4513
4514 public static function handle_legacy_slider_class()
4515 {
4516 $data = Page::get_all_data_by_kirki_meta_key();
4517
4518 foreach ($data as $key => $value) {
4519 $post_id = $value['post_id']; // ID of the post
4520 $meta_key = $value['meta_key']; // Meta key name
4521 $meta_value = $value['meta_value']; // Serialized meta value
4522
4523 $meta_value = unserialize($meta_value, ['allowed_classes' => false]); // Convert serialized data to array
4524
4525 // If the meta value has a 'blocks' key, handle it as a full page data
4526 if (isset($meta_value['blocks'])) {
4527 $blocks = $meta_value['blocks']; // Get the blocks array
4528 $styles = self::get_page_styleblocks($post_id);
4529 $updated_styles = self::update_slider_style_blocks($blocks, $styles); // Update block names
4530
4531 self::update_page_styleblocks($post_id, $updated_styles);
4532 } else {
4533 // If no 'blocks' key, treat entire value as blocks array
4534 $blocks = $meta_value;
4535 $post = get_post($post_id);
4536
4537
4538 if (isset($post->post_type) && $post->post_type === 'kirki_symbol') {
4539 $styles = $blocks['styleBlocks'];
4540 $updated_styles = self::update_slider_style_blocks($blocks['data'], $styles);
4541 $blocks['styleBlocks'] = $updated_styles;
4542
4543 update_post_meta($post_id, $meta_key, $blocks);
4544 }
4545 }
4546 }
4547 }
4548
4549 public static function handle_legacy_slider_default_class()
4550 {
4551 $styles = self::get_global_data_using_key(KIRKI_GLOBAL_STYLE_BLOCK_META_KEY);
4552 if (!$styles) {
4553 $styles = array();
4554 }
4555 if (count($styles) > 0) {
4556 if (isset($styles['kirki_slider_slide'])) {
4557 // Handle kirki_slider_mask
4558 if (isset($styles['kirki_slider_mask'])) {
4559 $variants = $styles['kirki_slider_mask']['variant'];
4560 if (count($variants) > 0) {
4561 $styleVariants = [];
4562 foreach ($variants as $key => $css) {
4563 $css = preg_replace('/overflow\s*:\s*hidden;?/', '', $css);
4564 $css = preg_replace('/pointer-events\s*:\s*none;?/', '', $css);
4565 $css = trim($css);
4566 $styleVariants[$key] = $css;
4567 }
4568 $styles['kirki_slider_mask']['variant'] = $styleVariants;
4569 }
4570 }
4571
4572 // Handle kirki_slider_slide
4573 if (isset($styles['kirki_slider_slide'])) {
4574 $variants = $styles['kirki_slider_slide']['variant'];
4575 if (count($variants) > 0) {
4576 $styleVariants = [];
4577 foreach ($variants as $key => $css) {
4578 $css = preg_replace('/position\s*:\s*absolute;?/', '', $css);
4579 $css = preg_replace('/display\s*:\s*none;?/', '', $css);
4580 $css = trim($css);
4581 $styleVariants[$key] = $css;
4582 }
4583 $styles['kirki_slider_slide']['variant'] = $styleVariants;
4584 }
4585 }
4586 }
4587 }
4588
4589 }
4590
4591 public static function get_current_item_index($index, $options)
4592 {
4593 $pagination = isset($options['pagination']) ? $options['pagination'] : false;
4594 $items_per_page = isset($options['items_per_page']) ? $options['items_per_page'] : 3;
4595 $page_no = isset($options['page_no']) ? $options['page_no'] : 1;
4596
4597 if ($pagination && $items_per_page > 0 && $page_no > 0) {
4598 // Calculate the start index based on the current page and items per page
4599 $index = (($page_no - 1) * $items_per_page) + $index;
4600 }
4601
4602 return $index;
4603 }
4604
4605 public static function convertToBytes($val)
4606 {
4607 $val = trim($val);
4608 $last = strtolower($val[strlen($val) - 1]);
4609 $val = (int) $val;
4610 switch ($last) {
4611 case 'g':
4612 $val *= 1024;
4613 case 'm':
4614 $val *= 1024;
4615 case 'k':
4616 $val *= 1024;
4617 }
4618 return $val;
4619 }
4620
4621 /**
4622 * @deprecated
4623 * @see Kirki\App\Supports\Canvas::get_full_canvas_template_path()
4624 */
4625 public static function get_kirki_full_canvas_template_path()
4626 {
4627 return self::normalize_kirki_full_canvas_template_path(KIRKI_FULL_CANVAS_TEMPLATE_PATH);
4628 }
4629
4630 /**
4631 * @deprecated
4632 * @see Kirki\App\Supports\Canvas::normalize_full_canvas_template_path()
4633 */
4634 public static function normalize_kirki_full_canvas_template_path($path)
4635 {
4636 // replace if has kirki-pro => kirki
4637 if (strpos($path, 'kirki-pro') !== false) {
4638 $path = str_replace('kirki-pro', 'kirki', $path);
4639 }
4640 return $path;
4641 }
4642 public static function normalize_variable_mode($mode)
4643 {
4644 if (!$mode) {
4645 return ['color' => 'inherit', 'size' => 'inherit', 'text-style' => 'inherit', 'font-family' => 'inherit'];
4646 }
4647 // if v is string
4648 if (is_string($mode)) {
4649 return ['color' => $mode, 'size' => $mode, 'text-style' => $mode, 'font-family' => $mode];
4650 }
4651 if (is_array($mode)) {
4652 return $mode;
4653 }
4654 return $mode;
4655 }
4656 }
4657