JezK
Edit File: ContentManagerHelper.php
<?php /** * Page or post data manager * * @package kirki */ namespace Kirki\API\ContentManager; use Kirki\App\Constants\PostTypes; use Kirki\HelperFunctions; if (!defined('ABSPATH')) { exit; // Exit if accessed directly. } /** * Content Manager data handler */ class ContentManagerHelper { /** * @deprecated Moved the constants in PostTypes * @see \Kirki\App\Constants\PostTypes */ const PARENT_POST_TYPE = KIRKI_CONTENT_MANAGER_PREFIX; /** * @deprecated This shouldn't be used like this. use with_prefix() instead */ const POST_META_PREFIX = KIRKI_CONTENT_MANAGER_PREFIX; /** * @deprecated Moved the constants in ContentManager * @see \Kirki\App\Supports\ContentManager */ const RESERVED_SLUG_WORDS = array('attachment', 'author', 'category', 'comment', 'feed', 'page', 'post', 'tag', 'profile', 'index'); /** * Get all post types with pagination * @param array $args * @return array * * @deprecated Reimplemented in the new architecture; use the CollectionService::paginated() method instead. * @see \Kirki\App\Services\CollectionService::paginated() */ public static function get_all_post_types($args) { $posts_per_page = isset($args['posts_per_page']) ? $args['posts_per_page'] : 20; $page = $args['page']; $offset = $posts_per_page * ($page - 1); $posts = get_posts( array( 'post_type' => self::PARENT_POST_TYPE, 'post_status' => array('draft', 'publish', 'future'), 'numberposts' => -1, 'post_parent' => 0, 'orderby' => 'ID', 'order' => 'DESC', 'posts_per_page' => $posts_per_page, 'offset' => $offset, // Use 'offset' for pagination ) ); foreach ($posts as $key => $post) { $posts[$key] = self::format_single_post($post); } return $posts; } /** * Get a single post type data * @param mixed $id * @param mixed $hierarchy * @return array * @deprecated Reimplemented in the new architecture; use the CollectionService::get_single() method instead. * @see \Kirki\App\Services\CollectionService::get_single() */ public static function get_post_type($id, $hierarchy = false) { return self::format_single_post(get_post($id), $hierarchy); } /** * Get a single post type data * @param mixed $id * @return array * @deprecated Reimplemented in the new architecture; use the CollectionService::get_single() method instead. * @see \Kirki\App\Services\CollectionService::get_single() */ public static function get_post_type_settings($id) { $post = get_post($id); if ($post) { return self::format_single_post($post); } return null; } public static function get_referenced_collection($post_id, $field_id) { global $wpdb; $name = $field_id; $cm_ref_field_meta_key = self::get_child_post_meta_key_using_field_id($post_id, $name); $results = $wpdb->get_results($wpdb->prepare("SELECT ref_post_id FROM {$wpdb->prefix}kirki_cm_reference WHERE field_meta_key=%s", $cm_ref_field_meta_key), ARRAY_A); $ref_parent_post = null; if (count($results) > 0) { $ref_parent_post = get_post($results[0]['ref_post_id']); $ref_parent_post = self::format_single_post(get_post($ref_parent_post->post_parent)); } return array( 'data' => $ref_parent_post, 'args' => array( 'post_parent' => $post_id, 'name' => $field_id, ), ); } /** * Validate a post slug. * * @deprecated Reimplemented in the new architecture; use the support class instead. * @see \Kirki\App\Supports\ContentManager::validate_slug() */ public static function validate_slug($post_id, $post_type, $post_name) { if (in_array($post_name, self::RESERVED_SLUG_WORDS)) { return false; } return HelperFunctions::validate_slug($post_id, $post_type, $post_name); } /** * Create or update parent post * * @param object $args parent post ID and post_title * @param object $othersArgs parent post slug and other configuration * * @deprecated Reimplemented in the new architecture; use the CollectionService::create_or_update_a_post_type() method instead. * @see \Kirki\App\Services\CollectionService::create_or_update_a_post_type() */ public static function create_or_update_a_post_type($args, $othersArgs) { $wp_post = array( 'post_type' => self::PARENT_POST_TYPE, 'post_title' => $args['post_title'], 'post_name' => $args['post_name'], 'post_status' => 'publish', ); if (isset($args['ID']) && !empty($args['ID'])) { $wp_post['ID'] = $args['ID']; $post_id = $args['ID']; wp_update_post($wp_post); } else { $post_id = wp_insert_post($wp_post); } self::add_or_update_post_type_fields($post_id, $othersArgs['fields'], $othersArgs['basic_fields']); if ($post_id) { return self::format_single_post(get_post($post_id)); } wp_send_json_error('Creation failed!', 422); } /** * Update post type fields. * first check prev meta then validate every filed and update child post field data accordingly * remove if any unused filed has in the child post. * * @param object $args parent post ID and post_title * @param object $othersArgs parent post slug and other configuration * @deprecated Reimplemented in the new architecture; use the CollectionService::save_fields() method instead. * @see \Kirki\App\Services\CollectionService::save_fields() */ private static function add_or_update_post_type_fields($post_id, $fields, $basic_fields) { $prev_fields = self::get_parent_post_fields($post_id); // check new fields and prv_fields value; $changed = self::find_changed_ids($prev_fields, $fields); if (count($changed['deleted_ids']) > 0) { global $wpdb; foreach ($changed['deleted_ids'] as $key => $field_id) { $meta_key = self::get_child_post_meta_key_using_field_id($post_id, $field_id); $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->postmeta} WHERE meta_key=%s", $meta_key)); // delete the all the fields from wp_kirki_cm_reference table where field_meta_key = $meta_key $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->prefix}kirki_cm_reference WHERE field_meta_key=%s", $meta_key)); } } // TODO: new_ids //set default value. foreach ($fields as &$field) { if ($field['type'] === 'reference' || $field['type'] === 'multi-reference') { $field['editRefCollection'] ??= false; } } update_post_meta($post_id, self::POST_META_PREFIX . '_fields', $fields); // if(!empty($fields)){ // update_post_meta( $post_id, self::POST_META_PREFIX . '_fields', $fields ); // } if (!empty($basic_fields)) { update_post_meta($post_id, self::POST_META_PREFIX . '_basic_fields', $basic_fields); } } /** * Find new and deleted field IDs between two field sets. * * @deprecated Reimplemented in the new architecture; use the CollectionService::cleanup_old_field_data() method instead. * @see \Kirki\App\Services\CollectionService::cleanup_old_field_data() */ public static function find_changed_ids($prev_fields, $new_fields) { $prev_ids = array_column($prev_fields, 'id'); $new_ids = array_column($new_fields, 'id'); // Find new IDs in $new_fields $new_ids_only = array_diff($new_ids, $prev_ids); // Find deleted IDs in $prev_fields $deleted_ids_only = array_diff($prev_ids, $new_ids); return array( 'new_ids' => $new_ids_only, 'deleted_ids' => $deleted_ids_only, ); } /** * Build the child post type value for a parent collection. * * @deprecated Reimplemented in the new architecture; use the support class instead. * @see \Kirki\App\Supports\ContentManager::get_child_post_post_type_value() */ public static function get_child_post_post_type_value($post_parent) { return self::PARENT_POST_TYPE . '_' . $post_parent; } /** * Create or update child post * * @param object $args parent post ID and post_title * @param object $othersArgs parent post slug and other configuration */ public static function create_or_update_a_post_type_item($args, $othersArgs) { if (isset($args['ID']) && !empty($args['ID'])) { $post = get_post($args['ID']); } $wp_post = array( 'post_parent' => $args['post_parent'], 'post_type' => self::get_child_post_post_type_value($args['post_parent']), 'post_title' => $args['post_title'], 'post_name' => $args['post_name'], 'post_status' => $args['post_status'], ); if (isset($args['post_date']) && !empty($args['post_date'])) { if (isset($args['post_status']) && $args['post_status'] === "future") { $wp_post['post_date'] = $args['post_date']; $wp_post['post_date_gmt'] = get_gmt_from_date($args['post_date']); } elseif ( isset($args['post_status']) && $post && $post->post_status === 'draft' && $args['post_status'] === 'publish' ) { $wp_post['post_date'] = current_time('mysql'); $wp_post['post_date_gmt'] = get_gmt_from_date($args['post_date']); } } if (isset($args['ID']) && !empty($args['ID'])) { $wp_post['ID'] = $args['ID']; $post_id = $args['ID']; wp_update_post($wp_post); } else { $post_id = wp_insert_post($wp_post); } if (!empty($othersArgs['fields'])) { $parent_fields = self::get_parent_post_fields($args['post_parent']); $fields = $othersArgs['fields']; // TODO: need to validate fields data with parent fields foreach ($parent_fields as $key => $parent_field) { if (isset($fields[$parent_field['id']])) { $meta_key = self::get_child_post_meta_key_using_field_id($args['post_parent'], $parent_field['id']); // Check if the $parent_field type is 'reference'/ 'multi-reference' then save the field value in the wp_kirki_cm_reference table if ($parent_field['type'] === 'reference' || $parent_field['type'] === 'multi-reference') { global $wpdb; $ref_post_id = $fields[$parent_field['id']]; // Check if the meta key exists $is_meta_key_exist = metadata_exists('post', $post_id, $meta_key); // Get the meta value $value = get_post_meta($post_id, $meta_key, true); // if meta key is not exist then set default value of the field if (!$is_meta_key_exist) { $value = $parent_field['default_value']; } // Format the field value $fields[$parent_field['id']] = $value; $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->prefix}kirki_cm_reference WHERE post_id=%d AND field_meta_key=%s", $post_id, $meta_key)); // Check if the ref_post_id is not empty if (!empty($ref_post_id)) { // before insert the ref_post_id into wp_kirki_cm_reference table, check if the ref_post_id is exist in wp_kirki_cm_reference table or not with the same post_id and field_meta_key foreach ($ref_post_id as $key => $single_ref_post_id) { $result = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}kirki_cm_reference WHERE post_id=%d AND field_meta_key=%s AND ref_post_id=%d", $post_id, $meta_key, $single_ref_post_id['value'])); // If the ref_post_id is not exist in wp_kirki_cm_reference table then insert the ref_post_id into wp_kirki_cm_reference table if (empty($result)) { $wpdb->insert( $wpdb->prefix . 'kirki_cm_reference', array( 'post_id' => $post_id, 'field_meta_key' => $meta_key, 'ref_post_id' => $single_ref_post_id['value'], ), array('%d', '%s', '%d') ); } } } } else { update_post_meta($post_id, $meta_key, $fields[$parent_field['id']]); } } } } if ($post_id) { return self::format_single_child_post(get_post($post_id)); } wp_send_json_error('Creation failed!', 422); } /** * Build the child post meta key for a parent collection field. * * @deprecated Reimplemented in the new architecture; use the support class instead. * @see \Kirki\App\Supports\ContentManager::get_child_post_meta_key_using_field_id() */ public static function get_child_post_meta_key_using_field_id($post_parent, $field_id) { return self::POST_META_PREFIX . '_field_' . $post_parent . '_' . $field_id; } private static function format_single_post($post, $hierarchy = false) { $post = (array) $post; $post['fields'] = self::get_parent_post_fields($post['ID'], $hierarchy); $post['item_count'] = self::get_child_post_count($post['ID']); $post['basic_fields'] = self::get_post_type_basic_fields($post['ID']); return $post; } private static function get_post_type_basic_fields($post_id) { $basic_fields = get_post_meta($post_id, self::POST_META_PREFIX . '_basic_fields', true); return $basic_fields ? $basic_fields : array( 'post_title' => array( 'title' => 'Name', 'help_text' => '', ), 'post_name' => array( 'title' => 'Slug', 'help_text' => '', ), ); } private static function get_parent_post_fields($post_id, $hierarchy = false) { $_fields = get_post_meta($post_id, self::POST_META_PREFIX . '_fields', true); if ($hierarchy === true) { foreach ($_fields as $key => $field) { if ($field['type'] === 'reference') { $ref_field_post = self::format_single_post(get_post($field['ref_collection']), $hierarchy); $field['fields'][] = $ref_field_post; } $_fields[$key] = $field; } } return $_fields ? $_fields : array(); } public static function format_single_child_post($post) { $post = (array) $post; $post_id = $post['ID']; $post_parent = $post['post_parent']; $parent_fields = self::get_parent_post_fields($post_parent); $fields = array(); foreach ($parent_fields as $key => $parent_field) { $meta_key = self::get_child_post_meta_key_using_field_id($post_parent, $parent_field['id']); // Check if the meta key exists $is_meta_key_exist = metadata_exists('post', $post_id, $meta_key); // Get the meta value $value = get_post_meta($post_id, $meta_key, true); // if meta key is not exist then set default value of the field if (!$is_meta_key_exist) { $value = isset($parent_field['default_value']) ? $parent_field['default_value'] : ''; } // Format the field value // check if the field type is 'reference' or 'multi-reference' then get the ref_post_id from wp_kirki_cm_reference table if ($parent_field['type'] === 'reference' || $parent_field['type'] === 'multi-reference') { global $wpdb; $ref_post_ids = $wpdb->get_results($wpdb->prepare("SELECT ref_post_id FROM {$wpdb->prefix}kirki_cm_reference WHERE post_id=%d AND field_meta_key=%s", $post_id, $meta_key)); $ref_post_id = array(); if (!empty($ref_post_ids)) { // check is ref_post_id is an array if (is_array($ref_post_ids)) { foreach ($ref_post_ids as $key => $ref_post) { $ref_post_id[] = array( 'value' => $ref_post->ref_post_id, 'title' => get_the_title($ref_post->ref_post_id), ); } } else { $ref_post_id[] = array( 'value' => $ref_post_ids->ref_post_id, 'title' => get_the_title($ref_post_ids->ref_post_id), ); } } $value = $ref_post_id; } $fields[$parent_field['id']] = $value; } $post['fields'] = $fields; $post_perma_link = get_permalink($post_id); $protocol = strpos(home_url(), 'https://') !== false ? 'https' : 'http'; if ($protocol === 'https') { $post_perma_link = str_replace('http://', 'https://', $post_perma_link); } else { $post_perma_link = str_replace('https://', 'http://', $post_perma_link); } $guid = add_query_arg( array( 'post_id' => $post_id, ), $post_perma_link ); $post['guid'] = $guid; return $post; } public static function get_all_child_items($args) { $posts_per_page = isset($args['posts_per_page']) ? $args['posts_per_page'] : 20; $exclude_post_ids = isset($args['exclude_post_ids']) ? $args['exclude_post_ids'] : array(); $post_parent = $args['post_parent']; $page = $args['page']; $offset = $posts_per_page * ($page - 1); $query = isset($args['query']) ? $args['query'] : ''; $filter = isset($args['filter']) ? $args['filter'] : ''; $args = array( 'post_type' => self::get_child_post_post_type_value($post_parent), 'post_status' => array('draft', 'publish', 'future'), 'post_parent' => $post_parent, 'orderby' => 'ID', 'order' => 'DESC', 'posts_per_page' => $posts_per_page, 'offset' => $offset, // Use 'offset' for pagination 's' => $query, // Add query parameter 'post__not_in' => $exclude_post_ids, // Exclude the post IDs ); // TODO: Need to check if we can use helper getpost method $args = self::generate_args_with_filter_data($args, $filter); $posts = get_posts($args); foreach ($posts as $key => $post) { $posts[$key] = self::format_single_child_post($post); } return $posts; } public static function get_post_type_item($post_id) { $post = get_post($post_id); if ($post) { return self::format_single_child_post($post); } return null; } private static function generate_args_with_filter_data($args, $filter) { if ($filter) { foreach ($filter as $key => $singleFilter) { if ($key === 'post_status') { if ($singleFilter === 'all') { $args['post_status'] = array('draft', 'publish', 'future'); } else { $args['post_status'] = $singleFilter; } } if ($key === 'post_date') { $current_time = current_time('timestamp'); // Get the current timestamp if ($singleFilter === 'last_24_hrs') { $args['date_query'] = array( array( 'after' => gmdate('Y-m-d H:i:s', strtotime('-24 hours', $current_time)), 'inclusive' => true, ), ); } elseif ($singleFilter === 'last_7_days') { $args['date_query'] = array( array( 'after' => gmdate('Y-m-d H:i:s', strtotime('-7 days', $current_time)), 'inclusive' => true, ), ); } elseif ($singleFilter === 'last_30_days') { $args['date_query'] = array( array( 'after' => gmdate('Y-m-d H:i:s', strtotime('-30 days', $current_time)), 'inclusive' => true, ), ); } } if ($key === 'post_modified') { $current_time = current_time('timestamp'); // Get the current timestamp if ($singleFilter === 'last_24_hrs') { $args['date_query'] = array( array( 'column' => 'post_modified', // Use 'post_modified' to compare with GMT time 'after' => gmdate('Y-m-d H:i:s', strtotime('-24 hours', $current_time)), 'inclusive' => true, ), ); } elseif ($singleFilter === 'last_7_days') { $args['date_query'] = array( array( 'column' => 'post_modified', 'after' => gmdate('Y-m-d H:i:s', strtotime('-7 days', $current_time)), 'inclusive' => true, ), ); } elseif ($singleFilter === 'last_30_days') { $args['date_query'] = array( array( 'column' => 'post_modified', 'after' => gmdate('Y-m-d H:i:s', strtotime('-30 days', $current_time)), 'inclusive' => true, ), ); } } } } return $args; } public static function get_child_post_count($parent_post_id, $post_status = array('draft', 'publish', 'future')) { $child_post_count = 0; // Query child posts based on parent post ID $child_posts = get_posts( array( 'post_type' => self::get_child_post_post_type_value($parent_post_id), 'post_status' => $post_status, 'post_parent' => $parent_post_id, 'posts_per_page' => -1, // Retrieve all child posts ) ); // Count the number of child posts if ($child_posts) { $child_post_count = count($child_posts); } return $child_post_count; } /** * delete post * * @param object $post_id post ID */ public static function delete_content_manager_post($post_id) { $post = get_post($post_id); if ($post) { self::delete_post_with_children($post->ID); return true; } wp_send_json_error('Delete failed!', 422); } /** * duplicate post * * @param object $post_id post ID */ public static function duplicate_content_manager_post($post_id) { $post = get_post($post_id); if ($post) { $new_post = self::duplicate_post($post->ID, true); $new_post_id = $new_post->ID; self::duplicate_cm_reference_data($post_id, $new_post_id); return self::format_single_child_post($new_post); } wp_send_json_error('Duplicate failed!', 422); } /** * Duplicate reference rows from one post to another. * * @deprecated Reimplemented in the new architecture; reference rows are now handled via the Reference model. * @see \Kirki\App\Models\Reference * @see \Kirki\App\Services\CollectionItemService::duplicate() */ public static function duplicate_cm_reference_data($post_id, $new_post_id) { global $wpdb; $results = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}kirki_cm_reference WHERE post_id=%d", $post_id), ARRAY_A); if (!empty($results)) { foreach ($results as $key => $result) { $wpdb->insert( $wpdb->prefix . 'kirki_cm_reference', array( 'post_id' => $new_post_id, 'field_meta_key' => $result['field_meta_key'], 'ref_post_id' => $result['ref_post_id'], ), array('%d', '%s', '%d') ); } } } private static function duplicate_post($post_id, $with_children = true) { // Get the post to duplicate. $post = get_post($post_id); // Duplicate the post $new_post_id = wp_insert_post( array( 'post_title' => $post->post_title . ' Copy', 'post_content' => $post->post_content, 'post_type' => $post->post_type, 'post_parent' => $post->post_parent, // Add more fields as needed ) ); if (is_wp_error($new_post_id)) { // Handle error if post duplication fails wp_send_json_error('Duplicate failed!', 422); } // Duplicate post meta data $post_meta = get_post_meta($post_id); foreach ($post_meta as $key => $values) { foreach ($values as $value) { add_post_meta($new_post_id, $key, maybe_unserialize($value));// it is important to unserialize data to avoid conflicts. } } if ($with_children) { // Get the child posts of the original post $children = get_children( array( 'post_parent' => $post_id, 'post_type' => $post->post_type, ) ); // Duplicate child posts recursively if (!empty($children)) { foreach ($children as $child) { self::duplicate_post($child->ID, $with_children); } } } // Return the ID of the duplicated post return get_post($new_post_id); } /** * duplicate data post * * @param object $post_id post ID */ public static function duplicate_content_manager_post_type($post_id) { $new_post = self::duplicate_post($post_id, false); if ($new_post) { return self::format_single_post($new_post); } wp_send_json_error('Duplicate failed!', 422); } private static function delete_post_with_children($post_id) { // Delete child posts recursively $children = get_children( array( 'post_parent' => $post_id, 'post_type' => self::get_child_post_post_type_value($post_id), // Change 'any' to specific post types if needed ) ); if (!empty($children)) { foreach ($children as $child) { self::delete_post_with_children($child->ID); } } // // Delete post all meta data $metas = get_post_meta($post_id); foreach ($metas as $key => $value) { delete_post_meta($post_id, $key); } // Delete the post itself wp_delete_post($post_id, true); // Set the second parameter to true to force delete } /** * Get the parent collection field definitions keyed by field id. * * @deprecated Reimplemented in the new architecture within the service layer. * @see \Kirki\App\Services\CollectionItemService */ public static function get_post_type_custom_field_keys($post_id) { $post_type_fields = self::get_parent_post_fields($post_id); $kirki_content_manager_post_type_fields = array(); if (is_array($post_type_fields)) { foreach ($post_type_fields as $field) { $kirki_content_manager_post_type_fields[$field['id']] = $field; } } return $kirki_content_manager_post_type_fields; } /** * Get all custom fields of a post in the kirki_cm_reference table by post ID. * * @deprecated Reimplemented in the new architecture; reference rows are now handled via the Reference model. * @see \Kirki\App\Models\Reference * @return array Custom fields. */ public static function get_post_cm_ref_fields() { global $wpdb; $results = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}kirki_cm_reference"), ARRAY_A); $ref_fields = array(); if (count($results) > 0) { foreach ($results as $key => $result) { $ref_fields[] = $result; } } return $ref_fields; } /** * Get post ids by ref_post_id from kirki_cm_reference table * * @deprecated Reimplemented in the new architecture; reference rows are now handled via the Reference model. * @see \Kirki\App\Models\Reference * @param int $ref_post_id post IDs -> Array of post IDs * @return array post ids */ public static function get_post_ids_by_ref_post_ids($ref_post_ids) { // first check if $ref_post_ids is an array or not if (!is_array($ref_post_ids)) { $ref_post_ids = array($ref_post_ids); } global $wpdb; $ids_int = array_map('intval', $ref_post_ids); $post_ids = $wpdb->get_results( $wpdb->prepare( "SELECT post_id FROM {$wpdb->prefix}kirki_cm_reference WHERE ref_post_id IN (" . implode(', ', array_fill(0, count($ids_int), '%d')) . ")", $ids_int ), ARRAY_A ); $post_ids = array_map('intval', wp_list_pluck($post_ids, 'post_id')); $post_ids = array_unique($post_ids); if (!empty($post_ids)) { return $post_ids; } return array(); } }