<?php 

    // prevent direct file access
	if( !defined( 'ABSPATH' ) ) exit;
    
    // require necessary function
    function pixe_template_table_init(){
        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');

        global $wpdb;
        $charset_collate = $wpdb->get_charset_collate();

        // order table
        // pixe_type varchar(100) DEFAULT '' NOT NULL,
        $sql = "CREATE TABLE {$wpdb->prefix}pixetemplate (
            id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
            pixe_type ENUM('template', 'template_part'),
            pixe_subtype ENUM('header', 'footer', 'popup', 'post_template', 'taxonomy_template', 'synced_block'),
            author bigint(20) UNSIGNED DEFAULT NULL,
            date_utc datetime DEFAULT NULL,
            title text DEFAULT NULL,
            content longtext,
            settings longtext,
            style longtext,
            dependency longtext,
            edit_lock text DEFAULT NULL,
            PRIMARY KEY (id)
        ) {$charset_collate};";
        dbDelta($sql);
    }

    // get object cache key
    function pixe_template_get_cache_key($args){
        $key = 'pixetemplate.v' . pixe_get_cache_version('template');

        if( !empty($args['select']) ){
            $key .= '|' . trim($args['select']);
        }
        if( !empty($args['id']) ){
            $key .= '|' . absint($args['id']);
        }
        if( !empty($args['ids']) && is_array($args['ids']) ){
            sort($args['ids']);
            $key .= '|' . implode(',', $args['ids']);
        }
        if( !empty($args['type']) ){
            $key .= '|' . trim($args['type']);
        }
        if( !empty($args['subtype']) ){
            $key .= '|' . trim($args['subtype']);
        }
        if( !empty($args['order']) ){
            $key .= '|' . trim($args['order']);
        }
        if( !empty($args['output']) ){
            $key .= '|' . $args['output'];
        }

        return $key;
    }

    // use to insert new data
    function pixe_set_template_data($data){
        global $wpdb;

        $id = '';
        if( !empty($data['id']) ){
            $id = $data['id'];
            unset($data['id']);
        }

        // create data format
        $formats = array();
        foreach( $data as $slug => $value ){

            // prepare json data
            if( is_array($value) ){
                $data[$slug] = json_encode($value);
            }
            
            // set format
            if( $slug == 'author' ){
                $formats[] = '%d';
            }else{
                $formats[] = '%s';
            }
        }

        // insert data
        if( !empty($id) ){
            $wpdb->update("{$wpdb->prefix}pixetemplate", $data, array('id' => $id), $formats, array('%d')); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Cache automatically invalidated on data changes
        }else{
            $wpdb->insert("{$wpdb->prefix}pixetemplate", $data, $formats); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
        }

        // delete cache after update
        pixe_increase_cache_version('template');

        return $wpdb->insert_id;
    }

    // save preview image
    add_action('wp_ajax_pixe_save_template_preview', 'pixe_ajax_save_template_preview');
    function pixe_ajax_save_template_preview(){

        // check nonce
        if( !check_ajax_referer('pixe-editor', 'security', false) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('nonce-head'),
                'message'=> pixe_get_error_message('nonce-message')
            )));
        }

        // check data
        if( empty($_POST['id']) || empty($_POST['type']) || $_POST['type'] != 'template_part' || empty($_FILES['preview']['name']) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('invalid-format-head'),
                'message'=> pixe_get_error_message('invalid-format-message')
            )));
        }

        // check permission
        if( !current_user_can('upload_files') ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('permission-head'),
                'message'=> pixe_get_error_message('permission-message')
            )));
        }

        // only load file.php when function's not exists
        if( ! function_exists( 'wp_handle_upload' ) ){
            require_once(ABSPATH . 'wp-admin/includes/file.php');
        }
        
        $filename = sanitize_file_name($_FILES['preview']['name']);

        // remove if file already exists
        $upload_dir = wp_upload_dir();
        $target_file = $upload_dir['basedir'] . '/pixe-template-preview/' . $filename;
        if( file_exists($target_file) ){
            wp_delete_file($target_file);
        }

        add_filter('upload_dir', 'pixe_template_preview_upload_dir');

        $upload = wp_handle_upload($_FILES['preview'], ['test_form' => false]);
        remove_filter('upload_dir', 'pixe_template_preview_upload_dir');

        if( !empty($upload['error']) ) {
            die(json_encode(array(
                'status' => 'failed',
                'head' => esc_html__('Upload Error', 'pixebuilder'),
                'message'=> esc_html__('Cannot upload preview image.' ,'pixebuilder')
            )));
        }

        die(json_encode(array('status' => 'success')));
    }
    
    // change uplaod path 
    function pixe_template_preview_upload_dir($dir) {
        $template_dir = '/pixe-template-preview';

        $dir['path']    = $dir['basedir'] . $template_dir;
        $dir['url']     = $dir['baseurl'] . $template_dir;
        $dir['subdir']  = $template_dir;

        // make sure folder exists
        if( !file_exists($dir['path']) ) {
            wp_mkdir_p($dir['path']);
        }

        return $dir;
    }
    function pixe_get_template_preview_image($id = '', $type = 'url'){
        if( empty($id) ) return '';

        $upload_dir = wp_upload_dir();
        $file_dir = $upload_dir['basedir'] . '/pixe-template-preview/' . $id . '.webp';
        $file_png = $upload_dir['basedir'] . '/pixe-template-preview/' . $id . '.png';

        // check if file exists
        if( file_exists($file_dir) ){
            if( $type == 'url' ){
                return $upload_dir['baseurl'] . '/pixe-template-preview/' . $id . '.webp?v=' . filemtime($file_dir);
            }else if( $type == 'dir' ){
                return $file_dir;
            }
        }else if( file_exists($file_png) ){
            if( $type == 'url' ){
                return $upload_dir['baseurl'] . '/pixe-template-preview/' . $id . '.png?v=' . filemtime($file_png);
            }else if( $type == 'dir' ){
                return $file_png;
            }
        }
        
        return '';
    }

    // save editor action
    function pixe_save_template_editor(){

        // check nonce
        if( !check_ajax_referer('pixe-editor', 'security', false) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('nonce-head'),
                'message'=> pixe_get_error_message('nonce-message')
            )));
        }

        // check permission
        if( !current_user_can('edit_posts') ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('permission-head'),
                'message'=> pixe_get_error_message('permission-message')
            )));
        }

        // check data
        if( empty($_POST['type']) || empty($_POST['id']) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('invalid-format-head'),
                'message'=> pixe_get_error_message('invalid-format-message')
            )));
        }

        $currentuser = wp_get_current_user();
        $currenttime = current_time('mysql', true);

        // store data
        $id = absint(wp_unslash($_POST['id']));
        $type = sanitize_text_field(wp_unslash($_POST['type']));
        $part = empty($_POST['part'])? '': sanitize_text_field(wp_unslash($_POST['part']));

        // builder data
        $content = empty($_POST['content'])? '': json_decode(wp_unslash($_POST['content']), true); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized below using array_walk_recursive
        if( !is_array($content) ){ $content = array(); }
        array_walk_recursive($content, 'pixe_sanitize_builder_data');

        $settings = empty($_POST['settings'])? '': map_deep(wp_unslash($_POST['settings']), 'sanitize_textarea_field');
        $style = empty($_POST['styles'])? '': map_deep(wp_unslash($_POST['styles']), 'sanitize_textarea_field');
        $dependency = empty($_POST['dependency'])? '': map_deep(wp_unslash($_POST['dependency']), 'sanitize_textarea_field');

        // save template data
        pixe_set_template_data(array(
            'id' => $id,
            'pixe_type' => $type,
            'pixe_subtype' => $part,
            'author' => $currentuser->ID,
            'date_utc' => $currenttime,
            'content' => $content,
            'settings' => $settings,
            'style' => $style,
            'dependency' => $dependency,
        ));

        // add string for ml translation
        if( $type == 'template_part' ){
            $ml_type = $part;
        }else{
            $ml_type = $type;
        }
        pixe_register_multilingual_strings($ml_type, $id, $content);
        
        die(json_encode(array(
            'status' => 'success'
        )));
    }

    // set title
    add_action('wp_ajax_pixe_set_template_title', 'pixe_ajax_set_template_title');
    function pixe_ajax_set_template_title(){
        
        // check nonce
        if( !check_ajax_referer('pixe-editor', 'security', false) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('nonce-head'),
                'message'=> pixe_get_error_message('nonce-message')
            )));
        }

        // check permission
        if( !current_user_can('edit_posts') ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('permission-head'),
                'message'=> pixe_get_error_message('permission-message')
            )));
        }

        // check data
        if( empty($_POST['id']) || empty($_POST['title']) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('invalid-format-head'),
                'message'=> pixe_get_error_message('invalid-format-message')
            )));
        }

        pixe_set_template_data(array(
            'id' => absint(wp_unslash($_POST['id'])),
            'title' => sanitize_text_field(wp_unslash($_POST['title']))
        ));
        
        die(json_encode(array(
            'status' => 'success',
        )));
    }

    // default template
    add_action('wp_ajax_pixe_set_default_template', 'pixe_ajax_set_default_template');
    function pixe_ajax_set_default_template(){

        // check nonce
        if( !check_ajax_referer('pixe-editor', 'security', false) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('nonce-head'),
                'message'=> pixe_get_error_message('nonce-message')
            )));
        }

        // check permission
        if( !current_user_can('edit_posts') ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('permission-head'),
                'message'=> pixe_get_error_message('permission-message')
            )));
        }

        // check data
        if( empty($_POST['id']) || !is_numeric($_POST['id']) ||
            empty($_POST['type']) || !in_array($_POST['type'], array('header', 'footer')) ){
                
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('invalid-format-head'),
                'message'=> pixe_get_error_message('invalid-format-message')
            )));
        }

        $template_id = absint(wp_unslash($_POST['id']));
        $template_type = sanitize_text_field(wp_unslash($_POST['type']));
        $template_active = empty($_POST['active'])? '': sanitize_text_field(wp_unslash($_POST['active']));
        if( $template_active == 'yes' ){
            update_option('pixe_default_' . $template_type, $template_id, false);
        }else{
            delete_option('pixe_default_' . $template_type);
        }

        die(json_encode(array('status' => 'success')));
    }

    // copy template
    function pixe_copy_template($template){
        $currentuser = wp_get_current_user();
        $currenttime = current_time('mysql', true);
        
        // replace id for template part
        if( $template['pixe_type'] == 'template_part' ){
            $template_id = pixe_set_template_data(array(
                'author' => $currentuser->ID,
                'date_utc' => $currenttime,
                'pixe_type' => $template['pixe_type'],
                'pixe_subtype' => $template['pixe_subtype'],
                'title' => $template['title'],
                'settings' => empty($template['settings'])? '': $template['settings'],
                'dependency' => empty($template['dependency'])?  '': $template['dependency']
            ));

            pixe_set_template_data(array(
                'id' => $template_id,
                'content' => empty($template['content'])?  '': pixe_update_template_part_id($template['content'], $template['pixe_subtype'], $template['id'], $template_id),
                'style' => empty($template['style'])?  '': pixe_update_template_part_id($template['style'], $template['pixe_subtype'], $template['id'], $template_id)
            ));

        // same id for normal template
        }else{
            $template_id = pixe_set_template_data(array(
                'author' => $currentuser->ID,
                'date_utc' => $currenttime,
                'pixe_type' => $template['pixe_type'],
                'pixe_subtype' => $template['pixe_subtype'],
                'title' => $template['title'],
                'content' => empty($template['content'])?  '': $template['content'],
                'settings' => empty($template['settings'])?  '': $template['settings'],
                'style' => empty($template['style'])?  '': $template['style'],
                'dependency' => empty($template['dependency'])?  '': $template['dependency']
            ));
        }
        
        return $template_id;
    }

    add_action('wp_ajax_pixe_copy_template', 'pixe_ajax_copy_template');
    function pixe_ajax_copy_template(){

        // check nonce
        if( !check_ajax_referer('pixe-editor', 'security', false) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('nonce-head'),
                'message'=> pixe_get_error_message('nonce-message')
            )));
        }

        // check permission
        if( !current_user_can('edit_posts') ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('permission-head'),
                'message'=> pixe_get_error_message('permission-message')
            )));
        }

        // check data
        if( empty($_POST['id']) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('invalid-format-head'),
                'message'=> pixe_get_error_message('invalid-format-message')
            )));
        }

        $template_id = absint(wp_unslash($_POST['id']));
        $template = pixe_get_template($template_id, '', ARRAY_A);

        if( empty($template) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => esc_html__('Template Error', 'pixebuilder'),
                'message'=> esc_html__('Cannot find the template you selected. Please try again.', 'pixebuilder')
            )));
        }else{
            $template['title'] = $template['title'] .  ' ' . esc_html__('Copy', 'pixebuilder');
            $new_template_id = pixe_copy_template($template);
            
            $template['id'] = $new_template_id;
            
            // return data
            die(json_encode(array(
                'status' => 'success',
                'template' => pixe_get_template_list_item($template)
            )));
        }

    }

    add_action('wp_ajax_pixe_remove_template', 'pixe_ajax_remove_template');
    function pixe_ajax_remove_template(){

        // check nonce
        if( !check_ajax_referer('pixe-editor', 'security', false) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('nonce-head'),
                'message'=> pixe_get_error_message('nonce-message')
            )));
        }

        // check permission
        if( !current_user_can('edit_posts') ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('permission-head'),
                'message'=> pixe_get_error_message('permission-message')
            )));
        }

        // check data
        if( empty($_POST['id']) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('invalid-format-head'),
                'message'=> pixe_get_error_message('invalid-format-message')
            )));
        }

        // delete from database
        global $wpdb;
        $id = absint(wp_unslash($_POST['id']));
        $wpdb->delete("{$wpdb->prefix}pixetemplate", array('id' => $id), array('%d')); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Cache automatically invalidated on data changes

        // delete cache after update
        pixe_increase_cache_version('template');

        // remove preview image
        $preview_image = pixe_get_template_preview_image($id, 'dir');
        if( !empty($preview_image) ){
            wp_delete_file($preview_image);
        }

        die(json_encode(array(
            'status' => 'success',
        )));

    }

    add_action('wp_ajax_pixe_create_template', 'pixe_ajax_create_template');
    function pixe_ajax_create_template(){

        // check nonce
        if( !check_ajax_referer('pixe-editor', 'security', false) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('nonce-head'),
                'message'=> pixe_get_error_message('nonce-message')
            )));
        }

        // check permission
        if( !current_user_can('edit_posts') ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('permission-head'),
                'message'=> pixe_get_error_message('permission-message')
            )));
        }

        $currentuser = wp_get_current_user();
        $currenttime = current_time('mysql', true);

        // create new template and get the id
        $type = 'template';
        $part = '';
        $title = empty($_POST['title'])? '': sanitize_text_field(wp_unslash($_POST['title']));
        $settings = array();

        if( !empty($_POST['part']) ){
            $type = 'template_part';
            $part = sanitize_text_field(wp_unslash($_POST['part']));

            if( ($part == 'post_template' || $part == 'taxonomy_template') && !empty($_POST['layout']) ){
                $settings['layout'] = sanitize_text_field(wp_unslash($_POST['layout']));
            }
        }

        $new_template = array(
            'pixe_type' => $type,
            'pixe_subtype' => $part,
            'title' => $title,
            'settings' => $settings,
            'author' => $currentuser->ID,
            'date_utc' => $currenttime
        );
        $id = pixe_set_template_data($new_template);

        if( empty($id) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => esc_html__('Cannot Create Template', 'pixebuilder'),
                'message'=> esc_html__('An error occurs, please try again.' ,'pixebuilder')
            )));
        }else{
            $new_template['id'] = $id;

            // insert default title
            if( empty($title) ){
                if( $type == 'template_part' ){
                    switch($part){
                        /* translators: %d: Template ID */
                        case 'header': $title = sprintf(esc_html__('Header %d', 'pixebuilder'), $id); break;
                        /* translators: %d: Template ID */
                        case 'footer': $title = sprintf(esc_html__('Footer %d', 'pixebuilder'), $id); break;
                        /* translators: %d: Template ID */
                        case 'popup': $title = sprintf(esc_html__('Popup %d', 'pixebuilder'), $id); break;
                        /* translators: %d: Template ID */
                        case 'synced_block': $title = sprintf(esc_html__('Synced Block %d', 'pixebuilder'), $id); break;
                        /* translators: %d: Template ID */
                        case 'post_template': $title = sprintf(esc_html__('Post Template %d', 'pixebuilder'), $id); break;
                        /* translators: %d: Template ID */
                        case 'taxonomy_template': $title = sprintf(esc_html__('Taxonomy Template %d', 'pixebuilder'), $id); break;
                    }
                }else{
                    /* translators: %d: Template ID */
                    $title = sprintf(esc_html__('Template %d', 'pixebuilder'), $id);
                }
                if( empty($title) ){
                    $title = esc_html__('Template', 'pixebuilder');
                }
                pixe_set_template_data(array(
                    'id' => $id,
                    'title' => $title
                ));
                $new_template['title'] = $title;
            }

            // return data
            die(json_encode(array(
                'status' => 'success',
                'template' => pixe_get_template_list_item($new_template)
            )));
        }

    } // pixe_create_template_part

    // ajax get template
    add_action('wp_ajax_pixe_get_template', 'pixe_ajax_get_template');
    function pixe_ajax_get_template(){

        // check nonce
        if( !check_ajax_referer('pixe-editor', 'security', false) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('nonce-head'),
                'message'=> pixe_get_error_message('nonce-message')
            )));
        }

        // check data
        if( empty($_POST['id']) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('invalid-format-head'),
                'message'=> pixe_get_error_message('invalid-format-message')
            )));
        }

        // get part id
        $id = absint(wp_unslash($_POST['id']));
        $result = pixe_get_template($id);

        if( empty($result) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => esc_html__('Template Not Found', 'pixebuilder'),
                'message'=> esc_html__('Cannot find the template you\'re selected.' ,'pixebuilder')
            )));
        }else{
            die(json_encode(array(
                'status' => 'success',
                'type' => 'wrapper',
                'content' => json_decode($result->content, true)
            )));
        }
    }   
    add_action('wp_ajax_pixe_get_template_part', 'pixe_ajax_get_template_part');
    function pixe_ajax_get_template_part(){

        // check nonce
        if( !check_ajax_referer('pixe-editor', 'security', false) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('nonce-head'),
                'message'=> pixe_get_error_message('nonce-message')
            )));
        }

        // check data
        if( empty($_POST['type']) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('invalid-format-head'),
                'message'=> pixe_get_error_message('invalid-format-message')
            )));
        }

        $template_id = empty($_POST['id'])? '': absint(wp_unslash($_POST['id']));
        $type = sanitize_text_field(wp_unslash($_POST['type']));

        // default template type
        if( empty($template_id) ){
            if( $type == 'header' ){
                $template_id = get_option('pixe_default_header');
            }else if( $type == 'footer' ){
                $template_id = get_option('pixe_default_footer');
            } 
        }

        // empty header
        if( empty($template_id) || $template_id == 'none' ){
            die(json_encode(array(
                'status' => 'success',
                'content' => '',
                'settings' => ''
            )));
        }

        // get part id
        $result = pixe_get_template($template_id);

        if( empty($result) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => esc_html__('Template Not Found', 'pixebuilder'),
                'message' => esc_html__('Cannot find the template you\'re selected.' ,'pixebuilder'),
            )));
        }else{
            die(json_encode(array(
                'status' => 'success',
                'content' => json_decode($result->content, true),
                'settings' => json_decode($result->settings, true)
            )));
        }
        
    }

    // save control preset
    add_action('wp_ajax_pixe_save_template_area', 'pixe_ajax_save_template_area');
    function pixe_ajax_save_template_area(){
        
        // check nonce
        if( !check_ajax_referer('pixe-editor', 'security', false) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('nonce-head'),
                'message'=> pixe_get_error_message('nonce-message')
            )));
        }

        // check permission
        if( !current_user_can('manage_options') ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('permission-head'),
                'message'=> pixe_get_error_message('permission-message')
            )));
        }

        // save to database
        if( !empty($_POST['template-area']) ){
            $template_area = map_deep(wp_unslash($_POST['template-area']), 'absint');
            update_option('pixe_template_area', $template_area, true);
        }else{
            delete_option('pixe_template_area');
        }

        die(json_encode(array(
            'status' => 'success',
            'head' => esc_html__('Template Area Saved', 'pixebuilder')
        )));
    }
    function pixe_set_template_area($type, $value){
        $template_area = pixe_get_template_area();
        $template_area[$type] = $value;
        update_option('pixe_template_area', $template_area);
    }
    function pixe_get_template_area(){
        return get_option('pixe_template_area', array());
    }

    // query template
    function pixe_get_template_list_item($template){

        if( is_array($template) ){
            $t = array(
                'id' => $template['id'],
                'title' => $template['title'],
                'edit-url' => Pixe_Builder::get_template_edit_url($template['id'], $template['pixe_type'], $template['pixe_subtype'], $template['settings']),
                'preview-url' => Pixe_Editor::get_editor_url($template['id'], $template['pixe_type'], $template['pixe_subtype'], true),
                'preview-thumb' => pixe_get_template_preview_image($template['id'])
            );

            $settings = empty($template['settings'])? array(): $template['settings'];
            if( $template['pixe_type'] == 'template_part' && $template['pixe_subtype'] == 'header'){
                $t['type'] = empty($settings['header']['position'])? '': $settings['header']['position'];
            }

            // admin settings
            if( defined('PIXEADMIN_URL') ){
                if( !empty($settings['admin']['display']) ){
                    $t['prebuilt'] = 1;
                }
                if( !empty( $settings['admin']['preview']['url']) ){
                    $t['preview-url'] = $settings['admin']['preview']['url'];
                    $t['preview-thumb'] = $settings['admin']['preview']['url'];
                }
            }
        }else{
            $t = array(
                'id' => $template->id,
                'title' => $template->title,
                'edit-url' => Pixe_Builder::get_template_edit_url($template->id, $template->pixe_type, $template->pixe_subtype, $template->settings),
                'preview-url' => Pixe_Editor::get_editor_url($template->id, $template->pixe_type, $template->pixe_subtype, true),
                'preview-thumb' => pixe_get_template_preview_image($template->id)
            );

            $settings = empty($template->settings)? array(): json_decode($template->settings, true);
            if( $template->pixe_type == 'template_part' && $template->pixe_subtype == 'header'){
                $t['type'] = empty($settings['header']['position'])? '': $settings['header']['position'];
            }

            // admin settings
            if( defined('PIXEADMIN_URL') ){
                if( !empty($settings['admin']['display']) ){
                    $t['prebuilt'] = 1;
                }
                if( !empty( $settings['admin']['preview']['url']) ){
                    $t['preview-url'] = $settings['admin']['preview']['url'];
                    $t['preview-thumb'] = $settings['admin']['preview']['url'];
                }
            }
        }

        return $t;
    }
    function pixe_get_template_list($type, $subtype = ''){
        $ret = array();
        
        $templates = pixe_get_templates($type, $subtype);
        foreach( $templates as $template ){
            $ret[] = pixe_get_template_list_item($template);
        }

        return $ret;
    }
    function pixe_get_templates($type, $subtype = '', $orderby = ''){
        if( empty($type) ) return;

        global $wpdb;

        // query all ids
        $params = array($type);
        $condition  = '';
        
        if( !empty($subtype) ){
            $params[] = $subtype;
            $condition .= "AND pixe_subtype = %s ";
        }

        if( empty($orderby) ){
            $condition .= "ORDER BY id DESC;";
        }else if($orderby == 'name'){
            $condition .= "ORDER BY pixe_type ASC, pixe_subtype ASC, id DESC;";
        }

        // get result from cache first
        $cache_key = pixe_template_get_cache_key(array('type' => $type, 'subtype' => $subtype, 'order' => $orderby));
        $results = wp_cache_get($cache_key, 'pixebuilder');
        if( !empty($results) ) return $results;
        
        // no cache, query from database
        $results = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}pixetemplate WHERE pixe_type = %s {$condition}", $params)); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Condition is generated safely
        wp_cache_set($cache_key, $results, 'pixebuilder', DAY_IN_SECONDS);

        return $results;
    }
    function pixe_get_template($id, $type = '', $output = OBJECT){
        if( empty($id) || $id == 'none' ) return;

        global $wpdb;

        if( is_array($id) ){

            // template id
            $ids = array_unique(array_map('absint', $id));
            if( empty($ids) ) return array();

            $params = $ids;
            $condition = '';
            $placeholder = esc_html(implode(',', array_fill(0, count($ids), '%d')));
            
            // template type
            if( !empty($type) ){
                $params[] = $type;
                $condition .= "AND pixe_type = 'template_part' AND pixe_subtype = %s ";
            }

            // get result from cache first
            $cache_key = pixe_template_get_cache_key(array('ids' => $ids, 'type' => (empty($type)? '': 'template_part'), 'subtype' => $type, 'output' => $output));
            $result = wp_cache_get($cache_key, 'pixebuilder');
            if( !empty($result) ) return $result;

            // no cache, query from database
            $result = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}pixetemplate WHERE id IN({$placeholder}) {$condition}", $params), $output); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Condition and placeholder is generated safely
            wp_cache_set($cache_key, $result, 'pixebuilder', DAY_IN_SECONDS);

        }else{

            // template id
            $params = array($id);
            $condition = '';

            // template type
            if( !empty($type) ){
                $params[] = $type;
                $condition .= "AND pixe_type = 'template_part' AND pixe_subtype = %s ";
            }
            
            // get result from cache first
            $cache_key = pixe_template_get_cache_key(array('id' => $id, 'type' => (empty($type)? '': 'template_part'), 'subtype' => $type, 'output' => $output));
            $result = wp_cache_get($cache_key, 'pixebuilder');
            if( !empty($result) ) return $result;

            $result = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}pixetemplate WHERE id = %d {$condition}", $params), $output); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Condition is generated safely
            wp_cache_set($cache_key, $result, 'pixebuilder', DAY_IN_SECONDS);
        }
        
        return $result;
    }

    // update template id
    function pixe_update_template_part_id($content, $subtype, $old_id, $new_id){
        $old_prefix = pixe_get_part_name('template_part', $subtype, $old_id);
        $new_prefix = pixe_get_part_name('template_part', $subtype, $new_id);

        $content = str_replace($old_prefix, $new_prefix, $content);

        $part_att = 'data-' . $subtype . '-id';
        $content = str_replace($part_att . '=\"' . $old_id . '\"', $part_att . '=\"' . $new_id .  '\"', $content);

        return $content;
    }
    
    // import templates locally
    function pixe_copy_templates($templates){
        $templates_data = array();

        if( !empty($templates) ){
            foreach($templates as $template){
                if( !empty($template['pixe_type']) && !empty($template['title']) ){
                    $template_id = pixe_copy_template($template);
                    
                    $template['id'] = $template_id;
                    $template_data = pixe_get_template_list_item($template);
                    $template_data['pixe_type'] = $template['pixe_type'];
                    $template_data['pixe_subtype'] = empty($template['pixe_subtype'])? '': $template['pixe_subtype'];
                    $templates_data[] = $template_data;
                }
            }
        }

        return $templates_data;
    }

    add_action('wp_ajax_pixe_import_templates_file', 'pixe_ajax_import_templates');
    function pixe_ajax_import_templates(){
        
        // check nonce
        if( !check_ajax_referer('pixe-editor', 'security', false) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('nonce-head'),
                'message'=> pixe_get_error_message('nonce-message')
            )));
        }

        // check permission
        if( !current_user_can('manage_options') ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('permission-head'),
                'message'=> pixe_get_error_message('permission-message')
            )));
        }

        // check data
        if( empty($_POST['file']['id']) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('invalid-format-head'),
                'message'=> pixe_get_error_message('invalid-format-message')
            )));
        }

        $id = absint(wp_unslash($_POST['file']['id']));
        $file = get_attached_file($id);

        if( !file_exists($file) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => esc_html__('File Not Found', 'pixebuilder'),
                'message'=> esc_html__('Please refresh the page and try again.' ,'pixebuilder')
            )));
        }

        $json_data = file_get_contents($file);
        $data = json_decode($json_data, true);
        $new_templates = pixe_copy_templates($data);

        die(json_encode(array(
            'status' => 'success',
            'templates' => $new_templates
        )));

    }

    // export template
    add_action('wp_ajax_pixe_export_templates', 'pixe_ajax_export_templates');
    function pixe_ajax_export_templates(){
            
        // check nonce
        if( !check_ajax_referer('pixe-editor', 'security', false) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('nonce-head'),
                'message'=> pixe_get_error_message('nonce-message')
            )));
        }

        // check data
        if( empty($_POST['ids']) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => pixe_get_error_message('invalid-format-head'),
                'message'=> pixe_get_error_message('invalid-format-message')
            )));
        }

        $ids = array_unique(array_map('absint', wp_unslash($_POST['ids'])));
        $data = pixe_get_template($ids);
        if( empty($data) ){
            die(json_encode(array(
                'status' => 'failed',
                'head' => esc_html__('No Template Found', 'pixebuilder'),
                'message'=> esc_html__('Please refresh the page and try again.' ,'pixebuilder')
            )));
        }
        
        die(json_encode(array(
            'status' => 'success',
            'data' => $data
        )));
    }