can_use_premium_code();
// TODO: TEST: For UI testing, it doesn't enable the real premium
// $is_premium_active = false;
// Arrays for categories and tags
$categories = [];
$tags = [];
$category_counts = [];
// Getting unique categories and tags
foreach ($templates['templates'] as $template) {
if (!in_array($template['category'], $categories)) {
$categories[] = $template['category'];
}
foreach ($template['tags'] as $tag) {
if (!in_array($tag, $tags)) {
$tags[] = $tag;
}
}
$category = $template['category'];
$category_counts[$category] = isset($category_counts[$category]) ? $category_counts[$category] + 1 : 1;
}
sort($categories);
// Get filters from query
$search_query = isset($_GET['s']) ? sanitize_text_field($_GET['s']) : '';
$selected_category = isset($_GET['category']) ? sanitize_text_field($_GET['category']) : '';
$selected_collection = isset($_GET['collection']) ? sanitize_text_field($_GET['collection']) : '';
$selected_tags = isset($_GET['tags']) ? array_filter(explode(',', sanitize_text_field($_GET['tags']))) : [];
$current_page = isset($_GET['paged']) ? max(1, intval($_GET['paged'])) : 1;
// Use the common function to get filtered templates and pagination
$result = $this->get_filtered_templates($templates, $search_query, $selected_category, $selected_tags, $selected_collection, $current_page);
if (isset($_GET['ajax']) && $_GET['ajax']) {
wp_send_json_success(['grid_html' => $result['grid_html'], 'pagination_html' => $result['pagination_html']]);
}
if ($is_premium_active) {
?>
can_use_premium_code()): ?>
can_use_premium_code()): ?>
0
$template) {
$found_in_title = false;
$found_in_tags = false;
foreach ($search_terms as $term) {
if ($term && stripos($template['title'], $term) !== false) {
$found_in_title = true;
}
foreach ($template['tags'] as $tag) {
if (stripos($tag, $term) !== false) {
$found_in_tags = true;
break;
}
}
// if (!$found_in_title && !$found_in_tags) {
// continue;
// }
}
if ($selected_category && $template['category'] !== $selected_category) {
continue;
}
if ($selected_tags) {
$template_tags = $template['tags'];
foreach ($selected_tags as $tag) {
if (!in_array($tag, $template_tags)) {
continue 2;
}
}
}
if ($selected_collection && $template['collection'] != $selected_collection) {
continue;
}
// Attach the template key for later use
$template['template_key'] = $key;
if ($found_in_title) {
$matched_by_title[] = $template;
} elseif ($found_in_tags) {
$matched_by_tags[] = $template;
}
}
// Combine the arrays, so templates matching by title come first
$filtered_templates = array_merge($matched_by_title, $matched_by_tags);
}
}
// Pagination setup
$items_per_page = 20;
$total_templates = count($filtered_templates);
$offset = ($current_page - 1) * $items_per_page;
$paged_templates = array_slice($filtered_templates, $offset, $items_per_page);
ob_start();
if (empty($paged_templates)) {
echo '' . esc_html__('No templates found.', 'king-addons') . '
';
} else {
foreach ($paged_templates as $key => $template) {
$attr_key = ($has_search) ? $template['template_key'] : $key;
?>
"
alt="">
add_query_arg(array(
'paged' => '%#%',
's' => $search_query,
'category' => $selected_category,
'collection' => $selected_collection,
'tags' => implode(',', $selected_tags),
)),
'format' => '?paged=%#%',
'current' => $current_page,
'total' => ceil($total_templates / $items_per_page),
'prev_text' => __('← Previous', 'king-addons'),
'next_text' => __('Next →', 'king-addons'),
'end_size' => 9,
'mid_size' => 3,
));
if ($pages) {
echo '';
}
$pagination_html = ob_get_clean();
return ['grid_html' => $grid_html, 'pagination_html' => $pagination_html];
}
public function king_addons_enqueue_scripts(): void
{
$screen = get_current_screen();
if ($screen->id === 'toplevel_page_king-addons-templates') {
wp_enqueue_style('king-addons-templates-style', KING_ADDONS_URL . 'includes/admin/css/templates.css', '', KING_ADDONS_VERSION);
if (!wp_script_is(KING_ADDONS_ASSETS_UNIQUE_KEY . '-' . 'jquery' . '-' . 'jquery')) {
wp_enqueue_script(KING_ADDONS_ASSETS_UNIQUE_KEY . '-' . 'jquery' . '-' . 'jquery', '', '', KING_ADDONS_VERSION);
}
wp_enqueue_script('king-addons-templates-script', KING_ADDONS_URL . 'includes/admin/js/templates.js', '', KING_ADDONS_VERSION, true);
wp_localize_script('king-addons-templates-script', 'kingAddonsData', array(
'adminUrl' => admin_url('admin-post.php'),
'ajaxUrl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('kingAddonsNonce'),
));
}
// if ($screen->id === 'king-addons_page_king-addons-account') {
// wp_enqueue_style('king-addons-account-style', KING_ADDONS_URL . 'includes/admin/css/account.css', '', KING_ADDONS_VERSION);
// }
}
public function __construct()
{
add_action('admin_enqueue_scripts', array($this, 'king_addons_enqueue_scripts'));
// Get the performance setting
$improve_import = get_option('king_addons_improve_import_performance', '1');
// Conditionally add time limit adjustments based on setting
if ($improve_import === '1') {
add_action('wp_ajax_import_elementor_page_with_images', function () {
@set_time_limit(300);
}, 0);
add_action('wp_ajax_process_import_images', function () {
@set_time_limit(300);
}, 0);
}
add_action(
'wp_ajax_import_elementor_page_with_images',
[$this, 'import_elementor_page_with_images']
);
add_action(
'wp_ajax_process_import_images',
[$this, 'process_import_images']
);
add_action('wp_ajax_filter_templates', array($this, 'handle_filter_templates'));
// Sections catalog endpoints
add_action('wp_ajax_king_addons_get_sections_catalog', array($this, 'handle_get_sections_catalog'));
add_action('wp_ajax_king_addons_import_section_admin', array($this, 'handle_import_section_to_page'));
add_action('http_api_curl', array($this, 'set_custom_curl_options'), 10, 3);
}
public function set_custom_curl_options($handle)
{
curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 60);
curl_setopt($handle, CURLOPT_DNS_CACHE_TIMEOUT, 300);
curl_setopt($handle, CURLOPT_TIMEOUT, 300);
}
function handle_filter_templates(): void
{
if (!current_user_can('manage_options')) {
return;
}
if (!isset($_POST['action']) || $_POST['action'] !== 'filter_templates') {
wp_send_json_error('Invalid request');
return;
}
$search_query = isset($_POST['s']) ? sanitize_text_field($_POST['s']) : '';
$selected_category = isset($_POST['category']) ? sanitize_text_field($_POST['category']) : '';
$selected_collection = isset($_POST['collection']) ? sanitize_text_field($_POST['collection']) : '';
$selected_tags = isset($_POST['tags']) ? array_filter(explode(',', sanitize_text_field($_POST['tags']))) : [];
$current_page = isset($_POST['paged']) ? max(1, intval($_POST['paged'])) : 1;
$templates = TemplatesMap::getTemplatesMapArray();
// Use the common function to get filtered templates and pagination
$result = $this->get_filtered_templates($templates, $search_query, $selected_category, $selected_tags, $selected_collection, $current_page);
wp_send_json_success(['grid_html' => $result['grid_html'], 'pagination_html' => $result['pagination_html']]);
}
public function import_elementor_page_with_images(): void
{
if (!current_user_can('manage_options')) {
return;
}
$import_data = json_decode(stripslashes($_POST['data']), true);
if (json_last_error() !== JSON_ERROR_NONE) {
wp_send_json_error('JSON decode error: ' . json_last_error_msg());
return;
}
if (isset($import_data['content']) && isset($import_data['images']) && isset($import_data['title'])) {
$content = $import_data['content'];
$image_data = $import_data['images'];
$page_title = sanitize_text_field($import_data['title']);
$elementor_version = sanitize_text_field($import_data['elementor_version']);
// Check if this is for existing page (from popup import)
$existing_page_id = isset($import_data['existing_page_id']) ? intval($import_data['existing_page_id']) : 0;
$create_new_page = isset($import_data['create_new_page']) ? (bool)$import_data['create_new_page'] : true;
delete_transient('elementor_import_content');
delete_transient('elementor_import_images');
delete_transient('elementor_import_total_images');
delete_transient('elementor_import_images_processed');
delete_transient('elementor_import_image_retry_count');
delete_transient('elementor_import_page_title');
delete_transient('elementor_import_elementor_version');
delete_transient('elementor_import_existing_page_id');
delete_transient('elementor_import_create_new_page');
set_transient('elementor_import_content', $content, 60 * 60);
set_transient('elementor_import_images', $image_data, 60 * 60);
set_transient('elementor_import_total_images', count($image_data), 60 * 60);
set_transient('elementor_import_images_processed', 0, 60 * 60);
set_transient('elementor_import_image_retry_count', [], 60 * 60);
set_transient('elementor_import_page_title', $page_title, 60 * 60);
set_transient('elementor_import_elementor_version', $elementor_version, 60 * 60);
set_transient('elementor_import_existing_page_id', $existing_page_id, 60 * 60);
set_transient('elementor_import_create_new_page', $create_new_page, 60 * 60);
error_log('King Addons Import: Initialized ' . ($create_new_page ? 'new page' : 'existing page') . ' import. Existing page ID: ' . $existing_page_id);
wp_send_json_success([
'message' => 'Import initialized.',
'images' => $image_data,
'existing_page_id' => $existing_page_id,
'create_new_page' => $create_new_page
]);
} else {
wp_send_json_error('Invalid import data.');
}
}
private function replace_image_data(array &$array, $old_url, $new_url, $old_id, $new_id)
{
foreach ($array as $key => &$value) {
if (is_array($value)) {
// Standard structure with both 'url' and 'id'
if (
isset($value['url'], $value['id']) &&
$value['url'] === $old_url &&
$value['id'] === $old_id
) {
$value['url'] = $new_url;
$value['id'] = $new_id;
}
// Background image structure (common in Elementor)
if (
isset($value['url']) &&
$value['url'] === $old_url &&
(!isset($value['id']) || $value['id'] === $old_id)
) {
$value['url'] = $new_url;
if (isset($value['id'])) {
$value['id'] = $new_id;
}
}
// Recursively check deeper nested arrays
$this->replace_image_data($value, $old_url, $new_url, $old_id, $new_id);
} elseif (is_string($value)) {
// Direct URL string replacement
if ($value === $old_url) {
$array[$key] = $new_url;
}
// CSS background-image style replacement
if (strpos($value, 'background-image:') !== false && strpos($value, $old_url) !== false) {
$array[$key] = str_replace($old_url, $new_url, $value);
}
// URL() function replacement in CSS
if (strpos($value, 'url(') !== false && strpos($value, $old_url) !== false) {
$array[$key] = str_replace($old_url, $new_url, $value);
}
// JSON string containing URLs (for widget settings)
if (strpos($value, '{') === 0 && strpos($value, $old_url) !== false) {
$decoded = json_decode($value, true);
if (is_array($decoded)) {
$this->replace_image_data($decoded, $old_url, $new_url, $old_id, $new_id);
$array[$key] = json_encode($decoded);
}
}
}
}
}
public function process_import_images(): void
{
// Conditionally increase execution time limit based on setting
$improve_import = get_option('king_addons_improve_import_performance', '1');
if ($improve_import === '1') {
@set_time_limit(300);
}
if (!current_user_can('manage_options')) {
wp_send_json_error('The current user can not manage options and create pages. Please change it in the WordPress settings.');
return;
}
$start_time = time();
$timeout = 30;
$content = get_transient('elementor_import_content');
$image_data = get_transient('elementor_import_images');
$total_images = get_transient('elementor_import_total_images');
$images_processed = get_transient('elementor_import_images_processed');
$image_retry_count = get_transient('elementor_import_image_retry_count');
$page_title = get_transient('elementor_import_page_title');
$elementor_version = get_transient('elementor_import_elementor_version');
$existing_page_id = get_transient('elementor_import_existing_page_id');
$create_new_page = get_transient('elementor_import_create_new_page');
if (!is_array($image_retry_count)) {
$image_retry_count = [];
}
if ($images_processed < $total_images) {
$current_image = $image_data[$images_processed];
$url = $current_image['url'];
if (!isset($image_retry_count[$url])) {
$image_retry_count[$url] = 0;
}
$new_image_id = $this->download_image_to_media_gallery($url, $image_retry_count[$url]);
if ($new_image_id === false) {
$image_retry_count[$url]++;
set_transient('elementor_import_image_retry_count', $image_retry_count, 60 * 60);
if ($image_retry_count[$url] > 3) {
$images_processed++;
set_transient('elementor_import_images_processed', $images_processed, 60 * 60);
$progress = round(($images_processed / $total_images) * 90) + 10;
wp_send_json_success([
'progress' => $progress,
'message' => "Processed $images_processed of $total_images images.",
'image_url' => $url,
'images_processed' => $images_processed,
'new_image_id' => 'SKIPPED'
]);
} else {
wp_send_json_error([
'retry' => true,
'image_url' => $url
]);
}
} else {
$new_url = wp_get_attachment_url($new_image_id);
$images_processed++;
set_transient('elementor_import_images_processed', $images_processed, 60 * 60);
$progress = round(($images_processed / $total_images) * 90) + 10;
$this->replace_image_data($content, $url, $new_url, $current_image['id'], $new_image_id);
set_transient('elementor_import_content', $content, 60 * 60);
wp_send_json_success([
'progress' => $progress,
'message' => "Processed $images_processed of $total_images images.",
'image_url' => $url,
'new_image_url' => $new_url
]);
}
} else {
// All images processed
if ($create_new_page) {
// Original behavior - create new page
$new_post_id = wp_insert_post([
'post_title' => $page_title,
'post_content' => '',
'post_status' => 'publish',
'post_type' => 'page',
]);
if ($new_post_id) {
update_post_meta($new_post_id, '_elementor_data', wp_slash(json_encode($content)));
update_post_meta($new_post_id, '_elementor_edit_mode', 'builder');
update_post_meta($new_post_id, '_elementor_template_type', 'page');
update_post_meta($new_post_id, '_elementor_version', $elementor_version);
update_post_meta($new_post_id, '_wp_page_template', 'elementor_canvas');
update_post_meta($new_post_id, '_wp_gutenberg_disable', '1');
update_post_meta($new_post_id, '_wp_gutenberg_enabled', '0');
delete_transient('elementor_import_content');
delete_transient('elementor_import_images');
delete_transient('elementor_import_total_images');
delete_transient('elementor_import_images_processed');
delete_transient('elementor_import_image_retry_count');
delete_transient('elementor_import_page_title');
delete_transient('elementor_import_elementor_version');
delete_transient('elementor_import_existing_page_id');
delete_transient('elementor_import_create_new_page');
wp_send_json_success([
'message' => "Page imported successfully!",
'page_url' => get_permalink($new_post_id),
]);
} else {
wp_send_json_error('Failed to import page.');
}
} else {
// New behavior - for existing page, just signal completion
// Content and images are processed and stored in transients
// Will be merged by king_addons_merge_with_existing_page endpoint
error_log('King Addons Import: Image processing completed for existing page. Content ready for merge.');
wp_send_json_success([
'message' => "Image processing completed! Content ready for merge.",
'images_processed' => $images_processed,
'existing_page_id' => $existing_page_id,
'processing_complete' => true
]);
}
}
if (time() >= $start_time + $timeout) {
wp_send_json_error('Process timeout, please resume the import.');
}
}
public function download_image_to_media_gallery($image_url, $image_retry_count)
{
try {
$response = wp_remote_get($image_url, ['timeout' => 30]);
if (is_wp_error($response)) {
throw new Exception('HTTP request error: ' . $response->get_error_message());
}
$status_code = wp_remote_retrieve_response_code($response);
if ($status_code !== 200) {
throw new Exception(
'HTTP status code ' . $status_code . ' when trying to download: ' . $image_url
);
}
$image_data = wp_remote_retrieve_body($response);
if (empty($image_data)) {
throw new Exception('Failed to retrieve image data from URL: ' . $image_url);
}
$image_name = pathinfo(basename($image_url), PATHINFO_FILENAME);
$image_extension = pathinfo(basename($image_url), PATHINFO_EXTENSION);
$unique_image_name = $image_name . '-' . time() . '.' . $image_extension;
$upload_dir = wp_upload_dir();
if (! file_exists($upload_dir['path'])) {
wp_mkdir_p($upload_dir['path']);
}
$image_file = $upload_dir['path'] . '/' . $unique_image_name;
if (file_put_contents($image_file, $image_data) === false) {
throw new Exception('Failed to write image data to file: ' . $image_file);
}
$wp_filetype = wp_check_filetype($unique_image_name);
$attachment = [
'post_mime_type' => $wp_filetype['type'],
'post_title' => sanitize_file_name($unique_image_name),
'post_content' => '',
'post_status' => 'inherit',
];
$attach_id = wp_insert_attachment($attachment, $image_file);
// Conditionally disable intermediate image sizes based on setting
$improve_import = get_option('king_addons_improve_import_performance', '1');
if ($improve_import === '1') {
// Disable ALL extra sizes and big-image scaling
add_filter('intermediate_image_sizes', '__return_empty_array', 999);
add_filter('big_image_size_threshold', '__return_false', 999);
/* Save only the original file info — no thumbnails, no EXIF */
// Get image dimensions
$image_size = getimagesize($image_file);
$width = $image_size ? $image_size[0] : 0;
$height = $image_size ? $image_size[1] : 0;
$meta = [
'file' => wp_basename($image_file),
'filesize' => filesize($image_file),
'width' => $width,
'height' => $height,
'sizes' => [],
'image_meta' => [],
];
wp_update_attachment_metadata($attach_id, $meta);
// Clean up filters
remove_filter('intermediate_image_sizes', '__return_empty_array', 999);
remove_filter('big_image_size_threshold', '__return_false', 999);
} else {
if ($image_retry_count > 1) {
add_filter('intermediate_image_sizes', '__return_empty_array', 999);
}
// Generate default metadata if optimization is off
require_once(ABSPATH . 'wp-admin/includes/image.php');
$attach_data = wp_generate_attachment_metadata($attach_id, $image_file);
wp_update_attachment_metadata($attach_id, $attach_data);
if ($image_retry_count > 1) {
remove_filter('intermediate_image_sizes', '__return_empty_array', 999);
}
}
return $attach_id;
} catch (Exception $e) {
error_log('[KING_ADDONS_ERROR] ' . $e->getMessage());
return false;
}
}
/**
* AJAX handler for getting sections catalog data
*/
public function handle_get_sections_catalog(): void
{
if (!current_user_can('manage_options')) {
wp_send_json_error('Insufficient permissions');
return;
}
// Check nonce - handle both admin area and popup
if (isset($_POST['nonce'])) {
$valid_nonce = wp_verify_nonce($_POST['nonce'], 'kingAddonsNonce') ||
wp_verify_nonce($_POST['nonce'], 'king_addons_template_catalog');
if (!$valid_nonce) {
wp_send_json_error('Invalid nonce');
return;
}
}
if (!class_exists('King_Addons\\SectionsMap')) {
require_once KING_ADDONS_PATH . 'includes/SectionsMap.php';
}
$sections_map = SectionsMap::getSectionsMapArray();
$sections = $sections_map['sections'] ?? [];
$is_premium_active = function_exists('king_addons_freemius') && king_addons_freemius()->can_use_premium_code();
// Get filters from request
$search_query = sanitize_text_field($_POST['search'] ?? '');
$selected_category = sanitize_text_field($_POST['category'] ?? '');
$selected_type = sanitize_text_field($_POST['section_type'] ?? '');
$selected_plan = sanitize_text_field($_POST['plan'] ?? '');
$current_page = max(1, intval($_POST['page'] ?? 1));
// Get categories and section types for filters
$categories = [];
$section_types = [];
foreach ($sections as $section_key => $section) {
if (!in_array($section['category'], $categories)) {
$categories[] = $section['category'];
}
if (!in_array($section['section_type'], $section_types)) {
$section_types[] = $section['section_type'];
}
}
sort($categories);
sort($section_types);
// Filter sections
$filtered_sections = [];
foreach ($sections as $section_key => $section) {
// Add section key for frontend
$section['section_key'] = $section_key;
// Note: Premium sections are shown but restricted for import if no premium license
// Apply search filter
if (!empty($search_query)) {
$found_in_title = stripos($section['title'], $search_query) !== false;
$found_in_tags = false;
foreach ($section['tags'] ?? [] as $tag) {
if (stripos($tag, $search_query) !== false) {
$found_in_tags = true;
break;
}
}
if (!$found_in_title && !$found_in_tags) {
continue;
}
}
// Apply category filter
if (!empty($selected_category) && $section['category'] !== $selected_category) {
continue;
}
// Apply section type filter
if (!empty($selected_type) && $section['section_type'] !== $selected_type) {
continue;
}
// Apply plan filter
if (!empty($selected_plan) && $section['plan'] !== $selected_plan) {
continue;
}
$filtered_sections[] = $section;
}
// Pagination
$items_per_page = 20;
$total_sections = count($filtered_sections);
$total_pages = ceil($total_sections / $items_per_page);
$offset = ($current_page - 1) * $items_per_page;
$paged_sections = array_slice($filtered_sections, $offset, $items_per_page);
wp_send_json_success([
'sections' => $paged_sections,
'categories' => $categories,
'section_types' => $section_types,
'pagination' => [
'current_page' => $current_page,
'total_pages' => $total_pages,
'total_sections' => $total_sections,
'items_per_page' => $items_per_page
],
'is_premium_active' => $is_premium_active
]);
}
/**
* AJAX handler for importing section to current page (from main admin catalog)
*/
public function handle_import_section_to_page(): void
{
if (!current_user_can('edit_posts')) {
wp_send_json_error('Insufficient permissions');
return;
}
if (!wp_verify_nonce($_POST['nonce'], 'kingAddonsNonce')) {
wp_send_json_error('Invalid nonce');
return;
}
$section_key = sanitize_text_field($_POST['section_key']);
$section_plan = sanitize_text_field($_POST['section_plan']);
$is_premium_active = function_exists('king_addons_freemius') && king_addons_freemius()->can_use_premium_code();
// Determine API URL and install ID (same logic as templates)
if ($is_premium_active && $section_plan === 'premium') {
$api_url = 'https://api.kingaddons.com/get-section.php';
// Use the same method as original templates catalog
if (function_exists('king_addons_freemius')) {
$freemius_site = king_addons_freemius()->get_site();
$install_id = $freemius_site ? $freemius_site->id : 0;
} else {
$install_id = 0;
}
error_log('King Addons Premium Section: Using install_id: ' . $install_id . ' for premium section: ' . $section_key);
} elseif ($section_plan === 'free') {
$api_url = 'https://api.kingaddons.com/get-section-free.php';
$install_id = 0;
error_log('King Addons Free Section: Fetching free section: ' . $section_key);
} else {
error_log('King Addons Section Error: Premium section requires premium license. Section: ' . $section_key . ', Plan: ' . $section_plan . ', Premium Active: ' . ($is_premium_active ? 'Yes' : 'No'));
wp_send_json_error('Premium section requires premium license');
return;
}
// Get section data from API (same as templates)
$response = wp_remote_post($api_url, [
'headers' => ['Content-Type' => 'application/json'],
'body' => json_encode([
'key' => $section_key,
'install' => $install_id,
]),
'timeout' => 60
]);
if (is_wp_error($response)) {
wp_send_json_error('Failed to fetch section: ' . $response->get_error_message());
return;
}
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
error_log('King Addons Section API Response: ' . substr($body, 0, 500) . (strlen($body) > 500 ? '...' : ''));
if (!$data) {
error_log('King Addons Section Error: Failed to decode JSON response');
wp_send_json_error('Invalid JSON response from section API');
return;
}
if (!isset($data['success']) || !$data['success']) {
$error_message = isset($data['message']) ? $data['message'] : 'Unknown API error';
error_log('King Addons Section Error: API returned error: ' . $error_message);
wp_send_json_error('Section API error: ' . $error_message);
return;
}
// Return section data for frontend processing (adjust format from your API)
wp_send_json_success([
'section_data' => $data['section'], // Your API returns 'section' not 'landing'
'message' => 'Section data retrieved successfully'
]);
}
}
Templates::instance();