PluginProbe ʕ •ᴥ•ʔ
Kirki – Freeform Page Builder, Website Builder & Customizer / 6.1.1
Kirki – Freeform Page Builder, Website Builder & Customizer v6.1.1
6.1.1 6.1.0 6.0.14 6.0.13 6.0.12 6.0.11 6.0.10 6.0.9 6.0.8 6.0.7 6.0.6 6.0.5 6.0.4 6.0.3 6.0.2 6.0.1 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 4.0.19 4.0.20 4.0.21 4.0.22 4.0.23 4.0.24 4.1 4.2.0 5.0.0 5.1.0 5.1.1 5.2.0 5.2.1 5.2.2 5.2.3 6.0.0 trunk 3.0.40 3.0.41 3.0.42 3.0.43 3.0.44 3.0.45 3.1.0 3.1.1 3.1.2
kirki / includes / Ajax / Page.php
kirki / includes / Ajax Last commit date
Collaboration 3 weeks ago Apps.php 3 weeks ago Collection.php 1 month ago Comments.php 2 months ago DynamicContent.php 1 month ago ExportImport.php 3 days ago Form.php 3 weeks ago Media.php 3 days ago Page.php 3 days ago PageSettings.php 3 weeks ago RBAC.php 3 weeks ago Symbol.php 3 weeks ago Taxonomy.php 2 months ago TemplateExportImport.php 2 months ago UserData.php 3 weeks ago Users.php 2 months ago Walkthrough.php 2 months ago WordpressData.php 2 months ago WpAdmin.php 3 days ago
Page.php
1091 lines
1 <?php
2 /**
3 * Page or post data manager
4 *
5 * @package kirki
6 */
7
8 namespace Kirki\Ajax;
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit; // Exit if accessed directly.
12 }
13 use Kirki\HelperFunctions;
14 use Kirki\Staging;
15
16 /**
17 * Page API Class
18 */
19 class Page {
20
21 const TYPE_FORGOT_PASSWORD = 'forgot_password';
22 const TYPE_RESET_PASSWORD = 'reset_password';
23
24 /**
25 * Save page data
26 *
27 * @return void wp_send_json.
28 *
29 * @deprecated
30 * @see Kirki\App\Services\PageService::save_page_data()
31 */
32 public static function save_page_data() {
33 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
34 $page_data = isset( $_POST['data'] ) ? $_POST['data'] : null;
35 $page_data = json_decode( stripslashes( $page_data ), true );
36 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
37 $post_id = (int) HelperFunctions::sanitize_text( isset( $_POST['id'] ) ? $_POST['id'] : '' );
38 $is_staging = isset( $_POST['is_staging'] ) ? HelperFunctions::sanitize_text( $_POST['is_staging'] ) : false;
39
40 if ( ! empty( $page_data ) && ! empty( $post_id ) ) {
41
42 $version_where_saved = HelperFunctions::save_kirki_data_to_db( $post_id, $page_data, $is_staging );
43
44 $post = get_post( $post_id );
45 $arr = array(
46 'ID' => $post->ID,
47 'type' => $post->post_type,
48 );
49 $post_id = wp_update_post( $arr );
50 wp_send_json(
51 array(
52 'status' => 'Page data saved.',
53 'staging_version' => $version_where_saved,
54 )
55 );
56 } else {
57 wp_send_json( array( 'status' => 'Page data save failed!' ) );
58 }
59 die();
60 }
61
62 /**
63 * Delete page
64 *
65 * @return void wp_send_json.
66 *
67 * @deprecated
68 * @see Kirki\App\Services\PageService::delete_page()
69 */
70 public static function delete_page() {
71 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
72 $id = (int) HelperFunctions::sanitize_text( isset( $_POST['id'] ) ? $_POST['id'] : '' );
73 $post = get_post( $id );
74 wp_delete_post( $id );
75 if ( $post && $post->post_type === 'kirki_utility' ) {
76 self::flush_utility_rewrite_rules();
77 }
78 wp_send_json( array( 'status' => 'Page deleted' ) );
79 }
80
81 /**
82 * Add new page
83 *
84 * @return void wp_send_json.
85 *
86 * @deprecated
87 * @see Kirki\App\Services\PageService::save()
88 */
89 public static function add_new_page() {
90 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
91 $options = isset( $_POST['options'] ) ? $_POST['options'] : null;
92 $options = json_decode( stripslashes( $options ), true );
93
94 if ( HelperFunctions::user_has_post_edit_access() ) {
95 $post_id = wp_insert_post(
96 array(
97 'post_title' => $options['post_title'],
98 'post_name' => $options['post_title'],
99 // check if type = kirki_page then change it to wp page type. cause we only set template if page type is kirki_page.
100 'post_type' => $options['post_type'] === 'kirki_page' ? 'page' : $options['post_type'],
101 )
102 );
103
104 if ( isset( $options['blocks'] ) ) {
105 // this is for popup creation. cause popup has predefined blocks.
106 update_post_meta( $post_id, 'kirki', $options['blocks'] );
107 }
108
109 if ( isset( $options['conditions'] ) ) {
110 // this is for template creation. cause popup has predefined conditions.
111 update_post_meta( $post_id,'kirki_template_conditions', $options['conditions'] );
112 }
113
114 // TODO: need to remove this code. after checking collection_type used or not
115 if ( isset( $options['collection_type'] ) && ! empty( $options['collection_type'] ) ) {
116 update_post_meta( $post_id,'kirki_template_collection_type', $options['collection_type'] );
117 }
118
119 if ( isset( $options['utility_page_type'] ) && ! empty( $options['utility_page_type'] ) ) {
120 update_post_meta( $post_id,'kirki_utility_page_type', $options['utility_page_type'] );
121 }
122
123 update_post_meta( $post_id, KIRKI_META_NAME_FOR_POST_EDITOR_MODE, 'kirki' );
124 if ( $options['post_type'] === 'page' || $options['post_type'] === 'kirki_page' ) {
125 // check if type = kirki_page then change it to wp page type. cause we only set template if page type is kirki_page.
126 update_post_meta( $post_id, '_wp_page_template', HelperFunctions::get_kirki_full_canvas_template_path() );
127 }
128
129 if ( $options['post_type'] ==='kirki_utility' ) {
130 self::initialize_predefine_template_data( $post_id, $options['utility_page_type'] );
131 self::flush_utility_rewrite_rules();
132 }
133
134 if ( isset( $options['custom_template'] ) && ! empty( $options['custom_template'] ) &&
135 isset( $options['custom_template']['url'] ) && ! empty( $options['custom_template']['url'] ) ) {
136 self::add_custom_template_to_page( $post_id, $options['custom_template']['url'] );
137 }
138
139 wp_send_json( ( new self() )->format_single_post( $post_id ) );
140 } else {
141 wp_send_json_error( 'Limited permission', 403 );
142 }
143 }
144
145 /**
146 * @deprecated
147 * @see \Kirki\App\Supports\Template::assign_utility_page_template()
148 */
149 public static function initialize_predefine_template_data( $post_id, $type ) {
150 if ( $type === '404' || $type === 'login' || $type === 'sign_up' || $type === 'forgot_password' || $type === 'reset_password' || $type === 'retrive_username' ) {
151 self::fetch_template_data( $post_id, $type );
152 }
153 }
154
155 /**
156 * @deprecated
157 * @see \Kirki\App\Supports\Template::assign_custom_page_template()
158 */
159 public static function add_custom_template_to_page( $post_id, $template_url ) {
160 self::fetch_template_data( $post_id, $template_url, true );
161 }
162
163 /**
164 * @deprecated
165 * @see \Kirki\App\Supports\Template::process_template()
166 */
167 public static function fetch_template_data( $post_id, $type, $custom = false ) {
168 $zip_file_path = KIRKI_PUBLIC_ASSETS_URL . '/pre-built-pages/basic/' . $type . '.zip';
169 if ( $custom ) {
170 $zip_file_path = $type;
171 }
172 $file_name_new = uniqid( '', true ) . '.zip'; // 'random.ext'
173 $zip_file_path = HelperFunctions::download_zip_from_remote( $zip_file_path, $file_name_new );
174 if ( $zip_file_path ) {
175 $d = ExportImport::process_kirki_template_zip( $zip_file_path, false, $post_id );
176 if ( $d ) {
177 // delete zip file
178 wp_delete_file( $zip_file_path );
179 return true;
180 } else {
181 wp_send_json_error( 'Failed to extract zip file' );
182 }
183 } else {
184 wp_send_json_error( 'Failed to download zip file' );
185 }
186 }
187
188 /**
189 * Update current page data
190 *
191 * @return void wp_send_json.
192 * @deprecated
193 * @see \Kirki\App\Services\PageService::update()
194 * @see \Kirki\App\Services\PageService::update_popup_data()
195 */
196 public static function update_page_data() {
197 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
198 $options = isset( $_POST['options'] ) ? $_POST['options'] : null;
199 $options = json_decode( stripslashes( $options ), true );
200 $arr = array();
201 if ( isset( $options['ID'] ) ) {
202 $arr['ID'] = $options['ID'];
203 $post_id = $arr['ID'];
204 if ( isset( $options['post_title'] ) ) {
205 $arr['post_title'] = $options['post_title'];
206 }
207 if ( isset( $options['post_name'] ) ) {
208 $arr['post_name'] = $options['post_name'];
209 }
210 if ( isset( $options['post_status'] ) ) {
211 $arr['post_status'] = $options['post_status'];
212 }
213 wp_update_post( $arr );
214
215 if ( isset( $options['blocks'] ) ) {
216 update_post_meta( $post_id, 'kirki', $options['blocks'] );
217 }
218 if ( isset( $options['styleBlocks'] ) ) {
219 update_post_meta( $post_id, KIRKI_GLOBAL_STYLE_BLOCK_META_KEY . '_random', $options['styleBlocks'] );
220 }
221 if ( isset( $options['usedFonts'] ) ) {
222 update_post_meta( $post_id, KIRKI_META_NAME_FOR_USED_FONT_LIST, $options['usedFonts'] );
223 }
224 if ( isset( $options['conditions'] ) ) {
225 update_post_meta( $post_id,'kirki_template_conditions', $options['conditions'] );
226 }
227 if ( isset( $options['variableMode'] ) ) {
228 update_post_meta( $post_id, 'kirki_variable_mode', $options['variableMode'] );
229 }
230 if ( isset( $options['post_name'] ) ) {
231 $post = get_post( $post_id );
232 if ( $post && $post->post_type === 'kirki_utility' ) {
233 self::flush_utility_rewrite_rules();
234 }
235 }
236 wp_send_json( ( new self() )->format_single_post( $post_id ) );
237 die();
238 } else {
239 wp_send_json( array( 'status' => 'Page data update failed' ) );
240 die();
241 }
242 }
243
244 /**
245 * Duplicate page data
246 *
247 * @return void wp_send_json.
248 * @deprecated
249 * @see \Kirki\App\Services\PageService::duplicate_page()
250 */
251 public static function duplicate_page() {
252 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
253 $post_id = (int) HelperFunctions::sanitize_text( isset( $_POST['id'] ) ? $_POST['id'] : '' );
254 $post = get_post( $post_id );
255 $new_post_id = wp_insert_post(
256 array(
257 'post_title' => $post->post_title . ' (copy)',
258 'post_content' => $post->post_content,
259 'post_name' => $post->post_name,
260 'post_type' => $post->post_type,
261 'post_status' => $post->post_status,
262 )
263 );
264
265 $page_data = get_post_meta( $post_id, 'kirki', true );
266 if ( $page_data ) {
267 update_post_meta( $new_post_id, 'kirki', $page_data );
268 update_post_meta( $new_post_id, KIRKI_META_NAME_FOR_POST_EDITOR_MODE, 'kirki' );
269 }
270
271 /**
272 * Also duplicate _wp_page_template meta if exists
273 */
274 $page_template = get_post_meta( $post_id, '_wp_page_template', true );
275 if ( $page_template ) {
276 $page_template = HelperFunctions::normalize_kirki_full_canvas_template_path($page_template);
277 update_post_meta( $new_post_id, '_wp_page_template', $page_template );
278 }
279
280 /**
281 * Also duplicate this page style blocks if exists
282 */
283 $post_styles = get_post_meta( $post_id, KIRKI_GLOBAL_STYLE_BLOCK_META_KEY . '_random', true );
284 if ( $post_styles ) {
285 update_post_meta( $new_post_id, KIRKI_GLOBAL_STYLE_BLOCK_META_KEY . '_random', $post_styles );
286 }
287
288 $used_fonts = get_post_meta( $post_id, KIRKI_META_NAME_FOR_USED_FONT_LIST, true );
289 if ( $used_fonts ) {
290 update_post_meta( $new_post_id, KIRKI_META_NAME_FOR_USED_FONT_LIST, $used_fonts );
291 }
292
293 if ( $post && $post->post_type === 'kirki_utility' ) {
294 self::flush_utility_rewrite_rules();
295 }
296
297 wp_send_json( ( new self() )->format_single_post( $new_post_id ) );
298 }
299
300 /**
301 * Back to kirki editor
302 *
303 * @return void wp_send_json.
304 *
305 * @deprecated
306 * @see \Kirki\App\Services\EditorService::back_to_kirki_editor()
307 */
308 public static function back_to_kirki_editor() {
309 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
310 $post_id = (int) HelperFunctions::sanitize_text( isset( $_POST['postId'] ) ? $_POST['postId'] : '' );
311
312 $post = get_post( $post_id );
313
314 if ( $post->post_status === 'auto-draft' ) {
315 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
316 $post_title = HelperFunctions::sanitize_text( isset( $_POST['title'] ) ? $_POST['title'] : null );
317
318 if ( ! isset( $post_title ) ) {
319 $post_title = 'Untitled';
320 }
321
322 $data = array(
323 'ID' => $post_id,
324 'post_title' => $post_title,
325 'post_name' => $post_title,
326 'post_status' => 'draft',
327 );
328 wp_update_post( $data );
329 }
330
331 update_post_meta( $post_id, '_wp_page_template', HelperFunctions::get_kirki_full_canvas_template_path() );
332 wp_send_json( array( 'status' => true ) );
333 }
334
335 /**
336 * Back to WordPress editor
337 *
338 * @return void wp_send_json.
339 *
340 * @deprecated
341 * @see \Kirki\App\Services\EditorService::back_to_wordpress_editor()
342 */
343 public static function back_to_wordpress_editor() {
344 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
345 $post_id = (int) HelperFunctions::sanitize_text( isset( $_POST['postId'] ) ? $_POST['postId'] : '' );
346
347 delete_post_meta( $post_id, KIRKI_META_NAME_FOR_POST_EDITOR_MODE );
348 wp_send_json( array( 'status' => true ) );
349 }
350
351 /**
352 * This function is called from EDITOR panel
353 *
354 * @return void wp_send_json.
355 *
356 * @deprecated
357 * @see \Kirki\App\Resources\PageContentResource::class
358 */
359 public static function get_page_blocks_and_styles() {
360 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
361 $post_id = (int) HelperFunctions::sanitize_text( isset( $_GET['id'] ) ? $_GET['id'] : '' );
362 $stage_version = HelperFunctions::sanitize_text( isset( $_GET['stage_version'] ) ? intval( $_GET['stage_version'] ) : false );
363 if ( ! $stage_version ) {
364 $stage_version = Staging::get_most_recent_stage_version( $post_id, false );
365 }
366
367 if ( ! empty( $post_id ) ) {
368 $post_meta = get_post_meta( $post_id, 'kirki', true );
369 if ( ! $post_meta ) {
370 $post_meta = array();
371 $post_meta['blocks'] = null;
372 }
373
374 if ( $stage_version ) {
375 $meta_name = Staging::get_staged_meta_name( 'kirki', $post_id, $stage_version );
376 $staging_post_meta = get_post_meta( $post_id, $meta_name, true );
377 if ( $staging_post_meta ) {
378 $post_meta = $staging_post_meta;
379 }
380 }
381
382 $styles = HelperFunctions::get_page_styleblocks( $post_id, $stage_version );
383 $post_meta['styles'] = $styles;
384
385 $post_meta['preview_url'] = HelperFunctions::get_post_url_arr_from_post_id( $post_id, array( 'preview_url' => true ) )['preview_url'];
386
387 $post_meta['is_kirki_editor_mode'] = HelperFunctions::is_editor_mode_is_kirki( $post_id );
388
389 $content = get_the_content( null, false, $post_id );
390 $post_meta['content_length'] = strlen( $content );
391 wp_send_json( $post_meta );
392 }
393 die();
394 }
395
396 public static function get_page_html() {
397 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
398 $post_id = (int) HelperFunctions::sanitize_text( isset( $_GET['id'] ) ? $_GET['id'] : '' );
399 if ( ! empty( $post_id ) ) {
400 $post_meta = get_post_meta( $post_id, 'kirki', true );
401 if ( ! $post_meta ) {
402 $post_meta = array();
403 $post_meta['blocks'] = null;
404 }
405
406 $params = array(
407 'blocks' => $post_meta['blocks'],
408 'style_blocks' => null,
409 'root' => 'root',
410 'post_id' => false,
411 'options' => array( 'check_access' => false ),
412 'get_style' => false,
413 'get_variable' => false,
414 'should_take_app_script' => false,
415 );
416
417 $html = HelperFunctions::get_html_using_preview_script( $params );
418 wp_send_json( $html );
419 }
420 die();
421 }
422
423 /**
424 * Format single post data
425 *
426 * @param int $post_id post id.
427 * @return object|null post with custom data.
428 *
429 * @deprecated
430 * @see \Kirki\App\Resources\PageResource
431 */
432 public function format_single_post( $post_id ) {
433 $post = get_post( $post_id );
434 if ( $post ) {
435 $page = array();
436 if ('kirki_popup' === $post->post_type ) {
437 $page['blocks'] = get_post_meta( $post->ID, 'kirki', true );
438 $page['styleBlocks'] = get_post_meta( $post->ID, KIRKI_GLOBAL_STYLE_BLOCK_META_KEY . '_random', true );
439 $page['usedFonts'] = get_post_meta( $post->ID, KIRKI_META_NAME_FOR_USED_FONT_LIST, true );
440 }
441
442 if ('kirki_template' === $post->post_type ) {
443 $conditions = get_post_meta( $post->ID,'kirki_template_conditions', true );
444 $page['conditions'] = $conditions ? $conditions : array();
445 $collection_type = get_post_meta( $post->ID,'kirki_template_collection_type', true );
446 $page['collection_type'] = $collection_type ? $collection_type : '';
447 }
448
449 if ('kirki_utility' === $post->post_type ) {
450 $utility_type_page = get_post_meta( $post->ID,'kirki_utility_page_type', true );
451 $page['utility_page_type'] = $utility_type_page ? $utility_type_page : '';
452 }
453
454 $temp_urls = HelperFunctions::get_post_url_arr_from_post_id(
455 $post->ID,
456 array(
457 'preview_url' => true,
458 'editor_url' => true,
459 )
460 );
461 $page['preview_url'] = $temp_urls['preview_url'];
462 $page['editor_url'] = $temp_urls['editor_url'];
463
464 $page['id'] = $post->ID;
465 $page['title'] = $post->post_title;
466 $page['status'] = $post->post_status;
467 $page['post_type'] = $post->post_type;
468 $page['post_parent'] = $post->post_parent;
469 $page['slug'] = $post->post_name;
470 $page['variableMode'] = self::get_variable_mode( $post->ID );
471 $page['isFrontPage'] = get_option( 'page_on_front' ) == $post->ID ? true : false;
472
473 $disabled_page_symbols = get_post_meta( $post_id, KIRKI_META_NAME_FOR_PAGE_HF_SYMBOL_DISABLE_STATUS, true );
474 if ( ! isset( $disabled_page_symbols ) || ! is_array( $disabled_page_symbols ) ) {
475 $disabled_page_symbols = array();
476 }
477 $page['disabled_page_symbols'] = $disabled_page_symbols;
478 $page = self::add_published_staged_info( $page );
479
480 return $page;
481 }
482 return null;
483 }
484
485 /**
486 * @deprecated
487 * @see \Kirki\App\Resources\PageResource::get_staged_last_updated()
488 */
489 public static function add_published_staged_info( $page ){
490 $staged_info = Staging::get_published_stage_version_info( $page['id'] );
491 $page['staged_last_updated'] = isset($staged_info['last_updated']) ? $staged_info['last_updated'] : null;
492 return $page;
493 }
494
495 /**
496 * @deprecated
497 * @see \Kirki\App\Managers\PageManager::get_variable_mode()
498 */
499 public static function get_variable_mode( $post_id ) {
500 $variable_mode = get_post_meta( $post_id, 'kirki_variable_mode', true );
501 return $variable_mode ? $variable_mode : 'inherit';
502 }
503
504 /**
505 * Fetch page list
506 *
507 * @return void wp_send_json.
508 */
509 public static function fetch_list_api() {
510 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
511 $post_types = HelperFunctions::sanitize_text( isset( $_GET['post_types'] ) ? $_GET['post_types'] : '[]' );
512 $post_types = json_decode( $post_types, true );
513 $exclude_post_ids = json_decode( HelperFunctions::sanitize_text( isset( $_GET['exclude_post_ids'] ) ? $_GET['exclude_post_ids'] : '[]' ), true );
514
515 $query = HelperFunctions::sanitize_text( isset( $_GET['query'] ) ? $_GET['query'] : null );
516 $numberposts = HelperFunctions::sanitize_text( isset( $_GET['numberposts'] ) ? $_GET['numberposts'] : 20 );
517
518 $page_list = array();
519 if ( HelperFunctions::user_has_post_edit_access() ) {
520 $page_list = static::fetch_list( $post_types, true, array( 'publish', 'draft' ), $query, $numberposts, 1, $exclude_post_ids );
521 }
522
523 wp_send_json( $page_list );
524 }
525
526 public static function get_pages_for_pages_panel() {
527 // Sanitize and validate inputs
528 $query = HelperFunctions::sanitize_text( isset( $_GET['query'] ) ? $_GET['query'] : null );
529 $page = HelperFunctions::sanitize_text( isset( $_GET['page'] ) ? $_GET['page'] : 1 );
530 $numberposts = intval( HelperFunctions::sanitize_text( isset( $_GET['numberposts'] ) ? $_GET['numberposts'] : 20 ) );
531 $post_types = HelperFunctions::sanitize_text( isset( $_GET['post_types'] ) ? $_GET['post_types'] : '[]' );
532 $post_types = json_decode( $post_types, true );
533
534 // Set a default post type if not provided
535 if ( empty( $post_types ) ) {
536 $post_types = array( 'page' ); // Default to pages if no post types are provided
537 }
538 $page_list = array();
539 $page_list = static::fetch_list( $post_types, true, array( 'publish', 'draft' ), $query, $numberposts, $page );
540 // if ( HelperFunctions::user_has_page_edit_access() ) {
541 // }
542
543 // Get total posts count
544 $total_arg = array(
545 'post_type' => $post_types,
546 'post_status' => array( 'publish', 'draft' ),
547 'posts_per_page' => -1,
548 'fields' => 'ids',
549 );
550 if ( $query ) {
551 $total_arg['s'] = $query;
552 }
553 $total_posts = count(get_posts($total_arg));
554
555 // Return the data as a JSON response
556 wp_send_json_success( array(
557 'pages' => $page_list,
558 'total' => $total_posts,
559 ) );
560 }
561
562 /**
563 * Fetch post list for search
564 *
565 * @return void wp_send_json.
566 */
567 public static function get_data_list_for_template_edit_search_flyout() {
568 $query = HelperFunctions::sanitize_text( isset( $_GET['query'] ) ? $_GET['query'] : '' );
569 $conditions = HelperFunctions::sanitize_text( isset( $_GET['conditions'] ) ? $_GET['conditions'] : array() );
570 $conditions = json_decode( $conditions, true );
571 $data = HelperFunctions::get_collection_items_from_conditions( $conditions, $query );
572 wp_send_json( $data['data'] );
573 }
574
575 /**
576 * Get all post types and found the all post types that are not discarded post types
577 *
578 * @return void wp_send_json
579 */
580 public static function fetch_post_list_data_post_type_wise() {
581
582 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
583 $search_query = HelperFunctions::sanitize_text( isset( $_GET['search'] ) ? $_GET['search'] : '' );
584
585 $post_types = get_post_types();
586 $discarded_post_types = array( 'attachment', 'custom_css', 'customize_changeset', 'wp_global_styles', 'revision', 'nav_menu_item', 'oembed_cache', 'user_request', 'wp_block', 'wp_template', 'wp_template_part', 'wp_navigation' );
587
588 $post_types['kirki_template'] = 'kirki_template';
589 $post_types['kirki_utility'] = 'kirki_utility';
590 $post_types['kirki_popup'] = 'kirki_popup';
591
592 $post_types = array_diff_key( $post_types, array_flip( $discarded_post_types ) );
593
594 $args = array(
595 'post_type' => $post_types,
596 's' => $search_query,
597 'posts_per_page' => -1,
598 'post_status' => 'any',
599 );
600
601 $all_posts = get_posts( $args );
602 $data = array();
603
604 // Post types to be grouped under "page"
605 $group_under_page = array( 'kirki_template', 'kirki_utility', 'kirki_page' );
606
607 foreach ( $all_posts as $p ) {
608 $single_post = array(
609 'id' => $p->ID,
610 'title' => $p->post_title,
611 'editor_url' => HelperFunctions::get_post_url_arr_from_post_id( $p->ID, array( 'editor_url' => true ) )['editor_url'],
612 );
613
614 // Normalize post_type
615 $type_key = in_array( $p->post_type, $group_under_page, true ) ? 'page' : $p->post_type;
616 $data[ $type_key ][] = $single_post;
617 }
618
619 wp_send_json( $data );
620 }
621
622 /**
623 * Fetch page list
624 * if $internal is true then it will return array
625 * otherwise it will return json for api call
626 *
627 * @param string $type post type.
628 * @param boolean $internal if this method call from internal response.
629 * @param string $post_status post status.
630 *
631 * @return void|array
632 */
633 public static function fetch_list( $type = 'page', $internal = true, $post_status = array( 'publish', 'draft' ), $query = null, $numberposts = 20, $current_page = 1, $exclude_post_ids = array() ) {
634 $pages = array();
635
636 $arg = array(
637 'post_type' => $type,
638 'post_status' => $post_status,
639 // 'numberposts' => $numberposts,
640 'orderby' => 'ID',
641 'order' => 'DESC',
642 'posts_per_page' => $numberposts,
643 'paged' => $current_page,
644 'post__not_in' => $exclude_post_ids,
645 );
646 if ( $query ) {
647 $arg['s'] = $query;
648 }
649
650 $posts = get_posts( $arg );
651
652 if ( ! empty( $posts ) ) {
653 foreach ( $posts as $post ) {
654
655 /**
656 * If page template type is kirki full page then check if GET['type'] is set to kirki_page otherwise send any page type data
657 */
658 $pages[] = ( new self() )->format_single_post( $post->ID );
659 }
660 }
661
662 // $pages items has isFrontPage true then add it to first position of array also do not duplicate same item
663 $frontPage = null;
664
665 foreach ($pages as $key => $page) {
666 if ($page['isFrontPage']) {
667 $frontPage = $page;
668 unset($pages[$key]); // remove original to avoid duplication
669 break;
670 }
671 }
672
673 if ($frontPage) {
674 array_unshift($pages, $frontPage); // add to first position
675 }
676
677 $pages = array_values($pages); // reindex array
678
679 if ( $internal ) {
680 return $pages;
681 }
682 wp_send_json( $pages );
683 }
684
685 /**
686 * Get current page data
687 *
688 * @return void wp_send_json.
689 */
690 public static function get_current_page_data() {
691 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
692 $post_id = (int) HelperFunctions::sanitize_text( isset( $_GET['id'] ) ? $_GET['id'] : '' );
693 $post_formatted = null;
694 if ( $post_id ) {
695 $post_formatted = ( new self() )->format_single_post( $post_id );
696 }
697 wp_send_json( $post_formatted );
698 }
699
700 /**
701 * Remove all unused style blocks from option meta
702 * it will collect all posts unused style block id
703 * then it will remove all unused style blocks from option meta
704 *
705 * @return void wp_send_json.
706 *
707 */
708 public static function remove_unused_style_block_from_db() {
709 $post_id = (int) HelperFunctions::sanitize_text( $_POST['post_id'] ?? '' );
710
711 if ( ! $post_id || ! get_post( $post_id ) ) {
712 wp_send_json_error( array( 'message' => 'Invalid post ID.' ) );
713 }
714
715 $all_post_ids = self::get_all_post_ids();
716 $all_used_style_ids = array_flip( self::get_all_used_style_ids() ); // faster lookup
717
718 // Helper to clean any style array
719 /**
720 * @see Kirki\App\Managers\PageManager::clean_styles()
721 */
722 $clean_styles = function ( array $styles ) use ( $all_used_style_ids ) {
723 $changed = false;
724 foreach ( $styles as $key => $style ) {
725 if ( ! isset( $all_used_style_ids[ $key ] ) && empty( $style['isDefault'] ) ) {
726 unset( $styles[ $key ] );
727 $changed = true;
728 }
729 }
730 return array( $styles, $changed );
731 };
732
733 // Clean global styles.
734 $all_global_styles = HelperFunctions::get_global_data_using_key( KIRKI_GLOBAL_STYLE_BLOCK_META_KEY ) ? HelperFunctions::get_global_data_using_key( KIRKI_GLOBAL_STYLE_BLOCK_META_KEY ) : array();
735 $result = (array) $clean_styles( $all_global_styles );
736 $all_global_styles = $result[0] ?? array();
737 $changed = $result[1] ?? false;
738 if ( $changed ) {
739 HelperFunctions::save_global_style_blocks( $all_global_styles );
740 }
741
742 // Clean post styles
743 foreach ( $all_post_ids as $p_id ) {
744 // Random styles
745 $post_styles = get_post_meta( $p_id, KIRKI_GLOBAL_STYLE_BLOCK_META_KEY . '_random', true ) ?: array();
746 $temp_result = (array) $clean_styles( $post_styles );
747 $post_styles = $temp_result[0] ?? array();
748 $changed = $temp_result[1] ?? false; // $changed
749 if ( $changed ) {
750 HelperFunctions::save_random_style_blocks( $p_id, $post_styles );
751 }
752
753 // Staged styles
754 $most_recent_stage_id = Staging::get_most_recent_unpublished_stage_id( $p_id );
755 if ( $most_recent_stage_id ) {
756 foreach ( array(
757 KIRKI_GLOBAL_STYLE_BLOCK_META_KEY,
758 KIRKI_GLOBAL_STYLE_BLOCK_META_KEY . '_random',
759 ) as $meta_key_base ) {
760 $meta_key = Staging::get_staged_meta_name( $meta_key_base, $p_id, $most_recent_stage_id );
761 $staged_styles = get_post_meta( $p_id, $meta_key, true ) ? get_post_meta( $p_id, $meta_key, true ) : array();
762
763 $temp_styles = $clean_styles( $staged_styles );
764
765 $staged_styles = $temp_styles[0] ?? array();
766 $changed = $temp_styles[1] ?? false;
767
768 if ( $changed ) {
769 HelperFunctions::save_staged_style_blocks( $p_id, $meta_key, $staged_styles );
770 }
771 }
772 }
773 }
774
775 wp_send_json(
776 array(
777 'status' => 'success',
778 'data' => HelperFunctions::get_page_styleblocks( $post_id ),
779 )
780 );
781 }
782 /**
783 * Get unused class info from db
784 *
785 * @param boolean $internal if this method call from internally.
786 * @return void|array wp_send_json.
787 */
788 public static function get_unused_class_info_from_db( $internal = false ) {
789 $all_post_ids = self::get_all_post_ids();
790 $all_used_style_ids = self::get_all_used_style_ids();
791
792 // Add global style IDs
793 $all_style_ids = array();
794
795 // Add global style IDs exclude default
796 $global_styles = HelperFunctions::get_global_data_using_key( KIRKI_GLOBAL_STYLE_BLOCK_META_KEY ) ?: array();
797 foreach ( $global_styles as $key => $style ) {
798 if ( empty( $style['isDefault'] ) ) {
799 $all_style_ids[] = $key;
800 }
801 }
802
803 // Add all post style IDs excluding default
804 foreach ( $all_post_ids as $p_id ) {
805 $post_styles = get_post_meta( $p_id, KIRKI_GLOBAL_STYLE_BLOCK_META_KEY . '_random', true ) ?: array();
806 foreach ( $post_styles as $key => $style ) {
807 if ( empty( $style['isDefault'] ) ) {
808 $all_style_ids[] = $key;
809 }
810 }
811 }
812
813 $all_style_ids = array_unique( $all_style_ids );
814
815 // Filter out any IDs that are used anywhere
816 $common_unused = array_values(
817 array_filter(
818 $all_style_ids,
819 function ( $id ) use ( $all_used_style_ids ) {
820 return ! in_array( $id, $all_used_style_ids, true );
821 }
822 )
823 );
824
825 if ( $internal ) {
826 return $common_unused;
827 }
828
829 wp_send_json(
830 array(
831 'status' => 'success',
832 'data' => $common_unused,
833 )
834 );
835 }
836
837 /**
838 * Collect all post IDs (including draft, published)
839 *
840 * @return array
841 *
842 * @deprecated
843 * @see \Kirki\App\Managers\PageManager::get_all_block_post_ids()
844 */
845 private static function get_all_post_ids() {
846 global $wpdb;
847
848 $results = $wpdb->get_col(
849 $wpdb->prepare(
850 "SELECT DISTINCT pm.post_id
851 FROM {$wpdb->postmeta} AS pm
852 INNER JOIN {$wpdb->posts} AS p ON p.ID = pm.post_id
853 WHERE pm.meta_key = %s
854 AND p.post_type NOT IN (%s, %s)",
855 'kirki',
856 'kirki_symbol',
857 'kirki_popup'
858 )
859 );
860
861 return $results;
862 }
863
864 /**
865 * Collect all used style IDs across published + most recent staged version.
866 *
867 * @return array
868 */
869 private static function get_all_used_style_ids() {
870 $all_post_ids = self::get_all_post_ids();
871 $all_used_style_ids = array();
872
873 foreach ( $all_post_ids as $p_id ) {
874 // Published
875 $published_used_ids = get_post_meta( $p_id, KIRKI_META_NAME_FOR_USED_STYLE_BLOCK_IDS, true ) ?: array();
876 $published_used_ids_random = get_post_meta( $p_id, KIRKI_META_NAME_FOR_USED_STYLE_BLOCK_IDS . '_random', true ) ?: array();
877 $published_used_ids = array_unique( array_merge( $published_used_ids, $published_used_ids_random ) );
878
879 // Most recent staged
880 $most_recent_stage_id = Staging::get_most_recent_unpublished_stage_id( $p_id );
881 $staged_used_ids = array();
882 if ( $most_recent_stage_id ) {
883 $staged_used_keys = array(
884 Staging::get_staged_meta_name( KIRKI_META_NAME_FOR_USED_STYLE_BLOCK_IDS, $p_id, $most_recent_stage_id ),
885 Staging::get_staged_meta_name( KIRKI_META_NAME_FOR_USED_STYLE_BLOCK_IDS . '_random', $p_id, $most_recent_stage_id ),
886 );
887 foreach ( $staged_used_keys as $key ) {
888 $staged_used_ids = array_merge( $staged_used_ids, get_post_meta( $p_id, $key, true ) ?: array() );
889 }
890 }
891
892 $all_used_style_ids = array_merge( $all_used_style_ids, $published_used_ids, $staged_used_ids );
893 }
894
895 return array_unique( $all_used_style_ids );
896 }
897
898 public static function validate_wp_post_slug() {
899 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
900 $post_id = (int) HelperFunctions::sanitize_text( isset( $_GET['post_id'] ) ? $_GET['post_id'] : '' );
901 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
902 $post_type = HelperFunctions::sanitize_text( isset( $_GET['post_type'] ) ? $_GET['post_type'] : '' );
903 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
904 $post_name = HelperFunctions::sanitize_text( isset( $_GET['post_name'] ) ? $_GET['post_name'] : '' );
905
906 wp_send_json(
907 array(
908 'status' => 'success',
909 'data' => HelperFunctions::validate_slug( $post_id, $post_type, $post_name ),
910 )
911 );
912 }
913
914 /**
915 * @deprecated
916 * @see function \Kirki\App\soft_flush_rewrite_rules()
917 */
918 private static function flush_utility_rewrite_rules() {
919 flush_rewrite_rules( false );
920 }
921
922 public static function get_editor_read_only_access_data() {
923 wp_send_json(
924 array(
925 'status' => 'success',
926 'data' => self::format_editor_access_data(),
927 )
928 );
929 }
930
931 private static function format_editor_access_data() {
932 $status = HelperFunctions::get_global_data_using_key( 'kirki_editor_read_only_access_status' );
933 $arr = array(
934 'status' => $status ? $status : false,
935 'url' => self::get_post_read_only_access_url(),
936 );
937 return $arr;
938 }
939
940 public static function save_editor_read_only_access_data() {
941 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
942 $data = isset( $_POST['data'] ) ? $_POST['data'] : null;
943 $data = json_decode( stripslashes( $data ), true );
944
945 if ( $data['type'] === 'status' ) {
946 HelperFunctions::update_global_data_using_key( 'kirki_editor_read_only_access_status', HelperFunctions::sanitize_text( $data['status'] ) );
947 }
948
949 if ( $data['type'] === 'regenerate' ) {
950 self::generate_read_only_access_token();
951 }
952
953 wp_send_json(
954 array(
955 'status' => 'success',
956 'data' => self::format_editor_access_data(),
957 )
958 );
959 }
960
961 private static function get_post_read_only_access_url() {
962 $token = HelperFunctions::get_global_data_using_key( 'kirki_editor_read_only_access_token' );
963 if ( ! $token ) {
964 $token = self::generate_read_only_access_token();
965 }
966
967 // Try to get the home page ID first
968 $home_page_id = get_option( 'page_on_front' ); // Retrieves the ID of the homepage if set
969
970 if ( $home_page_id ) {
971 $home_page_url_arr = HelperFunctions::get_post_url_arr_from_post_id( $home_page_id, array( 'editor_url' => true ) );
972 return esc_url( $home_page_url_arr['editor_url'] ) . '&editor-preview-token=' . $token;
973 }
974
975 // If no homepage is set, fallback to the last edited kirki editor page
976 $last_edited_kirki_editor_page = HelperFunctions::get_last_edited_kirki_editor_type_page();
977 if ( $last_edited_kirki_editor_page ) {
978 $last_edited_kirki_editor_page_url_arr = HelperFunctions::get_post_url_arr_from_post_id( $last_edited_kirki_editor_page->ID, array( 'editor_url' => true ) );
979 return esc_url( $last_edited_kirki_editor_page_url_arr['editor_url'] ) . '&editor-preview-token=' . $token;
980 }
981
982 // If neither the home page nor the last edited page is found, default to home URL
983 return home_url( '?action=kirki&editor-preview-token=' . $token );
984 }
985
986 private static function generate_read_only_access_token() {
987 $token = wp_generate_password( 32, false, false ); // Generate a secure random token
988 HelperFunctions::update_global_data_using_key( 'kirki_editor_read_only_access_token', $token );
989 return $token;
990 }
991 /**
992 * Get all global used style block ids
993 * first get all posts used global style ids
994 * then merge and returns.
995 *
996 * @return array style ids.
997 */
998 private static function get_all_global_used_style_block_ids() {
999 global $wpdb;
1000 //phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.DirectQuery
1001 $used_global_ids = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}postmeta WHERE meta_key = '" . KIRKI_META_NAME_FOR_USED_STYLE_BLOCK_IDS . "'", OBJECT );
1002
1003 $all_used_block_ids = array();
1004 foreach ( $used_global_ids as $key => $p_meta ) {
1005 $this_used_global = get_post_meta( $p_meta->post_id, $p_meta->meta_key, true );
1006 $all_used_block_ids = array_merge( $all_used_block_ids, $this_used_global );
1007 }
1008 $all_used_block_ids_global = array_unique( $all_used_block_ids );
1009 return $all_used_block_ids_global;
1010 }
1011
1012 public static function get_all_data_by_kirki_meta_key() {
1013 global $wpdb;
1014 //phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.DirectQuery
1015 // $all_page_meta_data = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}postmeta WHERE meta_key = 'kirki'", ARRAY_A );
1016 $all_page_meta_data = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}postmeta WHERE meta_key = 'kirki' ORDER BY meta_id DESC", ARRAY_A );
1017
1018 return $all_page_meta_data;
1019 }
1020
1021 /**
1022 * Get all global unused style block ids
1023 * first get all posts used global style ids using get_all_global_used_style_block_ids()
1024 * then collect and return.
1025 *
1026 * @return array style ids.
1027 */
1028 private static function get_unused_global_style_ids() {
1029 $all_used_ids = self::get_all_global_used_style_block_ids();
1030 $styles = HelperFunctions::get_global_data_using_key( KIRKI_GLOBAL_STYLE_BLOCK_META_KEY );
1031 $unused_keys = array();
1032
1033 foreach ( $styles as $key => $sb ) {
1034
1035 // we will also remove default style block too. if it is not used in any post. and added latest style block from front end.
1036 if ( ( true || ( ( isset( $sb['isDefault'] ) && ! $sb['isDefault'] ) || ! isset( $sb['isDefault'] ) ) ) && ! in_array( $key, $all_used_ids, true ) ) {
1037 $unused_keys[] = $key;
1038 }
1039 }
1040 return $unused_keys;
1041 }
1042
1043 /**
1044 * Get all post unused style block ids
1045 * first get all posts used post style ids using get_unused_post_style_ids()
1046 * then collect and return.
1047 *
1048 * @param int $post_id wp post id.
1049 * @return array style ids.
1050 */
1051 private static function get_unused_post_style_ids( $post_id ) {
1052 $all_used_ids = get_post_meta( $post_id, KIRKI_META_NAME_FOR_USED_STYLE_BLOCK_IDS . '_random', true );
1053 $styles = get_post_meta( $post_id, KIRKI_GLOBAL_STYLE_BLOCK_META_KEY . '_random', true );
1054
1055 if ( ! $styles ) {
1056 return array();
1057 }
1058 $unused_keys = array();
1059
1060 foreach ( $styles as $key => $sb ) {
1061 if ( ! $all_used_ids || ! in_array( $key, $all_used_ids, true ) ) {
1062 $unused_keys[] = $key;
1063 }
1064 }
1065 return $unused_keys;
1066 }
1067
1068 /**
1069 * @deprecated
1070 * @see Kirki\App\Services\PageService::toggle_disabled_page_symbols()
1071 */
1072 public static function toggle_disabled_page_symbols() {
1073 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1074 $post_id = (int) HelperFunctions::sanitize_text( isset( $_POST['post_id'] ) ? $_POST['post_id'] : get_the_ID() );
1075 $symbol_type = HelperFunctions::sanitize_text( isset( $_POST['symbol_type'] ) ? $_POST['symbol_type'] : null );
1076 $disable = HelperFunctions::sanitize_text( isset( $_POST['disable'] ) ? $_POST['disable'] : null );
1077
1078 if ( $post_id && $symbol_type && $disable ) {
1079 $prev_status = get_post_meta( $post_id, KIRKI_META_NAME_FOR_PAGE_HF_SYMBOL_DISABLE_STATUS, true );
1080 if ( ! isset( $prev_status ) || ! is_array( $prev_status ) ) {
1081 $prev_status = array();
1082 }
1083 $disable = filter_var( $disable, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE ) ?? false;
1084 $current_status = array_merge( $prev_status, array( $symbol_type => $disable ) );
1085 update_post_meta( $post_id, KIRKI_META_NAME_FOR_PAGE_HF_SYMBOL_DISABLE_STATUS, $current_status );
1086 wp_send_json( array( 'status' => 'Page data saved.' ) );
1087 }
1088 wp_send_json( array( 'status' => 'Page data save failed!' ) );
1089 }
1090 }
1091